Page MenuHomePhabricator

No OneTemporary

File Metadata

Created
Fri, Jan 24, 4:09 PM
Index: lld/trunk/test/ELF/Inputs/relocatable.s
===================================================================
--- lld/trunk/test/ELF/Inputs/relocatable.s (revision 0)
+++ lld/trunk/test/ELF/Inputs/relocatable.s (revision 261838)
@@ -0,0 +1,22 @@
+.text
+.type xx,@object
+.bss
+.globl xx
+.align 4
+xx:
+.long 0
+.size xx, 4
+.type yy,@object
+.globl yy
+.align 4
+yy:
+.long 0
+.size yy, 4
+
+.text
+.globl foo
+.align 16, 0x90
+.type foo,@function
+foo:
+movl $1, xx
+movl $2, yy
Index: lld/trunk/test/ELF/Inputs/relocatable2.s
===================================================================
--- lld/trunk/test/ELF/Inputs/relocatable2.s (revision 0)
+++ lld/trunk/test/ELF/Inputs/relocatable2.s (revision 261838)
@@ -0,0 +1,22 @@
+.text
+.type xxx,@object
+.bss
+.globl xxx
+.align 4
+xxx:
+.long 0
+.size xxx, 4
+.type yyy,@object
+.globl yyy
+.align 4
+yyy:
+.long 0
+.size yyy, 4
+
+.text
+.globl bar
+.align 16, 0x90
+.type bar,@function
+bar:
+movl $8, xxx
+movl $9, yyy
Index: lld/trunk/test/ELF/relocatable.s
===================================================================
--- lld/trunk/test/ELF/relocatable.s (revision 261837)
+++ lld/trunk/test/ELF/relocatable.s (revision 261838)
@@ -1,9 +1,129 @@
# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocatable.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocatable2.s -o %t3.o
+# RUN: ld.lld -r %t1.o %t2.o %t3.o -o %t
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s
+# RUN: llvm-objdump -s -d %t | FileCheck -check-prefix=CHECKTEXT %s
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: not ld.lld -r %t -o %t2 2>&1 | FileCheck %s
+## Test --relocatable alias
+# RUN: ld.lld --relocatable %t1.o %t2.o %t3.o -o %t
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s
+# RUN: llvm-objdump -s -d %t | FileCheck -check-prefix=CHECKTEXT %s
-# CHECK: -r option is not supported. Use 'ar' command instead.
+## Verify that we can use our relocation output as input to produce executable
+# RUN: ld.lld -e main %t -o %texec
+# RUN: llvm-readobj -file-headers %texec | FileCheck -check-prefix=CHECKEXE %s
-.globl _start;
-_start:
+## Attempt to link DSO with -r
+# RUN: ld.lld -shared %t1.o -o %t.so
+# RUN: not ld.lld -r %t.so %t2.o -o %tfail 2>&1 | FileCheck -check-prefix=ERR %s
+# ERR: Attempted static link of dynamic object
+
+## Attempt to use -r and shared together
+# RUN: not ld.lld -r -shared %t2.o -o %tfail 2>&1 | FileCheck -check-prefix=ERR2 %s
+# ERR2: -r and -shared may not be used together
+
+# CHECK: ElfHeader {
+# CHECK-NEXT: Ident {
+# CHECK-NEXT: Magic: (7F 45 4C 46)
+# CHECK-NEXT: Class: 64-bit
+# CHECK-NEXT: DataEncoding: LittleEndian
+# CHECK-NEXT: FileVersion: 1
+# CHECK-NEXT: OS/ABI: SystemV
+# CHECK-NEXT: ABIVersion: 0
+# CHECK-NEXT: Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT: }
+# CHECK-NEXT: Type: Relocatable
+# CHECK-NEXT: Machine: EM_X86_64
+# CHECK-NEXT: Version: 1
+# CHECK-NEXT: Entry: 0x0
+# CHECK-NEXT: ProgramHeaderOffset: 0x0
+# CHECK-NEXT: SectionHeaderOffset: 0x2D8
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: ]
+# CHECK-NEXT: HeaderSize: 64
+# CHECK-NEXT: ProgramHeaderEntrySize: 0
+# CHECK-NEXT: ProgramHeaderCount: 0
+# CHECK-NEXT: SectionHeaderEntrySize: 64
+# CHECK-NEXT: SectionHeaderCount: 7
+# CHECK-NEXT: StringTableSectionIndex: 5
+# CHECK-NEXT: }
+
+# CHECK: Relocations [
+# CHECK-NEXT: Section (3) .rela.text {
+# CHECK-NEXT: 0x3 R_X86_64_32S x 0x0
+# CHECK-NEXT: 0xE R_X86_64_32S y 0x0
+# CHECK-NEXT: 0x23 R_X86_64_32S xx 0x0
+# CHECK-NEXT: 0x2E R_X86_64_32S yy 0x0
+# CHECK-NEXT: 0x43 R_X86_64_32S xxx 0x0
+# CHECK-NEXT: 0x4E R_X86_64_32S yyy 0x0
+# CHECK-NEXT: }
+
+# CHECKTEXT: Disassembly of section .text:
+# CHECKTEXT-NEXT: main:
+# CHECKTEXT-NEXT: 0: c7 04 25 00 00 00 00 05 00 00 00 movl $5, 0
+# CHECKTEXT-NEXT: b: c7 04 25 00 00 00 00 07 00 00 00 movl $7, 0
+# CHECKTEXT: foo:
+# CHECKTEXT-NEXT: 20: c7 04 25 00 00 00 00 01 00 00 00 movl $1, 0
+# CHECKTEXT-NEXT: 2b: c7 04 25 00 00 00 00 02 00 00 00 movl $2, 0
+# CHECKTEXT: bar:
+# CHECKTEXT-NEXT: 40: c7 04 25 00 00 00 00 08 00 00 00 movl $8, 0
+# CHECKTEXT-NEXT: 4b: c7 04 25 00 00 00 00 09 00 00 00 movl $9, 0
+
+# CHECKEXE: Format: ELF64-x86-64
+# CHECKEXE-NEXT: Arch: x86_64
+# CHECKEXE-NEXT: AddressSize: 64bit
+# CHECKEXE-NEXT: LoadName:
+# CHECKEXE-NEXT: ElfHeader {
+# CHECKEXE-NEXT: Ident {
+# CHECKEXE-NEXT: Magic: (7F 45 4C 46)
+# CHECKEXE-NEXT: Class: 64-bit
+# CHECKEXE-NEXT: DataEncoding: LittleEndian
+# CHECKEXE-NEXT: FileVersion: 1
+# CHECKEXE-NEXT: OS/ABI: SystemV (0x0)
+# CHECKEXE-NEXT: ABIVersion: 0
+# CHECKEXE-NEXT: Unused: (00 00 00 00 00 00 00)
+# CHECKEXE-NEXT: }
+# CHECKEXE-NEXT: Type: Executable
+# CHECKEXE-NEXT: Machine: EM_X86_64
+# CHECKEXE-NEXT: Version: 1
+# CHECKEXE-NEXT: Entry: 0x11000
+# CHECKEXE-NEXT: ProgramHeaderOffset: 0x40
+# CHECKEXE-NEXT: SectionHeaderOffset: 0x11E8
+# CHECKEXE-NEXT: Flags [
+# CHECKEXE-NEXT: ]
+# CHECKEXE-NEXT: HeaderSize: 64
+# CHECKEXE-NEXT: ProgramHeaderEntrySize: 56
+# CHECKEXE-NEXT: ProgramHeaderCount: 5
+# CHECKEXE-NEXT: SectionHeaderEntrySize: 64
+# CHECKEXE-NEXT: SectionHeaderCount: 6
+# CHECKEXE-NEXT: StringTableSectionIndex: 4
+# CHECKEXE-NEXT: }
+
+.text
+.type x,@object
+.bss
+.globl x
+.align 4
+x:
+.long 0
+.size x, 4
+.type y,@object
+.globl y
+.align 4
+y:
+.long 0
+.size y, 4
+
+.text
+.globl main
+.align 16, 0x90
+.type main,@function
+main:
+movl $5, x
+movl $7, y
+
+blah:
+goo:
+abs = 42
Index: lld/trunk/test/ELF/strip-all.s
===================================================================
--- lld/trunk/test/ELF/strip-all.s (revision 261837)
+++ lld/trunk/test/ELF/strip-all.s (revision 261838)
@@ -1,25 +1,29 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
# RUN: ld.lld %t.o -o %t1
#RUN: llvm-objdump -section-headers %t1 | FileCheck %s -check-prefix BEFORE
#BEFORE: .symtab
#BEFORE-NEXT: .shstrtab
#BEFORE-NEXT: .strtab
#RUN: ld.lld %t.o --strip-all -o %t1
#RUN: llvm-objdump -section-headers %t1 | FileCheck %s -check-prefix AFTER
#AFTER-NOT: .symtab
#AFTER: .shstrtab
#AFTER-NOT: .strtab
+# Ignore --strip-all if -r is specified
+#RUN: ld.lld %t.o --strip-all -r -o %t1
+#RUN: llvm-objdump -section-headers %t1 | FileCheck %s -check-prefix BEFORE
+
# Test alias -s
#RUN: ld.lld %t.o -s -o %t1
#RUN: llvm-objdump -section-headers %t1 | FileCheck %s -check-prefix AFTER
# exits with return code 42 on linux
.globl _start;
_start:
mov $60, %rax
mov $42, %rdi
syscall
Index: lld/trunk/ELF/OutputSections.cpp
===================================================================
--- lld/trunk/ELF/OutputSections.cpp (revision 261837)
+++ lld/trunk/ELF/OutputSections.cpp (revision 261838)
@@ -1,1650 +1,1672 @@
//===- OutputSections.cpp -------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "OutputSections.h"
#include "Config.h"
#include "SymbolTable.h"
#include "Target.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/MathExtras.h"
#include <map>
using namespace llvm;
using namespace llvm::dwarf;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf2;
template <class ELFT>
OutputSectionBase<ELFT>::OutputSectionBase(StringRef Name, uint32_t Type,
uintX_t Flags)
: Name(Name) {
memset(&Header, 0, sizeof(Elf_Shdr));
Header.sh_type = Type;
Header.sh_flags = Flags;
}
template <class ELFT>
GotPltSection<ELFT>::GotPltSection()
: OutputSectionBase<ELFT>(".got.plt", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) {
this->Header.sh_addralign = sizeof(uintX_t);
}
template <class ELFT> void GotPltSection<ELFT>::addEntry(SymbolBody *Sym) {
Sym->GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size();
Entries.push_back(Sym);
}
template <class ELFT> bool GotPltSection<ELFT>::empty() const {
return Entries.empty();
}
template <class ELFT> void GotPltSection<ELFT>::finalize() {
this->Header.sh_size =
(Target->GotPltHeaderEntriesNum + Entries.size()) * sizeof(uintX_t);
}
template <class ELFT> void GotPltSection<ELFT>::writeTo(uint8_t *Buf) {
Target->writeGotPltHeader(Buf);
Buf += Target->GotPltHeaderEntriesNum * sizeof(uintX_t);
for (const SymbolBody *B : Entries) {
Target->writeGotPlt(Buf, B->getPltVA<ELFT>());
Buf += sizeof(uintX_t);
}
}
template <class ELFT>
GotSection<ELFT>::GotSection()
: OutputSectionBase<ELFT>(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) {
if (Config->EMachine == EM_MIPS)
this->Header.sh_flags |= SHF_MIPS_GPREL;
this->Header.sh_addralign = sizeof(uintX_t);
}
template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody *Sym) {
Sym->GotIndex = Entries.size();
Entries.push_back(Sym);
}
template <class ELFT> void GotSection<ELFT>::addMipsLocalEntry() {
++MipsLocalEntries;
}
template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody *Sym) {
if (Sym->hasGlobalDynIndex())
return false;
Sym->GlobalDynIndex = Target->GotHeaderEntriesNum + Entries.size();
// Global Dynamic TLS entries take two GOT slots.
Entries.push_back(Sym);
Entries.push_back(nullptr);
return true;
}
// Reserves TLS entries for a TLS module ID and a TLS block offset.
// In total it takes two GOT slots.
template <class ELFT> bool GotSection<ELFT>::addTlsIndex() {
if (TlsIndexOff != uint32_t(-1))
return false;
TlsIndexOff = Entries.size() * sizeof(uintX_t);
Entries.push_back(nullptr);
Entries.push_back(nullptr);
return true;
}
template <class ELFT>
typename GotSection<ELFT>::uintX_t
GotSection<ELFT>::getMipsLocalFullAddr(const SymbolBody &B) {
return getMipsLocalEntryAddr(B.getVA<ELFT>());
}
template <class ELFT>
typename GotSection<ELFT>::uintX_t
GotSection<ELFT>::getMipsLocalPageAddr(uintX_t EntryValue) {
// Initialize the entry by the %hi(EntryValue) expression
// but without right-shifting.
return getMipsLocalEntryAddr((EntryValue + 0x8000) & ~0xffff);
}
template <class ELFT>
typename GotSection<ELFT>::uintX_t
GotSection<ELFT>::getMipsLocalEntryAddr(uintX_t EntryValue) {
size_t NewIndex = Target->GotHeaderEntriesNum + MipsLocalGotPos.size();
auto P = MipsLocalGotPos.insert(std::make_pair(EntryValue, NewIndex));
assert(!P.second || MipsLocalGotPos.size() <= MipsLocalEntries);
return this->getVA() + P.first->second * sizeof(uintX_t);
}
template <class ELFT>
typename GotSection<ELFT>::uintX_t
GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t);
}
template <class ELFT>
const SymbolBody *GotSection<ELFT>::getMipsFirstGlobalEntry() const {
return Entries.empty() ? nullptr : Entries.front();
}
template <class ELFT>
unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {
return Target->GotHeaderEntriesNum + MipsLocalEntries;
}
template <class ELFT> void GotSection<ELFT>::finalize() {
this->Header.sh_size =
(Target->GotHeaderEntriesNum + MipsLocalEntries + Entries.size()) *
sizeof(uintX_t);
}
template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
Target->writeGotHeader(Buf);
for (std::pair<uintX_t, size_t> &L : MipsLocalGotPos) {
uint8_t *Entry = Buf + L.second * sizeof(uintX_t);
write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, L.first);
}
Buf += Target->GotHeaderEntriesNum * sizeof(uintX_t);
Buf += MipsLocalEntries * sizeof(uintX_t);
for (const SymbolBody *B : Entries) {
uint8_t *Entry = Buf;
Buf += sizeof(uintX_t);
if (!B)
continue;
// MIPS has special rules to fill up GOT entries.
// See "Global Offset Table" in Chapter 5 in the following document
// for detailed description:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
// As the first approach, we can just store addresses for all symbols.
if (Config->EMachine != EM_MIPS && canBePreempted(B, false))
continue; // The dynamic linker will take care of it.
uintX_t VA = B->getVA<ELFT>();
write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
}
}
template <class ELFT>
PltSection<ELFT>::PltSection()
: OutputSectionBase<ELFT>(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR) {
this->Header.sh_addralign = 16;
}
template <class ELFT> void PltSection<ELFT>::writeTo(uint8_t *Buf) {
size_t Off = 0;
if (Target->UseLazyBinding) {
// At beginning of PLT, we have code to call the dynamic linker
// to resolve dynsyms at runtime. Write such code.
Target->writePltZero(Buf);
Off += Target->PltZeroSize;
}
for (auto &I : Entries) {
const SymbolBody *B = I.first;
unsigned RelOff = I.second;
uint64_t Got =
Target->UseLazyBinding ? B->getGotPltVA<ELFT>() : B->getGotVA<ELFT>();
uint64_t Plt = this->getVA() + Off;
Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff);
Off += Target->PltEntrySize;
}
}
template <class ELFT> void PltSection<ELFT>::addEntry(SymbolBody *Sym) {
Sym->PltIndex = Entries.size();
unsigned RelOff = Target->UseLazyBinding
? Out<ELFT>::RelaPlt->getRelocOffset()
: Out<ELFT>::RelaDyn->getRelocOffset();
Entries.push_back(std::make_pair(Sym, RelOff));
}
template <class ELFT> void PltSection<ELFT>::finalize() {
this->Header.sh_size =
Target->PltZeroSize + Entries.size() * Target->PltEntrySize;
}
template <class ELFT>
RelocationSection<ELFT>::RelocationSection(StringRef Name, bool IsRela)
: OutputSectionBase<ELFT>(Name, IsRela ? SHT_RELA : SHT_REL, SHF_ALLOC),
IsRela(IsRela) {
this->Header.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
this->Header.sh_addralign = sizeof(uintX_t);
}
template <class ELFT>
void RelocationSection<ELFT>::addReloc(const DynamicReloc<ELFT> &Reloc) {
SymbolBody *Sym = Reloc.Sym;
if (!Reloc.UseSymVA && Sym)
Sym->MustBeInDynSym = true;
Relocs.push_back(Reloc);
}
template <class ELFT>
typename ELFFile<ELFT>::uintX_t DynamicReloc<ELFT>::getOffset() const {
switch (OKind) {
case Off_GTlsIndex:
return Out<ELFT>::Got->getGlobalDynAddr(*Sym);
case Off_GTlsOffset:
return Out<ELFT>::Got->getGlobalDynAddr(*Sym) + sizeof(uintX_t);
case Off_LTlsIndex:
return Out<ELFT>::Got->getTlsIndexVA();
case Off_Sec:
return OffsetSec->getOffset(OffsetInSec) + OffsetSec->OutSec->getVA();
case Off_Bss:
return cast<SharedSymbol<ELFT>>(Sym)->OffsetInBss + Out<ELFT>::Bss->getVA();
case Off_Got:
return Sym->getGotVA<ELFT>();
case Off_GotPlt:
return Sym->getGotPltVA<ELFT>();
}
llvm_unreachable("Invalid offset kind");
}
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
for (const DynamicReloc<ELFT> &Rel : Relocs) {
auto *P = reinterpret_cast<Elf_Rel *>(Buf);
Buf += IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
SymbolBody *Sym = Rel.Sym;
if (IsRela) {
uintX_t VA = 0;
if (Rel.UseSymVA)
VA = Sym->getVA<ELFT>();
else if (Rel.TargetSec)
VA = Rel.TargetSec->getOffset(Rel.OffsetInTargetSec) +
Rel.TargetSec->OutSec->getVA();
reinterpret_cast<Elf_Rela *>(P)->r_addend = Rel.Addend + VA;
}
P->r_offset = Rel.getOffset();
uint32_t SymIdx = (!Rel.UseSymVA && Sym) ? Sym->DynsymIndex : 0;
P->setSymbolAndType(SymIdx, Rel.Type, Config->Mips64EL);
}
}
template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
return this->Header.sh_entsize * Relocs.size();
}
template <class ELFT> void RelocationSection<ELFT>::finalize() {
this->Header.sh_link = Static ? Out<ELFT>::SymTab->SectionIndex
: Out<ELFT>::DynSymTab->SectionIndex;
this->Header.sh_size = Relocs.size() * this->Header.sh_entsize;
}
template <class ELFT>
InterpSection<ELFT>::InterpSection()
: OutputSectionBase<ELFT>(".interp", SHT_PROGBITS, SHF_ALLOC) {
this->Header.sh_size = Config->DynamicLinker.size() + 1;
this->Header.sh_addralign = 1;
}
template <class ELFT>
void OutputSectionBase<ELFT>::writeHeaderTo(Elf_Shdr *SHdr) {
*SHdr = Header;
}
template <class ELFT> void InterpSection<ELFT>::writeTo(uint8_t *Buf) {
memcpy(Buf, Config->DynamicLinker.data(), Config->DynamicLinker.size());
}
template <class ELFT>
HashTableSection<ELFT>::HashTableSection()
: OutputSectionBase<ELFT>(".hash", SHT_HASH, SHF_ALLOC) {
this->Header.sh_entsize = sizeof(Elf_Word);
this->Header.sh_addralign = sizeof(Elf_Word);
}
static uint32_t hashSysv(StringRef Name) {
uint32_t H = 0;
for (char C : Name) {
H = (H << 4) + C;
uint32_t G = H & 0xf0000000;
if (G)
H ^= G >> 24;
H &= ~G;
}
return H;
}
template <class ELFT> void HashTableSection<ELFT>::finalize() {
this->Header.sh_link = Out<ELFT>::DynSymTab->SectionIndex;
unsigned NumEntries = 2; // nbucket and nchain.
NumEntries += Out<ELFT>::DynSymTab->getNumSymbols(); // The chain entries.
// Create as many buckets as there are symbols.
// FIXME: This is simplistic. We can try to optimize it, but implementing
// support for SHT_GNU_HASH is probably even more profitable.
NumEntries += Out<ELFT>::DynSymTab->getNumSymbols();
this->Header.sh_size = NumEntries * sizeof(Elf_Word);
}
template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
unsigned NumSymbols = Out<ELFT>::DynSymTab->getNumSymbols();
auto *P = reinterpret_cast<Elf_Word *>(Buf);
*P++ = NumSymbols; // nbucket
*P++ = NumSymbols; // nchain
Elf_Word *Buckets = P;
Elf_Word *Chains = P + NumSymbols;
for (const std::pair<SymbolBody *, unsigned> &P :
Out<ELFT>::DynSymTab->getSymbols()) {
SymbolBody *Body = P.first;
StringRef Name = Body->getName();
unsigned I = Body->DynsymIndex;
uint32_t Hash = hashSysv(Name) % NumSymbols;
Chains[I] = Buckets[Hash];
Buckets[Hash] = I;
}
}
static uint32_t hashGnu(StringRef Name) {
uint32_t H = 5381;
for (uint8_t C : Name)
H = (H << 5) + H + C;
return H;
}
template <class ELFT>
GnuHashTableSection<ELFT>::GnuHashTableSection()
: OutputSectionBase<ELFT>(".gnu.hash", SHT_GNU_HASH, SHF_ALLOC) {
this->Header.sh_entsize = ELFT::Is64Bits ? 0 : 4;
this->Header.sh_addralign = sizeof(uintX_t);
}
template <class ELFT>
unsigned GnuHashTableSection<ELFT>::calcNBuckets(unsigned NumHashed) {
if (!NumHashed)
return 0;
// These values are prime numbers which are not greater than 2^(N-1) + 1.
// In result, for any particular NumHashed we return a prime number
// which is not greater than NumHashed.
static const unsigned Primes[] = {
1, 1, 3, 3, 7, 13, 31, 61, 127, 251,
509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071};
return Primes[std::min<unsigned>(Log2_32_Ceil(NumHashed),
array_lengthof(Primes) - 1)];
}
// Bloom filter estimation: at least 8 bits for each hashed symbol.
// GNU Hash table requirement: it should be a power of 2,
// the minimum value is 1, even for an empty table.
// Expected results for a 32-bit target:
// calcMaskWords(0..4) = 1
// calcMaskWords(5..8) = 2
// calcMaskWords(9..16) = 4
// For a 64-bit target:
// calcMaskWords(0..8) = 1
// calcMaskWords(9..16) = 2
// calcMaskWords(17..32) = 4
template <class ELFT>
unsigned GnuHashTableSection<ELFT>::calcMaskWords(unsigned NumHashed) {
if (!NumHashed)
return 1;
return NextPowerOf2((NumHashed - 1) / sizeof(Elf_Off));
}
template <class ELFT> void GnuHashTableSection<ELFT>::finalize() {
unsigned NumHashed = Symbols.size();
NBuckets = calcNBuckets(NumHashed);
MaskWords = calcMaskWords(NumHashed);
// Second hash shift estimation: just predefined values.
Shift2 = ELFT::Is64Bits ? 6 : 5;
this->Header.sh_link = Out<ELFT>::DynSymTab->SectionIndex;
this->Header.sh_size = sizeof(Elf_Word) * 4 // Header
+ sizeof(Elf_Off) * MaskWords // Bloom Filter
+ sizeof(Elf_Word) * NBuckets // Hash Buckets
+ sizeof(Elf_Word) * NumHashed; // Hash Values
}
template <class ELFT> void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) {
writeHeader(Buf);
if (Symbols.empty())
return;
writeBloomFilter(Buf);
writeHashTable(Buf);
}
template <class ELFT>
void GnuHashTableSection<ELFT>::writeHeader(uint8_t *&Buf) {
auto *P = reinterpret_cast<Elf_Word *>(Buf);
*P++ = NBuckets;
*P++ = Out<ELFT>::DynSymTab->getNumSymbols() - Symbols.size();
*P++ = MaskWords;
*P++ = Shift2;
Buf = reinterpret_cast<uint8_t *>(P);
}
template <class ELFT>
void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *&Buf) {
unsigned C = sizeof(Elf_Off) * 8;
auto *Masks = reinterpret_cast<Elf_Off *>(Buf);
for (const SymbolData &Sym : Symbols) {
size_t Pos = (Sym.Hash / C) & (MaskWords - 1);
uintX_t V = (uintX_t(1) << (Sym.Hash % C)) |
(uintX_t(1) << ((Sym.Hash >> Shift2) % C));
Masks[Pos] |= V;
}
Buf += sizeof(Elf_Off) * MaskWords;
}
template <class ELFT>
void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) {
Elf_Word *Buckets = reinterpret_cast<Elf_Word *>(Buf);
Elf_Word *Values = Buckets + NBuckets;
int PrevBucket = -1;
int I = 0;
for (const SymbolData &Sym : Symbols) {
int Bucket = Sym.Hash % NBuckets;
assert(PrevBucket <= Bucket);
if (Bucket != PrevBucket) {
Buckets[Bucket] = Sym.Body->DynsymIndex;
PrevBucket = Bucket;
if (I > 0)
Values[I - 1] |= 1;
}
Values[I] = Sym.Hash & ~1;
++I;
}
if (I > 0)
Values[I - 1] |= 1;
}
static bool includeInGnuHashTable(SymbolBody *B) {
// Assume that includeInDynsym() is already checked.
return !B->isUndefined();
}
// Add symbols to this symbol hash table. Note that this function
// destructively sort a given vector -- which is needed because
// GNU-style hash table places some sorting requirements.
template <class ELFT>
void GnuHashTableSection<ELFT>::addSymbols(
std::vector<std::pair<SymbolBody *, size_t>> &V) {
auto Mid = std::stable_partition(V.begin(), V.end(),
[](std::pair<SymbolBody *, size_t> &P) {
return !includeInGnuHashTable(P.first);
});
if (Mid == V.end())
return;
for (auto I = Mid, E = V.end(); I != E; ++I) {
SymbolBody *B = I->first;
size_t StrOff = I->second;
Symbols.push_back({B, StrOff, hashGnu(B->getName())});
}
unsigned NBuckets = calcNBuckets(Symbols.size());
std::stable_sort(Symbols.begin(), Symbols.end(),
[&](const SymbolData &L, const SymbolData &R) {
return L.Hash % NBuckets < R.Hash % NBuckets;
});
V.erase(Mid, V.end());
for (const SymbolData &Sym : Symbols)
V.push_back({Sym.Body, Sym.STName});
}
template <class ELFT>
DynamicSection<ELFT>::DynamicSection(SymbolTable<ELFT> &SymTab)
: OutputSectionBase<ELFT>(".dynamic", SHT_DYNAMIC, SHF_ALLOC | SHF_WRITE),
SymTab(SymTab) {
Elf_Shdr &Header = this->Header;
Header.sh_addralign = sizeof(uintX_t);
Header.sh_entsize = ELFT::Is64Bits ? 16 : 8;
// .dynamic section is not writable on MIPS.
// See "Special Section" in Chapter 4 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
if (Config->EMachine == EM_MIPS)
Header.sh_flags = SHF_ALLOC;
}
template <class ELFT> void DynamicSection<ELFT>::finalize() {
if (this->Header.sh_size)
return; // Already finalized.
Elf_Shdr &Header = this->Header;
Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex;
auto Add = [=](Entry E) { Entries.push_back(E); };
// Add strings. We know that these are the last strings to be added to
// DynStrTab and doing this here allows this function to set DT_STRSZ.
if (!Config->RPath.empty())
Add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
Out<ELFT>::DynStrTab->addString(Config->RPath)});
for (const std::unique_ptr<SharedFile<ELFT>> &F : SymTab.getSharedFiles())
if (F->isNeeded())
Add({DT_NEEDED, Out<ELFT>::DynStrTab->addString(F->getSoName())});
if (!Config->SoName.empty())
Add({DT_SONAME, Out<ELFT>::DynStrTab->addString(Config->SoName)});
Out<ELFT>::DynStrTab->finalize();
if (Out<ELFT>::RelaDyn->hasRelocs()) {
bool IsRela = Out<ELFT>::RelaDyn->isRela();
Add({IsRela ? DT_RELA : DT_REL, Out<ELFT>::RelaDyn});
Add({IsRela ? DT_RELASZ : DT_RELSZ, Out<ELFT>::RelaDyn->getSize()});
Add({IsRela ? DT_RELAENT : DT_RELENT,
uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))});
}
if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs()) {
Add({DT_JMPREL, Out<ELFT>::RelaPlt});
Add({DT_PLTRELSZ, Out<ELFT>::RelaPlt->getSize()});
Add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT,
Out<ELFT>::GotPlt});
Add({DT_PLTREL, uint64_t(Out<ELFT>::RelaPlt->isRela() ? DT_RELA : DT_REL)});
}
Add({DT_SYMTAB, Out<ELFT>::DynSymTab});
Add({DT_SYMENT, sizeof(Elf_Sym)});
Add({DT_STRTAB, Out<ELFT>::DynStrTab});
Add({DT_STRSZ, Out<ELFT>::DynStrTab->getSize()});
if (Out<ELFT>::GnuHashTab)
Add({DT_GNU_HASH, Out<ELFT>::GnuHashTab});
if (Out<ELFT>::HashTab)
Add({DT_HASH, Out<ELFT>::HashTab});
if (PreInitArraySec) {
Add({DT_PREINIT_ARRAY, PreInitArraySec});
Add({DT_PREINIT_ARRAYSZ, PreInitArraySec->getSize()});
}
if (InitArraySec) {
Add({DT_INIT_ARRAY, InitArraySec});
Add({DT_INIT_ARRAYSZ, (uintX_t)InitArraySec->getSize()});
}
if (FiniArraySec) {
Add({DT_FINI_ARRAY, FiniArraySec});
Add({DT_FINI_ARRAYSZ, (uintX_t)FiniArraySec->getSize()});
}
if (SymbolBody *B = SymTab.find(Config->Init))
Add({DT_INIT, B});
if (SymbolBody *B = SymTab.find(Config->Fini))
Add({DT_FINI, B});
uint32_t DtFlags = 0;
uint32_t DtFlags1 = 0;
if (Config->Bsymbolic)
DtFlags |= DF_SYMBOLIC;
if (Config->ZNodelete)
DtFlags1 |= DF_1_NODELETE;
if (Config->ZNow) {
DtFlags |= DF_BIND_NOW;
DtFlags1 |= DF_1_NOW;
}
if (Config->ZOrigin) {
DtFlags |= DF_ORIGIN;
DtFlags1 |= DF_1_ORIGIN;
}
if (DtFlags)
Add({DT_FLAGS, DtFlags});
if (DtFlags1)
Add({DT_FLAGS_1, DtFlags1});
if (!Config->Entry.empty())
Add({DT_DEBUG, (uint64_t)0});
if (Config->EMachine == EM_MIPS) {
Add({DT_MIPS_RLD_VERSION, 1});
Add({DT_MIPS_FLAGS, RHF_NOTPOT});
Add({DT_MIPS_BASE_ADDRESS, (uintX_t)Target->getVAStart()});
Add({DT_MIPS_SYMTABNO, Out<ELFT>::DynSymTab->getNumSymbols()});
Add({DT_MIPS_LOCAL_GOTNO, Out<ELFT>::Got->getMipsLocalEntriesNum()});
if (const SymbolBody *B = Out<ELFT>::Got->getMipsFirstGlobalEntry())
Add({DT_MIPS_GOTSYM, B->DynsymIndex});
else
Add({DT_MIPS_GOTSYM, Out<ELFT>::DynSymTab->getNumSymbols()});
Add({DT_PLTGOT, Out<ELFT>::Got});
if (Out<ELFT>::MipsRldMap)
Add({DT_MIPS_RLD_MAP, Out<ELFT>::MipsRldMap});
}
// +1 for DT_NULL
Header.sh_size = (Entries.size() + 1) * Header.sh_entsize;
}
template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
auto *P = reinterpret_cast<Elf_Dyn *>(Buf);
for (const Entry &E : Entries) {
P->d_tag = E.Tag;
switch (E.Kind) {
case Entry::SecAddr:
P->d_un.d_ptr = E.OutSec->getVA();
break;
case Entry::SymAddr:
P->d_un.d_ptr = E.Sym->template getVA<ELFT>();
break;
case Entry::PlainInt:
P->d_un.d_val = E.Val;
break;
}
++P;
}
}
template <class ELFT>
EhFrameHeader<ELFT>::EhFrameHeader()
: OutputSectionBase<ELFT>(".eh_frame_hdr", llvm::ELF::SHT_PROGBITS,
SHF_ALLOC) {
// It's a 4 bytes of header + pointer to the contents of the .eh_frame section
// + the number of FDE pointers in the table.
this->Header.sh_size = 12;
}
// We have to get PC values of FDEs. They depend on relocations
// which are target specific, so we run this code after performing
// all relocations. We read the values from ouput buffer according to the
// encoding given for FDEs. Return value is an offset to the initial PC value
// for the FDE.
template <class ELFT>
typename EhFrameHeader<ELFT>::uintX_t
EhFrameHeader<ELFT>::getFdePc(uintX_t EhVA, const FdeData &F) {
const endianness E = ELFT::TargetEndianness;
assert((F.Enc & 0xF0) != DW_EH_PE_datarel);
uintX_t FdeOff = EhVA + F.Off + 8;
switch (F.Enc & 0xF) {
case DW_EH_PE_udata2:
case DW_EH_PE_sdata2:
return FdeOff + read16<E>(F.PCRel);
case DW_EH_PE_udata4:
case DW_EH_PE_sdata4:
return FdeOff + read32<E>(F.PCRel);
case DW_EH_PE_udata8:
case DW_EH_PE_sdata8:
return FdeOff + read64<E>(F.PCRel);
case DW_EH_PE_absptr:
if (sizeof(uintX_t) == 8)
return FdeOff + read64<E>(F.PCRel);
return FdeOff + read32<E>(F.PCRel);
}
fatal("unknown FDE size encoding");
}
template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
const endianness E = ELFT::TargetEndianness;
const uint8_t Header[] = {1, DW_EH_PE_pcrel | DW_EH_PE_sdata4,
DW_EH_PE_udata4,
DW_EH_PE_datarel | DW_EH_PE_sdata4};
memcpy(Buf, Header, sizeof(Header));
uintX_t EhVA = Sec->getVA();
uintX_t VA = this->getVA();
uintX_t EhOff = EhVA - VA - 4;
write32<E>(Buf + 4, EhOff);
write32<E>(Buf + 8, this->FdeList.size());
Buf += 12;
// InitialPC -> Offset in .eh_frame, sorted by InitialPC.
std::map<uintX_t, size_t> PcToOffset;
for (const FdeData &F : FdeList)
PcToOffset[getFdePc(EhVA, F)] = F.Off;
for (auto &I : PcToOffset) {
// The first four bytes are an offset to the initial PC value for the FDE.
write32<E>(Buf, I.first - VA);
// The last four bytes are an offset to the FDE data itself.
write32<E>(Buf + 4, EhVA + I.second - VA);
Buf += 8;
}
}
template <class ELFT>
void EhFrameHeader<ELFT>::assignEhFrame(EHOutputSection<ELFT> *Sec) {
assert((!this->Sec || this->Sec == Sec) &&
"multiple .eh_frame sections not supported for .eh_frame_hdr");
Live = Config->EhFrameHdr;
this->Sec = Sec;
}
template <class ELFT>
void EhFrameHeader<ELFT>::addFde(uint8_t Enc, size_t Off, uint8_t *PCRel) {
if (Live && (Enc & 0xF0) == DW_EH_PE_datarel)
fatal("DW_EH_PE_datarel encoding unsupported for FDEs by .eh_frame_hdr");
FdeList.push_back(FdeData{Enc, Off, PCRel});
}
template <class ELFT> void EhFrameHeader<ELFT>::reserveFde() {
// Each FDE entry is 8 bytes long:
// The first four bytes are an offset to the initial PC value for the FDE. The
// last four byte are an offset to the FDE data itself.
this->Header.sh_size += 8;
}
template <class ELFT>
-OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type,
- uintX_t Flags)
- : OutputSectionBase<ELFT>(Name, Type, Flags) {}
+OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type, uintX_t Flags)
+ : OutputSectionBase<ELFT>(Name, Type, Flags) {
+ if (Type == SHT_RELA)
+ this->Header.sh_entsize = sizeof(Elf_Rela);
+ else if (Type == SHT_REL)
+ this->Header.sh_entsize = sizeof(Elf_Rel);
+}
+
+template <class ELFT> void OutputSection<ELFT>::finalize() {
+ uint32_t Type = this->Header.sh_type;
+ if (Type != SHT_RELA && Type != SHT_REL)
+ return;
+ this->Header.sh_link = Out<ELFT>::SymTab->SectionIndex;
+ // sh_info for SHT_REL[A] sections should contain the section header index of
+ // the section to which the relocation applies.
+ InputSectionBase<ELFT> *S = Sections[0]->getRelocatedSection();
+ this->Header.sh_info = S->OutSec->SectionIndex;
+}
template <class ELFT>
void OutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
auto *S = cast<InputSection<ELFT>>(C);
Sections.push_back(S);
S->OutSec = this;
this->updateAlign(S->Align);
uintX_t Off = this->Header.sh_size;
Off = alignTo(Off, S->Align);
S->OutSecOff = Off;
Off += S->getSize();
this->Header.sh_size = Off;
}
// If an input string is in the form of "foo.N" where N is a number,
// return N. Otherwise, returns 65536, which is one greater than the
// lowest priority.
static int getPriority(StringRef S) {
size_t Pos = S.rfind('.');
if (Pos == StringRef::npos)
return 65536;
int V;
if (S.substr(Pos + 1).getAsInteger(10, V))
return 65536;
return V;
}
// This function is called after we sort input sections
// to update their offsets.
template <class ELFT> void OutputSection<ELFT>::reassignOffsets() {
uintX_t Off = 0;
for (InputSection<ELFT> *S : Sections) {
Off = alignTo(Off, S->Align);
S->OutSecOff = Off;
Off += S->getSize();
}
this->Header.sh_size = Off;
}
// Sorts input sections by section name suffixes, so that .foo.N comes
// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections.
// We want to keep the original order if the priorities are the same
// because the compiler keeps the original initialization order in a
// translation unit and we need to respect that.
// For more detail, read the section of the GCC's manual about init_priority.
template <class ELFT> void OutputSection<ELFT>::sortInitFini() {
// Sort sections by priority.
typedef std::pair<int, InputSection<ELFT> *> Pair;
auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
std::vector<Pair> V;
for (InputSection<ELFT> *S : Sections)
V.push_back({getPriority(S->getSectionName()), S});
std::stable_sort(V.begin(), V.end(), Comp);
Sections.clear();
for (Pair &P : V)
Sections.push_back(P.second);
reassignOffsets();
}
// Returns true if S matches /Filename.?\.o$/.
static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
if (!S.endswith(".o"))
return false;
S = S.drop_back(2);
if (S.endswith(Filename))
return true;
return !S.empty() && S.drop_back().endswith(Filename);
}
static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); }
static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
// .ctors and .dtors are sorted by this priority from highest to lowest.
//
// 1. The section was contained in crtbegin (crtbegin contains
// some sentinel value in its .ctors and .dtors so that the runtime
// can find the beginning of the sections.)
//
// 2. The section has an optional priority value in the form of ".ctors.N"
// or ".dtors.N" where N is a number. Unlike .{init,fini}_array,
// they are compared as string rather than number.
//
// 3. The section is just ".ctors" or ".dtors".
//
// 4. The section was contained in crtend, which contains an end marker.
//
// In an ideal world, we don't need this function because .init_array and
// .ctors are duplicate features (and .init_array is newer.) However, there
// are too many real-world use cases of .ctors, so we had no choice to
// support that with this rather ad-hoc semantics.
template <class ELFT>
static bool compCtors(const InputSection<ELFT> *A,
const InputSection<ELFT> *B) {
bool BeginA = isCrtbegin(A->getFile()->getName());
bool BeginB = isCrtbegin(B->getFile()->getName());
if (BeginA != BeginB)
return BeginA;
bool EndA = isCrtend(A->getFile()->getName());
bool EndB = isCrtend(B->getFile()->getName());
if (EndA != EndB)
return EndB;
StringRef X = A->getSectionName();
StringRef Y = B->getSectionName();
assert(X.startswith(".ctors") || X.startswith(".dtors"));
assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
X = X.substr(6);
Y = Y.substr(6);
if (X.empty() && Y.empty())
return false;
return X < Y;
}
// Sorts input sections by the special rules for .ctors and .dtors.
// Unfortunately, the rules are different from the one for .{init,fini}_array.
// Read the comment above.
template <class ELFT> void OutputSection<ELFT>::sortCtorsDtors() {
std::stable_sort(Sections.begin(), Sections.end(), compCtors<ELFT>);
reassignOffsets();
}
// Returns a VA which a relocatin RI refers to. Used only for local symbols.
// For non-local symbols, use SymbolBody::getVA instead.
template <class ELFT, bool IsRela>
typename ELFFile<ELFT>::uintX_t
elf2::getLocalRelTarget(const ObjectFile<ELFT> &File,
const Elf_Rel_Impl<ELFT, IsRela> &RI,
typename ELFFile<ELFT>::uintX_t Addend) {
typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
// PPC64 has a special relocation representing the TOC base pointer
// that does not have a corresponding symbol.
if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC)
return getPPC64TocBase() + Addend;
const Elf_Sym *Sym =
File.getObj().getRelocationSymbol(&RI, File.getSymbolTable());
if (!Sym)
fatal("Unsupported relocation without symbol");
InputSectionBase<ELFT> *Section = File.getSection(*Sym);
if (Sym->getType() == STT_TLS)
return (Section->OutSec->getVA() + Section->getOffset(*Sym) + Addend) -
Out<ELFT>::TlsPhdr->p_vaddr;
// According to the ELF spec reference to a local symbol from outside
// the group are not allowed. Unfortunately .eh_frame breaks that rule
// and must be treated specially. For now we just replace the symbol with
// 0.
if (Section == InputSection<ELFT>::Discarded || !Section->Live)
return Addend;
uintX_t Offset = Sym->st_value;
if (Sym->getType() == STT_SECTION) {
Offset += Addend;
Addend = 0;
}
return Section->OutSec->getVA() + Section->getOffset(Offset) + Addend;
}
// Returns true if a symbol can be replaced at load-time by a symbol
// with the same name defined in other ELF executable or DSO.
bool elf2::canBePreempted(const SymbolBody *Body, bool NeedsGot) {
if (!Body)
return false; // Body is a local symbol.
if (Body->isShared())
return true;
if (Body->isUndefined()) {
if (!Body->isWeak())
return true;
// This is an horrible corner case. Ideally we would like to say that any
// undefined symbol can be preempted so that the dynamic linker has a
// chance of finding it at runtime.
//
// The problem is that the code sequence used to test for weak undef
// functions looks like
// if (func) func()
// If the code is -fPIC the first reference is a load from the got and
// everything works.
// If the code is not -fPIC there is no reasonable way to solve it:
// * A relocation writing to the text segment will fail (it is ro).
// * A copy relocation doesn't work for functions.
// * The trick of using a plt entry as the address would fail here since
// the plt entry would have a non zero address.
// Since we cannot do anything better, we just resolve the symbol to 0 and
// don't produce a dynamic relocation.
//
// As an extra hack, assume that if we are producing a shared library the
// user knows what he or she is doing and can handle a dynamic relocation.
return Config->Shared || NeedsGot;
}
if (!Config->Shared)
return false;
if (Body->getVisibility() != STV_DEFAULT)
return false;
if (Config->Bsymbolic || (Config->BsymbolicFunctions && Body->isFunc()))
return false;
return true;
}
template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
for (InputSection<ELFT> *C : Sections)
C->writeTo(Buf);
}
template <class ELFT>
EHOutputSection<ELFT>::EHOutputSection(StringRef Name, uint32_t Type,
uintX_t Flags)
: OutputSectionBase<ELFT>(Name, Type, Flags) {
Out<ELFT>::EhFrameHdr->assignEhFrame(this);
}
template <class ELFT>
EHRegion<ELFT>::EHRegion(EHInputSection<ELFT> *S, unsigned Index)
: S(S), Index(Index) {}
template <class ELFT> StringRef EHRegion<ELFT>::data() const {
ArrayRef<uint8_t> SecData = S->getSectionData();
ArrayRef<std::pair<uintX_t, uintX_t>> Offsets = S->Offsets;
size_t Start = Offsets[Index].first;
size_t End =
Index == Offsets.size() - 1 ? SecData.size() : Offsets[Index + 1].first;
return StringRef((const char *)SecData.data() + Start, End - Start);
}
template <class ELFT>
Cie<ELFT>::Cie(EHInputSection<ELFT> *S, unsigned Index)
: EHRegion<ELFT>(S, Index) {}
// Read a byte and advance D by one byte.
static uint8_t readByte(ArrayRef<uint8_t> &D) {
if (D.empty())
fatal("corrupted or unsupported CIE information");
uint8_t B = D.front();
D = D.slice(1);
return B;
}
static void skipLeb128(ArrayRef<uint8_t> &D) {
while (!D.empty()) {
uint8_t Val = D.front();
D = D.slice(1);
if ((Val & 0x80) == 0)
return;
}
fatal("corrupted or unsupported CIE information");
}
template <class ELFT> static size_t getAugPSize(unsigned Enc) {
switch (Enc & 0x0f) {
case DW_EH_PE_absptr:
case DW_EH_PE_signed:
return ELFT::Is64Bits ? 8 : 4;
case DW_EH_PE_udata2:
case DW_EH_PE_sdata2:
return 2;
case DW_EH_PE_udata4:
case DW_EH_PE_sdata4:
return 4;
case DW_EH_PE_udata8:
case DW_EH_PE_sdata8:
return 8;
}
fatal("unknown FDE encoding");
}
template <class ELFT> static void skipAugP(ArrayRef<uint8_t> &D) {
uint8_t Enc = readByte(D);
if ((Enc & 0xf0) == DW_EH_PE_aligned)
fatal("DW_EH_PE_aligned encoding is not supported");
size_t Size = getAugPSize<ELFT>(Enc);
if (Size >= D.size())
fatal("corrupted CIE");
D = D.slice(Size);
}
template <class ELFT>
uint8_t EHOutputSection<ELFT>::getFdeEncoding(ArrayRef<uint8_t> D) {
if (D.size() < 8)
fatal("CIE too small");
D = D.slice(8);
uint8_t Version = readByte(D);
if (Version != 1 && Version != 3)
fatal("FDE version 1 or 3 expected, but got " + Twine((unsigned)Version));
const unsigned char *AugEnd = std::find(D.begin() + 1, D.end(), '\0');
if (AugEnd == D.end())
fatal("corrupted CIE");
StringRef Aug(reinterpret_cast<const char *>(D.begin()), AugEnd - D.begin());
D = D.slice(Aug.size() + 1);
// Code alignment factor should always be 1 for .eh_frame.
if (readByte(D) != 1)
fatal("CIE code alignment must be 1");
// Skip data alignment factor.
skipLeb128(D);
// Skip the return address register. In CIE version 1 this is a single
// byte. In CIE version 3 this is an unsigned LEB128.
if (Version == 1)
readByte(D);
else
skipLeb128(D);
// We only care about an 'R' value, but other records may precede an 'R'
// record. Records are not in TLV (type-length-value) format, so we need
// to teach the linker how to skip records for each type.
for (char C : Aug) {
if (C == 'R')
return readByte(D);
if (C == 'z') {
skipLeb128(D);
continue;
}
if (C == 'P') {
skipAugP<ELFT>(D);
continue;
}
if (C == 'L')
continue;
fatal("unknown .eh_frame augmentation string: " + Aug);
}
return DW_EH_PE_absptr;
}
template <class ELFT>
static typename ELFFile<ELFT>::uintX_t readEntryLength(ArrayRef<uint8_t> D) {
const endianness E = ELFT::TargetEndianness;
if (D.size() < 4)
fatal("CIE/FDE too small");
// First 4 bytes of CIE/FDE is the size of the record.
// If it is 0xFFFFFFFF, the next 8 bytes contain the size instead.
uint64_t V = read32<E>(D.data());
if (V < UINT32_MAX) {
uint64_t Len = V + 4;
if (Len > D.size())
fatal("CIE/FIE ends past the end of the section");
return Len;
}
if (D.size() < 12)
fatal("CIE/FDE too small");
V = read64<E>(D.data() + 4);
uint64_t Len = V + 12;
if (Len < V || D.size() < Len)
fatal("CIE/FIE ends past the end of the section");
return Len;
}
template <class ELFT>
template <bool IsRela>
void EHOutputSection<ELFT>::addSectionAux(
EHInputSection<ELFT> *S,
iterator_range<const Elf_Rel_Impl<ELFT, IsRela> *> Rels) {
const endianness E = ELFT::TargetEndianness;
S->OutSec = this;
this->updateAlign(S->Align);
Sections.push_back(S);
ArrayRef<uint8_t> SecData = S->getSectionData();
ArrayRef<uint8_t> D = SecData;
uintX_t Offset = 0;
auto RelI = Rels.begin();
auto RelE = Rels.end();
DenseMap<unsigned, unsigned> OffsetToIndex;
while (!D.empty()) {
unsigned Index = S->Offsets.size();
S->Offsets.push_back(std::make_pair(Offset, -1));
uintX_t Length = readEntryLength<ELFT>(D);
// If CIE/FDE data length is zero then Length is 4, this
// shall be considered a terminator and processing shall end.
if (Length == 4)
break;
StringRef Entry((const char *)D.data(), Length);
while (RelI != RelE && RelI->r_offset < Offset)
++RelI;
uintX_t NextOffset = Offset + Length;
bool HasReloc = RelI != RelE && RelI->r_offset < NextOffset;
uint32_t ID = read32<E>(D.data() + 4);
if (ID == 0) {
// CIE
Cie<ELFT> C(S, Index);
if (Config->EhFrameHdr)
C.FdeEncoding = getFdeEncoding(D);
SymbolBody *Personality = nullptr;
if (HasReloc) {
uint32_t SymIndex = RelI->getSymbol(Config->Mips64EL);
Personality = S->getFile()->getSymbolBody(SymIndex)->repl();
}
std::pair<StringRef, SymbolBody *> CieInfo(Entry, Personality);
auto P = CieMap.insert(std::make_pair(CieInfo, Cies.size()));
if (P.second) {
Cies.push_back(C);
this->Header.sh_size += alignTo(Length, sizeof(uintX_t));
}
OffsetToIndex[Offset] = P.first->second;
} else {
if (!HasReloc)
fatal("FDE doesn't reference another section");
InputSectionBase<ELFT> *Target = S->getRelocTarget(*RelI);
if (Target != InputSection<ELFT>::Discarded && Target->Live) {
uint32_t CieOffset = Offset + 4 - ID;
auto I = OffsetToIndex.find(CieOffset);
if (I == OffsetToIndex.end())
fatal("Invalid CIE reference");
Cies[I->second].Fdes.push_back(EHRegion<ELFT>(S, Index));
Out<ELFT>::EhFrameHdr->reserveFde();
this->Header.sh_size += alignTo(Length, sizeof(uintX_t));
}
}
Offset = NextOffset;
D = D.slice(Length);
}
}
template <class ELFT>
void EHOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
auto *S = cast<EHInputSection<ELFT>>(C);
const Elf_Shdr *RelSec = S->RelocSection;
if (!RelSec) {
addSectionAux(S, make_range<const Elf_Rela *>(nullptr, nullptr));
return;
}
ELFFile<ELFT> &Obj = S->getFile()->getObj();
if (RelSec->sh_type == SHT_RELA)
addSectionAux(S, Obj.relas(RelSec));
else
addSectionAux(S, Obj.rels(RelSec));
}
template <class ELFT>
static typename ELFFile<ELFT>::uintX_t writeAlignedCieOrFde(StringRef Data,
uint8_t *Buf) {
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
const endianness E = ELFT::TargetEndianness;
uint64_t Len = alignTo(Data.size(), sizeof(uintX_t));
write32<E>(Buf, Len - 4);
memcpy(Buf + 4, Data.data() + 4, Data.size() - 4);
return Len;
}
template <class ELFT> void EHOutputSection<ELFT>::writeTo(uint8_t *Buf) {
const endianness E = ELFT::TargetEndianness;
size_t Offset = 0;
for (const Cie<ELFT> &C : Cies) {
size_t CieOffset = Offset;
uintX_t CIELen = writeAlignedCieOrFde<ELFT>(C.data(), Buf + Offset);
C.S->Offsets[C.Index].second = Offset;
Offset += CIELen;
for (const EHRegion<ELFT> &F : C.Fdes) {
uintX_t Len = writeAlignedCieOrFde<ELFT>(F.data(), Buf + Offset);
write32<E>(Buf + Offset + 4, Offset + 4 - CieOffset); // Pointer
F.S->Offsets[F.Index].second = Offset;
Out<ELFT>::EhFrameHdr->addFde(C.FdeEncoding, Offset, Buf + Offset + 8);
Offset += Len;
}
}
for (EHInputSection<ELFT> *S : Sections) {
const Elf_Shdr *RelSec = S->RelocSection;
if (!RelSec)
continue;
ELFFile<ELFT> &EObj = S->getFile()->getObj();
if (RelSec->sh_type == SHT_RELA)
S->relocate(Buf, nullptr, EObj.relas(RelSec));
else
S->relocate(Buf, nullptr, EObj.rels(RelSec));
}
}
template <class ELFT>
MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t Type,
uintX_t Flags, uintX_t Alignment)
: OutputSectionBase<ELFT>(Name, Type, Flags),
Builder(llvm::StringTableBuilder::RAW, Alignment) {}
template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
if (shouldTailMerge()) {
StringRef Data = Builder.data();
memcpy(Buf, Data.data(), Data.size());
return;
}
for (const std::pair<StringRef, size_t> &P : Builder.getMap()) {
StringRef Data = P.first;
memcpy(Buf + P.second, Data.data(), Data.size());
}
}
static size_t findNull(StringRef S, size_t EntSize) {
// Optimize the common case.
if (EntSize == 1)
return S.find(0);
for (unsigned I = 0, N = S.size(); I != N; I += EntSize) {
const char *B = S.begin() + I;
if (std::all_of(B, B + EntSize, [](char C) { return C == 0; }))
return I;
}
return StringRef::npos;
}
template <class ELFT>
void MergeOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
auto *S = cast<MergeInputSection<ELFT>>(C);
S->OutSec = this;
this->updateAlign(S->Align);
ArrayRef<uint8_t> D = S->getSectionData();
StringRef Data((const char *)D.data(), D.size());
uintX_t EntSize = S->getSectionHdr()->sh_entsize;
// If this is of type string, the contents are null-terminated strings.
if (this->Header.sh_flags & SHF_STRINGS) {
uintX_t Offset = 0;
while (!Data.empty()) {
size_t End = findNull(Data, EntSize);
if (End == StringRef::npos)
fatal("String is not null terminated");
StringRef Entry = Data.substr(0, End + EntSize);
uintX_t OutputOffset = Builder.add(Entry);
if (shouldTailMerge())
OutputOffset = -1;
S->Offsets.push_back(std::make_pair(Offset, OutputOffset));
uintX_t Size = End + EntSize;
Data = Data.substr(Size);
Offset += Size;
}
return;
}
// If this is not of type string, every entry has the same size.
for (unsigned I = 0, N = Data.size(); I != N; I += EntSize) {
StringRef Entry = Data.substr(I, EntSize);
size_t OutputOffset = Builder.add(Entry);
S->Offsets.push_back(std::make_pair(I, OutputOffset));
}
}
template <class ELFT>
unsigned MergeOutputSection<ELFT>::getOffset(StringRef Val) {
return Builder.getOffset(Val);
}
template <class ELFT> bool MergeOutputSection<ELFT>::shouldTailMerge() const {
return Config->Optimize >= 2 && this->Header.sh_flags & SHF_STRINGS;
}
template <class ELFT> void MergeOutputSection<ELFT>::finalize() {
if (shouldTailMerge())
Builder.finalize();
this->Header.sh_size = Builder.getSize();
}
template <class ELFT>
StringTableSection<ELFT>::StringTableSection(StringRef Name, bool Dynamic)
: OutputSectionBase<ELFT>(Name, SHT_STRTAB,
Dynamic ? (uintX_t)SHF_ALLOC : 0),
Dynamic(Dynamic) {
this->Header.sh_addralign = 1;
}
// Adds a string to the string table. If HashIt is true we hash and check for
// duplicates. It is optional because the name of global symbols are already
// uniqued and hashing them again has a big cost for a small value: uniquing
// them with some other string that happens to be the same.
template <class ELFT>
unsigned StringTableSection<ELFT>::addString(StringRef S, bool HashIt) {
if (HashIt) {
auto R = StringMap.insert(std::make_pair(S, Size));
if (!R.second)
return R.first->second;
}
unsigned Ret = Size;
Size += S.size() + 1;
Strings.push_back(S);
return Ret;
}
template <class ELFT> void StringTableSection<ELFT>::writeTo(uint8_t *Buf) {
// ELF string tables start with NUL byte, so advance the pointer by one.
++Buf;
for (StringRef S : Strings) {
memcpy(Buf, S.data(), S.size());
Buf += S.size() + 1;
}
}
template <class ELFT>
SymbolTableSection<ELFT>::SymbolTableSection(
SymbolTable<ELFT> &Table, StringTableSection<ELFT> &StrTabSec)
: OutputSectionBase<ELFT>(StrTabSec.isDynamic() ? ".dynsym" : ".symtab",
StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
StrTabSec.isDynamic() ? (uintX_t)SHF_ALLOC : 0),
StrTabSec(StrTabSec), Table(Table) {
this->Header.sh_entsize = sizeof(Elf_Sym);
this->Header.sh_addralign = sizeof(uintX_t);
}
// Orders symbols according to their positions in the GOT,
// in compliance with MIPS ABI rules.
// See "Global Offset Table" in Chapter 5 in the following document
// for detailed description:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
static bool sortMipsSymbols(const std::pair<SymbolBody *, unsigned> &L,
const std::pair<SymbolBody *, unsigned> &R) {
if (!L.first->isInGot() || !R.first->isInGot())
return R.first->isInGot();
return L.first->GotIndex < R.first->GotIndex;
}
template <class ELFT> void SymbolTableSection<ELFT>::finalize() {
if (this->Header.sh_size)
return; // Already finalized.
this->Header.sh_size = getNumSymbols() * sizeof(Elf_Sym);
this->Header.sh_link = StrTabSec.SectionIndex;
this->Header.sh_info = NumLocals + 1;
+ if (Config->Relocatable) {
+ size_t I = NumLocals;
+ for (const std::pair<SymbolBody *, size_t> &P : Symbols)
+ P.first->DynsymIndex = ++I;
+ return;
+ }
+
if (!StrTabSec.isDynamic()) {
std::stable_sort(Symbols.begin(), Symbols.end(),
[](const std::pair<SymbolBody *, unsigned> &L,
const std::pair<SymbolBody *, unsigned> &R) {
return getSymbolBinding(L.first) == STB_LOCAL &&
getSymbolBinding(R.first) != STB_LOCAL;
});
return;
}
if (Out<ELFT>::GnuHashTab)
// NB: It also sorts Symbols to meet the GNU hash table requirements.
Out<ELFT>::GnuHashTab->addSymbols(Symbols);
else if (Config->EMachine == EM_MIPS)
std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
size_t I = 0;
for (const std::pair<SymbolBody *, size_t> &P : Symbols)
P.first->DynsymIndex = ++I;
}
template <class ELFT>
void SymbolTableSection<ELFT>::addSymbol(SymbolBody *B) {
Symbols.push_back({B, StrTabSec.addString(B->getName(), false)});
}
template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
Buf += sizeof(Elf_Sym);
// All symbols with STB_LOCAL binding precede the weak and global symbols.
// .dynsym only contains global symbols.
if (!Config->DiscardAll && !StrTabSec.isDynamic())
writeLocalSymbols(Buf);
writeGlobalSymbols(Buf);
}
template <class ELFT>
void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
// Iterate over all input object files to copy their local symbols
// to the output symbol table pointed by Buf.
for (const std::unique_ptr<ObjectFile<ELFT>> &File : Table.getObjectFiles()) {
for (const std::pair<const Elf_Sym *, size_t> &P : File->KeptLocalSyms) {
const Elf_Sym *Sym = P.first;
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
uintX_t VA = 0;
if (Sym->st_shndx == SHN_ABS) {
ESym->st_shndx = SHN_ABS;
VA = Sym->st_value;
} else {
InputSectionBase<ELFT> *Section = File->getSection(*Sym);
const OutputSectionBase<ELFT> *OutSec = Section->OutSec;
ESym->st_shndx = OutSec->SectionIndex;
VA = Section->getOffset(*Sym);
// Symbol offsets for AMDGPU need to be the offset in bytes of the
// symbol from the beginning of the section.
if (Config->EMachine != EM_AMDGPU)
VA += OutSec->getVA();
}
ESym->st_name = P.second;
ESym->st_size = Sym->st_size;
ESym->setBindingAndType(Sym->getBinding(), Sym->getType());
ESym->st_value = VA;
Buf += sizeof(*ESym);
}
}
}
template <class ELFT>
static const typename llvm::object::ELFFile<ELFT>::Elf_Sym *
getElfSym(SymbolBody &Body) {
if (auto *EBody = dyn_cast<DefinedElf<ELFT>>(&Body))
return &EBody->Sym;
if (auto *EBody = dyn_cast<UndefinedElf<ELFT>>(&Body))
return &EBody->Sym;
return nullptr;
}
template <class ELFT>
void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
// Write the internal symbol table contents to the output symbol table
// pointed by Buf.
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
for (const std::pair<SymbolBody *, size_t> &P : Symbols) {
SymbolBody *Body = P.first;
size_t StrOff = P.second;
unsigned char Type = STT_NOTYPE;
uintX_t Size = 0;
if (const Elf_Sym *InputSym = getElfSym<ELFT>(*Body)) {
Type = InputSym->getType();
Size = InputSym->st_size;
} else if (auto *C = dyn_cast<DefinedCommon>(Body)) {
Type = STT_OBJECT;
Size = C->Size;
}
ESym->setBindingAndType(getSymbolBinding(Body), Type);
ESym->st_size = Size;
ESym->st_name = StrOff;
ESym->setVisibility(Body->getVisibility());
ESym->st_value = Body->getVA<ELFT>();
if (const OutputSectionBase<ELFT> *OutSec = getOutputSection(Body))
ESym->st_shndx = OutSec->SectionIndex;
else if (isa<DefinedRegular<ELFT>>(Body))
ESym->st_shndx = SHN_ABS;
++ESym;
}
}
template <class ELFT>
const OutputSectionBase<ELFT> *
SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) {
switch (Sym->kind()) {
case SymbolBody::DefinedSyntheticKind:
return &cast<DefinedSynthetic<ELFT>>(Sym)->Section;
case SymbolBody::DefinedRegularKind: {
auto *D = cast<DefinedRegular<ELFT>>(Sym->repl());
if (D->Section)
return D->Section->OutSec;
break;
}
case SymbolBody::DefinedCommonKind:
return Out<ELFT>::Bss;
case SymbolBody::SharedKind:
if (cast<SharedSymbol<ELFT>>(Sym)->needsCopy())
return Out<ELFT>::Bss;
break;
case SymbolBody::UndefinedElfKind:
case SymbolBody::UndefinedKind:
case SymbolBody::LazyKind:
break;
case SymbolBody::DefinedBitcodeKind:
llvm_unreachable("Should have been replaced");
}
return nullptr;
}
template <class ELFT>
uint8_t SymbolTableSection<ELFT>::getSymbolBinding(SymbolBody *Body) {
uint8_t Visibility = Body->getVisibility();
if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
return STB_LOCAL;
if (const Elf_Sym *ESym = getElfSym<ELFT>(*Body))
return ESym->getBinding();
if (isa<DefinedSynthetic<ELFT>>(Body))
return STB_LOCAL;
return Body->isWeak() ? STB_WEAK : STB_GLOBAL;
}
template <class ELFT>
MipsReginfoOutputSection<ELFT>::MipsReginfoOutputSection()
: OutputSectionBase<ELFT>(".reginfo", SHT_MIPS_REGINFO, SHF_ALLOC) {
this->Header.sh_addralign = 4;
this->Header.sh_entsize = sizeof(Elf_Mips_RegInfo);
this->Header.sh_size = sizeof(Elf_Mips_RegInfo);
}
template <class ELFT>
void MipsReginfoOutputSection<ELFT>::writeTo(uint8_t *Buf) {
auto *R = reinterpret_cast<Elf_Mips_RegInfo *>(Buf);
R->ri_gp_value = getMipsGpAddr<ELFT>();
R->ri_gprmask = GprMask;
}
template <class ELFT>
void MipsReginfoOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
// Copy input object file's .reginfo gprmask to output.
auto *S = cast<MipsReginfoInputSection<ELFT>>(C);
GprMask |= S->Reginfo->ri_gprmask;
}
namespace lld {
namespace elf2 {
template class OutputSectionBase<ELF32LE>;
template class OutputSectionBase<ELF32BE>;
template class OutputSectionBase<ELF64LE>;
template class OutputSectionBase<ELF64BE>;
template class EhFrameHeader<ELF32LE>;
template class EhFrameHeader<ELF32BE>;
template class EhFrameHeader<ELF64LE>;
template class EhFrameHeader<ELF64BE>;
template class GotPltSection<ELF32LE>;
template class GotPltSection<ELF32BE>;
template class GotPltSection<ELF64LE>;
template class GotPltSection<ELF64BE>;
template class GotSection<ELF32LE>;
template class GotSection<ELF32BE>;
template class GotSection<ELF64LE>;
template class GotSection<ELF64BE>;
template class PltSection<ELF32LE>;
template class PltSection<ELF32BE>;
template class PltSection<ELF64LE>;
template class PltSection<ELF64BE>;
template class RelocationSection<ELF32LE>;
template class RelocationSection<ELF32BE>;
template class RelocationSection<ELF64LE>;
template class RelocationSection<ELF64BE>;
template class InterpSection<ELF32LE>;
template class InterpSection<ELF32BE>;
template class InterpSection<ELF64LE>;
template class InterpSection<ELF64BE>;
template class GnuHashTableSection<ELF32LE>;
template class GnuHashTableSection<ELF32BE>;
template class GnuHashTableSection<ELF64LE>;
template class GnuHashTableSection<ELF64BE>;
template class HashTableSection<ELF32LE>;
template class HashTableSection<ELF32BE>;
template class HashTableSection<ELF64LE>;
template class HashTableSection<ELF64BE>;
template class DynamicSection<ELF32LE>;
template class DynamicSection<ELF32BE>;
template class DynamicSection<ELF64LE>;
template class DynamicSection<ELF64BE>;
template class OutputSection<ELF32LE>;
template class OutputSection<ELF32BE>;
template class OutputSection<ELF64LE>;
template class OutputSection<ELF64BE>;
template class EHOutputSection<ELF32LE>;
template class EHOutputSection<ELF32BE>;
template class EHOutputSection<ELF64LE>;
template class EHOutputSection<ELF64BE>;
template class MipsReginfoOutputSection<ELF32LE>;
template class MipsReginfoOutputSection<ELF32BE>;
template class MipsReginfoOutputSection<ELF64LE>;
template class MipsReginfoOutputSection<ELF64BE>;
template class MergeOutputSection<ELF32LE>;
template class MergeOutputSection<ELF32BE>;
template class MergeOutputSection<ELF64LE>;
template class MergeOutputSection<ELF64BE>;
template class StringTableSection<ELF32LE>;
template class StringTableSection<ELF32BE>;
template class StringTableSection<ELF64LE>;
template class StringTableSection<ELF64BE>;
template class SymbolTableSection<ELF32LE>;
template class SymbolTableSection<ELF32BE>;
template class SymbolTableSection<ELF64LE>;
template class SymbolTableSection<ELF64BE>;
template uint32_t getLocalRelTarget(const ObjectFile<ELF32LE> &,
const ELFFile<ELF32LE>::Elf_Rel &,
uint32_t);
template uint32_t getLocalRelTarget(const ObjectFile<ELF32BE> &,
const ELFFile<ELF32BE>::Elf_Rel &,
uint32_t);
template uint64_t getLocalRelTarget(const ObjectFile<ELF64LE> &,
const ELFFile<ELF64LE>::Elf_Rel &,
uint64_t);
template uint64_t getLocalRelTarget(const ObjectFile<ELF64BE> &,
const ELFFile<ELF64BE>::Elf_Rel &,
uint64_t);
template uint32_t getLocalRelTarget(const ObjectFile<ELF32LE> &,
const ELFFile<ELF32LE>::Elf_Rela &,
uint32_t);
template uint32_t getLocalRelTarget(const ObjectFile<ELF32BE> &,
const ELFFile<ELF32BE>::Elf_Rela &,
uint32_t);
template uint64_t getLocalRelTarget(const ObjectFile<ELF64LE> &,
const ELFFile<ELF64LE>::Elf_Rela &,
uint64_t);
template uint64_t getLocalRelTarget(const ObjectFile<ELF64BE> &,
const ELFFile<ELF64BE>::Elf_Rela &,
uint64_t);
}
}
Index: lld/trunk/ELF/Config.h
===================================================================
--- lld/trunk/ELF/Config.h (revision 261837)
+++ lld/trunk/ELF/Config.h (revision 261838)
@@ -1,92 +1,93 @@
//===- Config.h -------------------------------------------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_ELF_CONFIG_H
#define LLD_ELF_CONFIG_H
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ELF.h"
#include <vector>
namespace lld {
namespace elf2 {
class InputFile;
class SymbolBody;
enum ELFKind {
ELFNoneKind,
ELF32LEKind,
ELF32BEKind,
ELF64LEKind,
ELF64BEKind
};
// This struct contains the global configuration for the linker.
// Most fields are direct mapping from the command line options
// and such fields have the same name as the corresponding options.
// Most fields are initialized by the driver.
struct Configuration {
SymbolBody *EntrySym = nullptr;
SymbolBody *MipsGpDisp = nullptr;
SymbolBody *MipsLocalGp = nullptr;
InputFile *FirstElf = nullptr;
llvm::StringRef DynamicLinker;
llvm::StringRef Entry;
llvm::StringRef Emulation;
llvm::StringRef Fini;
llvm::StringRef Init;
llvm::StringRef OutputFile;
llvm::StringRef SoName;
llvm::StringRef Sysroot;
std::string RPath;
std::vector<llvm::StringRef> SearchPaths;
std::vector<llvm::StringRef> Undefined;
bool AllowMultipleDefinition;
bool AsNeeded = false;
bool Bsymbolic;
bool BsymbolicFunctions;
bool Demangle = true;
bool DiscardAll;
bool DiscardLocals;
bool DiscardNone;
bool EhFrameHdr;
bool EnableNewDtags;
bool ExportDynamic;
bool GcSections;
bool GnuHash = false;
bool Mips64EL = false;
bool NoInhibitExec;
bool NoUndefined;
bool PrintGcSections;
+ bool Relocatable;
bool Shared;
bool Static = false;
bool StripAll;
bool SysvHash = true;
bool Verbose;
bool ZExecStack;
bool ZNodelete;
bool ZNow;
bool ZOrigin;
bool ZRelro;
ELFKind EKind = ELFNoneKind;
uint16_t EMachine = llvm::ELF::EM_NONE;
uint64_t EntryAddr = -1;
unsigned Optimize = 0;
};
// The only instance of Configuration struct.
extern Configuration *Config;
} // namespace elf2
} // namespace lld
#endif
Index: lld/trunk/ELF/Writer.cpp
===================================================================
--- lld/trunk/ELF/Writer.cpp (revision 261837)
+++ lld/trunk/ELF/Writer.cpp (revision 261838)
@@ -1,1502 +1,1534 @@
//===- Writer.cpp ---------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Writer.h"
#include "Config.h"
#include "LinkerScript.h"
#include "OutputSections.h"
#include "SymbolTable.h"
#include "Target.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace lld;
using namespace lld::elf2;
namespace {
// The writer writes a SymbolTable result to a file.
template <class ELFT> class Writer {
public:
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr;
typedef typename ELFFile<ELFT>::Elf_Phdr Elf_Phdr;
typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
Writer(SymbolTable<ELFT> &S) : Symtab(S) {}
void run();
private:
// This describes a program header entry.
// Each contains type, access flags and range of output sections that will be
// placed in it.
struct Phdr {
Phdr(unsigned Type, unsigned Flags) {
H.p_type = Type;
H.p_flags = Flags;
}
Elf_Phdr H = {};
OutputSectionBase<ELFT> *First = nullptr;
OutputSectionBase<ELFT> *Last = nullptr;
};
void copyLocalSymbols();
void addReservedSymbols();
bool createSections();
void addPredefinedSections();
template <bool isRela>
void scanRelocs(InputSectionBase<ELFT> &C,
iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels);
void scanRelocs(InputSection<ELFT> &C);
void scanRelocs(InputSectionBase<ELFT> &S, const Elf_Shdr &RelSec);
void createPhdrs();
void assignAddresses();
+ void assignAddressesRelocatable();
void fixAbsoluteSymbols();
bool openFile();
void writeHeader();
void writeSections();
bool isDiscarded(InputSectionBase<ELFT> *IS) const;
StringRef getOutputSectionName(InputSectionBase<ELFT> *S) const;
bool needsInterpSection() const {
return !Symtab.getSharedFiles().empty() && !Config->DynamicLinker.empty();
}
bool isOutputDynamic() const {
return !Symtab.getSharedFiles().empty() || Config->Shared;
}
OutputSection<ELFT> *getBss();
void addCommonSymbols(std::vector<DefinedCommon *> &Syms);
void addCopyRelSymbols(std::vector<SharedSymbol<ELFT> *> &Syms);
std::unique_ptr<llvm::FileOutputBuffer> Buffer;
BumpPtrAllocator Alloc;
std::vector<OutputSectionBase<ELFT> *> OutputSections;
std::vector<std::unique_ptr<OutputSectionBase<ELFT>>> OwningSections;
// We create a section for the ELF header and one for the program headers.
- const unsigned NumDummySections = 2;
ArrayRef<OutputSectionBase<ELFT> *> getSections() const {
- return makeArrayRef(OutputSections).slice(NumDummySections);
+ return makeArrayRef(OutputSections).slice(dummySectionsNum());
}
unsigned getNumSections() const {
- return OutputSections.size() + 1 - NumDummySections;
+ return OutputSections.size() + 1 - dummySectionsNum();
}
+ // Usually there are 2 dummies sections: ELF header and program header.
+ // Relocatable output does not require program headers to be created.
+ unsigned dummySectionsNum() const { return Config->Relocatable ? 1 : 2; }
void addRelIpltSymbols();
void addStartEndSymbols();
void addStartStopSymbols(OutputSectionBase<ELFT> *Sec);
SymbolTable<ELFT> &Symtab;
std::vector<Phdr> Phdrs;
uintX_t FileSize;
uintX_t SectionHeaderOff;
// Flag to force GOT to be in output if we have relocations
// that relies on its address.
bool HasGotOffRel = false;
};
} // anonymous namespace
template <class ELFT> static bool shouldUseRela() { return ELFT::Is64Bits; }
template <class ELFT> void elf2::writeResult(SymbolTable<ELFT> *Symtab) {
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
// Create singleton output sections.
bool IsRela = shouldUseRela<ELFT>();
DynamicSection<ELFT> Dynamic(*Symtab);
EhFrameHeader<ELFT> EhFrameHdr;
GotSection<ELFT> Got;
InterpSection<ELFT> Interp;
PltSection<ELFT> Plt;
RelocationSection<ELFT> RelaDyn(IsRela ? ".rela.dyn" : ".rel.dyn", IsRela);
StringTableSection<ELFT> DynStrTab(".dynstr", true);
StringTableSection<ELFT> ShStrTab(".shstrtab", false);
SymbolTableSection<ELFT> DynSymTab(*Symtab, DynStrTab);
OutputSectionBase<ELFT> ElfHeader("", 0, SHF_ALLOC);
OutputSectionBase<ELFT> ProgramHeaders("", 0, SHF_ALLOC);
ProgramHeaders.updateAlign(sizeof(uintX_t));
// Instantiate optional output sections if they are needed.
std::unique_ptr<GnuHashTableSection<ELFT>> GnuHashTab;
std::unique_ptr<GotPltSection<ELFT>> GotPlt;
std::unique_ptr<HashTableSection<ELFT>> HashTab;
std::unique_ptr<RelocationSection<ELFT>> RelaPlt;
std::unique_ptr<StringTableSection<ELFT>> StrTab;
std::unique_ptr<SymbolTableSection<ELFT>> SymTabSec;
if (Config->GnuHash)
GnuHashTab.reset(new GnuHashTableSection<ELFT>);
if (Config->SysvHash)
HashTab.reset(new HashTableSection<ELFT>);
if (Target->UseLazyBinding) {
StringRef S = IsRela ? ".rela.plt" : ".rel.plt";
GotPlt.reset(new GotPltSection<ELFT>);
RelaPlt.reset(new RelocationSection<ELFT>(S, IsRela));
}
if (!Config->StripAll) {
StrTab.reset(new StringTableSection<ELFT>(".strtab", false));
SymTabSec.reset(new SymbolTableSection<ELFT>(*Symtab, *StrTab));
}
Out<ELFT>::DynStrTab = &DynStrTab;
Out<ELFT>::DynSymTab = &DynSymTab;
Out<ELFT>::Dynamic = &Dynamic;
Out<ELFT>::EhFrameHdr = &EhFrameHdr;
Out<ELFT>::GnuHashTab = GnuHashTab.get();
Out<ELFT>::Got = &Got;
Out<ELFT>::GotPlt = GotPlt.get();
Out<ELFT>::HashTab = HashTab.get();
Out<ELFT>::Interp = &Interp;
Out<ELFT>::Plt = &Plt;
Out<ELFT>::RelaDyn = &RelaDyn;
Out<ELFT>::RelaPlt = RelaPlt.get();
Out<ELFT>::ShStrTab = &ShStrTab;
Out<ELFT>::StrTab = StrTab.get();
Out<ELFT>::SymTab = SymTabSec.get();
Out<ELFT>::Bss = nullptr;
Out<ELFT>::MipsRldMap = nullptr;
Out<ELFT>::Opd = nullptr;
Out<ELFT>::OpdBuf = nullptr;
Out<ELFT>::TlsPhdr = nullptr;
Out<ELFT>::ElfHeader = &ElfHeader;
Out<ELFT>::ProgramHeaders = &ProgramHeaders;
Writer<ELFT>(*Symtab).run();
}
// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
if (!Config->DiscardAll)
copyLocalSymbols();
addReservedSymbols();
if (!createSections())
return;
- createPhdrs();
- assignAddresses();
+ if (!Config->Relocatable) {
+ createPhdrs();
+ assignAddresses();
+ } else {
+ assignAddressesRelocatable();
+ }
fixAbsoluteSymbols();
if (!openFile())
return;
writeHeader();
writeSections();
if (HasError)
return;
fatal(Buffer->commit());
}
namespace {
template <bool Is64Bits> struct SectionKey {
typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
StringRef Name;
uint32_t Type;
uintX_t Flags;
uintX_t Alignment;
};
}
namespace llvm {
template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> {
static SectionKey<Is64Bits> getEmptyKey() {
return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0,
0};
}
static SectionKey<Is64Bits> getTombstoneKey() {
return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0,
0, 0};
}
static unsigned getHashValue(const SectionKey<Is64Bits> &Val) {
return hash_combine(Val.Name, Val.Type, Val.Flags, Val.Alignment);
}
static bool isEqual(const SectionKey<Is64Bits> &LHS,
const SectionKey<Is64Bits> &RHS) {
return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) &&
LHS.Type == RHS.Type && LHS.Flags == RHS.Flags &&
LHS.Alignment == RHS.Alignment;
}
};
}
template <class ELFT, class RelT>
static bool handleTlsRelocation(unsigned Type, SymbolBody *Body,
InputSectionBase<ELFT> &C, RelT &RI) {
if (Target->isTlsLocalDynamicRel(Type)) {
if (Target->canRelaxTls(Type, nullptr))
return true;
if (Out<ELFT>::Got->addTlsIndex())
Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel,
DynamicReloc<ELFT>::Off_LTlsIndex,
nullptr});
return true;
}
if (!Body || !Body->IsTls)
return false;
if (Target->isTlsGlobalDynamicRel(Type)) {
if (!Target->canRelaxTls(Type, Body)) {
if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel,
DynamicReloc<ELFT>::Off_GTlsIndex, Body});
Out<ELFT>::RelaDyn->addReloc(
{Target->TlsOffsetRel, DynamicReloc<ELFT>::Off_GTlsOffset, Body});
}
return true;
}
if (!canBePreempted(Body, true))
return true;
}
return !Target->isTlsDynRel(Type, *Body);
}
// The reason we have to do this early scan is as follows
// * To mmap the output file, we need to know the size
// * For that, we need to know how many dynamic relocs we will have.
// It might be possible to avoid this by outputting the file with write:
// * Write the allocated output sections, computing addresses.
// * Apply relocations, recording which ones require a dynamic reloc.
// * Write the dynamic relocations.
// * Write the rest of the file.
// This would have some drawbacks. For example, we would only know if .rela.dyn
// is needed after applying relocations. If it is, it will go after rw and rx
// sections. Given that it is ro, we will need an extra PT_LOAD. This
// complicates things for the dynamic linker and means we would have to reserve
// space for the extra PT_LOAD even if we end up not using it.
template <class ELFT>
template <bool isRela>
void Writer<ELFT>::scanRelocs(
InputSectionBase<ELFT> &C,
iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels) {
typedef Elf_Rel_Impl<ELFT, isRela> RelType;
const ObjectFile<ELFT> &File = *C.getFile();
for (const RelType &RI : Rels) {
uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
SymbolBody *Body = File.getSymbolBody(SymIndex);
uint32_t Type = RI.getType(Config->Mips64EL);
// Ignore "hint" relocation because it is for optional code optimization.
if (Target->isHintRel(Type))
continue;
if (Target->isGotRelative(Type))
HasGotOffRel = true;
// Set "used" bit for --as-needed.
if (Body && Body->isUndefined() && !Body->isWeak())
if (auto *S = dyn_cast<SharedSymbol<ELFT>>(Body->repl()))
S->File->IsUsed = true;
if (Body)
Body = Body->repl();
if (handleTlsRelocation<ELFT>(Type, Body, C, RI))
continue;
if (Target->needsDynRelative(Type))
Out<ELFT>::RelaDyn->addReloc({Target->RelativeRel, &C, RI.r_offset, true,
Body, getAddend<ELFT>(RI)});
// MIPS has a special rule to create GOTs for local symbols.
if (Config->EMachine == EM_MIPS && !canBePreempted(Body, true) &&
(Type == R_MIPS_GOT16 || Type == R_MIPS_CALL16)) {
// FIXME (simon): Do not add so many redundant entries.
Out<ELFT>::Got->addMipsLocalEntry();
continue;
}
// If a symbol in a DSO is referenced directly instead of through GOT,
// we need to create a copy relocation for the symbol.
if (auto *B = dyn_cast_or_null<SharedSymbol<ELFT>>(Body)) {
if (B->needsCopy())
continue;
if (Target->needsCopyRel<ELFT>(Type, *B)) {
B->NeedsCopyOrPltAddr = true;
Out<ELFT>::RelaDyn->addReloc(
{Target->CopyRel, DynamicReloc<ELFT>::Off_Bss, B});
continue;
}
}
// An STT_GNU_IFUNC symbol always uses a PLT entry, and all references
// to the symbol go through the PLT. This is true even for a local
// symbol, although local symbols normally do not require PLT entries.
if (Body && isGnuIFunc<ELFT>(*Body)) {
if (Body->isInPlt())
continue;
Out<ELFT>::Plt->addEntry(Body);
bool CBP = canBePreempted(Body, /*NeedsGot=*/true);
if (Target->UseLazyBinding) {
Out<ELFT>::GotPlt->addEntry(Body);
Out<ELFT>::RelaPlt->addReloc(
{CBP ? Target->PltRel : Target->IRelativeRel,
DynamicReloc<ELFT>::Off_GotPlt, !CBP, Body});
} else {
Out<ELFT>::Got->addEntry(Body);
Out<ELFT>::RelaDyn->addReloc(
{CBP ? Target->PltRel : Target->IRelativeRel,
DynamicReloc<ELFT>::Off_Got, !CBP, Body});
}
continue;
}
// If a relocation needs PLT, we create a PLT and a GOT slot
// for the symbol.
TargetInfo::PltNeed NeedPlt = TargetInfo::Plt_No;
if (Body)
NeedPlt = Target->needsPlt<ELFT>(Type, *Body);
if (NeedPlt) {
if (NeedPlt == TargetInfo::Plt_Implicit)
Body->NeedsCopyOrPltAddr = true;
if (Body->isInPlt())
continue;
Out<ELFT>::Plt->addEntry(Body);
if (Target->UseLazyBinding) {
Out<ELFT>::GotPlt->addEntry(Body);
Out<ELFT>::RelaPlt->addReloc(
{Target->PltRel, DynamicReloc<ELFT>::Off_GotPlt, Body});
} else {
if (Body->isInGot())
continue;
Out<ELFT>::Got->addEntry(Body);
Out<ELFT>::RelaDyn->addReloc(
{Target->GotRel, DynamicReloc<ELFT>::Off_Got, Body});
}
continue;
}
// If a relocation needs GOT, we create a GOT slot for the symbol.
if (Body && Target->needsGot(Type, *Body)) {
if (Body->isInGot())
continue;
Out<ELFT>::Got->addEntry(Body);
if (Config->EMachine == EM_MIPS) {
// MIPS ABI has special rules to process GOT entries
// and doesn't require relocation entries for them.
// See "Global Offset Table" in Chapter 5 in the following document
// for detailed description:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
Body->MustBeInDynSym = true;
continue;
}
bool CBP = canBePreempted(Body, /*NeedsGot=*/true);
bool Dynrel = Config->Shared && !Target->isRelRelative(Type) &&
!Target->isSizeRel(Type);
if (CBP || Dynrel) {
uint32_t DynType;
if (CBP)
DynType = Body->IsTls ? Target->TlsGotRel : Target->GotRel;
else
DynType = Target->RelativeRel;
Out<ELFT>::RelaDyn->addReloc(
{DynType, DynamicReloc<ELFT>::Off_Got, !CBP, Body});
}
continue;
}
if (Config->EMachine == EM_MIPS) {
if (Type == R_MIPS_LO16)
// Ignore R_MIPS_LO16 relocation. If it is a pair for R_MIPS_GOT16 we
// already completed all required action (GOT entry allocation) when
// handle R_MIPS_GOT16a. If it is a pair for R_MIPS_HI16 against
// _gp_disp it does not require dynamic relocation. If its a pair for
// R_MIPS_HI16 against a regular symbol it does not require dynamic
// relocation too because that case is possible for executable file
// linking only.
continue;
if (Body == Config->MipsGpDisp || Body == Config->MipsLocalGp)
// MIPS _gp_disp designates offset between start of function and 'gp'
// pointer into GOT. __gnu_local_gp is equal to the current value of
// the 'gp'. Therefore any relocations against them do not require
// dynamic relocation.
continue;
}
if (canBePreempted(Body, /*NeedsGot=*/false)) {
// We don't know anything about the finaly symbol. Just ask the dynamic
// linker to handle the relocation for us.
Out<ELFT>::RelaDyn->addReloc({Target->getDynRel(Type), &C, RI.r_offset,
false, Body, getAddend<ELFT>(RI)});
continue;
}
// We know that this is the final symbol. If the program being produced
// is position independent, the final value is still not known.
// If the relocation depends on the symbol value (not the size or distances
// in the output), we still need some help from the dynamic linker.
// We can however do better than just copying the incoming relocation. We
// can process some of it and and just ask the dynamic linker to add the
// load address.
if (!Config->Shared || Target->isRelRelative(Type) ||
Target->isSizeRel(Type))
continue;
uintX_t Addend = getAddend<ELFT>(RI);
if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC) {
Out<ELFT>::RelaDyn->addReloc({R_PPC64_RELATIVE, &C, RI.r_offset, false,
nullptr,
(uintX_t)getPPC64TocBase() + Addend});
continue;
}
if (Body) {
Out<ELFT>::RelaDyn->addReloc(
{Target->RelativeRel, &C, RI.r_offset, true, Body, Addend});
continue;
}
const Elf_Sym *Sym =
File.getObj().getRelocationSymbol(&RI, File.getSymbolTable());
InputSectionBase<ELFT> *Section = File.getSection(*Sym);
uintX_t Offset = Sym->st_value;
if (Sym->getType() == STT_SECTION) {
Offset += Addend;
Addend = 0;
}
Out<ELFT>::RelaDyn->addReloc(
{Target->RelativeRel, &C, RI.r_offset, Section, Offset, Addend});
}
}
template <class ELFT> void Writer<ELFT>::scanRelocs(InputSection<ELFT> &C) {
if (C.getSectionHdr()->sh_flags & SHF_ALLOC)
for (const Elf_Shdr *RelSec : C.RelocSections)
scanRelocs(C, *RelSec);
}
template <class ELFT>
void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &S,
const Elf_Shdr &RelSec) {
ELFFile<ELFT> &EObj = S.getFile()->getObj();
if (RelSec.sh_type == SHT_RELA)
scanRelocs(S, EObj.relas(&RelSec));
else
scanRelocs(S, EObj.rels(&RelSec));
}
template <class ELFT>
static void reportUndefined(SymbolTable<ELFT> &Symtab, SymbolBody *Sym) {
- if (Config->Shared && !Config->NoUndefined)
+ if ((Config->Relocatable || Config->Shared) && !Config->NoUndefined)
return;
std::string Msg = "undefined symbol: " + Sym->getName().str();
if (ELFFileBase<ELFT> *File = Symtab.findFile(Sym))
Msg += " in " + File->getName().str();
if (Config->NoInhibitExec)
warning(Msg);
else
error(Msg);
}
template <class ELFT>
static bool shouldKeepInSymtab(const ObjectFile<ELFT> &File, StringRef SymName,
const typename ELFFile<ELFT>::Elf_Sym &Sym) {
if (Sym.getType() == STT_SECTION || Sym.getType() == STT_FILE)
return false;
InputSectionBase<ELFT> *Sec = File.getSection(Sym);
// If sym references a section in a discarded group, don't keep it.
if (Sec == InputSection<ELFT>::Discarded)
return false;
if (Config->DiscardNone)
return true;
// In ELF assembly .L symbols are normally discarded by the assembler.
// If the assembler fails to do so, the linker discards them if
// * --discard-locals is used.
// * The symbol is in a SHF_MERGE section, which is normally the reason for
// the assembler keeping the .L symbol.
if (!SymName.startswith(".L") && !SymName.empty())
return true;
if (Config->DiscardLocals)
return false;
return !(Sec->getSectionHdr()->sh_flags & SHF_MERGE);
}
// Local symbols are not in the linker's symbol table. This function scans
// each object file's symbol table to copy local symbols to the output.
template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
if (!Out<ELFT>::SymTab)
return;
for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
for (const Elf_Sym &Sym : F->getLocalSymbols()) {
ErrorOr<StringRef> SymNameOrErr = Sym.getName(F->getStringTable());
fatal(SymNameOrErr);
StringRef SymName = *SymNameOrErr;
if (!shouldKeepInSymtab<ELFT>(*F, SymName, Sym))
continue;
if (Sym.st_shndx != SHN_ABS) {
InputSectionBase<ELFT> *Section = F->getSection(Sym);
if (!Section->Live)
continue;
}
++Out<ELFT>::SymTab->NumLocals;
F->KeptLocalSyms.push_back(std::make_pair(
&Sym, Out<ELFT>::SymTab->StrTabSec.addString(SymName)));
}
}
}
// PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections that
// we would like to make sure appear is a specific order to maximize their
// coverage by a single signed 16-bit offset from the TOC base pointer.
// Conversely, the special .tocbss section should be first among all SHT_NOBITS
// sections. This will put it next to the loaded special PPC64 sections (and,
// thus, within reach of the TOC base pointer).
static int getPPC64SectionRank(StringRef SectionName) {
return StringSwitch<int>(SectionName)
.Case(".tocbss", 0)
.Case(".branch_lt", 2)
.Case(".toc", 3)
.Case(".toc1", 4)
.Case(".opd", 5)
.Default(1);
}
template <class ELFT> static bool isRelroSection(OutputSectionBase<ELFT> *Sec) {
if (!Config->ZRelro)
return false;
typename OutputSectionBase<ELFT>::uintX_t Flags = Sec->getFlags();
if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE))
return false;
if (Flags & SHF_TLS)
return true;
uint32_t Type = Sec->getType();
if (Type == SHT_INIT_ARRAY || Type == SHT_FINI_ARRAY ||
Type == SHT_PREINIT_ARRAY)
return true;
if (Sec == Out<ELFT>::GotPlt)
return Config->ZNow;
if (Sec == Out<ELFT>::Dynamic || Sec == Out<ELFT>::Got)
return true;
StringRef S = Sec->getName();
return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" ||
S == ".eh_frame";
}
// Output section ordering is determined by this function.
template <class ELFT>
static bool compareSections(OutputSectionBase<ELFT> *A,
OutputSectionBase<ELFT> *B) {
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
int Comp = Script->compareSections(A->getName(), B->getName());
if (Comp != 0)
return Comp < 0;
uintX_t AFlags = A->getFlags();
uintX_t BFlags = B->getFlags();
// Allocatable sections go first to reduce the total PT_LOAD size and
// so debug info doesn't change addresses in actual code.
bool AIsAlloc = AFlags & SHF_ALLOC;
bool BIsAlloc = BFlags & SHF_ALLOC;
if (AIsAlloc != BIsAlloc)
return AIsAlloc;
// We don't have any special requirements for the relative order of
// two non allocatable sections.
if (!AIsAlloc)
return false;
// We want the read only sections first so that they go in the PT_LOAD
// covering the program headers at the start of the file.
bool AIsWritable = AFlags & SHF_WRITE;
bool BIsWritable = BFlags & SHF_WRITE;
if (AIsWritable != BIsWritable)
return BIsWritable;
// For a corresponding reason, put non exec sections first (the program
// header PT_LOAD is not executable).
bool AIsExec = AFlags & SHF_EXECINSTR;
bool BIsExec = BFlags & SHF_EXECINSTR;
if (AIsExec != BIsExec)
return BIsExec;
// If we got here we know that both A and B are in the same PT_LOAD.
// The TLS initialization block needs to be a single contiguous block in a R/W
// PT_LOAD, so stick TLS sections directly before R/W sections. The TLS NOBITS
// sections are placed here as they don't take up virtual address space in the
// PT_LOAD.
bool AIsTls = AFlags & SHF_TLS;
bool BIsTls = BFlags & SHF_TLS;
if (AIsTls != BIsTls)
return AIsTls;
// The next requirement we have is to put nobits sections last. The
// reason is that the only thing the dynamic linker will see about
// them is a p_memsz that is larger than p_filesz. Seeing that it
// zeros the end of the PT_LOAD, so that has to correspond to the
// nobits sections.
bool AIsNoBits = A->getType() == SHT_NOBITS;
bool BIsNoBits = B->getType() == SHT_NOBITS;
if (AIsNoBits != BIsNoBits)
return BIsNoBits;
// We place RelRo section before plain r/w ones.
bool AIsRelRo = isRelroSection(A);
bool BIsRelRo = isRelroSection(B);
if (AIsRelRo != BIsRelRo)
return AIsRelRo;
// Some architectures have additional ordering restrictions for sections
// within the same PT_LOAD.
if (Config->EMachine == EM_PPC64)
return getPPC64SectionRank(A->getName()) <
getPPC64SectionRank(B->getName());
return false;
}
template <class ELFT> OutputSection<ELFT> *Writer<ELFT>::getBss() {
if (!Out<ELFT>::Bss) {
Out<ELFT>::Bss =
new OutputSection<ELFT>(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
OwningSections.emplace_back(Out<ELFT>::Bss);
OutputSections.push_back(Out<ELFT>::Bss);
}
return Out<ELFT>::Bss;
}
// Until this function is called, common symbols do not belong to any section.
// This function adds them to end of BSS section.
template <class ELFT>
void Writer<ELFT>::addCommonSymbols(std::vector<DefinedCommon *> &Syms) {
if (Syms.empty())
return;
// Sort the common symbols by alignment as an heuristic to pack them better.
std::stable_sort(Syms.begin(), Syms.end(),
[](const DefinedCommon *A, const DefinedCommon *B) {
return A->MaxAlignment > B->MaxAlignment;
});
uintX_t Off = getBss()->getSize();
for (DefinedCommon *C : Syms) {
Off = alignTo(Off, C->MaxAlignment);
C->OffsetInBss = Off;
Off += C->Size;
}
Out<ELFT>::Bss->setSize(Off);
}
// Reserve space in .bss for copy relocations.
template <class ELFT>
void Writer<ELFT>::addCopyRelSymbols(std::vector<SharedSymbol<ELFT> *> &Syms) {
if (Syms.empty())
return;
uintX_t Off = getBss()->getSize();
for (SharedSymbol<ELFT> *C : Syms) {
const Elf_Sym &Sym = C->Sym;
const Elf_Shdr *Sec = C->File->getSection(Sym);
uintX_t SecAlign = Sec->sh_addralign;
unsigned TrailingZeros =
std::min(countTrailingZeros(SecAlign),
countTrailingZeros((uintX_t)Sym.st_value));
uintX_t Align = 1 << TrailingZeros;
Out<ELFT>::Bss->updateAlign(Align);
Off = alignTo(Off, Align);
C->OffsetInBss = Off;
Off += Sym.st_size;
}
Out<ELFT>::Bss->setSize(Off);
}
template <class ELFT>
StringRef Writer<ELFT>::getOutputSectionName(InputSectionBase<ELFT> *S) const {
StringRef Dest = Script->getOutputSection<ELFT>(S);
if (!Dest.empty())
return Dest;
StringRef Name = S->getSectionName();
for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.",
".init_array.", ".fini_array.", ".ctors.", ".dtors.",
".tbss.", ".gcc_except_table.", ".tdata."})
if (Name.startswith(V))
return V.drop_back();
return Name;
}
template <class ELFT>
void reportDiscarded(InputSectionBase<ELFT> *IS,
const std::unique_ptr<ObjectFile<ELFT>> &File) {
if (!Config->PrintGcSections || !IS || IS->Live)
return;
llvm::errs() << "removing unused section from '" << IS->getSectionName()
<< "' in file '" << File->getName() << "'\n";
}
template <class ELFT>
bool Writer<ELFT>::isDiscarded(InputSectionBase<ELFT> *S) const {
return !S || S == InputSection<ELFT>::Discarded || !S->Live ||
Script->isDiscarded(S);
}
// The beginning and the ending of .rel[a].plt section are marked
// with __rel[a]_iplt_{start,end} symbols if it is a statically linked
// executable. The runtime needs these symbols in order to resolve
// all IRELATIVE relocs on startup. For dynamic executables, we don't
// need these symbols, since IRELATIVE relocs are resolved through GOT
// and PLT. For details, see http://www.airs.com/blog/archives/403.
template <class ELFT>
void Writer<ELFT>::addRelIpltSymbols() {
if (isOutputDynamic() || !Out<ELFT>::RelaPlt)
return;
bool IsRela = shouldUseRela<ELFT>();
StringRef S = IsRela ? "__rela_iplt_start" : "__rel_iplt_start";
if (Symtab.find(S))
Symtab.addAbsolute(S, ElfSym<ELFT>::RelaIpltStart);
S = IsRela ? "__rela_iplt_end" : "__rel_iplt_end";
if (Symtab.find(S))
Symtab.addAbsolute(S, ElfSym<ELFT>::RelaIpltEnd);
}
template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
if (!B.isUsedInRegularObj())
return false;
if (auto *D = dyn_cast<DefinedRegular<ELFT>>(&B)) {
// Don't include synthetic symbols like __init_array_start in every output.
if (&D->Sym == &ElfSym<ELFT>::Ignored)
return false;
// Exclude symbols pointing to garbage-collected sections.
if (D->Section && !D->Section->Live)
return false;
}
return true;
}
static bool includeInDynsym(const SymbolBody &B) {
uint8_t V = B.getVisibility();
if (V != STV_DEFAULT && V != STV_PROTECTED)
return false;
if (Config->ExportDynamic || Config->Shared)
return true;
return B.MustBeInDynSym;
}
// This class knows how to create an output section for a given
// input section. Output section type is determined by various
// factors, including input section's sh_flags, sh_type and
// linker scripts.
namespace {
template <class ELFT> class OutputSectionFactory {
typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
public:
std::pair<OutputSectionBase<ELFT> *, bool> create(InputSectionBase<ELFT> *C,
StringRef OutsecName);
OutputSectionBase<ELFT> *lookup(StringRef Name, uint32_t Type, uintX_t Flags);
private:
SectionKey<ELFT::Is64Bits> createKey(InputSectionBase<ELFT> *C,
StringRef OutsecName);
SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSectionBase<ELFT> *> Map;
};
}
template <class ELFT>
std::pair<OutputSectionBase<ELFT> *, bool>
OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C,
StringRef OutsecName) {
SectionKey<ELFT::Is64Bits> Key = createKey(C, OutsecName);
OutputSectionBase<ELFT> *&Sec = Map[Key];
if (Sec)
return {Sec, false};
switch (C->SectionKind) {
case InputSectionBase<ELFT>::Regular:
Sec = new OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
break;
case InputSectionBase<ELFT>::EHFrame:
Sec = new EHOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
break;
case InputSectionBase<ELFT>::Merge:
Sec = new MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags,
Key.Alignment);
break;
case InputSectionBase<ELFT>::MipsReginfo:
Sec = new MipsReginfoOutputSection<ELFT>();
break;
}
return {Sec, true};
}
template <class ELFT>
OutputSectionBase<ELFT> *OutputSectionFactory<ELFT>::lookup(StringRef Name,
uint32_t Type,
uintX_t Flags) {
return Map.lookup({Name, Type, Flags, 0});
}
template <class ELFT>
SectionKey<ELFT::Is64Bits>
OutputSectionFactory<ELFT>::createKey(InputSectionBase<ELFT> *C,
StringRef OutsecName) {
const Elf_Shdr *H = C->getSectionHdr();
uintX_t Flags = H->sh_flags & ~SHF_GROUP;
// For SHF_MERGE we create different output sections for each alignment.
// This makes each output section simple and keeps a single level mapping from
// input to output.
uintX_t Alignment = 0;
if (isa<MergeInputSection<ELFT>>(C)) {
Alignment = H->sh_addralign;
if (H->sh_entsize > Alignment)
Alignment = H->sh_entsize;
}
// GNU as can give .eh_frame secion type SHT_PROGBITS or SHT_X86_64_UNWIND
// depending on the construct. We want to canonicalize it so that
// there is only one .eh_frame in the end.
uint32_t Type = H->sh_type;
if (Type == SHT_PROGBITS && Config->EMachine == EM_X86_64 &&
isa<EHInputSection<ELFT>>(C))
Type = SHT_X86_64_UNWIND;
return SectionKey<ELFT::Is64Bits>{OutsecName, Type, Flags, Alignment};
}
// The linker is expected to define some symbols depending on
// the linking result. This function defines such symbols.
template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
// __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For
// static linking the linker is required to optimize away any references to
// __tls_get_addr, so it's not defined anywhere. Create a hidden definition
// to avoid the undefined symbol error.
if (!isOutputDynamic())
Symtab.addIgnored("__tls_get_addr");
// If the "_end" symbol is referenced, it is expected to point to the address
// right after the data segment. Usually, this symbol points to the end
// of .bss section or to the end of .data section if .bss section is absent.
// We don't know the final address of _end yet, so just add a symbol here,
// and fix ElfSym<ELFT>::End.st_value later.
if (Symtab.find("_end"))
Symtab.addAbsolute("_end", ElfSym<ELFT>::End);
// Define "end" as an alias to "_end" if it is used but not defined.
// We don't want to define that unconditionally because we don't want to
// break programs that uses "end" as a regular symbol.
if (SymbolBody *B = Symtab.find("end"))
if (B->isUndefined())
Symtab.addAbsolute("end", ElfSym<ELFT>::End);
}
// Sort input sections by section name suffixes for
// __attribute__((init_priority(N))).
template <class ELFT> static void sortInitFini(OutputSectionBase<ELFT> *S) {
if (S)
reinterpret_cast<OutputSection<ELFT> *>(S)->sortInitFini();
}
// Sort input sections by the special rule for .ctors and .dtors.
template <class ELFT> static void sortCtorsDtors(OutputSectionBase<ELFT> *S) {
if (S)
reinterpret_cast<OutputSection<ELFT> *>(S)->sortCtorsDtors();
}
// Create output section objects and add them to OutputSections.
template <class ELFT> bool Writer<ELFT>::createSections() {
OutputSections.push_back(Out<ELFT>::ElfHeader);
- OutputSections.push_back(Out<ELFT>::ProgramHeaders);
+ if (!Config->Relocatable)
+ OutputSections.push_back(Out<ELFT>::ProgramHeaders);
// Add .interp first because some loaders want to see that section
// on the first page of the executable file when loaded into memory.
if (needsInterpSection())
OutputSections.push_back(Out<ELFT>::Interp);
// Create output sections for input object file sections.
std::vector<OutputSectionBase<ELFT> *> RegularSections;
OutputSectionFactory<ELFT> Factory;
for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
for (InputSectionBase<ELFT> *C : F->getSections()) {
if (isDiscarded(C)) {
reportDiscarded(C, F);
continue;
}
OutputSectionBase<ELFT> *Sec;
bool IsNew;
std::tie(Sec, IsNew) = Factory.create(C, getOutputSectionName(C));
if (IsNew) {
OwningSections.emplace_back(Sec);
OutputSections.push_back(Sec);
RegularSections.push_back(Sec);
}
Sec->addSection(C);
}
}
Out<ELFT>::Bss = static_cast<OutputSection<ELFT> *>(
Factory.lookup(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE));
// If we have a .opd section (used under PPC64 for function descriptors),
// store a pointer to it here so that we can use it later when processing
// relocations.
Out<ELFT>::Opd = Factory.lookup(".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC);
Out<ELFT>::Dynamic->PreInitArraySec = Factory.lookup(
".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC);
Out<ELFT>::Dynamic->InitArraySec =
Factory.lookup(".init_array", SHT_INIT_ARRAY, SHF_WRITE | SHF_ALLOC);
Out<ELFT>::Dynamic->FiniArraySec =
Factory.lookup(".fini_array", SHT_FINI_ARRAY, SHF_WRITE | SHF_ALLOC);
// Sort section contents for __attribute__((init_priority(N)).
sortInitFini(Out<ELFT>::Dynamic->InitArraySec);
sortInitFini(Out<ELFT>::Dynamic->FiniArraySec);
sortCtorsDtors(Factory.lookup(".ctors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC));
sortCtorsDtors(Factory.lookup(".dtors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC));
// The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop
// symbols for sections, so that the runtime can get the start and end
// addresses of each section by section name. Add such symbols.
addStartEndSymbols();
for (OutputSectionBase<ELFT> *Sec : RegularSections)
addStartStopSymbols(Sec);
// Define __rel[a]_iplt_{start,end} symbols if needed.
addRelIpltSymbols();
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.
for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
for (InputSectionBase<ELFT> *C : F->getSections()) {
if (isDiscarded(C))
continue;
if (auto *S = dyn_cast<InputSection<ELFT>>(C))
scanRelocs(*S);
else if (auto *S = dyn_cast<EHInputSection<ELFT>>(C))
if (S->RelocSection)
scanRelocs(*S, *S->RelocSection);
}
}
// Now that we have defined all possible symbols including linker-
// synthesized ones. Visit all symbols to give the finishing touches.
std::vector<DefinedCommon *> CommonSymbols;
std::vector<SharedSymbol<ELFT> *> CopyRelSymbols;
for (auto &P : Symtab.getSymbols()) {
SymbolBody *Body = P.second->Body;
if (auto *U = dyn_cast<Undefined>(Body))
if (!U->isWeak() && !U->canKeepUndefined())
reportUndefined<ELFT>(Symtab, Body);
if (auto *C = dyn_cast<DefinedCommon>(Body))
CommonSymbols.push_back(C);
if (auto *SC = dyn_cast<SharedSymbol<ELFT>>(Body))
if (SC->needsCopy())
CopyRelSymbols.push_back(SC);
if (!includeInSymtab<ELFT>(*Body))
continue;
if (Out<ELFT>::SymTab)
Out<ELFT>::SymTab->addSymbol(Body);
if (isOutputDynamic() && includeInDynsym(*Body))
Out<ELFT>::DynSymTab->addSymbol(Body);
}
// Do not proceed if there was an undefined symbol.
if (HasError)
return false;
addCommonSymbols(CommonSymbols);
addCopyRelSymbols(CopyRelSymbols);
// So far we have added sections from input object files.
// This function adds linker-created Out<ELFT>::* sections.
addPredefinedSections();
std::stable_sort(OutputSections.begin(), OutputSections.end(),
compareSections<ELFT>);
- for (unsigned I = NumDummySections, N = OutputSections.size(); I < N; ++I)
- OutputSections[I]->SectionIndex = I + 1 - NumDummySections;
+ for (unsigned I = dummySectionsNum(), N = OutputSections.size(); I < N; ++I)
+ OutputSections[I]->SectionIndex = I + 1 - dummySectionsNum();
for (OutputSectionBase<ELFT> *Sec : getSections())
Sec->setSHName(Out<ELFT>::ShStrTab->addString(Sec->getName()));
// Finalizers fix each section's size.
// .dynsym is finalized early since that may fill up .gnu.hash.
if (isOutputDynamic())
Out<ELFT>::DynSymTab->finalize();
// Fill other section headers. The dynamic table is finalized
// at the end because some tags like RELSZ depend on result
// of finalizing other sections. The dynamic string table is
// finalized once the .dynamic finalizer has added a few last
// strings. See DynamicSection::finalize()
for (OutputSectionBase<ELFT> *Sec : OutputSections)
if (Sec != Out<ELFT>::DynStrTab && Sec != Out<ELFT>::Dynamic)
Sec->finalize();
if (isOutputDynamic())
Out<ELFT>::Dynamic->finalize();
return true;
}
// This function add Out<ELFT>::* sections to OutputSections.
template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
auto Add = [&](OutputSectionBase<ELFT> *C) {
if (C)
OutputSections.push_back(C);
};
// This order is not the same as the final output order
// because we sort the sections using their attributes below.
Add(Out<ELFT>::SymTab);
Add(Out<ELFT>::ShStrTab);
Add(Out<ELFT>::StrTab);
if (isOutputDynamic()) {
Add(Out<ELFT>::DynSymTab);
Add(Out<ELFT>::GnuHashTab);
Add(Out<ELFT>::HashTab);
Add(Out<ELFT>::Dynamic);
Add(Out<ELFT>::DynStrTab);
if (Out<ELFT>::RelaDyn->hasRelocs())
Add(Out<ELFT>::RelaDyn);
// This is a MIPS specific section to hold a space within the data segment
// of executable file which is pointed to by the DT_MIPS_RLD_MAP entry.
// See "Dynamic section" in Chapter 5 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
if (Config->EMachine == EM_MIPS && !Config->Shared) {
Out<ELFT>::MipsRldMap = new OutputSection<ELFT>(".rld_map", SHT_PROGBITS,
SHF_ALLOC | SHF_WRITE);
Out<ELFT>::MipsRldMap->setSize(sizeof(uintX_t));
Out<ELFT>::MipsRldMap->updateAlign(sizeof(uintX_t));
OwningSections.emplace_back(Out<ELFT>::MipsRldMap);
Add(Out<ELFT>::MipsRldMap);
}
}
// We always need to add rel[a].plt to output if it has entries.
// Even during static linking it can contain R_[*]_IRELATIVE relocations.
if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs()) {
Add(Out<ELFT>::RelaPlt);
Out<ELFT>::RelaPlt->Static = !isOutputDynamic();
}
bool needsGot = !Out<ELFT>::Got->empty();
// We add the .got section to the result for dynamic MIPS target because
// its address and properties are mentioned in the .dynamic section.
if (Config->EMachine == EM_MIPS)
needsGot |= isOutputDynamic();
// If we have a relocation that is relative to GOT (such as GOTOFFREL),
// we need to emit a GOT even if it's empty.
if (HasGotOffRel)
needsGot = true;
if (needsGot)
Add(Out<ELFT>::Got);
if (Out<ELFT>::GotPlt && !Out<ELFT>::GotPlt->empty())
Add(Out<ELFT>::GotPlt);
if (!Out<ELFT>::Plt->empty())
Add(Out<ELFT>::Plt);
if (Out<ELFT>::EhFrameHdr->Live)
Add(Out<ELFT>::EhFrameHdr);
}
// The linker is expected to define SECNAME_start and SECNAME_end
// symbols for a few sections. This function defines them.
template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
auto Define = [&](StringRef Start, StringRef End,
OutputSectionBase<ELFT> *OS) {
if (OS) {
Symtab.addSynthetic(Start, *OS, 0);
Symtab.addSynthetic(End, *OS, OS->getSize());
} else {
Symtab.addIgnored(Start);
Symtab.addIgnored(End);
}
};
Define("__preinit_array_start", "__preinit_array_end",
Out<ELFT>::Dynamic->PreInitArraySec);
Define("__init_array_start", "__init_array_end",
Out<ELFT>::Dynamic->InitArraySec);
Define("__fini_array_start", "__fini_array_end",
Out<ELFT>::Dynamic->FiniArraySec);
}
static bool isAlpha(char C) {
return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z') || C == '_';
}
static bool isAlnum(char C) { return isAlpha(C) || ('0' <= C && C <= '9'); }
// Returns true if S is valid as a C language identifier.
static bool isValidCIdentifier(StringRef S) {
if (S.empty() || !isAlpha(S[0]))
return false;
return std::all_of(S.begin() + 1, S.end(), isAlnum);
}
// If a section name is valid as a C identifier (which is rare because of
// the leading '.'), linkers are expected to define __start_<secname> and
// __stop_<secname> symbols. They are at beginning and end of the section,
// respectively. This is not requested by the ELF standard, but GNU ld and
// gold provide the feature, and used by many programs.
template <class ELFT>
void Writer<ELFT>::addStartStopSymbols(OutputSectionBase<ELFT> *Sec) {
StringRef S = Sec->getName();
if (!isValidCIdentifier(S))
return;
StringSaver Saver(Alloc);
StringRef Start = Saver.save("__start_" + S);
StringRef Stop = Saver.save("__stop_" + S);
if (SymbolBody *B = Symtab.find(Start))
if (B->isUndefined())
Symtab.addSynthetic(Start, *Sec, 0);
if (SymbolBody *B = Symtab.find(Stop))
if (B->isUndefined())
Symtab.addSynthetic(Stop, *Sec, Sec->getSize());
}
template <class ELFT> static bool needsPtLoad(OutputSectionBase<ELFT> *Sec) {
if (!(Sec->getFlags() & SHF_ALLOC))
return false;
// Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is
// responsible for allocating space for them, not the PT_LOAD that
// contains the TLS initialization image.
if (Sec->getFlags() & SHF_TLS && Sec->getType() == SHT_NOBITS)
return false;
return true;
}
static uint32_t toPhdrFlags(uint64_t Flags) {
uint32_t Ret = PF_R;
if (Flags & SHF_WRITE)
Ret |= PF_W;
if (Flags & SHF_EXECINSTR)
Ret |= PF_X;
return Ret;
}
/// For AMDGPU we need to use custom segment kinds in order to specify which
/// address space data should be loaded into.
template <class ELFT>
static uint32_t getAmdgpuPhdr(OutputSectionBase<ELFT> *Sec) {
uint32_t Flags = Sec->getFlags();
if (Flags & SHF_AMDGPU_HSA_CODE)
return PT_AMDGPU_HSA_LOAD_CODE_AGENT;
if ((Flags & SHF_AMDGPU_HSA_GLOBAL) && !(Flags & SHF_AMDGPU_HSA_AGENT))
return PT_AMDGPU_HSA_LOAD_GLOBAL_PROGRAM;
return PT_LOAD;
}
// Decide which program headers to create and which sections to include in each
// one.
template <class ELFT> void Writer<ELFT>::createPhdrs() {
auto AddHdr = [this](unsigned Type, unsigned Flags) {
return &*Phdrs.emplace(Phdrs.end(), Type, Flags);
};
auto AddSec = [](Phdr &Hdr, OutputSectionBase<ELFT> *Sec) {
Hdr.Last = Sec;
if (!Hdr.First)
Hdr.First = Sec;
Hdr.H.p_align = std::max<uintX_t>(Hdr.H.p_align, Sec->getAlign());
};
// The first phdr entry is PT_PHDR which describes the program header itself.
Phdr &Hdr = *AddHdr(PT_PHDR, PF_R);
AddSec(Hdr, Out<ELFT>::ProgramHeaders);
// PT_INTERP must be the second entry if exists.
if (needsInterpSection()) {
Phdr &Hdr = *AddHdr(PT_INTERP, toPhdrFlags(Out<ELFT>::Interp->getFlags()));
AddSec(Hdr, Out<ELFT>::Interp);
}
// Add the first PT_LOAD segment for regular output sections.
uintX_t Flags = PF_R;
Phdr *Load = AddHdr(PT_LOAD, Flags);
AddSec(*Load, Out<ELFT>::ElfHeader);
Phdr TlsHdr(PT_TLS, PF_R);
Phdr RelRo(PT_GNU_RELRO, PF_R);
for (OutputSectionBase<ELFT> *Sec : OutputSections) {
if (!(Sec->getFlags() & SHF_ALLOC))
break;
// If we meet TLS section then we create TLS header
// and put all TLS sections inside for futher use when
// assign addresses.
if (Sec->getFlags() & SHF_TLS)
AddSec(TlsHdr, Sec);
if (!needsPtLoad<ELFT>(Sec))
continue;
// If flags changed then we want new load segment.
uintX_t NewFlags = toPhdrFlags(Sec->getFlags());
if (Flags != NewFlags) {
uint32_t LoadType = (Config->EMachine == EM_AMDGPU) ? getAmdgpuPhdr(Sec)
: (uint32_t)PT_LOAD;
Load = AddHdr(LoadType, NewFlags);
Flags = NewFlags;
}
AddSec(*Load, Sec);
if (isRelroSection(Sec))
AddSec(RelRo, Sec);
}
// Add the TLS segment unless it's empty.
if (TlsHdr.First)
Phdrs.push_back(std::move(TlsHdr));
// Add an entry for .dynamic.
if (isOutputDynamic()) {
Phdr &H = *AddHdr(PT_DYNAMIC, toPhdrFlags(Out<ELFT>::Dynamic->getFlags()));
AddSec(H, Out<ELFT>::Dynamic);
}
// PT_GNU_RELRO includes all sections that should be marked as
// read-only by dynamic linker after proccessing relocations.
if (RelRo.First)
Phdrs.push_back(std::move(RelRo));
// PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr.
if (Out<ELFT>::EhFrameHdr->Live) {
Phdr &Hdr = *AddHdr(PT_GNU_EH_FRAME,
toPhdrFlags(Out<ELFT>::EhFrameHdr->getFlags()));
AddSec(Hdr, Out<ELFT>::EhFrameHdr);
}
// PT_GNU_STACK is a special section to tell the loader to make the
// pages for the stack non-executable.
if (!Config->ZExecStack)
AddHdr(PT_GNU_STACK, PF_R | PF_W);
}
+// Used for relocatable output (-r). In this case we create only ELF file
+// header, do not create program headers. Also assign of section addresses
+// is very straightforward: we just put all sections sequentually to the file.
+template <class ELFT> void Writer<ELFT>::assignAddressesRelocatable() {
+ Out<ELFT>::ElfHeader->setSize(sizeof(Elf_Ehdr));
+ uintX_t FileOff = 0;
+ for (OutputSectionBase<ELFT> *Sec : OutputSections) {
+ FileOff = alignTo(FileOff, Sec->getAlign());
+ Sec->setFileOffset(FileOff);
+ FileOff += Sec->getSize();
+ }
+ SectionHeaderOff = alignTo(FileOff, sizeof(uintX_t));
+ FileSize = SectionHeaderOff + getNumSections() * sizeof(Elf_Shdr);
+}
+
// Visits all headers in PhdrTable and assigns the adresses to
// the output sections. Also creates common and special headers.
template <class ELFT> void Writer<ELFT>::assignAddresses() {
Out<ELFT>::ElfHeader->setSize(sizeof(Elf_Ehdr));
size_t PhdrSize = sizeof(Elf_Phdr) * Phdrs.size();
Out<ELFT>::ProgramHeaders->setSize(PhdrSize);
// The first section of each PT_LOAD and the first section after PT_GNU_RELRO
// have to be page aligned so that the dynamic linker can set the permissions.
SmallPtrSet<OutputSectionBase<ELFT> *, 4> PageAlign;
for (const Phdr &P : Phdrs) {
if (P.H.p_type == PT_GNU_RELRO) {
// Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we
// have to align it to a page.
auto I = std::find(OutputSections.begin(), OutputSections.end(), P.Last);
++I;
if (I != OutputSections.end() && needsPtLoad(*I))
PageAlign.insert(*I);
}
if (P.H.p_type == PT_LOAD)
PageAlign.insert(P.First);
}
uintX_t ThreadBssOffset = 0;
uintX_t VA = Target->getVAStart();
uintX_t FileOff = 0;
for (OutputSectionBase<ELFT> *Sec : OutputSections) {
uintX_t Align = Sec->getAlign();
if (PageAlign.count(Sec))
Align = std::max<uintX_t>(Align, Target->PageSize);
if (Sec->getType() != SHT_NOBITS)
FileOff = alignTo(FileOff, Align);
Sec->setFileOffset(FileOff);
if (Sec->getType() != SHT_NOBITS)
FileOff += Sec->getSize();
// We only assign VAs to allocated sections.
if (needsPtLoad<ELFT>(Sec)) {
VA = alignTo(VA, Align);
Sec->setVA(VA);
VA += Sec->getSize();
} else if (Sec->getFlags() & SHF_TLS && Sec->getType() == SHT_NOBITS) {
uintX_t TVA = VA + ThreadBssOffset;
TVA = alignTo(TVA, Align);
Sec->setVA(TVA);
ThreadBssOffset = TVA - VA + Sec->getSize();
}
}
// Add space for section headers.
SectionHeaderOff = alignTo(FileOff, sizeof(uintX_t));
FileSize = SectionHeaderOff + getNumSections() * sizeof(Elf_Shdr);
// Update "_end" and "end" symbols so that they
// point to the end of the data segment.
ElfSym<ELFT>::End.st_value = VA;
for (Phdr &PHdr : Phdrs) {
Elf_Phdr &H = PHdr.H;
if (PHdr.First) {
OutputSectionBase<ELFT> *Last = PHdr.Last;
H.p_filesz = Last->getFileOff() - PHdr.First->getFileOff();
if (Last->getType() != SHT_NOBITS)
H.p_filesz += Last->getSize();
H.p_memsz = Last->getVA() + Last->getSize() - PHdr.First->getVA();
H.p_offset = PHdr.First->getFileOff();
H.p_vaddr = PHdr.First->getVA();
}
if (PHdr.H.p_type == PT_LOAD)
H.p_align = Target->PageSize;
else if (PHdr.H.p_type == PT_GNU_RELRO)
H.p_align = 1;
H.p_paddr = H.p_vaddr;
// The TLS pointer goes after PT_TLS. At least glibc will align it,
// so round up the size to make sure the offsets are correct.
if (PHdr.H.p_type == PT_TLS) {
Out<ELFT>::TlsPhdr = &H;
H.p_memsz = alignTo(H.p_memsz, H.p_align);
}
}
}
static uint32_t getELFFlags() {
if (Config->EMachine != EM_MIPS)
return 0;
// FIXME: In fact ELF flags depends on ELF flags of input object files
// and selected emulation. For now just use hard coded values.
uint32_t V = EF_MIPS_ABI_O32 | EF_MIPS_CPIC | EF_MIPS_ARCH_32R2;
if (Config->Shared)
V |= EF_MIPS_PIC;
return V;
}
template <class ELFT>
static typename ELFFile<ELFT>::uintX_t getEntryAddr() {
if (Config->EntrySym) {
if (SymbolBody *B = Config->EntrySym->repl())
return B->getVA<ELFT>();
return 0;
}
if (Config->EntryAddr != uint64_t(-1))
return Config->EntryAddr;
return 0;
}
// This function is called after we have assigned address and size
// to each section. This function fixes some predefined absolute
// symbol values that depend on section address and size.
template <class ELFT> void Writer<ELFT>::fixAbsoluteSymbols() {
// Update __rel[a]_iplt_{start,end} symbols so that they point
// to beginning or ending of .rela.plt section, respectively.
if (Out<ELFT>::RelaPlt) {
uintX_t Start = Out<ELFT>::RelaPlt->getVA();
ElfSym<ELFT>::RelaIpltStart.st_value = Start;
ElfSym<ELFT>::RelaIpltEnd.st_value = Start + Out<ELFT>::RelaPlt->getSize();
}
// Update MIPS _gp absolute symbol so that it points to the static data.
if (Config->EMachine == EM_MIPS)
ElfSym<ELFT>::MipsGp.st_value = getMipsGpAddr<ELFT>();
}
template <class ELFT> void Writer<ELFT>::writeHeader() {
uint8_t *Buf = Buffer->getBufferStart();
memcpy(Buf, "\177ELF", 4);
// Write the ELF header.
auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
EHdr->e_ident[EI_DATA] = ELFT::TargetEndianness == llvm::support::little
? ELFDATA2LSB
: ELFDATA2MSB;
EHdr->e_ident[EI_VERSION] = EV_CURRENT;
auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
EHdr->e_ident[EI_OSABI] = FirstObj.getOSABI();
- EHdr->e_type = Config->Shared ? ET_DYN : ET_EXEC;
+ if (Config->Shared)
+ EHdr->e_type = ET_DYN;
+ else if (Config->Relocatable)
+ EHdr->e_type = ET_REL;
+ else
+ EHdr->e_type = ET_EXEC;
+
EHdr->e_machine = FirstObj.getEMachine();
EHdr->e_version = EV_CURRENT;
EHdr->e_entry = getEntryAddr<ELFT>();
- EHdr->e_phoff = sizeof(Elf_Ehdr);
EHdr->e_shoff = SectionHeaderOff;
EHdr->e_flags = getELFFlags();
EHdr->e_ehsize = sizeof(Elf_Ehdr);
- EHdr->e_phentsize = sizeof(Elf_Phdr);
EHdr->e_phnum = Phdrs.size();
EHdr->e_shentsize = sizeof(Elf_Shdr);
EHdr->e_shnum = getNumSections();
EHdr->e_shstrndx = Out<ELFT>::ShStrTab->SectionIndex;
+ if (!Config->Relocatable) {
+ EHdr->e_phoff = sizeof(Elf_Ehdr);
+ EHdr->e_phentsize = sizeof(Elf_Phdr);
+ }
+
// Write the program header table.
auto *HBuf = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
for (Phdr &P : Phdrs)
*HBuf++ = P.H;
// Write the section header table. Note that the first table entry is null.
auto SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
for (OutputSectionBase<ELFT> *Sec : getSections())
Sec->writeHeaderTo(++SHdrs);
}
template <class ELFT> bool Writer<ELFT>::openFile() {
ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
FileOutputBuffer::create(Config->OutputFile, FileSize,
FileOutputBuffer::F_executable);
if (error(BufferOrErr, "failed to open " + Config->OutputFile))
return false;
Buffer = std::move(*BufferOrErr);
return true;
}
// Write section contents to a mmap'ed file.
template <class ELFT> void Writer<ELFT>::writeSections() {
uint8_t *Buf = Buffer->getBufferStart();
// PPC64 needs to process relocations in the .opd section before processing
// relocations in code-containing sections.
if (OutputSectionBase<ELFT> *Sec = Out<ELFT>::Opd) {
Out<ELFT>::OpdBuf = Buf + Sec->getFileOff();
Sec->writeTo(Buf + Sec->getFileOff());
}
for (OutputSectionBase<ELFT> *Sec : OutputSections)
if (Sec != Out<ELFT>::Opd)
Sec->writeTo(Buf + Sec->getFileOff());
}
template void elf2::writeResult<ELF32LE>(SymbolTable<ELF32LE> *Symtab);
template void elf2::writeResult<ELF32BE>(SymbolTable<ELF32BE> *Symtab);
template void elf2::writeResult<ELF64LE>(SymbolTable<ELF64LE> *Symtab);
template void elf2::writeResult<ELF64BE>(SymbolTable<ELF64BE> *Symtab);
Index: lld/trunk/ELF/OutputSections.h
===================================================================
--- lld/trunk/ELF/OutputSections.h (revision 261837)
+++ lld/trunk/ELF/OutputSections.h (revision 261838)
@@ -1,582 +1,583 @@
//===- OutputSections.h -----------------------------------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_ELF_OUTPUT_SECTIONS_H
#define LLD_ELF_OUTPUT_SECTIONS_H
#include "lld/Core/LLVM.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELF.h"
#include "Config.h"
#include <type_traits>
namespace lld {
namespace elf2 {
class SymbolBody;
template <class ELFT> class SymbolTable;
template <class ELFT> class SymbolTableSection;
template <class ELFT> class StringTableSection;
template <class ELFT> class EHInputSection;
template <class ELFT> class InputSection;
template <class ELFT> class InputSectionBase;
template <class ELFT> class MergeInputSection;
template <class ELFT> class MipsReginfoInputSection;
template <class ELFT> class OutputSection;
template <class ELFT> class ObjectFile;
template <class ELFT> class DefinedRegular;
template <class ELFT>
static inline typename llvm::object::ELFFile<ELFT>::uintX_t
getAddend(const typename llvm::object::ELFFile<ELFT>::Elf_Rel &Rel) {
return 0;
}
template <class ELFT>
static inline typename llvm::object::ELFFile<ELFT>::uintX_t
getAddend(const typename llvm::object::ELFFile<ELFT>::Elf_Rela &Rel) {
return Rel.r_addend;
}
template <class ELFT, bool IsRela>
typename llvm::object::ELFFile<ELFT>::uintX_t
getLocalRelTarget(const ObjectFile<ELFT> &File,
const llvm::object::Elf_Rel_Impl<ELFT, IsRela> &Rel,
typename llvm::object::ELFFile<ELFT>::uintX_t Addend);
bool canBePreempted(const SymbolBody *Body, bool NeedsGot);
// This represents a section in an output file.
// Different sub classes represent different types of sections. Some contain
// input sections, others are created by the linker.
// The writer creates multiple OutputSections and assign them unique,
// non-overlapping file offsets and VAs.
template <class ELFT> class OutputSectionBase {
public:
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
OutputSectionBase(StringRef Name, uint32_t Type, uintX_t Flags);
void setVA(uintX_t VA) { Header.sh_addr = VA; }
uintX_t getVA() const { return Header.sh_addr; }
void setFileOffset(uintX_t Off) { Header.sh_offset = Off; }
void setSHName(unsigned Val) { Header.sh_name = Val; }
void writeHeaderTo(Elf_Shdr *SHdr);
StringRef getName() { return Name; }
virtual void addSection(InputSectionBase<ELFT> *C) {}
unsigned SectionIndex;
// Returns the size of the section in the output file.
uintX_t getSize() const { return Header.sh_size; }
void setSize(uintX_t Val) { Header.sh_size = Val; }
uintX_t getFlags() { return Header.sh_flags; }
uintX_t getFileOff() { return Header.sh_offset; }
uintX_t getAlign() {
// The ELF spec states that a value of 0 means the section has no alignment
// constraits.
return std::max<uintX_t>(Header.sh_addralign, 1);
}
uint32_t getType() { return Header.sh_type; }
void updateAlign(uintX_t Align) {
if (Align > Header.sh_addralign)
Header.sh_addralign = Align;
}
virtual void finalize() {}
virtual void writeTo(uint8_t *Buf) {}
virtual ~OutputSectionBase() = default;
protected:
StringRef Name;
Elf_Shdr Header;
};
template <class ELFT> class GotSection final : public OutputSectionBase<ELFT> {
typedef OutputSectionBase<ELFT> Base;
typedef typename Base::uintX_t uintX_t;
public:
GotSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
void addEntry(SymbolBody *Sym);
void addMipsLocalEntry();
bool addDynTlsEntry(SymbolBody *Sym);
bool addTlsIndex();
bool empty() const { return MipsLocalEntries == 0 && Entries.empty(); }
uintX_t getMipsLocalFullAddr(const SymbolBody &B);
uintX_t getMipsLocalPageAddr(uintX_t Addr);
uintX_t getGlobalDynAddr(const SymbolBody &B) const;
uintX_t getNumEntries() const { return Entries.size(); }
// Returns the symbol which corresponds to the first entry of the global part
// of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic
// table properties.
// Returns nullptr if the global part is empty.
const SymbolBody *getMipsFirstGlobalEntry() const;
// Returns the number of entries in the local part of GOT including
// the number of reserved entries. This method is MIPS-specific.
unsigned getMipsLocalEntriesNum() const;
uintX_t getTlsIndexVA() { return Base::getVA() + TlsIndexOff; }
private:
std::vector<const SymbolBody *> Entries;
uint32_t TlsIndexOff = -1;
uint32_t MipsLocalEntries = 0;
llvm::DenseMap<uintX_t, size_t> MipsLocalGotPos;
uintX_t getMipsLocalEntryAddr(uintX_t EntryValue);
};
template <class ELFT>
class GotPltSection final : public OutputSectionBase<ELFT> {
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
public:
GotPltSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
void addEntry(SymbolBody *Sym);
bool empty() const;
private:
std::vector<const SymbolBody *> Entries;
};
template <class ELFT> class PltSection final : public OutputSectionBase<ELFT> {
typedef OutputSectionBase<ELFT> Base;
typedef typename Base::uintX_t uintX_t;
public:
PltSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
void addEntry(SymbolBody *Sym);
bool empty() const { return Entries.empty(); }
private:
std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
};
template <class ELFT> struct DynamicReloc {
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
uint32_t Type;
// Where the relocation is.
enum OffsetKind {
Off_Got, // The got entry of Sym.
Off_GotPlt, // The got.plt entry of Sym.
Off_Bss, // The bss entry of Sym (copy reloc).
Off_Sec, // The final position of the given input section and offset.
Off_LTlsIndex, // The local tls index.
Off_GTlsIndex, // The global tls index of Sym.
Off_GTlsOffset // The global tls offset of Sym.
} OKind;
SymbolBody *Sym = nullptr;
InputSectionBase<ELFT> *OffsetSec = nullptr;
uintX_t OffsetInSec = 0;
bool UseSymVA = false;
InputSectionBase<ELFT> *TargetSec = nullptr;
uintX_t OffsetInTargetSec = 0;
uintX_t Addend = 0;
DynamicReloc(uint32_t Type, OffsetKind OKind, SymbolBody *Sym)
: Type(Type), OKind(OKind), Sym(Sym) {}
DynamicReloc(uint32_t Type, OffsetKind OKind, bool UseSymVA, SymbolBody *Sym)
: Type(Type), OKind(OKind), Sym(Sym), UseSymVA(UseSymVA) {}
DynamicReloc(uint32_t Type, InputSectionBase<ELFT> *OffsetSec,
uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
uintX_t Addend)
: Type(Type), OKind(Off_Sec), Sym(Sym), OffsetSec(OffsetSec),
OffsetInSec(OffsetInSec), UseSymVA(UseSymVA), Addend(Addend) {}
DynamicReloc(uint32_t Type, InputSectionBase<ELFT> *OffsetSec,
uintX_t OffsetInSec, InputSectionBase<ELFT> *TargetSec,
uintX_t OffsetInTargetSec, uintX_t Addend)
: Type(Type), OKind(Off_Sec), OffsetSec(OffsetSec),
OffsetInSec(OffsetInSec), TargetSec(TargetSec),
OffsetInTargetSec(OffsetInTargetSec), Addend(Addend) {}
uintX_t getOffset() const;
};
template <class ELFT>
class SymbolTableSection final : public OutputSectionBase<ELFT> {
public:
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
SymbolTableSection(SymbolTable<ELFT> &Table,
StringTableSection<ELFT> &StrTabSec);
void finalize() override;
void writeTo(uint8_t *Buf) override;
void addSymbol(SymbolBody *Body);
StringTableSection<ELFT> &getStrTabSec() const { return StrTabSec; }
unsigned getNumSymbols() const { return NumLocals + Symbols.size() + 1; }
ArrayRef<std::pair<SymbolBody *, size_t>> getSymbols() const {
return Symbols;
}
unsigned NumLocals = 0;
StringTableSection<ELFT> &StrTabSec;
private:
void writeLocalSymbols(uint8_t *&Buf);
void writeGlobalSymbols(uint8_t *Buf);
const OutputSectionBase<ELFT> *getOutputSection(SymbolBody *Sym);
static uint8_t getSymbolBinding(SymbolBody *Body);
SymbolTable<ELFT> &Table;
// A vector of symbols and their string table offsets.
std::vector<std::pair<SymbolBody *, size_t>> Symbols;
};
template <class ELFT>
class RelocationSection final : public OutputSectionBase<ELFT> {
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
public:
RelocationSection(StringRef Name, bool IsRela);
void addReloc(const DynamicReloc<ELFT> &Reloc);
unsigned getRelocOffset();
void finalize() override;
void writeTo(uint8_t *Buf) override;
bool hasRelocs() const { return !Relocs.empty(); }
bool isRela() const { return IsRela; }
bool Static = false;
private:
std::vector<DynamicReloc<ELFT>> Relocs;
const bool IsRela;
};
template <class ELFT>
class OutputSection final : public OutputSectionBase<ELFT> {
public:
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
OutputSection(StringRef Name, uint32_t Type, uintX_t Flags);
void addSection(InputSectionBase<ELFT> *C) override;
void sortInitFini();
void sortCtorsDtors();
void writeTo(uint8_t *Buf) override;
+ void finalize() override;
private:
void reassignOffsets();
std::vector<InputSection<ELFT> *> Sections;
};
template <class ELFT>
class MergeOutputSection final : public OutputSectionBase<ELFT> {
typedef typename OutputSectionBase<ELFT>::uintX_t uintX_t;
bool shouldTailMerge() const;
public:
MergeOutputSection(StringRef Name, uint32_t Type, uintX_t Flags,
uintX_t Alignment);
void addSection(InputSectionBase<ELFT> *S) override;
void writeTo(uint8_t *Buf) override;
unsigned getOffset(StringRef Val);
void finalize() override;
private:
llvm::StringTableBuilder Builder;
};
// FDE or CIE
template <class ELFT> struct EHRegion {
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
EHRegion(EHInputSection<ELFT> *S, unsigned Index);
StringRef data() const;
EHInputSection<ELFT> *S;
unsigned Index;
};
template <class ELFT> struct Cie : public EHRegion<ELFT> {
Cie(EHInputSection<ELFT> *S, unsigned Index);
std::vector<EHRegion<ELFT>> Fdes;
uint8_t FdeEncoding;
};
template <class ELFT>
class EHOutputSection final : public OutputSectionBase<ELFT> {
public:
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
EHOutputSection(StringRef Name, uint32_t Type, uintX_t Flags);
void writeTo(uint8_t *Buf) override;
template <bool IsRela>
void addSectionAux(
EHInputSection<ELFT> *S,
llvm::iterator_range<const llvm::object::Elf_Rel_Impl<ELFT, IsRela> *>
Rels);
void addSection(InputSectionBase<ELFT> *S) override;
private:
uint8_t getFdeEncoding(ArrayRef<uint8_t> D);
std::vector<EHInputSection<ELFT> *> Sections;
std::vector<Cie<ELFT>> Cies;
// Maps CIE content + personality to a index in Cies.
llvm::DenseMap<std::pair<StringRef, SymbolBody *>, unsigned> CieMap;
};
template <class ELFT>
class InterpSection final : public OutputSectionBase<ELFT> {
public:
InterpSection();
void writeTo(uint8_t *Buf) override;
};
template <class ELFT>
class StringTableSection final : public OutputSectionBase<ELFT> {
public:
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
StringTableSection(StringRef Name, bool Dynamic);
unsigned addString(StringRef S, bool HashIt = true);
void writeTo(uint8_t *Buf) override;
unsigned getSize() const { return Size; }
void finalize() override { this->Header.sh_size = getSize(); }
bool isDynamic() const { return Dynamic; }
private:
const bool Dynamic;
llvm::DenseMap<StringRef, unsigned> StringMap;
std::vector<StringRef> Strings;
unsigned Size = 1; // ELF string tables start with a NUL byte, so 1.
};
template <class ELFT>
class HashTableSection final : public OutputSectionBase<ELFT> {
typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
public:
HashTableSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
};
// Outputs GNU Hash section. For detailed explanation see:
// https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections
template <class ELFT>
class GnuHashTableSection final : public OutputSectionBase<ELFT> {
typedef typename llvm::object::ELFFile<ELFT>::Elf_Off Elf_Off;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
public:
GnuHashTableSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
// Adds symbols to the hash table.
// Sorts the input to satisfy GNU hash section requirements.
void addSymbols(std::vector<std::pair<SymbolBody *, size_t>> &Symbols);
private:
static unsigned calcNBuckets(unsigned NumHashed);
static unsigned calcMaskWords(unsigned NumHashed);
void writeHeader(uint8_t *&Buf);
void writeBloomFilter(uint8_t *&Buf);
void writeHashTable(uint8_t *Buf);
struct SymbolData {
SymbolBody *Body;
size_t STName;
uint32_t Hash;
};
std::vector<SymbolData> Symbols;
unsigned MaskWords;
unsigned NBuckets;
unsigned Shift2;
};
template <class ELFT>
class DynamicSection final : public OutputSectionBase<ELFT> {
typedef OutputSectionBase<ELFT> Base;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Dyn Elf_Dyn;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
// The .dynamic section contains information for the dynamic linker.
// The section consists of fixed size entries, which consist of
// type and value fields. Value are one of plain integers, symbol
// addresses, or section addresses. This struct represents the entry.
struct Entry {
int32_t Tag;
union {
OutputSectionBase<ELFT> *OutSec;
uint64_t Val;
const SymbolBody *Sym;
};
enum KindT { SecAddr, SymAddr, PlainInt } Kind;
Entry(int32_t Tag, OutputSectionBase<ELFT> *OutSec)
: Tag(Tag), OutSec(OutSec), Kind(SecAddr) {}
Entry(int32_t Tag, uint64_t Val) : Tag(Tag), Val(Val), Kind(PlainInt) {}
Entry(int32_t Tag, const SymbolBody *Sym)
: Tag(Tag), Sym(Sym), Kind(SymAddr) {}
};
// finalize() fills this vector with the section contents. finalize()
// cannot directly create final section contents because when the
// function is called, symbol or section addresses are not fixed yet.
std::vector<Entry> Entries;
public:
DynamicSection(SymbolTable<ELFT> &SymTab);
void finalize() override;
void writeTo(uint8_t *Buf) override;
OutputSectionBase<ELFT> *PreInitArraySec = nullptr;
OutputSectionBase<ELFT> *InitArraySec = nullptr;
OutputSectionBase<ELFT> *FiniArraySec = nullptr;
private:
SymbolTable<ELFT> &SymTab;
};
template <class ELFT>
class MipsReginfoOutputSection final : public OutputSectionBase<ELFT> {
typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
public:
MipsReginfoOutputSection();
void writeTo(uint8_t *Buf) override;
void addSection(InputSectionBase<ELFT> *S) override;
private:
uint32_t GprMask = 0;
};
// --eh-frame-hdr option tells linker to construct a header for all the
// .eh_frame sections. This header is placed to a section named .eh_frame_hdr
// and also to a PT_GNU_EH_FRAME segment.
// At runtime the unwinder then can find all the PT_GNU_EH_FRAME segments by
// calling dl_iterate_phdr.
// This section contains a lookup table for quick binary search of FDEs.
// Detailed info about internals can be found in Ian Lance Taylor's blog:
// http://www.airs.com/blog/archives/460 (".eh_frame")
// http://www.airs.com/blog/archives/462 (".eh_frame_hdr")
template <class ELFT>
class EhFrameHeader final : public OutputSectionBase<ELFT> {
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
public:
EhFrameHeader();
void writeTo(uint8_t *Buf) override;
void addFde(uint8_t Enc, size_t Off, uint8_t *PCRel);
void assignEhFrame(EHOutputSection<ELFT> *Sec);
void reserveFde();
bool Live = false;
private:
struct FdeData {
uint8_t Enc;
size_t Off;
uint8_t *PCRel;
};
uintX_t getFdePc(uintX_t EhVA, const FdeData &F);
EHOutputSection<ELFT> *Sec = nullptr;
std::vector<FdeData> FdeList;
};
// All output sections that are hadnled by the linker specially are
// globally accessible. Writer initializes them, so don't use them
// until Writer is initialized.
template <class ELFT> struct Out {
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Phdr Elf_Phdr;
static DynamicSection<ELFT> *Dynamic;
static EhFrameHeader<ELFT> *EhFrameHdr;
static GnuHashTableSection<ELFT> *GnuHashTab;
static GotPltSection<ELFT> *GotPlt;
static GotSection<ELFT> *Got;
static HashTableSection<ELFT> *HashTab;
static InterpSection<ELFT> *Interp;
static OutputSection<ELFT> *Bss;
static OutputSection<ELFT> *MipsRldMap;
static OutputSectionBase<ELFT> *Opd;
static uint8_t *OpdBuf;
static PltSection<ELFT> *Plt;
static RelocationSection<ELFT> *RelaDyn;
static RelocationSection<ELFT> *RelaPlt;
static StringTableSection<ELFT> *DynStrTab;
static StringTableSection<ELFT> *ShStrTab;
static StringTableSection<ELFT> *StrTab;
static SymbolTableSection<ELFT> *DynSymTab;
static SymbolTableSection<ELFT> *SymTab;
static Elf_Phdr *TlsPhdr;
static OutputSectionBase<ELFT> *ElfHeader;
static OutputSectionBase<ELFT> *ProgramHeaders;
};
template <class ELFT> DynamicSection<ELFT> *Out<ELFT>::Dynamic;
template <class ELFT> EhFrameHeader<ELFT> *Out<ELFT>::EhFrameHdr;
template <class ELFT> GnuHashTableSection<ELFT> *Out<ELFT>::GnuHashTab;
template <class ELFT> GotPltSection<ELFT> *Out<ELFT>::GotPlt;
template <class ELFT> GotSection<ELFT> *Out<ELFT>::Got;
template <class ELFT> HashTableSection<ELFT> *Out<ELFT>::HashTab;
template <class ELFT> InterpSection<ELFT> *Out<ELFT>::Interp;
template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss;
template <class ELFT> OutputSection<ELFT> *Out<ELFT>::MipsRldMap;
template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::Opd;
template <class ELFT> uint8_t *Out<ELFT>::OpdBuf;
template <class ELFT> PltSection<ELFT> *Out<ELFT>::Plt;
template <class ELFT> RelocationSection<ELFT> *Out<ELFT>::RelaDyn;
template <class ELFT> RelocationSection<ELFT> *Out<ELFT>::RelaPlt;
template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::DynStrTab;
template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::ShStrTab;
template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::StrTab;
template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::DynSymTab;
template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::SymTab;
template <class ELFT> typename Out<ELFT>::Elf_Phdr *Out<ELFT>::TlsPhdr;
template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ElfHeader;
template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ProgramHeaders;
} // namespace elf2
} // namespace lld
#endif // LLD_ELF_OUTPUT_SECTIONS_H
Index: lld/trunk/ELF/Options.td
===================================================================
--- lld/trunk/ELF/Options.td (revision 261837)
+++ lld/trunk/ELF/Options.td (revision 261838)
@@ -1,173 +1,174 @@
include "llvm/Option/OptParser.td"
def Bsymbolic: Flag<["-"], "Bsymbolic">,
HelpText<"Bind defined symbols locally">;
def Bsymbolic_functions: Flag<["-"], "Bsymbolic-functions">,
HelpText<"Bind defined function symbols locally">;
def Bdynamic: Flag<["-"], "Bdynamic">,
HelpText<"Link against shared libraries">;
def Bstatic: Flag<["-"], "Bstatic">,
HelpText<"Do not link against shared libraries">;
def L : JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
HelpText<"Directory to search for libraries">;
def O : Joined<["-"], "O">, HelpText<"Optimize">;
def allow_multiple_definition: Flag<["--"], "allow-multiple-definition">,
HelpText<"Allow multiple definitions">;
def allow_shlib_undefined : Flag<["--", "-"], "allow-shlib-undefined">;
def as_needed : Flag<["--"], "as-needed">;
def disable_new_dtags : Flag<["--"], "disable-new-dtags">,
HelpText<"Disable new dynamic tags">;
def discard_all : Flag<["-"], "discard-all">,
HelpText<"Delete all local symbols">;
def discard_locals : Flag<["-"], "discard-locals">,
HelpText<"Delete temporary local symbols">;
def discard_none : Flag<["-"], "discard-none">,
HelpText<"Keep all symbols in the symbol table">;
def dynamic_linker : Separate<["--", "-"], "dynamic-linker">,
HelpText<"Which dynamic linker to use">;
def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">,
HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">;
def enable_new_dtags : Flag<["--"], "enable-new-dtags">,
HelpText<"Enable new dynamic tags">;
def entry : Separate<["--", "-"], "entry">, MetaVarName<"<entry>">,
HelpText<"Name of entry point symbol">;
def export_dynamic : Flag<["--", "-"], "export-dynamic">,
HelpText<"Put symbols in the dynamic symbol table">;
def fini : Separate<["-"], "fini">, MetaVarName<"<symbol>">,
HelpText<"Specify a finalizer function">;
def hash_style : Separate<["--", "-"], "hash-style">,
HelpText<"Specify hash style (sysv, gnu or both)">;
def gc_sections : Flag<["--"], "gc-sections">,
HelpText<"Enable garbage collection of unused sections">;
def init : Separate<["-"], "init">, MetaVarName<"<symbol>">,
HelpText<"Specify an initializer function">;
def l : JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">,
HelpText<"Root name of library to use">;
def m : JoinedOrSeparate<["-"], "m">,
HelpText<"Set target emulation">;
def no_allow_shlib_undefined : Flag<["--"], "no-allow-shlib-undefined">;
def no_as_needed : Flag<["--"], "no-as-needed">;
def no_demangle: Flag<["--"], "no-demangle">,
HelpText<"Demangle symbol names">;
def no_whole_archive : Flag<["--", "-"], "no-whole-archive">,
HelpText<"Restores the default behavior of loading archive members">;
def noinhibit_exec : Flag<["--"], "noinhibit-exec">,
HelpText<"Retain the executable output file whenever it is still usable">;
def no_undefined : Flag<["--"], "no-undefined">,
HelpText<"Report unresolved symbols even if the linker is creating a shared library">;
def o : Separate<["-"], "o">, MetaVarName<"<path>">,
HelpText<"Path to file to write output">;
def print_gc_sections: Flag<["--"], "print-gc-sections">,
HelpText<"List removed unused sections">;
def rpath : Separate<["-"], "rpath">,
HelpText<"Add a DT_RUNPATH to the output">;
-def relocatable : Flag<["--"], "relocatable">;
+def relocatable : Flag<["--"], "relocatable">,
+ HelpText<"Create relocatable object file">;
def script : Separate<["--"], "script">, HelpText<"Read linker script">;
def shared : Flag<["-"], "shared">,
HelpText<"Build a shared object">;
def soname : Joined<["-"], "soname=">,
HelpText<"Set DT_SONAME">;
def strip_all : Flag<["--"], "strip-all">,
HelpText<"Strip all symbols">;
def sysroot : Joined<["--"], "sysroot=">,
HelpText<"Set the system root">;
def undefined : Joined<["--"], "undefined=">,
HelpText<"Force undefined symbol during linking">;
def verbose : Flag<["--"], "verbose">;
def whole_archive : Flag<["--", "-"], "whole-archive">,
HelpText<"Force load of all members in a static library">;
def wrap : Separate<["--", "-"], "wrap">, MetaVarName<"<symbol>">,
HelpText<"Use wrapper functions for symbol">;
def z : JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
HelpText<"Linker option extensions">;
// Aliases
def alias_Bdynamic_call_shared: Flag<["-"], "call_shared">, Alias<Bdynamic>;
def alias_Bdynamic_dy: Flag<["-"], "dy">, Alias<Bdynamic>;
def alias_Bstatic_dn: Flag<["-"], "dn">, Alias<Bstatic>;
def alias_Bstatic_non_shared: Flag<["-"], "non_shared">, Alias<Bstatic>;
def alias_Bstatic_static: Flag<["-"], "static">, Alias<Bstatic>;
def alias_L__library_path : Joined<["--"], "library-path=">, Alias<L>;
def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
def alias_entry_e : Separate<["-"], "e">, Alias<entry>;
def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>;
def alias_fini_fini : Joined<["-"], "fini=">, Alias<fini>;
def alias_hash_style_hash_style : Joined<["--", "-"], "hash-style=">, Alias<hash_style>;
def alias_init_init : Joined<["-"], "init=">, Alias<init>;
def alias_l__library : Joined<["--"], "library=">, Alias<l>;
def alias_o_output : Joined<["--"], "output=">, Alias<o>;
def alias_rpath_rpath : Joined<["-"], "rpath=">, Alias<rpath>;
def alias_relocatable_r : Flag<["-"], "r">, Alias<relocatable>;
def alias_shared_Bshareable : Flag<["-"], "Bshareable">, Alias<shared>;
def alias_soname_h : Separate<["-"], "h">, Alias<soname>;
def alias_soname_soname : Separate<["-"], "soname">, Alias<soname>;
def alias_script_T : Separate<["-"], "T">, Alias<script>;
def alias_strip_all: Flag<["-"], "s">, Alias<strip_all>;
def alias_undefined_u : Separate<["-"], "u">, Alias<undefined>;
def alias_wrap_wrap : Joined<["--", "-"], "wrap=">, Alias<wrap>;
// Our symbol resolution algorithm handles symbols in archive files differently
// than traditional linkers, so we don't need --start-group and --end-group.
// These options are recongized for compatibility but ignored.
def end_group : Flag<["--"], "end-group">;
def end_group_paren: Flag<["-"], ")">;
def start_group : Flag<["--"], "start-group">;
def start_group_paren: Flag<["-"], "(">;
// Options listed below are silently ignored for now for compatibility.
def build_id : Flag<["--"], "build-id">;
def fatal_warnings : Flag<["--"], "fatal-warnings">;
def no_add_needed : Flag<["--"], "no-add-needed">;
def no_fatal_warnings : Flag<["--"], "no-fatal-warnings">;
def no_warn_mismatch : Flag<["--"], "no-warn-mismatch">;
def version_script : Separate<["--"], "version-script">;
def warn_common : Flag<["--"], "warn-common">;
def warn_shared_textrel : Flag<["--"], "warn-shared-textrel">;
def G : Separate<["-"], "G">;
// Aliases for ignored options
def alias_version_script_version_script : Joined<["--"], "version-script=">, Alias<version_script>;
Index: lld/trunk/ELF/InputFiles.cpp
===================================================================
--- lld/trunk/ELF/InputFiles.cpp (revision 261837)
+++ lld/trunk/ELF/InputFiles.cpp (revision 261838)
@@ -1,521 +1,524 @@
//===- 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"
#include "Error.h"
#include "InputSection.h"
#include "Symbols.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Object/IRObjectFile.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::sys::fs;
using namespace lld;
using namespace lld::elf2;
namespace {
class ECRAII {
std::error_code EC;
public:
std::error_code &getEC() { return EC; }
~ECRAII() { fatal(EC); }
};
}
template <class ELFT>
ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef M)
: InputFile(K, M), ELFObj(MB.getBuffer(), ECRAII().getEC()) {}
template <class ELFT>
ELFKind ELFFileBase<ELFT>::getELFKind() {
if (ELFT::TargetEndianness == support::little)
return ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind;
return ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind;
}
template <class ELFT>
typename ELFFileBase<ELFT>::Elf_Sym_Range
ELFFileBase<ELFT>::getSymbolsHelper(bool Local) {
if (!Symtab)
return Elf_Sym_Range(nullptr, nullptr);
Elf_Sym_Range Syms = ELFObj.symbols(Symtab);
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
uint32_t FirstNonLocal = Symtab->sh_info;
if (FirstNonLocal > NumSymbols)
fatal("Invalid sh_info in symbol table");
if (!Local)
return make_range(Syms.begin() + FirstNonLocal, Syms.end());
// +1 to skip over dummy symbol.
return make_range(Syms.begin() + 1, Syms.begin() + FirstNonLocal);
}
template <class ELFT>
uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const {
uint32_t I = Sym.st_shndx;
if (I == ELF::SHN_XINDEX)
return ELFObj.getExtendedSymbolTableIndex(&Sym, Symtab, SymtabSHNDX);
if (I >= ELF::SHN_LORESERVE || I == ELF::SHN_ABS)
return 0;
return I;
}
template <class ELFT> void ELFFileBase<ELFT>::initStringTable() {
if (!Symtab)
return;
ErrorOr<StringRef> StringTableOrErr = ELFObj.getStringTableForSymtab(*Symtab);
fatal(StringTableOrErr);
StringTable = *StringTableOrErr;
}
template <class ELFT>
typename ELFFileBase<ELFT>::Elf_Sym_Range
ELFFileBase<ELFT>::getNonLocalSymbols() {
return getSymbolsHelper(false);
}
template <class ELFT>
elf2::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M)
: ELFFileBase<ELFT>(Base::ObjectKind, M) {}
template <class ELFT>
typename elf2::ObjectFile<ELFT>::Elf_Sym_Range
elf2::ObjectFile<ELFT>::getLocalSymbols() {
return this->getSymbolsHelper(true);
}
template <class ELFT> uint32_t elf2::ObjectFile<ELFT>::getMipsGp0() const {
if (MipsReginfo)
return MipsReginfo->Reginfo->ri_gp_value;
return 0;
}
template <class ELFT>
const typename elf2::ObjectFile<ELFT>::Elf_Sym *
elf2::ObjectFile<ELFT>::getLocalSymbol(uintX_t SymIndex) {
uint32_t FirstNonLocal = this->Symtab->sh_info;
if (SymIndex >= FirstNonLocal)
return nullptr;
Elf_Sym_Range Syms = this->ELFObj.symbols(this->Symtab);
return Syms.begin() + SymIndex;
}
template <class ELFT>
void elf2::ObjectFile<ELFT>::parse(DenseSet<StringRef> &ComdatGroups) {
// Read section and symbol tables.
initializeSections(ComdatGroups);
initializeSymbols();
}
// 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.
template <class ELFT>
StringRef elf2::ObjectFile<ELFT>::getShtGroupSignature(const Elf_Shdr &Sec) {
const ELFFile<ELFT> &Obj = this->ELFObj;
uint32_t SymtabdSectionIndex = Sec.sh_link;
ErrorOr<const Elf_Shdr *> SecOrErr = Obj.getSection(SymtabdSectionIndex);
fatal(SecOrErr);
const Elf_Shdr *SymtabSec = *SecOrErr;
uint32_t SymIndex = Sec.sh_info;
const Elf_Sym *Sym = Obj.getSymbol(SymtabSec, SymIndex);
ErrorOr<StringRef> StringTableOrErr = Obj.getStringTableForSymtab(*SymtabSec);
fatal(StringTableOrErr);
ErrorOr<StringRef> SignatureOrErr = Sym->getName(*StringTableOrErr);
fatal(SignatureOrErr);
return *SignatureOrErr;
}
template <class ELFT>
ArrayRef<typename elf2::ObjectFile<ELFT>::uint32_X>
elf2::ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
const ELFFile<ELFT> &Obj = this->ELFObj;
ErrorOr<ArrayRef<uint32_X>> EntriesOrErr =
Obj.template getSectionContentsAsArray<uint32_X>(&Sec);
fatal(EntriesOrErr);
ArrayRef<uint32_X> Entries = *EntriesOrErr;
if (Entries.empty() || Entries[0] != GRP_COMDAT)
fatal("Unsupported SHT_GROUP format");
return Entries.slice(1);
}
template <class ELFT>
static bool shouldMerge(const typename ELFFile<ELFT>::Elf_Shdr &Sec) {
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
uintX_t Flags = Sec.sh_flags;
if (!(Flags & SHF_MERGE))
return false;
if (Flags & SHF_WRITE)
fatal("Writable SHF_MERGE sections are not supported");
uintX_t EntSize = Sec.sh_entsize;
if (!EntSize || Sec.sh_size % EntSize)
fatal("SHF_MERGE section size must be a multiple of sh_entsize");
// Don't try to merge if the aligment is larger than the sh_entsize and this
// is not SHF_STRINGS.
//
// 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
// sh_entsize.
if (Flags & SHF_STRINGS)
return true;
if (Sec.sh_addralign > EntSize)
return false;
return true;
}
template <class ELFT>
void elf2::ObjectFile<ELFT>::initializeSections(
DenseSet<StringRef> &ComdatGroups) {
uint64_t Size = this->ELFObj.getNumSections();
Sections.resize(Size);
unsigned I = -1;
const ELFFile<ELFT> &Obj = this->ELFObj;
for (const Elf_Shdr &Sec : Obj.sections()) {
++I;
if (Sections[I] == InputSection<ELFT>::Discarded)
continue;
switch (Sec.sh_type) {
case SHT_GROUP:
Sections[I] = InputSection<ELFT>::Discarded;
if (ComdatGroups.insert(getShtGroupSignature(Sec)).second)
continue;
for (uint32_t SecIndex : getShtGroupEntries(Sec)) {
if (SecIndex >= Size)
fatal("Invalid section index in group");
Sections[SecIndex] = InputSection<ELFT>::Discarded;
}
break;
case SHT_SYMTAB:
this->Symtab = &Sec;
break;
case SHT_SYMTAB_SHNDX: {
ErrorOr<ArrayRef<Elf_Word>> ErrorOrTable = Obj.getSHNDXTable(Sec);
fatal(ErrorOrTable);
this->SymtabSHNDX = *ErrorOrTable;
break;
}
case SHT_STRTAB:
case SHT_NULL:
break;
case SHT_RELA:
case SHT_REL: {
uint32_t RelocatedSectionIndex = Sec.sh_info;
if (RelocatedSectionIndex >= Size)
fatal("Invalid relocated section index");
InputSectionBase<ELFT> *RelocatedSection =
Sections[RelocatedSectionIndex];
// 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.
if (RelocatedSection == InputSection<ELFT>::Discarded)
continue;
if (!RelocatedSection)
fatal("Unsupported relocation reference");
- if (auto *S = dyn_cast<InputSection<ELFT>>(RelocatedSection)) {
+ if (Config->Relocatable) {
+ // For -r, relocation sections are handled as regular input sections.
+ Sections[I] = new (Alloc) InputSection<ELFT>(this, &Sec);
+ } else if (auto *S = dyn_cast<InputSection<ELFT>>(RelocatedSection)) {
S->RelocSections.push_back(&Sec);
} else if (auto *S = dyn_cast<EHInputSection<ELFT>>(RelocatedSection)) {
if (S->RelocSection)
fatal("Multiple relocation sections to .eh_frame are not supported");
S->RelocSection = &Sec;
} else {
fatal("Relocations pointing to SHF_MERGE are not supported");
}
break;
}
default:
Sections[I] = createInputSection(Sec);
}
}
}
template <class ELFT>
InputSectionBase<ELFT> *
elf2::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
ErrorOr<StringRef> NameOrErr = this->ELFObj.getSectionName(&Sec);
fatal(NameOrErr);
StringRef Name = *NameOrErr;
// .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")
return InputSection<ELFT>::Discarded;
// A MIPS object file has a special section that contains register
// usage info, which needs to be handled by the linker specially.
if (Config->EMachine == EM_MIPS && Name == ".reginfo") {
MipsReginfo = new (Alloc) MipsReginfoInputSection<ELFT>(this, &Sec);
return MipsReginfo;
}
if (Name == ".eh_frame")
return new (EHAlloc.Allocate()) EHInputSection<ELFT>(this, &Sec);
if (shouldMerge<ELFT>(Sec))
return new (MAlloc.Allocate()) MergeInputSection<ELFT>(this, &Sec);
return new (Alloc) InputSection<ELFT>(this, &Sec);
}
template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSymbols() {
this->initStringTable();
Elf_Sym_Range Syms = this->getNonLocalSymbols();
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
SymbolBodies.reserve(NumSymbols);
for (const Elf_Sym &Sym : Syms)
SymbolBodies.push_back(createSymbolBody(&Sym));
}
template <class ELFT>
InputSectionBase<ELFT> *
elf2::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
uint32_t Index = this->getSectionIndex(Sym);
if (Index == 0)
return nullptr;
if (Index >= Sections.size() || !Sections[Index])
fatal("Invalid section index");
return Sections[Index];
}
template <class ELFT>
SymbolBody *elf2::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
ErrorOr<StringRef> NameOrErr = Sym->getName(this->StringTable);
fatal(NameOrErr);
StringRef Name = *NameOrErr;
switch (Sym->st_shndx) {
case SHN_UNDEF:
return new (Alloc) UndefinedElf<ELFT>(Name, *Sym);
case SHN_COMMON:
return new (Alloc) DefinedCommon(Name, Sym->st_size, Sym->st_value,
Sym->getBinding() == llvm::ELF::STB_WEAK,
Sym->getVisibility());
}
switch (Sym->getBinding()) {
default:
fatal("unexpected binding");
case STB_GLOBAL:
case STB_WEAK:
case STB_GNU_UNIQUE: {
InputSectionBase<ELFT> *Sec = getSection(*Sym);
if (Sec == InputSection<ELFT>::Discarded)
return new (Alloc) UndefinedElf<ELFT>(Name, *Sym);
return new (Alloc) DefinedRegular<ELFT>(Name, *Sym, Sec);
}
}
}
void ArchiveFile::parse() {
ErrorOr<std::unique_ptr<Archive>> FileOrErr = Archive::create(MB);
fatal(FileOrErr, "Failed to parse archive");
File = std::move(*FileOrErr);
// Allocate a buffer for Lazy objects.
size_t NumSyms = File->getNumberOfSymbols();
LazySymbols.reserve(NumSyms);
// Read the symbol table to construct Lazy objects.
for (const Archive::Symbol &Sym : File->symbols())
LazySymbols.emplace_back(this, Sym);
}
// Returns a buffer pointing to a member file containing a given symbol.
MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) {
ErrorOr<Archive::Child> COrErr = Sym->getMember();
fatal(COrErr, "Could not get the member for symbol " + Sym->getName());
const Archive::Child &C = *COrErr;
if (!Seen.insert(C.getChildOffset()).second)
return MemoryBufferRef();
ErrorOr<MemoryBufferRef> RefOrErr = C.getMemoryBufferRef();
if (!RefOrErr)
fatal(RefOrErr, "Could not get the buffer for the member defining symbol " +
Sym->getName());
return *RefOrErr;
}
template <class ELFT>
SharedFile<ELFT>::SharedFile(MemoryBufferRef M)
: ELFFileBase<ELFT>(Base::SharedKind, M), AsNeeded(Config->AsNeeded) {}
template <class ELFT>
const typename ELFFile<ELFT>::Elf_Shdr *
SharedFile<ELFT>::getSection(const Elf_Sym &Sym) const {
uint32_t Index = this->getSectionIndex(Sym);
if (Index == 0)
return nullptr;
ErrorOr<const Elf_Shdr *> Ret = this->ELFObj.getSection(Index);
fatal(Ret);
return *Ret;
}
// Partially parse the shared object file so that we can call
// getSoName on this object.
template <class ELFT> void SharedFile<ELFT>::parseSoName() {
typedef typename ELFFile<ELFT>::Elf_Dyn Elf_Dyn;
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
const Elf_Shdr *DynamicSec = nullptr;
const ELFFile<ELFT> Obj = this->ELFObj;
for (const Elf_Shdr &Sec : Obj.sections()) {
switch (Sec.sh_type) {
default:
continue;
case SHT_DYNSYM:
this->Symtab = &Sec;
break;
case SHT_DYNAMIC:
DynamicSec = &Sec;
break;
case SHT_SYMTAB_SHNDX: {
ErrorOr<ArrayRef<Elf_Word>> ErrorOrTable = Obj.getSHNDXTable(Sec);
fatal(ErrorOrTable);
this->SymtabSHNDX = *ErrorOrTable;
break;
}
}
}
this->initStringTable();
SoName = this->getName();
if (!DynamicSec)
return;
auto *Begin =
reinterpret_cast<const Elf_Dyn *>(Obj.base() + DynamicSec->sh_offset);
const Elf_Dyn *End = Begin + DynamicSec->sh_size / sizeof(Elf_Dyn);
for (const Elf_Dyn &Dyn : make_range(Begin, End)) {
if (Dyn.d_tag == DT_SONAME) {
uintX_t Val = Dyn.getVal();
if (Val >= this->StringTable.size())
fatal("Invalid DT_SONAME entry");
SoName = StringRef(this->StringTable.data() + Val);
return;
}
}
}
// Fully parse the shared object file. This must be called after parseSoName().
template <class ELFT> void SharedFile<ELFT>::parseRest() {
Elf_Sym_Range Syms = this->getNonLocalSymbols();
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
SymbolBodies.reserve(NumSymbols);
for (const Elf_Sym &Sym : Syms) {
ErrorOr<StringRef> NameOrErr = Sym.getName(this->StringTable);
fatal(NameOrErr.getError());
StringRef Name = *NameOrErr;
if (Sym.isUndefined())
Undefs.push_back(Name);
else
SymbolBodies.emplace_back(this, Name, Sym);
}
}
BitcodeFile::BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {}
bool BitcodeFile::classof(const InputFile *F) {
return F->kind() == BitcodeKind;
}
void BitcodeFile::parse() {
LLVMContext Context;
ErrorOr<std::unique_ptr<IRObjectFile>> ObjOrErr =
IRObjectFile::create(MB, Context);
fatal(ObjOrErr);
IRObjectFile &Obj = **ObjOrErr;
for (const BasicSymbolRef &Sym : Obj.symbols()) {
SmallString<64> Name;
raw_svector_ostream OS(Name);
Sym.printName(OS);
StringRef NameRef = Saver.save(StringRef(Name));
SymbolBody *Body;
if (Sym.getFlags() & object::BasicSymbolRef::SF_Undefined)
Body = new (Alloc) Undefined(NameRef, false, STV_DEFAULT, false);
else
Body = new (Alloc) DefinedBitcode(NameRef);
SymbolBodies.push_back(Body);
}
}
template <typename T>
static std::unique_ptr<InputFile> createELFFileAux(MemoryBufferRef MB) {
std::unique_ptr<T> Ret = llvm::make_unique<T>(MB);
if (!Config->FirstElf)
Config->FirstElf = Ret.get();
if (Config->EKind == ELFNoneKind) {
Config->EKind = Ret->getELFKind();
Config->EMachine = Ret->getEMachine();
}
return std::move(Ret);
}
template <template <class> class T>
static std::unique_ptr<InputFile> createELFFile(MemoryBufferRef MB) {
std::pair<unsigned char, unsigned char> Type = getElfArchType(MB.getBuffer());
if (Type.second != ELF::ELFDATA2LSB && Type.second != ELF::ELFDATA2MSB)
fatal("Invalid data encoding: " + MB.getBufferIdentifier());
if (Type.first == ELF::ELFCLASS32) {
if (Type.second == ELF::ELFDATA2LSB)
return createELFFileAux<T<ELF32LE>>(MB);
return createELFFileAux<T<ELF32BE>>(MB);
}
if (Type.first == ELF::ELFCLASS64) {
if (Type.second == ELF::ELFDATA2LSB)
return createELFFileAux<T<ELF64LE>>(MB);
return createELFFileAux<T<ELF64BE>>(MB);
}
fatal("Invalid file class: " + MB.getBufferIdentifier());
}
std::unique_ptr<InputFile> elf2::createObjectFile(MemoryBufferRef MB,
StringRef ArchiveName) {
using namespace sys::fs;
std::unique_ptr<InputFile> F;
if (identify_magic(MB.getBuffer()) == file_magic::bitcode)
F.reset(new BitcodeFile(MB));
else
F = createELFFile<ObjectFile>(MB);
F->ArchiveName = ArchiveName;
return F;
}
std::unique_ptr<InputFile> elf2::createSharedFile(MemoryBufferRef MB) {
return createELFFile<SharedFile>(MB);
}
template class elf2::ELFFileBase<ELF32LE>;
template class elf2::ELFFileBase<ELF32BE>;
template class elf2::ELFFileBase<ELF64LE>;
template class elf2::ELFFileBase<ELF64BE>;
template class elf2::ObjectFile<ELF32LE>;
template class elf2::ObjectFile<ELF32BE>;
template class elf2::ObjectFile<ELF64LE>;
template class elf2::ObjectFile<ELF64BE>;
template class elf2::SharedFile<ELF32LE>;
template class elf2::SharedFile<ELF32BE>;
template class elf2::SharedFile<ELF64LE>;
template class elf2::SharedFile<ELF64BE>;
Index: lld/trunk/ELF/InputSection.cpp
===================================================================
--- lld/trunk/ELF/InputSection.cpp (revision 261837)
+++ lld/trunk/ELF/InputSection.cpp (revision 261838)
@@ -1,405 +1,454 @@
//===- InputSection.cpp ---------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "InputSection.h"
#include "Config.h"
#include "Error.h"
#include "InputFiles.h"
#include "OutputSections.h"
#include "Target.h"
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace lld;
using namespace lld::elf2;
template <class ELFT>
InputSectionBase<ELFT>::InputSectionBase(ObjectFile<ELFT> *File,
const Elf_Shdr *Header,
Kind SectionKind)
: Header(Header), File(File), SectionKind(SectionKind) {
// The garbage collector sets sections' Live bits.
// If GC is disabled, all sections are considered live by default.
Live = !Config->GcSections;
// The ELF spec states that a value of 0 means the section has
// no alignment constraits.
Align = std::max<uintX_t>(Header->sh_addralign, 1);
}
template <class ELFT> StringRef InputSectionBase<ELFT>::getSectionName() const {
ErrorOr<StringRef> Name = File->getObj().getSectionName(this->Header);
fatal(Name);
return *Name;
}
template <class ELFT>
ArrayRef<uint8_t> InputSectionBase<ELFT>::getSectionData() const {
ErrorOr<ArrayRef<uint8_t>> Ret =
this->File->getObj().getSectionContents(this->Header);
fatal(Ret);
return *Ret;
}
template <class ELFT>
typename ELFFile<ELFT>::uintX_t
InputSectionBase<ELFT>::getOffset(uintX_t Offset) {
switch (SectionKind) {
case Regular:
return cast<InputSection<ELFT>>(this)->OutSecOff + Offset;
case EHFrame:
return cast<EHInputSection<ELFT>>(this)->getOffset(Offset);
case Merge:
return cast<MergeInputSection<ELFT>>(this)->getOffset(Offset);
case MipsReginfo:
// MIPS .reginfo sections are consumed by the linker,
// so it should never be copied to output.
llvm_unreachable("MIPS .reginfo reached writeTo().");
}
llvm_unreachable("Invalid section kind");
}
template <class ELFT>
typename ELFFile<ELFT>::uintX_t
InputSectionBase<ELFT>::getOffset(const Elf_Sym &Sym) {
return getOffset(Sym.st_value);
}
// Returns a section that Rel relocation is pointing to.
template <class ELFT>
InputSectionBase<ELFT> *
InputSectionBase<ELFT>::getRelocTarget(const Elf_Rel &Rel) const {
// Global symbol
uint32_t SymIndex = Rel.getSymbol(Config->Mips64EL);
if (SymbolBody *B = File->getSymbolBody(SymIndex))
if (auto *D = dyn_cast<DefinedRegular<ELFT>>(B->repl()))
return D->Section;
// Local symbol
if (const Elf_Sym *Sym = File->getLocalSymbol(SymIndex))
if (InputSectionBase<ELFT> *Sec = File->getSection(*Sym))
return Sec;
return nullptr;
}
template <class ELFT>
InputSectionBase<ELFT> *
InputSectionBase<ELFT>::getRelocTarget(const Elf_Rela &Rel) const {
return getRelocTarget(reinterpret_cast<const Elf_Rel &>(Rel));
}
template <class ELFT>
InputSection<ELFT>::InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header)
: InputSectionBase<ELFT>(F, Header, Base::Regular) {}
template <class ELFT>
bool InputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
return S->SectionKind == Base::Regular;
}
template <class ELFT>
+InputSectionBase<ELFT> *InputSection<ELFT>::getRelocatedSection() {
+ assert(this->Header->sh_type == SHT_RELA || this->Header->sh_type == SHT_REL);
+ ArrayRef<InputSectionBase<ELFT> *> Sections = this->File->getSections();
+ return Sections[this->Header->sh_info];
+}
+
+// This is used for -r. We can't use memcpy to copy relocations because we need
+// to update symbol table offset and section index for each relocation. So we
+// copy relocations one by one.
+template <class ELFT>
+template <bool isRela>
+void InputSection<ELFT>::copyRelocations(uint8_t *Buf,
+ RelIteratorRange<isRela> Rels) {
+ typedef Elf_Rel_Impl<ELFT, isRela> RelType;
+ InputSectionBase<ELFT> *RelocatedSection = getRelocatedSection();
+
+ for (const RelType &Rel : Rels) {
+ uint32_t SymIndex = Rel.getSymbol(Config->Mips64EL);
+ uint32_t Type = Rel.getType(Config->Mips64EL);
+ const Elf_Shdr *SymTab = this->File->getSymbolTable();
+
+ RelType *P = reinterpret_cast<RelType *>(Buf);
+ Buf += sizeof(RelType);
+
+ // Relocation for local symbol here means that it is probably
+ // rel[a].eh_frame section which has references to
+ // sections in r_info field. Also needs fix for addend.
+ if (SymIndex < SymTab->sh_info)
+ fatal("Relocation against local symbols is not supported yet");
+
+ SymbolBody *Body = this->File->getSymbolBody(SymIndex)->repl();
+ P->r_offset = RelocatedSection->getOffset(Rel.r_offset);
+ P->setSymbolAndType(Body->DynsymIndex, Type, Config->Mips64EL);
+ }
+}
+
+template <class ELFT>
template <bool isRela>
uint8_t *
InputSectionBase<ELFT>::findMipsPairedReloc(uint8_t *Buf, uint32_t SymIndex,
uint32_t Type,
RelIteratorRange<isRela> Rels) {
// Some MIPS relocations use addend calculated from addend of the relocation
// itself and addend of paired relocation. ABI requires to compute such
// combined addend in case of REL relocation record format only.
// See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
if (isRela || Config->EMachine != EM_MIPS)
return nullptr;
if (Type == R_MIPS_HI16)
Type = R_MIPS_LO16;
else if (Type == R_MIPS_PCHI16)
Type = R_MIPS_PCLO16;
else if (Type == R_MICROMIPS_HI16)
Type = R_MICROMIPS_LO16;
else
return nullptr;
for (const auto &RI : Rels) {
if (RI.getType(Config->Mips64EL) != Type)
continue;
if (RI.getSymbol(Config->Mips64EL) != SymIndex)
continue;
uintX_t Offset = getOffset(RI.r_offset);
if (Offset == (uintX_t)-1)
return nullptr;
return Buf + Offset;
}
return nullptr;
}
template <class ELFT>
template <bool isRela>
void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
RelIteratorRange<isRela> Rels) {
typedef Elf_Rel_Impl<ELFT, isRela> RelType;
size_t Num = Rels.end() - Rels.begin();
for (size_t I = 0; I < Num; ++I) {
const RelType &RI = *(Rels.begin() + I);
uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
uint32_t Type = RI.getType(Config->Mips64EL);
uintX_t Offset = getOffset(RI.r_offset);
if (Offset == (uintX_t)-1)
continue;
uint8_t *BufLoc = Buf + Offset;
uintX_t AddrLoc = OutSec->getVA() + Offset;
auto NextRelocs = llvm::make_range(&RI, Rels.end());
if (Target->isTlsLocalDynamicRel(Type) &&
!Target->canRelaxTls(Type, nullptr)) {
Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
Out<ELFT>::Got->getTlsIndexVA() +
getAddend<ELFT>(RI));
continue;
}
const Elf_Shdr *SymTab = File->getSymbolTable();
SymbolBody *Body = nullptr;
if (SymIndex >= SymTab->sh_info)
Body = File->getSymbolBody(SymIndex)->repl();
if (Target->canRelaxTls(Type, Body)) {
uintX_t SymVA;
if (!Body)
SymVA = getLocalRelTarget(*File, RI, 0);
else if (Target->needsGot(Type, *Body))
SymVA = Body->getGotVA<ELFT>();
else
SymVA = Body->getVA<ELFT>();
// By optimizing TLS relocations, it is sometimes needed to skip
// relocations that immediately follow TLS relocations. This function
// knows how many slots we need to skip.
I += Target->relaxTls(BufLoc, BufEnd, Type, AddrLoc, SymVA, Body);
continue;
}
// Handle relocations for local symbols -- they never get
// resolved so we don't allocate a SymbolBody.
uintX_t A = getAddend<ELFT>(RI);
if (!Body) {
uintX_t SymVA = getLocalRelTarget(*File, RI, A);
if (Config->EMachine == EM_MIPS) {
if (Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32)
// We need to adjust SymVA value in case of R_MIPS_GPREL16/32
// relocations because they use the following expression to calculate
// the relocation's result for local symbol: S + A + GP0 - G.
SymVA += File->getMipsGp0();
else if (Type == R_MIPS_GOT16)
// R_MIPS_GOT16 relocation against local symbol requires index of
// a local GOT entry which contains page address corresponds
// to the symbol address.
SymVA = Out<ELFT>::Got->getMipsLocalPageAddr(SymVA);
}
Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0,
findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs));
continue;
}
if (Target->isTlsGlobalDynamicRel(Type) &&
!Target->canRelaxTls(Type, Body)) {
Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
Out<ELFT>::Got->getGlobalDynAddr(*Body) +
getAddend<ELFT>(RI));
continue;
}
uintX_t SymVA = Body->getVA<ELFT>();
if (Target->needsPlt<ELFT>(Type, *Body)) {
SymVA = Body->getPltVA<ELFT>();
} else if (Target->needsGot(Type, *Body)) {
if (Config->EMachine == EM_MIPS && !canBePreempted(Body, true))
// Under some conditions relocations against non-local symbols require
// entries in the local part of MIPS GOT. In that case we need an entry
// initialized by full address of the symbol.
SymVA = Out<ELFT>::Got->getMipsLocalFullAddr(*Body);
else
SymVA = Body->getGotVA<ELFT>();
if (Body->IsTls)
Type = Target->getTlsGotRel(Type);
} else if (!Target->needsCopyRel<ELFT>(Type, *Body) &&
isa<SharedSymbol<ELFT>>(*Body)) {
continue;
} else if (Target->isTlsDynRel(Type, *Body)) {
continue;
} else if (Target->isSizeRel(Type) && canBePreempted(Body, false)) {
// A SIZE relocation is supposed to set a symbol size, but if a symbol
// can be preempted, the size at runtime may be different than link time.
// If that's the case, we leave the field alone rather than filling it
// with a possibly incorrect value.
continue;
} else if (Config->EMachine == EM_MIPS) {
if (Type == R_MIPS_HI16 && Body == Config->MipsGpDisp)
SymVA = getMipsGpAddr<ELFT>() - AddrLoc;
else if (Type == R_MIPS_LO16 && Body == Config->MipsGpDisp)
SymVA = getMipsGpAddr<ELFT>() - AddrLoc + 4;
else if (Body == Config->MipsLocalGp)
SymVA = getMipsGpAddr<ELFT>();
}
uintX_t Size = Body->getSize<ELFT>();
Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA + A, Size + A,
findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs));
}
}
template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
if (this->Header->sh_type == SHT_NOBITS)
return;
// Copy section contents from source object file to output file.
ArrayRef<uint8_t> Data = this->getSectionData();
+ ELFFile<ELFT> &EObj = this->File->getObj();
+
+ // That happens with -r. In that case we need fix the relocation position and
+ // target. No relocations are applied.
+ if (this->Header->sh_type == SHT_RELA) {
+ this->copyRelocations(Buf + OutSecOff, EObj.relas(this->Header));
+ return;
+ }
+ if (this->Header->sh_type == SHT_REL) {
+ this->copyRelocations(Buf + OutSecOff, EObj.rels(this->Header));
+ return;
+ }
+
memcpy(Buf + OutSecOff, Data.data(), Data.size());
- ELFFile<ELFT> &EObj = this->File->getObj();
uint8_t *BufEnd = Buf + OutSecOff + Data.size();
// Iterate over all relocation sections that apply to this section.
for (const Elf_Shdr *RelSec : this->RelocSections) {
if (RelSec->sh_type == SHT_RELA)
this->relocate(Buf, BufEnd, EObj.relas(RelSec));
else
this->relocate(Buf, BufEnd, EObj.rels(RelSec));
}
}
template <class ELFT>
SplitInputSection<ELFT>::SplitInputSection(
ObjectFile<ELFT> *File, const Elf_Shdr *Header,
typename InputSectionBase<ELFT>::Kind SectionKind)
: InputSectionBase<ELFT>(File, Header, SectionKind) {}
template <class ELFT>
EHInputSection<ELFT>::EHInputSection(ObjectFile<ELFT> *F,
const Elf_Shdr *Header)
: SplitInputSection<ELFT>(F, Header, InputSectionBase<ELFT>::EHFrame) {
// Mark .eh_frame sections as live by default because there are
// usually no relocations that point to .eh_frames. Otherwise,
// the garbage collector would drop all .eh_frame sections.
this->Live = true;
}
template <class ELFT>
bool EHInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
return S->SectionKind == InputSectionBase<ELFT>::EHFrame;
}
template <class ELFT>
typename EHInputSection<ELFT>::uintX_t
EHInputSection<ELFT>::getOffset(uintX_t Offset) {
// The file crtbeginT.o has relocations pointing to the start of an empty
// .eh_frame that is known to be the first in the link. It does that to
// identify the start of the output .eh_frame. Handle this special case.
if (this->getSectionHdr()->sh_size == 0)
return Offset;
std::pair<uintX_t, uintX_t> *I = this->getRangeAndSize(Offset).first;
uintX_t Base = I->second;
if (Base == uintX_t(-1))
return -1; // Not in the output
uintX_t Addend = Offset - I->first;
return Base + Addend;
}
template <class ELFT>
MergeInputSection<ELFT>::MergeInputSection(ObjectFile<ELFT> *F,
const Elf_Shdr *Header)
: SplitInputSection<ELFT>(F, Header, InputSectionBase<ELFT>::Merge) {}
template <class ELFT>
bool MergeInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
return S->SectionKind == InputSectionBase<ELFT>::Merge;
}
template <class ELFT>
std::pair<std::pair<typename ELFFile<ELFT>::uintX_t,
typename ELFFile<ELFT>::uintX_t> *,
typename ELFFile<ELFT>::uintX_t>
SplitInputSection<ELFT>::getRangeAndSize(uintX_t Offset) {
ArrayRef<uint8_t> D = this->getSectionData();
StringRef Data((const char *)D.data(), D.size());
uintX_t Size = Data.size();
if (Offset >= Size)
fatal("Entry is past the end of the section");
// Find the element this offset points to.
auto I = std::upper_bound(
Offsets.begin(), Offsets.end(), Offset,
[](const uintX_t &A, const std::pair<uintX_t, uintX_t> &B) {
return A < B.first;
});
uintX_t End = I == Offsets.end() ? Data.size() : I->first;
--I;
return std::make_pair(&*I, End);
}
template <class ELFT>
typename MergeInputSection<ELFT>::uintX_t
MergeInputSection<ELFT>::getOffset(uintX_t Offset) {
std::pair<std::pair<uintX_t, uintX_t> *, uintX_t> T =
this->getRangeAndSize(Offset);
std::pair<uintX_t, uintX_t> *I = T.first;
uintX_t End = T.second;
uintX_t Start = I->first;
// Compute the Addend and if the Base is cached, return.
uintX_t Addend = Offset - Start;
uintX_t &Base = I->second;
if (Base != uintX_t(-1))
return Base + Addend;
// Map the base to the offset in the output section and cache it.
ArrayRef<uint8_t> D = this->getSectionData();
StringRef Data((const char *)D.data(), D.size());
StringRef Entry = Data.substr(Start, End - Start);
Base =
static_cast<MergeOutputSection<ELFT> *>(this->OutSec)->getOffset(Entry);
return Base + Addend;
}
template <class ELFT>
MipsReginfoInputSection<ELFT>::MipsReginfoInputSection(ObjectFile<ELFT> *F,
const Elf_Shdr *Hdr)
: InputSectionBase<ELFT>(F, Hdr, InputSectionBase<ELFT>::MipsReginfo) {
// Initialize this->Reginfo.
ArrayRef<uint8_t> D = this->getSectionData();
if (D.size() != sizeof(Elf_Mips_RegInfo<ELFT>))
fatal("Invalid size of .reginfo section");
Reginfo = reinterpret_cast<const Elf_Mips_RegInfo<ELFT> *>(D.data());
}
template <class ELFT>
bool MipsReginfoInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
return S->SectionKind == InputSectionBase<ELFT>::MipsReginfo;
}
template class elf2::InputSectionBase<ELF32LE>;
template class elf2::InputSectionBase<ELF32BE>;
template class elf2::InputSectionBase<ELF64LE>;
template class elf2::InputSectionBase<ELF64BE>;
template class elf2::InputSection<ELF32LE>;
template class elf2::InputSection<ELF32BE>;
template class elf2::InputSection<ELF64LE>;
template class elf2::InputSection<ELF64BE>;
template class elf2::EHInputSection<ELF32LE>;
template class elf2::EHInputSection<ELF32BE>;
template class elf2::EHInputSection<ELF64LE>;
template class elf2::EHInputSection<ELF64BE>;
template class elf2::MergeInputSection<ELF32LE>;
template class elf2::MergeInputSection<ELF32BE>;
template class elf2::MergeInputSection<ELF64LE>;
template class elf2::MergeInputSection<ELF64BE>;
template class elf2::MipsReginfoInputSection<ELF32LE>;
template class elf2::MipsReginfoInputSection<ELF32BE>;
template class elf2::MipsReginfoInputSection<ELF64LE>;
template class elf2::MipsReginfoInputSection<ELF64BE>;
Index: lld/trunk/ELF/InputSection.h
===================================================================
--- lld/trunk/ELF/InputSection.h (revision 261837)
+++ lld/trunk/ELF/InputSection.h (revision 261838)
@@ -1,183 +1,193 @@
//===- InputSection.h -------------------------------------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_ELF_INPUT_SECTION_H
#define LLD_ELF_INPUT_SECTION_H
#include "Config.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Object/ELF.h"
namespace lld {
namespace elf2 {
template <class ELFT> class ObjectFile;
template <class ELFT> class OutputSection;
template <class ELFT> class OutputSectionBase;
// This corresponds to a section of an input file.
template <class ELFT> class InputSectionBase {
protected:
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
const Elf_Shdr *Header;
// The file this section is from.
ObjectFile<ELFT> *File;
public:
enum Kind { Regular, EHFrame, Merge, MipsReginfo };
Kind SectionKind;
InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
Kind SectionKind);
OutputSectionBase<ELFT> *OutSec = nullptr;
uint32_t Align = 1;
// Used for garbage collection.
bool Live = false;
// Returns the size of this section (even if this is a common or BSS.)
size_t getSize() const { return Header->sh_size; }
static InputSectionBase<ELFT> *Discarded;
StringRef getSectionName() const;
const Elf_Shdr *getSectionHdr() const { return Header; }
ObjectFile<ELFT> *getFile() const { return File; }
uintX_t getOffset(const Elf_Sym &Sym);
// Translate an offset in the input section to an offset in the output
// section.
uintX_t getOffset(uintX_t Offset);
ArrayRef<uint8_t> getSectionData() const;
// Returns a section that Rel is pointing to. Used by the garbage collector.
InputSectionBase<ELFT> *getRelocTarget(const Elf_Rel &Rel) const;
InputSectionBase<ELFT> *getRelocTarget(const Elf_Rela &Rel) const;
template <bool isRela>
using RelIteratorRange =
llvm::iterator_range<const llvm::object::Elf_Rel_Impl<ELFT, isRela> *>;
template <bool isRela>
void relocate(uint8_t *Buf, uint8_t *BufEnd, RelIteratorRange<isRela> Rels);
private:
template <bool isRela>
uint8_t *findMipsPairedReloc(uint8_t *Buf, uint32_t SymIndex, uint32_t Type,
RelIteratorRange<isRela> Rels);
};
template <class ELFT>
InputSectionBase<ELFT> *
InputSectionBase<ELFT>::Discarded = (InputSectionBase<ELFT> *)-1ULL;
// Usually sections are copied to the output as atomic chunks of data,
// but some special types of sections are split into small pieces of data
// and each piece is copied to a different place in the output.
// This class represents such special sections.
template <class ELFT> class SplitInputSection : public InputSectionBase<ELFT> {
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
public:
SplitInputSection(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
typename InputSectionBase<ELFT>::Kind SectionKind);
// For each piece of data, we maintain the offsets in the input section and
// in the output section. The latter may be -1 if it is not assigned yet.
std::vector<std::pair<uintX_t, uintX_t>> Offsets;
std::pair<std::pair<uintX_t, uintX_t> *, uintX_t>
getRangeAndSize(uintX_t Offset);
};
// This corresponds to a SHF_MERGE section of an input file.
template <class ELFT> class MergeInputSection : public SplitInputSection<ELFT> {
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
public:
MergeInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
static bool classof(const InputSectionBase<ELFT> *S);
// Translate an offset in the input section to an offset in the output
// section.
uintX_t getOffset(uintX_t Offset);
};
// This corresponds to a .eh_frame section of an input file.
template <class ELFT> class EHInputSection : public SplitInputSection<ELFT> {
public:
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
EHInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
static bool classof(const InputSectionBase<ELFT> *S);
// Translate an offset in the input section to an offset in the output
// section.
uintX_t getOffset(uintX_t Offset);
// Relocation section that refer to this one.
const Elf_Shdr *RelocSection = nullptr;
};
// This corresponds to a non SHF_MERGE section of an input file.
template <class ELFT> class InputSection : public InputSectionBase<ELFT> {
typedef InputSectionBase<ELFT> Base;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
public:
InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
// Write this section to a mmap'ed file, assuming Buf is pointing to
// beginning of the output section.
void writeTo(uint8_t *Buf);
// Relocation sections that refer to this one.
llvm::TinyPtrVector<const Elf_Shdr *> RelocSections;
// The offset from beginning of the output sections this section was assigned
// to. The writer sets a value.
uint64_t OutSecOff = 0;
static bool classof(const InputSectionBase<ELFT> *S);
+
+ InputSectionBase<ELFT> *getRelocatedSection();
+
+private:
+ template <bool isRela>
+ using RelIteratorRange =
+ llvm::iterator_range<const llvm::object::Elf_Rel_Impl<ELFT, isRela> *>;
+
+ template <bool isRela>
+ void copyRelocations(uint8_t *Buf, RelIteratorRange<isRela> Rels);
};
// MIPS .reginfo section provides information on the registers used by the code
// in the object file. Linker should collect this information and write a single
// .reginfo section in the output file. The output section contains a union of
// used registers masks taken from input .reginfo sections and final value
// of the `_gp` symbol. For details: Chapter 4 / "Register Information" at
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
template <class ELFT>
class MipsReginfoInputSection : public InputSectionBase<ELFT> {
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
public:
MipsReginfoInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Hdr);
static bool classof(const InputSectionBase<ELFT> *S);
const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo;
};
} // namespace elf2
} // namespace lld
#endif
Index: lld/trunk/ELF/Driver.cpp
===================================================================
--- lld/trunk/ELF/Driver.cpp (revision 261837)
+++ lld/trunk/ELF/Driver.cpp (revision 261838)
@@ -1,374 +1,379 @@
//===- Driver.cpp ---------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Driver.h"
#include "Config.h"
#include "Error.h"
#include "InputFiles.h"
#include "LinkerScript.h"
#include "SymbolTable.h"
#include "Target.h"
#include "Writer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include <utility>
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace lld;
using namespace lld::elf2;
Configuration *elf2::Config;
LinkerDriver *elf2::Driver;
bool elf2::link(ArrayRef<const char *> Args, raw_ostream &Error) {
HasError = false;
ErrorOS = &Error;
Configuration C;
LinkerDriver D;
LinkerScript LS;
Config = &C;
Driver = &D;
Script = &LS;
Driver->main(Args.slice(1));
return !HasError;
}
static std::pair<ELFKind, uint16_t> parseEmulation(StringRef S) {
if (S == "elf32btsmip")
return {ELF32BEKind, EM_MIPS};
if (S == "elf32ltsmip")
return {ELF32LEKind, EM_MIPS};
if (S == "elf32ppc" || S == "elf32ppc_fbsd")
return {ELF32BEKind, EM_PPC};
if (S == "elf64ppc" || S == "elf64ppc_fbsd")
return {ELF64BEKind, EM_PPC64};
if (S == "elf_i386")
return {ELF32LEKind, EM_386};
if (S == "elf_x86_64")
return {ELF64LEKind, EM_X86_64};
if (S == "aarch64linux")
return {ELF64LEKind, EM_AARCH64};
if (S == "i386pe" || S == "i386pep" || S == "thumb2pe")
error("Windows targets are not supported on the ELF frontend: " + S);
else
error("Unknown emulation: " + S);
return {ELFNoneKind, 0};
}
// Returns slices of MB by parsing MB as an archive file.
// Each slice consists of a member file in the archive.
static std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB) {
ErrorOr<std::unique_ptr<Archive>> FileOrErr = Archive::create(MB);
fatal(FileOrErr, "Failed to parse archive");
std::unique_ptr<Archive> File = std::move(*FileOrErr);
std::vector<MemoryBufferRef> V;
for (const ErrorOr<Archive::Child> &C : File->children()) {
fatal(C, "Could not get the child of the archive " + File->getFileName());
ErrorOr<MemoryBufferRef> MbOrErr = C->getMemoryBufferRef();
fatal(MbOrErr, "Could not get the buffer for a child of the archive " +
File->getFileName());
V.push_back(*MbOrErr);
}
return V;
}
// Opens and parses a file. Path has to be resolved already.
// Newly created memory buffers are owned by this driver.
void LinkerDriver::addFile(StringRef Path) {
using namespace llvm::sys::fs;
if (Config->Verbose)
llvm::outs() << Path << "\n";
auto MBOrErr = MemoryBuffer::getFile(Path);
if (error(MBOrErr, "cannot open " + Path))
return;
std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
MemoryBufferRef MBRef = MB->getMemBufferRef();
OwningMBs.push_back(std::move(MB)); // take MB ownership
switch (identify_magic(MBRef.getBuffer())) {
case file_magic::unknown:
Script->read(MBRef);
return;
case file_magic::archive:
if (WholeArchive) {
StringRef S = MBRef.getBufferIdentifier();
for (MemoryBufferRef MB : getArchiveMembers(MBRef))
Files.push_back(createObjectFile(MB, S));
return;
}
Files.push_back(make_unique<ArchiveFile>(MBRef));
return;
case file_magic::elf_shared_object:
+ if (Config->Relocatable) {
+ error("Attempted static link of dynamic object " + Path);
+ return;
+ }
Files.push_back(createSharedFile(MBRef));
return;
default:
Files.push_back(createObjectFile(MBRef));
}
}
// Add a given library by searching it from input search paths.
void LinkerDriver::addLibrary(StringRef Name) {
std::string Path = searchLibrary(Name);
if (Path.empty())
error("Unable to find library -l" + Name);
else
addFile(Path);
}
// Some command line options or some combinations of them are not allowed.
// This function checks for such errors.
static void checkOptions(opt::InputArgList &Args) {
- // Traditional linkers can generate re-linkable object files instead
- // of executables or DSOs. We don't support that since the feature
- // does not seem to provide more value than the static archiver.
- if (Args.hasArg(OPT_relocatable))
- error("-r option is not supported. Use 'ar' command instead.");
-
// The MIPS ABI as of 2016 does not support the GNU-style symbol lookup
// table which is a relatively new feature.
if (Config->EMachine == EM_MIPS && Config->GnuHash)
error("The .gnu.hash section is not compatible with the MIPS target.");
if (Config->EMachine == EM_AMDGPU && !Config->Entry.empty())
error("-e option is not valid for AMDGPU.");
+
+ if (Config->Relocatable && Config->Shared)
+ error("-r and -shared may not be used together");
}
static StringRef
getString(opt::InputArgList &Args, unsigned Key, StringRef Default = "") {
if (auto *Arg = Args.getLastArg(Key))
return Arg->getValue();
return Default;
}
static bool hasZOption(opt::InputArgList &Args, StringRef Key) {
for (auto *Arg : Args.filtered(OPT_z))
if (Key == Arg->getValue())
return true;
return false;
}
void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
initSymbols();
opt::InputArgList Args = parseArgs(&Alloc, ArgsArr);
readConfigs(Args);
createFiles(Args);
checkOptions(Args);
if (HasError)
return;
switch (Config->EKind) {
case ELF32LEKind:
link<ELF32LE>(Args);
return;
case ELF32BEKind:
link<ELF32BE>(Args);
return;
case ELF64LEKind:
link<ELF64LE>(Args);
return;
case ELF64BEKind:
link<ELF64BE>(Args);
return;
default:
error("-m or at least a .o file required");
}
}
// Initializes Config members by the command line options.
void LinkerDriver::readConfigs(opt::InputArgList &Args) {
for (auto *Arg : Args.filtered(OPT_L))
Config->SearchPaths.push_back(Arg->getValue());
std::vector<StringRef> RPaths;
for (auto *Arg : Args.filtered(OPT_rpath))
RPaths.push_back(Arg->getValue());
if (!RPaths.empty())
Config->RPath = llvm::join(RPaths.begin(), RPaths.end(), ":");
if (auto *Arg = Args.getLastArg(OPT_m)) {
// Parse ELF{32,64}{LE,BE} and CPU type.
StringRef S = Arg->getValue();
std::tie(Config->EKind, Config->EMachine) = parseEmulation(S);
Config->Emulation = S;
}
Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
Config->Demangle = !Args.hasArg(OPT_no_demangle);
Config->DiscardAll = Args.hasArg(OPT_discard_all);
Config->DiscardLocals = Args.hasArg(OPT_discard_locals);
Config->DiscardNone = Args.hasArg(OPT_discard_none);
Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr);
Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);
Config->ExportDynamic = Args.hasArg(OPT_export_dynamic);
Config->GcSections = Args.hasArg(OPT_gc_sections);
Config->NoInhibitExec = Args.hasArg(OPT_noinhibit_exec);
Config->NoUndefined = Args.hasArg(OPT_no_undefined);
Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
+ Config->Relocatable = Args.hasArg(OPT_relocatable);
Config->Shared = Args.hasArg(OPT_shared);
Config->StripAll = Args.hasArg(OPT_strip_all);
Config->Verbose = Args.hasArg(OPT_verbose);
Config->DynamicLinker = getString(Args, OPT_dynamic_linker);
Config->Entry = getString(Args, OPT_entry);
Config->Fini = getString(Args, OPT_fini, "_fini");
Config->Init = getString(Args, OPT_init, "_init");
Config->OutputFile = getString(Args, OPT_o);
Config->SoName = getString(Args, OPT_soname);
Config->Sysroot = getString(Args, OPT_sysroot);
Config->ZExecStack = hasZOption(Args, "execstack");
Config->ZNodelete = hasZOption(Args, "nodelete");
Config->ZNow = hasZOption(Args, "now");
Config->ZOrigin = hasZOption(Args, "origin");
Config->ZRelro = !hasZOption(Args, "norelro");
+ if (Config->Relocatable)
+ Config->StripAll = false;
+
if (auto *Arg = Args.getLastArg(OPT_O)) {
StringRef Val = Arg->getValue();
if (Val.getAsInteger(10, Config->Optimize))
error("Invalid optimization level");
}
if (auto *Arg = Args.getLastArg(OPT_hash_style)) {
StringRef S = Arg->getValue();
if (S == "gnu") {
Config->GnuHash = true;
Config->SysvHash = false;
} else if (S == "both") {
Config->GnuHash = true;
} else if (S != "sysv")
error("Unknown hash style: " + S);
}
for (auto *Arg : Args.filtered(OPT_undefined))
Config->Undefined.push_back(Arg->getValue());
}
void LinkerDriver::createFiles(opt::InputArgList &Args) {
for (auto *Arg : Args) {
switch (Arg->getOption().getID()) {
case OPT_l:
addLibrary(Arg->getValue());
break;
case OPT_INPUT:
case OPT_script:
addFile(Arg->getValue());
break;
case OPT_as_needed:
Config->AsNeeded = true;
break;
case OPT_no_as_needed:
Config->AsNeeded = false;
break;
case OPT_Bstatic:
Config->Static = true;
break;
case OPT_Bdynamic:
Config->Static = false;
break;
case OPT_whole_archive:
WholeArchive = true;
break;
case OPT_no_whole_archive:
WholeArchive = false;
break;
}
}
if (Files.empty() && !HasError)
error("no input files.");
}
template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// For LTO
InitializeAllTargets();
InitializeAllTargetMCs();
InitializeAllAsmPrinters();
SymbolTable<ELFT> Symtab;
std::unique_ptr<TargetInfo> TI(createTarget());
Target = TI.get();
- if (!Config->Shared) {
+ if (!Config->Shared && !Config->Relocatable) {
// Add entry symbol.
//
// There is no entry symbol for AMDGPU binaries, so skip adding one to avoid
// having and undefined symbol.
if (Config->Entry.empty() && Config->EMachine != EM_AMDGPU)
Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start";
// In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
// is magical and is used to produce a R_386_GOTPC relocation.
// The R_386_GOTPC relocation value doesn't actually depend on the
// symbol value, so it could use an index of STN_UNDEF which, according
// to the spec, means the symbol value is 0.
// Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
// the object file.
// The situation is even stranger on x86_64 where the assembly doesn't
// need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
// an undefined symbol in the .o files.
// Given that the symbol is effectively unused, we just create a dummy
// hidden one to avoid the undefined symbol error.
Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_");
}
if (!Config->Entry.empty()) {
// Set either EntryAddr (if S is a number) or EntrySym (otherwise).
StringRef S = Config->Entry;
if (S.getAsInteger(0, Config->EntryAddr))
Config->EntrySym = Symtab.addUndefined(S);
}
if (Config->EMachine == EM_MIPS) {
// On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
// start of function and 'gp' pointer into GOT.
Config->MipsGpDisp = Symtab.addIgnored("_gp_disp");
// The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
// pointer. This symbol is used in the code generated by .cpload pseudo-op
// in case of using -mno-shared option.
// https://sourceware.org/ml/binutils/2004-12/msg00094.html
Config->MipsLocalGp = Symtab.addIgnored("__gnu_local_gp");
// Define _gp for MIPS. st_value of _gp symbol will be updated by Writer
// so that it points to an absolute address which is relative to GOT.
// See "Global Data Symbols" in Chapter 6 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
Symtab.addAbsolute("_gp", ElfSym<ELFT>::MipsGp);
}
for (std::unique_ptr<InputFile> &F : Files)
Symtab.addFile(std::move(F));
if (HasError)
return; // There were duplicate symbols or incompatible files
for (StringRef S : Config->Undefined)
Symtab.addUndefinedOpt(S);
Symtab.addCombinedLtoObject();
for (auto *Arg : Args.filtered(OPT_wrap))
Symtab.wrap(Arg->getValue());
if (Config->OutputFile.empty())
Config->OutputFile = "a.out";
// Write the result to the file.
Symtab.scanShlibUndefined();
if (Config->GcSections)
markLive<ELFT>(&Symtab);
writeResult<ELFT>(&Symtab);
}

Event Timeline