<div dir="ltr">On Sun, Jun 30, 2013 at 6:33 AM, Rui Ueyama <span dir="ltr"><<a href="mailto:ruiu@google.com" target="_blank">ruiu@google.com</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Author: ruiu<br>
Date: Sun Jun 30 08:33:36 2013<br>
New Revision: 185283<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=185283&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=185283&view=rev</a><br>
Log:<br>
[PECOFF][Reader] Create a jump table for functions exported by DLL.<br>
<br>
Modified:<br>
    lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h<br>
    lld/trunk/lib/ReaderWriter/PECOFF/GroupedSectionsPass.h<br>
    lld/trunk/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp<br>
    lld/trunk/test/pecoff/importlib.test<br>
<br>
Modified: lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h?rev=185283&r1=185282&r2=185283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h?rev=185283&r1=185282&r2=185283&view=diff</a><br>

==============================================================================<br>
--- lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h (original)<br>
+++ lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h Sun Jun 30 08:33:36 2013<br>
@@ -235,28 +235,22 @@ private:<br>
<br>
 class COFFSharedLibraryAtom : public SharedLibraryAtom {<br>
 public:<br>
-  enum class Kind {<br>
-    DATA, FUNC<br>
-  };<br>
+  COFFSharedLibraryAtom(const File &file, StringRef symbolName,<br>
+                        StringRef originalName, StringRef loadName)<br>
+      : _file(file), _symbolName(symbolName), _loadName(loadName),<br>
+        _originalName(originalName) {}<br>
<br>
   virtual const File &file() const { return _file; }<br>
   virtual StringRef name() const { return _symbolName; }<br>
   virtual StringRef loadName() const { return _loadName; }<br>
   virtual bool canBeNullAtRuntime() const { return false; }<br>
-<br>
-  Kind getKind() const { return _kind; }<br>
-<br>
-protected:<br>
-  COFFSharedLibraryAtom(const File &file, StringRef symbolName,<br>
-                        StringRef loadName, Kind kind)<br>
-      : _file(file), _symbolName(symbolName), _loadName(loadName), _kind(kind) {<br>
-  }<br>
+  virtual StringRef originalName() const { return _originalName; }<br>
<br>
 private:<br>
   const File &_file;<br>
   StringRef _symbolName;<br>
   StringRef _loadName;<br>
-  Kind _kind;<br>
+  StringRef _originalName;<br>
 };<br>
<br>
 //===----------------------------------------------------------------------===//<br>
<br>
Modified: lld/trunk/lib/ReaderWriter/PECOFF/GroupedSectionsPass.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/GroupedSectionsPass.h?rev=185283&r1=185282&r2=185283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/GroupedSectionsPass.h?rev=185283&r1=185282&r2=185283&view=diff</a><br>

==============================================================================<br>
--- lld/trunk/lib/ReaderWriter/PECOFF/GroupedSectionsPass.h (original)<br>
+++ lld/trunk/lib/ReaderWriter/PECOFF/GroupedSectionsPass.h Sun Jun 30 08:33:36 2013<br>
@@ -45,6 +45,7 @@<br>
 #include <algorithm><br>
 #include <map><br>
<br>
+using lld::coff::COFFBaseDefinedAtom;<br>
 using lld::coff::COFFDefinedAtom;<br>
<br>
 namespace lld {<br>
@@ -76,8 +77,8 @@ private:<br>
   SectionToAtomsT filterHeadAtoms(MutableFile &mutableFile) const {<br>
     SectionToAtomsT result;<br>
     for (const DefinedAtom *atom : mutableFile.defined()) {<br>
-      auto *coffAtom = (COFFDefinedAtom *)atom;<br>
-      if (coffAtom->ordinal() == 0)<br>
+      auto *coffAtom = dyn_cast<COFFDefinedAtom>((COFFBaseDefinedAtom *)atom);<br>
+      if (coffAtom && coffAtom->ordinal() == 0)<br>
         result[coffAtom->getSectionName()].push_back(coffAtom);<br>
     }<br>
     return std::move(result);<br>
<br>
Modified: lld/trunk/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp?rev=185283&r1=185282&r2=185283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp?rev=185283&r1=185282&r2=185283&view=diff</a><br>

==============================================================================<br>
--- lld/trunk/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp (original)<br>
+++ lld/trunk/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp Sun Jun 30 08:33:36 2013<br>
@@ -7,8 +7,11 @@<br>
 //<br>
 //===----------------------------------------------------------------------===//<br>
 ///<br>
-/// \file \brief This file provides a way to read an import library<br>
-/// member in a .lib file.<br>
+/// \file \brief This file provides a way to read an import library member in a<br>
+/// .lib file.<br>
+///<br>
+/// Archive Files in Windows<br>
+/// ========================<br>
 ///<br>
 /// In Windows, archive files with .lib file extension serve two different<br>
 /// purposes.<br>
@@ -17,19 +20,90 @@<br>
 ///    normal .obj files and is used for static linking. This is the same<br>
 ///    usage as .a file in Unix.<br>
 ///<br>
-///  - For dynamic linking: An archive file in this case contains pseudo .obj<br>
-///    files to describe exported symbols of a DLL. Each .obj file in an archive<br>
-///    has a name of an exported symbol and a DLL filename from which the symbol<br>
-///    can be imported. When you link a DLL on Windows, you pass the name of the<br>
-///    .lib file for the DLL instead of the DLL filename itself. That is the<br>
-///    Windows way of linking a shared library.<br>
-///<br>
-/// This file contains a function to parse the pseudo object file.<br>
+///  - For dynamic linking: An archive file in this use case contains pseudo<br>
+///    .obj files to describe exported symbols of a DLL. Each pseudo .obj file<br>
+///    in an archive has a name of an exported symbol and a DLL filename from<br>
+///    which the symbol can be imported. When you link a DLL on Windows, you<br>
+///    pass the name of the .lib file for the DLL instead of the DLL filename<br>
+///    itself. That is the Windows way of linking against a shared library.<br>
+///<br>
+/// This file contains a function to handle the pseudo object file.<br>
+///<br>
+/// Windows Loader and Import Address Table<br>
+/// =======================================<br>
+///<br>
+/// Windows supports a GOT-like mechanism for DLLs. The executable using DLLs<br>
+/// contains a list of DLL names and list of symbols that need to be resolved by<br>
+/// the loader. Windows loader maps the executable and all the DLLs to memory,<br>
+/// resolves the symbols referencing items in DLLs, and updates the import<br>
+/// address table in memory. The import address table is an array of pointers to<br>
+/// all of the data or functions in DLL referenced by the executable. You cannot<br>
+/// access items in DLLs directly. They have to be accessed through an extra<br>
+/// level of indirection.<br>
+///<br>
+/// So, if you want to access an item in DLL, you have to go through a<br>
+/// pointer. How do you actually do that? For each symbol in DLL, there is<br>
+/// another set of symbols with "_imp__" prefix. For example, if you have a<br>
+/// global variable "foo" in a DLL, a pointer to the variable is exported from<br>
+/// the DLL as "_imp__foo". You cannot directly use "foo" but need to go through<br>
+/// "_imp__foo", because symbol "foo" is not exported.<br></blockquote><div><br></div><div>This terminology seems confusing to me.  "foo" is presumably annotated with dllexport, so I consider it to be exported.  Also, the IAT is part of the importing image, and the IAT is basically an array of __imp_ symbols, right?</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+/// Is this OK? That's not that complicated. Because items in a DLL are not<br>
+/// directly accessible, you need to access through a pointer, and the pointer<br>
+/// is available as a symbol with "_imp__" prefix.<br>
+///<br>
+/// Trick 1: Although you can write code with "_imp__" prefix, today's compiler<br>
+/// and linker let you write code as if there's no extra level of<br>
+/// indirection. That's why you haven't seen lots of _imp__ in your code. A<br>
+/// variable or a function declared with "dllimport" attributes is treated as an<br>
+/// item in a DLL, and the compiler automatically mangles its name and inserts<br>
+/// the extra level of indirection when accessing the item. Here are some<br>
+/// examples:<br>
+///<br>
+///   __declspec(dllimport) int var_in_dll;<br>
+///   var_in_dll = 3; // is equivalent to *_imp__var_in_dll = 3;<br>
+///<br>
+///   __declspec(dllimport) int fn_in_dll(void);<br>
+///   fn_in_dll();     // is equivalent to (*_imp__fn_in_dll)();<br>
+///<br>
+/// It's just the compiler rewrites code for you so that you don't need to<br>
+/// handle the indirection youself.<br>
+///<br>
+/// Trick 2: __declspec(dllimport) is mandatory for data but optional for<br>
+/// function. For a function, the linker creates a jump table with the original<br>
+/// symbol name, so that the function is accessible without "_imp__" prefix. The<br>
+/// same function in a DLL can be called through two different symbols if it's<br>
+/// not dllimport'ed.<br></blockquote><div><br></div><div>Cool.  I actually spent some time trying to make the Clang/LLVM shared library build work on Windows by generating map files from dumpbin /symbols, but there was too much data that had to be annotated with dllimport.  The resulting build was also too slow for development, which was my true goal.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+///   (*_imp__fn)()<br>
+///   fn()<br>
+///<br>
+/// The above functions do the same thing. fn's content is a JMP instruction to<br>
+/// branch to the address pointed by _imp__fn. The latter may be a little bit<br>
+/// slower than the former because it will execute the extra JMP instruction, but<br>
+/// that's not an important point here.<br>
+///<br>
+/// If a function is dllimport'ed, which is usually done in a header file,<br>
+/// mangled name will be used at compile time so the jump table will not be<br>
+/// used.<br>
+///<br>
+/// Because there's no way to hide the indirection for data access at link time,<br>
+/// data has to be accessed through dllimport'ed symbols or explicit "_imp__"<br>
+/// prefix.<br>
+///<br>
+/// Creating Atoms for the Import Address Table<br>
+/// ===========================================<br>
+///<br>
+/// This file is to read a pseudo object file and create at most two atoms. One<br>
+/// is a shared library atom for "_imp__" symbol. The another is a defined atom<br>
+/// for the JMP instruction if the symbol is for a function.<br>
 ///<br>
 //===----------------------------------------------------------------------===//<br>
<br>
 #define DEBUG_TYPE "ReaderImportHeader"<br>
<br>
+#include "Atoms.h"<br>
+<br>
 #include "lld/Core/File.h"<br>
 #include "lld/Core/Error.h"<br>
 #include "lld/Core/SharedLibraryAtom.h"<br>
@@ -58,20 +132,25 @@ namespace coff {<br>
<br>
 namespace {<br>
<br>
-class COFFDynamicAtom : public SharedLibraryAtom {<br>
+/// The defined atom for jump table.<br>
+class FuncAtom : public COFFBaseDefinedAtom {<br>
 public:<br>
-  COFFDynamicAtom(File &file, StringRef symbolName, StringRef dllName)<br>
-      : _owningFile(file), _symbolName(symbolName), _dllName(dllName) {}<br>
+  FuncAtom(const File &file, StringRef symbolName)<br>
+      : COFFBaseDefinedAtom(file, symbolName, &rawContent) {}<br>
<br>
-  virtual const File &file() const { return _owningFile; }<br>
-  virtual StringRef name() const { return _symbolName; }<br>
-  virtual StringRef loadName() const { return _dllName; }<br>
-  virtual bool canBeNullAtRuntime() const { return true; }<br>
+  virtual uint64_t ordinal() const { return 0; }<br>
+  virtual Scope scope() const { return scopeGlobal; }<br>
+  virtual ContentType contentType() const { return typeCode; }<br>
+  virtual Alignment alignment() const { return Alignment(1); }<br>
+  virtual ContentPermissions permissions() const { return permR_X; }<br>
<br>
 private:<br>
-  const File &_owningFile;<br>
-  StringRef _symbolName;<br>
-  StringRef _dllName;<br>
+  static std::vector<uint8_t> rawContent;<br>
+};<br>
+<br>
+std::vector<uint8_t> FuncAtom::rawContent = {<br>
+  0xff, 0x25, 0x00, 0x00, 0x00, 0x00,  // jmp *0x0<br>
+  0x90, 0x90,                          // nop; nop<br>
 };<br>
<br>
 class FileImportLibrary : public File {<br>
@@ -96,14 +175,17 @@ public:<br>
     StringRef symbolName(buf + 20);<br>
     StringRef dllName(buf + 20 + symbolName.size() + 1);<br>
<br>
-    auto *atom = new (allocator.Allocate<COFFDynamicAtom>())<br>
-        COFFDynamicAtom(*this, symbolName, dllName);<br>
-    _sharedLibraryAtoms._atoms.push_back(atom);<br>
+    const COFFSharedLibraryAtom *dataAtom = addSharedLibraryAtom(symbolName,<br>
+                                                                 dllName);<br>
+    int type = *reinterpret_cast<const support::ulittle16_t *>(buf + 18) >> 16;<br>
+    if (type == llvm::COFF::IMPORT_CODE)<br>
+      addDefinedAtom(symbolName, dllName, dataAtom);<br>
+<br>
     ec = error_code::success();<br>
   }<br>
<br>
   virtual const atom_collection<DefinedAtom> &defined() const {<br>
-    return _noDefinedAtoms;<br>
+    return _definedAtoms;<br>
   }<br>
<br>
   virtual const atom_collection<UndefinedAtom> &undefined() const {<br>
@@ -121,6 +203,28 @@ public:<br>
   virtual const TargetInfo &getTargetInfo() const { return _targetInfo; }<br>
<br>
 private:<br>
+  const COFFSharedLibraryAtom *addSharedLibraryAtom(StringRef symbolName,<br>
+                                                    StringRef dllName) {<br>
+    auto *name = new (allocator.Allocate<std::string>()) std::string("__imp_");<br>
+    name->append(symbolName);<br>
+    auto *atom = new (allocator.Allocate<COFFSharedLibraryAtom>())<br>
+        COFFSharedLibraryAtom(*this, *name, symbolName, dllName);<br>
+    _sharedLibraryAtoms._atoms.push_back(atom);<br>
+    return atom;<br>
+  }<br>
+<br>
+  void addDefinedAtom(StringRef symbolName, StringRef dllName,<br>
+                      const COFFSharedLibraryAtom *dataAtom) {<br>
+    auto *atom = new (allocator.Allocate<FuncAtom>())<br>
+        FuncAtom(*this, symbolName);<br>
+<br>
+    // The first two byte of the atom is JMP instruction.<br>
+    atom->addReference(std::unique_ptr<COFFReference>(<br>
+        new COFFReference(dataAtom, 2, llvm::COFF::IMAGE_REL_I386_DIR32)));<br>
+    _definedAtoms._atoms.push_back(atom);<br>
+  }<br>
+<br>
+  atom_collection_vector<DefinedAtom> _definedAtoms;<br>
   atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;<br>
   const TargetInfo &_targetInfo;<br>
   mutable llvm::BumpPtrAllocator allocator;<br>
<br>
Modified: lld/trunk/test/pecoff/importlib.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/importlib.test?rev=185283&r1=185282&r2=185283&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/importlib.test?rev=185283&r1=185282&r2=185283&view=diff</a><br>

==============================================================================<br>
--- lld/trunk/test/pecoff/importlib.test (original)<br>
+++ lld/trunk/test/pecoff/importlib.test Sun Jun 30 08:33:36 2013<br>
@@ -7,6 +7,12 @@<br>
<br>
 CHECK: Disassembly of section .text:<br>
 CHECK: .text:<br>
-CHECK:     1000:       a1 00 00 40 00<br>
-CHECK:     1005:       03 05 00 00 40 00<br>
-CHECK:     100b:       c3<br>
+CHECK:     1000:       a1 0c 10 40 00            movl    4198412, %eax<br>
+CHECK:     1005:       03 05 14 10 40 00         addl    4198420, %eax<br>
+CHECK:     100b:       c3                        ret<br>
+CHECK:     100c:       ff 25 00 00 40 00         jmpl    *4194304<br>
+CHECK:     1012:       90                        nop<br>
+CHECK:     1013:       90                        nop<br>
+CHECK:     1014:       ff 25 00 00 40 00         jmpl    *4194304<br>
+CHECK:     101a:       90                        nop<br>
+CHECK:     101b:       90                        nop<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>