Index: COFF/Chunks.h =================================================================== --- COFF/Chunks.h +++ COFF/Chunks.h @@ -36,6 +36,7 @@ class DefinedRegular; class ObjFile; class OutputSection; +class RuntimePseudoReloc; class Symbol; // Mask for permissions (discardable, writable, readable, executable, etc). @@ -161,6 +162,8 @@ void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const; + void getRuntimePseudoRelocs(std::vector &Res); + // Called if the garbage collector decides to not include this chunk // in a final output. It's supposed to print out a log message to stdout. void printDiscardedMessage() const; @@ -418,6 +421,53 @@ uint8_t Type; }; +// This is a placeholder Chunk, to allow attaching a DefinedSynthetic to a +// specific place in a section, without any data. This is used for the MinGW +// specific symbol __RUNTIME_PSEUDO_RELOC_LIST_END__, even though the concept +// of an empty chunk isn't MinGW specific. +class EmptyChunk : public Chunk { +public: + EmptyChunk() {} + size_t getSize() const override { return 0; } + void writeTo(uint8_t *Buf) const override {} +}; + +// MinGW specific, for the "automatic import of variables from DLLs" feature. +// This provides the table of runtime pseudo relocations, for variable +// references that turned out to need to be imported from a DLL even though +// the reference didn't use the dllimport attribute. The MinGW runtime will +// process this table after loading, before handling control over to user +// code. +class PseudoRelocTableChunk : public Chunk { +public: + PseudoRelocTableChunk(std::vector &Relocs) + : Relocs(std::move(Relocs)) { + Alignment = 4; + } + size_t getSize() const override; + void writeTo(uint8_t *Buf) const override; + +private: + std::vector Relocs; +}; + +// MinGW specific; information about one individual location in the image +// that needs to be fixed up at runtime after loading. This represents +// one individual element in the PseudoRelocTableChunk table. +class RuntimePseudoReloc { +public: + RuntimePseudoReloc(Defined *Sym, SectionChunk *Target, uint32_t TargetOffset, + int Flags) + : Sym(Sym), Target(Target), TargetOffset(TargetOffset), Flags(Flags) {} + + Defined *Sym; + SectionChunk *Target; + uint32_t TargetOffset; + // The Flags field contains the size of the relocation, in bits. No other + // flags are currently defined. + int Flags; +}; + void applyMOV32T(uint8_t *Off, uint32_t V); void applyBranch24T(uint8_t *Off, int32_t V); Index: COFF/Chunks.cpp =================================================================== --- COFF/Chunks.cpp +++ COFF/Chunks.cpp @@ -425,6 +425,111 @@ } } +// MinGW specific. +// Check whether a static relocation of type Type can be deferred and +// handled at runtime as a pseudo relocation (for references to a module +// local variable, which turned out to actually need to be imported from +// another DLL) This returns the size the relocation is supposed to update, +// in bits, or 0 if the relocation cannot be handled as a runtime pseudo +// relocation. +static int getRuntimePseudoRelocSize(uint16_t Type) { + // Relocations that either contain an absolute address, or a plain + // relative offset, since the runtime pseudo reloc implementation + // adds 8/16/32/64 bit values to a memory address. + // + // Given a pseudo relocation entry, + // + // typedef struct { + // DWORD sym; + // DWORD target; + // DWORD flags; + // } runtime_pseudo_reloc_item_v2; + // + // the runtime relocation performs this adjustment: + // *(base + .target) += *(base + .sym) - (base + .sym) + // + // This works for both absolute addresses (IMAGE_REL_*_ADDR32/64, + // IMAGE_REL_I386_DIR32, where the memory location initially contains + // the address of the IAT slot, and for relative addresses (IMAGE_REL*_REL32), + // where the memory location originally contains the relative offset to the + // IAT slot. + // + // This requires the target address to be writable, either directly out of + // the image, or temporarily changed at runtime with VirtualProtect. + // Since this only operates on direct address values, it doesn't work for + // ARM/ARM64 relocations, other than the plain ADDR32/ADDR64 relocations. + switch (Config->Machine) { + case AMD64: + switch (Type) { + case IMAGE_REL_AMD64_ADDR64: + return 64; + case IMAGE_REL_AMD64_ADDR32: + case IMAGE_REL_AMD64_REL32: + case IMAGE_REL_AMD64_REL32_1: + case IMAGE_REL_AMD64_REL32_2: + case IMAGE_REL_AMD64_REL32_3: + case IMAGE_REL_AMD64_REL32_4: + case IMAGE_REL_AMD64_REL32_5: + return 32; + default: + return 0; + } + case I386: + switch (Type) { + case IMAGE_REL_I386_DIR32: + case IMAGE_REL_I386_REL32: + return 32; + default: + return 0; + } + case ARMNT: + switch (Type) { + case IMAGE_REL_ARM_ADDR32: + return 32; + default: + return 0; + } + case ARM64: + switch (Type) { + case IMAGE_REL_ARM64_ADDR64: + return 64; + case IMAGE_REL_ARM64_ADDR32: + return 32; + default: + return 0; + } + default: + llvm_unreachable("unknown machine type"); + } +} + +// MinGW specific. +// Append information to the provided vector about all relocations that +// need to be handled at runtime as runtime pseudo relocations (references +// to a module local variable, which turned out to actually need to be +// imported from another DLL). +void SectionChunk::getRuntimePseudoRelocs( + std::vector &Res) { + for (const coff_relocation &Rel : Relocs) { + auto *Target = dyn_cast_or_null( + File->getSymbol(Rel.SymbolTableIndex)); + if (!Target || !Target->IsRuntimePseudoReloc) + continue; + int SizeInBits = getRuntimePseudoRelocSize(Rel.Type); + if (SizeInBits == 0) { + error("unable to automatically import from " + Target->getName() + + " with relocation type " + + File->getCOFFObj()->getRelocationTypeName(Rel.Type) + " in " + + toString(File)); + continue; + } + // SizeInBits is used to initialize the Flags field; currently no + // other flags are defined. + Res.emplace_back( + RuntimePseudoReloc(Target, this, Rel.VirtualAddress, SizeInBits)); + } +} + bool SectionChunk::hasData() const { return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA); } @@ -543,6 +648,34 @@ "RVA tables should be de-duplicated"); } +// MinGW specific, for the "automatic import of variables from DLLs" feature. +size_t PseudoRelocTableChunk::getSize() const { + if (Relocs.empty()) + return 0; + return 12 + 12 * Relocs.size(); +} + +// MinGW specific. +void PseudoRelocTableChunk::writeTo(uint8_t *Buf) const { + if (Relocs.empty()) + return; + + ulittle32_t *Table = reinterpret_cast(Buf + OutputSectionOff); + // This is the list header, to signal the runtime pseudo relocation v2 + // format. + Table[0] = 0; + Table[1] = 0; + Table[2] = 1; + + size_t Idx = 3; + for (const RuntimePseudoReloc &RPR : Relocs) { + Table[Idx + 0] = RPR.Sym->getRVA(); + Table[Idx + 1] = RPR.Target->getRVA() + RPR.TargetOffset; + Table[Idx + 2] = RPR.Flags; + Idx += 3; + } +} + // Windows-specific. This class represents a block in .reloc section. // The format is described here. // Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -1372,6 +1372,11 @@ // Needed for MSVC 2017 15.5 CRT. Symtab->addAbsolute(mangle("__enclave_config"), 0); + if (Config->MinGW) { + Symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0); + Symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0); + } + // This code may add new undefined symbols to the link, which may enqueue more // symbol resolution tasks, so we need to continue executing tasks until we // converge. @@ -1416,6 +1421,24 @@ Symtab->addCombinedLTOObjects(); run(); + if (Config->MinGW) { + // Load any further object files that might be needed for doing automatic + // imports. + // + // For cases with no automatically imported symbols, this iterates once + // over the symbol table and doesn't do anything. + // + // For the normal case with a few automatically imported symbols, this + // should only need to be run once, since each new object file imported + // is an import library and wouldn't add any new undefined references, + // but there's nothing stopping the __imp_ symbols from coming from a + // normal object file as well (although that won't be used for the + // actual autoimport later on). If this pass adds new undefined references, + // we won't iterate further to resolve them. + Symtab->loadMinGWAutomaticImports(); + run(); + } + // Make sure we have resolved all symbols. Symtab->reportRemainingUndefines(); if (errorCount()) Index: COFF/SymbolTable.h =================================================================== --- COFF/SymbolTable.h +++ COFF/SymbolTable.h @@ -54,6 +54,9 @@ // symbols. void reportRemainingUndefines(); + void loadMinGWAutomaticImports(); + bool handleMinGWAutomaticImport(Symbol *Sym, StringRef Name); + // Returns a list of chunks of selected symbols. std::vector getChunks(); Index: COFF/SymbolTable.cpp =================================================================== --- COFF/SymbolTable.cpp +++ COFF/SymbolTable.cpp @@ -125,6 +125,53 @@ return OS.str(); } +void SymbolTable::loadMinGWAutomaticImports() { + for (auto &I : SymMap) { + Symbol *Sym = I.second; + auto *Undef = dyn_cast(Sym); + if (!Undef) + continue; + if (!Sym->IsUsedInRegularObj) + continue; + + StringRef Name = Undef->getName(); + + if (Name.startswith("__imp_")) + continue; + // If we have an undefined symbol, but we have a Lazy representing a + // symbol we could load from file, make sure to load that. + Lazy *L = dyn_cast_or_null(find(("__imp_" + Name).str())); + if (!L || L->PendingArchiveLoad) + continue; + + log("Loading lazy " + L->getName() + " from " + L->File->getName() + + " for automatic import"); + L->PendingArchiveLoad = true; + L->File->addMember(&L->Sym); + } +} + +bool SymbolTable::handleMinGWAutomaticImport(Symbol *Sym, StringRef Name) { + if (Name.startswith("__imp_")) + return false; + DefinedImportData *Imp = + dyn_cast_or_null(find(("__imp_" + Name).str())); + if (!Imp) + return false; + + log("Automatically importing " + Name + " from " + Imp->getDLLName()); + + // Replace the reference directly to a variable with a reference + // to the import address table instead. This obviously isn't right, + // but we mark the symbol as IsRuntimePseudoReloc, and a later pass + // will add runtime pseudo relocations for every relocation against + // this Symbol. The runtime pseudo relocation framework expects the + // reference itself to point at the IAT entry. + Sym->replaceKeepingName(Imp, sizeof(DefinedImportData)); + cast(Sym)->IsRuntimePseudoReloc = true; + return true; +} + void SymbolTable::reportRemainingUndefines() { SmallPtrSet Undefs; DenseMap LocalImports; @@ -168,6 +215,9 @@ } } + if (Config->MinGW && handleMinGWAutomaticImport(Sym, Name)) + continue; + // Remaining undefined symbols are not fatal if /force is specified. // They are replaced with dummy defined symbols. if (Config->Force) Index: COFF/Symbols.h =================================================================== --- COFF/Symbols.h +++ COFF/Symbols.h @@ -66,6 +66,8 @@ // Returns the symbol name. StringRef getName(); + void replaceKeepingName(Symbol *Other, size_t Size); + // Returns the file from which this symbol was created. InputFile *getFile(); @@ -307,6 +309,8 @@ uint16_t getOrdinal() { return File->Hdr->OrdinalHint; } ImportFile *File; + + bool IsRuntimePseudoReloc = false; }; // This class represents a symbol for a jump table entry which jumps Index: COFF/Symbols.cpp =================================================================== --- COFF/Symbols.cpp +++ COFF/Symbols.cpp @@ -63,6 +63,13 @@ return true; } +// MinGW specific. +void Symbol::replaceKeepingName(Symbol *Other, size_t Size) { + StringRef OrigName = Name; + memcpy(this, Other, Size); + Name = OrigName; +} + COFFSymbolRef DefinedCOFF::getCOFFSymbol() { size_t SymSize = cast(File)->getCOFFObj()->getSymbolTableEntrySize(); if (SymSize == sizeof(coff_symbol16)) Index: COFF/Writer.cpp =================================================================== --- COFF/Writer.cpp +++ COFF/Writer.cpp @@ -158,6 +158,7 @@ void openFile(StringRef OutputPath); template void writeHeader(); void createSEHTable(); + void createRuntimePseudoRelocs(); void createGuardCFTables(); void markSymbolsForRVATable(ObjFile *File, ArrayRef SymIdxChunks, @@ -524,6 +525,9 @@ // Create /guard:cf tables if requested. if (Config->GuardCF != GuardCFLevel::Off) createGuardCFTables(); + + if (Config->MinGW) + createRuntimePseudoRelocs(); } // Create .idata section for the DLL-imported symbol table. @@ -1140,6 +1144,35 @@ cast(C)->setVA(TableChunk->getSize() / 4); } +// MinGW specific. Gather all relocations that are imported from a DLL even +// though the code didn't expect it to, produce the table that the runtime +// uses for fixing them up, and provide the synthetic symbols that the +// runtime uses for finding the table. +void Writer::createRuntimePseudoRelocs() { + std::vector RuntimePseudoRelocs; + + for (Chunk *C : Symtab->getChunks()) { + auto *SC = dyn_cast(C); + if (!SC || !SC->isLive()) + continue; + SC->getRuntimePseudoRelocs(RuntimePseudoRelocs); + } + + if (!RuntimePseudoRelocs.empty()) + log("Writing " + Twine(RuntimePseudoRelocs.size()) + + " runtime pseudo relocations"); + PseudoRelocTableChunk *Table = + make(RuntimePseudoRelocs); + RdataSec->addChunk(Table); + EmptyChunk *EndOfList = make(); + RdataSec->addChunk(EndOfList); + + Symbol *HeadSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__"); + Symbol *EndSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__"); + replaceSymbol(HeadSym, HeadSym->getName(), Table); + replaceSymbol(EndSym, EndSym->getName(), EndOfList); +} + // Handles /section options to allow users to overwrite // section attributes. void Writer::setSectionPermissions() { Index: test/COFF/autoimport-arm-code.s =================================================================== --- /dev/null +++ test/COFF/autoimport-arm-code.s @@ -0,0 +1,19 @@ +# REQUIRES: arm + +# RUN: echo -e ".global variable\n.global DllMainCRTStartup\n.thumb\n.text\nDllMainCRTStartup:\nbx lr\n.data\nvariable:\n.long 42" > %t-lib.s +# RUN: llvm-mc -triple=armv7-windows-gnu %t-lib.s -filetype=obj -o %t-lib.obj +# RUN: lld-link -out:%t-lib.dll -dll -entry:DllMainCRTStartup %t-lib.obj -lldmingw -implib:%t-lib.lib + +# RUN: llvm-mc -triple=armv7-windows-gnu %s -filetype=obj -o %t.obj +# RUN: not lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib 2>&1 | FileCheck %s + +# CHECK: error: unable to automatically import from variable with relocation type IMAGE_REL_ARM_MOV32T + + .global main + .text + .thumb +main: + movw r0, :lower16:variable + movt r0, :upper16:variable + ldr r0, [r0] + bx lr Index: test/COFF/autoimport-arm-data.s =================================================================== --- /dev/null +++ test/COFF/autoimport-arm-data.s @@ -0,0 +1,42 @@ +# REQUIRES: arm + +# RUN: echo -e ".global variable\n.global DllMainCRTStartup\n.thumb\n.text\nDllMainCRTStartup:\nbx lr\n.data\nvariable:\n.long 42" > %t-lib.s +# RUN: llvm-mc -triple=armv7-windows-gnu %t-lib.s -filetype=obj -o %t-lib.obj +# RUN: lld-link -out:%t-lib.dll -dll -entry:DllMainCRTStartup %t-lib.obj -lldmingw -implib:%t-lib.lib + +# RUN: llvm-mc -triple=armv7-windows-gnu %s -filetype=obj -o %t.obj +# RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose + +# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s +# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s + +# IMPORTS: Import { +# IMPORTS-NEXT: Name: autoimport-arm-data.s.tmp-lib.dll +# IMPORTS-NEXT: ImportLookupTableRVA: 0x2040 +# IMPORTS-NEXT: ImportAddressTableRVA: 0x2048 +# IMPORTS-NEXT: Symbol: variable (0) +# IMPORTS-NEXT: } + +# Runtime pseudo reloc list header consisting of 0x0, 0x0, 0x1. +# First runtime pseudo reloc, with import from 0x2048, +# applied at 0x3000, with a size of 32 bits. +# CONTENTS: Contents of section .rdata: +# CONTENTS: 402000 00000000 00000000 01000000 48200000 +# CONTENTS: 402010 00300000 20000000 +# ptr: pointing at the IAT RVA at 0x2048 +# relocs: pointing at the runtime pseudo reloc list at +# 0x2000 - 0x2018. +# CONTENTS: Contents of section .data: +# CONTENTS: 403000 48204000 00204000 18204000 + + .global main + .text + .thumb +main: + bx lr + .data +ptr: + .long variable +relocs: + .long __RUNTIME_PSEUDO_RELOC_LIST__ + .long __RUNTIME_PSEUDO_RELOC_LIST_END__ Index: test/COFF/autoimport-arm64-code.s =================================================================== --- /dev/null +++ test/COFF/autoimport-arm64-code.s @@ -0,0 +1,18 @@ +# REQUIRES: aarch64 + +# RUN: echo -e ".global variable\n.global DllMainCRTStartup\n.text\nDllMainCRTStartup:\nret\n.data\nvariable:\n.long 42" > %t-lib.s +# RUN: llvm-mc -triple=aarch64-windows-gnu %t-lib.s -filetype=obj -o %t-lib.obj +# RUN: lld-link -out:%t-lib.dll -dll -entry:DllMainCRTStartup %t-lib.obj -lldmingw -implib:%t-lib.lib + +# RUN: llvm-mc -triple=aarch64-windows-gnu %s -filetype=obj -o %t.obj +# RUN: not lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib 2>&1 | FileCheck %s + +# CHECK: error: unable to automatically import from variable with relocation type IMAGE_REL_ARM64_PAGEBASE_REL21 +# CHECK: error: unable to automatically import from variable with relocation type IMAGE_REL_ARM64_PAGEOFFSET_12L + + .global main + .text +main: + adrp x0, variable + ldr w0, [x0, :lo12:variable] + ret Index: test/COFF/autoimport-arm64-data.s =================================================================== --- /dev/null +++ test/COFF/autoimport-arm64-data.s @@ -0,0 +1,42 @@ +# REQUIRES: aarch64 + +# RUN: echo -e ".global variable\n.global DllMainCRTStartup\n.text\nDllMainCRTStartup:\nret\n.data\nvariable:\n.long 42" > %t-lib.s +# RUN: llvm-mc -triple=aarch64-windows-gnu %t-lib.s -filetype=obj -o %t-lib.obj +# RUN: lld-link -out:%t-lib.dll -dll -entry:DllMainCRTStartup %t-lib.obj -lldmingw -implib:%t-lib.lib + +# RUN: llvm-mc -triple=aarch64-windows-gnu %s -filetype=obj -o %t.obj +# RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose + +# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s +# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s + +# IMPORTS: Import { +# IMPORTS-NEXT: Name: autoimport-arm64-data.s.tmp-lib.dll +# IMPORTS-NEXT: ImportLookupTableRVA: 0x2040 +# IMPORTS-NEXT: ImportAddressTableRVA: 0x2050 +# IMPORTS-NEXT: Symbol: variable (0) +# IMPORTS-NEXT: } + +# Runtime pseudo reloc list header consisting of 0x0, 0x0, 0x1. +# First runtime pseudo reloc, with import from 0x2050, +# applied at 0x3000, with a size of 32 bits. +# CONTENTS: Contents of section .rdata: +# CONTENTS: 140002000 00000000 00000000 01000000 50200000 +# CONTENTS: 140002010 00300000 40000000 +# ptr: pointing at the IAT RVA at 0x2050 +# relocs: pointing at the runtime pseudo reloc list at +# 0x2000 - 0x2018. +# CONTENTS: Contents of section .data: +# CONTENTS: 140003000 50200040 01000000 00200040 01000000 +# CONTENTS: 140003010 18200040 01000000 + + .global main + .text +main: + ret + .data +ptr: + .quad variable +relocs: + .quad __RUNTIME_PSEUDO_RELOC_LIST__ + .quad __RUNTIME_PSEUDO_RELOC_LIST_END__ Index: test/COFF/autoimport-list-ptrs.s =================================================================== --- /dev/null +++ test/COFF/autoimport-list-ptrs.s @@ -0,0 +1,20 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj +# RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj -verbose + +# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s + +# Even if we didn't actually write any pseudo relocations, +# check that the synthetic pointers still are set to a non-null value +# CONTENTS: Contents of section .data: +# CONTENTS: 140002000 00200040 01000000 00200040 01000000 + + .global main + .text +main: + retq + .data +relocs: + .quad __RUNTIME_PSEUDO_RELOC_LIST__ + .quad __RUNTIME_PSEUDO_RELOC_LIST_END__ Index: test/COFF/autoimport-x86.s =================================================================== --- /dev/null +++ test/COFF/autoimport-x86.s @@ -0,0 +1,53 @@ +# REQUIRES: x86 + +# RUN: echo -e ".global variable\n.global DllMainCRTStartup\n.text\nDllMainCRTStartup:\nret\n.data\nvariable:\n.long 42" > %t-lib.s +# RUN: llvm-mc -triple=x86_64-windows-gnu %t-lib.s -filetype=obj -o %t-lib.obj +# RUN: lld-link -out:%t-lib.dll -dll -entry:DllMainCRTStartup %t-lib.obj -lldmingw -implib:%t-lib.lib + +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj +# RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose + +# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s +# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s +# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s + +# IMPORTS: Import { +# IMPORTS-NEXT: Name: autoimport-x86.s.tmp-lib.dll +# IMPORTS-NEXT: ImportLookupTableRVA: 0x2050 +# IMPORTS-NEXT: ImportAddressTableRVA: 0x2060 +# IMPORTS-NEXT: Symbol: variable (0) +# IMPORTS-NEXT: } + +# DISASM: Disassembly of section .text: +# DISASM: .text: +# Relative offset at 0x1002 pointing at the IAT at 0x2060. +# DISASM: 140001000: 8b 05 5a 10 00 00 movl 4186(%rip), %eax +# DISASM: 140001006: c3 retq + +# Runtime pseudo reloc list header consisting of 0x0, 0x0, 0x1. +# First runtime pseudo reloc, with import from 0x2060, +# applied at 0x1002, with a size of 32 bits. +# Second runtime pseudo reloc, with import from 0x2060, +# applied at 0x3000, with a size of 64 bits. +# CONTENTS: Contents of section .rdata: +# CONTENTS: 140002000 00000000 00000000 01000000 60200000 +# CONTENTS: 140002010 02100000 20000000 60200000 00300000 +# CONTENTS: 140002020 40000000 +# ptr: pointing at the IAT RVA at 0x2060 +# relocs: pointing at the runtime pseudo reloc list at +# 0x2000 - 0x2024. +# CONTENTS: Contents of section .data: +# CONTENTS: 140003000 60200040 01000000 00200040 01000000 +# CONTENTS: 140003010 24200040 01000000 + + .global main + .text +main: + movl variable(%rip), %eax + ret + .data +ptr: + .quad variable +relocs: + .quad __RUNTIME_PSEUDO_RELOC_LIST__ + .quad __RUNTIME_PSEUDO_RELOC_LIST_END__