summaryrefslogtreecommitdiff
path: root/ELF/Writer.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-01-13 20:06:04 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-01-13 20:06:04 +0000
commitb289257c7f3ed78b7d3971c596d7c60a9050c705 (patch)
treed6b57e29a5a86347a020d6f0cae76cc2d0f3bf8d /ELF/Writer.cpp
parentfba2c04f31e119eacf142fcbbaabd5a9e63a39ed (diff)
Notes
Diffstat (limited to 'ELF/Writer.cpp')
-rw-r--r--ELF/Writer.cpp124
1 files changed, 76 insertions, 48 deletions
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index 2437a435657c..fbecfc601ac1 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -98,12 +98,9 @@ private:
};
} // anonymous namespace
-template <class ELFT> static bool shouldUseRela() {
- ELFKind K = cast<ELFFileBase<ELFT>>(Config->FirstElf)->getELFKind();
- return K == ELF64LEKind || K == ELF64BEKind;
-}
+template <class ELFT> static bool shouldUseRela() { return ELFT::Is64Bits; }
-template <class ELFT> void lld::elf2::writeResult(SymbolTable<ELFT> *Symtab) {
+template <class ELFT> void elf2::writeResult(SymbolTable<ELFT> *Symtab) {
// Initialize output sections that are handled by Writer specially.
// Don't reorder because the order of initialization matters.
InterpSection<ELFT> Interp;
@@ -290,18 +287,31 @@ void Writer<ELFT>::scanRelocs(
continue;
}
- if (Config->EMachine == EM_MIPS && NeedsGot) {
- // 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->setUsedInDynamicReloc();
- continue;
+ if (Config->EMachine == EM_MIPS) {
+ if (NeedsGot) {
+ // 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->setUsedInDynamicReloc();
+ continue;
+ }
+ if (Body == Config->MipsGpDisp)
+ // MIPS _gp_disp designates offset between start of function and gp
+ // pointer into GOT therefore any relocations against it do not require
+ // dynamic relocation.
+ continue;
}
+
+ // Here we are creating a relocation for the dynamic linker based on
+ // a relocation from an object file, but some relocations need no
+ // load-time fixup. Skip such relocation.
bool CBP = canBePreempted(Body, NeedsGot);
- if (!CBP && (!Config->Shared || Target->isRelRelative(Type)))
+ bool NoDynrel = Target->isRelRelative(Type) || Target->isSizeReloc(Type);
+ if (!CBP && (NoDynrel || !Config->Shared))
continue;
+
if (CBP)
Body->setUsedInDynamicReloc();
if (NeedsPlt && Target->supportsLazyRelocations())
@@ -490,8 +500,7 @@ void Writer<ELFT>::addCommonSymbols(std::vector<DefinedCommon *> &Syms) {
uintX_t Off = getBss()->getSize();
for (DefinedCommon *C : Syms) {
- uintX_t Align = C->MaxAlignment;
- Off = RoundUpToAlignment(Off, Align);
+ Off = align(Off, C->MaxAlignment);
C->OffsetInBss = Off;
Off += C->Size;
}
@@ -514,7 +523,7 @@ void Writer<ELFT>::addCopyRelSymbols(std::vector<SharedSymbol<ELFT> *> &Syms) {
countTrailingZeros((uintX_t)Sym.st_value));
uintX_t Align = 1 << TrailingZeros;
Out<ELFT>::Bss->updateAlign(Align);
- Off = RoundUpToAlignment(Off, Align);
+ Off = align(Off, Align);
C->OffsetInBss = Off;
Off += Sym.st_size;
}
@@ -597,7 +606,8 @@ template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
// Don't include synthetic symbols like __init_array_start in every output.
if (auto *U = dyn_cast<DefinedRegular<ELFT>>(&B))
- if (&U->Sym == &ElfSym<ELFT>::IgnoreUndef)
+ if (&U->Sym == &ElfSym<ELFT>::IgnoredWeak ||
+ &U->Sym == &ElfSym<ELFT>::Ignored)
return false;
return true;
@@ -630,8 +640,6 @@ public:
private:
SectionKey<ELFT::Is64Bits> createKey(InputSectionBase<ELFT> *C,
StringRef OutsecName);
- OutputSectionBase<ELFT> *createAux(InputSectionBase<ELFT> *C,
- const SectionKey<ELFT::Is64Bits> &Key);
SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSectionBase<ELFT> *> Map;
};
@@ -645,25 +653,22 @@ OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C,
OutputSectionBase<ELFT> *&Sec = Map[Key];
if (Sec)
return {Sec, false};
- Sec = createAux(C, Key);
- return {Sec, true};
-}
-template <class ELFT>
-OutputSectionBase<ELFT> *
-OutputSectionFactory<ELFT>::createAux(InputSectionBase<ELFT> *C,
- const SectionKey<ELFT::Is64Bits> &Key) {
switch (C->SectionKind) {
case InputSectionBase<ELFT>::Regular:
- return new OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+ Sec = new OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+ break;
case InputSectionBase<ELFT>::EHFrame:
- return new EHOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+ Sec = new EHOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+ break;
case InputSectionBase<ELFT>::Merge:
- return new MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+ Sec = new MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+ break;
case InputSectionBase<ELFT>::MipsReginfo:
- return new MipsReginfoOutputSection<ELFT>();
+ Sec = new MipsReginfoOutputSection<ELFT>();
+ break;
}
- llvm_unreachable("Unknown output section type");
+ return {Sec, true};
}
template <class ELFT>
@@ -832,7 +837,7 @@ template <class ELFT> void Writer<ELFT>::createSections() {
}
for (OutputSectionBase<ELFT> *Sec : OutputSections)
- Out<ELFT>::ShStrTab->add(Sec->getName());
+ Out<ELFT>::ShStrTab->reserve(Sec->getName());
// Finalizers fix each section's size.
// .dynamic section's finalizer may add strings to .dynstr,
@@ -976,6 +981,18 @@ static uint32_t toPhdrFlags(uint64_t Flags) {
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;
+}
+
template <class ELFT>
void Writer<ELFT>::updateRelro(Elf_Phdr *Cur, Elf_Phdr *GnuRelroPhdr,
uintX_t VA) {
@@ -1024,8 +1041,8 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
bool InRelRo = Config->ZRelro && (Flags & PF_W) && isRelroSection(Sec);
bool FirstNonRelRo = GnuRelroPhdr.p_type && !InRelRo && !RelroAligned;
if (FirstNonRelRo || PH->p_flags != Flags) {
- VA = RoundUpToAlignment(VA, Target->getPageSize());
- FileOff = RoundUpToAlignment(FileOff, Target->getPageSize());
+ VA = align(VA, Target->getPageSize());
+ FileOff = align(FileOff, Target->getPageSize());
if (FirstNonRelRo)
RelroAligned = true;
}
@@ -1033,15 +1050,17 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
if (PH->p_flags != Flags) {
// Flags changed. Create a new PT_LOAD.
PH = &Phdrs[++PhdrIdx];
- setPhdr(PH, PT_LOAD, Flags, FileOff, VA, 0, Target->getPageSize());
+ uint32_t PTType = (Config->EMachine != EM_AMDGPU) ? (uint32_t)PT_LOAD
+ : getAmdgpuPhdr(Sec);
+ setPhdr(PH, PTType, Flags, FileOff, VA, 0, Target->getPageSize());
}
if (Sec->getFlags() & SHF_TLS) {
if (!TlsPhdr.p_vaddr)
setPhdr(&TlsPhdr, PT_TLS, PF_R, FileOff, VA, 0, Sec->getAlign());
if (Sec->getType() != SHT_NOBITS)
- VA = RoundUpToAlignment(VA, Sec->getAlign());
- uintX_t TVA = RoundUpToAlignment(VA + ThreadBssOffset, Sec->getAlign());
+ VA = align(VA, Sec->getAlign());
+ uintX_t TVA = align(VA + ThreadBssOffset, Sec->getAlign());
Sec->setVA(TVA);
TlsPhdr.p_memsz += Sec->getSize();
if (Sec->getType() == SHT_NOBITS) {
@@ -1052,7 +1071,7 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
}
TlsPhdr.p_align = std::max<uintX_t>(TlsPhdr.p_align, Sec->getAlign());
} else {
- VA = RoundUpToAlignment(VA, Sec->getAlign());
+ VA = align(VA, Sec->getAlign());
Sec->setVA(VA);
VA += Sec->getSize();
if (InRelRo)
@@ -1060,7 +1079,7 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
}
}
- FileOff = RoundUpToAlignment(FileOff, Sec->getAlign());
+ FileOff = align(FileOff, Sec->getAlign());
Sec->setFileOffset(FileOff);
if (Sec->getType() != SHT_NOBITS)
FileOff += Sec->getSize();
@@ -1073,7 +1092,7 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
if (TlsPhdr.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.
- TlsPhdr.p_memsz = RoundUpToAlignment(TlsPhdr.p_memsz, TlsPhdr.p_align);
+ TlsPhdr.p_memsz = align(TlsPhdr.p_memsz, TlsPhdr.p_align);
Phdrs[++PhdrIdx] = TlsPhdr;
Out<ELFT>::TlsPhdr = &Phdrs[PhdrIdx];
}
@@ -1105,7 +1124,7 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
}
// Add space for section headers.
- SectionHeaderOff = RoundUpToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4);
+ SectionHeaderOff = align(FileOff, ELFT::Is64Bits ? 8 : 4);
FileSize = SectionHeaderOff + getNumSections() * sizeof(Elf_Shdr);
// Update "_end" and "end" symbols so that they
@@ -1146,7 +1165,7 @@ 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 hadr coded values.
+ // 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;
@@ -1238,8 +1257,17 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
Sec->writeTo(Buf + Sec->getFileOff());
}
+ // Write all sections but string table sections. We know the sizes of the
+ // string tables already, but they may not have actual strings yet (only
+ // room may be reserved), because writeTo() is allowed to add actual
+ // strings to the string tables.
+ for (OutputSectionBase<ELFT> *Sec : OutputSections)
+ if (Sec != Out<ELFT>::Opd && Sec->getType() != SHT_STRTAB)
+ Sec->writeTo(Buf + Sec->getFileOff());
+
+ // Write string table sections.
for (OutputSectionBase<ELFT> *Sec : OutputSections)
- if (Sec != Out<ELFT>::Opd)
+ if (Sec != Out<ELFT>::Opd && Sec->getType() == SHT_STRTAB)
Sec->writeTo(Buf + Sec->getFileOff());
}
@@ -1275,7 +1303,7 @@ template <class ELFT> void Writer<ELFT>::buildSectionMap() {
InputToOutputSection[Name] = OutSec.first;
}
-template void lld::elf2::writeResult<ELF32LE>(SymbolTable<ELF32LE> *Symtab);
-template void lld::elf2::writeResult<ELF32BE>(SymbolTable<ELF32BE> *Symtab);
-template void lld::elf2::writeResult<ELF64LE>(SymbolTable<ELF64LE> *Symtab);
-template void lld::elf2::writeResult<ELF64BE>(SymbolTable<ELF64BE> *Symtab);
+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);