2015-07-25 05:03:07 +08:00
|
|
|
//===- InputFiles.cpp -----------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Linker
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "InputFiles.h"
|
2016-04-29 03:30:41 +08:00
|
|
|
#include "Driver.h"
|
2015-08-06 23:08:23 +08:00
|
|
|
#include "Error.h"
|
2016-02-11 23:24:48 +08:00
|
|
|
#include "InputSection.h"
|
2016-08-13 03:56:57 +08:00
|
|
|
#include "LinkerScript.h"
|
2016-10-29 04:57:25 +08:00
|
|
|
#include "Memory.h"
|
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
|
|
|
#include "SymbolTable.h"
|
2015-07-25 05:03:07 +08:00
|
|
|
#include "Symbols.h"
|
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2016-06-29 14:12:39 +08:00
|
|
|
#include "llvm/Bitcode/ReaderWriter.h"
|
2016-04-22 05:44:25 +08:00
|
|
|
#include "llvm/CodeGen/Analysis.h"
|
2016-10-26 19:07:09 +08:00
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
2016-02-13 04:54:57 +08:00
|
|
|
#include "llvm/IR/LLVMContext.h"
|
2016-03-02 23:43:50 +08:00
|
|
|
#include "llvm/IR/Module.h"
|
2016-09-29 08:40:08 +08:00
|
|
|
#include "llvm/LTO/LTO.h"
|
2016-09-10 06:08:04 +08:00
|
|
|
#include "llvm/MC/StringTableBuilder.h"
|
2016-11-01 17:17:50 +08:00
|
|
|
#include "llvm/Object/ELFObjectFile.h"
|
2016-09-09 05:18:38 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
2016-02-13 04:54:57 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2015-07-25 05:03:07 +08:00
|
|
|
|
2015-09-05 06:28:10 +08:00
|
|
|
using namespace llvm;
|
2015-07-25 05:03:07 +08:00
|
|
|
using namespace llvm::ELF;
|
2015-09-04 04:03:54 +08:00
|
|
|
using namespace llvm::object;
|
2015-10-01 01:06:09 +08:00
|
|
|
using namespace llvm::sys::fs;
|
2015-07-25 05:03:07 +08:00
|
|
|
|
|
|
|
using namespace lld;
|
2016-02-28 08:25:54 +08:00
|
|
|
using namespace lld::elf;
|
2015-07-25 05:03:07 +08:00
|
|
|
|
2016-09-14 08:05:51 +08:00
|
|
|
|
2016-11-01 17:17:50 +08:00
|
|
|
namespace {
|
|
|
|
// In ELF object file all section addresses are zero. If we have multiple
|
|
|
|
// .text sections (when using -ffunction-section or comdat group) then
|
|
|
|
// LLVM DWARF parser will not be able to parse .debug_line correctly, unless
|
|
|
|
// we assign each section some unique address. This callback method assigns
|
|
|
|
// each section an address equal to its offset in ELF object file.
|
|
|
|
class ObjectInfo : public LoadedObjectInfo {
|
|
|
|
public:
|
|
|
|
uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override {
|
|
|
|
return static_cast<const ELFSectionRef &>(Sec).getOffset();
|
|
|
|
}
|
|
|
|
std::unique_ptr<LoadedObjectInfo> clone() const override {
|
|
|
|
return std::unique_ptr<LoadedObjectInfo>();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT> DIHelper<ELFT>::DIHelper(InputFile *F) {
|
2016-10-26 19:07:09 +08:00
|
|
|
Expected<std::unique_ptr<object::ObjectFile>> Obj =
|
|
|
|
object::ObjectFile::createObjectFile(F->MB);
|
|
|
|
if (!Obj)
|
|
|
|
return;
|
|
|
|
|
2016-11-01 17:17:50 +08:00
|
|
|
ObjectInfo ObjInfo;
|
|
|
|
DWARFContextInMemory Dwarf(*Obj.get(), &ObjInfo);
|
2016-10-26 19:07:09 +08:00
|
|
|
DwarfLine.reset(new DWARFDebugLine(&Dwarf.getLineSection().Relocs));
|
|
|
|
DataExtractor LineData(Dwarf.getLineSection().Data,
|
|
|
|
ELFT::TargetEndianness == support::little,
|
|
|
|
ELFT::Is64Bits ? 8 : 4);
|
|
|
|
// The second parameter is offset in .debug_line section
|
|
|
|
// for compilation unit (CU) of interest. We have only one
|
|
|
|
// CU (object file), so offset is always 0.
|
|
|
|
DwarfLine->getOrParseLineTable(LineData, 0);
|
|
|
|
}
|
|
|
|
|
2016-10-28 05:26:57 +08:00
|
|
|
template <class ELFT> DIHelper<ELFT>::~DIHelper() {}
|
|
|
|
|
2016-11-01 17:17:50 +08:00
|
|
|
template <class ELFT>
|
|
|
|
std::string DIHelper<ELFT>::getLineInfo(InputSectionBase<ELFT> *S,
|
|
|
|
uintX_t Offset) {
|
2016-10-26 19:07:09 +08:00
|
|
|
if (!DwarfLine)
|
|
|
|
return "";
|
|
|
|
|
|
|
|
DILineInfo LineInfo;
|
|
|
|
DILineInfoSpecifier Spec;
|
|
|
|
// The offset to CU is 0 (see DIHelper constructor).
|
|
|
|
const DWARFDebugLine::LineTable *LineTbl = DwarfLine->getLineTable(0);
|
|
|
|
if (!LineTbl)
|
|
|
|
return "";
|
2016-11-01 17:17:50 +08:00
|
|
|
|
|
|
|
// Use fake address calcuated by adding section file offset and offset in
|
|
|
|
// section.
|
|
|
|
// See comments for ObjectInfo class
|
|
|
|
LineTbl->getFileLineInfoForAddress(S->Offset + Offset, nullptr, Spec.FLIKind,
|
|
|
|
LineInfo);
|
2016-10-26 19:07:09 +08:00
|
|
|
return LineInfo.Line != 0
|
|
|
|
? LineInfo.FileName + " (" + std::to_string(LineInfo.Line) + ")"
|
|
|
|
: "";
|
|
|
|
}
|
|
|
|
|
2016-05-10 05:40:06 +08:00
|
|
|
// Returns "(internal)", "foo.a(bar.o)" or "baz.o".
|
2016-07-16 04:38:28 +08:00
|
|
|
std::string elf::getFilename(const InputFile *F) {
|
2016-05-10 05:40:06 +08:00
|
|
|
if (!F)
|
|
|
|
return "(internal)";
|
|
|
|
if (!F->ArchiveName.empty())
|
|
|
|
return (F->ArchiveName + "(" + F->getName() + ")").str();
|
|
|
|
return F->getName();
|
|
|
|
}
|
|
|
|
|
2016-10-03 19:13:55 +08:00
|
|
|
template <class ELFT> static ELFFile<ELFT> createELFObj(MemoryBufferRef MB) {
|
2015-07-25 05:03:07 +08:00
|
|
|
std::error_code EC;
|
2016-03-03 14:22:29 +08:00
|
|
|
ELFFile<ELFT> F(MB.getBuffer(), EC);
|
2016-07-15 10:01:03 +08:00
|
|
|
if (EC)
|
2016-10-07 16:51:57 +08:00
|
|
|
fatal(EC, "failed to read " + MB.getBufferIdentifier());
|
2016-03-03 14:22:29 +08:00
|
|
|
return F;
|
2015-09-04 04:03:54 +08:00
|
|
|
}
|
|
|
|
|
2016-06-29 09:30:50 +08:00
|
|
|
template <class ELFT> static ELFKind getELFKind() {
|
2016-01-06 08:09:41 +08:00
|
|
|
if (ELFT::TargetEndianness == support::little)
|
|
|
|
return ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind;
|
|
|
|
return ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind;
|
2015-11-20 10:10:52 +08:00
|
|
|
}
|
|
|
|
|
2016-06-29 09:30:50 +08:00
|
|
|
template <class ELFT>
|
|
|
|
ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB)
|
|
|
|
: InputFile(K, MB), ELFObj(createELFObj<ELFT>(MB)) {
|
|
|
|
EKind = getELFKind<ELFT>();
|
|
|
|
EMachine = ELFObj.getHeader()->e_machine;
|
2016-10-27 22:00:51 +08:00
|
|
|
OSABI = ELFObj.getHeader()->e_ident[llvm::ELF::EI_OSABI];
|
2016-06-29 09:30:50 +08:00
|
|
|
}
|
|
|
|
|
2015-09-08 23:50:05 +08:00
|
|
|
template <class ELFT>
|
2016-03-15 07:16:09 +08:00
|
|
|
typename ELFT::SymRange ELFFileBase<ELFT>::getElfSymbols(bool OnlyGlobals) {
|
2015-09-08 23:50:05 +08:00
|
|
|
if (!Symtab)
|
|
|
|
return Elf_Sym_Range(nullptr, nullptr);
|
2015-09-24 23:11:50 +08:00
|
|
|
Elf_Sym_Range Syms = ELFObj.symbols(Symtab);
|
2015-09-17 04:45:57 +08:00
|
|
|
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
|
|
|
|
uint32_t FirstNonLocal = Symtab->sh_info;
|
2016-10-07 23:16:27 +08:00
|
|
|
if (FirstNonLocal == 0 || FirstNonLocal > NumSymbols)
|
2016-07-16 04:38:28 +08:00
|
|
|
fatal(getFilename(this) + ": invalid sh_info in symbol table");
|
2016-03-11 20:06:30 +08:00
|
|
|
|
|
|
|
if (OnlyGlobals)
|
2016-04-05 22:47:28 +08:00
|
|
|
return makeArrayRef(Syms.begin() + FirstNonLocal, Syms.end());
|
|
|
|
return makeArrayRef(Syms.begin(), Syms.end());
|
2015-09-17 04:45:57 +08:00
|
|
|
}
|
2015-09-08 23:50:05 +08:00
|
|
|
|
2015-11-03 22:13:40 +08:00
|
|
|
template <class ELFT>
|
|
|
|
uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const {
|
2015-12-24 16:36:56 +08:00
|
|
|
uint32_t I = Sym.st_shndx;
|
|
|
|
if (I == ELF::SHN_XINDEX)
|
2016-01-06 09:14:11 +08:00
|
|
|
return ELFObj.getExtendedSymbolTableIndex(&Sym, Symtab, SymtabSHNDX);
|
2016-03-09 22:31:18 +08:00
|
|
|
if (I >= ELF::SHN_LORESERVE)
|
2015-11-03 22:13:40 +08:00
|
|
|
return 0;
|
2015-12-24 16:36:56 +08:00
|
|
|
return I;
|
2015-11-03 22:13:40 +08:00
|
|
|
}
|
|
|
|
|
2015-10-12 09:55:32 +08:00
|
|
|
template <class ELFT> void ELFFileBase<ELFT>::initStringTable() {
|
2015-10-02 04:26:37 +08:00
|
|
|
if (!Symtab)
|
|
|
|
return;
|
2016-03-04 06:24:39 +08:00
|
|
|
StringTable = check(ELFObj.getStringTableForSymtab(*Symtab));
|
2015-10-02 03:52:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
2016-10-29 04:57:25 +08:00
|
|
|
elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M)
|
|
|
|
: ELFFileBase<ELFT>(Base::ObjectKind, M) {}
|
2016-03-11 20:06:30 +08:00
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getNonLocalSymbols() {
|
|
|
|
if (!this->Symtab)
|
|
|
|
return this->SymbolBodies;
|
|
|
|
uint32_t FirstNonLocal = this->Symtab->sh_info;
|
|
|
|
return makeArrayRef(this->SymbolBodies).slice(FirstNonLocal);
|
2015-09-17 04:45:57 +08:00
|
|
|
}
|
2015-09-08 23:50:05 +08:00
|
|
|
|
2015-09-24 23:11:50 +08:00
|
|
|
template <class ELFT>
|
2016-03-11 20:06:30 +08:00
|
|
|
ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getLocalSymbols() {
|
|
|
|
if (!this->Symtab)
|
|
|
|
return this->SymbolBodies;
|
|
|
|
uint32_t FirstNonLocal = this->Symtab->sh_info;
|
|
|
|
return makeArrayRef(this->SymbolBodies).slice(1, FirstNonLocal - 1);
|
|
|
|
}
|
2015-09-24 23:11:50 +08:00
|
|
|
|
2015-09-17 04:45:57 +08:00
|
|
|
template <class ELFT>
|
2016-03-11 20:06:30 +08:00
|
|
|
ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getSymbols() {
|
|
|
|
if (!this->Symtab)
|
|
|
|
return this->SymbolBodies;
|
|
|
|
return makeArrayRef(this->SymbolBodies).slice(1);
|
2015-09-08 23:50:05 +08:00
|
|
|
}
|
|
|
|
|
2016-10-26 19:07:09 +08:00
|
|
|
template <class ELFT> DIHelper<ELFT> *elf::ObjectFile<ELFT>::getDIHelper() {
|
|
|
|
if (!DIH)
|
|
|
|
DIH.reset(new DIHelper<ELFT>(this));
|
|
|
|
|
|
|
|
return DIH.get();
|
|
|
|
}
|
|
|
|
|
2016-02-28 08:25:54 +08:00
|
|
|
template <class ELFT> uint32_t elf::ObjectFile<ELFT>::getMipsGp0() const {
|
2016-05-04 18:07:38 +08:00
|
|
|
if (ELFT::Is64Bits && MipsOptions && MipsOptions->Reginfo)
|
|
|
|
return MipsOptions->Reginfo->ri_gp_value;
|
|
|
|
if (!ELFT::Is64Bits && MipsReginfo && MipsReginfo->Reginfo)
|
2016-01-07 06:42:43 +08:00
|
|
|
return MipsReginfo->Reginfo->ri_gp_value;
|
|
|
|
return 0;
|
2015-12-25 21:02:13 +08:00
|
|
|
}
|
|
|
|
|
2015-10-10 03:25:07 +08:00
|
|
|
template <class ELFT>
|
2016-10-22 03:49:42 +08:00
|
|
|
void elf::ObjectFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
|
2015-07-25 05:03:07 +08:00
|
|
|
// Read section and symbol tables.
|
2016-01-06 10:06:33 +08:00
|
|
|
initializeSections(ComdatGroups);
|
2015-07-25 05:03:07 +08:00
|
|
|
initializeSymbols();
|
2016-10-10 18:18:58 +08:00
|
|
|
if (Config->GcSections && Config->EMachine == EM_ARM)
|
2016-10-10 18:10:27 +08:00
|
|
|
initializeReverseDependencies();
|
2015-07-25 05:03:07 +08:00
|
|
|
}
|
|
|
|
|
2015-12-24 16:41:12 +08:00
|
|
|
// Sections with SHT_GROUP and comdat bits define comdat section groups.
|
|
|
|
// They are identified and deduplicated by group name. This function
|
|
|
|
// returns a group name.
|
2015-10-10 03:25:07 +08:00
|
|
|
template <class ELFT>
|
2016-02-28 08:25:54 +08:00
|
|
|
StringRef elf::ObjectFile<ELFT>::getShtGroupSignature(const Elf_Shdr &Sec) {
|
2015-10-10 03:25:07 +08:00
|
|
|
const ELFFile<ELFT> &Obj = this->ELFObj;
|
2016-07-16 04:05:05 +08:00
|
|
|
const Elf_Shdr *Symtab = check(Obj.getSection(Sec.sh_link));
|
|
|
|
const Elf_Sym *Sym = Obj.getSymbol(Symtab, Sec.sh_info);
|
|
|
|
StringRef Strtab = check(Obj.getStringTableForSymtab(*Symtab));
|
|
|
|
return check(Sym->getName(Strtab));
|
2015-10-10 03:25:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
2016-03-14 06:02:04 +08:00
|
|
|
ArrayRef<typename elf::ObjectFile<ELFT>::Elf_Word>
|
2016-02-28 08:25:54 +08:00
|
|
|
elf::ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
|
2015-10-10 03:25:07 +08:00
|
|
|
const ELFFile<ELFT> &Obj = this->ELFObj;
|
2016-03-14 06:02:04 +08:00
|
|
|
ArrayRef<Elf_Word> Entries =
|
|
|
|
check(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec));
|
2015-10-10 03:25:07 +08:00
|
|
|
if (Entries.empty() || Entries[0] != GRP_COMDAT)
|
2016-07-16 04:38:28 +08:00
|
|
|
fatal(getFilename(this) + ": unsupported SHT_GROUP format");
|
2015-10-10 03:25:07 +08:00
|
|
|
return Entries.slice(1);
|
|
|
|
}
|
|
|
|
|
2016-07-16 04:38:28 +08:00
|
|
|
template <class ELFT>
|
|
|
|
bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
|
2016-04-30 00:12:29 +08:00
|
|
|
// We don't merge sections if -O0 (default is -O1). This makes sometimes
|
|
|
|
// the linker significantly faster, although the output will be bigger.
|
|
|
|
if (Config->Optimize == 0)
|
|
|
|
return false;
|
|
|
|
|
2016-10-05 15:49:18 +08:00
|
|
|
// Do not merge sections if generating a relocatable object. It makes
|
|
|
|
// the code simpler because we do not need to update relocation addends
|
|
|
|
// to reflect changes introduced by merging. Instead of that we write
|
|
|
|
// such "merge" sections into separate OutputSections and keep SHF_MERGE
|
|
|
|
// / SHF_STRINGS flags and sh_entsize value to be able to perform merging
|
|
|
|
// later during a final linking.
|
|
|
|
if (Config->Relocatable)
|
|
|
|
return false;
|
|
|
|
|
2016-08-03 13:28:02 +08:00
|
|
|
// A mergeable section with size 0 is useless because they don't have
|
|
|
|
// any data to merge. A mergeable string section with size 0 can be
|
|
|
|
// argued as invalid because it doesn't end with a null character.
|
|
|
|
// We'll avoid a mess by handling them as if they were non-mergeable.
|
|
|
|
if (Sec.sh_size == 0)
|
|
|
|
return false;
|
|
|
|
|
2016-09-21 11:22:18 +08:00
|
|
|
// Check for sh_entsize. The ELF spec is not clear about the zero
|
|
|
|
// sh_entsize. It says that "the member [sh_entsize] contains 0 if
|
|
|
|
// the section does not hold a table of fixed-size entries". We know
|
|
|
|
// that Rust 1.13 produces a string mergeable section with a zero
|
|
|
|
// sh_entsize. Here we just accept it rather than being picky about it.
|
|
|
|
uintX_t EntSize = Sec.sh_entsize;
|
|
|
|
if (EntSize == 0)
|
|
|
|
return false;
|
|
|
|
if (Sec.sh_size % EntSize)
|
|
|
|
fatal(getFilename(this) +
|
|
|
|
": SHF_MERGE section size must be a multiple of sh_entsize");
|
|
|
|
|
2015-10-25 06:51:01 +08:00
|
|
|
uintX_t Flags = Sec.sh_flags;
|
|
|
|
if (!(Flags & SHF_MERGE))
|
|
|
|
return false;
|
|
|
|
if (Flags & SHF_WRITE)
|
2016-07-16 04:38:28 +08:00
|
|
|
fatal(getFilename(this) + ": writable SHF_MERGE section is not supported");
|
2015-10-25 06:51:01 +08:00
|
|
|
|
2016-05-18 19:40:16 +08:00
|
|
|
// Don't try to merge if the alignment is larger than the sh_entsize and this
|
2016-02-19 22:17:40 +08:00
|
|
|
// is not SHF_STRINGS.
|
2015-10-25 06:51:01 +08:00
|
|
|
//
|
2016-02-19 22:17:40 +08:00
|
|
|
// Since this is not a SHF_STRINGS, we would need to pad after every entity.
|
|
|
|
// It would be equivalent for the producer of the .o to just set a larger
|
2015-10-25 06:51:01 +08:00
|
|
|
// sh_entsize.
|
2016-02-19 22:17:40 +08:00
|
|
|
if (Flags & SHF_STRINGS)
|
|
|
|
return true;
|
|
|
|
|
2016-06-08 20:04:59 +08:00
|
|
|
return Sec.sh_addralign <= EntSize;
|
2015-10-25 06:51:01 +08:00
|
|
|
}
|
|
|
|
|
2015-10-10 03:25:07 +08:00
|
|
|
template <class ELFT>
|
2016-02-28 08:25:54 +08:00
|
|
|
void elf::ObjectFile<ELFT>::initializeSections(
|
2016-10-22 03:49:42 +08:00
|
|
|
DenseSet<CachedHashStringRef> &ComdatGroups) {
|
2015-09-24 23:11:50 +08:00
|
|
|
uint64_t Size = this->ELFObj.getNumSections();
|
2015-09-22 08:16:19 +08:00
|
|
|
Sections.resize(Size);
|
2015-10-10 03:25:07 +08:00
|
|
|
unsigned I = -1;
|
2015-10-08 20:02:38 +08:00
|
|
|
const ELFFile<ELFT> &Obj = this->ELFObj;
|
2016-11-02 05:48:00 +08:00
|
|
|
StringRef SectionStringTable = check(Obj.getSectionStringTable());
|
2015-10-08 20:02:38 +08:00
|
|
|
for (const Elf_Shdr &Sec : Obj.sections()) {
|
2015-10-10 03:25:07 +08:00
|
|
|
++I;
|
2016-04-04 22:04:16 +08:00
|
|
|
if (Sections[I] == &InputSection<ELFT>::Discarded)
|
2015-10-10 03:25:07 +08:00
|
|
|
continue;
|
|
|
|
|
2016-10-05 00:47:49 +08:00
|
|
|
// SHF_EXCLUDE'ed sections are discarded by the linker. However,
|
|
|
|
// if -r is given, we'll let the final link discard such sections.
|
|
|
|
// This is compatible with GNU.
|
|
|
|
if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) {
|
2016-09-28 16:42:02 +08:00
|
|
|
Sections[I] = &InputSection<ELFT>::Discarded;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-08-13 22:45:44 +08:00
|
|
|
switch (Sec.sh_type) {
|
2015-10-10 03:25:07 +08:00
|
|
|
case SHT_GROUP:
|
2016-04-04 22:04:16 +08:00
|
|
|
Sections[I] = &InputSection<ELFT>::Discarded;
|
2016-10-22 03:49:42 +08:00
|
|
|
if (ComdatGroups.insert(CachedHashStringRef(getShtGroupSignature(Sec)))
|
|
|
|
.second)
|
2015-10-10 03:25:07 +08:00
|
|
|
continue;
|
2016-01-07 04:30:02 +08:00
|
|
|
for (uint32_t SecIndex : getShtGroupEntries(Sec)) {
|
2015-10-10 03:25:07 +08:00
|
|
|
if (SecIndex >= Size)
|
2016-07-16 04:38:28 +08:00
|
|
|
fatal(getFilename(this) + ": invalid section index in group: " +
|
|
|
|
Twine(SecIndex));
|
2016-04-04 22:04:16 +08:00
|
|
|
Sections[SecIndex] = &InputSection<ELFT>::Discarded;
|
2015-10-10 03:25:07 +08:00
|
|
|
}
|
|
|
|
break;
|
2015-08-13 22:45:44 +08:00
|
|
|
case SHT_SYMTAB:
|
2015-09-08 23:50:05 +08:00
|
|
|
this->Symtab = &Sec;
|
2015-08-13 22:45:44 +08:00
|
|
|
break;
|
2016-03-04 00:21:44 +08:00
|
|
|
case SHT_SYMTAB_SHNDX:
|
2016-03-04 06:24:39 +08:00
|
|
|
this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec));
|
2015-08-25 05:43:25 +08:00
|
|
|
break;
|
2015-08-13 22:45:44 +08:00
|
|
|
case SHT_STRTAB:
|
|
|
|
case SHT_NULL:
|
2015-08-28 07:15:56 +08:00
|
|
|
break;
|
2015-11-22 06:19:32 +08:00
|
|
|
default:
|
2016-11-02 05:48:00 +08:00
|
|
|
Sections[I] = createInputSection(Sec, SectionStringTable);
|
2015-07-25 05:03:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-10 18:10:27 +08:00
|
|
|
// .ARM.exidx sections have a reverse dependency on the InputSection they
|
|
|
|
// have a SHF_LINK_ORDER dependency, this is identified by the sh_link.
|
|
|
|
template <class ELFT>
|
|
|
|
void elf::ObjectFile<ELFT>::initializeReverseDependencies() {
|
|
|
|
unsigned I = -1;
|
|
|
|
for (const Elf_Shdr &Sec : this->ELFObj.sections()) {
|
|
|
|
++I;
|
|
|
|
if ((Sections[I] == &InputSection<ELFT>::Discarded) ||
|
|
|
|
!(Sec.sh_flags & SHF_LINK_ORDER))
|
|
|
|
continue;
|
|
|
|
if (Sec.sh_link >= Sections.size())
|
|
|
|
fatal(getFilename(this) + ": invalid sh_link index: " +
|
|
|
|
Twine(Sec.sh_link));
|
|
|
|
auto *IS = cast<InputSection<ELFT>>(Sections[Sec.sh_link]);
|
|
|
|
IS->DependentSection = Sections[I];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-14 05:52:57 +08:00
|
|
|
template <class ELFT>
|
|
|
|
InputSectionBase<ELFT> *
|
|
|
|
elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
|
|
|
|
uint32_t Idx = Sec.sh_info;
|
|
|
|
if (Idx >= Sections.size())
|
2016-07-16 04:38:28 +08:00
|
|
|
fatal(getFilename(this) + ": invalid relocated section index: " +
|
|
|
|
Twine(Idx));
|
2016-03-14 05:52:57 +08:00
|
|
|
InputSectionBase<ELFT> *Target = Sections[Idx];
|
|
|
|
|
|
|
|
// Strictly speaking, a relocation section must be included in the
|
|
|
|
// group of the section it relocates. However, LLVM 3.3 and earlier
|
|
|
|
// would fail to do so, so we gracefully handle that case.
|
2016-04-04 22:04:16 +08:00
|
|
|
if (Target == &InputSection<ELFT>::Discarded)
|
2016-03-14 05:52:57 +08:00
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
if (!Target)
|
2016-07-16 04:38:28 +08:00
|
|
|
fatal(getFilename(this) + ": unsupported relocation reference");
|
2016-03-14 05:52:57 +08:00
|
|
|
return Target;
|
|
|
|
}
|
|
|
|
|
2016-02-13 05:17:10 +08:00
|
|
|
template <class ELFT>
|
|
|
|
InputSectionBase<ELFT> *
|
2016-11-02 05:48:00 +08:00
|
|
|
elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
|
|
|
|
StringRef SectionStringTable) {
|
|
|
|
StringRef Name = check(this->ELFObj.getSectionName(&Sec, SectionStringTable));
|
2015-12-24 16:41:12 +08:00
|
|
|
|
2016-09-08 22:06:08 +08:00
|
|
|
switch (Sec.sh_type) {
|
|
|
|
case SHT_ARM_ATTRIBUTES:
|
|
|
|
// FIXME: ARM meta-data section. At present attributes are ignored,
|
|
|
|
// they can be used to reason about object compatibility.
|
|
|
|
return &InputSection<ELFT>::Discarded;
|
|
|
|
case SHT_MIPS_REGINFO:
|
2016-10-17 19:31:46 +08:00
|
|
|
if (MipsReginfo)
|
|
|
|
fatal(getFilename(this) +
|
|
|
|
": multiple SHT_MIPS_REGINFO sections are not allowed");
|
2016-09-08 22:06:08 +08:00
|
|
|
MipsReginfo.reset(new MipsReginfoInputSection<ELFT>(this, &Sec, Name));
|
|
|
|
return MipsReginfo.get();
|
|
|
|
case SHT_MIPS_OPTIONS:
|
2016-10-14 19:10:36 +08:00
|
|
|
if (MipsOptions)
|
|
|
|
fatal(getFilename(this) +
|
|
|
|
": multiple SHT_MIPS_OPTIONS sections are not allowed");
|
2016-09-08 22:06:08 +08:00
|
|
|
MipsOptions.reset(new MipsOptionsInputSection<ELFT>(this, &Sec, Name));
|
|
|
|
return MipsOptions.get();
|
|
|
|
case SHT_MIPS_ABIFLAGS:
|
2016-10-17 19:31:46 +08:00
|
|
|
if (MipsAbiFlags)
|
|
|
|
fatal(getFilename(this) +
|
|
|
|
": multiple SHT_MIPS_ABIFLAGS sections are not allowed");
|
2016-09-08 22:06:08 +08:00
|
|
|
MipsAbiFlags.reset(new MipsAbiFlagsInputSection<ELFT>(this, &Sec, Name));
|
|
|
|
return MipsAbiFlags.get();
|
|
|
|
case SHT_RELA:
|
|
|
|
case SHT_REL: {
|
|
|
|
// This section contains relocation information.
|
|
|
|
// If -r is given, we do not interpret or apply relocation
|
|
|
|
// but just copy relocation sections to output.
|
|
|
|
if (Config->Relocatable)
|
2016-11-02 06:53:18 +08:00
|
|
|
return make<InputSection<ELFT>>(this, &Sec, Name);
|
2016-09-08 22:06:08 +08:00
|
|
|
|
|
|
|
// Find the relocation target section and associate this
|
|
|
|
// section with it.
|
|
|
|
InputSectionBase<ELFT> *Target = getRelocTarget(Sec);
|
|
|
|
if (!Target)
|
|
|
|
return nullptr;
|
|
|
|
if (auto *S = dyn_cast<InputSection<ELFT>>(Target)) {
|
|
|
|
S->RelocSections.push_back(&Sec);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (auto *S = dyn_cast<EhInputSection<ELFT>>(Target)) {
|
|
|
|
if (S->RelocSection)
|
|
|
|
fatal(getFilename(this) +
|
|
|
|
": multiple relocation sections to .eh_frame are not supported");
|
|
|
|
S->RelocSection = &Sec;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
fatal(getFilename(this) +
|
|
|
|
": relocations pointing to SHF_MERGE are not supported");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-24 16:41:12 +08:00
|
|
|
// .note.GNU-stack is a marker section to control the presence of
|
|
|
|
// PT_GNU_STACK segment in outputs. Since the presence of the segment
|
|
|
|
// is controlled only by the command line option (-z execstack) in LLD,
|
|
|
|
// .note.GNU-stack is ignored.
|
|
|
|
if (Name == ".note.GNU-stack")
|
2016-04-04 22:04:16 +08:00
|
|
|
return &InputSection<ELFT>::Discarded;
|
2015-12-24 16:41:12 +08:00
|
|
|
|
2016-04-08 05:04:51 +08:00
|
|
|
if (Name == ".note.GNU-split-stack") {
|
2016-03-12 16:31:34 +08:00
|
|
|
error("objects using splitstacks are not supported");
|
2016-04-08 05:04:51 +08:00
|
|
|
return &InputSection<ELFT>::Discarded;
|
|
|
|
}
|
|
|
|
|
2016-08-31 16:38:11 +08:00
|
|
|
if (Config->Strip != StripPolicy::None && Name.startswith(".debug"))
|
2016-04-08 05:04:51 +08:00
|
|
|
return &InputSection<ELFT>::Discarded;
|
2016-03-10 02:01:45 +08:00
|
|
|
|
2016-07-15 12:57:44 +08:00
|
|
|
// The linker merges EH (exception handling) frames and creates a
|
|
|
|
// .eh_frame_hdr section for runtime. So we handle them with a special
|
|
|
|
// class. For relocatable outputs, they are just passed through.
|
|
|
|
if (Name == ".eh_frame" && !Config->Relocatable)
|
2016-11-02 06:53:18 +08:00
|
|
|
return make<EhInputSection<ELFT>>(this, &Sec, Name);
|
2016-07-15 12:57:44 +08:00
|
|
|
|
2016-07-16 04:38:28 +08:00
|
|
|
if (shouldMerge(Sec))
|
2016-11-02 06:53:18 +08:00
|
|
|
return make<MergeInputSection<ELFT>>(this, &Sec, Name);
|
|
|
|
return make<InputSection<ELFT>>(this, &Sec, Name);
|
2015-12-24 16:41:12 +08:00
|
|
|
}
|
|
|
|
|
2016-02-28 08:25:54 +08:00
|
|
|
template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() {
|
2015-10-02 03:52:48 +08:00
|
|
|
this->initStringTable();
|
2016-03-11 20:06:30 +08:00
|
|
|
Elf_Sym_Range Syms = this->getElfSymbols(false);
|
2015-08-12 04:06:51 +08:00
|
|
|
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
|
2016-01-06 09:14:11 +08:00
|
|
|
SymbolBodies.reserve(NumSymbols);
|
2015-08-04 22:00:56 +08:00
|
|
|
for (const Elf_Sym &Sym : Syms)
|
2016-01-21 10:10:12 +08:00
|
|
|
SymbolBodies.push_back(createSymbolBody(&Sym));
|
2015-07-25 05:03:07 +08:00
|
|
|
}
|
|
|
|
|
2015-10-16 23:29:48 +08:00
|
|
|
template <class ELFT>
|
2015-10-20 05:00:02 +08:00
|
|
|
InputSectionBase<ELFT> *
|
2016-02-28 08:25:54 +08:00
|
|
|
elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
|
2015-11-03 22:13:40 +08:00
|
|
|
uint32_t Index = this->getSectionIndex(Sym);
|
2016-08-13 03:25:54 +08:00
|
|
|
if (Index >= Sections.size())
|
2016-07-16 04:38:28 +08:00
|
|
|
fatal(getFilename(this) + ": invalid section index: " + Twine(Index));
|
2016-02-26 02:43:51 +08:00
|
|
|
InputSectionBase<ELFT> *S = Sections[Index];
|
2016-10-06 17:17:55 +08:00
|
|
|
|
2016-08-13 03:25:54 +08:00
|
|
|
// We found that GNU assembler 2.17.50 [FreeBSD] 2007-07-03
|
|
|
|
// could generate broken objects. STT_SECTION symbols can be
|
|
|
|
// associated with SHT_REL[A]/SHT_SYMTAB/SHT_STRTAB sections.
|
|
|
|
// In this case it is fine for section to be null here as we
|
|
|
|
// do not allocate sections of these types.
|
2016-10-06 17:17:55 +08:00
|
|
|
if (!S) {
|
|
|
|
if (Index == 0 || Sym.getType() == STT_SECTION)
|
|
|
|
return nullptr;
|
|
|
|
fatal(getFilename(this) + ": invalid section index: " + Twine(Index));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (S == &InputSectionBase<ELFT>::Discarded)
|
2016-02-26 02:43:51 +08:00
|
|
|
return S;
|
|
|
|
return S->Repl;
|
2015-10-16 23:29:48 +08:00
|
|
|
}
|
|
|
|
|
2015-07-25 05:03:07 +08:00
|
|
|
template <class ELFT>
|
2016-02-28 08:25:54 +08:00
|
|
|
SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
|
2016-07-16 04:38:28 +08:00
|
|
|
int Binding = Sym->getBinding();
|
2016-03-11 22:21:37 +08:00
|
|
|
InputSectionBase<ELFT> *Sec = getSection(*Sym);
|
|
|
|
if (Binding == STB_LOCAL) {
|
2016-10-26 19:07:09 +08:00
|
|
|
if (Sym->getType() == STT_FILE)
|
|
|
|
SourceFile = check(Sym->getName(this->StringTable));
|
2016-04-04 22:04:16 +08:00
|
|
|
if (Sym->st_shndx == SHN_UNDEF)
|
2016-10-29 04:57:25 +08:00
|
|
|
return new (BAlloc)
|
2016-07-17 11:11:46 +08:00
|
|
|
Undefined(Sym->st_name, Sym->st_other, Sym->getType(), this);
|
2016-10-29 04:57:25 +08:00
|
|
|
return new (BAlloc) DefinedRegular<ELFT>(*Sym, Sec);
|
2016-03-11 22:21:37 +08:00
|
|
|
}
|
2016-03-11 20:06:30 +08:00
|
|
|
|
2016-03-04 06:24:39 +08:00
|
|
|
StringRef Name = check(Sym->getName(this->StringTable));
|
2015-08-25 05:43:25 +08:00
|
|
|
|
2015-10-16 23:29:48 +08:00
|
|
|
switch (Sym->st_shndx) {
|
2015-08-29 05:26:51 +08:00
|
|
|
case SHN_UNDEF:
|
2016-10-03 19:13:55 +08:00
|
|
|
return elf::Symtab<ELFT>::X->addUndefined(Name, Binding, Sym->st_other,
|
|
|
|
Sym->getType(),
|
|
|
|
/*CanOmitFromDynSym*/ false, this)
|
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
|
|
|
->body();
|
2015-08-29 05:26:51 +08:00
|
|
|
case SHN_COMMON:
|
2016-10-10 18:31:03 +08:00
|
|
|
if (Sym->st_value == 0 || Sym->st_value >= UINT32_MAX)
|
2016-10-04 16:49:52 +08:00
|
|
|
fatal(getFilename(this) + ": common symbol '" + Name +
|
2016-10-10 18:31:03 +08:00
|
|
|
"' has invalid alignment: " + Twine(Sym->st_value));
|
2016-10-03 19:13:55 +08:00
|
|
|
return elf::Symtab<ELFT>::X->addCommon(Name, Sym->st_size, Sym->st_value,
|
|
|
|
Binding, Sym->st_other,
|
|
|
|
Sym->getType(), this)
|
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
|
|
|
->body();
|
2015-08-29 05:26:51 +08:00
|
|
|
}
|
2015-08-25 05:43:25 +08:00
|
|
|
|
2016-03-11 20:06:30 +08:00
|
|
|
switch (Binding) {
|
2015-08-12 01:33:02 +08:00
|
|
|
default:
|
2016-07-16 04:38:28 +08:00
|
|
|
fatal(getFilename(this) + ": unexpected binding: " + Twine(Binding));
|
2015-08-12 01:33:02 +08:00
|
|
|
case STB_GLOBAL:
|
2015-08-29 04:19:34 +08:00
|
|
|
case STB_WEAK:
|
2016-03-11 22:21:37 +08:00
|
|
|
case STB_GNU_UNIQUE:
|
2016-04-04 22:04:16 +08:00
|
|
|
if (Sec == &InputSection<ELFT>::Discarded)
|
2016-10-03 19:13:55 +08:00
|
|
|
return elf::Symtab<ELFT>::X->addUndefined(Name, Binding, Sym->st_other,
|
|
|
|
Sym->getType(),
|
|
|
|
/*CanOmitFromDynSym*/ false,
|
|
|
|
this)
|
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
|
|
|
->body();
|
2016-05-01 14:00:09 +08:00
|
|
|
return elf::Symtab<ELFT>::X->addRegular(Name, *Sym, Sec)->body();
|
2015-10-10 03:25:07 +08:00
|
|
|
}
|
2015-07-25 05:03:07 +08:00
|
|
|
}
|
|
|
|
|
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 ArchiveFile::parse() {
|
2016-03-15 05:31:07 +08:00
|
|
|
File = check(Archive::create(MB), "failed to parse archive");
|
2015-09-05 06:28:10 +08:00
|
|
|
|
|
|
|
// Read the symbol table to construct Lazy objects.
|
2016-10-01 01:56:20 +08:00
|
|
|
for (const Archive::Symbol &Sym : File->symbols())
|
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
|
|
|
Symtab<ELFT>::X->addLazyArchive(this, Sym);
|
2015-09-05 06:28:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a buffer pointing to a member file containing a given symbol.
|
2016-10-13 03:35:54 +08:00
|
|
|
std::pair<MemoryBufferRef, uint64_t>
|
|
|
|
ArchiveFile::getMember(const Archive::Symbol *Sym) {
|
2016-03-04 00:21:44 +08:00
|
|
|
Archive::Child C =
|
2016-03-04 06:24:39 +08:00
|
|
|
check(Sym->getMember(),
|
2016-03-15 05:31:07 +08:00
|
|
|
"could not get the member for symbol " + Sym->getName());
|
2015-09-05 06:28:10 +08:00
|
|
|
|
2015-11-05 22:40:28 +08:00
|
|
|
if (!Seen.insert(C.getChildOffset()).second)
|
2016-10-13 03:35:54 +08:00
|
|
|
return {MemoryBufferRef(), 0};
|
2015-09-09 04:36:20 +08:00
|
|
|
|
2016-05-04 01:30:44 +08:00
|
|
|
MemoryBufferRef Ret =
|
|
|
|
check(C.getMemoryBufferRef(),
|
|
|
|
"could not get the buffer for the member defining symbol " +
|
|
|
|
Sym->getName());
|
2016-05-02 21:54:10 +08:00
|
|
|
|
2016-05-16 01:10:23 +08:00
|
|
|
if (C.getParent()->isThin() && Driver->Cpio)
|
|
|
|
Driver->Cpio->append(relativeToRoot(check(C.getFullName())),
|
|
|
|
Ret.getBuffer());
|
2016-10-13 03:35:54 +08:00
|
|
|
if (C.getParent()->isThin())
|
|
|
|
return {Ret, 0};
|
|
|
|
return {Ret, C.getChildOffset()};
|
2015-09-05 06:28:10 +08:00
|
|
|
}
|
|
|
|
|
2015-09-24 23:11:50 +08:00
|
|
|
template <class ELFT>
|
2016-10-29 04:57:25 +08:00
|
|
|
SharedFile<ELFT>::SharedFile(MemoryBufferRef M)
|
2016-01-06 08:09:41 +08:00
|
|
|
: ELFFileBase<ELFT>(Base::SharedKind, M), AsNeeded(Config->AsNeeded) {}
|
2015-09-08 23:50:05 +08:00
|
|
|
|
2015-11-03 22:13:40 +08:00
|
|
|
template <class ELFT>
|
2016-03-15 07:16:09 +08:00
|
|
|
const typename ELFT::Shdr *
|
2015-11-03 22:13:40 +08:00
|
|
|
SharedFile<ELFT>::getSection(const Elf_Sym &Sym) const {
|
|
|
|
uint32_t Index = this->getSectionIndex(Sym);
|
|
|
|
if (Index == 0)
|
|
|
|
return nullptr;
|
2016-03-04 06:24:39 +08:00
|
|
|
return check(this->ELFObj.getSection(Index));
|
2015-11-03 22:13:40 +08:00
|
|
|
}
|
|
|
|
|
2016-01-06 09:56:36 +08:00
|
|
|
// Partially parse the shared object file so that we can call
|
|
|
|
// getSoName on this object.
|
2015-10-02 03:52:48 +08:00
|
|
|
template <class ELFT> void SharedFile<ELFT>::parseSoName() {
|
2016-03-15 07:16:09 +08:00
|
|
|
typedef typename ELFT::Dyn Elf_Dyn;
|
|
|
|
typedef typename ELFT::uint uintX_t;
|
2015-10-01 23:47:50 +08:00
|
|
|
const Elf_Shdr *DynamicSec = nullptr;
|
|
|
|
|
|
|
|
const ELFFile<ELFT> Obj = this->ELFObj;
|
|
|
|
for (const Elf_Shdr &Sec : Obj.sections()) {
|
2015-11-03 22:13:40 +08:00
|
|
|
switch (Sec.sh_type) {
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
case SHT_DYNSYM:
|
2015-09-08 23:50:05 +08:00
|
|
|
this->Symtab = &Sec;
|
2015-11-03 22:13:40 +08:00
|
|
|
break;
|
|
|
|
case SHT_DYNAMIC:
|
2015-10-01 23:47:50 +08:00
|
|
|
DynamicSec = &Sec;
|
2015-11-03 22:13:40 +08:00
|
|
|
break;
|
2016-03-04 00:21:44 +08:00
|
|
|
case SHT_SYMTAB_SHNDX:
|
2016-03-04 06:24:39 +08:00
|
|
|
this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec));
|
2015-11-03 22:13:40 +08:00
|
|
|
break;
|
2016-04-28 04:22:31 +08:00
|
|
|
case SHT_GNU_versym:
|
|
|
|
this->VersymSec = &Sec;
|
|
|
|
break;
|
|
|
|
case SHT_GNU_verdef:
|
|
|
|
this->VerdefSec = &Sec;
|
|
|
|
break;
|
2015-11-03 22:13:40 +08:00
|
|
|
}
|
2015-09-08 23:50:05 +08:00
|
|
|
}
|
|
|
|
|
2015-10-02 03:52:48 +08:00
|
|
|
this->initStringTable();
|
2016-09-10 05:35:38 +08:00
|
|
|
|
|
|
|
// DSOs are identified by soname, and they usually contain
|
|
|
|
// DT_SONAME tag in their header. But if they are missing,
|
|
|
|
// filenames are used as default sonames.
|
2016-09-09 05:18:38 +08:00
|
|
|
SoName = sys::path::filename(this->getName());
|
2015-10-01 23:47:50 +08:00
|
|
|
|
2015-10-12 23:49:02 +08:00
|
|
|
if (!DynamicSec)
|
|
|
|
return;
|
|
|
|
|
2016-10-07 17:01:04 +08:00
|
|
|
ArrayRef<Elf_Dyn> Arr =
|
|
|
|
check(Obj.template getSectionContentsAsArray<Elf_Dyn>(DynamicSec),
|
|
|
|
getFilename(this) + ": getSectionContentsAsArray failed");
|
|
|
|
for (const Elf_Dyn &Dyn : Arr) {
|
2015-10-12 23:49:02 +08:00
|
|
|
if (Dyn.d_tag == DT_SONAME) {
|
|
|
|
uintX_t Val = Dyn.getVal();
|
|
|
|
if (Val >= this->StringTable.size())
|
2016-07-16 04:38:28 +08:00
|
|
|
fatal(getFilename(this) + ": invalid DT_SONAME entry");
|
2016-01-06 09:14:11 +08:00
|
|
|
SoName = StringRef(this->StringTable.data() + Val);
|
2015-10-12 23:49:02 +08:00
|
|
|
return;
|
2015-10-01 23:47:50 +08:00
|
|
|
}
|
|
|
|
}
|
2015-10-02 03:52:48 +08:00
|
|
|
}
|
2015-10-01 23:47:50 +08:00
|
|
|
|
2016-04-28 04:22:31 +08:00
|
|
|
// Parse the version definitions in the object file if present. Returns a vector
|
|
|
|
// whose nth element contains a pointer to the Elf_Verdef for version identifier
|
|
|
|
// n. Version identifiers that are not definitions map to nullptr. The array
|
|
|
|
// always has at least length 1.
|
|
|
|
template <class ELFT>
|
|
|
|
std::vector<const typename ELFT::Verdef *>
|
|
|
|
SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) {
|
|
|
|
std::vector<const Elf_Verdef *> Verdefs(1);
|
|
|
|
// We only need to process symbol versions for this DSO if it has both a
|
|
|
|
// versym and a verdef section, which indicates that the DSO contains symbol
|
|
|
|
// version definitions.
|
|
|
|
if (!VersymSec || !VerdefSec)
|
|
|
|
return Verdefs;
|
|
|
|
|
|
|
|
// The location of the first global versym entry.
|
|
|
|
Versym = reinterpret_cast<const Elf_Versym *>(this->ELFObj.base() +
|
|
|
|
VersymSec->sh_offset) +
|
|
|
|
this->Symtab->sh_info;
|
|
|
|
|
|
|
|
// We cannot determine the largest verdef identifier without inspecting
|
|
|
|
// every Elf_Verdef, but both bfd and gold assign verdef identifiers
|
|
|
|
// sequentially starting from 1, so we predict that the largest identifier
|
|
|
|
// will be VerdefCount.
|
|
|
|
unsigned VerdefCount = VerdefSec->sh_info;
|
|
|
|
Verdefs.resize(VerdefCount + 1);
|
|
|
|
|
|
|
|
// Build the Verdefs array by following the chain of Elf_Verdef objects
|
|
|
|
// from the start of the .gnu.version_d section.
|
|
|
|
const uint8_t *Verdef = this->ELFObj.base() + VerdefSec->sh_offset;
|
|
|
|
for (unsigned I = 0; I != VerdefCount; ++I) {
|
|
|
|
auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef);
|
|
|
|
Verdef += CurVerdef->vd_next;
|
|
|
|
unsigned VerdefIndex = CurVerdef->vd_ndx;
|
|
|
|
if (Verdefs.size() <= VerdefIndex)
|
|
|
|
Verdefs.resize(VerdefIndex + 1);
|
|
|
|
Verdefs[VerdefIndex] = CurVerdef;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Verdefs;
|
|
|
|
}
|
|
|
|
|
2016-01-06 09:56:36 +08:00
|
|
|
// Fully parse the shared object file. This must be called after parseSoName().
|
|
|
|
template <class ELFT> void SharedFile<ELFT>::parseRest() {
|
2016-04-28 04:22:31 +08:00
|
|
|
// Create mapping from version identifiers to Elf_Verdef entries.
|
|
|
|
const Elf_Versym *Versym = nullptr;
|
|
|
|
std::vector<const Elf_Verdef *> Verdefs = parseVerdefs(Versym);
|
|
|
|
|
2016-03-11 20:06:30 +08:00
|
|
|
Elf_Sym_Range Syms = this->getElfSymbols(true);
|
2015-09-08 23:50:05 +08:00
|
|
|
for (const Elf_Sym &Sym : Syms) {
|
2016-04-30 01:46:07 +08:00
|
|
|
unsigned VersymIndex = 0;
|
|
|
|
if (Versym) {
|
|
|
|
VersymIndex = Versym->vs_index;
|
|
|
|
++Versym;
|
|
|
|
}
|
|
|
|
|
2016-04-30 00:23:31 +08:00
|
|
|
StringRef Name = check(Sym.getName(this->StringTable));
|
|
|
|
if (Sym.isUndefined()) {
|
|
|
|
Undefs.push_back(Name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-04-28 04:22:31 +08:00
|
|
|
if (Versym) {
|
|
|
|
// Ignore local symbols and non-default versions.
|
2016-06-09 23:45:49 +08:00
|
|
|
if (VersymIndex == VER_NDX_LOCAL || (VersymIndex & VERSYM_HIDDEN))
|
2016-04-28 04:22:31 +08:00
|
|
|
continue;
|
|
|
|
}
|
2016-06-09 23:45:49 +08:00
|
|
|
|
|
|
|
const Elf_Verdef *V =
|
|
|
|
VersymIndex == VER_NDX_GLOBAL ? nullptr : Verdefs[VersymIndex];
|
|
|
|
elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V);
|
2015-09-08 23:50:05 +08:00
|
|
|
}
|
|
|
|
}
|
2015-09-04 04:03:54 +08:00
|
|
|
|
2016-08-04 04:33:17 +08:00
|
|
|
static ELFKind getBitcodeELFKind(MemoryBufferRef MB) {
|
2016-08-04 04:25:29 +08:00
|
|
|
Triple T(getBitcodeTargetTriple(MB, Driver->Context));
|
|
|
|
if (T.isLittleEndian())
|
|
|
|
return T.isArch64Bit() ? ELF64LEKind : ELF32LEKind;
|
|
|
|
return T.isArch64Bit() ? ELF64BEKind : ELF32BEKind;
|
2016-06-29 14:12:39 +08:00
|
|
|
}
|
|
|
|
|
2016-08-04 04:33:17 +08:00
|
|
|
static uint8_t getBitcodeMachineKind(MemoryBufferRef MB) {
|
2016-08-04 04:25:29 +08:00
|
|
|
Triple T(getBitcodeTargetTriple(MB, Driver->Context));
|
|
|
|
switch (T.getArch()) {
|
2016-07-07 10:46:30 +08:00
|
|
|
case Triple::aarch64:
|
|
|
|
return EM_AARCH64;
|
|
|
|
case Triple::arm:
|
|
|
|
return EM_ARM;
|
|
|
|
case Triple::mips:
|
|
|
|
case Triple::mipsel:
|
|
|
|
case Triple::mips64:
|
|
|
|
case Triple::mips64el:
|
|
|
|
return EM_MIPS;
|
|
|
|
case Triple::ppc:
|
|
|
|
return EM_PPC;
|
|
|
|
case Triple::ppc64:
|
|
|
|
return EM_PPC64;
|
|
|
|
case Triple::x86:
|
2016-08-04 04:25:29 +08:00
|
|
|
return T.isOSIAMCU() ? EM_IAMCU : EM_386;
|
2016-07-07 10:46:30 +08:00
|
|
|
case Triple::x86_64:
|
|
|
|
return EM_X86_64;
|
|
|
|
default:
|
2016-07-16 04:38:28 +08:00
|
|
|
fatal(MB.getBufferIdentifier() +
|
2016-08-04 04:25:29 +08:00
|
|
|
": could not infer e_machine from bitcode target triple " + T.str());
|
2016-06-29 14:12:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-07 10:46:30 +08:00
|
|
|
BitcodeFile::BitcodeFile(MemoryBufferRef MB) : InputFile(BitcodeKind, MB) {
|
2016-08-04 04:33:17 +08:00
|
|
|
EKind = getBitcodeELFKind(MB);
|
|
|
|
EMachine = getBitcodeMachineKind(MB);
|
2016-06-29 14:12:39 +08:00
|
|
|
}
|
2016-02-13 04:54:57 +08:00
|
|
|
|
2016-09-29 08:40:08 +08:00
|
|
|
static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) {
|
|
|
|
switch (GvVisibility) {
|
2016-03-08 03:06:14 +08:00
|
|
|
case GlobalValue::DefaultVisibility:
|
|
|
|
return STV_DEFAULT;
|
2016-03-07 08:54:17 +08:00
|
|
|
case GlobalValue::HiddenVisibility:
|
|
|
|
return STV_HIDDEN;
|
|
|
|
case GlobalValue::ProtectedVisibility:
|
|
|
|
return STV_PROTECTED;
|
|
|
|
}
|
2016-03-12 16:31:34 +08:00
|
|
|
llvm_unreachable("unknown visibility");
|
2016-03-12 02:46:51 +08:00
|
|
|
}
|
|
|
|
|
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>
|
2016-10-25 20:02:31 +08:00
|
|
|
static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
|
2016-09-29 08:40:08 +08:00
|
|
|
const lto::InputFile::Symbol &ObjSym,
|
2016-10-29 04:57:25 +08:00
|
|
|
BitcodeFile *F) {
|
2016-09-29 08:40:08 +08:00
|
|
|
StringRef NameRef = Saver.save(ObjSym.getName());
|
|
|
|
uint32_t Flags = ObjSym.getFlags();
|
2016-08-31 04:53:26 +08:00
|
|
|
uint32_t Binding = (Flags & BasicSymbolRef::SF_Weak) ? STB_WEAK : STB_GLOBAL;
|
2016-04-23 02:26:33 +08:00
|
|
|
|
2016-09-29 08:40:08 +08:00
|
|
|
uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE;
|
|
|
|
uint8_t Visibility = mapVisibility(ObjSym.getVisibility());
|
|
|
|
bool CanOmitFromDynSym = ObjSym.canBeOmittedFromSymbolTable();
|
2016-03-12 02:46:51 +08:00
|
|
|
|
2016-10-25 20:02:31 +08:00
|
|
|
int C = check(ObjSym.getComdatIndex());
|
|
|
|
if (C != -1 && !KeptComdats[C])
|
|
|
|
return Symtab<ELFT>::X->addUndefined(NameRef, Binding, Visibility, Type,
|
|
|
|
CanOmitFromDynSym, F);
|
2016-03-12 02:46:51 +08:00
|
|
|
|
2016-04-23 02:26:33 +08:00
|
|
|
if (Flags & BasicSymbolRef::SF_Undefined)
|
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
|
|
|
return Symtab<ELFT>::X->addUndefined(NameRef, Binding, Visibility, Type,
|
2016-09-29 08:40:08 +08:00
|
|
|
CanOmitFromDynSym, F);
|
|
|
|
|
|
|
|
if (Flags & BasicSymbolRef::SF_Common)
|
|
|
|
return Symtab<ELFT>::X->addCommon(NameRef, ObjSym.getCommonSize(),
|
|
|
|
ObjSym.getCommonAlignment(), Binding,
|
|
|
|
Visibility, STT_OBJECT, F);
|
2016-04-23 02:26:33 +08:00
|
|
|
|
2016-09-29 08:40:08 +08:00
|
|
|
return Symtab<ELFT>::X->addBitcode(NameRef, Binding, Visibility, Type,
|
|
|
|
CanOmitFromDynSym, F);
|
2016-03-12 00:11:47 +08:00
|
|
|
}
|
|
|
|
|
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>
|
2016-10-22 03:49:42 +08:00
|
|
|
void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
|
2016-10-13 03:35:54 +08:00
|
|
|
|
|
|
|
// Here we pass a new MemoryBufferRef which is identified by ArchiveName
|
|
|
|
// (the fully resolved path of the archive) + member name + offset of the
|
|
|
|
// member in the archive.
|
|
|
|
// ThinLTO uses the MemoryBufferRef identifier to access its internal
|
|
|
|
// data structures and if two archives define two members with the same name,
|
|
|
|
// this causes a collision which result in only one of the objects being
|
|
|
|
// taken into consideration at LTO time (which very likely causes undefined
|
|
|
|
// symbols later in the link stage).
|
|
|
|
Obj = check(lto::InputFile::create(MemoryBufferRef(
|
|
|
|
MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier() +
|
|
|
|
utostr(OffsetInArchive)))));
|
2016-10-25 20:02:31 +08:00
|
|
|
|
|
|
|
std::vector<bool> KeptComdats;
|
|
|
|
for (StringRef S : Obj->getComdatTable()) {
|
|
|
|
StringRef N = Saver.save(S);
|
|
|
|
KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(N)).second);
|
|
|
|
}
|
|
|
|
|
2016-09-29 08:40:08 +08:00
|
|
|
for (const lto::InputFile::Symbol &ObjSym : Obj->symbols())
|
2016-10-29 04:57:25 +08:00
|
|
|
Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, this));
|
2016-02-13 04:54:57 +08:00
|
|
|
}
|
|
|
|
|
2015-10-12 23:31:09 +08:00
|
|
|
template <template <class> class T>
|
2016-10-29 04:57:25 +08:00
|
|
|
static InputFile *createELFFile(MemoryBufferRef MB) {
|
2016-04-08 08:18:25 +08:00
|
|
|
unsigned char Size;
|
|
|
|
unsigned char Endian;
|
|
|
|
std::tie(Size, Endian) = getElfArchType(MB.getBuffer());
|
|
|
|
if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB)
|
2016-03-12 16:31:34 +08:00
|
|
|
fatal("invalid data encoding: " + MB.getBufferIdentifier());
|
2015-10-12 23:31:09 +08:00
|
|
|
|
2016-09-14 08:05:51 +08:00
|
|
|
InputFile *Obj;
|
2016-06-29 09:30:50 +08:00
|
|
|
if (Size == ELFCLASS32 && Endian == ELFDATA2LSB)
|
2016-11-02 06:53:18 +08:00
|
|
|
Obj = make<T<ELF32LE>>(MB);
|
2016-06-29 09:30:50 +08:00
|
|
|
else if (Size == ELFCLASS32 && Endian == ELFDATA2MSB)
|
2016-11-02 06:53:18 +08:00
|
|
|
Obj = make<T<ELF32BE>>(MB);
|
2016-06-29 09:30:50 +08:00
|
|
|
else if (Size == ELFCLASS64 && Endian == ELFDATA2LSB)
|
2016-11-02 06:53:18 +08:00
|
|
|
Obj = make<T<ELF64LE>>(MB);
|
2016-06-29 09:30:50 +08:00
|
|
|
else if (Size == ELFCLASS64 && Endian == ELFDATA2MSB)
|
2016-11-02 06:53:18 +08:00
|
|
|
Obj = make<T<ELF64BE>>(MB);
|
2016-06-29 09:30:50 +08:00
|
|
|
else
|
|
|
|
fatal("invalid file class: " + MB.getBufferIdentifier());
|
|
|
|
|
|
|
|
if (!Config->FirstElf)
|
2016-09-14 08:05:51 +08:00
|
|
|
Config->FirstElf = Obj;
|
2016-06-29 09:30:50 +08:00
|
|
|
return Obj;
|
2015-10-12 23:31:09 +08:00
|
|
|
}
|
|
|
|
|
2016-10-28 01:45:40 +08:00
|
|
|
template <class ELFT> void BinaryFile::parse() {
|
|
|
|
StringRef Buf = MB.getBuffer();
|
|
|
|
ArrayRef<uint8_t> Data =
|
|
|
|
makeArrayRef<uint8_t>((const uint8_t *)Buf.data(), Buf.size());
|
2016-10-21 05:57:06 +08:00
|
|
|
|
2016-10-28 01:45:40 +08:00
|
|
|
std::string Filename = MB.getBufferIdentifier();
|
|
|
|
std::transform(Filename.begin(), Filename.end(), Filename.begin(),
|
|
|
|
[](char C) { return isalnum(C) ? C : '_'; });
|
|
|
|
Filename = "_binary_" + Filename;
|
|
|
|
StringRef StartName = Saver.save(Twine(Filename) + "_start");
|
|
|
|
StringRef EndName = Saver.save(Twine(Filename) + "_end");
|
|
|
|
StringRef SizeName = Saver.save(Twine(Filename) + "_size");
|
|
|
|
|
|
|
|
auto *Section =
|
|
|
|
new InputSection<ELFT>(SHF_ALLOC, SHT_PROGBITS, 8, Data, ".data");
|
|
|
|
Sections.push_back(Section);
|
|
|
|
|
|
|
|
elf::Symtab<ELFT>::X->addRegular(StartName, STV_DEFAULT, Section, STB_GLOBAL,
|
|
|
|
STT_OBJECT, 0);
|
|
|
|
elf::Symtab<ELFT>::X->addRegular(EndName, STV_DEFAULT, Section, STB_GLOBAL,
|
|
|
|
STT_OBJECT, Data.size());
|
|
|
|
elf::Symtab<ELFT>::X->addRegular(SizeName, STV_DEFAULT, nullptr, STB_GLOBAL,
|
|
|
|
STT_OBJECT, Data.size());
|
2016-09-10 06:08:04 +08:00
|
|
|
}
|
|
|
|
|
2016-04-08 08:14:55 +08:00
|
|
|
static bool isBitcode(MemoryBufferRef MB) {
|
|
|
|
using namespace sys::fs;
|
|
|
|
return identify_magic(MB.getBuffer()) == file_magic::bitcode;
|
|
|
|
}
|
|
|
|
|
2016-10-29 04:57:25 +08:00
|
|
|
InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName,
|
2016-10-13 03:35:54 +08:00
|
|
|
uint64_t OffsetInArchive) {
|
2016-10-29 04:57:25 +08:00
|
|
|
InputFile *F =
|
|
|
|
isBitcode(MB) ? new BitcodeFile(MB) : createELFFile<ObjectFile>(MB);
|
2016-02-02 16:22:41 +08:00
|
|
|
F->ArchiveName = ArchiveName;
|
2016-10-13 03:35:54 +08:00
|
|
|
F->OffsetInArchive = OffsetInArchive;
|
2016-02-02 16:22:41 +08:00
|
|
|
return F;
|
2016-01-06 08:09:43 +08:00
|
|
|
}
|
|
|
|
|
2016-10-29 04:57:25 +08:00
|
|
|
InputFile *elf::createSharedFile(MemoryBufferRef MB) {
|
|
|
|
return createELFFile<SharedFile>(MB);
|
2016-01-06 08:09:43 +08:00
|
|
|
}
|
|
|
|
|
2016-06-15 05:56:36 +08:00
|
|
|
MemoryBufferRef LazyObjectFile::getBuffer() {
|
|
|
|
if (Seen)
|
|
|
|
return MemoryBufferRef();
|
|
|
|
Seen = true;
|
|
|
|
return MB;
|
|
|
|
}
|
|
|
|
|
2016-10-03 19:13:55 +08:00
|
|
|
template <class ELFT> void LazyObjectFile::parse() {
|
2016-04-08 03:24:51 +08:00
|
|
|
for (StringRef Sym : getSymbols())
|
2016-06-15 05:56:36 +08:00
|
|
|
Symtab<ELFT>::X->addLazyObject(Sym, *this);
|
2016-04-08 03:24:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() {
|
|
|
|
typedef typename ELFT::Shdr Elf_Shdr;
|
|
|
|
typedef typename ELFT::Sym Elf_Sym;
|
|
|
|
typedef typename ELFT::SymRange Elf_Sym_Range;
|
|
|
|
|
|
|
|
const ELFFile<ELFT> Obj = createELFObj<ELFT>(this->MB);
|
|
|
|
for (const Elf_Shdr &Sec : Obj.sections()) {
|
|
|
|
if (Sec.sh_type != SHT_SYMTAB)
|
|
|
|
continue;
|
|
|
|
Elf_Sym_Range Syms = Obj.symbols(&Sec);
|
|
|
|
uint32_t FirstNonLocal = Sec.sh_info;
|
|
|
|
StringRef StringTable = check(Obj.getStringTableForSymtab(Sec));
|
|
|
|
std::vector<StringRef> V;
|
|
|
|
for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal))
|
2016-04-09 04:49:31 +08:00
|
|
|
if (Sym.st_shndx != SHN_UNDEF)
|
|
|
|
V.push_back(check(Sym.getName(StringTable)));
|
2016-04-08 03:24:51 +08:00
|
|
|
return V;
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() {
|
2016-09-29 08:40:08 +08:00
|
|
|
std::unique_ptr<lto::InputFile> Obj = check(lto::InputFile::create(this->MB));
|
2016-09-29 08:58:10 +08:00
|
|
|
std::vector<StringRef> V;
|
|
|
|
for (const lto::InputFile::Symbol &Sym : Obj->symbols())
|
|
|
|
if (!(Sym.getFlags() & BasicSymbolRef::SF_Undefined))
|
|
|
|
V.push_back(Saver.save(Sym.getName()));
|
2016-04-08 03:24:51 +08:00
|
|
|
return V;
|
|
|
|
}
|
|
|
|
|
2016-04-09 04:49:31 +08:00
|
|
|
// Returns a vector of globally-visible defined symbol names.
|
2016-04-08 03:24:51 +08:00
|
|
|
std::vector<StringRef> LazyObjectFile::getSymbols() {
|
2016-04-08 08:14:55 +08:00
|
|
|
if (isBitcode(this->MB))
|
2016-04-08 03:24:51 +08:00
|
|
|
return getBitcodeSymbols();
|
|
|
|
|
2016-04-08 08:14:55 +08:00
|
|
|
unsigned char Size;
|
|
|
|
unsigned char Endian;
|
|
|
|
std::tie(Size, Endian) = getElfArchType(this->MB.getBuffer());
|
|
|
|
if (Size == ELFCLASS32) {
|
|
|
|
if (Endian == ELFDATA2LSB)
|
2016-04-08 03:24:51 +08:00
|
|
|
return getElfSymbols<ELF32LE>();
|
|
|
|
return getElfSymbols<ELF32BE>();
|
|
|
|
}
|
2016-04-08 08:14:55 +08:00
|
|
|
if (Endian == ELFDATA2LSB)
|
2016-04-08 03:24:51 +08:00
|
|
|
return getElfSymbols<ELF64LE>();
|
|
|
|
return getElfSymbols<ELF64BE>();
|
|
|
|
}
|
|
|
|
|
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 void ArchiveFile::parse<ELF32LE>();
|
|
|
|
template void ArchiveFile::parse<ELF32BE>();
|
|
|
|
template void ArchiveFile::parse<ELF64LE>();
|
|
|
|
template void ArchiveFile::parse<ELF64BE>();
|
|
|
|
|
2016-10-22 03:49:42 +08:00
|
|
|
template void BitcodeFile::parse<ELF32LE>(DenseSet<CachedHashStringRef> &);
|
|
|
|
template void BitcodeFile::parse<ELF32BE>(DenseSet<CachedHashStringRef> &);
|
|
|
|
template void BitcodeFile::parse<ELF64LE>(DenseSet<CachedHashStringRef> &);
|
|
|
|
template void BitcodeFile::parse<ELF64BE>(DenseSet<CachedHashStringRef> &);
|
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 void LazyObjectFile::parse<ELF32LE>();
|
|
|
|
template void LazyObjectFile::parse<ELF32BE>();
|
|
|
|
template void LazyObjectFile::parse<ELF64LE>();
|
|
|
|
template void LazyObjectFile::parse<ELF64BE>();
|
|
|
|
|
2016-02-28 08:25:54 +08:00
|
|
|
template class elf::ELFFileBase<ELF32LE>;
|
|
|
|
template class elf::ELFFileBase<ELF32BE>;
|
|
|
|
template class elf::ELFFileBase<ELF64LE>;
|
|
|
|
template class elf::ELFFileBase<ELF64BE>;
|
2015-11-20 10:19:36 +08:00
|
|
|
|
2016-02-28 08:25:54 +08:00
|
|
|
template class elf::ObjectFile<ELF32LE>;
|
|
|
|
template class elf::ObjectFile<ELF32BE>;
|
|
|
|
template class elf::ObjectFile<ELF64LE>;
|
|
|
|
template class elf::ObjectFile<ELF64BE>;
|
2015-11-20 10:19:36 +08:00
|
|
|
|
2016-02-28 08:25:54 +08:00
|
|
|
template class elf::SharedFile<ELF32LE>;
|
|
|
|
template class elf::SharedFile<ELF32BE>;
|
|
|
|
template class elf::SharedFile<ELF64LE>;
|
|
|
|
template class elf::SharedFile<ELF64BE>;
|
2016-09-10 06:08:04 +08:00
|
|
|
|
2016-10-28 01:45:40 +08:00
|
|
|
template void BinaryFile::parse<ELF32LE>();
|
|
|
|
template void BinaryFile::parse<ELF32BE>();
|
|
|
|
template void BinaryFile::parse<ELF64LE>();
|
|
|
|
template void BinaryFile::parse<ELF64BE>();
|
2016-10-26 19:07:09 +08:00
|
|
|
|
|
|
|
template class elf::DIHelper<ELF32LE>;
|
|
|
|
template class elf::DIHelper<ELF32BE>;
|
|
|
|
template class elf::DIHelper<ELF64LE>;
|
|
|
|
template class elf::DIHelper<ELF64BE>;
|