[lld] r197212 - [PECOFF] Create .edata section for the DLL export table.

Rui Ueyama ruiu at google.com
Thu Dec 12 23:15:43 PST 2013


Hi Yaron,

Thanks for the link! I was aware of the MinGW's feature and actually
thinking to add the same feature to LLD in the future. We need the import
library support anyway for MSVC compatibility, though.


On Fri, Dec 13, 2013 at 4:10 PM, Yaron Keren <yaron.keren at gmail.com> wrote:

> Hi Rui,
>
> MinGW (gcc) can link against DLL files created by MinGW without an import
> library. You just need the header and DLL files. See here:
>
> http://www.mingw.org/wiki/CreateImportLibraries
>
> I hope this helps,
>
> Yaron
>
>
>
> 2013/12/13 Rui Ueyama <ruiu at google.com>
>
>> Author: ruiu
>> Date: Fri Dec 13 00:58:27 2013
>> New Revision: 197212
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=197212&view=rev
>> Log:
>> [PECOFF] Create .edata section for the DLL export table.
>>
>> This is the first patch to emit data for the DLL export table. The DLL
>> export
>> table is the data used by the Windows loader to find the address of
>> exported
>> function from DLL. With this patch, LLD is able to emit a valid DLL export
>> table which the Windows loader can interpret and load.
>>
>> The data structure of the DLL export table is described in the Microsoft
>> PE/COFF Specification, section 5.3.
>>
>> DLL support is not complete yet; the linker needs to emit an import
>> library
>> for a DLL, otherwise the linker cannot link against the DLL. We also do
>> not
>> support export-only-by-ordinal yet.
>>
>> Added:
>>     lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp
>>     lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.h
>>     lld/trunk/test/pecoff/Inputs/export.obj.yaml
>>     lld/trunk/test/pecoff/export.test
>> Modified:
>>     lld/trunk/lib/ReaderWriter/PECOFF/CMakeLists.txt
>>     lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
>>     lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp
>>
>> Modified: lld/trunk/lib/ReaderWriter/PECOFF/CMakeLists.txt
>> URL:
>> http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/CMakeLists.txt?rev=197212&r1=197211&r2=197212&view=diff
>>
>> ==============================================================================
>> --- lld/trunk/lib/ReaderWriter/PECOFF/CMakeLists.txt (original)
>> +++ lld/trunk/lib/ReaderWriter/PECOFF/CMakeLists.txt Fri Dec 13 00:58:27
>> 2013
>> @@ -1,4 +1,5 @@
>>  add_lld_library(lldPECOFF
>> +  EdataPass.cpp
>>    IdataPass.cpp
>>    PECOFFLinkingContext.cpp
>>    Pass.cpp
>>
>> Added: lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp?rev=197212&view=auto
>>
>> ==============================================================================
>> --- lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp (added)
>> +++ lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp Fri Dec 13 00:58:27
>> 2013
>> @@ -0,0 +1,142 @@
>> +//===- lib/ReaderWriter/PECOFF/EdataPass.cpp
>> ------------------------------===//
>> +//
>> +//                             The LLVM Linker
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#include "Pass.h"
>> +#include "EdataPass.h"
>> +
>> +#include "lld/Core/File.h"
>> +#include "lld/Core/Pass.h"
>> +#include "lld/ReaderWriter/Simple.h"
>> +#include "llvm/Support/Path.h"
>> +
>> +#include <ctime>
>> +
>> +using lld::pecoff::edata::EdataAtom;
>> +using llvm::object::export_address_table_entry;
>> +using llvm::object::export_directory_table_entry;
>> +
>> +namespace lld {
>> +namespace pecoff {
>> +
>> +static bool
>> +getExportedAtoms(const PECOFFLinkingContext &ctx, MutableFile *file,
>> +                 std::vector<const DefinedAtom *> &ret) {
>> +  std::map<StringRef, const DefinedAtom *> definedAtoms;
>> +  for (const DefinedAtom *atom : file->defined())
>> +    definedAtoms[atom->name()] = atom;
>> +
>> +  for (StringRef dllExport : ctx.getDllExports()) {
>> +    auto it = definedAtoms.find(ctx.decorateSymbol(dllExport));
>> +    if (it == definedAtoms.end()) {
>> +      llvm::errs() << "Symbol <" << dllExport
>> +                   << "> is exported but not defined.\n";
>> +      return false;
>> +    }
>> +    const DefinedAtom *atom = it->second;
>> +    ret.push_back(atom);
>> +  }
>> +  return true;
>> +}
>> +
>> +static bool compare(const DefinedAtom *a, const DefinedAtom *b) {
>> +  return a->name().compare(b->name()) < 0;
>> +}
>> +
>> +edata::EdataAtom *
>> +EdataPass::createAddressTable(const std::vector<const DefinedAtom *>
>> &atoms) {
>> +  EdataAtom *addressTable = new (_alloc) EdataAtom(
>> +    _file, sizeof(export_address_table_entry) * atoms.size());
>> +
>> +  size_t offset = 0;
>> +  for (const DefinedAtom *atom : atoms) {
>> +    addDir32NBReloc(addressTable, atom, offset);
>> +    offset += sizeof(export_address_table_entry);
>> +  }
>> +  return addressTable;
>> +}
>> +
>> +edata::EdataAtom *
>> +EdataPass::createNamePointerTable(const std::vector<const DefinedAtom *>
>> &atoms,
>> +                                  MutableFile *file) {
>> +  EdataAtom *table = new (_alloc) EdataAtom(_file, sizeof(uint32_t) *
>> atoms.size());
>> +
>> +  size_t offset = 0;
>> +  for (const DefinedAtom *atom : atoms) {
>> +    COFFStringAtom *stringAtom = new (_alloc) COFFStringAtom(
>> +      _file, _file.getNextOrdinal(), ".edata", atom->name());
>> +    file->addAtom(*stringAtom);
>> +    addDir32NBReloc(table, stringAtom, offset);
>> +    offset += sizeof(uint32_t);
>> +  }
>> +  return table;
>> +}
>> +
>> +edata::EdataAtom *EdataPass::createExportDirectoryTable(size_t
>> numEntries) {
>> +  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;
>> +  return ret;
>> +}
>> +
>> +edata::EdataAtom *
>> +EdataPass::createOrdinalTable(const std::vector<const DefinedAtom *>
>> &atoms,
>> +                              const std::vector<const DefinedAtom *>
>> &sortedAtoms) {
>> +  EdataAtom *ret = new (_alloc) EdataAtom(_file, sizeof(uint16_t) *
>> atoms.size());
>> +  uint16_t *data = ret->getContents<uint16_t>();
>> +
>> +  std::map<const DefinedAtom *, size_t> ordinals;
>> +  size_t ordinal = 0;
>> +  for (const DefinedAtom *atom : atoms)
>> +    ordinals[atom] = ordinal++;
>> +
>> +  size_t index = 0;
>> +  for (const DefinedAtom *atom : sortedAtoms)
>> +    data[index++] = ordinals[atom];
>> +  return ret;
>> +}
>> +
>> +void EdataPass::perform(std::unique_ptr<MutableFile> &file) {
>> +  std::vector<const DefinedAtom *> atoms;
>> +  if (!getExportedAtoms(_ctx, file.get(), atoms))
>> +    return;
>> +  if (atoms.empty())
>> +    return;
>> +
>> +  EdataAtom *table = createExportDirectoryTable(atoms.size());
>> +  file->addAtom(*table);
>> +
>> +  COFFStringAtom *dllName = new (_alloc) COFFStringAtom(
>> +    _file, _file.getNextOrdinal(),
>> +    ".edata", llvm::sys::path::filename(_ctx.outputPath()));
>> +  file->addAtom(*dllName);
>> +  addDir32NBReloc(table, dllName, offsetof(export_directory_table_entry,
>> NameRVA));
>> +
>> +  EdataAtom *addressTable = createAddressTable(atoms);
>> +  file->addAtom(*addressTable);
>> +  addDir32NBReloc(table, addressTable,
>> +                  offsetof(export_directory_table_entry,
>> ExportAddressTableRVA));
>> +
>> +  std::vector<const DefinedAtom *> sortedAtoms(atoms);
>> +  std::sort(sortedAtoms.begin(), sortedAtoms.end(), compare);
>> +  EdataAtom *namePointerTable = createNamePointerTable(sortedAtoms,
>> file.get());
>> +  file->addAtom(*namePointerTable);
>> +  addDir32NBReloc(table, namePointerTable,
>> +                  offsetof(export_directory_table_entry,
>> NamePointerRVA));
>> +
>> +  EdataAtom *ordinalTable = createOrdinalTable(atoms, sortedAtoms);
>> +  file->addAtom(*ordinalTable);
>> +  addDir32NBReloc(table, ordinalTable,
>> +                  offsetof(export_directory_table_entry,
>> OrdinalTableRVA));
>> +}
>> +
>> +} // namespace pecoff
>> +} // namespace lld
>>
>> Added: lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.h?rev=197212&view=auto
>>
>> ==============================================================================
>> --- lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.h (added)
>> +++ lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.h Fri Dec 13 00:58:27 2013
>> @@ -0,0 +1,81 @@
>> +//===- lib/ReaderWriter/PECOFF/EdataPass.h
>> --------------------------------===//
>> +//
>> +//                             The LLVM Linker
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +///
>> +/// \file \brief This linker pass creates atoms for the DLL export
>> +/// information. The defined atoms constructed in this pass will go into
>> .edata
>> +/// section.
>> +///
>> +/// For the details of the .edata section format, see Microsoft PE/COFF
>> +/// Specification section 5.3, The .edata Section.
>> +///
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#ifndef LLD_READER_WRITER_PE_COFF_EDATA_PASS_H
>> +#define LLD_READER_WRITER_PE_COFF_EDATA_PASS_H
>> +
>> +#include "Atoms.h"
>> +
>> +#include "lld/Core/File.h"
>> +#include "lld/Core/Pass.h"
>> +#include "lld/ReaderWriter/PECOFFLinkingContext.h"
>> +#include "lld/ReaderWriter/Simple.h"
>> +#include "llvm/Support/COFF.h"
>> +
>> +#include <map>
>> +
>> +using llvm::COFF::ImportDirectoryTableEntry;
>> +
>> +namespace lld {
>> +namespace pecoff {
>> +namespace edata {
>> +
>> +/// The root class of all edata atoms.
>> +class EdataAtom : public COFFLinkerInternalAtom {
>> +public:
>> +  EdataAtom(VirtualFile &file, size_t size)
>> +    : COFFLinkerInternalAtom(file, file.getNextOrdinal(),
>> +                             std::vector<uint8_t>(size)) {}
>> +
>> +  virtual SectionChoice sectionChoice() const { return
>> sectionCustomRequired; }
>> +  virtual StringRef customSectionName() const { return ".edata"; }
>> +  virtual ContentType contentType() const { return typeData; }
>> +  virtual ContentPermissions permissions() const { return permR__; }
>> +
>> +  template<typename T> T *getContents() const {
>> +    return (T *)rawContent().data();
>> +  }
>> +};
>> +
>> +} // namespace edata
>> +
>> +class EdataPass : public lld::Pass {
>> +public:
>> +  EdataPass(const PECOFFLinkingContext &ctx) : _ctx(ctx), _file(ctx) {}
>> +
>> +  virtual void perform(std::unique_ptr<MutableFile> &file);
>> +
>> +private:
>> +  edata::EdataAtom *createExportDirectoryTable(size_t numEntries);
>> +  edata::EdataAtom *createAddressTable(
>> +    const std::vector<const DefinedAtom *> &atoms);
>> +  edata::EdataAtom *createNamePointerTable(
>> +    const std::vector<const DefinedAtom *> &atoms, MutableFile *file);
>> +  edata::EdataAtom *createOrdinalTable(
>> +    const std::vector<const DefinedAtom *> &atoms,
>> +    const std::vector<const DefinedAtom *> &sortedAtoms);
>> +
>> +  const PECOFFLinkingContext &_ctx;
>> +  VirtualFile _file;
>> +  mutable llvm::BumpPtrAllocator _alloc;
>> +};
>> +
>> +} // namespace pecoff
>> +} // namespace lld
>> +
>> +#endif
>>
>> Modified: lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp?rev=197212&r1=197211&r2=197212&view=diff
>>
>> ==============================================================================
>> --- lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp (original)
>> +++ lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp Fri Dec 13
>> 00:58:27 2013
>> @@ -8,6 +8,7 @@
>>
>>  //===----------------------------------------------------------------------===//
>>
>>  #include "Atoms.h"
>> +#include "EdataPass.h"
>>  #include "GroupedSectionsPass.h"
>>  #include "IdataPass.h"
>>  #include "LinkerGeneratedSymbolFile.h"
>> @@ -249,6 +250,7 @@ uint32_t PECOFFLinkingContext::getSectio
>>
>>  void PECOFFLinkingContext::addPasses(PassManager &pm) {
>>    pm.add(std::unique_ptr<Pass>(new pecoff::SetSubsystemPass(*this)));
>> +  pm.add(std::unique_ptr<Pass>(new pecoff::EdataPass(*this)));
>>    pm.add(std::unique_ptr<Pass>(new pecoff::IdataPass(*this)));
>>    pm.add(std::unique_ptr<Pass>(new LayoutPass()));
>>    pm.add(std::unique_ptr<Pass>(new pecoff::GroupedSectionsPass()));
>>
>> Modified: lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp?rev=197212&r1=197211&r2=197212&view=diff
>>
>> ==============================================================================
>> --- lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp (original)
>> +++ lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp Fri Dec 13
>> 00:58:27 2013
>> @@ -885,6 +885,9 @@ void ExecutableWriter::build(const File
>>      if (section->getSectionName() == ".idata.d")
>>        dataDirectory->setField(DataDirectoryIndex::IMPORT_TABLE,
>>                                section->getVirtualAddress(),
>> section->size());
>> +    if (section->getSectionName() == ".edata")
>> +      dataDirectory->setField(DataDirectoryIndex::EXPORT_TABLE,
>> +                              section->getVirtualAddress(),
>> section->size());
>>    }
>>
>>    // Now that we know the size and file offset of sections. Set the file
>>
>> Added: lld/trunk/test/pecoff/Inputs/export.obj.yaml
>> URL:
>> http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/Inputs/export.obj.yaml?rev=197212&view=auto
>>
>> ==============================================================================
>> --- lld/trunk/test/pecoff/Inputs/export.obj.yaml (added)
>> +++ lld/trunk/test/pecoff/Inputs/export.obj.yaml Fri Dec 13 00:58:27 2013
>> @@ -0,0 +1,31 @@
>> +---
>> +header:
>> +  Machine:         IMAGE_FILE_MACHINE_I386
>> +  Characteristics: []
>> +sections:
>> +  - Name:            .text
>> +    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE,
>> IMAGE_SCN_MEM_READ ]
>> +    Alignment:       4
>> +    SectionData:
>> B800000000506800000000680000000050E80000000050E800000000
>> +symbols:
>> +  - Name:            .text
>> +    Value:           0
>> +    SectionNumber:   1
>> +    SimpleType:      IMAGE_SYM_TYPE_NULL
>> +    ComplexType:     IMAGE_SYM_DTYPE_NULL
>> +    StorageClass:    IMAGE_SYM_CLASS_STATIC
>> +    NumberOfAuxSymbols: 1
>> +    AuxiliaryData:   1C0000000400000000000000000000000000
>> +  - Name:            _init
>> +    Value:           0
>> +    SectionNumber:   1
>> +    SimpleType:      IMAGE_SYM_TYPE_NULL
>> +    ComplexType:     IMAGE_SYM_DTYPE_NULL
>> +    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
>> +  - Name:            _exportfn
>> +    Value:           8
>> +    SectionNumber:   1
>> +    SimpleType:      IMAGE_SYM_TYPE_NULL
>> +    ComplexType:     IMAGE_SYM_DTYPE_NULL
>> +    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
>> +...
>>
>> Added: lld/trunk/test/pecoff/export.test
>> URL:
>> http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/export.test?rev=197212&view=auto
>>
>> ==============================================================================
>> --- lld/trunk/test/pecoff/export.test (added)
>> +++ lld/trunk/test/pecoff/export.test Fri Dec 13 00:58:27 2013
>> @@ -0,0 +1,12 @@
>> +# RUN: yaml2obj %p/Inputs/export.obj.yaml > %t.obj
>> +#
>> +# RUN: lld -flavor link /out:%t.dll /dll /subsystem:console /entry:_init
>> \
>> +# RUN:   /export:exportfn -- %t.obj
>> +# RUN: llvm-objdump -s %t.dll | FileCheck %s
>> +
>> +CHECK:      Contents of section .edata:
>> +CHECK-NEXT:  1000 00000000 {{........}} 00000000 28100000
>> +CHECK-NEXT:  1010 01000000 01000000 01000000 3c100000
>> +CHECK-NEXT:  1020 40100000 4e100000 6578706f 72742e74
>> +CHECK-NEXT:  1030 6573742e 746d702e 646c6c00 08200000
>> +CHECK-NEXT:  1040 44100000 5f657870 6f727466 6e000000
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20131213/46f17af5/attachment.html>


More information about the llvm-commits mailing list