Index: include/llvm/MC/MCAssembler.h =================================================================== --- include/llvm/MC/MCAssembler.h +++ include/llvm/MC/MCAssembler.h @@ -54,6 +54,7 @@ FT_Org, FT_Dwarf, FT_DwarfFrame, + FT_CoffStaticOffset, FT_LEB }; @@ -538,6 +539,35 @@ } }; +class MCCoffStaticOffsetFragment : public MCFragment { + virtual void anchor(); + + /// AddrDelta - The expression for the offset between two labels. + const MCExpr *AddrDelta; + + SmallString<8> Contents; + +public: + MCCoffStaticOffsetFragment(const MCExpr &AddrDelta, MCSectionData *SD = 0) + : MCFragment(FT_CoffStaticOffset, SD), AddrDelta(&AddrDelta) { + Contents.assign(4u, '\0'); + } + + /// @name Accessors + /// @{ + + const MCExpr &getAddrDelta() const { return *AddrDelta; } + + SmallString<8> &getContents() { return Contents; } + const SmallString<8> &getContents() const { return Contents; } + + /// @} + + static bool classof(const MCFragment *F) { + return F->getKind() == MCFragment::FT_CoffStaticOffset; + } +}; + // FIXME: Should this be a separate class, or just merged into MCSection? Since // we anticipate the fast path being through an MCAssembler, the only reason to // keep it out is for API abstraction. @@ -932,6 +962,8 @@ bool relaxDwarfLineAddr(MCAsmLayout &Layout, MCDwarfLineAddrFragment &DF); bool relaxDwarfCallFrameFragment(MCAsmLayout &Layout, MCDwarfCallFrameFragment &DF); + bool relaxCoffStaticOffsetFragment(MCAsmLayout &Layout, + MCCoffStaticOffsetFragment &LDF); /// finishLayout - Finalize a layout, including fragment lowering. void finishLayout(MCAsmLayout &Layout); Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -411,11 +411,20 @@ /// EndCOFFSymbolDef - Marks the end of the symbol definition. virtual void EndCOFFSymbolDef() = 0; + /// EmitCOFFSectionReference - Emits a COFF section number. + /// + /// @param Symbol - Symbol the section number relocation should point to. + virtual void EmitCOFFSectionReference(MCSymbol const *Symbol); + /// EmitCOFFSecRel32 - Emits a COFF section relative relocation. /// - /// @param Symbol - Symbol the section relative realocation should point to. + /// @param Symbol - Symbol the section relative relocation should point to. virtual void EmitCOFFSecRel32(MCSymbol const *Symbol); + /// EmitCOFFStaticOffset - Emits statically-known difference between two + /// labels in the same section. + virtual void EmitCOFFStaticOffset(const MCSymbol *From, const MCSymbol *To); + /// EmitELFSize - Emit an ELF .size directive. /// /// This corresponds to an assembler statement such as: Index: lib/MC/MCAsmStreamer.cpp =================================================================== --- lib/MC/MCAsmStreamer.cpp +++ lib/MC/MCAsmStreamer.cpp @@ -160,7 +160,9 @@ virtual void EmitCOFFSymbolStorageClass(int StorageClass); virtual void EmitCOFFSymbolType(int Type); virtual void EndCOFFSymbolDef(); + virtual void EmitCOFFSectionReference(MCSymbol const *Symbol); virtual void EmitCOFFSecRel32(MCSymbol const *Symbol); + virtual void EmitCOFFStaticOffset(const MCSymbol *From, const MCSymbol *To); virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value); virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment); @@ -505,8 +507,19 @@ EmitEOL(); } +void MCAsmStreamer::EmitCOFFSectionReference(MCSymbol const *Symbol) { + OS << "\t.secref\t" << *Symbol; + EmitEOL(); +} + void MCAsmStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol) { - OS << "\t.secrel32\t" << *Symbol << '\n'; + OS << "\t.secrel32\t" << *Symbol; + EmitEOL(); +} + +void MCAsmStreamer::EmitCOFFStaticOffset(const MCSymbol *From, + const MCSymbol *To) { + OS << "\t.offset from " << *From << " to " << *To; EmitEOL(); } Index: lib/MC/MCAssembler.cpp =================================================================== --- lib/MC/MCAssembler.cpp +++ lib/MC/MCAssembler.cpp @@ -469,6 +469,8 @@ return cast(F).getContents().size(); case MCFragment::FT_DwarfFrame: return cast(F).getContents().size(); + case MCFragment::FT_CoffStaticOffset: + return cast(F).getContents().size(); } llvm_unreachable("invalid fragment kind"); @@ -676,6 +678,11 @@ OW->WriteBytes(CF.getContents().str()); break; } + case MCFragment::FT_CoffStaticOffset: { + const MCCoffStaticOffsetFragment &LDF = cast(F); + OW->WriteBytes(LDF.getContents().str()); + break; + } } assert(OW->getStream().tell() - Start == FragmentSize && @@ -937,6 +944,25 @@ return OldSize != Data.size(); } +bool MCAssembler::relaxCoffStaticOffsetFragment( + MCAsmLayout &Layout, MCCoffStaticOffsetFragment &LDF) { + MCContext &Context = Layout.getAssembler().getContext(); + int64_t AddrDelta = 0; + uint64_t OldSize = LDF.getContents().size(); + bool IsAbs = LDF.getAddrDelta().EvaluateAsAbsolute(AddrDelta, Layout); + (void)IsAbs; + assert(IsAbs); + SmallString<8> &Data = LDF.getContents(); + Data.clear(); + raw_svector_ostream OSE(Data); + OSE << uint8_t( AddrDelta & 0xff); + OSE << uint8_t((AddrDelta >> 8) & 0xff); + OSE << uint8_t((AddrDelta >> 16) & 0xff); + OSE << uint8_t((AddrDelta >> 24) & 0xff); + OSE.flush(); + return OldSize != Data.size(); +} + bool MCAssembler::layoutSectionOnce(MCAsmLayout &Layout, MCSectionData &SD) { // Holds the first fragment which needed relaxing during this layout. It will // remain NULL if none were relaxed. @@ -965,6 +991,10 @@ relaxDwarfCallFrameFragment(Layout, *cast(I)); break; + case MCFragment::FT_CoffStaticOffset: + RelaxedFrag = relaxCoffStaticOffsetFragment( + Layout, *cast(I)); + break; case MCFragment::FT_LEB: RelaxedFrag = relaxLEB(Layout, *cast(I)); break; @@ -1027,6 +1057,8 @@ case MCFragment::FT_Org: OS << "MCOrgFragment"; break; case MCFragment::FT_Dwarf: OS << "MCDwarfFragment"; break; case MCFragment::FT_DwarfFrame: OS << "MCDwarfCallFrameFragment"; break; + case MCFragment::FT_CoffStaticOffset: + OS << "MCCoffStaticOffsetFragment"; break; case MCFragment::FT_LEB: OS << "MCLEBFragment"; break; } @@ -1114,6 +1146,13 @@ OS << " AddrDelta:" << CF->getAddrDelta(); break; } + case MCFragment::FT_CoffStaticOffset: { + const MCCoffStaticOffsetFragment *LDF = + cast(this); + OS << "\n "; + OS << " Offset:" << LDF->getAddrDelta(); + break; + } case MCFragment::FT_LEB: { const MCLEBFragment *LF = cast(this); OS << "\n "; @@ -1185,3 +1224,4 @@ void MCLEBFragment::anchor() { } void MCDwarfLineAddrFragment::anchor() { } void MCDwarfCallFrameFragment::anchor() { } +void MCCoffStaticOffsetFragment::anchor() { } Index: lib/MC/MCParser/COFFAsmParser.cpp =================================================================== --- lib/MC/MCParser/COFFAsmParser.cpp +++ lib/MC/MCParser/COFFAsmParser.cpp @@ -55,6 +55,8 @@ addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRef>(".secref"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveOffset>(".offset"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce"); // Win64 EH directives. @@ -115,6 +117,8 @@ bool ParseDirectiveType(StringRef, SMLoc); bool ParseDirectiveEndef(StringRef, SMLoc); bool ParseDirectiveSecRel32(StringRef, SMLoc); + bool ParseDirectiveSecRef(StringRef, SMLoc); + bool ParseDirectiveOffset(StringRef, SMLoc); bool parseCOMDATTypeAndAssoc(COFF::COMDATType &Type, const MCSectionCOFF *&Assoc); bool ParseDirectiveLinkOnce(StringRef, SMLoc); @@ -432,7 +436,7 @@ bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) { StringRef SymbolID; if (getParser().parseIdentifier(SymbolID)) - return true; + return TokError("expected identifier in directive"); if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in directive"); @@ -444,6 +448,48 @@ return false; } +bool COFFAsmParser::ParseDirectiveSecRef(StringRef, SMLoc) { + StringRef SymbolID; + if (getParser().parseIdentifier(SymbolID)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID); + + Lex(); + getStreamer().EmitCOFFSectionReference(Symbol); + return false; +} + +bool COFFAsmParser::ParseDirectiveOffset(StringRef, SMLoc) { + StringRef FromSymbolID, ToSymbolID; + if (getLexer().getTok().getString() != "from") + return TokError("expected 'from'"); + Lex(); + + if (getParser().parseIdentifier(FromSymbolID)) + return TokError("expected a label"); + + if (getLexer().getTok().getString() != "to") + return TokError("expected 'to'"); + Lex(); + + if (getParser().parseIdentifier(ToSymbolID)) + return TokError("expected a label"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + MCSymbol *FromSymbol = getContext().GetOrCreateSymbol(FromSymbolID), + *ToSymbol = getContext().GetOrCreateSymbol(ToSymbolID); + + Lex(); + getStreamer().EmitCOFFStaticOffset(FromSymbol, ToSymbol); + return false; +} + /// ::= [ identifier [ identifier ] ] bool COFFAsmParser::parseCOMDATTypeAndAssoc(COFF::COMDATType &Type, const MCSectionCOFF *&Assoc) { Index: lib/MC/MCStreamer.cpp =================================================================== --- lib/MC/MCStreamer.cpp +++ lib/MC/MCStreamer.cpp @@ -566,10 +566,19 @@ EmitLabel(CurFrame->PrologEnd); } +void MCStreamer::EmitCOFFSectionReference(MCSymbol const *Symbol) { + llvm_unreachable("This file format doesn't support this directive"); +} + void MCStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol) { llvm_unreachable("This file format doesn't support this directive"); } +void MCStreamer::EmitCOFFStaticOffset(const MCSymbol *From, + const MCSymbol *To) { + llvm_unreachable("This file format doesn't support this directive"); +} + /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. Index: lib/MC/WinCOFFStreamer.cpp =================================================================== --- lib/MC/WinCOFFStreamer.cpp +++ lib/MC/WinCOFFStreamer.cpp @@ -61,7 +61,9 @@ virtual void EmitCOFFSymbolStorageClass(int StorageClass); virtual void EmitCOFFSymbolType(int Type); virtual void EndCOFFSymbolDef(); + virtual void EmitCOFFSectionReference(MCSymbol const *Symbol); virtual void EmitCOFFSecRel32(MCSymbol const *Symbol); + virtual void EmitCOFFStaticOffset(const MCSymbol *From, const MCSymbol *To); virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value); virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment); @@ -249,6 +251,17 @@ CurSymbol = NULL; } +void WinCOFFStreamer::EmitCOFFSectionReference(MCSymbol const *Symbol) +{ + MCDataFragment *DF = getOrCreateDataFragment(); + + DF->getFixups().push_back( + MCFixup::Create(DF->getContents().size(), + MCSymbolRefExpr::Create (Symbol, getContext ()), + FK_SecRel_2)); + DF->getContents().resize(DF->getContents().size() + 4, 0); +} + void WinCOFFStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol) { MCDataFragment *DF = getOrCreateDataFragment(); @@ -260,6 +273,18 @@ DF->getContents().resize(DF->getContents().size() + 4, 0); } +void WinCOFFStreamer::EmitCOFFStaticOffset(const MCSymbol *From, + const MCSymbol *To) { + const MCExpr *AddrDelta = BuildSymbolDiff(getContext(), To, From); + int64_t Res; + if (AddrDelta->EvaluateAsAbsolute(Res, getAssembler())) { + EmitIntValue(Res, 4); + return; + } + AddrDelta = ForceExpAbs(AddrDelta); + insert(new MCCoffStaticOffsetFragment(*AddrDelta)); +} + void WinCOFFStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { llvm_unreachable("not implemented"); } Index: lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp =================================================================== --- lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp +++ lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp @@ -65,6 +65,9 @@ if (Is64Bit) return COFF::IMAGE_REL_AMD64_ADDR64; llvm_unreachable("unsupported relocation type"); + case FK_SecRel_2: + return Is64Bit ? COFF::IMAGE_REL_AMD64_SECTION + : COFF::IMAGE_REL_I386_SECTION; case FK_SecRel_4: return Is64Bit ? COFF::IMAGE_REL_AMD64_SECREL : COFF::IMAGE_REL_I386_SECREL; default: Index: test/MC/COFF/secref.s =================================================================== --- /dev/null +++ test/MC/COFF/secref.s @@ -0,0 +1,10 @@ +// RUN: llvm-mc -filetype=obj -triple i686-pc-win32 %s | llvm-readobj -s -sr | FileCheck %s + +// check that we produce the correct relocation for .secref + +Lfoo: + .secref Lfoo + +// CHECK: Relocations [ +// CHECK-NEXT: 0x0 IMAGE_REL_I386_SECTION .text +// CHECK-NEXT: ] Index: test/MC/COFF/static_offset.s =================================================================== --- /dev/null +++ test/MC/COFF/static_offset.s @@ -0,0 +1,16 @@ +// RUN: llvm-mc -filetype=obj -triple i686-pc-win32 %s | llvm-readobj -s -sd | FileCheck %s + +// check that we produce the correct static offset for .offset + +Lfoo: + .offset from L1 to L2 +L1: + nop + nop + nop +L2: + .offset from L1 to L2 + +// CHECK: SectionData ( +// CHECK-NEXT: 0000: 03000000 90909003 000000 +// CHECK-NEXT: )