[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