diff options
Diffstat (limited to 'COFF')
-rw-r--r-- | COFF/Chunks.cpp | 44 | ||||
-rw-r--r-- | COFF/Config.h | 1 | ||||
-rw-r--r-- | COFF/Driver.cpp | 17 | ||||
-rw-r--r-- | COFF/Driver.h | 2 | ||||
-rw-r--r-- | COFF/DriverUtils.cpp | 27 | ||||
-rw-r--r-- | COFF/InputFiles.h | 3 | ||||
-rw-r--r-- | COFF/Librarian.cpp | 20 | ||||
-rw-r--r-- | COFF/ModuleDef.cpp | 7 | ||||
-rw-r--r-- | COFF/SymbolTable.h | 5 |
9 files changed, 100 insertions, 26 deletions
diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp index 10eeedd88e551..2e49f417a2064 100644 --- a/COFF/Chunks.cpp +++ b/COFF/Chunks.cpp @@ -319,8 +319,48 @@ void SEHTableChunk::writeTo(uint8_t *Buf) const { std::sort(Begin, Begin + Cnt); } -// Windows-specific. -// This class represents a block in .reloc section. +// Windows-specific. This class represents a block in .reloc section. +// The format is described here. +// +// On Windows, each DLL is linked against a fixed base address and +// usually loaded to that address. However, if there's already another +// DLL that overlaps, the loader has to relocate it. To do that, DLLs +// contain .reloc sections which contain offsets that need to be fixed +// up at runtime. If the loader find that a DLL cannot be loaded to its +// desired base address, it loads it to somewhere else, and add <actual +// base address> - <desired base address> to each offset that is +// specified by .reloc section. +// +// In ELF terms, .reloc sections contain arrays of relocation offsets. +// All these offsets in the section are implicitly R_*_RELATIVE, and +// addends are read from section contents (so it is REL as opposed to +// RELA). +// +// This already reduce the size of relocations to 1/3 compared to ELF +// .dynrel, but Windows does more to reduce it (probably because it was +// invented for PCs in the late '80s or early '90s.) Offsets in .reloc +// are grouped by page where page size is 16 bits, and offsets sharing +// the same page address are stored consecutively to represent them with +// less space. This is a very similar to the page table which is grouped +// by (multiple stages of) pages. +// +// For example, let's say we have 0x00030, 0x00500, 0x01000, 0x01100, +// 0x20004, and 0x20008 in a .reloc section. In the section, they are +// represented like this: +// +// 0x00000 -- page address (4 bytes) +// 16 -- size of this block (4 bytes) +// 0x0030 -- entries (2 bytes each) +// 0x0500 +// 0x1000 +// 0x1100 +// 0x20000 -- page address (4 bytes) +// 12 -- size of this block (4 bytes) +// 0x0004 -- entries (2 bytes each) +// 0x0008 +// +// Usually we have a lot of relocatinos for each page, so the number of +// bytes for one .reloc entry is close to 2 bytes. BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) { // Block header consists of 4 byte page RVA and 4 byte block size. // Each entry is 2 byte. Last entry may be padding. diff --git a/COFF/Config.h b/COFF/Config.h index 31534aeb39719..fafd3bcde2e32 100644 --- a/COFF/Config.h +++ b/COFF/Config.h @@ -43,6 +43,7 @@ struct Export { bool Noname = false; bool Data = false; bool Private = false; + bool Constant = false; // If an export is a form of /export:foo=dllname.bar, that means // that foo should be exported as an alias to bar in the DLL. diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp index daddfb86d4cf2..5a15b5b11507e 100644 --- a/COFF/Driver.cpp +++ b/COFF/Driver.cpp @@ -512,6 +512,23 @@ void LinkerDriver::invokeMSVC(opt::InputArgList &Args) { std::string Rsp = "/nologo\n"; std::vector<std::string> Temps; + // Write out archive members that we used in symbol resolution and pass these + // to MSVC before any archives, so that MSVC uses the same objects to satisfy + // references. + for (const auto *O : Symtab.ObjectFiles) { + if (O->ParentName.empty()) + continue; + SmallString<128> S; + int Fd; + if (auto EC = sys::fs::createTemporaryFile( + "lld-" + sys::path::filename(O->ParentName), ".obj", Fd, S)) + fatal(EC, "cannot create a temporary file"); + raw_fd_ostream OS(Fd, /*shouldClose*/ true); + OS << O->MB.getBuffer(); + Temps.push_back(S.str()); + Rsp += quote(S) + "\n"; + } + for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_linkrepro: diff --git a/COFF/Driver.h b/COFF/Driver.h index 4566f73eef318..ad725625e030f 100644 --- a/COFF/Driver.h +++ b/COFF/Driver.h @@ -48,7 +48,7 @@ public: llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> Args); // Concatenate LINK environment varirable and given arguments and parse them. - llvm::opt::InputArgList parseLINK(llvm::ArrayRef<const char *> Args); + llvm::opt::InputArgList parseLINK(std::vector<const char *> Args); // Tokenizes a given string and then parses as command line options. llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); } diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp index 2c9ba797f73b3..252590c7d8703 100644 --- a/COFF/DriverUtils.cpp +++ b/COFF/DriverUtils.cpp @@ -479,6 +479,10 @@ Export parseExport(StringRef Arg) { E.Data = true; continue; } + if (Tok.equals_lower("constant")) { + E.Constant = true; + continue; + } if (Tok.equals_lower("private")) { E.Private = true; continue; @@ -695,17 +699,20 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> ArgsArr) { return Args; } -// link.exe has an interesting feature. If LINK environment exists, -// its contents are handled as a command line string. So you can pass -// extra arguments using the environment variable. -opt::InputArgList ArgParser::parseLINK(ArrayRef<const char *> Args) { +// link.exe has an interesting feature. If LINK or _LINK_ environment +// variables exist, their contents are handled as command line strings. +// So you can pass extra arguments using them. +opt::InputArgList ArgParser::parseLINK(std::vector<const char *> Args) { // Concatenate LINK env and command line arguments, and then parse them. - Optional<std::string> Env = Process::GetEnv("LINK"); - if (!Env) - return parse(Args); - std::vector<const char *> V = tokenize(*Env); - V.insert(V.end(), Args.begin(), Args.end()); - return parse(V); + if (Optional<std::string> S = Process::GetEnv("LINK")) { + std::vector<const char *> V = tokenize(*S); + Args.insert(Args.begin(), V.begin(), V.end()); + } + if (Optional<std::string> S = Process::GetEnv("_LINK_")) { + std::vector<const char *> V = tokenize(*S); + Args.insert(Args.begin(), V.begin(), V.end()); + } + return parse(Args); } std::vector<const char *> ArgParser::tokenize(StringRef S) { diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h index 9e02b2fc68bb8..3078de687525d 100644 --- a/COFF/InputFiles.h +++ b/COFF/InputFiles.h @@ -58,6 +58,8 @@ public: // Returns the CPU type this file was compiled to. virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; } + MemoryBufferRef MB; + // An archive file name if this file is created from an archive. StringRef ParentName; @@ -67,7 +69,6 @@ public: protected: InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} - MemoryBufferRef MB; std::string Directives; private: diff --git a/COFF/Librarian.cpp b/COFF/Librarian.cpp index 3ce72822180b0..91316ee6b0c91 100644 --- a/COFF/Librarian.cpp +++ b/COFF/Librarian.cpp @@ -162,7 +162,7 @@ public: // Create a short import file which is described in PE/COFF spec 7. Import // Library Format. NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal, - ImportNameType NameType, bool isData); + ImportType Type, ImportNameType NameType); }; } @@ -440,8 +440,8 @@ NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) { NewArchiveMember ObjectFactory::createShortImport(StringRef Sym, uint16_t Ordinal, - ImportNameType NameType, - bool isData) { + ImportType ImportType, + ImportNameType NameType) { size_t ImpSize = DLLName.size() + Sym.size() + 2; // +2 for NULs size_t Size = sizeof(coff_import_header) + ImpSize; char *Buf = Alloc.Allocate<char>(Size); @@ -456,8 +456,7 @@ NewArchiveMember ObjectFactory::createShortImport(StringRef Sym, Imp->SizeOfData = ImpSize; if (Ordinal > 0) Imp->OrdinalHint = Ordinal; - Imp->TypeInfo = (isData ? IMPORT_DATA : IMPORT_CODE); - Imp->TypeInfo |= NameType << 2; + Imp->TypeInfo = (NameType << 2) | ImportType; // Write symbol name and DLL name. memcpy(P, Sym.data(), Sym.size()); @@ -490,11 +489,18 @@ void lld::coff::writeImportLibrary() { if (E.Private) continue; - ImportNameType Type = getNameType(E.SymbolName, E.Name); + ImportType ImportType = IMPORT_CODE; + if (E.Data) + ImportType = IMPORT_DATA; + if (E.Constant) + ImportType = IMPORT_CONST; + + ImportNameType NameType = getNameType(E.SymbolName, E.Name); std::string Name = E.ExtName.empty() ? std::string(E.SymbolName) : replace(E.SymbolName, E.Name, E.ExtName); - Members.push_back(OF.createShortImport(Name, E.Ordinal, Type, E.Data)); + Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType, + NameType)); } std::pair<StringRef, std::error_code> Result = diff --git a/COFF/ModuleDef.cpp b/COFF/ModuleDef.cpp index c9a40ac5ab8c6..740ce867a7c4a 100644 --- a/COFF/ModuleDef.cpp +++ b/COFF/ModuleDef.cpp @@ -38,6 +38,7 @@ enum Kind { Comma, Equal, KwBase, + KwConstant, KwData, KwExports, KwHeapsize, @@ -92,6 +93,7 @@ public: StringRef Word = Buf.substr(0, End); Kind K = llvm::StringSwitch<Kind>(Word) .Case("BASE", KwBase) + .Case("CONSTANT", KwConstant) .Case("DATA", KwData) .Case("EXPORTS", KwExports) .Case("HEAPSIZE", KwHeapsize) @@ -227,6 +229,11 @@ private: E.Data = true; continue; } + if (Tok.K == KwConstant) { + warn("CONSTANT keyword is obsolete; use DATA"); + E.Constant = true; + continue; + } if (Tok.K == KwPrivate) { E.Private = true; continue; diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h index 764dd53187750..bf8d6618d964a 100644 --- a/COFF/SymbolTable.h +++ b/COFF/SymbolTable.h @@ -108,14 +108,9 @@ public: std::vector<Chunk *> LocalImportChunks; private: - void readArchive(); - void readObjects(); - std::pair<Symbol *, bool> insert(StringRef Name); StringRef findByPrefix(StringRef Prefix); - void addCombinedLTOObject(ObjectFile *Obj); - llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> Symtab; std::vector<BitcodeFile *> BitcodeFiles; |