diff options
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h | 103 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp | 5 | ||||
-rw-r--r-- | lld/test/pecoff/localyimported.test | 7 | ||||
-rw-r--r-- | lld/test/pecoff/reloc.test | 10 |
4 files changed, 100 insertions, 25 deletions
diff --git a/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h b/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h index cbf7ddcde07..e6926980f18 100644 --- a/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h +++ b/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h @@ -9,6 +9,7 @@ #include "Atoms.h" +#include "lld/Core/ArchiveLibraryFile.h" #include "lld/ReaderWriter/PECOFFLinkingContext.h" #include "lld/ReaderWriter/Simple.h" #include "llvm/Support/Allocator.h" @@ -16,6 +17,8 @@ namespace lld { namespace pecoff { +namespace { + /// The defined atom for dllexported symbols with __imp_ prefix. class ImpPointerAtom : public COFFLinkerInternalAtom { public: @@ -34,6 +37,24 @@ private: uint64_t _ordinal; }; +class ImpSymbolFile : public SimpleFile { +public: + ImpSymbolFile(StringRef defsym, StringRef undefsym, uint64_t ordinal) + : SimpleFile(defsym), _undefined(*this, undefsym), + _defined(*this, defsym, ordinal) { + _defined.addReference(std::unique_ptr<COFFReference>( + new COFFReference(&_undefined, 0, llvm::COFF::IMAGE_REL_I386_DIR32))); + addAtom(_defined); + addAtom(_undefined); + }; + +private: + SimpleUndefinedAtom _undefined; + ImpPointerAtom _defined; +}; + +} // anonymous namespace + // A virtual file containing absolute symbol __ImageBase. __ImageBase (or // ___ImageBase on x86) is a linker-generated symbol whose address is the same // as the image base address. @@ -44,31 +65,73 @@ public: _imageBaseAtom(*this, ctx.decorateSymbol("__ImageBase"), Atom::scopeGlobal, ctx.getBaseAddress()) { addAtom(_imageBaseAtom); - _ordinal = 1; - - // Create implciit symbols for exported symbols. - for (const PECOFFLinkingContext::ExportDesc &exp : ctx.getDllExports()) { - UndefinedAtom *target = new (_alloc) SimpleUndefinedAtom(*this, exp.name); - COFFLinkerInternalAtom *imp = createImpPointerAtom(ctx, exp.name); - imp->addReference(std::unique_ptr<COFFReference>( - new COFFReference(target, 0, llvm::COFF::IMAGE_REL_I386_DIR32))); - addAtom(*target); - addAtom(*imp); - } }; private: - COFFLinkerInternalAtom *createImpPointerAtom(const PECOFFLinkingContext &ctx, - StringRef name) { - std::string sym = "_imp_"; - sym.append(name); - sym = ctx.decorateSymbol(sym); - return new (_alloc) ImpPointerAtom(*this, ctx.allocate(sym), _ordinal++); + COFFAbsoluteAtom _imageBaseAtom; +}; + +// A LocallyImporteSymbolFile is an archive file containing _imp_ +// symbols for local use. +// +// For each defined symbol, linker creates an implicit defined symbol +// by appending "_imp_" prefix to the original name. The content of +// the implicit symbol is a pointer to the original symbol +// content. This feature allows one to compile and link the following +// code without error, although _imp__hello is not defined in the +// code. +// +// void hello() { printf("Hello\n"); } +// extern void (*_imp__hello)(); +// int main() { +// _imp__hello(); +// return 0; +// } +// +// This odd feature is for the compatibility with MSVC link.exe. +class LocallyImportedSymbolFile : public ArchiveLibraryFile { +public: + LocallyImportedSymbolFile(const PECOFFLinkingContext &ctx) + : ArchiveLibraryFile("__imp_"), _prefix(ctx.decorateSymbol("_imp_")), + _ordinal(0) {} + + const File *find(StringRef sym, bool dataSymbolOnly) const override { + if (!sym.startswith(_prefix)) + return nullptr; + StringRef undef = sym.substr(_prefix.size()); + return new (_alloc) ImpSymbolFile(sym, undef, _ordinal++); } - COFFAbsoluteAtom _imageBaseAtom; - uint64_t _ordinal; - llvm::BumpPtrAllocator _alloc; + const atom_collection<DefinedAtom> &defined() const override { + return _definedAtoms; + } + + const atom_collection<UndefinedAtom> &undefined() const override { + return _undefinedAtoms; + } + + const atom_collection<SharedLibraryAtom> &sharedLibrary() const override { + return _sharedLibraryAtoms; + } + + const atom_collection<AbsoluteAtom> &absolute() const override { + return _absoluteAtoms; + } + + error_code + parseAllMembers(std::vector<std::unique_ptr<File>> &result) const override { + return error_code::success(); + } + +private: + std::string _prefix; + mutable uint64_t _ordinal; + mutable llvm::BumpPtrAllocator _alloc; + + atom_collection_vector<DefinedAtom> _definedAtoms; + atom_collection_vector<UndefinedAtom> _undefinedAtoms; + atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms; + atom_collection_vector<AbsoluteAtom> _absoluteAtoms; }; } // end namespace pecoff diff --git a/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp b/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp index 474b14829b6..d9117d05a5e 100644 --- a/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp +++ b/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp @@ -110,6 +110,11 @@ bool PECOFFLinkingContext::createImplicitFiles( fileNode->appendInputFile(std::move(linkerGeneratedSymFile)); getInputGraph().insertElementAt(std::move(fileNode), InputGraph::Position::END); + + std::unique_ptr<SimpleFileNode> impFileNode(new SimpleFileNode("imp")); + impFileNode->appendInputFile( + std::unique_ptr<File>(new pecoff::LocallyImportedSymbolFile(*this))); + getLibraryGroup()->addFile(std::move(impFileNode)); return true; } diff --git a/lld/test/pecoff/localyimported.test b/lld/test/pecoff/localyimported.test new file mode 100644 index 00000000000..592c0fa6507 --- /dev/null +++ b/lld/test/pecoff/localyimported.test @@ -0,0 +1,7 @@ +# RUN: yaml2obj %p/Inputs/hello.obj.yaml > %t.obj +# +# RUN: not lld -flavor link /out:%t2.exe /include:__imp__nosuchsym %t.obj \ +# RUN: >& %t2.log +# RUN: FileCheck %s < %t2.log + +CHECK: Undefined symbol: __imp__nosuchsym: _nosuchsym diff --git a/lld/test/pecoff/reloc.test b/lld/test/pecoff/reloc.test index 08f95b12eba..ba1e9353c09 100644 --- a/lld/test/pecoff/reloc.test +++ b/lld/test/pecoff/reloc.test @@ -5,8 +5,8 @@ # RUN: llvm-objdump -d %t.exe | FileCheck %s CHECK: .text: -CHECK: 2000: 68 02 00 00 00 -CHECK: 2005: 68 05 00 00 00 -CHECK: 200a: 68 00 10 40 00 -CHECK: 200f: 68 00 10 40 00 -CHECK: 2014: 68 00 00 40 00 +CHECK: 3000: 68 02 00 00 00 +CHECK: 3005: 68 05 00 00 00 +CHECK: 300a: 68 00 10 40 00 +CHECK: 300f: 68 00 10 40 00 +CHECK: 3014: 68 00 20 40 00 |