[lld] r187388 - [PECOFF] Process Import Name/Type field in the import library.

Rui Ueyama ruiu at google.com
Mon Jul 29 15:55:39 PDT 2013


Author: ruiu
Date: Mon Jul 29 17:55:39 2013
New Revision: 187388

URL: http://llvm.org/viewvc/llvm-project?rev=187388&view=rev
Log:
[PECOFF] Process Import Name/Type field in the import library.

This patch removes hacky mangle() function, which strips all decorations
uncondtitionally. LLD now interprets Import Name/Type field in the import
library properly as described in the Microsoft PE/COFF Spec.

Modified:
    lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h
    lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h
    lld/trunk/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp
    lld/trunk/test/pecoff/Inputs/vars.c
    lld/trunk/test/pecoff/Inputs/vars.lib
    lld/trunk/test/pecoff/importlib.test

Modified: lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h?rev=187388&r1=187387&r2=187388&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h Mon Jul 29 17:55:39 2013
@@ -264,17 +264,23 @@ private:
 // to an import address table entry in Idata pass.
 class COFFSharedLibraryAtom : public SharedLibraryAtom {
 public:
-  COFFSharedLibraryAtom(const File &file, uint16_t hint,
-                        StringRef symbolName, StringRef loadName)
-      : _file(file), _hint(hint), _unmangledName(symbolName),
-        _loadName(loadName), _mangledName(addImpPrefix(symbolName)),
+  COFFSharedLibraryAtom(const File &file, uint16_t hint, StringRef symbolName,
+                        StringRef importName, StringRef dllName)
+      : _file(file), _hint(hint), _mangledName(addImpPrefix(symbolName)),
+        _importName(importName), _dllName(dllName),
         _importTableEntry(nullptr) {}
 
   virtual const File &file() const { return _file; }
   uint16_t hint() const { return _hint; }
+
+  /// Returns the symbol name to be used by the core linker.
   virtual StringRef name() const { return _mangledName; }
-  virtual StringRef unmangledName() const { return _unmangledName; }
-  virtual StringRef loadName() const { return _loadName; }
+
+  /// Returns the symbol name to be used in the import description table in the
+  /// COFF header.
+  virtual StringRef importName() const { return _importName; }
+
+  virtual StringRef loadName() const { return _dllName; }
   virtual bool canBeNullAtRuntime() const { return false; }
 
   void setImportTableEntry(const DefinedAtom *atom) {
@@ -296,9 +302,9 @@ private:
 
   const File &_file;
   uint16_t _hint;
-  StringRef _unmangledName;
-  StringRef _loadName;
   std::string _mangledName;
+  std::string _importName;
+  StringRef _dllName;
   const DefinedAtom *_importTableEntry;
 };
 

Modified: lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h?rev=187388&r1=187387&r2=187388&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h Mon Jul 29 17:55:39 2013
@@ -116,41 +116,41 @@ private:
 /// loader can find the symbol quickly.
 class HintNameAtom : public IdataAtom {
 public:
-  HintNameAtom(Context &ctx, uint16_t hint, StringRef name)
-      : IdataAtom(ctx.file, assembleRawContent(hint, name)), _name(name) {
+  HintNameAtom(Context &ctx, uint16_t hint, StringRef importName)
+      : IdataAtom(ctx.file, assembleRawContent(hint, importName)),
+        _importName(importName) {
     ctx.hintNameAtoms.push_back(this);
   }
 
-  StringRef getContentString() { return _name; }
+  StringRef getContentString() { return _importName; }
 
 private:
   // The first two bytes of the content is a hint, followed by a null-terminated
   // symbol name. The total size needs to be multiple of 2.
-  vector<uint8_t> assembleRawContent(uint16_t hint, StringRef name) {
-    name = unmangle(name);
-    size_t size = llvm::RoundUpToAlignment(sizeof(hint) + name.size() + 1, 2);
+  vector<uint8_t> assembleRawContent(uint16_t hint, StringRef importName) {
+    size_t size = llvm::RoundUpToAlignment(sizeof(hint) + importName.size() + 1, 2);
     vector<uint8_t> ret(size);
-    ret[name.size()] = 0;
-    ret[name.size() - 1] = 0;
+    ret[importName.size()] = 0;
+    ret[importName.size() - 1] = 0;
     *reinterpret_cast<llvm::support::ulittle16_t *>(&ret[0]) = hint;
-    std::memcpy(&ret[2], name.data(), name.size());
+    std::memcpy(&ret[2], importName.data(), importName.size());
     return ret;
   }
 
-  /// Undo name mangling. In Windows, the symbol name for function is encoded
-  /// as "_name at X", where X is the number of bytes of the arguments.
-  StringRef unmangle(StringRef mangledName) {
-    assert(mangledName.startswith("_"));
-    return mangledName.substr(1).split('@').first;
-  }
-
-  StringRef _name;
+  StringRef _importName;
 };
 
 class ImportTableEntryAtom : public IdataAtom {
 public:
-  explicit ImportTableEntryAtom(Context &ctx)
-      : IdataAtom(ctx.file, vector<uint8_t>(4, 0)) {}
+  explicit ImportTableEntryAtom(Context &ctx, uint32_t contents)
+      : IdataAtom(ctx.file, assembleRawContent(contents)) {}
+
+private:
+  vector<uint8_t> assembleRawContent(uint32_t contents) {
+    vector<uint8_t> ret(4);
+    *reinterpret_cast<llvm::support::ulittle32_t *>(&ret[0]) = contents;
+    return ret;
+  }
 };
 
 /// An ImportDirectoryAtom includes information to load a DLL, including a DLL
@@ -194,21 +194,29 @@ private:
                            const vector<COFFSharedLibraryAtom *> &sharedAtoms,
                            bool shouldAddReference,
                            vector<ImportTableEntryAtom *> &ret) const {
-    for (COFFSharedLibraryAtom *shared : sharedAtoms) {
-      HintNameAtom *hintName = createHintNameAtom(ctx, shared);
-      ImportTableEntryAtom *entry = new (_alloc) ImportTableEntryAtom(ctx);
-      addDir32NBReloc(entry, hintName);
+    for (COFFSharedLibraryAtom *atom : sharedAtoms) {
+      ImportTableEntryAtom *entry = nullptr;
+      if (atom->importName().empty()) {
+        // Import by ordinal
+        uint32_t hint = (1U << 31) | atom->hint();
+        entry = new (_alloc) ImportTableEntryAtom(ctx, hint);
+      } else {
+        // Import by name
+        entry = new (_alloc) ImportTableEntryAtom(ctx, 0);
+        HintNameAtom *hintName = createHintNameAtom(ctx, atom);
+        addDir32NBReloc(entry, hintName);
+      }
       ret.push_back(entry);
       if (shouldAddReference)
-        shared->setImportTableEntry(entry);
+        atom->setImportTableEntry(entry);
     }
     // Add the NULL entry.
-    ret.push_back(new (_alloc) ImportTableEntryAtom(ctx));
+    ret.push_back(new (_alloc) ImportTableEntryAtom(ctx, 0));
   }
 
   HintNameAtom *createHintNameAtom(
       Context &ctx, const COFFSharedLibraryAtom *atom) const {
-    return new (_alloc) HintNameAtom(ctx, atom->hint(), atom->unmangledName());
+    return new (_alloc) HintNameAtom(ctx, atom->hint(), atom->importName());
   }
 
   mutable llvm::BumpPtrAllocator _alloc;

Modified: lld/trunk/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp?rev=187388&r1=187387&r2=187388&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp Mon Jul 29 17:55:39 2013
@@ -184,10 +184,20 @@ public:
     StringRef symbolName(buf + sizeof(COFF::ImportHeader));
     StringRef dllName(buf + sizeof(COFF::ImportHeader) + symbolName.size() + 1);
 
+    // TypeInfo is a bitfield. The least significant 2 bits are import
+    // type, followed by 3 bit import name type.
+    uint16_t typeInfo = *reinterpret_cast<const support::ulittle16_t *>(
+        buf + offsetof(COFF::ImportHeader, TypeInfo));
+    int type = typeInfo & 0x3;
+    int nameType = (typeInfo >> 2) & 0x7;
+
+    // Symbol name used by the linker may be different from the symbol name used
+    // by the loader. The latter may lack symbol decorations, or may not even
+    // have name if it's imported by ordinal.
+    StringRef importName = symbolNameToImportName(symbolName, nameType);
+
     const COFFSharedLibraryAtom *dataAtom = addSharedLibraryAtom(
-        hint, symbolName, dllName);
-    int type = *reinterpret_cast<const support::ulittle16_t *>(
-        buf + offsetof(COFF::ImportHeader, TypeInfo)) >> 14;
+        hint, symbolName, importName, dllName);
     if (type == llvm::COFF::IMPORT_CODE)
       addDefinedAtom(symbolName, dllName, dataAtom);
 
@@ -213,10 +223,11 @@ public:
   virtual const TargetInfo &getTargetInfo() const { return _targetInfo; }
 
 private:
-  const COFFSharedLibraryAtom *addSharedLibraryAtom(
-      uint16_t hint, StringRef symbolName, StringRef dllName) {
+  const COFFSharedLibraryAtom *
+  addSharedLibraryAtom(uint16_t hint, StringRef symbolName,
+                       StringRef importName, StringRef dllName) {
     auto *atom = new (_alloc) COFFSharedLibraryAtom(
-        *this, hint, symbolName, dllName);
+        *this, hint, symbolName, importName, dllName);
     _sharedLibraryAtoms._atoms.push_back(atom);
     return atom;
   }
@@ -235,6 +246,32 @@ private:
   atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
   const TargetInfo &_targetInfo;
   mutable llvm::BumpPtrAllocator _alloc;
+
+  // Convert the given symbol name to the import symbol name exported by the
+  // DLL.
+  StringRef symbolNameToImportName(StringRef symbolName, int nameType) const {
+    StringRef ret;
+    switch (nameType) {
+    case llvm::COFF::IMPORT_ORDINAL:
+      // The import is by ordinal. No symbol name will be used to identify the
+      // item in the DLL. Only its ordinal will be used.
+      return "";
+    case llvm::COFF::IMPORT_NAME:
+      // The import name in this case is identical to the symbol name.
+      return symbolName;
+    case llvm::COFF::IMPORT_NAME_NOPREFIX:
+      // The import name is the symbol name without leading ?, @ or _.
+      ret = symbolName.ltrim("?@_");
+      break;
+    case llvm::COFF::IMPORT_NAME_UNDECORATE:
+      // Similar to NOPREFIX, but we also need to truncate at the first @.
+      ret = symbolName.ltrim("?@_");
+      ret = ret.substr(0, ret.find('@'));
+      break;
+    }
+    std::string *str = new (_alloc) std::string(ret);
+    return *str;
+  }
 };
 
 } // end anonymous namespace

Modified: lld/trunk/test/pecoff/Inputs/vars.c
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/Inputs/vars.c?rev=187388&r1=187387&r2=187388&view=diff
==============================================================================
--- lld/trunk/test/pecoff/Inputs/vars.c (original)
+++ lld/trunk/test/pecoff/Inputs/vars.c Mon Jul 29 17:55:39 2013
@@ -1,8 +1,11 @@
 // cl.exe /c vars.c
-// link.exe /debug /nodefaultlib /entry:dllmain vars.obj
-__declspec(dllexport) int var = 3;
+// link /debug /dll /nodefaultlib /entry:dllmain /export:var, at 1,NONAME,DATA /export:fn vars.obj
 
-__declspec(dllexport) int fn(void) {
+// will be exported by ordinal
+int var = 3;
+
+// will be exported by name
+int fn(void) {
   return 4;
 }
 

Modified: lld/trunk/test/pecoff/Inputs/vars.lib
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/Inputs/vars.lib?rev=187388&r1=187387&r2=187388&view=diff
==============================================================================
Binary files lld/trunk/test/pecoff/Inputs/vars.lib (original) and lld/trunk/test/pecoff/Inputs/vars.lib Mon Jul 29 17:55:39 2013 differ

Modified: lld/trunk/test/pecoff/importlib.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/importlib.test?rev=187388&r1=187387&r2=187388&view=diff
==============================================================================
--- lld/trunk/test/pecoff/importlib.test (original)
+++ lld/trunk/test/pecoff/importlib.test Mon Jul 29 17:55:39 2013
@@ -1,5 +1,5 @@
-# Verify that lld can handle .lib files. "main.obj" refers _val1 and
-# _val2 that are defined in "vars.lib".
+# Verify that lld can handle .lib files. "main.obj" refers "var" and
+# "fn" defined in "vars.lib".
 #
 # RUN: yaml2obj %p/Inputs/vars-main.obj.yaml > %t.obj
 #
@@ -22,8 +22,8 @@ CHECK: Disassembly of section .text:
 CHECK: .text:
 CHECK:     1000:       55                    pushl   %ebp
 CHECK:     1001:       8b ec                 movl    %esp, %ebp
-CHECK:     1003:       ff 15 4c 20 40 00     calll   *4202572
-CHECK:     1009:       8b 0d 50 20 40 00     movl    4202576, %ecx
+CHECK:     1003:       ff 15 40 20 40 00     calll   *4202560
+CHECK:     1009:       8b 0d 44 20 40 00     movl    4202564, %ecx
 CHECK:     100f:       03 01                 addl    (%ecx), %eax
 CHECK:     1011:       5d                    popl    %ebp
 CHECK:     1012:       c3                    ret





More information about the llvm-commits mailing list