summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp')
-rw-r--r--lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp389
1 files changed, 0 insertions, 389 deletions
diff --git a/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp b/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp
deleted file mode 100644
index 8c9641376a0d..000000000000
--- a/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp
+++ /dev/null
@@ -1,389 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp ---------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file \brief This file provides a way to read an import library member in a
-/// .lib file.
-///
-/// Archive Files in Windows
-/// ========================
-///
-/// In Windows, archive files with .lib file extension serve two different
-/// purposes.
-///
-/// - For static linking: An archive file in this use case contains multiple
-/// regular .obj files and is used for static linking. This is the same
-/// usage as .a file in Unix.
-///
-/// - For dynamic linking: An archive file in this use case contains pseudo
-/// .obj files to describe exported symbols of a DLL. Each pseudo .obj file
-/// in an archive has a name of an exported symbol and a DLL filename from
-/// which the symbol can be imported. When you link a DLL on Windows, you
-/// pass the name of the .lib file for the DLL instead of the DLL filename
-/// itself. That is the Windows way of linking against a shared library.
-///
-/// This file contains a function to handle the pseudo object file.
-///
-/// Windows Loader and Import Address Table
-/// =======================================
-///
-/// Windows supports a GOT-like mechanism for DLLs. The executable using DLLs
-/// contains a list of DLL names and list of symbols that need to be resolved by
-/// the loader. Windows loader maps the executable and all the DLLs to memory,
-/// resolves the symbols referencing items in DLLs, and updates the import
-/// address table (IAT) in memory. The IAT is an array of pointers to all of the
-/// data or functions in DLL referenced by the executable. You cannot access
-/// items in DLLs directly. They have to be accessed through an extra level of
-/// indirection.
-///
-/// So, if you want to access an item in DLL, you have to go through a
-/// pointer. How do you actually do that? You need a symbol for a pointer in the
-/// IAT. For each symbol defined in a DLL, a symbol with "__imp_" prefix is
-/// exported from the DLL for an IAT entry. For example, if you have a global
-/// variable "foo" in a DLL, a pointer to the variable is available as
-/// "_imp__foo". The IAT is an array of _imp__ symbols.
-///
-/// Is this OK? That's not that complicated. Because items in a DLL are not
-/// directly accessible, you need to access through a pointer, and the pointer
-/// is available as a symbol with _imp__ prefix.
-///
-/// Note 1: Although you can write code with _imp__ prefix, today's compiler and
-/// linker let you write code as if there's no extra level of indirection.
-/// That's why you haven't seen lots of _imp__ in your code. A variable or a
-/// function declared with "dllimport" attribute is treated as an item in a DLL,
-/// and the compiler automatically mangles its name and inserts the extra level
-/// of indirection when accessing the item. Here are some examples:
-///
-/// __declspec(dllimport) int var_in_dll;
-/// var_in_dll = 3; // is equivalent to *_imp__var_in_dll = 3;
-///
-/// __declspec(dllimport) int fn_in_dll(void);
-/// fn_in_dll(); // is equivalent to (*_imp__fn_in_dll)();
-///
-/// It's just the compiler rewrites code for you so that you don't need to
-/// handle the indirection yourself.
-///
-/// Note 2: __declspec(dllimport) is mandatory for data but optional for
-/// function. For a function, the linker creates a jump table with the original
-/// symbol name, so that the function is accessible without _imp__ prefix. The
-/// same function in a DLL can be called through two different symbols if it's
-/// not dllimport'ed.
-///
-/// (*_imp__fn)()
-/// fn()
-///
-/// The above functions do the same thing. fn's content is a JMP instruction to
-/// branch to the address pointed by _imp__fn. The latter may be a little bit
-/// slower than the former because it will execute the extra JMP instruction,
-/// but that's usually negligible.
-///
-/// If a function is dllimport'ed, which is usually done in a header file,
-/// mangled name will be used at compile time so the jump table will not be
-/// used.
-///
-/// Because there's no way to hide the indirection for data access at link time,
-/// data has to be accessed through dllimport'ed symbols or explicit _imp__
-/// prefix.
-///
-/// Idata Sections in the Pseudo Object File
-/// ========================================
-///
-/// The object file created by cl.exe has several sections whose name starts
-/// with ".idata$" followed by a number. The contents of the sections seem the
-/// fragments of a complete ".idata" section. These sections has relocations for
-/// the data referenced from the idata secton. Generally, the linker discards
-/// "$" and all characters that follow from the section name and merges their
-/// contents to one section. So, it looks like if everything would work fine,
-/// the idata section would naturally be constructed without having any special
-/// code for doing that.
-///
-/// However, the LLD linker cannot do that. An idata section constructed in that
-/// way was never be in valid format. We don't know the reason yet. Our
-/// assumption on the idata fragment could simply be wrong, or the LLD linker is
-/// not powerful enough to do the job. Meanwhile, we construct the idata section
-/// ourselves. All the "idata$" sections in the pseudo object file are currently
-/// ignored.
-///
-/// Creating Atoms for the Import Address Table
-/// ===========================================
-///
-/// The function in this file reads a pseudo object file and creates at most two
-/// atoms. One is a shared library atom for _imp__ symbol. The another is a
-/// defined atom for the JMP instruction if the symbol is for a function.
-///
-//===----------------------------------------------------------------------===//
-
-#include "Atoms.h"
-#include "lld/Core/Error.h"
-#include "lld/Core/File.h"
-#include "lld/Core/SharedLibraryAtom.h"
-#include "lld/ReaderWriter/PECOFFLinkingContext.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Support/COFF.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/Memory.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cstring>
-#include <map>
-#include <system_error>
-#include <vector>
-
-using namespace lld;
-using namespace lld::pecoff;
-using namespace llvm;
-using namespace llvm::support::endian;
-
-#define DEBUG_TYPE "ReaderImportHeader"
-
-namespace lld {
-
-namespace {
-
-// This code is valid both in x86 and x64.
-const uint8_t FuncAtomContentX86[] = {
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0
- 0xcc, 0xcc // INT 3; INT 3
-};
-
-const uint8_t FuncAtomContentARMNT[] = {
- 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0
- 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0
- 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip]
-};
-
-static void setJumpInstTarget(COFFLinkerInternalAtom *src, const Atom *dst,
- int off, MachineTypes machine) {
- SimpleReference *ref;
-
- switch (machine) {
- default: llvm::report_fatal_error("unsupported machine type");
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- ref = new SimpleReference(Reference::KindNamespace::COFF,
- Reference::KindArch::x86,
- llvm::COFF::IMAGE_REL_I386_DIR32,
- off, dst, 0);
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- ref = new SimpleReference(Reference::KindNamespace::COFF,
- Reference::KindArch::x86_64,
- llvm::COFF::IMAGE_REL_AMD64_REL32,
- off, dst, 0);
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
- ref = new SimpleReference(Reference::KindNamespace::COFF,
- Reference::KindArch::ARM,
- llvm::COFF::IMAGE_REL_ARM_MOV32T,
- off, dst, 0);
- break;
- }
- src->addReference(std::unique_ptr<SimpleReference>(ref));
-}
-
-/// The defined atom for jump table.
-class FuncAtom : public COFFLinkerInternalAtom {
-public:
- FuncAtom(const File &file, StringRef symbolName,
- const COFFSharedLibraryAtom *impAtom, MachineTypes machine)
- : COFFLinkerInternalAtom(file, /*oridnal*/ 0, createContent(machine),
- symbolName) {
- size_t Offset;
-
- switch (machine) {
- default: llvm::report_fatal_error("unsupported machine type");
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- Offset = 2;
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
- Offset = 0;
- break;
- }
-
- setJumpInstTarget(this, impAtom, Offset, machine);
- }
-
- uint64_t ordinal() const override { return 0; }
- Scope scope() const override { return scopeGlobal; }
- ContentType contentType() const override { return typeCode; }
- Alignment alignment() const override { return Alignment(1); }
- ContentPermissions permissions() const override { return permR_X; }
-
-private:
- std::vector<uint8_t> createContent(MachineTypes machine) const {
- const uint8_t *Data;
- size_t Size;
-
- switch (machine) {
- default: llvm::report_fatal_error("unsupported machine type");
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- Data = FuncAtomContentX86;
- Size = sizeof(FuncAtomContentX86);
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
- Data = FuncAtomContentARMNT;
- Size = sizeof(FuncAtomContentARMNT);
- break;
- }
-
- return std::vector<uint8_t>(Data, Data + Size);
- }
-};
-
-class FileImportLibrary : public File {
-public:
- FileImportLibrary(std::unique_ptr<MemoryBuffer> mb, MachineTypes machine)
- : File(mb->getBufferIdentifier(), kindSharedLibrary),
- _mb(std::move(mb)), _machine(machine) {}
-
- std::error_code doParse() override {
- const char *buf = _mb->getBufferStart();
- const char *end = _mb->getBufferEnd();
-
- // The size of the string that follows the header.
- uint32_t dataSize
- = read32le(buf + offsetof(COFF::ImportHeader, SizeOfData));
-
- // Check if the total size is valid.
- if (std::size_t(end - buf) != sizeof(COFF::ImportHeader) + dataSize)
- return make_error_code(NativeReaderError::unknown_file_format);
-
- uint16_t hint = read16le(buf + offsetof(COFF::ImportHeader, OrdinalHint));
- StringRef symbolName(buf + sizeof(COFF::ImportHeader));
- StringRef dllName(buf + sizeof(COFF::ImportHeader) + symbolName.size() + 1);
-
- // TypeInfo is a bitfield. The least significant 2 bits are import
- // type, followed by 3 bit import name type.
- uint16_t typeInfo = read16le(buf + offsetof(COFF::ImportHeader, TypeInfo));
- int type = typeInfo & 0x3;
- int nameType = (typeInfo >> 2) & 0x7;
-
- // Symbol name used by the linker may be different from the symbol name used
- // by the loader. The latter may lack symbol decorations, or may not even
- // have name if it's imported by ordinal.
- StringRef importName = symbolNameToImportName(symbolName, nameType);
-
- const COFFSharedLibraryAtom *dataAtom =
- addSharedLibraryAtom(hint, symbolName, importName, dllName);
- if (type == llvm::COFF::IMPORT_CODE)
- addFuncAtom(symbolName, dllName, dataAtom);
-
- return std::error_code();
- }
-
- const atom_collection<DefinedAtom> &defined() const override {
- return _definedAtoms;
- }
-
- const atom_collection<UndefinedAtom> &undefined() const override {
- return _noUndefinedAtoms;
- }
-
- const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
- return _sharedLibraryAtoms;
- }
-
- const atom_collection<AbsoluteAtom> &absolute() const override {
- return _noAbsoluteAtoms;
- }
-
-private:
- const COFFSharedLibraryAtom *addSharedLibraryAtom(uint16_t hint,
- StringRef symbolName,
- StringRef importName,
- StringRef dllName) {
- auto *atom = new (_alloc)
- COFFSharedLibraryAtom(*this, hint, symbolName, importName, dllName);
- _sharedLibraryAtoms._atoms.push_back(atom);
- return atom;
- }
-
- void addFuncAtom(StringRef symbolName, StringRef dllName,
- const COFFSharedLibraryAtom *impAtom) {
- auto *atom = new (_alloc) FuncAtom(*this, symbolName, impAtom, _machine);
- _definedAtoms._atoms.push_back(atom);
- }
-
- atom_collection_vector<DefinedAtom> _definedAtoms;
- atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
- mutable llvm::BumpPtrAllocator _alloc;
-
- // Does the same thing as StringRef::ltrim() but removes at most one
- // character.
- StringRef ltrim1(StringRef str, const char *chars) const {
- if (!str.empty() && strchr(chars, str[0]))
- return str.substr(1);
- return str;
- }
-
- // Convert the given symbol name to the import symbol name exported by the
- // DLL.
- StringRef symbolNameToImportName(StringRef symbolName, int nameType) const {
- StringRef ret;
- switch (nameType) {
- case llvm::COFF::IMPORT_ORDINAL:
- // The import is by ordinal. No symbol name will be used to identify the
- // item in the DLL. Only its ordinal will be used.
- return "";
- case llvm::COFF::IMPORT_NAME:
- // The import name in this case is identical to the symbol name.
- return symbolName;
- case llvm::COFF::IMPORT_NAME_NOPREFIX:
- // The import name is the symbol name without leading ?, @ or _.
- ret = ltrim1(symbolName, "?@_");
- break;
- case llvm::COFF::IMPORT_NAME_UNDECORATE:
- // Similar to NOPREFIX, but we also need to truncate at the first @.
- ret = ltrim1(symbolName, "?@_");
- ret = ret.substr(0, ret.find('@'));
- break;
- }
- std::string *str = new (_alloc) std::string(ret);
- return *str;
- }
-
- std::unique_ptr<MemoryBuffer> _mb;
- MachineTypes _machine;
-};
-
-class COFFImportLibraryReader : public Reader {
-public:
- COFFImportLibraryReader(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
-
- bool canParse(file_magic magic, StringRef,
- const MemoryBuffer &mb) const override {
- if (mb.getBufferSize() < sizeof(COFF::ImportHeader))
- return false;
- return (magic == llvm::sys::fs::file_magic::coff_import_library);
- }
-
- std::error_code
- loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
- std::vector<std::unique_ptr<File> > &result) const override {
- auto *file = new FileImportLibrary(std::move(mb), _ctx.getMachineType());
- result.push_back(std::unique_ptr<File>(file));
- return std::error_code();
- }
-
-private:
- PECOFFLinkingContext &_ctx;
-};
-
-} // end anonymous namespace
-
-void Registry::addSupportCOFFImportLibraries(PECOFFLinkingContext &ctx) {
- add(llvm::make_unique<COFFImportLibraryReader>(ctx));
-}
-
-} // end namespace lld