[lld] r340726 - [COFF] Support MinGW automatic dllimport of data

Martin Storsjo via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 27 01:43:32 PDT 2018


Author: mstorsjo
Date: Mon Aug 27 01:43:31 2018
New Revision: 340726

URL: http://llvm.org/viewvc/llvm-project?rev=340726&view=rev
Log:
[COFF] Support MinGW automatic dllimport of data

Normally, in order to reference exported data symbols from a different
DLL, the declarations need to have the dllimport attribute, in order to
use the __imp_<var> symbol (which contains an address to the actual
variable) instead of the variable itself directly. This isn't an issue
in the same way for functions, since any reference to the function without
the dllimport attribute will end up as a reference to a thunk which loads
the actual target function from the import address table (IAT).

GNU ld, in MinGW environments, supports automatically importing data
symbols from DLLs, even if the references didn't have the appropriate
dllimport attribute. Since the PE/COFF format doesn't support the kind
of relocations that this would require, the MinGW's CRT startup code
has an custom framework of their own for manually fixing the missing
relocations once module is loaded and the target addresses in the IAT
are known.

For this to work, the linker (originall in GNU ld) creates a list of
remaining references needing fixup, which the runtime processes on
startup before handing over control to user code.

While this feature is rather controversial, it's one of the main features
allowing unix style libraries to be used on windows without any extra
porting effort.

Some sort of automatic fixing of data imports is also necessary for the
itanium C++ ABI on windows (as clang implements it right now) for importing
vtable pointers in certain cases, see D43184 for some discussion on that.

The runtime pseudo relocation handler supports 8/16/32/64 bit addresses,
either PC relative references (like IMAGE_REL_*_REL32*) or absolute
references (IMAGE_REL_AMD64_ADDR32, IMAGE_REL_AMD64_ADDR32,
IMAGE_REL_I386_DIR32). On linking, the relocation is handled as a
relocation against the corresponding IAT slot. For the absolute references,
a normal base relocation is created, to update the embedded address
in case the image is loaded at a different address.

The list of runtime pseudo relocations contains the RVA of the
imported symbol (the IAT slot), the RVA of the location the relocation
should be applied to, and a size of the memory location. When the
relocations are fixed at runtime, the difference between the actual
IAT slot value and the IAT slot address is added to the reference,
doing the right thing for both absolute and relative references.

With this patch alone, things work fine for i386 binaries, and mostly
for x86_64 binaries, with feature parity with GNU ld. Despite this,
there are a few gotchas:
- References to data from within code works fine on both x86 architectures,
  since their relocations consist of plain 32 or 64 bit absolute/relative
  references. On ARM and AArch64, references to data doesn't consist of
  a plain 32 or 64 bit embedded address or offset in the code. On ARMNT,
  it's usually a MOVW+MOVT instruction pair represented by a
  IMAGE_REL_ARM_MOV32T relocation, each instruction containing 16 bit of
  the target address), on AArch64, it's usually an ADRP+ADD/LDR/STR
  instruction pair with an even more complex encoding, storing a PC
  relative address (with a range of +/- 4 GB). This could theoretically
  be remedied by extending the runtime pseudo relocation handler with new
  relocation types, to support these instruction encodings. This isn't an
  issue for GCC/GNU ld since they don't support windows on ARMNT/AArch64.
- For x86_64, if references in code are encoded as 32 bit PC relative
  offsets, the runtime relocation will fail if the target turns out to be
  out of range for a 32 bit offset.
- Fixing up the relocations at runtime requires making sections writable
  if necessary, with the VirtualProtect function. In Windows Store/UWP apps,
  this function is forbidden.

These limitations are addressed by a few later patches in lld and
llvm.

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

Added:
    lld/trunk/test/COFF/autoimport-arm-code.s
    lld/trunk/test/COFF/autoimport-arm-data.s
    lld/trunk/test/COFF/autoimport-arm64-code.s
    lld/trunk/test/COFF/autoimport-arm64-data.s
    lld/trunk/test/COFF/autoimport-list-ptrs.s
    lld/trunk/test/COFF/autoimport-x86.s
Modified:
    lld/trunk/COFF/Chunks.cpp
    lld/trunk/COFF/Chunks.h
    lld/trunk/COFF/Driver.cpp
    lld/trunk/COFF/SymbolTable.cpp
    lld/trunk/COFF/SymbolTable.h
    lld/trunk/COFF/Symbols.cpp
    lld/trunk/COFF/Symbols.h
    lld/trunk/COFF/Writer.cpp

Modified: lld/trunk/COFF/Chunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.cpp?rev=340726&r1=340725&r2=340726&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.cpp (original)
+++ lld/trunk/COFF/Chunks.cpp Mon Aug 27 01:43:31 2018
@@ -421,6 +421,111 @@ void SectionChunk::getBaserels(std::vect
   }
 }
 
+// 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<RuntimePseudoReloc> &Res) {
+  for (const coff_relocation &Rel : Relocs) {
+    auto *Target = dyn_cast_or_null<DefinedImportData>(
+        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);
 }
@@ -539,6 +644,34 @@ void RVATableChunk::writeTo(uint8_t *Buf
          "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<ulittle32_t *>(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.
 //

Modified: lld/trunk/COFF/Chunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.h?rev=340726&r1=340725&r2=340726&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.h (original)
+++ lld/trunk/COFF/Chunks.h Mon Aug 27 01:43:31 2018
@@ -36,6 +36,7 @@ class DefinedImportData;
 class DefinedRegular;
 class ObjFile;
 class OutputSection;
+class RuntimePseudoReloc;
 class Symbol;
 
 // Mask for permissions (discardable, writable, readable, executable, etc).
@@ -161,6 +162,8 @@ public:
   void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
                      uint64_t P) const;
 
+  void getRuntimePseudoRelocs(std::vector<RuntimePseudoReloc> &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 @@ public:
   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<RuntimePseudoReloc> &Relocs)
+      : Relocs(std::move(Relocs)) {
+    Alignment = 4;
+  }
+  size_t getSize() const override;
+  void writeTo(uint8_t *Buf) const override;
+
+private:
+  std::vector<RuntimePseudoReloc> 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);
 

Modified: lld/trunk/COFF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=340726&r1=340725&r2=340726&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.cpp (original)
+++ lld/trunk/COFF/Driver.cpp Mon Aug 27 01:43:31 2018
@@ -1367,6 +1367,11 @@ void LinkerDriver::link(ArrayRef<const c
   // 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.
@@ -1411,6 +1416,24 @@ void LinkerDriver::link(ArrayRef<const c
   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())

Modified: lld/trunk/COFF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.cpp?rev=340726&r1=340725&r2=340726&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.cpp (original)
+++ lld/trunk/COFF/SymbolTable.cpp Mon Aug 27 01:43:31 2018
@@ -125,6 +125,53 @@ static std::string getSymbolLocations(Ob
   return OS.str();
 }
 
+void SymbolTable::loadMinGWAutomaticImports() {
+  for (auto &I : SymMap) {
+    Symbol *Sym = I.second;
+    auto *Undef = dyn_cast<Undefined>(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<Lazy>(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<DefinedImportData>(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<DefinedImportData>(Sym)->IsRuntimePseudoReloc = true;
+  return true;
+}
+
 void SymbolTable::reportRemainingUndefines() {
   SmallPtrSet<Symbol *, 8> Undefs;
   DenseMap<Symbol *, Symbol *> LocalImports;
@@ -168,6 +215,9 @@ void SymbolTable::reportRemainingUndefin
       }
     }
 
+    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)

Modified: lld/trunk/COFF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.h?rev=340726&r1=340725&r2=340726&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.h (original)
+++ lld/trunk/COFF/SymbolTable.h Mon Aug 27 01:43:31 2018
@@ -54,6 +54,9 @@ public:
   // symbols.
   void reportRemainingUndefines();
 
+  void loadMinGWAutomaticImports();
+  bool handleMinGWAutomaticImport(Symbol *Sym, StringRef Name);
+
   // Returns a list of chunks of selected symbols.
   std::vector<Chunk *> getChunks();
 

Modified: lld/trunk/COFF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Symbols.cpp?rev=340726&r1=340725&r2=340726&view=diff
==============================================================================
--- lld/trunk/COFF/Symbols.cpp (original)
+++ lld/trunk/COFF/Symbols.cpp Mon Aug 27 01:43:31 2018
@@ -63,6 +63,13 @@ bool Symbol::isLive() const {
   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<ObjFile>(File)->getCOFFObj()->getSymbolTableEntrySize();
   if (SymSize == sizeof(coff_symbol16))

Modified: lld/trunk/COFF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Symbols.h?rev=340726&r1=340725&r2=340726&view=diff
==============================================================================
--- lld/trunk/COFF/Symbols.h (original)
+++ lld/trunk/COFF/Symbols.h Mon Aug 27 01:43:31 2018
@@ -66,6 +66,8 @@ public:
   // 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 @@ public:
   uint16_t getOrdinal() { return File->Hdr->OrdinalHint; }
 
   ImportFile *File;
+
+  bool IsRuntimePseudoReloc = false;
 };
 
 // This class represents a symbol for a jump table entry which jumps

Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=340726&r1=340725&r2=340726&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Mon Aug 27 01:43:31 2018
@@ -158,6 +158,7 @@ private:
   void openFile(StringRef OutputPath);
   template <typename PEHeaderTy> void writeHeader();
   void createSEHTable();
+  void createRuntimePseudoRelocs();
   void createGuardCFTables();
   void markSymbolsForRVATable(ObjFile *File,
                               ArrayRef<SectionChunk *> SymIdxChunks,
@@ -524,6 +525,9 @@ void Writer::createMiscChunks() {
   // 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,33 @@ void Writer::maybeAddRVATable(SymbolRVAS
   cast<DefinedAbsolute>(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<RuntimePseudoReloc> Rels;
+
+  for (Chunk *C : Symtab->getChunks()) {
+    auto *SC = dyn_cast<SectionChunk>(C);
+    if (!SC || !SC->isLive())
+      continue;
+    SC->getRuntimePseudoRelocs(Rels);
+  }
+
+  if (!Rels.empty())
+    log("Writing " + Twine(Rels.size()) + " runtime pseudo relocations");
+  PseudoRelocTableChunk *Table = make<PseudoRelocTableChunk>(Rels);
+  RdataSec->addChunk(Table);
+  EmptyChunk *EndOfList = make<EmptyChunk>();
+  RdataSec->addChunk(EndOfList);
+
+  Symbol *HeadSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__");
+  Symbol *EndSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__");
+  replaceSymbol<DefinedSynthetic>(HeadSym, HeadSym->getName(), Table);
+  replaceSymbol<DefinedSynthetic>(EndSym, EndSym->getName(), EndOfList);
+}
+
 // Handles /section options to allow users to overwrite
 // section attributes.
 void Writer::setSectionPermissions() {

Added: lld/trunk/test/COFF/autoimport-arm-code.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/autoimport-arm-code.s?rev=340726&view=auto
==============================================================================
--- lld/trunk/test/COFF/autoimport-arm-code.s (added)
+++ lld/trunk/test/COFF/autoimport-arm-code.s Mon Aug 27 01:43:31 2018
@@ -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

Added: lld/trunk/test/COFF/autoimport-arm-data.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/autoimport-arm-data.s?rev=340726&view=auto
==============================================================================
--- lld/trunk/test/COFF/autoimport-arm-data.s (added)
+++ lld/trunk/test/COFF/autoimport-arm-data.s Mon Aug 27 01:43:31 2018
@@ -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__

Added: lld/trunk/test/COFF/autoimport-arm64-code.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/autoimport-arm64-code.s?rev=340726&view=auto
==============================================================================
--- lld/trunk/test/COFF/autoimport-arm64-code.s (added)
+++ lld/trunk/test/COFF/autoimport-arm64-code.s Mon Aug 27 01:43:31 2018
@@ -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

Added: lld/trunk/test/COFF/autoimport-arm64-data.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/autoimport-arm64-data.s?rev=340726&view=auto
==============================================================================
--- lld/trunk/test/COFF/autoimport-arm64-data.s (added)
+++ lld/trunk/test/COFF/autoimport-arm64-data.s Mon Aug 27 01:43:31 2018
@@ -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__

Added: lld/trunk/test/COFF/autoimport-list-ptrs.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/autoimport-list-ptrs.s?rev=340726&view=auto
==============================================================================
--- lld/trunk/test/COFF/autoimport-list-ptrs.s (added)
+++ lld/trunk/test/COFF/autoimport-list-ptrs.s Mon Aug 27 01:43:31 2018
@@ -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__

Added: lld/trunk/test/COFF/autoimport-x86.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/autoimport-x86.s?rev=340726&view=auto
==============================================================================
--- lld/trunk/test/COFF/autoimport-x86.s (added)
+++ lld/trunk/test/COFF/autoimport-x86.s Mon Aug 27 01:43:31 2018
@@ -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__




More information about the llvm-commits mailing list