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-02-11 23:24:48 +08:00
|
|
|
#include "InputSection.h"
|
2016-08-13 03:56:57 +08:00
|
|
|
#include "LinkerScript.h"
|
2016-12-18 22:06:06 +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"
|
2016-12-14 18:36:12 +08:00
|
|
|
#include "SyntheticSections.h"
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-26 06:28:38 +08:00
|
|
|
#include "lld/Common/ErrorHandler.h"
|
2015-07-25 05:03:07 +08:00
|
|
|
#include "llvm/ADT/STLExtras.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"
|
2017-01-09 09:42:02 +08:00
|
|
|
#include "llvm/Support/TarWriter.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
|
|
|
|
2017-09-19 17:20:54 +08:00
|
|
|
std::vector<BinaryFile *> elf::BinaryFiles;
|
|
|
|
std::vector<BitcodeFile *> elf::BitcodeFiles;
|
|
|
|
std::vector<InputFile *> elf::ObjectFiles;
|
|
|
|
std::vector<InputFile *> elf::SharedFiles;
|
|
|
|
|
2017-01-09 09:42:02 +08:00
|
|
|
TarWriter *elf::Tar;
|
|
|
|
|
2017-04-04 03:11:23 +08:00
|
|
|
InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
|
2017-03-31 05:13:00 +08:00
|
|
|
|
2017-01-09 09:42:02 +08:00
|
|
|
Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
|
2017-07-21 02:17:55 +08:00
|
|
|
// The --chroot option changes our virtual root directory.
|
|
|
|
// This is useful when you are dealing with files created by --reproduce.
|
|
|
|
if (!Config->Chroot.empty() && Path.startswith("/"))
|
|
|
|
Path = Saver.save(Config->Chroot + Path);
|
|
|
|
|
2017-02-22 07:22:56 +08:00
|
|
|
log(Path);
|
2017-07-21 02:17:55 +08:00
|
|
|
|
2017-01-09 09:42:02 +08:00
|
|
|
auto MBOrErr = MemoryBuffer::getFile(Path);
|
|
|
|
if (auto EC = MBOrErr.getError()) {
|
2017-01-13 06:18:04 +08:00
|
|
|
error("cannot open " + Path + ": " + EC.message());
|
2017-01-09 09:42:02 +08:00
|
|
|
return None;
|
|
|
|
}
|
2017-02-22 07:22:56 +08:00
|
|
|
|
2017-01-09 09:42:02 +08:00
|
|
|
std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
|
|
|
|
MemoryBufferRef MBRef = MB->getMemBufferRef();
|
|
|
|
make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership
|
|
|
|
|
|
|
|
if (Tar)
|
|
|
|
Tar->append(relativeToRoot(Path), MBRef.getBuffer());
|
|
|
|
return MBRef;
|
|
|
|
}
|
|
|
|
|
2017-11-01 15:42:38 +08:00
|
|
|
template <class ELFT> void ObjFile<ELFT>::initializeDwarf() {
|
2017-07-20 06:27:35 +08:00
|
|
|
DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(this));
|
|
|
|
const DWARFObject &Obj = Dwarf.getDWARFObj();
|
2017-06-30 00:52:29 +08:00
|
|
|
DwarfLine.reset(new DWARFDebugLine);
|
2017-07-20 06:27:35 +08:00
|
|
|
DWARFDataExtractor LineData(Obj, Obj.getLineSection(), Config->IsLE,
|
2017-06-30 00:52:29 +08:00
|
|
|
Config->Wordsize);
|
2016-11-03 02:42:13 +08:00
|
|
|
|
2016-10-26 19:07:09 +08:00
|
|
|
// 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.
|
2017-11-08 03:57:12 +08:00
|
|
|
// FIXME: Provide the associated DWARFUnit if there is one. DWARF v5
|
|
|
|
// needs it in order to find indirect strings.
|
2017-11-01 15:42:38 +08:00
|
|
|
const DWARFDebugLine::LineTable *LT =
|
2017-11-08 03:57:12 +08:00
|
|
|
DwarfLine->getOrParseLineTable(LineData, 0, nullptr);
|
2017-11-01 15:42:38 +08:00
|
|
|
|
|
|
|
// Return if there is no debug information about CU available.
|
|
|
|
if (!Dwarf.getNumCompileUnits())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Loop over variable records and insert them to VariableLoc.
|
|
|
|
DWARFCompileUnit *CU = Dwarf.getCompileUnitAtIndex(0);
|
|
|
|
for (const auto &Entry : CU->dies()) {
|
|
|
|
DWARFDie Die(CU, &Entry);
|
|
|
|
// Skip all tags that are not variables.
|
|
|
|
if (Die.getTag() != dwarf::DW_TAG_variable)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Skip if a local variable because we don't need them for generating error
|
|
|
|
// messages. In general, only non-local symbols can fail to be linked.
|
|
|
|
if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Get the source filename index for the variable.
|
|
|
|
unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0);
|
|
|
|
if (!LT->hasFileAtIndex(File))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Get the line number on which the variable is declared.
|
|
|
|
unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0);
|
|
|
|
|
|
|
|
// Get the name of the variable and add the collected information to
|
|
|
|
// VariableLoc. Usually Name is non-empty, but it can be empty if the input
|
|
|
|
// object file lacks some debug info.
|
|
|
|
StringRef Name = dwarf::toString(Die.find(dwarf::DW_AT_name), "");
|
|
|
|
if (!Name.empty())
|
|
|
|
VariableLoc.insert({Name, {File, Line}});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the pair of file name and line number describing location of data
|
|
|
|
// object (variable, array, etc) definition.
|
|
|
|
template <class ELFT>
|
|
|
|
Optional<std::pair<std::string, unsigned>>
|
|
|
|
ObjFile<ELFT>::getVariableLoc(StringRef Name) {
|
|
|
|
llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); });
|
|
|
|
|
|
|
|
// There is always only one CU so it's offset is 0.
|
|
|
|
const DWARFDebugLine::LineTable *LT = DwarfLine->getLineTable(0);
|
|
|
|
if (!LT)
|
|
|
|
return None;
|
|
|
|
|
|
|
|
// Return if we have no debug information about data object.
|
|
|
|
auto It = VariableLoc.find(Name);
|
|
|
|
if (It == VariableLoc.end())
|
|
|
|
return None;
|
|
|
|
|
|
|
|
// Take file name string from line table.
|
|
|
|
std::string FileName;
|
|
|
|
if (!LT->getFileNameByIndex(
|
|
|
|
It->second.first /* File */, nullptr,
|
|
|
|
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName))
|
|
|
|
return None;
|
|
|
|
|
|
|
|
return std::make_pair(FileName, It->second.second /*Line*/);
|
2016-10-26 19:07:09 +08:00
|
|
|
}
|
|
|
|
|
2016-11-03 02:42:13 +08:00
|
|
|
// Returns source line information for a given offset
|
|
|
|
// using DWARF debug info.
|
2016-11-01 17:17:50 +08:00
|
|
|
template <class ELFT>
|
2017-07-27 06:13:32 +08:00
|
|
|
Optional<DILineInfo> ObjFile<ELFT>::getDILineInfo(InputSectionBase *S,
|
|
|
|
uint64_t Offset) {
|
2017-11-01 15:42:38 +08:00
|
|
|
llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); });
|
2016-10-26 19:07:09 +08:00
|
|
|
|
2016-11-03 02:42:13 +08:00
|
|
|
// The offset to CU is 0.
|
|
|
|
const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0);
|
|
|
|
if (!Tbl)
|
2017-03-31 03:13:47 +08:00
|
|
|
return None;
|
2016-11-01 17:17:50 +08:00
|
|
|
|
|
|
|
// Use fake address calcuated by adding section file offset and offset in
|
2016-11-03 02:42:13 +08:00
|
|
|
// section. See comments for ObjectInfo class.
|
|
|
|
DILineInfo Info;
|
2016-12-08 03:42:25 +08:00
|
|
|
Tbl->getFileLineInfoForAddress(
|
2017-03-08 23:57:17 +08:00
|
|
|
S->getOffsetInFile() + Offset, nullptr,
|
2016-12-08 03:42:25 +08:00
|
|
|
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info);
|
2016-11-03 02:42:13 +08:00
|
|
|
if (Info.Line == 0)
|
2017-03-31 03:13:47 +08:00
|
|
|
return None;
|
|
|
|
return Info;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns source line information for a given offset
|
|
|
|
// using DWARF debug info.
|
|
|
|
template <class ELFT>
|
2017-07-27 06:13:32 +08:00
|
|
|
std::string ObjFile<ELFT>::getLineInfo(InputSectionBase *S, uint64_t Offset) {
|
2017-03-31 03:13:47 +08:00
|
|
|
if (Optional<DILineInfo> Info = getDILineInfo(S, Offset))
|
|
|
|
return Info->FileName + ":" + std::to_string(Info->Line);
|
|
|
|
return "";
|
2016-10-26 19:07:09 +08:00
|
|
|
}
|
|
|
|
|
2017-04-29 04:00:09 +08:00
|
|
|
// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
|
2017-01-06 18:04:08 +08:00
|
|
|
std::string lld::toString(const InputFile *F) {
|
2017-04-04 03:11:23 +08:00
|
|
|
if (!F)
|
2017-04-29 04:00:09 +08:00
|
|
|
return "<internal>";
|
2017-04-04 03:11:23 +08:00
|
|
|
|
|
|
|
if (F->ToStringCache.empty()) {
|
|
|
|
if (F->ArchiveName.empty())
|
|
|
|
F->ToStringCache = F->getName();
|
|
|
|
else
|
|
|
|
F->ToStringCache = (F->ArchiveName + "(" + F->getName() + ")").str();
|
|
|
|
}
|
|
|
|
return F->ToStringCache;
|
2016-05-10 05:40:06 +08:00
|
|
|
}
|
|
|
|
|
2016-06-29 09:30:50 +08:00
|
|
|
template <class ELFT>
|
2016-11-04 04:44:50 +08:00
|
|
|
ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) {
|
2017-04-27 06:51:51 +08:00
|
|
|
if (ELFT::TargetEndianness == support::little)
|
|
|
|
EKind = ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind;
|
|
|
|
else
|
|
|
|
EKind = ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind;
|
|
|
|
|
2016-11-04 04:44:50 +08:00
|
|
|
EMachine = getObj().getHeader()->e_machine;
|
|
|
|
OSABI = getObj().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>
|
2017-08-03 01:35:18 +08:00
|
|
|
typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalELFSyms() {
|
|
|
|
return makeArrayRef(ELFSyms.begin() + FirstNonLocal, ELFSyms.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 {
|
2017-08-03 01:35:18 +08:00
|
|
|
return check(getObj().getSectionIndex(&Sym, ELFSyms, SymtabSHNDX),
|
2017-04-04 03:11:23 +08:00
|
|
|
toString(this));
|
2015-11-03 22:13:40 +08:00
|
|
|
}
|
|
|
|
|
2016-11-03 21:24:29 +08:00
|
|
|
template <class ELFT>
|
2016-11-03 23:43:47 +08:00
|
|
|
void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections,
|
|
|
|
const Elf_Shdr *Symtab) {
|
2016-11-04 00:55:44 +08:00
|
|
|
FirstNonLocal = Symtab->sh_info;
|
2017-08-03 01:35:18 +08:00
|
|
|
ELFSyms = check(getObj().symbols(Symtab), toString(this));
|
|
|
|
if (FirstNonLocal == 0 || FirstNonLocal > ELFSyms.size())
|
2016-11-24 02:07:33 +08:00
|
|
|
fatal(toString(this) + ": invalid sh_info in symbol table");
|
2016-11-04 00:55:44 +08:00
|
|
|
|
2017-04-04 03:11:23 +08:00
|
|
|
StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections),
|
|
|
|
toString(this));
|
2015-10-02 03:52:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
2017-07-27 06:13:32 +08:00
|
|
|
ObjFile<ELFT>::ObjFile(MemoryBufferRef M, StringRef ArchiveName)
|
2017-08-19 08:13:54 +08:00
|
|
|
: ELFFileBase<ELFT>(Base::ObjKind, M) {
|
2017-04-27 06:51:51 +08:00
|
|
|
this->ArchiveName = ArchiveName;
|
|
|
|
}
|
2016-03-11 20:06:30 +08:00
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getLocalSymbols() {
|
2017-08-04 19:07:42 +08:00
|
|
|
if (this->Symbols.empty())
|
|
|
|
return {};
|
|
|
|
return makeArrayRef(this->Symbols).slice(1, this->FirstNonLocal - 1);
|
2015-09-08 23:50:05 +08:00
|
|
|
}
|
|
|
|
|
2015-10-10 03:25:07 +08:00
|
|
|
template <class ELFT>
|
2017-07-27 06:13:32 +08:00
|
|
|
void ObjFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
|
2015-07-25 05:03:07 +08:00
|
|
|
// Read section and symbol tables.
|
2016-11-08 23:51:00 +08:00
|
|
|
initializeSections(ComdatGroups);
|
|
|
|
initializeSymbols();
|
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>
|
2017-07-27 06:13:32 +08:00
|
|
|
StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
|
|
|
|
const Elf_Shdr &Sec) {
|
2017-06-13 02:46:33 +08:00
|
|
|
// Group signatures are stored as symbol names in object files.
|
|
|
|
// sh_info contains a symbol index, so we fetch a symbol and read its name.
|
2017-08-03 01:35:18 +08:00
|
|
|
if (this->ELFSyms.empty())
|
2017-03-31 05:13:00 +08:00
|
|
|
this->initSymtab(
|
|
|
|
Sections,
|
2017-04-04 03:11:23 +08:00
|
|
|
check(object::getSection<ELFT>(Sections, Sec.sh_link), toString(this)));
|
2017-06-13 02:46:33 +08:00
|
|
|
|
2017-04-04 03:11:23 +08:00
|
|
|
const Elf_Sym *Sym = check(
|
2017-08-03 01:35:18 +08:00
|
|
|
object::getSymbol<ELFT>(this->ELFSyms, Sec.sh_info), toString(this));
|
2017-06-13 02:46:33 +08:00
|
|
|
StringRef Signature = check(Sym->getName(this->StringTable), toString(this));
|
|
|
|
|
|
|
|
// As a special case, if a symbol is a section symbol and has no name,
|
|
|
|
// we use a section name as a signature.
|
|
|
|
//
|
|
|
|
// Such SHT_GROUP sections are invalid from the perspective of the ELF
|
|
|
|
// standard, but GNU gold 1.14 (the neweset version as of July 2017) or
|
|
|
|
// older produce such sections as outputs for the -r option, so we need
|
|
|
|
// a bug-compatibility.
|
|
|
|
if (Signature.empty() && Sym->getType() == STT_SECTION)
|
|
|
|
return getSectionName(Sec);
|
|
|
|
return Signature;
|
2015-10-10 03:25:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
2017-07-27 06:13:32 +08:00
|
|
|
ArrayRef<typename ObjFile<ELFT>::Elf_Word>
|
|
|
|
ObjFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
|
2016-11-04 04:44:50 +08:00
|
|
|
const ELFFile<ELFT> &Obj = this->getObj();
|
2017-03-31 05:13:00 +08:00
|
|
|
ArrayRef<Elf_Word> Entries = check(
|
2017-04-04 03:11:23 +08:00
|
|
|
Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), toString(this));
|
2015-10-10 03:25:07 +08:00
|
|
|
if (Entries.empty() || Entries[0] != GRP_COMDAT)
|
2016-11-24 02:07:33 +08:00
|
|
|
fatal(toString(this) + ": unsupported SHT_GROUP format");
|
2015-10-10 03:25:07 +08:00
|
|
|
return Entries.slice(1);
|
|
|
|
}
|
|
|
|
|
2017-07-27 06:13:32 +08:00
|
|
|
template <class ELFT> bool ObjFile<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
|
2017-10-30 06:38:00 +08:00
|
|
|
// to reflect changes introduced by merging.
|
2016-10-05 15:49:18 +08:00
|
|
|
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.
|
2017-02-25 03:52:52 +08:00
|
|
|
uint64_t EntSize = Sec.sh_entsize;
|
2016-09-21 11:22:18 +08:00
|
|
|
if (EntSize == 0)
|
|
|
|
return false;
|
|
|
|
if (Sec.sh_size % EntSize)
|
2016-11-24 02:07:33 +08:00
|
|
|
fatal(toString(this) +
|
2016-09-21 11:22:18 +08:00
|
|
|
": SHF_MERGE section size must be a multiple of sh_entsize");
|
|
|
|
|
2017-02-25 03:52:52 +08:00
|
|
|
uint64_t Flags = Sec.sh_flags;
|
2015-10-25 06:51:01 +08:00
|
|
|
if (!(Flags & SHF_MERGE))
|
|
|
|
return false;
|
|
|
|
if (Flags & SHF_WRITE)
|
2016-11-24 02:07:33 +08:00
|
|
|
fatal(toString(this) + ": writable SHF_MERGE section is not supported");
|
2015-10-25 06:51:01 +08:00
|
|
|
|
2017-11-16 01:31:27 +08:00
|
|
|
return true;
|
2015-10-25 06:51:01 +08:00
|
|
|
}
|
|
|
|
|
2015-10-10 03:25:07 +08:00
|
|
|
template <class ELFT>
|
2017-07-27 06:13:32 +08:00
|
|
|
void ObjFile<ELFT>::initializeSections(
|
2017-05-26 05:53:02 +08:00
|
|
|
DenseSet<CachedHashStringRef> &ComdatGroups) {
|
2017-05-26 10:17:30 +08:00
|
|
|
const ELFFile<ELFT> &Obj = this->getObj();
|
|
|
|
|
2017-03-31 05:13:00 +08:00
|
|
|
ArrayRef<Elf_Shdr> ObjSections =
|
2017-04-04 03:11:23 +08:00
|
|
|
check(this->getObj().sections(), toString(this));
|
2016-11-02 22:42:20 +08:00
|
|
|
uint64_t Size = ObjSections.size();
|
2017-03-21 16:44:25 +08:00
|
|
|
this->Sections.resize(Size);
|
2017-06-13 02:46:33 +08:00
|
|
|
this->SectionStringTable =
|
2017-04-04 03:11:23 +08:00
|
|
|
check(Obj.getSectionStringTable(ObjSections), toString(this));
|
2017-05-26 10:17:30 +08:00
|
|
|
|
|
|
|
for (size_t I = 0, E = ObjSections.size(); I < E; I++) {
|
2017-03-21 16:44:25 +08:00
|
|
|
if (this->Sections[I] == &InputSection::Discarded)
|
2015-10-10 03:25:07 +08:00
|
|
|
continue;
|
2017-05-26 10:17:30 +08:00
|
|
|
const Elf_Shdr &Sec = ObjSections[I];
|
2015-10-10 03:25:07 +08:00
|
|
|
|
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) {
|
2017-03-21 16:44:25 +08:00
|
|
|
this->Sections[I] = &InputSection::Discarded;
|
2016-09-28 16:42:02 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-08-13 22:45:44 +08:00
|
|
|
switch (Sec.sh_type) {
|
2017-05-29 16:37:50 +08:00
|
|
|
case SHT_GROUP: {
|
2017-06-09 10:42:20 +08:00
|
|
|
// De-duplicate section groups by their signatures.
|
|
|
|
StringRef Signature = getShtGroupSignature(ObjSections, Sec);
|
|
|
|
bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second;
|
|
|
|
this->Sections[I] = &InputSection::Discarded;
|
|
|
|
|
|
|
|
// If it is a new section group, we want to keep group members.
|
|
|
|
// Group leader sections, which contain indices of group members, are
|
|
|
|
// discarded because they are useless beyond this point. The only
|
|
|
|
// exception is the -r option because in order to produce re-linkable
|
|
|
|
// object files, we want to pass through basically everything.
|
|
|
|
if (IsNew) {
|
|
|
|
if (Config->Relocatable)
|
2017-06-13 02:46:33 +08:00
|
|
|
this->Sections[I] = createInputSection(Sec);
|
2015-10-10 03:25:07 +08:00
|
|
|
continue;
|
2017-06-09 10:42:20 +08:00
|
|
|
}
|
2017-05-29 16:37:50 +08:00
|
|
|
|
2017-06-09 10:42:20 +08:00
|
|
|
// Otherwise, discard group members.
|
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)
|
2017-03-21 16:44:25 +08:00
|
|
|
fatal(toString(this) +
|
|
|
|
": invalid section index in group: " + Twine(SecIndex));
|
|
|
|
this->Sections[SecIndex] = &InputSection::Discarded;
|
2015-10-10 03:25:07 +08:00
|
|
|
}
|
|
|
|
break;
|
2017-05-29 16:37:50 +08:00
|
|
|
}
|
2015-08-13 22:45:44 +08:00
|
|
|
case SHT_SYMTAB:
|
2016-11-03 23:43:47 +08:00
|
|
|
this->initSymtab(ObjSections, &Sec);
|
2015-08-13 22:45:44 +08:00
|
|
|
break;
|
2016-03-04 00:21:44 +08:00
|
|
|
case SHT_SYMTAB_SHNDX:
|
2017-03-31 05:13:00 +08:00
|
|
|
this->SymtabSHNDX =
|
2017-04-04 03:11:23 +08:00
|
|
|
check(Obj.getSHNDXTable(Sec, ObjSections), toString(this));
|
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:
|
2017-06-13 02:46:33 +08:00
|
|
|
this->Sections[I] = createInputSection(Sec);
|
2015-07-25 05:03:07 +08:00
|
|
|
}
|
|
|
|
|
2016-11-02 21:36:31 +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.
|
|
|
|
if (Sec.sh_flags & SHF_LINK_ORDER) {
|
2017-03-21 16:57:13 +08:00
|
|
|
if (Sec.sh_link >= this->Sections.size())
|
2016-11-24 02:07:33 +08:00
|
|
|
fatal(toString(this) + ": invalid sh_link index: " +
|
2016-11-02 21:36:31 +08:00
|
|
|
Twine(Sec.sh_link));
|
2017-03-21 16:44:25 +08:00
|
|
|
this->Sections[Sec.sh_link]->DependentSections.push_back(
|
2017-10-11 12:01:13 +08:00
|
|
|
cast<InputSection>(this->Sections[I]));
|
2016-11-02 21:36:31 +08:00
|
|
|
}
|
2016-10-10 18:10:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-14 05:52:57 +08:00
|
|
|
template <class ELFT>
|
2017-07-27 06:13:32 +08:00
|
|
|
InputSectionBase *ObjFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
|
2016-03-14 05:52:57 +08:00
|
|
|
uint32_t Idx = Sec.sh_info;
|
2017-03-21 16:44:25 +08:00
|
|
|
if (Idx >= this->Sections.size())
|
2016-11-24 02:07:33 +08:00
|
|
|
fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx));
|
2017-03-21 16:44:25 +08:00
|
|
|
InputSectionBase *Target = this->Sections[Idx];
|
2016-03-14 05:52:57 +08:00
|
|
|
|
|
|
|
// 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.
|
2017-02-24 00:49:07 +08:00
|
|
|
if (Target == &InputSection::Discarded)
|
2016-03-14 05:52:57 +08:00
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
if (!Target)
|
2016-11-24 02:07:33 +08:00
|
|
|
fatal(toString(this) + ": unsupported relocation reference");
|
2016-03-14 05:52:57 +08:00
|
|
|
return Target;
|
|
|
|
}
|
|
|
|
|
2017-05-02 04:49:09 +08:00
|
|
|
// Create a regular InputSection class that has the same contents
|
|
|
|
// as a given section.
|
|
|
|
InputSectionBase *toRegularSection(MergeInputSection *Sec) {
|
|
|
|
auto *Ret = make<InputSection>(Sec->Flags, Sec->Type, Sec->Alignment,
|
|
|
|
Sec->Data, Sec->Name);
|
|
|
|
Ret->File = Sec->File;
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
2016-02-13 05:17:10 +08:00
|
|
|
template <class ELFT>
|
2017-07-27 06:13:32 +08:00
|
|
|
InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
|
2017-06-13 02:46:33 +08:00
|
|
|
StringRef Name = getSectionName(Sec);
|
2015-12-24 16:41:12 +08:00
|
|
|
|
2016-09-08 22:06:08 +08:00
|
|
|
switch (Sec.sh_type) {
|
|
|
|
case SHT_ARM_ATTRIBUTES:
|
2016-12-14 18:36:12 +08:00
|
|
|
// FIXME: ARM meta-data section. Retain the first attribute section
|
|
|
|
// we see. The eglibc ARM dynamic loaders require the presence of an
|
|
|
|
// attribute section for dlopen to work.
|
|
|
|
// In a full implementation we would merge all attribute sections.
|
2017-05-12 06:02:41 +08:00
|
|
|
if (InX::ARMAttributes == nullptr) {
|
|
|
|
InX::ARMAttributes = make<InputSection>(this, &Sec, Name);
|
|
|
|
return InX::ARMAttributes;
|
2016-12-14 18:36:12 +08:00
|
|
|
}
|
2017-02-24 00:49:07 +08:00
|
|
|
return &InputSection::Discarded;
|
2016-09-08 22:06:08 +08:00
|
|
|
case SHT_RELA:
|
|
|
|
case SHT_REL: {
|
2017-02-15 00:42:38 +08:00
|
|
|
// Find the relocation target section and associate this
|
|
|
|
// section with it. Target can be discarded, for example
|
|
|
|
// if it is a duplicated member of SHT_GROUP section, we
|
|
|
|
// do not create or proccess relocatable sections then.
|
2017-02-23 10:28:28 +08:00
|
|
|
InputSectionBase *Target = getRelocTarget(Sec);
|
2017-02-15 00:42:38 +08:00
|
|
|
if (!Target)
|
|
|
|
return nullptr;
|
|
|
|
|
2016-09-08 22:06:08 +08:00
|
|
|
// 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)
|
2017-02-24 00:49:07 +08:00
|
|
|
return make<InputSection>(this, &Sec, Name);
|
2016-09-08 22:06:08 +08:00
|
|
|
|
2016-11-10 22:53:24 +08:00
|
|
|
if (Target->FirstRelocation)
|
2016-11-24 02:07:33 +08:00
|
|
|
fatal(toString(this) +
|
2016-11-10 22:53:24 +08:00
|
|
|
": multiple relocation sections to one section are not supported");
|
2017-05-02 04:49:09 +08:00
|
|
|
|
|
|
|
// Mergeable sections with relocations are tricky because relocations
|
|
|
|
// need to be taken into account when comparing section contents for
|
2017-05-03 05:16:06 +08:00
|
|
|
// merging. It's not worth supporting such mergeable sections because
|
2017-05-02 10:58:04 +08:00
|
|
|
// they are rare and it'd complicates the internal design (we usually
|
|
|
|
// have to determine if two sections are mergeable early in the link
|
|
|
|
// process much before applying relocations). We simply handle mergeable
|
|
|
|
// sections with relocations as non-mergeable.
|
2017-05-02 04:49:09 +08:00
|
|
|
if (auto *MS = dyn_cast<MergeInputSection>(Target)) {
|
|
|
|
Target = toRegularSection(MS);
|
|
|
|
this->Sections[Sec.sh_info] = Target;
|
2017-04-29 09:24:34 +08:00
|
|
|
}
|
2016-11-10 22:53:24 +08:00
|
|
|
|
|
|
|
size_t NumRelocations;
|
|
|
|
if (Sec.sh_type == SHT_RELA) {
|
2017-03-31 05:13:00 +08:00
|
|
|
ArrayRef<Elf_Rela> Rels =
|
2017-04-04 03:11:23 +08:00
|
|
|
check(this->getObj().relas(&Sec), toString(this));
|
2016-11-10 22:53:24 +08:00
|
|
|
Target->FirstRelocation = Rels.begin();
|
|
|
|
NumRelocations = Rels.size();
|
|
|
|
Target->AreRelocsRela = true;
|
|
|
|
} else {
|
2017-04-04 03:11:23 +08:00
|
|
|
ArrayRef<Elf_Rel> Rels = check(this->getObj().rels(&Sec), toString(this));
|
2016-11-10 22:53:24 +08:00
|
|
|
Target->FirstRelocation = Rels.begin();
|
|
|
|
NumRelocations = Rels.size();
|
|
|
|
Target->AreRelocsRela = false;
|
2016-09-08 22:06:08 +08:00
|
|
|
}
|
2016-11-10 22:53:24 +08:00
|
|
|
assert(isUInt<31>(NumRelocations));
|
|
|
|
Target->NumRelocations = NumRelocations;
|
2017-02-09 00:18:10 +08:00
|
|
|
|
|
|
|
// Relocation sections processed by the linker are usually removed
|
|
|
|
// from the output, so returning `nullptr` for the normal case.
|
|
|
|
// However, if -emit-relocs is given, we need to leave them in the output.
|
|
|
|
// (Some post link analysis tools need this information.)
|
2017-02-18 03:46:47 +08:00
|
|
|
if (Config->EmitRelocs) {
|
2017-02-24 00:49:07 +08:00
|
|
|
InputSection *RelocSec = make<InputSection>(this, &Sec, Name);
|
2017-02-18 03:46:47 +08:00
|
|
|
// We will not emit relocation section if target was discarded.
|
|
|
|
Target->DependentSections.push_back(RelocSec);
|
|
|
|
return RelocSec;
|
|
|
|
}
|
2016-11-10 22:53:24 +08:00
|
|
|
return nullptr;
|
2016-09-08 22:06:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-23 15:06:43 +08:00
|
|
|
// The GNU linker uses .note.GNU-stack section as a marker indicating
|
|
|
|
// that the code in the object file does not expect that the stack is
|
|
|
|
// executable (in terms of NX bit). If all input files have the marker,
|
|
|
|
// the GNU linker adds a PT_GNU_STACK segment to tells the loader to
|
2017-02-23 15:15:46 +08:00
|
|
|
// make the stack non-executable. Most object files have this section as
|
|
|
|
// of 2017.
|
2017-02-23 15:06:43 +08:00
|
|
|
//
|
|
|
|
// But making the stack non-executable is a norm today for security
|
2017-02-23 15:15:46 +08:00
|
|
|
// reasons. Failure to do so may result in a serious security issue.
|
|
|
|
// Therefore, we make LLD always add PT_GNU_STACK unless it is
|
2017-02-23 15:06:43 +08:00
|
|
|
// explicitly told to do otherwise (by -z execstack). Because the stack
|
|
|
|
// executable-ness is controlled solely by command line options,
|
|
|
|
// .note.GNU-stack sections are simply ignored.
|
2015-12-24 16:41:12 +08:00
|
|
|
if (Name == ".note.GNU-stack")
|
2017-02-24 00:49:07 +08:00
|
|
|
return &InputSection::Discarded;
|
2015-12-24 16:41:12 +08:00
|
|
|
|
2017-02-23 15:35:11 +08:00
|
|
|
// Split stacks is a feature to support a discontiguous stack. At least
|
|
|
|
// as of 2017, it seems that the feature is not being used widely.
|
|
|
|
// Only GNU gold supports that. We don't. For the details about that,
|
|
|
|
// see https://gcc.gnu.org/wiki/SplitStacks
|
2016-04-08 05:04:51 +08:00
|
|
|
if (Name == ".note.GNU-split-stack") {
|
2017-02-23 15:35:30 +08:00
|
|
|
error(toString(this) +
|
|
|
|
": object file compiled with -fsplit-stack is not supported");
|
2017-02-24 00:49:07 +08:00
|
|
|
return &InputSection::Discarded;
|
2016-04-08 05:04:51 +08:00
|
|
|
}
|
|
|
|
|
2017-01-10 04:26:33 +08:00
|
|
|
// The linkonce feature is a sort of proto-comdat. Some glibc i386 object
|
|
|
|
// files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce
|
|
|
|
// sections. Drop those sections to avoid duplicate symbol errors.
|
|
|
|
// FIXME: This is glibc PR20543, we should remove this hack once that has been
|
|
|
|
// fixed for a while.
|
|
|
|
if (Name.startswith(".gnu.linkonce."))
|
2017-02-24 00:49:07 +08:00
|
|
|
return &InputSection::Discarded;
|
2017-01-10 04:26:33 +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)
|
2017-03-07 05:17:18 +08:00
|
|
|
return make<EhInputSection>(this, &Sec, Name);
|
2016-07-15 12:57:44 +08:00
|
|
|
|
2016-07-16 04:38:28 +08:00
|
|
|
if (shouldMerge(Sec))
|
2017-03-07 04:23:56 +08:00
|
|
|
return make<MergeInputSection>(this, &Sec, Name);
|
2017-02-24 00:49:07 +08:00
|
|
|
return make<InputSection>(this, &Sec, Name);
|
2015-12-24 16:41:12 +08:00
|
|
|
}
|
|
|
|
|
2017-06-13 02:46:33 +08:00
|
|
|
template <class ELFT>
|
2017-07-27 06:13:32 +08:00
|
|
|
StringRef ObjFile<ELFT>::getSectionName(const Elf_Shdr &Sec) {
|
2017-06-13 02:46:33 +08:00
|
|
|
return check(this->getObj().getSectionName(&Sec, SectionStringTable),
|
|
|
|
toString(this));
|
|
|
|
}
|
|
|
|
|
2017-07-27 06:13:32 +08:00
|
|
|
template <class ELFT> void ObjFile<ELFT>::initializeSymbols() {
|
2017-08-04 19:07:42 +08:00
|
|
|
this->Symbols.reserve(this->ELFSyms.size());
|
2017-08-03 01:35:18 +08:00
|
|
|
for (const Elf_Sym &Sym : this->ELFSyms)
|
2017-11-04 05:21:47 +08:00
|
|
|
this->Symbols.push_back(createSymbol(&Sym));
|
2015-07-25 05:03:07 +08:00
|
|
|
}
|
|
|
|
|
2015-10-16 23:29:48 +08:00
|
|
|
template <class ELFT>
|
2017-10-29 04:15:56 +08:00
|
|
|
InputSectionBase *ObjFile<ELFT>::getSection(uint32_t Index) const {
|
2017-10-28 08:05:12 +08:00
|
|
|
if (Index == 0)
|
|
|
|
return nullptr;
|
2017-03-21 16:44:25 +08:00
|
|
|
if (Index >= this->Sections.size())
|
2016-11-24 02:07:33 +08:00
|
|
|
fatal(toString(this) + ": invalid section index: " + Twine(Index));
|
2016-10-06 17:17:55 +08:00
|
|
|
|
2017-10-30 07:41:16 +08:00
|
|
|
if (InputSectionBase *Sec = this->Sections[Index])
|
|
|
|
return Sec->Repl;
|
|
|
|
return nullptr;
|
2015-10-16 23:29:48 +08:00
|
|
|
}
|
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
template <class ELFT> Symbol *ObjFile<ELFT>::createSymbol(const Elf_Sym *Sym) {
|
2016-07-16 04:38:28 +08:00
|
|
|
int Binding = Sym->getBinding();
|
2017-10-29 04:15:56 +08:00
|
|
|
InputSectionBase *Sec = getSection(this->getSectionIndex(*Sym));
|
2016-11-23 14:59:47 +08:00
|
|
|
|
2016-11-30 02:05:04 +08:00
|
|
|
uint8_t StOther = Sym->st_other;
|
|
|
|
uint8_t Type = Sym->getType();
|
2017-02-25 03:52:52 +08:00
|
|
|
uint64_t Value = Sym->st_value;
|
|
|
|
uint64_t Size = Sym->st_size;
|
2016-11-30 02:05:04 +08:00
|
|
|
|
2016-03-11 22:21:37 +08:00
|
|
|
if (Binding == STB_LOCAL) {
|
2016-10-26 19:07:09 +08:00
|
|
|
if (Sym->getType() == STT_FILE)
|
2017-04-04 03:11:23 +08:00
|
|
|
SourceFile = check(Sym->getName(this->StringTable), toString(this));
|
2016-11-23 12:57:25 +08:00
|
|
|
|
|
|
|
if (this->StringTable.size() <= Sym->st_name)
|
2016-11-24 02:07:33 +08:00
|
|
|
fatal(toString(this) + ": invalid symbol name offset");
|
2016-11-23 12:57:25 +08:00
|
|
|
|
2016-11-30 03:11:39 +08:00
|
|
|
StringRefZ Name = this->StringTable.data() + Sym->st_name;
|
2016-04-04 22:04:16 +08:00
|
|
|
if (Sym->st_shndx == SHN_UNDEF)
|
2017-08-05 06:31:42 +08:00
|
|
|
return make<Undefined>(Name, /*IsLocal=*/true, StOther, Type);
|
2016-11-30 02:05:04 +08:00
|
|
|
|
2017-11-06 12:35:31 +08:00
|
|
|
return make<Defined>(Name, /*IsLocal=*/true, StOther, Type, Value, Size,
|
|
|
|
Sec);
|
2016-03-11 22:21:37 +08:00
|
|
|
}
|
2016-03-11 20:06:30 +08:00
|
|
|
|
2017-04-04 03:11:23 +08:00
|
|
|
StringRef Name = check(Sym->getName(this->StringTable), toString(this));
|
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:
|
2017-11-01 00:07:41 +08:00
|
|
|
return Symtab->addUndefined<ELFT>(Name, /*IsLocal=*/false, Binding, StOther,
|
|
|
|
Type,
|
|
|
|
/*CanOmitFromDynSym=*/false, this);
|
2015-08-29 05:26:51 +08:00
|
|
|
case SHN_COMMON:
|
2016-11-23 14:59:47 +08:00
|
|
|
if (Value == 0 || Value >= UINT32_MAX)
|
2016-11-24 02:07:33 +08:00
|
|
|
fatal(toString(this) + ": common symbol '" + Name +
|
2016-11-23 14:59:47 +08:00
|
|
|
"' has invalid alignment: " + Twine(Value));
|
2017-11-01 00:07:41 +08:00
|
|
|
return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, this);
|
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-11-24 02:07:33 +08:00
|
|
|
fatal(toString(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:
|
2017-02-24 00:49:07 +08:00
|
|
|
if (Sec == &InputSection::Discarded)
|
2017-11-01 00:07:41 +08:00
|
|
|
return Symtab->addUndefined<ELFT>(Name, /*IsLocal=*/false, Binding,
|
|
|
|
StOther, Type,
|
|
|
|
/*CanOmitFromDynSym=*/false, this);
|
|
|
|
return Symtab->addRegular<ELFT>(Name, StOther, Type, Value, Size, Binding,
|
|
|
|
Sec, this);
|
2015-10-10 03:25:07 +08:00
|
|
|
}
|
2015-07-25 05:03:07 +08:00
|
|
|
}
|
|
|
|
|
2017-05-04 05:03:08 +08:00
|
|
|
ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File)
|
|
|
|
: InputFile(ArchiveKind, File->getMemoryBufferRef()),
|
|
|
|
File(std::move(File)) {}
|
2015-09-05 06:28:10 +08:00
|
|
|
|
2017-05-04 05:03:08 +08:00
|
|
|
template <class ELFT> void ArchiveFile::parse() {
|
2017-06-21 23:36:24 +08:00
|
|
|
Symbols.reserve(File->getNumberOfSymbols());
|
2017-05-04 05:03:08 +08:00
|
|
|
for (const Archive::Symbol &Sym : File->symbols())
|
2017-11-01 00:07:41 +08:00
|
|
|
Symbols.push_back(Symtab->addLazyArchive<ELFT>(Sym.getName(), 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 =
|
2017-04-04 03:11:23 +08:00
|
|
|
check(Sym->getMember(), toString(this) +
|
2017-03-31 05:13:00 +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(),
|
2017-04-04 03:11:23 +08:00
|
|
|
toString(this) +
|
2017-03-31 05:13:00 +08:00
|
|
|
": could not get the buffer for the member defining symbol " +
|
2016-05-04 01:30:44 +08:00
|
|
|
Sym->getName());
|
2016-05-02 21:54:10 +08:00
|
|
|
|
2017-01-09 09:42:02 +08:00
|
|
|
if (C.getParent()->isThin() && Tar)
|
2017-04-04 03:11:23 +08:00
|
|
|
Tar->append(relativeToRoot(check(C.getFullName(), toString(this))),
|
2017-03-31 05:13:00 +08:00
|
|
|
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>
|
2017-04-25 05:44:20 +08:00
|
|
|
SharedFile<ELFT>::SharedFile(MemoryBufferRef M, StringRef DefaultSoName)
|
|
|
|
: ELFFileBase<ELFT>(Base::SharedKind, M), SoName(DefaultSoName),
|
|
|
|
AsNeeded(Config->AsNeeded) {}
|
2015-09-08 23:50:05 +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() {
|
2015-10-01 23:47:50 +08:00
|
|
|
const Elf_Shdr *DynamicSec = nullptr;
|
2016-11-04 04:44:50 +08:00
|
|
|
const ELFFile<ELFT> Obj = this->getObj();
|
2017-04-04 03:11:23 +08:00
|
|
|
ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this));
|
2017-04-13 08:23:32 +08:00
|
|
|
|
|
|
|
// Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d.
|
2016-11-03 20:21:00 +08:00
|
|
|
for (const Elf_Shdr &Sec : Sections) {
|
2015-11-03 22:13:40 +08:00
|
|
|
switch (Sec.sh_type) {
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
case SHT_DYNSYM:
|
2016-11-03 23:43:47 +08:00
|
|
|
this->initSymtab(Sections, &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:
|
2017-03-31 05:13:00 +08:00
|
|
|
this->SymtabSHNDX =
|
2017-04-04 03:11:23 +08:00
|
|
|
check(Obj.getSHNDXTable(Sec, Sections), toString(this));
|
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
|
|
|
}
|
|
|
|
|
2017-08-03 01:35:18 +08:00
|
|
|
if (this->VersymSec && this->ELFSyms.empty())
|
2016-11-02 18:16:25 +08:00
|
|
|
error("SHT_GNU_versym should be associated with symbol table");
|
|
|
|
|
2017-04-13 08:23:32 +08:00
|
|
|
// Search for a DT_SONAME tag to initialize this->SoName.
|
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),
|
2017-04-04 03:11:23 +08:00
|
|
|
toString(this));
|
2016-10-07 17:01:04 +08:00
|
|
|
for (const Elf_Dyn &Dyn : Arr) {
|
2015-10-12 23:49:02 +08:00
|
|
|
if (Dyn.d_tag == DT_SONAME) {
|
2017-02-25 03:52:52 +08:00
|
|
|
uint64_t Val = Dyn.getVal();
|
2015-10-12 23:49:02 +08:00
|
|
|
if (Val >= this->StringTable.size())
|
2016-11-24 02:07:33 +08:00
|
|
|
fatal(toString(this) + ": invalid DT_SONAME entry");
|
2017-04-27 07:00:32 +08:00
|
|
|
SoName = 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.
|
2016-11-04 04:44:50 +08:00
|
|
|
const char *Base = this->MB.getBuffer().data();
|
|
|
|
Versym = reinterpret_cast<const Elf_Versym *>(Base + VersymSec->sh_offset) +
|
2016-11-04 00:55:44 +08:00
|
|
|
this->FirstNonLocal;
|
2016-04-28 04:22:31 +08:00
|
|
|
|
|
|
|
// 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.
|
2016-11-04 04:44:50 +08:00
|
|
|
const char *Verdef = Base + VerdefSec->sh_offset;
|
2016-04-28 04:22:31 +08:00
|
|
|
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);
|
|
|
|
|
2017-10-29 04:15:56 +08:00
|
|
|
ArrayRef<Elf_Shdr> Sections =
|
|
|
|
check(this->getObj().sections(), toString(this));
|
|
|
|
|
|
|
|
// Add symbols to the symbol table.
|
2017-08-03 01:35:18 +08:00
|
|
|
Elf_Sym_Range Syms = this->getGlobalELFSyms();
|
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;
|
|
|
|
}
|
2017-01-07 06:30:35 +08:00
|
|
|
bool Hidden = VersymIndex & VERSYM_HIDDEN;
|
|
|
|
VersymIndex = VersymIndex & ~VERSYM_HIDDEN;
|
2016-04-30 01:46:07 +08:00
|
|
|
|
2017-04-04 03:11:23 +08:00
|
|
|
StringRef Name = check(Sym.getName(this->StringTable), toString(this));
|
2016-04-30 00:23:31 +08:00
|
|
|
if (Sym.isUndefined()) {
|
|
|
|
Undefs.push_back(Name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-07 06:30:35 +08:00
|
|
|
// Ignore local symbols.
|
|
|
|
if (Versym && VersymIndex == VER_NDX_LOCAL)
|
|
|
|
continue;
|
2017-10-29 04:16:11 +08:00
|
|
|
const Elf_Verdef *Ver = nullptr;
|
2017-10-06 07:28:29 +08:00
|
|
|
if (VersymIndex != VER_NDX_GLOBAL) {
|
|
|
|
if (VersymIndex >= Verdefs.size()) {
|
|
|
|
error("corrupt input file: version definition index " +
|
|
|
|
Twine(VersymIndex) + " for symbol " + Name +
|
2017-10-06 07:28:34 +08:00
|
|
|
" is out of bounds\n>>> defined in " + toString(this));
|
2017-10-06 07:28:29 +08:00
|
|
|
continue;
|
|
|
|
}
|
2017-10-29 04:16:11 +08:00
|
|
|
Ver = Verdefs[VersymIndex];
|
2017-10-06 07:28:29 +08:00
|
|
|
}
|
2017-01-07 06:30:35 +08:00
|
|
|
|
2017-10-29 04:15:56 +08:00
|
|
|
// We do not usually care about alignments of data in shared object
|
|
|
|
// files because the loader takes care of it. However, if we promote a
|
|
|
|
// DSO symbol to point to .bss due to copy relocation, we need to keep
|
|
|
|
// the original alignment requirements. We infer it here.
|
2017-11-07 08:12:05 +08:00
|
|
|
uint64_t Alignment = 1;
|
2017-10-30 00:49:42 +08:00
|
|
|
if (Sym.st_value)
|
|
|
|
Alignment = 1ULL << countTrailingZeros((uint64_t)Sym.st_value);
|
2017-10-29 04:15:56 +08:00
|
|
|
if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size()) {
|
2017-11-07 08:12:05 +08:00
|
|
|
uint64_t SecAlign = Sections[Sym.st_shndx].sh_addralign;
|
2017-10-29 04:15:56 +08:00
|
|
|
Alignment = std::min(Alignment, SecAlign);
|
|
|
|
}
|
2017-11-07 08:12:05 +08:00
|
|
|
if (Alignment > UINT32_MAX)
|
|
|
|
error(toString(this) + ": alignment too large: " + Name);
|
2017-10-29 04:15:56 +08:00
|
|
|
|
2017-01-07 06:30:35 +08:00
|
|
|
if (!Hidden)
|
2017-10-29 04:16:11 +08:00
|
|
|
Symtab->addShared(Name, this, Sym, Alignment, Ver);
|
2017-01-07 06:30:35 +08:00
|
|
|
|
|
|
|
// Also add the symbol with the versioned name to handle undefined symbols
|
|
|
|
// with explicit versions.
|
2017-10-29 04:16:11 +08:00
|
|
|
if (Ver) {
|
|
|
|
StringRef VerName = this->StringTable.data() + Ver->getAux()->vda_name;
|
2017-04-27 12:01:14 +08:00
|
|
|
Name = Saver.save(Name + "@" + VerName);
|
2017-10-29 04:16:11 +08:00
|
|
|
Symtab->addShared(Name, this, Sym, Alignment, Ver);
|
2017-01-07 06:30:35 +08:00
|
|
|
}
|
2015-09-08 23:50:05 +08:00
|
|
|
}
|
|
|
|
}
|
2015-09-04 04:03:54 +08:00
|
|
|
|
2017-04-14 10:55:06 +08:00
|
|
|
static ELFKind getBitcodeELFKind(const Triple &T) {
|
2016-08-04 04:25:29 +08:00
|
|
|
if (T.isLittleEndian())
|
|
|
|
return T.isArch64Bit() ? ELF64LEKind : ELF32LEKind;
|
|
|
|
return T.isArch64Bit() ? ELF64BEKind : ELF32BEKind;
|
2016-06-29 14:12:39 +08:00
|
|
|
}
|
|
|
|
|
2017-04-14 10:55:06 +08:00
|
|
|
static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) {
|
2016-08-04 04:25:29 +08:00
|
|
|
switch (T.getArch()) {
|
2016-07-07 10:46:30 +08:00
|
|
|
case Triple::aarch64:
|
|
|
|
return EM_AARCH64;
|
|
|
|
case Triple::arm:
|
2017-02-28 11:00:48 +08:00
|
|
|
case Triple::thumb:
|
2016-07-07 10:46:30 +08:00
|
|
|
return EM_ARM;
|
2017-06-15 10:27:50 +08:00
|
|
|
case Triple::avr:
|
|
|
|
return EM_AVR;
|
2016-07-07 10:46:30 +08:00
|
|
|
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:
|
2017-04-14 10:55:06 +08:00
|
|
|
fatal(Path + ": could not infer e_machine from bitcode target triple " +
|
|
|
|
T.str());
|
2016-06-29 14:12:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-14 10:55:06 +08:00
|
|
|
BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName,
|
|
|
|
uint64_t OffsetInArchive)
|
|
|
|
: InputFile(BitcodeKind, MB) {
|
|
|
|
this->ArchiveName = ArchiveName;
|
|
|
|
|
|
|
|
// 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).
|
|
|
|
MemoryBufferRef MBRef(MB.getBuffer(),
|
|
|
|
Saver.save(ArchiveName + MB.getBufferIdentifier() +
|
|
|
|
utostr(OffsetInArchive)));
|
|
|
|
Obj = check(lto::InputFile::create(MBRef), toString(this));
|
|
|
|
|
|
|
|
Triple T(Obj->getTargetTriple());
|
|
|
|
EKind = getBitcodeELFKind(T);
|
|
|
|
EMachine = getBitcodeMachineKind(MB.getBufferIdentifier(), T);
|
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>
|
2017-11-04 05:21:47 +08:00
|
|
|
static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
|
|
|
|
const lto::InputFile::Symbol &ObjSym,
|
|
|
|
BitcodeFile *F) {
|
2016-09-29 08:40:08 +08:00
|
|
|
StringRef NameRef = Saver.save(ObjSym.getName());
|
2017-03-29 06:31:35 +08:00
|
|
|
uint32_t Binding = ObjSym.isWeak() ? 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
|
|
|
|
2017-03-31 12:47:07 +08:00
|
|
|
int C = ObjSym.getComdatIndex();
|
2016-10-25 20:02:31 +08:00
|
|
|
if (C != -1 && !KeptComdats[C])
|
2017-07-27 02:42:48 +08:00
|
|
|
return Symtab->addUndefined<ELFT>(NameRef, /*IsLocal=*/false, Binding,
|
|
|
|
Visibility, Type, CanOmitFromDynSym, F);
|
2016-03-12 02:46:51 +08:00
|
|
|
|
2017-03-29 06:31:35 +08:00
|
|
|
if (ObjSym.isUndefined())
|
2017-07-27 02:42:48 +08:00
|
|
|
return Symtab->addUndefined<ELFT>(NameRef, /*IsLocal=*/false, Binding,
|
|
|
|
Visibility, Type, CanOmitFromDynSym, F);
|
2016-09-29 08:40:08 +08:00
|
|
|
|
2017-03-29 06:31:35 +08:00
|
|
|
if (ObjSym.isCommon())
|
2017-07-27 02:42:48 +08:00
|
|
|
return Symtab->addCommon(NameRef, ObjSym.getCommonSize(),
|
|
|
|
ObjSym.getCommonAlignment(), Binding, Visibility,
|
|
|
|
STT_OBJECT, F);
|
2016-04-23 02:26:33 +08:00
|
|
|
|
2017-07-27 02:42:48 +08:00
|
|
|
return Symtab->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>
|
2017-05-26 05:53:02 +08:00
|
|
|
void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
|
2016-10-25 20:02:31 +08:00
|
|
|
std::vector<bool> KeptComdats;
|
2017-03-31 12:47:07 +08:00
|
|
|
for (StringRef S : Obj->getComdatTable())
|
2017-05-26 05:53:02 +08:00
|
|
|
KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second);
|
2016-10-25 20:02:31 +08:00
|
|
|
|
2016-09-29 08:40:08 +08:00
|
|
|
for (const lto::InputFile::Symbol &ObjSym : Obj->symbols())
|
2017-11-01 00:07:41 +08:00
|
|
|
Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, this));
|
2016-02-13 04:54:57 +08:00
|
|
|
}
|
|
|
|
|
2017-04-27 06:51:51 +08:00
|
|
|
static ELFKind getELFKind(MemoryBufferRef MB) {
|
2016-04-08 08:18:25 +08:00
|
|
|
unsigned char Size;
|
|
|
|
unsigned char Endian;
|
|
|
|
std::tie(Size, Endian) = getElfArchType(MB.getBuffer());
|
2017-04-27 06:51:51 +08:00
|
|
|
|
2016-04-08 08:18:25 +08:00
|
|
|
if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB)
|
2016-11-23 18:07:46 +08:00
|
|
|
fatal(MB.getBufferIdentifier() + ": invalid data encoding");
|
2017-04-27 06:51:51 +08:00
|
|
|
if (Size != ELFCLASS32 && Size != ELFCLASS64)
|
|
|
|
fatal(MB.getBufferIdentifier() + ": invalid file class");
|
2015-10-12 23:31:09 +08:00
|
|
|
|
2016-11-04 04:17:25 +08:00
|
|
|
size_t BufSize = MB.getBuffer().size();
|
|
|
|
if ((Size == ELFCLASS32 && BufSize < sizeof(Elf32_Ehdr)) ||
|
|
|
|
(Size == ELFCLASS64 && BufSize < sizeof(Elf64_Ehdr)))
|
2016-11-23 18:07:46 +08:00
|
|
|
fatal(MB.getBufferIdentifier() + ": file is too short");
|
2016-11-04 04:17:25 +08:00
|
|
|
|
2017-04-27 06:51:51 +08:00
|
|
|
if (Size == ELFCLASS32)
|
|
|
|
return (Endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind;
|
|
|
|
return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind;
|
2015-10-12 23:31:09 +08:00
|
|
|
}
|
|
|
|
|
2016-10-28 01:45:40 +08:00
|
|
|
template <class ELFT> void BinaryFile::parse() {
|
2017-04-27 12:01:36 +08:00
|
|
|
ArrayRef<uint8_t> Data = toArrayRef(MB.getBuffer());
|
2017-02-24 00:49:07 +08:00
|
|
|
auto *Section =
|
|
|
|
make<InputSection>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 8, Data, ".data");
|
2016-10-28 01:45:40 +08:00
|
|
|
Sections.push_back(Section);
|
|
|
|
|
2017-04-27 12:01:36 +08:00
|
|
|
// For each input file foo that is embedded to a result as a binary
|
|
|
|
// blob, we define _binary_foo_{start,end,size} symbols, so that
|
|
|
|
// user programs can access blobs by name. Non-alphanumeric
|
|
|
|
// characters in a filename are replaced with underscore.
|
|
|
|
std::string S = "_binary_" + MB.getBufferIdentifier().str();
|
|
|
|
for (size_t I = 0; I < S.size(); ++I)
|
2017-10-04 16:50:34 +08:00
|
|
|
if (!isAlnum(S[I]))
|
2017-04-27 12:01:36 +08:00
|
|
|
S[I] = '_';
|
|
|
|
|
2017-07-27 05:24:01 +08:00
|
|
|
Symtab->addRegular<ELFT>(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT,
|
|
|
|
0, 0, STB_GLOBAL, Section, nullptr);
|
|
|
|
Symtab->addRegular<ELFT>(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT,
|
|
|
|
Data.size(), 0, STB_GLOBAL, Section, nullptr);
|
|
|
|
Symtab->addRegular<ELFT>(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT,
|
|
|
|
Data.size(), 0, STB_GLOBAL, nullptr, nullptr);
|
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) {
|
2017-04-27 06:51:51 +08:00
|
|
|
if (isBitcode(MB))
|
|
|
|
return make<BitcodeFile>(MB, ArchiveName, OffsetInArchive);
|
|
|
|
|
|
|
|
switch (getELFKind(MB)) {
|
|
|
|
case ELF32LEKind:
|
2017-07-27 06:13:32 +08:00
|
|
|
return make<ObjFile<ELF32LE>>(MB, ArchiveName);
|
2017-04-27 06:51:51 +08:00
|
|
|
case ELF32BEKind:
|
2017-07-27 06:13:32 +08:00
|
|
|
return make<ObjFile<ELF32BE>>(MB, ArchiveName);
|
2017-04-27 06:51:51 +08:00
|
|
|
case ELF64LEKind:
|
2017-07-27 06:13:32 +08:00
|
|
|
return make<ObjFile<ELF64LE>>(MB, ArchiveName);
|
2017-04-27 06:51:51 +08:00
|
|
|
case ELF64BEKind:
|
2017-07-27 06:13:32 +08:00
|
|
|
return make<ObjFile<ELF64BE>>(MB, ArchiveName);
|
2017-04-27 06:51:51 +08:00
|
|
|
default:
|
|
|
|
llvm_unreachable("getELFKind");
|
|
|
|
}
|
2016-01-06 08:09:43 +08:00
|
|
|
}
|
|
|
|
|
2017-04-25 05:44:20 +08:00
|
|
|
InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) {
|
2017-04-27 06:51:51 +08:00
|
|
|
switch (getELFKind(MB)) {
|
|
|
|
case ELF32LEKind:
|
|
|
|
return make<SharedFile<ELF32LE>>(MB, DefaultSoName);
|
|
|
|
case ELF32BEKind:
|
|
|
|
return make<SharedFile<ELF32BE>>(MB, DefaultSoName);
|
|
|
|
case ELF64LEKind:
|
|
|
|
return make<SharedFile<ELF64LE>>(MB, DefaultSoName);
|
|
|
|
case ELF64BEKind:
|
|
|
|
return make<SharedFile<ELF64BE>>(MB, DefaultSoName);
|
|
|
|
default:
|
|
|
|
llvm_unreachable("getELFKind");
|
|
|
|
}
|
2016-01-06 08:09:43 +08:00
|
|
|
}
|
|
|
|
|
2017-07-27 06:13:32 +08:00
|
|
|
MemoryBufferRef LazyObjFile::getBuffer() {
|
2016-06-15 05:56:36 +08:00
|
|
|
if (Seen)
|
|
|
|
return MemoryBufferRef();
|
|
|
|
Seen = true;
|
|
|
|
return MB;
|
|
|
|
}
|
|
|
|
|
2017-07-27 06:13:32 +08:00
|
|
|
InputFile *LazyObjFile::fetch() {
|
2017-05-04 22:54:48 +08:00
|
|
|
MemoryBufferRef MBRef = getBuffer();
|
|
|
|
if (MBRef.getBuffer().empty())
|
|
|
|
return nullptr;
|
2017-05-05 23:17:07 +08:00
|
|
|
return createObjectFile(MBRef, ArchiveName, OffsetInArchive);
|
2017-05-04 22:54:48 +08:00
|
|
|
}
|
|
|
|
|
2017-07-27 06:13:32 +08:00
|
|
|
template <class ELFT> void LazyObjFile::parse() {
|
2017-08-03 01:35:18 +08:00
|
|
|
for (StringRef Sym : getSymbolNames())
|
2017-07-27 02:42:48 +08:00
|
|
|
Symtab->addLazyObject<ELFT>(Sym, *this);
|
2016-04-08 03:24:51 +08:00
|
|
|
}
|
|
|
|
|
2017-07-27 06:13:32 +08:00
|
|
|
template <class ELFT> std::vector<StringRef> LazyObjFile::getElfSymbols() {
|
2016-04-08 03:24:51 +08:00
|
|
|
typedef typename ELFT::Shdr Elf_Shdr;
|
|
|
|
typedef typename ELFT::Sym Elf_Sym;
|
|
|
|
typedef typename ELFT::SymRange Elf_Sym_Range;
|
|
|
|
|
2017-10-11 06:18:16 +08:00
|
|
|
ELFFile<ELFT> Obj = check(ELFFile<ELFT>::create(this->MB.getBuffer()));
|
2017-04-04 03:11:23 +08:00
|
|
|
ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this));
|
2016-11-03 21:24:29 +08:00
|
|
|
for (const Elf_Shdr &Sec : Sections) {
|
2016-04-08 03:24:51 +08:00
|
|
|
if (Sec.sh_type != SHT_SYMTAB)
|
|
|
|
continue;
|
2017-03-31 05:13:00 +08:00
|
|
|
|
2017-04-04 03:11:23 +08:00
|
|
|
Elf_Sym_Range Syms = check(Obj.symbols(&Sec), toString(this));
|
2016-04-08 03:24:51 +08:00
|
|
|
uint32_t FirstNonLocal = Sec.sh_info;
|
2017-03-31 05:13:00 +08:00
|
|
|
StringRef StringTable =
|
2017-04-04 03:11:23 +08:00
|
|
|
check(Obj.getStringTableForSymtab(Sec, Sections), toString(this));
|
2016-04-08 03:24:51 +08:00
|
|
|
std::vector<StringRef> V;
|
2017-03-31 05:13:00 +08:00
|
|
|
|
2016-04-08 03:24:51 +08:00
|
|
|
for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal))
|
2016-04-09 04:49:31 +08:00
|
|
|
if (Sym.st_shndx != SHN_UNDEF)
|
2017-04-04 03:11:23 +08:00
|
|
|
V.push_back(check(Sym.getName(StringTable), toString(this)));
|
2016-04-08 03:24:51 +08:00
|
|
|
return V;
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2017-07-27 06:13:32 +08:00
|
|
|
std::vector<StringRef> LazyObjFile::getBitcodeSymbols() {
|
2017-03-31 05:13:00 +08:00
|
|
|
std::unique_ptr<lto::InputFile> Obj =
|
2017-04-04 03:11:23 +08:00
|
|
|
check(lto::InputFile::create(this->MB), toString(this));
|
2016-09-29 08:58:10 +08:00
|
|
|
std::vector<StringRef> V;
|
|
|
|
for (const lto::InputFile::Symbol &Sym : Obj->symbols())
|
2017-03-29 06:31:35 +08:00
|
|
|
if (!Sym.isUndefined())
|
2016-09-29 08:58:10 +08:00
|
|
|
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.
|
2017-08-03 01:35:18 +08:00
|
|
|
std::vector<StringRef> LazyObjFile::getSymbolNames() {
|
2016-04-08 08:14:55 +08:00
|
|
|
if (isBitcode(this->MB))
|
2016-04-08 03:24:51 +08:00
|
|
|
return getBitcodeSymbols();
|
|
|
|
|
2017-04-27 06:51:51 +08:00
|
|
|
switch (getELFKind(this->MB)) {
|
|
|
|
case ELF32LEKind:
|
|
|
|
return getElfSymbols<ELF32LE>();
|
|
|
|
case ELF32BEKind:
|
2016-04-08 03:24:51 +08:00
|
|
|
return getElfSymbols<ELF32BE>();
|
2017-04-27 06:51:51 +08:00
|
|
|
case ELF64LEKind:
|
2016-04-08 03:24:51 +08:00
|
|
|
return getElfSymbols<ELF64LE>();
|
2017-04-27 06:51:51 +08:00
|
|
|
case ELF64BEKind:
|
|
|
|
return getElfSymbols<ELF64BE>();
|
|
|
|
default:
|
|
|
|
llvm_unreachable("getELFKind");
|
|
|
|
}
|
2016-04-08 03:24: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 void ArchiveFile::parse<ELF32LE>();
|
|
|
|
template void ArchiveFile::parse<ELF32BE>();
|
|
|
|
template void ArchiveFile::parse<ELF64LE>();
|
|
|
|
template void ArchiveFile::parse<ELF64BE>();
|
|
|
|
|
2017-05-26 05:53:02 +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
|
|
|
|
2017-07-27 06:13:32 +08:00
|
|
|
template void LazyObjFile::parse<ELF32LE>();
|
|
|
|
template void LazyObjFile::parse<ELF32BE>();
|
|
|
|
template void LazyObjFile::parse<ELF64LE>();
|
|
|
|
template void LazyObjFile::parse<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
|
|
|
|
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
|
|
|
|
2017-07-27 06:13:32 +08:00
|
|
|
template class elf::ObjFile<ELF32LE>;
|
|
|
|
template class elf::ObjFile<ELF32BE>;
|
|
|
|
template class elf::ObjFile<ELF64LE>;
|
|
|
|
template class elf::ObjFile<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>();
|