[lld] r197364 - [PECOFF] Make it possible to specify export ordinals.

Rui Ueyama ruiu at google.com
Sun Dec 15 21:46:07 PST 2013


Author: ruiu
Date: Sun Dec 15 23:46:07 2013
New Revision: 197364

URL: http://llvm.org/viewvc/llvm-project?rev=197364&view=rev
Log:
[PECOFF] Make it possible to specify export ordinals.

You can specify exported function's ordinal by /export:func,@<number> command
line option, but LLD ignored the option until now. This patch implements the
feature.

Ordinal is basically the index into the exported function address table. So,
for example, if /export:foo, at 42 is specified, the linker writes foo's address
to 42th entry in the address table. Windows supports import-by-ordinal; you
can not only import a function by name, but by its ordinal. If you want to
allow your DLL users to import your functions by their ordinals, you need to
make sure that your functions are always exported with the same ordinals.
This is the feature for that situation.

Modified:
    lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp
    lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.h
    lld/trunk/test/pecoff/export.test

Modified: lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp?rev=197364&r1=197363&r2=197364&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp Sun Dec 15 23:46:07 2013
@@ -13,23 +13,27 @@
 #include "lld/Core/File.h"
 #include "lld/Core/Pass.h"
 #include "lld/ReaderWriter/Simple.h"
+#include "llvm/Support/Debug.h"
 #include "llvm/Support/Path.h"
 
 #include <ctime>
 
 using lld::pecoff::edata::EdataAtom;
+using lld::pecoff::edata::TableEntry;
 using llvm::object::export_address_table_entry;
 using llvm::object::export_directory_table_entry;
 
 namespace lld {
 namespace pecoff {
 
-static bool compare(const DefinedAtom *a, const DefinedAtom *b) {
-  return a->name().compare(b->name()) < 0;
+static const int ORDINAL_BASE = 1;
+
+static bool compare(const TableEntry &a, const TableEntry &b) {
+  return a.exportName.compare(b.exportName) < 0;
 }
 
 static bool getExportedAtoms(const PECOFFLinkingContext &ctx, MutableFile *file,
-                             std::vector<const DefinedAtom *> &ret) {
+                             std::vector<TableEntry> &ret) {
   std::map<StringRef, const DefinedAtom *> definedAtoms;
   for (const DefinedAtom *atom : file->defined())
     definedAtoms[atom->name()] = atom;
@@ -42,36 +46,54 @@ static bool getExportedAtoms(const PECOF
       return false;
     }
     const DefinedAtom *atom = it->second;
-    ret.push_back(atom);
+    ret.push_back(TableEntry(desc.name, desc.ordinal, atom));
   }
   std::sort(ret.begin(), ret.end(), compare);
   return true;
 }
 
+static int assignOrdinals(std::vector<TableEntry> &entries) {
+  int maxOrdinal = -1;
+  for (TableEntry &e : entries)
+    maxOrdinal = std::max(maxOrdinal, e.ordinal);
+
+  if (maxOrdinal == -1) {
+    int ordinal = 0;
+    for (TableEntry &e : entries)
+      e.ordinal = ++ordinal;
+    return ordinal;
+  }
+  for (TableEntry &e : entries)
+    if (e.ordinal == -1)
+      e.ordinal = ++maxOrdinal;
+  return maxOrdinal;
+}
+
 edata::EdataAtom *
-EdataPass::createAddressTable(const std::vector<const DefinedAtom *> &atoms) {
+EdataPass::createAddressTable(const std::vector<TableEntry> &entries,
+                              int maxOrdinal) {
   EdataAtom *addressTable = new (_alloc)
-      EdataAtom(_file, sizeof(export_address_table_entry) * atoms.size());
+      EdataAtom(_file, sizeof(export_address_table_entry) * maxOrdinal);
 
-  size_t offset = 0;
-  for (const DefinedAtom *atom : atoms) {
-    addDir32NBReloc(addressTable, atom, offset);
-    offset += sizeof(export_address_table_entry);
+  for (const TableEntry &e : entries) {
+    int index = e.ordinal - ORDINAL_BASE;
+    size_t offset = index * sizeof(export_address_table_entry);
+    addDir32NBReloc(addressTable, e.atom, offset);
   }
   return addressTable;
 }
 
 edata::EdataAtom *
 EdataPass::createNamePointerTable(const PECOFFLinkingContext &ctx,
-                                  const std::vector<const DefinedAtom *> &atoms,
+                                  const std::vector<TableEntry> &entries,
                                   MutableFile *file) {
   EdataAtom *table =
-      new (_alloc) EdataAtom(_file, sizeof(uint32_t) * atoms.size());
+      new (_alloc) EdataAtom(_file, sizeof(uint32_t) * entries.size());
 
   size_t offset = 0;
-  for (const DefinedAtom *atom : atoms) {
-    auto *stringAtom = new (_alloc) COFFStringAtom(
-        _file, _stringOrdinal++, ".edata", ctx.undecorateSymbol(atom->name()));
+  for (const TableEntry &e : entries) {
+    auto *stringAtom = new (_alloc)
+        COFFStringAtom(_file, _stringOrdinal++, ".edata", e.exportName);
     file->addAtom(*stringAtom);
     addDir32NBReloc(table, stringAtom, offset);
     offset += sizeof(uint32_t);
@@ -79,35 +101,38 @@ EdataPass::createNamePointerTable(const
   return table;
 }
 
-edata::EdataAtom *EdataPass::createExportDirectoryTable(size_t numEntries) {
+edata::EdataAtom *EdataPass::createExportDirectoryTable(
+    const std::vector<edata::TableEntry> &entries, int maxOrdinal) {
   EdataAtom *ret =
       new (_alloc) EdataAtom(_file, sizeof(export_directory_table_entry));
   auto *data = ret->getContents<export_directory_table_entry>();
   data->TimeDateStamp = time(nullptr);
-  data->OrdinalBase = 1;
-  data->AddressTableEntries = numEntries;
-  data->NumberOfNamePointers = numEntries;
+  data->OrdinalBase = ORDINAL_BASE;
+  data->AddressTableEntries = maxOrdinal;
+  data->NumberOfNamePointers = entries.size();
   return ret;
 }
 
-edata::EdataAtom *EdataPass::createOrdinalTable(
-    const std::vector<const DefinedAtom *> &atoms) {
+edata::EdataAtom *
+EdataPass::createOrdinalTable(const std::vector<TableEntry> &entries) {
   EdataAtom *ret =
-      new (_alloc) EdataAtom(_file, sizeof(uint16_t) * atoms.size());
+      new (_alloc) EdataAtom(_file, sizeof(uint16_t) * entries.size());
   uint16_t *data = ret->getContents<uint16_t>();
-  for (size_t i = 0, e = atoms.size(); i < e; ++i)
-    data[i] = i;
+  int i = 0;
+  for (const TableEntry &e : entries)
+    data[i++] = e.ordinal - ORDINAL_BASE;
   return ret;
 }
 
 void EdataPass::perform(std::unique_ptr<MutableFile> &file) {
-  std::vector<const DefinedAtom *> atoms;
-  if (!getExportedAtoms(_ctx, file.get(), atoms))
+  std::vector<TableEntry> entries;
+  if (!getExportedAtoms(_ctx, file.get(), entries))
     return;
-  if (atoms.empty())
+  if (entries.empty())
     return;
+  int maxOrdinal = assignOrdinals(entries);
 
-  EdataAtom *table = createExportDirectoryTable(atoms.size());
+  EdataAtom *table = createExportDirectoryTable(entries, maxOrdinal);
   file->addAtom(*table);
 
   COFFStringAtom *dllName =
@@ -117,17 +142,18 @@ void EdataPass::perform(std::unique_ptr<
   addDir32NBReloc(table, dllName,
                   offsetof(export_directory_table_entry, NameRVA));
 
-  EdataAtom *addressTable = createAddressTable(atoms);
+  EdataAtom *addressTable = createAddressTable(entries, maxOrdinal);
   file->addAtom(*addressTable);
   addDir32NBReloc(table, addressTable, offsetof(export_directory_table_entry,
                                                 ExportAddressTableRVA));
 
-  EdataAtom *namePointerTable = createNamePointerTable(_ctx, atoms, file.get());
+  EdataAtom *namePointerTable =
+      createNamePointerTable(_ctx, entries, file.get());
   file->addAtom(*namePointerTable);
   addDir32NBReloc(table, namePointerTable,
                   offsetof(export_directory_table_entry, NamePointerRVA));
 
-  EdataAtom *ordinalTable = createOrdinalTable(atoms);
+  EdataAtom *ordinalTable = createOrdinalTable(entries);
   file->addAtom(*ordinalTable);
   addDir32NBReloc(table, ordinalTable,
                   offsetof(export_directory_table_entry, OrdinalTableRVA));

Modified: lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.h?rev=197364&r1=197363&r2=197364&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.h (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.h Sun Dec 15 23:46:07 2013
@@ -35,6 +35,14 @@ namespace lld {
 namespace pecoff {
 namespace edata {
 
+struct TableEntry {
+  TableEntry(StringRef exportName, int ordinal, const DefinedAtom *atom)
+      : exportName(exportName), ordinal(ordinal), atom(atom) {}
+  StringRef exportName;
+  int ordinal;
+  const DefinedAtom *atom;
+};
+
 /// The root class of all edata atoms.
 class EdataAtom : public COFFLinkerInternalAtom {
 public:
@@ -62,15 +70,21 @@ public:
   virtual void perform(std::unique_ptr<MutableFile> &file);
 
 private:
-  edata::EdataAtom *createExportDirectoryTable(size_t numEntries);
   edata::EdataAtom *
-  createAddressTable(const std::vector<const DefinedAtom *> &atoms);
+  createExportDirectoryTable(const std::vector<edata::TableEntry> &entries,
+                             int maxOrdinal);
+
+  edata::EdataAtom *
+  createAddressTable(const std::vector<edata::TableEntry> &entries,
+                     int maxOrdinal);
+
   edata::EdataAtom *
   createNamePointerTable(const PECOFFLinkingContext &ctx,
-                         const std::vector<const DefinedAtom *> &atoms,
+                         const std::vector<edata::TableEntry> &entries,
                          MutableFile *file);
+
   edata::EdataAtom *
-  createOrdinalTable(const std::vector<const DefinedAtom *> &atoms);
+  createOrdinalTable(const std::vector<edata::TableEntry> &entries);
 
   const PECOFFLinkingContext &_ctx;
   VirtualFile _file;

Modified: lld/trunk/test/pecoff/export.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/export.test?rev=197364&r1=197363&r2=197364&view=diff
==============================================================================
--- lld/trunk/test/pecoff/export.test (original)
+++ lld/trunk/test/pecoff/export.test Sun Dec 15 23:46:07 2013
@@ -1,14 +1,28 @@
 # RUN: yaml2obj %p/Inputs/export.obj.yaml > %t.obj
 #
-# RUN: lld -flavor link /out:%t.dll /dll /subsystem:console /entry:_init \
+# RUN: lld -flavor link /out:%t1.dll /dll /subsystem:console /entry:_init \
 # RUN:   /export:exportfn1 /export:exportfn2 -- %t.obj
-# RUN: llvm-objdump -s %t.dll | FileCheck %s
+# RUN: llvm-objdump -s %t1.dll | FileCheck -check-prefix=CHECK1 %s
 
-CHECK:      Contents of section .edata:
-CHECK-NEXT:  1000 00000000 {{........}} 00000000 3c100000
-CHECK-NEXT:  1010 01000000 02000000 02000000 28100000
-CHECK-NEXT:  1020 30100000 38100000 08200000 10200000
-CHECK-NEXT:  1030 50100000 5a100000 00000100 6578706f
-CHECK-NEXT:  1040 72742e74 6573742e 746d702e 646c6c00
-CHECK-NEXT:  1050 6578706f 7274666e 31006578 706f7274
-CHECK-NEXT:  1060 666e3200
+CHECK1:      Contents of section .edata:
+CHECK1-NEXT:  1000 00000000 {{........}} 00000000 3c100000
+CHECK1-NEXT:  1010 01000000 02000000 02000000 28100000
+CHECK1-NEXT:  1020 30100000 38100000 08200000 10200000
+CHECK1-NEXT:  1030 51100000 5b100000 00000100 6578706f
+CHECK1-NEXT:  1040 72742e74 6573742e 746d7031 2e646c6c
+CHECK1-NEXT:  1050 00657870 6f727466 6e310065 78706f72
+CHECK1-NEXT:  1060 74666e32 00
+
+# RUN: lld -flavor link /out:%t2.dll /dll /subsystem:console /entry:_init \
+# RUN:   /export:exportfn1, at 5 /export:exportfn2 -- %t.obj
+# RUN: llvm-objdump -s %t2.dll | FileCheck -check-prefix=CHECK2 %s
+
+CHECK2:      Contents of section .edata:
+CHECK2-NEXT:  1000 00000000 {{........}} 00000000 4c100000
+CHECK2-NEXT:  1010 01000000 06000000 02000000 28100000
+CHECK2-NEXT:  1020 40100000 48100000 00000000 00000000
+CHECK2-NEXT:  1030 00000000 00000000 08200000 10200000
+CHECK2-NEXT:  1040 61100000 6b100000 04000500 6578706f
+CHECK2-NEXT:  1050 72742e74 6573742e 746d7032 2e646c6c
+CHECK2-NEXT:  1060 00657870 6f727466 6e310065 78706f72
+CHECK2-NEXT:  1070 74666e32 00





More information about the llvm-commits mailing list