Skip to content

Commit

Permalink
[MC] Add support for the .rva assembler directive for COFF targets
Browse files Browse the repository at this point in the history
Even though gas doesn't document it, it has been supported there for
a very long time.

This produces the 32 bit relative virtual address (aka image relative
address) for a given symbol. ".rva foo" is essentially equal to
".long foo@imgrel".

Differential Revision: https://reviews.llvm.org/D49821

llvm-svn: 338063
  • Loading branch information
mstorsjo committed Jul 26, 2018
1 parent e6e75bf commit 390bce4
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 2 deletions.
5 changes: 5 additions & 0 deletions llvm/include/llvm/MC/MCStreamer.h
Expand Up @@ -522,6 +522,11 @@ class MCStreamer {
/// \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:
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/MC/MCWinCOFFStreamer.h
Expand Up @@ -54,6 +54,7 @@ class MCWinCOFFStreamer : public MCObjectStreamer {
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,
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/MC/MCAsmStreamer.cpp
Expand Up @@ -165,6 +165,7 @@ class MCAsmStreamer final : public MCStreamer {
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;
Expand Down Expand Up @@ -706,6 +707,16 @@ void MCAsmStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) {
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";
Expand Down
33 changes: 33 additions & 0 deletions llvm/lib/MC/MCParser/COFFAsmParser.cpp
Expand Up @@ -69,6 +69,7 @@ class COFFAsmParser : public MCAsmParserExtension {
addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh");
addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx");
addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva");

// Win64 EH directives.
addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
Expand Down Expand Up @@ -134,6 +135,7 @@ class COFFAsmParser : public MCAsmParserExtension {
bool ParseDirectiveSymIdx(StringRef, SMLoc);
bool parseCOMDATType(COFF::COMDATType &Type);
bool ParseDirectiveLinkOnce(StringRef, SMLoc);
bool ParseDirectiveRVA(StringRef, SMLoc);

// Win64 EH directives.
bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
Expand Down Expand Up @@ -492,6 +494,37 @@ bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
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<int32_t>::min() ||
Offset > std::numeric_limits<int32_t>::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))
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/MC/MCStreamer.cpp
Expand Up @@ -830,6 +830,8 @@ void MCStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) {

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.
Expand Down
19 changes: 19 additions & 0 deletions llvm/lib/MC/MCWinCOFFStreamer.cpp
Expand Up @@ -232,6 +232,25 @@ void MCWinCOFFStreamer::EmitCOFFSecRel32(const MCSymbol *Symbol,
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<MCSymbolCOFF>(S);
Expand Down
34 changes: 32 additions & 2 deletions llvm/test/MC/COFF/relocation-imgrel.s
Expand Up @@ -3,27 +3,57 @@
// 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 [
// W32-NEXT: Section (1) .text {
// 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

0 comments on commit 390bce4

Please sign in to comment.