llvm-project/lld/ELF/InputFiles.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

420 lines
13 KiB
C
Raw Normal View History

//===- InputFiles.h ---------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLD_ELF_INPUT_FILES_H
#define LLD_ELF_INPUT_FILES_H
#include "Config.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/LLVM.h"
#include "lld/Common/Reproduce.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/Comdat.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/IRObjectFile.h"
#include "llvm/Support/Threading.h"
#include <map>
namespace llvm {
struct DILineInfo;
class TarWriter;
namespace lto {
class InputFile;
}
} // namespace llvm
namespace lld {
class DWARFCache;
// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
std::string toString(const elf::InputFile *f);
2016-02-28 08:25:54 +08:00
namespace elf {
using llvm::object::Archive;
class Symbol;
// If --reproduce is specified, all input files are written to this tar archive.
extern std::unique_ptr<llvm::TarWriter> tar;
// Opens a given file.
llvm::Optional<MemoryBufferRef> readFile(StringRef path);
// Add symbols in File to the symbol table.
void parseFile(InputFile *file);
// The root class of input files.
class InputFile {
public:
enum Kind {
ObjKind,
SharedKind,
LazyObjKind,
ArchiveKind,
BitcodeKind,
BinaryKind,
};
Kind kind() const { return fileKind; }
bool isElf() const {
Kind k = kind();
return k == ObjKind || k == SharedKind;
}
StringRef getName() const { return mb.getBufferIdentifier(); }
MemoryBufferRef mb;
2017-03-22 01:22:13 +08:00
// Returns sections. It is a runtime error to call this function
// on files that don't have the notion of sections.
ArrayRef<InputSectionBase *> getSections() const {
assert(fileKind == ObjKind || fileKind == BinaryKind);
return sections;
}
// Returns object file symbols. It is a runtime error to call this
// function on files of other types.
ArrayRef<Symbol *> getSymbols() { return getMutableSymbols(); }
MutableArrayRef<Symbol *> getMutableSymbols() {
assert(fileKind == BinaryKind || fileKind == ObjKind ||
fileKind == BitcodeKind);
return symbols;
}
// Get filename to use for linker script processing.
StringRef getNameForScript() const;
// If not empty, this stores the name of the archive containing this file.
// We use this string for creating error messages.
std::string archiveName;
// If this is an architecture-specific file, the following members
// have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type.
ELFKind ekind = ELFNoneKind;
uint16_t emachine = llvm::ELF::EM_NONE;
uint8_t osabi = 0;
uint8_t abiVersion = 0;
// Cache for toString(). Only toString() should use this member.
mutable std::string toStringCache;
std::string getSrcMsg(const Symbol &sym, InputSectionBase &sec,
uint64_t offset);
// True if this is an argument for --just-symbols. Usually false.
bool justSymbols = false;
// outSecOff of .got2 in the current file. This is used by PPC32 -fPIC/-fPIE
[PPC32] Improve the 32-bit PowerPC port Many -static/-no-pie/-shared/-pie applications linked against glibc or musl should work with this patch. This also helps FreeBSD PowerPC64 to migrate their lib32 (PR40888). * Fix default image base and max page size. * Support new-style Secure PLT (see below). Old-style BSS PLT is not implemented, so it is not suitable for FreeBSD rtld now because it doesn't support Secure PLT yet. * Support more initial relocation types: R_PPC_ADDR32, R_PPC_REL16*, R_PPC_LOCAL24PC, R_PPC_PLTREL24, and R_PPC_GOT16. The addend of R_PPC_PLTREL24 is special: it decides the call stub PLT type but it should be ignored for the computation of target symbol VA. * Support GNU ifunc * Support .glink used for lazy PLT resolution in glibc * Add a new thunk type: PPC32PltCallStub that is similar to PPC64PltCallStub. It is used by R_PPC_REL24 and R_PPC_PLTREL24. A PLT stub used in -fPIE/-fPIC usually loads an address relative to .got2+0x8000 (-fpie/-fpic code uses _GLOBAL_OFFSET_TABLE_ relative addresses). Two .got2 sections in two object files have different addresses, thus a PLT stub can't be shared by two object files. To handle this incompatibility, change the parameters of Thunk::isCompatibleWith to `const InputSection &, const Relocation &`. PowerPC psABI specified an old-style .plt (BSS PLT) that is both writable and executable. Linkers don't make separate RW- and RWE segments, which causes all initially writable memory (think .data) executable. This is a big security concern so a new PLT scheme (secure PLT) was developed to address the security issue. TLS will be implemented in D62940. glibc older than ~2012 requires .rela.dyn to include .rela.plt, it can not handle the DT_RELA+DT_RELASZ == DT_JMPREL case correctly. A hack (not included in this patch) in LinkerScript.cpp addOrphanSections() to work around the issue: if (Config->EMachine == EM_PPC) { // Older glibc assumes .rela.dyn includes .rela.plt Add(In.RelaDyn); if (In.RelaPlt->isLive() && !In.RelaPlt->Parent) In.RelaDyn->getParent()->addSection(In.RelaPlt); } Reviewed By: ruiu Differential Revision: https://reviews.llvm.org/D62464 llvm-svn: 362721
2019-06-07 01:03:00 +08:00
// to compute offsets in PLT call stubs.
uint32_t ppc32Got2OutSecOff = 0;
// On PPC64 we need to keep track of which files contain small code model
// relocations that access the .toc section. To minimize the chance of a
// relocation overflow, files that do contain said relocations should have
// their .toc sections sorted closer to the .got section than files that do
// not contain any small code model relocations. Thats because the toc-pointer
// is defined to point at .got + 0x8000 and the instructions used with small
// code model relocations support immediates in the range [-0x8000, 0x7FFC],
// making the addressable range relative to the toc pointer
// [.got, .got + 0xFFFC].
bool ppc64SmallCodeModelTocRelocs = false;
[ELF][PPC64] Detect missing R_PPC64_TLSGD/R_PPC64_TLSLD and disable TLS relaxation Alternative to D91611. The TLS General Dynamic/Local Dynamic code sequences need to mark `__tls_get_addr` with R_PPC64_TLSGD or R_PPC64_TLSLD, e.g. ``` addis r3, r2, x@got@tlsgd@ha # R_PPC64_GOT_TLSGD16_HA addi r3, r3, x@got@tlsgd@l # R_PPC64_GOT_TLSGD16_LO bl __tls_get_addr(x@tlsgd) # R_PPC64_TLSGD followed by R_PPC64_REL24 nop ``` However, there are two deviations form the above: 1. direct call to `__tls_get_addr`. This is essential to implement ld.so in glibc/musl/FreeBSD. ``` bl __tls_get_addr nop ``` This is only used in a -shared link, and thus not subject to the GD/LD to IE/LE relaxation issue below. 2. Missing R_PPC64_TLSGD/R_PPC64_TLSGD for compiler generated TLS references According to Stefan Pintille, "In the early days of the transition from the ELFv1 ABI that is used for big endian PowerPC Linux distributions to the ELFv2 ABI that is used for little endian PowerPC Linux distributions, there was some ambiguity in the specification of the relocations for TLS. The GNU linker has implemented support for correct handling of calls to __tls_get_addr with a missing relocation. Unfortunately, we didn't notice that the IBM XL compiler did not handle TLS according to the updated ABI until we tried linking XL compiled libraries with LLD." In short, LLD needs to work around the old IBM XL compiler issue. Otherwise, if the object file is linked in -no-pie or -pie mode, the result will be incorrect because the 4 instructions are partially rewritten (the latter 2 are not changed). Work around the compiler bug by disable General Dynamic/Local Dynamic to Initial Exec/Local Exec relaxation. Note, we also disable Initial Exec to Local Exec relaxation for implementation simplicity, though technically it can be kept. ppc64-tls-missing-gdld.s demonstrates the updated behavior. Reviewed By: #powerpc, stefanp, grimar Differential Revision: https://reviews.llvm.org/D92959
2020-12-22 00:45:41 +08:00
// True if the file has TLSGD/TLSLD GOT relocations without R_PPC64_TLSGD or
// R_PPC64_TLSLD. Disable TLS relaxation to avoid bad code generation.
bool ppc64DisableTLSRelax = false;
// groupId is used for --warn-backrefs which is an optional error
// checking feature. All files within the same --{start,end}-group or
// --{start,end}-lib get the same group ID. Otherwise, each file gets a new
// group ID. For more info, see checkDependency() in SymbolTable.cpp.
Add --warn-backrefs to maintain compatibility with other linkers I'm proposing a new command line flag, --warn-backrefs in this patch. The flag and the feature proposed below don't exist in GNU linkers nor the current lld. --warn-backrefs is an option to detect reverse or cyclic dependencies between static archives, and it can be used to keep your program compatible with GNU linkers after you switch to lld. I'll explain the feature and why you may find it useful below. lld's symbol resolution semantics is more relaxed than traditional Unix linkers. Therefore, ld.lld foo.a bar.o succeeds even if bar.o contains an undefined symbol that have to be resolved by some object file in foo.a. Traditional Unix linkers don't allow this kind of backward reference, as they visit each file only once from left to right in the command line while resolving all undefined symbol at the moment of visiting. In the above case, since there's no undefined symbol when a linker visits foo.a, no files are pulled out from foo.a, and because the linker forgets about foo.a after visiting, it can't resolve undefined symbols that could have been resolved otherwise. That lld accepts more relaxed form means (besides it makes more sense) that you can accidentally write a command line or a build file that works only with lld, even if you have a plan to distribute it to wider users who may be using GNU linkers. With --check-library-dependency, you can detect a library order that doesn't work with other Unix linkers. The option is also useful to detect cyclic dependencies between static archives. Again, lld accepts ld.lld foo.a bar.a even if foo.a and bar.a depend on each other. With --warn-backrefs it is handled as an error. Here is how the option works. We assign a group ID to each file. A file with a smaller group ID can pull out object files from an archive file with an equal or greater group ID. Otherwise, it is a reverse dependency and an error. A file outside --{start,end}-group gets a fresh ID when instantiated. All files within the same --{start,end}-group get the same group ID. E.g. ld.lld A B --start-group C D --end-group E A and B form group 0, C, D and their member object files form group 1, and E forms group 2. I think that you can see how this group assignment rule simulates the traditional linker's semantics. Differential Revision: https://reviews.llvm.org/D45195 llvm-svn: 329636
2018-04-10 07:05:48 +08:00
uint32_t groupId;
static bool isInGroup;
static uint32_t nextGroupId;
Add --warn-backrefs to maintain compatibility with other linkers I'm proposing a new command line flag, --warn-backrefs in this patch. The flag and the feature proposed below don't exist in GNU linkers nor the current lld. --warn-backrefs is an option to detect reverse or cyclic dependencies between static archives, and it can be used to keep your program compatible with GNU linkers after you switch to lld. I'll explain the feature and why you may find it useful below. lld's symbol resolution semantics is more relaxed than traditional Unix linkers. Therefore, ld.lld foo.a bar.o succeeds even if bar.o contains an undefined symbol that have to be resolved by some object file in foo.a. Traditional Unix linkers don't allow this kind of backward reference, as they visit each file only once from left to right in the command line while resolving all undefined symbol at the moment of visiting. In the above case, since there's no undefined symbol when a linker visits foo.a, no files are pulled out from foo.a, and because the linker forgets about foo.a after visiting, it can't resolve undefined symbols that could have been resolved otherwise. That lld accepts more relaxed form means (besides it makes more sense) that you can accidentally write a command line or a build file that works only with lld, even if you have a plan to distribute it to wider users who may be using GNU linkers. With --check-library-dependency, you can detect a library order that doesn't work with other Unix linkers. The option is also useful to detect cyclic dependencies between static archives. Again, lld accepts ld.lld foo.a bar.a even if foo.a and bar.a depend on each other. With --warn-backrefs it is handled as an error. Here is how the option works. We assign a group ID to each file. A file with a smaller group ID can pull out object files from an archive file with an equal or greater group ID. Otherwise, it is a reverse dependency and an error. A file outside --{start,end}-group gets a fresh ID when instantiated. All files within the same --{start,end}-group get the same group ID. E.g. ld.lld A B --start-group C D --end-group E A and B form group 0, C, D and their member object files form group 1, and E forms group 2. I think that you can see how this group assignment rule simulates the traditional linker's semantics. Differential Revision: https://reviews.llvm.org/D45195 llvm-svn: 329636
2018-04-10 07:05:48 +08:00
[ELF][MIPS] Multi-GOT implementation Almost all entries inside MIPS GOT are referenced by signed 16-bit index. Zero entry lies approximately in the middle of the GOT. So the total number of GOT entries cannot exceed ~16384 for 32-bit architecture and ~8192 for 64-bit architecture. This limitation makes impossible to link rather large application like for example LLVM+Clang. There are two workaround for this problem. The first one is using the -mxgot compiler's flag. It enables using a 32-bit index to access GOT entries. But each access requires two assembly instructions two load GOT entry index to a register. Another workaround is multi-GOT. This patch implements it. Here is a brief description of multi-GOT for detailed one see the following link https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT. If the sum of local, global and tls entries is less than 64K only single got is enough. Otherwise, multi-got is created. Series of primary and multiple secondary GOTs have the following layout: ``` - Primary GOT Header Local entries Global entries Relocation only entries TLS entries - Secondary GOT Local entries Global entries TLS entries ... ``` All GOT entries required by relocations from a single input file entirely belong to either primary or one of secondary GOTs. To reference GOT entries each GOT has its own _gp value points to the "middle" of the GOT. In the code this value loaded to the register which is used for GOT access. MIPS 32 function's prologue: ``` lui v0,0x0 0: R_MIPS_HI16 _gp_disp addiu v0,v0,0 4: R_MIPS_LO16 _gp_disp ``` MIPS 64 function's prologue: ``` lui at,0x0 14: R_MIPS_GPREL16 main ``` Dynamic linker does not know anything about secondary GOTs and cannot use a regular MIPS mechanism for GOT entries initialization. So we have to use an approach accepted by other architectures and create dynamic relocations R_MIPS_REL32 to initialize global entries (and local in case of PIC code) in secondary GOTs. But ironically MIPS dynamic linker requires GOT entries and correspondingly ordered dynamic symbol table entries to deal with dynamic relocations. To handle this problem relocation-only section in the primary GOT contains entries for all symbols referenced in global parts of secondary GOTs. Although the sum of local and normal global entries of the primary got should be less than 64K, the size of the primary got (including relocation-only entries can be greater than 64K, because parts of the primary got that overflow the 64K limit are used only by the dynamic linker at dynamic link-time and not by 16-bit gp-relative addressing at run-time. The patch affects common LLD code in the following places: - Added new hidden -mips-got-size flag. This flag required to set low maximum size of a single GOT to be able to test the implementation using small test cases. - Added InputFile argument to the getRelocTargetVA function. The same symbol referenced by GOT relocation from different input file might be allocated in different GOT. So result of relocation depends on the file. - Added new ctor to the DynamicReloc class. This constructor records settings of dynamic relocation which used to adjust address of 64kb page lies inside a specific output section. With the patch LLD is able to link all LLVM+Clang+LLD applications and libraries for MIPS 32/64 targets. Differential revision: https://reviews.llvm.org/D31528 llvm-svn: 334390
2018-06-11 15:24:31 +08:00
// Index of MIPS GOT built for this file.
llvm::Optional<size_t> mipsGotIndex;
Speed up --start-lib and --end-lib. --{start,end}-lib give files grouped by the options the archive file semantics. That is, each object file between them acts as if it were in an archive file whose sole member is the file. Therefore, files between --{start,end}-lib are linked to the final output only if they are needed to resolve some undefined symbols. Previously, the feature was implemented this way: 1. We read a symbol table and insert defined symbols to the symbol table as lazy symbols. 2. If an undefind symbol is resolved to a lazy symbol, that lazy symbol instantiate ObjFile class for that symbol, which re-insert all defined symbols to the symbol table. So, if an ObjFile is instantiated, defined symbols are inserted to the symbol table twice. Since inserting long symbol names is not cheap, there's a room to optimize here. This patch optimzies it. Now, LazyObjFile remembers symbol handles and passed them over to a new ObjFile instance, so that the ObjFile doesn't insert the same strings. Here is a quick benchmark to link clang. "Original" is the original lld with unmodified command line options. For "Case 1" and "Case 2", I extracted all files from archive files and replace .a's in a command line with .o's wrapped with --{start,end}-lib. I used the original lld for Case 1" and use this patch for Case 2. Original: 5.892 Case 1: 6.001 (+1.8%) Case 2: 5.701 (-3.2%) So, interestingly, --{start,end}-lib are now faster than the regular linking scheme with archive files. That's perhaps not too surprising, though, because for regular archive files, we look up the symbol table with the same string twice. Differential Revision: https://reviews.llvm.org/D62188 llvm-svn: 361473
2019-05-23 17:53:30 +08:00
std::vector<Symbol *> symbols;
protected:
InputFile(Kind k, MemoryBufferRef m);
std::vector<InputSectionBase *> sections;
private:
const Kind fileKind;
// Cache for getNameForScript().
mutable std::string nameForScriptCache;
};
class ELFFileBase : public InputFile {
public:
ELFFileBase(Kind k, MemoryBufferRef m);
static bool classof(const InputFile *f) { return f->isElf(); }
template <typename ELFT> llvm::object::ELFFile<ELFT> getObj() const {
return check(llvm::object::ELFFile<ELFT>::create(mb.getBuffer()));
}
StringRef getStringTable() const { return stringTable; }
template <typename ELFT> typename ELFT::SymRange getELFSyms() const {
return typename ELFT::SymRange(
reinterpret_cast<const typename ELFT::Sym *>(elfSyms), numELFSyms);
}
template <typename ELFT> typename ELFT::SymRange getGlobalELFSyms() const {
return getELFSyms<ELFT>().slice(firstGlobal);
}
ELF: New symbol table design. This patch implements a new design for the symbol table that stores SymbolBodies within a memory region of the Symbol object. Symbols are mutated by constructing SymbolBodies in place over existing SymbolBodies, rather than by mutating pointers. As mentioned in the initial proposal [1], this memory layout helps reduce the cache miss rate by improving memory locality. Performance numbers: old(s) new(s) Without debug info: chrome 7.178 6.432 (-11.5%) LLVMgold.so 0.505 0.502 (-0.5%) clang 0.954 0.827 (-15.4%) llvm-as 0.052 0.045 (-15.5%) With debug info: scylla 5.695 5.613 (-1.5%) clang 14.396 14.143 (-1.8%) Performance counter results show that the fewer required indirections is indeed the cause of the improved performance. For example, when linking chrome, stalled cycles decreases from 14,556,444,002 to 12,959,238,310, and instructions per cycle increases from 0.78 to 0.83. We are also executing many fewer instructions (15,516,401,933 down to 15,002,434,310), probably because we spend less time allocating SymbolBodies. The new mechanism by which symbols are added to the symbol table is by calling add* functions on the SymbolTable. In this patch, I handle local symbols by storing them inside "unparented" SymbolBodies. This is suboptimal, but if we do want to try to avoid allocating these SymbolBodies, we can probably do that separately. I also removed a few members from the SymbolBody class that were only being used to pass information from the input file to the symbol table. This patch implements the new design for the ELF linker only. I intend to prepare a similar patch for the COFF linker. [1] http://lists.llvm.org/pipermail/llvm-dev/2016-April/098832.html Differential Revision: http://reviews.llvm.org/D19752 llvm-svn: 268178
2016-05-01 12:55:03 +08:00
protected:
// Initializes this class's member variables.
template <typename ELFT> void init();
const void *elfSyms = nullptr;
size_t numELFSyms = 0;
uint32_t firstGlobal = 0;
2015-10-12 23:15:45 +08:00
StringRef stringTable;
};
// .o file.
template <class ELFT> class ObjFile : public ELFFileBase {
LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
public:
static bool classof(const InputFile *f) { return f->kind() == ObjKind; }
llvm::object::ELFFile<ELFT> getObj() const {
return this->ELFFileBase::getObj<ELFT>();
}
ArrayRef<Symbol *> getLocalSymbols();
ArrayRef<Symbol *> getGlobalSymbols();
ObjFile(MemoryBufferRef m, StringRef archiveName) : ELFFileBase(ObjKind, m) {
this->archiveName = std::string(archiveName);
}
void parse(bool ignoreComdats = false);
StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> sections,
const Elf_Shdr &sec);
Symbol &getSymbol(uint32_t symbolIndex) const {
if (symbolIndex >= this->symbols.size())
fatal(toString(this) + ": invalid symbol index");
return *this->symbols[symbolIndex];
}
uint32_t getSectionIndex(const Elf_Sym &sym) const;
template <typename RelT> Symbol &getRelocTargetSym(const RelT &rel) const {
uint32_t symIndex = rel.getSymbol(config->isMips64EL);
return getSymbol(symIndex);
}
llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t);
llvm::Optional<std::pair<std::string, unsigned>> getVariableLoc(StringRef name);
// MIPS GP0 value defined by this file. This value represents the gp value
// used to create the relocatable object and required to support
// R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
uint32_t mipsGp0 = 0;
uint32_t andFeatures = 0;
// Name of source file obtained from STT_FILE symbol value,
// or empty string if there is no such symbol in object file
// symbol table.
StringRef sourceFile;
// True if the file defines functions compiled with
// -fsplit-stack. Usually false.
bool splitStack = false;
// True if the file defines functions compiled with -fsplit-stack,
// but had one or more functions with the no_split_stack attribute.
bool someNoSplitStack = false;
// Pointer to this input file's .llvm_addrsig section, if it has one.
const Elf_Shdr *addrsigSec = nullptr;
// SHT_LLVM_CALL_GRAPH_PROFILE section index.
uint32_t cgProfileSectionIndex = 0;
// Get cached DWARF information.
DWARFCache *getDwarf();
private:
void initializeSections(bool ignoreComdats);
void initializeSymbols();
void initializeJustSymbols();
InputSectionBase *getRelocTarget(const Elf_Shdr &sec);
InputSectionBase *createInputSection(uint32_t idx, const Elf_Shdr &sec,
StringRef shstrtab);
bool shouldMerge(const Elf_Shdr &sec, StringRef name);
// Each ELF symbol contains a section index which the symbol belongs to.
// However, because the number of bits dedicated for that is limited, a
// symbol can directly point to a section only when the section index is
// equal to or smaller than 65280.
//
// If an object file contains more than 65280 sections, the file must
// contain .symtab_shndx section. The section contains an array of
// 32-bit integers whose size is the same as the number of symbols.
// Nth symbol's section index is in the Nth entry of .symtab_shndx.
//
// The following variable contains the contents of .symtab_shndx.
// If the section does not exist (which is common), the array is empty.
ArrayRef<Elf_Word> shndxTable;
// Debugging information to retrieve source file and line for error
// reporting. Linker may find reasonable number of errors in a
// single object file, so we cache debugging information in order to
// parse it only once for each object file we link.
std::unique_ptr<DWARFCache> dwarf;
llvm::once_flag initDwarf;
};
// LazyObjFile is analogous to ArchiveFile in the sense that
// the file contains lazy symbols. The difference is that
// LazyObjFile wraps a single file instead of multiple files.
//
// This class is used for --start-lib and --end-lib options which
// instruct the linker to link object files between them with the
// archive file semantics.
class LazyObjFile : public InputFile {
public:
LazyObjFile(MemoryBufferRef m, StringRef archiveName,
uint64_t offsetInArchive)
: InputFile(LazyObjKind, m), offsetInArchive(offsetInArchive) {
this->archiveName = std::string(archiveName);
}
static bool classof(const InputFile *f) { return f->kind() == LazyObjKind; }
ELF: New symbol table design. This patch implements a new design for the symbol table that stores SymbolBodies within a memory region of the Symbol object. Symbols are mutated by constructing SymbolBodies in place over existing SymbolBodies, rather than by mutating pointers. As mentioned in the initial proposal [1], this memory layout helps reduce the cache miss rate by improving memory locality. Performance numbers: old(s) new(s) Without debug info: chrome 7.178 6.432 (-11.5%) LLVMgold.so 0.505 0.502 (-0.5%) clang 0.954 0.827 (-15.4%) llvm-as 0.052 0.045 (-15.5%) With debug info: scylla 5.695 5.613 (-1.5%) clang 14.396 14.143 (-1.8%) Performance counter results show that the fewer required indirections is indeed the cause of the improved performance. For example, when linking chrome, stalled cycles decreases from 14,556,444,002 to 12,959,238,310, and instructions per cycle increases from 0.78 to 0.83. We are also executing many fewer instructions (15,516,401,933 down to 15,002,434,310), probably because we spend less time allocating SymbolBodies. The new mechanism by which symbols are added to the symbol table is by calling add* functions on the SymbolTable. In this patch, I handle local symbols by storing them inside "unparented" SymbolBodies. This is suboptimal, but if we do want to try to avoid allocating these SymbolBodies, we can probably do that separately. I also removed a few members from the SymbolBody class that were only being used to pass information from the input file to the symbol table. This patch implements the new design for the ELF linker only. I intend to prepare a similar patch for the COFF linker. [1] http://lists.llvm.org/pipermail/llvm-dev/2016-April/098832.html Differential Revision: http://reviews.llvm.org/D19752 llvm-svn: 268178
2016-05-01 12:55:03 +08:00
template <class ELFT> void parse();
void fetch();
// Check if a non-common symbol should be fetched to override a common
// definition.
bool shouldFetchForCommon(const StringRef &name);
bool fetched = false;
private:
uint64_t offsetInArchive;
};
// An ArchiveFile object represents a .a file.
class ArchiveFile : public InputFile {
public:
explicit ArchiveFile(std::unique_ptr<Archive> &&file);
static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; }
void parse();
// Pulls out an object file that contains a definition for Sym and
// returns it. If the same file was instantiated before, this
// function does nothing (so we don't instantiate the same file
// more than once.)
void fetch(const Archive::Symbol &sym);
// Check if a non-common symbol should be fetched to override a common
// definition.
bool shouldFetchForCommon(const Archive::Symbol &sym);
size_t getMemberCount() const;
size_t getFetchedMemberCount() const { return seen.size(); }
bool parsed = false;
private:
std::unique_ptr<Archive> file;
llvm::DenseSet<uint64_t> seen;
};
class BitcodeFile : public InputFile {
public:
BitcodeFile(MemoryBufferRef m, StringRef archiveName,
uint64_t offsetInArchive);
ELF: New symbol table design. This patch implements a new design for the symbol table that stores SymbolBodies within a memory region of the Symbol object. Symbols are mutated by constructing SymbolBodies in place over existing SymbolBodies, rather than by mutating pointers. As mentioned in the initial proposal [1], this memory layout helps reduce the cache miss rate by improving memory locality. Performance numbers: old(s) new(s) Without debug info: chrome 7.178 6.432 (-11.5%) LLVMgold.so 0.505 0.502 (-0.5%) clang 0.954 0.827 (-15.4%) llvm-as 0.052 0.045 (-15.5%) With debug info: scylla 5.695 5.613 (-1.5%) clang 14.396 14.143 (-1.8%) Performance counter results show that the fewer required indirections is indeed the cause of the improved performance. For example, when linking chrome, stalled cycles decreases from 14,556,444,002 to 12,959,238,310, and instructions per cycle increases from 0.78 to 0.83. We are also executing many fewer instructions (15,516,401,933 down to 15,002,434,310), probably because we spend less time allocating SymbolBodies. The new mechanism by which symbols are added to the symbol table is by calling add* functions on the SymbolTable. In this patch, I handle local symbols by storing them inside "unparented" SymbolBodies. This is suboptimal, but if we do want to try to avoid allocating these SymbolBodies, we can probably do that separately. I also removed a few members from the SymbolBody class that were only being used to pass information from the input file to the symbol table. This patch implements the new design for the ELF linker only. I intend to prepare a similar patch for the COFF linker. [1] http://lists.llvm.org/pipermail/llvm-dev/2016-April/098832.html Differential Revision: http://reviews.llvm.org/D19752 llvm-svn: 268178
2016-05-01 12:55:03 +08:00
static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
template <class ELFT> void parse();
std::unique_ptr<llvm::lto::InputFile> obj;
};
// .so file.
class SharedFile : public ELFFileBase {
public:
SharedFile(MemoryBufferRef m, StringRef defaultSoName)
: ELFFileBase(SharedKind, m), soName(defaultSoName),
isNeeded(!config->asNeeded) {}
// This is actually a vector of Elf_Verdef pointers.
std::vector<const void *> verdefs;
// If the output file needs Elf_Verneed data structures for this file, this is
// a vector of Elf_Vernaux version identifiers that map onto the entries in
// Verdefs, otherwise it is empty.
std::vector<unsigned> vernauxs;
static unsigned vernauxNum;
std::vector<StringRef> dtNeeded;
StringRef soName;
static bool classof(const InputFile *f) { return f->kind() == SharedKind; }
template <typename ELFT> void parse();
// Used for --as-needed
bool isNeeded;
// Non-weak undefined symbols which are not yet resolved when the SO is
// parsed. Only filled for `--no-allow-shlib-undefined`.
std::vector<Symbol *> requiredSymbols;
private:
template <typename ELFT>
std::vector<uint32_t> parseVerneed(const llvm::object::ELFFile<ELFT> &obj,
const typename ELFT::Shdr *sec);
};
class BinaryFile : public InputFile {
public:
explicit BinaryFile(MemoryBufferRef m) : InputFile(BinaryKind, m) {}
static bool classof(const InputFile *f) { return f->kind() == BinaryKind; }
void parse();
};
InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName = "",
uint64_t offsetInArchive = 0);
inline bool isBitcode(MemoryBufferRef mb) {
return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode;
}
std::string replaceThinLTOSuffix(StringRef path);
extern std::vector<ArchiveFile *> archiveFiles;
extern std::vector<BinaryFile *> binaryFiles;
extern std::vector<BitcodeFile *> bitcodeFiles;
extern std::vector<LazyObjFile *> lazyObjFiles;
extern std::vector<InputFile *> objectFiles;
extern std::vector<SharedFile *> sharedFiles;
2016-02-28 08:25:54 +08:00
} // namespace elf
} // namespace lld
#endif