Index: llvm/trunk/include/llvm/MC/MCStreamer.h =================================================================== --- llvm/trunk/include/llvm/MC/MCStreamer.h +++ llvm/trunk/include/llvm/MC/MCStreamer.h @@ -522,6 +522,11 @@ /// \param Symbol - Symbol the section relative relocation should point to. virtual void EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset); + /// Emits a COFF image relative relocation. + /// + /// \param Symbol - Symbol the image relative relocation should point to. + virtual void EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset); + /// Emit an ELF .size directive. /// /// This corresponds to an assembler statement such as: Index: llvm/trunk/include/llvm/MC/MCWinCOFFStreamer.h =================================================================== --- llvm/trunk/include/llvm/MC/MCWinCOFFStreamer.h +++ llvm/trunk/include/llvm/MC/MCWinCOFFStreamer.h @@ -54,6 +54,7 @@ void EmitCOFFSymbolIndex(MCSymbol const *Symbol) override; void EmitCOFFSectionIndex(MCSymbol const *Symbol) override; void EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override; + void EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, Index: llvm/trunk/lib/MC/MCAsmStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCAsmStreamer.cpp +++ llvm/trunk/lib/MC/MCAsmStreamer.cpp @@ -165,6 +165,7 @@ void EmitCOFFSymbolIndex(MCSymbol const *Symbol) override; void EmitCOFFSectionIndex(MCSymbol const *Symbol) override; void EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override; + void EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) override; void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; @@ -706,6 +707,16 @@ EmitEOL(); } +void MCAsmStreamer::EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) { + OS << "\t.rva\t"; + Symbol->print(OS, MAI); + if (Offset > 0) + OS << '+' << Offset; + else if (Offset < 0) + OS << '-' << -Offset; + EmitEOL(); +} + void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { assert(MAI->hasDotTypeDotSizeDirective()); OS << "\t.size\t"; Index: llvm/trunk/lib/MC/MCParser/COFFAsmParser.cpp =================================================================== --- llvm/trunk/lib/MC/MCParser/COFFAsmParser.cpp +++ llvm/trunk/lib/MC/MCParser/COFFAsmParser.cpp @@ -69,6 +69,7 @@ addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva"); // Win64 EH directives. addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>( @@ -134,6 +135,7 @@ bool ParseDirectiveSymIdx(StringRef, SMLoc); bool parseCOMDATType(COFF::COMDATType &Type); bool ParseDirectiveLinkOnce(StringRef, SMLoc); + bool ParseDirectiveRVA(StringRef, SMLoc); // Win64 EH directives. bool ParseSEHDirectiveStartProc(StringRef, SMLoc); @@ -492,6 +494,37 @@ return false; } +bool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) { + auto parseOp = [&]() -> bool { + StringRef SymbolID; + if (getParser().parseIdentifier(SymbolID)) + return TokError("expected identifier in directive"); + + int64_t Offset = 0; + SMLoc OffsetLoc; + if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) { + OffsetLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Offset)) + return true; + } + + if (Offset < std::numeric_limits::min() || + Offset > std::numeric_limits::max()) + return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less " + "than -2147483648 or greater than " + "2147483647"); + + MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); + + getStreamer().EmitCOFFImgRel32(Symbol, Offset); + return false; + }; + + if (getParser().parseMany(parseOp)) + return addErrorSuffix(" in directive"); + return false; +} + bool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) { StringRef SymbolID; if (getParser().parseIdentifier(SymbolID)) Index: llvm/trunk/lib/MC/MCStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCStreamer.cpp +++ llvm/trunk/lib/MC/MCStreamer.cpp @@ -830,6 +830,8 @@ void MCStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) {} +void MCStreamer::EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) {} + /// 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: llvm/trunk/lib/MC/MCWinCOFFStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCWinCOFFStreamer.cpp +++ llvm/trunk/lib/MC/MCWinCOFFStreamer.cpp @@ -232,6 +232,25 @@ DF->getContents().resize(DF->getContents().size() + 4, 0); } +void MCWinCOFFStreamer::EmitCOFFImgRel32(const MCSymbol *Symbol, + int64_t Offset) { + visitUsedSymbol(*Symbol); + MCDataFragment *DF = getOrCreateDataFragment(); + // Create Symbol A for the relocation relative reference. + const MCExpr *MCE = MCSymbolRefExpr::create( + Symbol, MCSymbolRefExpr::VK_COFF_IMGREL32, getContext()); + // Add the constant offset, if given. + if (Offset) + MCE = MCBinaryExpr::createAdd( + MCE, MCConstantExpr::create(Offset, getContext()), getContext()); + // Build the imgrel relocation. + MCFixup Fixup = MCFixup::create(DF->getContents().size(), MCE, FK_Data_4); + // Record the relocation. + DF->getFixups().push_back(Fixup); + // Emit 4 bytes (zeros) to the object file. + DF->getContents().resize(DF->getContents().size() + 4, 0); +} + void MCWinCOFFStreamer::EmitCommonSymbol(MCSymbol *S, uint64_t Size, unsigned ByteAlignment) { auto *Symbol = cast(S); Index: llvm/trunk/test/MC/COFF/relocation-imgrel.s =================================================================== --- llvm/trunk/test/MC/COFF/relocation-imgrel.s +++ llvm/trunk/test/MC/COFF/relocation-imgrel.s @@ -3,15 +3,23 @@ // Test that we produce image-relative relocations (IMAGE_REL_I386_DIR32NB // and IMAGE_REL_AMD64_ADDR32NB) when accessing foo@imgrel. -// RUN: llvm-mc -filetype=obj -triple i686-pc-win32 %s | llvm-readobj -r | FileCheck --check-prefix=W32 %s -// RUN: llvm-mc -filetype=obj -triple x86_64-pc-win32 %s | llvm-readobj -r | FileCheck --check-prefix=W64 %s +// RUN: llvm-mc -filetype=obj -triple i686-pc-win32 %s > %t.w32.obj +// RUN: llvm-readobj -r %t.w32.obj | FileCheck --check-prefix=W32 %s +// RUN: llvm-objdump -s %t.w32.obj | FileCheck --check-prefix=W32OBJ %s +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-win32 %s > %t.w64.obj +// RUN: llvm-readobj -r %t.w64.obj | FileCheck --check-prefix=W64 %s +// RUN: llvm-objdump -s %t.w64.obj | FileCheck --check-prefix=W64OBJ %s .data foo: .long 1 + .long .Llabel@imgrel + .rva .Llabel, .Llabel + 16, foo, .Lother - 3 .text +.Llabel: mov foo@IMGREL(%ebx, %ecx, 4), %eax +.Lother: mov foo@imgrel(%ebx, %ecx, 4), %eax // W32: Relocations [ @@ -19,11 +27,33 @@ // W32-NEXT: 0x3 IMAGE_REL_I386_DIR32NB foo // W32-NEXT: 0xA IMAGE_REL_I386_DIR32NB foo // W32-NEXT: } +// W32-NEXT: Section (2) .data { +// W32-NEXT: 0x4 IMAGE_REL_I386_DIR32NB .Llabel +// W32-NEXT: 0x8 IMAGE_REL_I386_DIR32NB .Llabel +// W32-NEXT: 0xC IMAGE_REL_I386_DIR32NB .Llabel +// W32-NEXT: 0x10 IMAGE_REL_I386_DIR32NB foo +// W32-NEXT: 0x14 IMAGE_REL_I386_DIR32NB .Lother +// W32-NEXT: } // W32-NEXT: ] +// W32OBJ: Contents of section .data: +// W32OBJ-NEXT: 0000 01000000 00000000 00000000 10000000 +// W32OBJ-NEXT: 0010 00000000 fdffffff + // W64: Relocations [ // W64-NEXT: Section (1) .text { // W64-NEXT: 0x4 IMAGE_REL_AMD64_ADDR32NB foo // W64-NEXT: 0xC IMAGE_REL_AMD64_ADDR32NB foo // W64-NEXT: } +// W64-NEXT: Section (2) .data { +// W64-NEXT: 0x4 IMAGE_REL_AMD64_ADDR32NB .text +// W64-NEXT: 0x8 IMAGE_REL_AMD64_ADDR32NB .text +// W64-NEXT: 0xC IMAGE_REL_AMD64_ADDR32NB .text +// W64-NEXT: 0x10 IMAGE_REL_AMD64_ADDR32NB foo +// W64-NEXT: 0x14 IMAGE_REL_AMD64_ADDR32NB .text +// W64-NEXT: } // W64-NEXT: ] + +// W64OBJ: Contents of section .data: +// W64OBJ-NEXT: 0000 01000000 00000000 00000000 10000000 +// W64OBJ-NEXT: 0010 00000000 05000000