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

Yaron Keren yaron.keren at gmail.com
Thu Dec 12 23:10:50 PST 2013


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/a37b93db/attachment.html>


More information about the llvm-commits mailing list