[lld] r259516 - Expand comment a bit.
Rafael EspĂndola via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 2 08:00:02 PST 2016
On 2 February 2016 at 10:45, Rafael Espindola via llvm-commits
<llvm-commits at lists.llvm.org> wrote:
> Author: rafael
> Date: Tue Feb 2 09:45:37 2016
> New Revision: 259516
>
> URL: http://llvm.org/viewvc/llvm-project?rev=259516&view=rev
> Log:
> Expand comment a bit.
>
> I have spent some time prototyping this idea. While it seems to work, I
> now think it is probably not worth it.
In case anyone is interested this is what the currently very broken
patch looks like.
I might come back to it at some point, but for now I will explore some
other options for simplifying the relocation code.
Cheers,
Rafael
-------------- next part --------------
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index d5ff181..f6c8f8d 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -14,6 +14,8 @@
#include "OutputSections.h"
#include "Target.h"
+#include "llvm/Support/raw_ostream.h"
+
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
@@ -212,6 +214,12 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
getAddend<ELFT>(RI));
continue;
}
+ bool NeedsGot = Target->needsGot(Type, *Body);
+ bool CBP = canBePreempted(Body, NeedsGot);
+ bool NoDynrel = Target->isRelRelative(Type) || Target->isSizeRel(Type) ||
+ !Config->Shared;
+ if (CBP || !NoDynrel)
+ Out<ELFT>::RelaDyn->addReloc({this, &RI});
uintX_t SymVA = Body->getVA<ELFT>();
if (Target->needsPlt(Type, *Body)) {
@@ -249,22 +257,20 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
}
}
-template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
+template <class ELFT> void InputSection<ELFT>::writeTo(raw_fd_ostream &OS) {
if (this->Header->sh_type == SHT_NOBITS)
return;
+
+ uint32_t Align = this->getAlign();
+ uint64_t P = OS.tell();
+ uint64_t PAlign = alignTo(P, Align);
+ uint64_t Padding = PAlign - P;
+ for (uint64_t I = 0; I < Padding; ++I)
+ OS.write('\0');
+
// Copy section contents from source object file to output file.
ArrayRef<uint8_t> Data = this->getSectionData();
- 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));
- }
+ OS.write(reinterpret_cast<const char *>(Data.data()), Data.size());
}
template <class ELFT>
@@ -382,6 +388,23 @@ template class elf2::InputSectionBase<ELF32BE>;
template class elf2::InputSectionBase<ELF64LE>;
template class elf2::InputSectionBase<ELF64BE>;
+template void InputSectionBase<ELF32LE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+ RelIteratorRange<false> Rels);
+template void InputSectionBase<ELF32LE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+ RelIteratorRange<true> Rels);
+template void InputSectionBase<ELF32BE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+ RelIteratorRange<false> Rels);
+template void InputSectionBase<ELF32BE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+ RelIteratorRange<true> Rels);
+template void InputSectionBase<ELF64LE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+ RelIteratorRange<false> Rels);
+template void InputSectionBase<ELF64LE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+ RelIteratorRange<true> Rels);
+template void InputSectionBase<ELF64BE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+ RelIteratorRange<false> Rels);
+template void InputSectionBase<ELF64BE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+ RelIteratorRange<true> Rels);
+
template class elf2::InputSection<ELF32LE>;
template class elf2::InputSection<ELF32BE>;
template class elf2::InputSection<ELF64LE>;
@@ -401,3 +424,4 @@ template class elf2::MipsReginfoInputSection<ELF32LE>;
template class elf2::MipsReginfoInputSection<ELF32BE>;
template class elf2::MipsReginfoInputSection<ELF64LE>;
template class elf2::MipsReginfoInputSection<ELF64BE>;
+
diff --git a/ELF/InputSection.h b/ELF/InputSection.h
index 26956c7..673b665 100644
--- a/ELF/InputSection.h
+++ b/ELF/InputSection.h
@@ -14,6 +14,10 @@
#include "lld/Core/LLVM.h"
#include "llvm/Object/ELF.h"
+namespace llvm {
+class raw_fd_ostream;
+}
+
namespace lld {
namespace elf2 {
@@ -157,7 +161,7 @@ public:
// Write this section to a mmap'ed file, assuming Buf is pointing to
// beginning of the output section.
- void writeTo(uint8_t *Buf);
+ void writeTo(llvm::raw_fd_ostream &OS);
// Relocation sections that refer to this one.
SmallVector<const Elf_Shdr *, 1> RelocSections;
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index 14194f7..e56a017 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -12,7 +12,9 @@
#include "SymbolTable.h"
#include "Target.h"
#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/EndianStream.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
#include <map>
using namespace llvm;
@@ -33,6 +35,16 @@ OutputSectionBase<ELFT>::OutputSectionBase(StringRef Name, uint32_t Type,
}
template <class ELFT>
+void OutputSectionBase<ELFT>::align(llvm::raw_fd_ostream &OS) {
+ uint64_t A = OS.tell();
+ uint64_t B = getFileOff();
+ assert(B >= A);
+ B-= A;
+ while (B--)
+ OS.write('\0');
+}
+
+template <class ELFT>
GotPltSection<ELFT>::GotPltSection()
: OutputSectionBase<ELFT>(".got.plt", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) {
this->Header.sh_addralign = sizeof(uintX_t);
@@ -52,13 +64,11 @@ template <class ELFT> void GotPltSection<ELFT>::finalize() {
(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> void GotPltSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+ this->align(OS);
+ Target->writeGotPltHeader(OS);
+ for (const SymbolBody *B : Entries)
+ Target->writeGotPlt(OS, B->getPltVA<ELFT>());
}
template <class ELFT>
@@ -142,28 +152,31 @@ template <class ELFT> void GotSection<ELFT>::finalize() {
sizeof(uintX_t);
}
-template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
- Target->writeGotHeader(Buf);
- for (const auto &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);
+template <class ELFT> void GotSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+ Writer<ELFT::TargetEndianness> W(OS);
+ this->align(OS);
+
+ Target->writeGotHeader(OS);
+ std::vector<uintX_t> EntriesVal;
+ EntriesVal.resize(MipsLocalEntries);
+ for (const auto &L : MipsLocalGotPos)
+ EntriesVal[L.second - 2 ] = L.first;
+ W.template write<uintX_t>(EntriesVal);
for (const SymbolBody *B : Entries) {
- uint8_t *Entry = Buf;
- Buf += sizeof(uintX_t);
- if (!B)
+ if (!B) {
+ W. write((uintX_t)0);
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))
+ if (Config->EMachine != EM_MIPS && canBePreempted(B, false)) {
+ W. write((uintX_t)0);
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);
+ }
+ W. write( (uintX_t)B->getVA<ELFT>());
}
}
@@ -173,11 +186,13 @@ PltSection<ELFT>::PltSection()
this->Header.sh_addralign = 16;
}
-template <class ELFT> void PltSection<ELFT>::writeTo(uint8_t *Buf) {
+template <class ELFT> void PltSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+ this->align(OS);
+
size_t Off = 0;
if (Target->UseLazyBinding) {
// First write PLT[0] entry which is special.
- Target->writePltZero(Buf);
+ Target->writePltZero(OS);
Off += Target->PltZeroSize;
}
for (auto &I : Entries) {
@@ -186,7 +201,7 @@ template <class ELFT> void PltSection<ELFT>::writeTo(uint8_t *Buf) {
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);
+ Target->writePlt(OS, Got, Plt, B->PltIndex, RelOff);
Off += Target->PltEntrySize;
}
}
@@ -216,11 +231,15 @@ RelocationSection<ELFT>::RelocationSection(StringRef Name, bool IsRela)
// Returns true if relocation was handled.
template <class ELFT>
bool RelocationSection<ELFT>::applyTlsDynamicReloc(SymbolBody *Body,
- uint32_t Type, Elf_Rel *P,
- Elf_Rel *N) {
+ uint32_t Type,
+ raw_fd_ostream &OS) {
+ Elf_Rela P{};
+ unsigned Size = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+
if (Target->isTlsLocalDynamicRel(Type)) {
- P->setSymbolAndType(0, Target->TlsModuleIndexRel, Config->Mips64EL);
- P->r_offset = Out<ELFT>::Got->getLocalTlsIndexVA();
+ P.setSymbolAndType(0, Target->TlsModuleIndexRel, Config->Mips64EL);
+ P.r_offset = Out<ELFT>::Got->getLocalTlsIndexVA();
+ OS.write(reinterpret_cast<const char*>(&P), Size);
return true;
}
@@ -228,26 +247,30 @@ bool RelocationSection<ELFT>::applyTlsDynamicReloc(SymbolBody *Body,
return false;
if (Target->canRelaxTls(Type, Body)) {
- P->setSymbolAndType(Body->DynsymIndex, Target->getTlsGotRel(),
+ P.setSymbolAndType(Body->DynsymIndex, Target->getTlsGotRel(),
Config->Mips64EL);
- P->r_offset = Body->getGotVA<ELFT>();
+ P.r_offset = Body->getGotVA<ELFT>();
+ OS.write(reinterpret_cast<const char*>(&P), Size);
return true;
}
- P->setSymbolAndType(Body->DynsymIndex, Target->TlsModuleIndexRel,
+ P.setSymbolAndType(Body->DynsymIndex, Target->TlsModuleIndexRel,
Config->Mips64EL);
- P->r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body);
- N->setSymbolAndType(Body->DynsymIndex, Target->TlsOffsetRel,
+ P.r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body);
+ OS.write(reinterpret_cast<const char*>(&P), Size);
+ P.setSymbolAndType(Body->DynsymIndex, Target->TlsOffsetRel,
Config->Mips64EL);
- N->r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body) + sizeof(uintX_t);
+ P.r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body) + sizeof(uintX_t);
+ OS.write(reinterpret_cast<const char*>(&P), Size);
return true;
}
-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);
+template <class ELFT>
+void RelocationSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+ this->align(OS);
+ Writer<ELFT::TargetEndianness> W(OS);
+ for (const DynamicReloc<ELFT> &Rel : Relocs) {
// Skip placeholder for global dynamic TLS relocation pair. It was already
// handled by the previous relocation.
if (!Rel.C)
@@ -262,22 +285,26 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
Body = Body->repl();
uint32_t Type = RI.getType(Config->Mips64EL);
- if (applyTlsDynamicReloc(Body, Type, P, reinterpret_cast<Elf_Rel *>(Buf)))
+ if (applyTlsDynamicReloc(Body, Type, OS))
continue;
+ Elf_Rela P{};
+ unsigned Size = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
// Writer::scanRelocs creates a RELATIVE reloc for some type of TLS reloc.
// We want to write it down as is.
if (Type == Target->RelativeRel) {
- P->setSymbolAndType(0, Type, Config->Mips64EL);
- P->r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
+ P.setSymbolAndType(0, Type, Config->Mips64EL);
+ P.r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
+ OS.write(reinterpret_cast<const char*>(&P), Size);
continue;
}
// Emit a copy relocation.
auto *SS = dyn_cast_or_null<SharedSymbol<ELFT>>(Body);
if (SS && SS->NeedsCopy) {
- P->setSymbolAndType(Body->DynsymIndex, Target->CopyRel, Config->Mips64EL);
- P->r_offset = Out<ELFT>::Bss->getVA() + SS->OffsetInBss;
+ P.setSymbolAndType(Body->DynsymIndex, Target->CopyRel, Config->Mips64EL);
+ P.r_offset = Out<ELFT>::Bss->getVA() + SS->OffsetInBss;
+ OS.write(reinterpret_cast<const char*>(&P), Size);
continue;
}
@@ -289,11 +316,12 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
// the usual JUMP_SLOT reloc for the GOT entry. For the details, you
// want to read http://www.airs.com/blog/archives/403
if (!CBP && Body && isGnuIFunc<ELFT>(*Body)) {
- P->setSymbolAndType(0, Target->IRelativeRel, Config->Mips64EL);
+ P.setSymbolAndType(0, Target->IRelativeRel, Config->Mips64EL);
if (Out<ELFT>::GotPlt)
- P->r_offset = Body->getGotPltVA<ELFT>();
+ P.r_offset = Body->getGotPltVA<ELFT>();
else
- P->r_offset = Body->getGotVA<ELFT>();
+ P.r_offset = Body->getGotVA<ELFT>();
+ OS.write(reinterpret_cast<const char*>(&P), Size);
continue;
}
@@ -309,27 +337,26 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
Reloc = Body->isTls() ? Target->getTlsGotRel() : Target->GotRel;
else
Reloc = Target->getDynRel(Type);
- P->setSymbolAndType(CBP ? Body->DynsymIndex : 0, Reloc, Config->Mips64EL);
+ P.setSymbolAndType(CBP ? Body->DynsymIndex : 0, Reloc, Config->Mips64EL);
if (LazyReloc)
- P->r_offset = Body->getGotPltVA<ELFT>();
+ P.r_offset = Body->getGotPltVA<ELFT>();
else if (NeedsGot)
- P->r_offset = Body->getGotVA<ELFT>();
+ P.r_offset = Body->getGotVA<ELFT>();
else
- P->r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
-
- if (!IsRela)
- continue;
-
- auto R = static_cast<const Elf_Rela &>(RI);
- auto S = static_cast<Elf_Rela *>(P);
- uintX_t A = NeedsGot ? 0 : R.r_addend;
- if (CBP)
- S->r_addend = A;
- else if (Body)
- S->r_addend = Body->getVA<ELFT>() + A;
- else
- S->r_addend = getLocalRelTarget(File, R, A);
+ P.r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
+
+ if (IsRela ) {
+ auto R = static_cast<const Elf_Rela &>(RI);
+ uintX_t A = NeedsGot ? 0 : R.r_addend;
+ if (CBP)
+ P.r_addend = A;
+ else if (Body)
+ P.r_addend = Body->getVA<ELFT>() + A;
+ else
+ P.r_addend = getLocalRelTarget(File, R, A);
+ }
+ OS.write(reinterpret_cast<const char*>(&P), Size);
}
}
@@ -352,12 +379,13 @@ InterpSection<ELFT>::InterpSection()
}
template <class ELFT>
-void OutputSectionBase<ELFT>::writeHeaderTo(Elf_Shdr *SHdr) {
- *SHdr = Header;
+void OutputSectionBase<ELFT>::writeHeaderTo(raw_fd_ostream &OS) {
+ OS.write(reinterpret_cast<const char*>(&Header), sizeof(Header));
}
-template <class ELFT> void InterpSection<ELFT>::writeTo(uint8_t *Buf) {
- memcpy(Buf, Config->DynamicLinker.data(), Config->DynamicLinker.size());
+template <class ELFT> void InterpSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+ this->align(OS);
+ OS.write(Config->DynamicLinker.data(), Config->DynamicLinker.size());
}
template <class ELFT>
@@ -392,14 +420,19 @@ template <class ELFT> void HashTableSection<ELFT>::finalize() {
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
+template <class ELFT> void HashTableSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+ this->align(OS);
+ Elf_Word NumSymbols = (Elf_Word) Out<ELFT>::DynSymTab->getNumSymbols();
+ // FIXME: a templated write would be nice.
+ OS.write(reinterpret_cast<const char *>(&NumSymbols),
+ sizeof(NumSymbols)); // nbucket
+ OS.write(reinterpret_cast<const char *>(&NumSymbols),
+ sizeof(NumSymbols)); // nchain
- Elf_Word *Buckets = P;
- Elf_Word *Chains = P + NumSymbols;
+ std::vector<Elf_Word> Buckets;
+ std::vector<Elf_Word> Chains;
+ Buckets.resize(NumSymbols);
+ Chains.resize(NumSymbols);
for (const std::pair<SymbolBody *, unsigned> &P :
Out<ELFT>::DynSymTab->getSymbols()) {
@@ -410,6 +443,10 @@ template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
Chains[I] = Buckets[Hash];
Buckets[Hash] = I;
}
+ OS.write(reinterpret_cast<const char *>(Buckets.data()),
+ NumSymbols * sizeof(Elf_Word));
+ OS.write(reinterpret_cast<const char *>(Chains.data()),
+ NumSymbols * sizeof(Elf_Word));
}
static uint32_t hashGnu(StringRef Name) {
@@ -474,42 +511,49 @@ template <class ELFT> void GnuHashTableSection<ELFT>::finalize() {
+ sizeof(Elf_Word) * NumHashed; // Hash Values
}
-template <class ELFT> void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) {
- writeHeader(Buf);
+template <class ELFT>
+void GnuHashTableSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+ writeHeader(OS);
if (HashedSymbols.empty())
return;
- writeBloomFilter(Buf);
- writeHashTable(Buf);
+ writeBloomFilter(OS);
+ writeHashTable(OS);
}
template <class ELFT>
-void GnuHashTableSection<ELFT>::writeHeader(uint8_t *&Buf) {
- auto *P = reinterpret_cast<Elf_Word *>(Buf);
- *P++ = NBuckets;
- *P++ = Out<ELFT>::DynSymTab->getNumSymbols() - HashedSymbols.size();
- *P++ = MaskWords;
- *P++ = Shift2;
- Buf = reinterpret_cast<uint8_t *>(P);
+void GnuHashTableSection<ELFT>::writeHeader(raw_fd_ostream &OS) {
+ Writer<ELFT::TargetEndianness> W(OS);
+
+ W.write(uint32_t(NBuckets));
+ W.write(
+ uint32_t(Out<ELFT>::DynSymTab->getNumSymbols() - HashedSymbols.size()));
+ W.write(uint32_t(MaskWords));
+ W.write(uint32_t(Shift2));
}
template <class ELFT>
-void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *&Buf) {
+void GnuHashTableSection<ELFT>::writeBloomFilter(raw_fd_ostream &OS) {
unsigned C = sizeof(Elf_Off) * 8;
- auto *Masks = reinterpret_cast<Elf_Off *>(Buf);
+ std::vector<Elf_Off> Masks;
+ Masks.resize(MaskWords);
for (const HashedSymbolData &Item : HashedSymbols) {
size_t Pos = (Item.Hash / C) & (MaskWords - 1);
uintX_t V = (uintX_t(1) << (Item.Hash % C)) |
(uintX_t(1) << ((Item.Hash >> Shift2) % C));
Masks[Pos] |= V;
}
- Buf += sizeof(Elf_Off) * MaskWords;
+ OS.write(reinterpret_cast<const char *>(Masks.data()),
+ Masks.size() * sizeof(Elf_Off));
}
template <class ELFT>
-void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) {
- Elf_Word *Buckets = reinterpret_cast<Elf_Word *>(Buf);
- Elf_Word *Values = Buckets + NBuckets;
+void GnuHashTableSection<ELFT>::writeHashTable(raw_fd_ostream &OS) {
+ std::vector<Elf_Word> Buckets;
+ Buckets.resize(NBuckets);
+
+ std::vector<Elf_Word> Values;
+ Values.resize(HashedSymbols.size());
int PrevBucket = -1;
int I = 0;
@@ -527,6 +571,11 @@ void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) {
}
if (I > 0)
Values[I - 1] |= 1;
+
+ OS.write(reinterpret_cast<const char *>(Buckets.data()),
+ Buckets.size() * sizeof(Elf_Word));
+ OS.write(reinterpret_cast<const char *>(Values.data()),
+ Values.size() * sizeof(Elf_Word));
}
static bool includeInGnuHashTable(SymbolBody *B) {
@@ -684,23 +733,23 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
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);
+template <class ELFT> void DynamicSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+ this->align(OS);
+ Writer<ELFT::TargetEndianness> W(OS);
for (const Entry &E : Entries) {
- P->d_tag = E.Tag;
+ W.write((uintX_t)E.Tag);
switch (E.Kind) {
case Entry::SecAddr:
- P->d_un.d_ptr = E.OutSec->getVA();
+ W.write((uintX_t)E.OutSec->getVA());
break;
case Entry::SymAddr:
- P->d_un.d_ptr = E.Sym->template getVA<ELFT>();
+ W.write((uintX_t)E.Sym->template getVA<ELFT>());
break;
case Entry::PlainInt:
- P->d_un.d_val = E.Val;
+ W.write((uintX_t)E.Val);
break;
}
- ++P;
}
}
@@ -743,20 +792,19 @@ EhFrameHeader<ELFT>::getFdePc(uintX_t EhVA, const FdeData &F) {
fatal("unknown FDE size encoding");
}
-template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
- const endianness E = ELFT::TargetEndianness;
+template <class ELFT> void EhFrameHeader<ELFT>::writeTo(raw_fd_ostream &OS) {
+ Writer<ELFT::TargetEndianness> W(OS);
+ this->align(OS);
- const uint8_t Header[] = {1, dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4,
- dwarf::DW_EH_PE_udata4,
- dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4};
- memcpy(Buf, Header, sizeof(Header));
+ W.template write<uint8_t>({1, dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4,
+ dwarf::DW_EH_PE_udata4,
+ dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4});
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;
+ W.template write<uint32_t>(EhOff);
+ W.template write<uint32_t>(this->FdeList.size());
// InitialPC -> Offset in .eh_frame, sorted by InitialPC.
std::map<uintX_t, size_t> PcToOffset;
@@ -765,10 +813,9 @@ template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
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);
+ W.template write<uint32_t>(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;
+ W.template write<uint32_t>(EhVA + I.second - VA);
}
}
@@ -898,9 +945,28 @@ bool elf2::canBePreempted(const SymbolBody *Body, bool NeedsGot) {
return Body->getVisibility() == STV_DEFAULT;
}
-template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
+template <class ELFT> void OutputSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+ this->align(OS);
for (InputSection<ELFT> *C : Sections)
- C->writeTo(Buf);
+ C->writeTo(OS);
+}
+
+template <class ELFT> void OutputSection<ELFT>::relocate(uint8_t *Buf) {
+ Buf = Buf + this->getFileOff();
+
+ if (this == Out<ELFT>::Opd)
+ Out<ELFT>::OpdBuf = Buf;
+
+ for (InputSection<ELFT> *S : Sections) {
+ uint8_t *BufEnd = Buf + S->OutSecOff + S->getSize();
+ ELFFile<ELFT> &EObj = S->getFile()->getObj();
+ for (const Elf_Shdr *RelSec : S->RelocSections) {
+ if (RelSec->sh_type == SHT_RELA)
+ S->relocate(Buf, BufEnd, EObj.relas(RelSec));
+ else
+ S->relocate(Buf, BufEnd, EObj.rels(RelSec));
+ }
+ }
}
template <class ELFT>
@@ -1145,45 +1211,61 @@ void EHOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
}
template <class ELFT>
-static typename ELFFile<ELFT>::uintX_t writeAlignedCieOrFde(StringRef Data,
- uint8_t *Buf) {
+static typename ELFFile<ELFT>::uintX_t
+writeAlignedCieOrFde(StringRef Data, uint32_t CIEPointer, raw_fd_ostream &OS) {
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);
+ unsigned Pad = Len - Data.size();
+ support::ulittle32_t V(Len - 4);
+ OS.write(reinterpret_cast<const char *>(&V), sizeof(V));
+ support::ulittle32_t V2(CIEPointer);
+ OS.write(reinterpret_cast<const char *>(&V2), sizeof(V2));
+ OS.write(Data.data() + 8, Data.size() - 8);
+ for (unsigned I = 0; I < Pad; ++I)
+ OS.write('\0');
return Len;
}
-template <class ELFT> void EHOutputSection<ELFT>::writeTo(uint8_t *Buf) {
- const endianness E = ELFT::TargetEndianness;
+template <class ELFT> void EHOutputSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+ this->align(OS);
size_t Offset = 0;
for (const Cie<ELFT> &C : Cies) {
size_t CieOffset = Offset;
- uintX_t CIELen = writeAlignedCieOrFde<ELFT>(C.data(), Buf + Offset);
+ uintX_t CIELen = writeAlignedCieOrFde<ELFT>(C.data(), 0, OS);
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
+ uintX_t Len =
+ writeAlignedCieOrFde<ELFT>(F.data(), Offset + 4 - CieOffset, OS);
F.S->Offsets[F.Index].second = Offset;
- Out<ELFT>::EhFrameHdr->addFde(C.FdeEncoding, Offset, Buf + Offset + 8);
Offset += Len;
}
}
+}
+
+template <class ELFT> void EHOutputSection<ELFT>::relocate(uint8_t *Buf) {
+ Buf = Buf + this->getFileOff();
for (EHInputSection<ELFT> *S : Sections) {
+ ELFFile<ELFT> &EObj = S->getFile()->getObj();
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));
}
+ if (!Config->EhFrameHdr)
+ return;
+ for (const Cie<ELFT> &C : Cies) {
+ for (const EHRegion<ELFT> &F : C.Fdes) {
+ auto Offset = F.S->Offsets[F.Index].second;
+ Out<ELFT>::EhFrameHdr->addFde(C.FdeEncoding, Offset, Buf + Offset + 8);
+ }
+ }
}
template <class ELFT>
@@ -1191,15 +1273,23 @@ MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t Type,
uintX_t Flags)
: OutputSectionBase<ELFT>(Name, Type, Flags) {}
-template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
+template <class ELFT>
+void MergeOutputSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+ this-> align(OS);
if (shouldTailMerge()) {
StringRef Data = Builder.data();
- memcpy(Buf, Data.data(), Data.size());
+ OS.write(Data.data(), Data.size());
return;
}
- for (const std::pair<StringRef, size_t> &P : Builder.getMap()) {
+ std::vector<std::pair<StringRef, size_t> > Entries;
+ const auto &Map = Builder.getMap();
+ Entries.reserve(Map.size());
+ for (const std::pair<StringRef, size_t> &P : Map)
+ Entries.push_back(P);
+ std::sort(Entries.begin(), Entries.end(), [&](std::pair<StringRef, size_t> &A, std::pair<StringRef, size_t> &B) {return A.second < B.second;});
+ for (const std::pair<StringRef, size_t> &P : Entries) {
StringRef Data = P.first;
- memcpy(Buf + P.second, Data.data(), Data.size());
+ OS.write(Data.data(), Data.size());
}
}
@@ -1293,12 +1383,14 @@ unsigned StringTableSection<ELFT>::addString(StringRef S, bool HashIt) {
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;
+template <class ELFT>
+void StringTableSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+ // ELF string tables start with NUL byte.
+ this->align(OS);
+ OS << '\0';
for (StringRef S : Strings) {
- memcpy(Buf, S.data(), S.size());
- Buf += S.size() + 1;
+ OS << S;
+ OS << '\0';
}
}
@@ -1358,45 +1450,49 @@ void SymbolTableSection<ELFT>::addSymbol(SymbolBody *Body) {
std::make_pair(Body, StrTabSec.addString(Body->getName(), false)));
}
-template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
- Buf += sizeof(Elf_Sym);
+template <class ELFT>
+void SymbolTableSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+ this->align(OS);
+ // First entry is null.
+ Elf_Sym S{};
+ OS.write(reinterpret_cast<const char *>(&S), sizeof(S));
// All symbols with STB_LOCAL binding precede the weak and global symbols.
// .dynsym only contains global symbols.
if (!Config->DiscardAll && !StrTabSec.isDynamic())
- writeLocalSymbols(Buf);
+ writeLocalSymbols(OS);
- writeGlobalSymbols(Buf);
+ writeGlobalSymbols(OS);
}
template <class ELFT>
-void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
+void SymbolTableSection<ELFT>::writeLocalSymbols(raw_fd_ostream &OS) {
// 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 *, unsigned> &P : File->KeptLocalSyms) {
const Elf_Sym *Sym = P.first;
-
- auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
uintX_t VA = 0;
+
+ Elf_Sym ESym{};
if (Sym->st_shndx == SHN_ABS) {
- ESym->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;
+ 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);
+ ESym.st_name = P.second;
+ ESym.st_size = Sym->st_size;
+ ESym.setBindingAndType(Sym->getBinding(), Sym->getType());
+ ESym.st_value = VA;
+ OS.write(reinterpret_cast<const char*>(&ESym), sizeof(ESym));
}
}
}
@@ -1412,10 +1508,9 @@ getElfSym(SymbolBody &Body) {
}
template <class ELFT>
-void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
+void SymbolTableSection<ELFT>::writeGlobalSymbols(raw_fd_ostream &OS) {
// 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 *, unsigned> &P : Symbols) {
SymbolBody *Body = P.first;
const OutputSectionBase<ELFT> *OutSec = nullptr;
@@ -1447,7 +1542,9 @@ void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
break;
}
- ESym->st_name = P.second;
+ Elf_Sym ESym{};
+
+ ESym.st_name = P.second;
unsigned char Type = STT_NOTYPE;
uintX_t Size = 0;
@@ -1459,17 +1556,16 @@ void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
Size = C->Size;
}
- ESym->setBindingAndType(getSymbolBinding(Body), Type);
- ESym->st_size = Size;
- ESym->setVisibility(Body->getVisibility());
- ESym->st_value = Body->getVA<ELFT>();
+ ESym.setBindingAndType(getSymbolBinding(Body), Type);
+ ESym.st_size = Size;
+ ESym.setVisibility(Body->getVisibility());
+ ESym.st_value = Body->getVA<ELFT>();
if (OutSec)
- ESym->st_shndx = OutSec->SectionIndex;
+ ESym.st_shndx = OutSec->SectionIndex;
else if (isa<DefinedRegular<ELFT>>(Body))
- ESym->st_shndx = SHN_ABS;
-
- ++ESym;
+ ESym.st_shndx = SHN_ABS;
+ OS.write(reinterpret_cast<const char*>(&ESym), sizeof(ESym));
}
}
@@ -1494,10 +1590,13 @@ MipsReginfoOutputSection<ELFT>::MipsReginfoOutputSection()
}
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;
+void MipsReginfoOutputSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+ this->align(OS);
+
+ Elf_Mips_RegInfo R{};
+ R.ri_gp_value = getMipsGpAddr<ELFT>();
+ R.ri_gprmask = GprMask;
+ OS.write(reinterpret_cast<const char*>(&R), sizeof(R));
}
template <class ELFT>
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index 7045720..5104bfe 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -19,6 +19,10 @@
#include <type_traits>
+namespace llvm {
+class raw_fd_ostream;
+}
+
namespace lld {
namespace elf2 {
@@ -70,7 +74,7 @@ public:
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);
+ void writeHeaderTo(llvm::raw_fd_ostream &OS);
StringRef getName() { return Name; }
virtual void addSection(InputSectionBase<ELFT> *C) {}
@@ -94,10 +98,12 @@ public:
}
virtual void finalize() {}
- virtual void writeTo(uint8_t *Buf) = 0;
+ virtual void writeTo(llvm::raw_fd_ostream &OS) = 0;
+ virtual void relocate(uint8_t *Buf) {}
virtual ~OutputSectionBase() = default;
protected:
+ void align(llvm::raw_fd_ostream &OS);
StringRef Name;
Elf_Shdr Header;
};
@@ -109,7 +115,7 @@ template <class ELFT> class GotSection final : public OutputSectionBase<ELFT> {
public:
GotSection();
void finalize() override;
- void writeTo(uint8_t *Buf) override;
+ void writeTo(llvm::raw_fd_ostream &OS) override;
void addEntry(SymbolBody *Sym);
void addMipsLocalEntry();
bool addDynTlsEntry(SymbolBody *Sym);
@@ -148,7 +154,7 @@ class GotPltSection final : public OutputSectionBase<ELFT> {
public:
GotPltSection();
void finalize() override;
- void writeTo(uint8_t *Buf) override;
+ void writeTo(llvm::raw_fd_ostream &OS) override;
void addEntry(SymbolBody *Sym);
bool empty() const;
@@ -163,7 +169,7 @@ template <class ELFT> class PltSection final : public OutputSectionBase<ELFT> {
public:
PltSection();
void finalize() override;
- void writeTo(uint8_t *Buf) override;
+ void writeTo(llvm::raw_fd_ostream &OS) override;
void addEntry(SymbolBody *Sym);
bool empty() const { return Entries.empty(); }
@@ -188,7 +194,7 @@ public:
StringTableSection<ELFT> &StrTabSec);
void finalize() override;
- void writeTo(uint8_t *Buf) override;
+ void writeTo(llvm::raw_fd_ostream &OS) override;
void addSymbol(SymbolBody *Body);
StringTableSection<ELFT> &getStrTabSec() const { return StrTabSec; }
unsigned getNumSymbols() const { return NumLocals + Symbols.size() + 1; }
@@ -201,8 +207,8 @@ public:
StringTableSection<ELFT> &StrTabSec;
private:
- void writeLocalSymbols(uint8_t *&Buf);
- void writeGlobalSymbols(uint8_t *Buf);
+ void writeLocalSymbols(llvm::raw_fd_ostream &OS);
+ void writeGlobalSymbols(llvm::raw_fd_ostream &OS);
static uint8_t getSymbolBinding(SymbolBody *Body);
@@ -221,15 +227,15 @@ public:
void addReloc(const DynamicReloc<ELFT> &Reloc) { Relocs.push_back(Reloc); }
unsigned getRelocOffset();
void finalize() override;
- void writeTo(uint8_t *Buf) override;
+ void writeTo(llvm::raw_fd_ostream &OS) override;
bool hasRelocs() const { return !Relocs.empty(); }
bool isRela() const { return IsRela; }
bool Static = false;
private:
- bool applyTlsDynamicReloc(SymbolBody *Body, uint32_t Type, Elf_Rel *P,
- Elf_Rel *N);
+ bool applyTlsDynamicReloc(SymbolBody *Body, uint32_t Type,
+ llvm::raw_fd_ostream &OS);
std::vector<DynamicReloc<ELFT>> Relocs;
const bool IsRela;
@@ -245,7 +251,8 @@ public:
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
OutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags);
void addSection(InputSectionBase<ELFT> *C) override;
- void writeTo(uint8_t *Buf) override;
+ void writeTo(llvm::raw_fd_ostream &OS) override;
+ void relocate(uint8_t *Buf) override;
private:
std::vector<InputSection<ELFT> *> Sections;
@@ -260,7 +267,7 @@ class MergeOutputSection final : public OutputSectionBase<ELFT> {
public:
MergeOutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags);
void addSection(InputSectionBase<ELFT> *S) override;
- void writeTo(uint8_t *Buf) override;
+ void writeTo(llvm::raw_fd_ostream &OS) override;
unsigned getOffset(StringRef Val);
void finalize() override;
@@ -291,7 +298,7 @@ public:
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 sh_type, uintX_t sh_flags);
- void writeTo(uint8_t *Buf) override;
+ void writeTo(llvm::raw_fd_ostream &OS) override;
template <bool IsRela>
void addSectionAux(
@@ -300,6 +307,7 @@ public:
Rels);
void addSection(InputSectionBase<ELFT> *S) override;
+ void relocate(uint8_t *Buf) override;
private:
uint8_t getFdeEncoding(ArrayRef<uint8_t> D);
@@ -316,7 +324,7 @@ template <class ELFT>
class InterpSection final : public OutputSectionBase<ELFT> {
public:
InterpSection();
- void writeTo(uint8_t *Buf) override;
+ void writeTo(llvm::raw_fd_ostream &OS) override;
};
template <class ELFT>
@@ -325,7 +333,7 @@ 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;
+ void writeTo(llvm::raw_fd_ostream &OS) override;
unsigned getSize() const { return Size; }
void finalize() override { this->Header.sh_size = getSize(); }
bool isDynamic() const { return Dynamic; }
@@ -344,7 +352,7 @@ class HashTableSection final : public OutputSectionBase<ELFT> {
public:
HashTableSection();
void finalize() override;
- void writeTo(uint8_t *Buf) override;
+ void writeTo(llvm::raw_fd_ostream &OS) override;
};
// Outputs GNU Hash section. For detailed explanation see:
@@ -358,7 +366,7 @@ class GnuHashTableSection final : public OutputSectionBase<ELFT> {
public:
GnuHashTableSection();
void finalize() override;
- void writeTo(uint8_t *Buf) override;
+ void writeTo(llvm::raw_fd_ostream &OS) override;
// Adds symbols to the hash table.
// Sorts the input to satisfy GNU hash section requirements.
@@ -368,9 +376,9 @@ 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);
+ void writeHeader(llvm::raw_fd_ostream &OS);
+ void writeBloomFilter(llvm::raw_fd_ostream &OS);
+ void writeHashTable(llvm::raw_fd_ostream &OS);
struct HashedSymbolData {
SymbolBody *Body;
@@ -414,7 +422,7 @@ class DynamicSection final : public OutputSectionBase<ELFT> {
public:
DynamicSection(SymbolTable<ELFT> &SymTab);
void finalize() override;
- void writeTo(uint8_t *Buf) override;
+ void writeTo(llvm::raw_fd_ostream &OS) override;
OutputSectionBase<ELFT> *PreInitArraySec = nullptr;
OutputSectionBase<ELFT> *InitArraySec = nullptr;
@@ -430,7 +438,7 @@ class MipsReginfoOutputSection final : public OutputSectionBase<ELFT> {
public:
MipsReginfoOutputSection();
- void writeTo(uint8_t *Buf) override;
+ void writeTo(llvm::raw_fd_ostream &OS) override;
void addSection(InputSectionBase<ELFT> *S) override;
private:
@@ -452,7 +460,7 @@ class EhFrameHeader final : public OutputSectionBase<ELFT> {
public:
EhFrameHeader();
- void writeTo(uint8_t *Buf) override;
+ void writeTo(llvm::raw_fd_ostream &OS) override;
void addFde(uint8_t Enc, size_t Off, uint8_t *PCRel);
void assignEhFrame(EHOutputSection<ELFT> *Sec);
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index d248459..4758d3d 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -22,8 +22,9 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/Endian.h"
#include "llvm/Support/ELF.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::object;
@@ -80,14 +81,15 @@ namespace {
class X86TargetInfo final : public TargetInfo {
public:
X86TargetInfo();
- void writeGotPltHeader(uint8_t *Buf) const override;
+ void writeGotPltHeader(raw_fd_ostream &OS) const override;
unsigned getDynRel(unsigned Type) const override;
unsigned getTlsGotRel(unsigned Type) const override;
bool isTlsDynRel(unsigned Type, const SymbolBody &S) const override;
- void writeGotPlt(uint8_t *Buf, uint64_t Plt) const override;
- void writePltZero(uint8_t *Buf) const override;
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
- int32_t Index, unsigned RelOff) const override;
+ void writeGotPlt(raw_fd_ostream &OS, uint64_t Plt) const override;
+ void writePltZero(raw_fd_ostream &OS) const override;
+ void writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const override;
bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
bool needsDynRelative(unsigned Type) const override;
bool needsGot(uint32_t Type, const SymbolBody &S) const override;
@@ -115,11 +117,13 @@ class X86_64TargetInfo final : public TargetInfo {
public:
X86_64TargetInfo();
bool isTlsDynRel(unsigned Type, const SymbolBody &S) const override;
- void writeGotPltHeader(uint8_t *Buf) const override;
- void writeGotPlt(uint8_t *Buf, uint64_t Plt) const override;
- void writePltZero(uint8_t *Buf) const override;
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
- int32_t Index, unsigned RelOff) const override;
+ void writeGotPltHeader(raw_fd_ostream &OS) const override;
+ void writeGotPlt(raw_fd_ostream &OS, uint64_t Plt) const override;
+ void writePltZero(raw_fd_ostream &OS) const override;
+ void writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const override;
+
bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
bool needsGot(uint32_t Type, const SymbolBody &S) const override;
bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
@@ -155,8 +159,9 @@ public:
class PPC64TargetInfo final : public TargetInfo {
public:
PPC64TargetInfo();
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
- int32_t Index, unsigned RelOff) const override;
+ void writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const override;
bool needsGot(uint32_t Type, const SymbolBody &S) const override;
bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
@@ -169,10 +174,11 @@ class AArch64TargetInfo final : public TargetInfo {
public:
AArch64TargetInfo();
unsigned getDynRel(unsigned Type) const override;
- void writeGotPlt(uint8_t *Buf, uint64_t Plt) const override;
- void writePltZero(uint8_t *Buf) const override;
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
- int32_t Index, unsigned RelOff) const override;
+ void writeGotPlt(raw_fd_ostream &OS, uint64_t Plt) const override;
+ void writePltZero(raw_fd_ostream &OS) const override;
+ void writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const override;
unsigned getTlsGotRel(unsigned Type = -1) const override;
bool isTlsDynRel(unsigned Type, const SymbolBody &S) const override;
bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
@@ -195,7 +201,7 @@ template <class ELFT> class MipsTargetInfo final : public TargetInfo {
public:
MipsTargetInfo();
unsigned getDynRel(unsigned Type) const override;
- void writeGotHeader(uint8_t *Buf) const override;
+ void writeGotHeader(raw_fd_ostream &OS) const override;
bool needsGot(uint32_t Type, const SymbolBody &S) const override;
bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
@@ -276,6 +282,14 @@ unsigned TargetInfo::relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
return 0;
}
+void TargetInfo::writeGotPltHeader(llvm::raw_fd_ostream &OS) const {
+ uint64_t E = 0;
+ unsigned Size =
+ (Config->EKind == ELF64LEKind || Config->EKind == ELF64BEKind) ? 8 : 4;
+ for (unsigned I = 0; I < GotPltHeaderEntriesNum; ++I)
+ OS.write((const char*)&E, Size);
+}
+
X86TargetInfo::X86TargetInfo() {
CopyRel = R_386_COPY;
GotRel = R_386_GLOB_DAT;
@@ -292,14 +306,16 @@ X86TargetInfo::X86TargetInfo() {
PltZeroSize = 16;
}
-void X86TargetInfo::writeGotPltHeader(uint8_t *Buf) const {
- write32le(Buf, Out<ELF32LE>::Dynamic->getVA());
+void X86TargetInfo::writeGotPltHeader(raw_fd_ostream &OS) const {
+ Writer<support::little> W(OS);
+ W.write<uint32_t>({Out<ELF32LE>::Dynamic->getVA(), 0, 0});
}
-void X86TargetInfo::writeGotPlt(uint8_t *Buf, uint64_t Plt) const {
+void X86TargetInfo::writeGotPlt(raw_fd_ostream &OS, uint64_t Plt) const {
+ Writer<support::little> W(OS);
// Entries in .got.plt initially points back to the corresponding
// PLT entries with a fixed offset to skip the first instruction.
- write32le(Buf, Plt + 6);
+ W.write<uint32_t>(Plt + 6);
}
unsigned X86TargetInfo::getDynRel(unsigned Type) const {
@@ -325,47 +341,53 @@ bool X86TargetInfo::isTlsDynRel(unsigned Type, const SymbolBody &S) const {
return Type == R_386_TLS_GD;
}
-void X86TargetInfo::writePltZero(uint8_t *Buf) const {
+void X86TargetInfo::writePltZero(raw_fd_ostream &OS) const {
+ Writer<support::little> W(OS);
+
// Executable files and shared object files have
// separate procedure linkage tables.
if (Config->Shared) {
- const uint8_t V[] = {
+ W.write<uint8_t>({
0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx)
0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx)
0x90, 0x90, 0x90, 0x90 // nop; nop; nop; nop
- };
- memcpy(Buf, V, sizeof(V));
+ });
return;
}
- const uint8_t PltData[] = {
- 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOT+4)
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOT+8)
- 0x90, 0x90, 0x90, 0x90 // nop; nop; nop; nop
- };
- memcpy(Buf, PltData, sizeof(PltData));
uint32_t Got = Out<ELF32LE>::GotPlt->getVA();
- write32le(Buf + 2, Got + 4);
- write32le(Buf + 8, Got + 8);
+
+ // pushl (GOT+4)
+ W.write<uint8_t>({0xff, 0x35});
+ W.write<uint32_t>(Got + 4);
+
+ // jmp *(GOT+8)
+ W.write<uint8_t>({0xff, 0x25});
+ W.write<uint32_t>(Got + 8);
+
+ // nop; nop; nop; nop
+ W.write<uint8_t>({0x90, 0x90, 0x90, 0x90});
}
-void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+void X86TargetInfo::writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
- const uint8_t Inst[] = {
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, // jmp *foo_in_GOT|*foo at GOT(%ebx)
- 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $reloc_offset
- 0xe9, 0x00, 0x00, 0x00, 0x00 // jmp .PLT0 at PC
- };
- memcpy(Buf, Inst, sizeof(Inst));
+ Writer<support::little> W(OS);
- // jmp *foo at GOT(%ebx) or jmp *foo_in_GOT
- Buf[1] = Config->Shared ? 0xa3 : 0x25;
uint32_t Got = UseLazyBinding ? Out<ELF32LE>::GotPlt->getVA()
: Out<ELF32LE>::Got->getVA();
- write32le(Buf + 2, Config->Shared ? GotEntryAddr - Got : GotEntryAddr);
- write32le(Buf + 7, RelOff);
- write32le(Buf + 12, -Index * PltEntrySize - PltZeroSize - 16);
+
+ // jmp *foo_in_GOT|*foo at GOT(%ebx)
+ W.write<uint8_t>({0xff, Config->Shared ? (uint8_t)0xa3 : (uint8_t)0x25});
+ W.write<uint32_t>(Config->Shared ? GotEntryAddr - Got : GotEntryAddr);
+
+ // pushl $reloc_offset
+ W.write<uint8_t>(0x68);
+ W.write<uint32_t>(RelOff);
+
+ // jmp .PLT0 at PC
+ W.write<uint8_t>(0xe9);
+ W.write<uint32_t>(-Index * PltEntrySize - PltZeroSize - 16);
}
bool X86TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const {
@@ -600,41 +622,50 @@ X86_64TargetInfo::X86_64TargetInfo() {
PltZeroSize = 16;
}
-void X86_64TargetInfo::writeGotPltHeader(uint8_t *Buf) const {
- write64le(Buf, Out<ELF64LE>::Dynamic->getVA());
+void X86_64TargetInfo::writeGotPltHeader(raw_fd_ostream &OS) const {
+ Writer<support::little> W(OS);
+ W.write<uint64_t>({Out<ELF64LE>::Dynamic->getVA(), 0, 0});
}
-void X86_64TargetInfo::writeGotPlt(uint8_t *Buf, uint64_t Plt) const {
+void X86_64TargetInfo::writeGotPlt(raw_fd_ostream &OS, uint64_t Plt) const {
// See comments in X86TargetInfo::writeGotPlt.
- write32le(Buf, Plt + 6);
+ Writer<support::little> W(OS);
+ W.write<uint64_t>(Plt + 6);
}
-void X86_64TargetInfo::writePltZero(uint8_t *Buf) const {
- const uint8_t PltData[] = {
- 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip)
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip)
- 0x0f, 0x1f, 0x40, 0x00 // nopl 0x0(rax)
- };
- memcpy(Buf, PltData, sizeof(PltData));
+void X86_64TargetInfo::writePltZero(raw_fd_ostream &OS) const {
+ Writer<support::little> W(OS);
uint64_t Got = Out<ELF64LE>::GotPlt->getVA();
uint64_t Plt = Out<ELF64LE>::Plt->getVA();
- write32le(Buf + 2, Got - Plt + 2); // GOT+8
- write32le(Buf + 8, Got - Plt + 4); // GOT+16
+
+ // pushq GOT+8(%rip)
+ W.write<uint8_t>({0xff, 0x35});
+ W.write<uint32_t>(Got - Plt + 2); // GOT+8
+
+ // jmp *GOT+16(%rip)
+ W.write<uint8_t>({0xff, 0x25});
+ W.write<uint32_t>(Got - Plt + 4); // GOT+16
+
+ // nopl 0x0(rax)
+ W.write<uint8_t>({0x0f, 0x1f, 0x40, 0x00});
}
-void X86_64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+void X86_64TargetInfo::writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
- const uint8_t Inst[] = {
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip)
- 0x68, 0x00, 0x00, 0x00, 0x00, // pushq <relocation index>
- 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[0]
- };
- memcpy(Buf, Inst, sizeof(Inst));
+ Writer<support::little> W(OS);
+
+ // jmpq *got(%rip)
+ W.write<uint8_t>({0xff, 0x25});
+ W.write<uint32_t>(GotEntryAddr - PltEntryAddr - 6);
+
+ // pushq <relocation index>
+ W.write<uint8_t>(0x68);
+ W.write<uint32_t>(Index);
- write32le(Buf + 2, GotEntryAddr - PltEntryAddr - 6);
- write32le(Buf + 7, Index);
- write32le(Buf + 12, -Index * PltEntrySize - PltZeroSize - 16);
+ // jmpq plt[0]
+ W.write<uint8_t>(0xe9);
+ W.write<uint32_t>(-Index * PltEntrySize - PltZeroSize - 16);
}
bool X86_64TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const {
@@ -970,7 +1001,7 @@ uint64_t getPPC64TocBase() {
return TocVA + 0x8000;
}
-void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+void PPC64TargetInfo::writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
uint64_t Off = GotEntryAddr - getPPC64TocBase();
@@ -980,15 +1011,15 @@ void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
// TOC-base pointer). Instead, we have the GOT-entry offset, and that will
// be a pointer to the function descriptor in the .opd section. Using
// this scheme is simpler, but requires an extra indirection per PLT dispatch.
-
- write32be(Buf, 0xf8410028); // std %r2, 40(%r1)
- write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X at ha
- write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X at l(%r11)
- write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12)
- write32be(Buf + 16, 0x7d6903a6); // mtctr %r11
- write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12)
- write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12)
- write32be(Buf + 28, 0x4e800420); // bctr
+ Writer<support::big> W(OS);
+ W.write<uint32_t>(0xf8410028); // std %r2, 40(%r1)
+ W.write<uint32_t>(0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X at ha
+ W.write<uint32_t>(0xe98b0000 | applyPPCLo(Off)); // ld %r12, X at l(%r11)
+ W.write<uint32_t>(0xe96c0000); // ld %r11,0(%r12)
+ W.write<uint32_t>(0x7d6903a6); // mtctr %r11
+ W.write<uint32_t>(0xe84c0008); // ld %r2,8(%r12)
+ W.write<uint32_t>(0xe96c0010); // ld %r11,16(%r12)
+ W.write<uint32_t>(0x4e800420); // bctr
}
bool PPC64TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
@@ -1160,12 +1191,13 @@ unsigned AArch64TargetInfo::getDynRel(unsigned Type) const {
"recompile with -fPIC.");
}
-void AArch64TargetInfo::writeGotPlt(uint8_t *Buf, uint64_t Plt) const {
- write64le(Buf, Out<ELF64LE>::Plt->getVA());
+void AArch64TargetInfo::writeGotPlt(raw_fd_ostream &OS, uint64_t Plt) const {
+ Writer<support::little> W(OS);
+ W.write((uint64_t)Out<ELF64LE>::Plt->getVA());
}
-void AArch64TargetInfo::writePltZero(uint8_t *Buf) const {
- const uint8_t PltData[] = {
+void AArch64TargetInfo::writePltZero(raw_fd_ostream &OS) const {
+ uint8_t PltData[] = {
0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]!
0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2]))
0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))]
@@ -1175,34 +1207,35 @@ void AArch64TargetInfo::writePltZero(uint8_t *Buf) const {
0x1f, 0x20, 0x03, 0xd5, // nop
0x1f, 0x20, 0x03, 0xd5 // nop
};
- memcpy(Buf, PltData, sizeof(PltData));
uint64_t Got = Out<ELF64LE>::GotPlt->getVA();
uint64_t Plt = Out<ELF64LE>::Plt->getVA();
- relocateOne(Buf + 4, Buf + 8, R_AARCH64_ADR_PREL_PG_HI21, Plt + 4, Got + 16);
- relocateOne(Buf + 8, Buf + 12, R_AARCH64_LDST64_ABS_LO12_NC, Plt + 8,
+ relocateOne(PltData + 4, PltData + 8, R_AARCH64_ADR_PREL_PG_HI21, Plt + 4, Got + 16);
+ relocateOne(PltData + 8, PltData + 12, R_AARCH64_LDST64_ABS_LO12_NC, Plt + 8,
Got + 16);
- relocateOne(Buf + 12, Buf + 16, R_AARCH64_ADD_ABS_LO12_NC, Plt + 12,
+ relocateOne(PltData + 12, PltData + 16, R_AARCH64_ADD_ABS_LO12_NC, Plt + 12,
Got + 16);
+ OS.write((const char*)PltData, sizeof(PltData));
}
-void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+void AArch64TargetInfo::writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
- const uint8_t Inst[] = {
+ uint8_t Inst[] = {
0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n]))
0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))]
0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[n]))
0x20, 0x02, 0x1f, 0xd6 // br x17
};
- memcpy(Buf, Inst, sizeof(Inst));
- relocateOne(Buf, Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, PltEntryAddr,
+ relocateOne(Inst, Inst + 4, R_AARCH64_ADR_PREL_PG_HI21, PltEntryAddr,
GotEntryAddr);
- relocateOne(Buf + 4, Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, PltEntryAddr + 4,
+ relocateOne(Inst + 4, Inst + 8, R_AARCH64_LDST64_ABS_LO12_NC, PltEntryAddr + 4,
GotEntryAddr);
- relocateOne(Buf + 8, Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, PltEntryAddr + 8,
+ relocateOne(Inst + 8, Inst + 12, R_AARCH64_ADD_ABS_LO12_NC, PltEntryAddr + 8,
GotEntryAddr);
+ Writer<support::little> W(OS);
+ W.write<uint8_t>(Inst);
}
unsigned AArch64TargetInfo::getTlsGotRel(unsigned Type) const {
@@ -1402,9 +1435,9 @@ unsigned MipsTargetInfo<ELFT>::getDynRel(unsigned Type) const {
}
template <class ELFT>
-void MipsTargetInfo<ELFT>::writeGotHeader(uint8_t *Buf) const {
- typedef typename ELFFile<ELFT>::Elf_Off Elf_Off;
+void MipsTargetInfo<ELFT>::writeGotHeader(raw_fd_ostream &OS) const {
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
+ Writer<ELFT::TargetEndianness> W(OS);
// Set the MSB of the second GOT slot. This is not required by any
// MIPS ABI documentation, though.
@@ -1420,8 +1453,8 @@ void MipsTargetInfo<ELFT>::writeGotHeader(uint8_t *Buf) const {
// we've been doing this for years, it is probably a safe bet to
// keep doing this for now. We really need to revisit this to see
// if we had to do this.
- auto *P = reinterpret_cast<Elf_Off *>(Buf);
- P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31);
+ W.template write<uintX_t>(
+ {(uintX_t)0, (uintX_t)(1) << (ELFT::Is64Bits ? 63 : 31)});
}
template <class ELFT>
diff --git a/ELF/Target.h b/ELF/Target.h
index 2b1e14d..9e0f6e7 100644
--- a/ELF/Target.h
+++ b/ELF/Target.h
@@ -15,6 +15,10 @@
#include <memory>
+namespace llvm {
+class raw_fd_ostream;
+}
+
namespace lld {
namespace elf2 {
class SymbolBody;
@@ -27,16 +31,16 @@ public:
virtual unsigned getDynRel(unsigned Type) const { return Type; }
virtual bool isTlsDynRel(unsigned Type, const SymbolBody &S) const;
virtual unsigned getTlsGotRel(unsigned Type = -1) const { return TlsGotRel; }
- virtual void writeGotHeader(uint8_t *Buf) const {}
- virtual void writeGotPltHeader(uint8_t *Buf) const {}
- virtual void writeGotPlt(uint8_t *Buf, uint64_t Plt) const {};
+ virtual void writeGotHeader(llvm::raw_fd_ostream &OS) const {}
+ virtual void writeGotPltHeader(llvm::raw_fd_ostream &OS) const;
+ virtual void writeGotPlt(llvm::raw_fd_ostream &OS, uint64_t Plt) const {};
// If lazy binding is supported, the first entry of the PLT has code
// to call the dynamic linker to resolve PLT entries the first time
// they are called. This function writes that code.
- virtual void writePltZero(uint8_t *Buf) const {}
+ virtual void writePltZero(llvm::raw_fd_ostream &OS) const {}
- virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+ virtual void writePlt(llvm::raw_fd_ostream &OS, uint64_t GotEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {}
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index f8f6215..1226037 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -15,7 +15,6 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/StringSaver.h"
@@ -37,7 +36,7 @@ public:
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) {}
+ Writer(SymbolTable<ELFT> &S, raw_fd_ostream &OS) : OS(OS), Symtab(S) {}
void run();
private:
@@ -56,9 +55,9 @@ private:
void assignAddresses();
void buildSectionMap();
void fixAbsoluteSymbols();
- void openFile(StringRef OutputPath);
void writeHeader();
void writeSections();
+ void writeSectionHeader();
bool isDiscarded(InputSectionBase<ELFT> *IS) const;
StringRef getOutputSectionName(StringRef S) const;
bool needsInterpSection() const {
@@ -73,7 +72,7 @@ private:
void addCommonSymbols(std::vector<DefinedCommon *> &Syms);
void addCopyRelSymbols(std::vector<SharedSymbol<ELFT> *> &Syms);
- std::unique_ptr<llvm::FileOutputBuffer> Buffer;
+ raw_fd_ostream &OS;
BumpPtrAllocator Alloc;
std::vector<OutputSectionBase<ELFT> *> OutputSections;
@@ -147,7 +146,10 @@ template <class ELFT> void elf2::writeResult(SymbolTable<ELFT> *Symtab) {
EhFrameHeader<ELFT> EhFrameHdr;
Out<ELFT>::EhFrameHdr = &EhFrameHdr;
- Writer<ELFT>(*Symtab).run();
+ // FIXME: use temp file
+ std::error_code EC;
+ raw_fd_ostream OS(Config->OutputFile,EC, sys::fs::F_RW);
+ Writer<ELFT>(*Symtab, OS).run();
}
// The main function of the writer.
@@ -160,10 +162,9 @@ template <class ELFT> void Writer<ELFT>::run() {
return;
assignAddresses();
fixAbsoluteSymbols();
- openFile(Config->OutputFile);
writeHeader();
writeSections();
- fatal(Buffer->commit());
+ writeSectionHeader();
}
namespace {
@@ -356,22 +357,6 @@ void Writer<ELFT>::scanRelocs(
}
}
-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)
@@ -473,6 +458,12 @@ template <class ELFT> static bool isRelroSection(OutputSectionBase<ELFT> *Sec) {
S == ".eh_frame";
}
+template <class ELFT>
+static bool isAfterReloc(OutputSectionBase<ELFT> *S) {
+ return S == Out<ELFT>::Got || S == Out<ELFT>::EhFrameHdr ||
+ S == Out<ELFT>::RelaDyn || S == Out<ELFT>::RelaPlt;
+}
+
// Output section ordering is determined by this function.
template <class ELFT>
static bool compareOutputSections(OutputSectionBase<ELFT> *A,
@@ -494,6 +485,12 @@ static bool compareOutputSections(OutputSectionBase<ELFT> *A,
if (!AIsAlloc)
return false;
+
+ bool AIsAfterReloc = isAfterReloc(A);
+ bool BIsAfterReloc = isAfterReloc(B);
+ if (AIsAfterReloc != BIsAfterReloc)
+ return BIsAfterReloc;
+
// 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;
@@ -846,20 +843,6 @@ template <class ELFT> bool Writer<ELFT>::createSections() {
for (OutputSectionBase<ELFT> *Sec : RegularSections)
addStartStopSymbols(Sec);
- // 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);
- }
- }
-
// Define __rel[a]_iplt_{start,end} symbols if needed.
addRelIpltSymbols();
@@ -899,6 +882,8 @@ template <class ELFT> bool Writer<ELFT>::createSections() {
// This function adds linker-created Out<ELFT>::* sections.
addPredefinedSections();
+ // FIXME: We don't actually support reordering some predefined sections. We
+ // should check for that.
std::stable_sort(OutputSections.begin(), OutputSections.end(),
compareSections<ELFT>);
@@ -1284,64 +1269,86 @@ template <class ELFT> void Writer<ELFT>::fixAbsoluteSymbols() {
}
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
+ Elf_Ehdr EHdr{};
+ EHdr.e_ident[0] = 0x7f;
+ EHdr.e_ident[1] = 'E';
+ EHdr.e_ident[2] = 'L';
+ EHdr.e_ident[3] = 'F';
+ 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;
+ 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;
- 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;
+ EHdr.e_ident[EI_OSABI] = FirstObj.getOSABI();
+
+ EHdr.e_type = Config->Shared ? ET_DYN : 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;
+
+ OS.write(reinterpret_cast<const char*>(&EHdr), sizeof(EHdr));
// Write the program header table.
- memcpy(Buf + EHdr->e_phoff, &Phdrs[0], Phdrs.size() * sizeof(Phdrs[0]));
+ OS.write(reinterpret_cast<const char *>(&Phdrs[0]),
+ Phdrs.size() * sizeof(Phdrs[0]));
+}
+template <class ELFT> void Writer<ELFT>::writeSectionHeader() {
// Write the section header table. Note that the first table entry is null.
- auto SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
+ OS.seek(SectionHeaderOff + sizeof(Elf_Shdr));
for (OutputSectionBase<ELFT> *Sec : OutputSections)
- Sec->writeHeaderTo(++SHdrs);
-}
-
-template <class ELFT> void Writer<ELFT>::openFile(StringRef Path) {
- ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
- FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable);
- fatal(BufferOrErr, "failed to open " + Path);
- Buffer = std::move(*BufferOrErr);
+ Sec->writeHeaderTo(OS);
}
// 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)
+ Sec->setSHName( Out<ELFT>::ShStrTab->addString(Sec->getName()));
+
+ unsigned SecI;
+ for (SecI = 0; SecI < OutputSections.size(); ++SecI) {
+ OutputSectionBase<ELFT> *Sec = OutputSections[SecI];
+ if (isAfterReloc(Sec))
+ break;
+ Sec->writeTo(OS);
}
+ OS.flush();
+ std::error_code EC;
+ sys::fs::mapped_file_region Region(
+ OS.getFD(), sys::fs::mapped_file_region::readwrite, OS.tell(), 0,
+ EC);
+ error(EC, "bar");
+ auto *Buf = reinterpret_cast<uint8_t*>(Region.data());
+
+ if (OutputSectionBase<ELFT> *Sec = Out<ELFT>::Opd)
+ Sec->relocate(Buf);
+
for (OutputSectionBase<ELFT> *Sec : OutputSections)
if (Sec != Out<ELFT>::Opd)
- Sec->writeTo(Buf + Sec->getFileOff());
+ Sec->relocate(Buf);
+
+ if (Out<ELFT>::RelaDyn->hasRelocs())
+ OutputSections.push_back(Out<ELFT>::RelaDyn);
+
+ for (; SecI < OutputSections.size(); ++SecI) {
+ OutputSectionBase<ELFT> *Sec = OutputSections[SecI];
+ Sec->writeTo(OS);
+ }
+
+
}
template <class ELFT>
diff --git a/test/ELF/basic.s b/test/ELF/basic.s
index bbc674c..c8559cd 100644
--- a/test/ELF/basic.s
+++ b/test/ELF/basic.s
@@ -98,7 +98,7 @@ _start:
# CHECK-NEXT: }
# CHECK-NEXT: Section {
# CHECK-NEXT: Index: 4
-# CHECK-NEXT: Name: .strtab (25)
+# CHECK-NEXT: Name: .strtab
# CHECK-NEXT: Type: SHT_STRTAB (0x3)
# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
diff --git a/test/ELF/eh-frame-hdr.s b/test/ELF/eh-frame-hdr.s
index 97bef97..707b8f3 100644
--- a/test/ELF/eh-frame-hdr.s
+++ b/test/ELF/eh-frame-hdr.s
@@ -48,8 +48,8 @@ _start:
// HDR-NEXT: Flags [
// HDR-NEXT: SHF_ALLOC
// HDR-NEXT: ]
-// HDR-NEXT: Address: 0x10158
-// HDR-NEXT: Offset: 0x158
+// HDR-NEXT: Address: 0x10190
+// HDR-NEXT: Offset: 0x190
// HDR-NEXT: Size: 96
// HDR-NEXT: Link: 0
// HDR-NEXT: Info: 0
diff --git a/test/ELF/mips-got16.s b/test/ELF/mips-got16.s
index c1eee3c..89b1189 100644
--- a/test/ELF/mips-got16.s
+++ b/test/ELF/mips-got16.s
@@ -19,24 +19,24 @@
#
# CHECK: SYMBOL TABLE:
# CHECK: 0001001c .text 00000000 $LC0
-# CHECK: 00030000 .data 00000000 $LC1
-# CHECK: 00030004 .data 00000000 .hidden bar
+# CHECK: 00020000 .data 00000000 $LC1
+# CHECK: 00020004 .data 00000000 .hidden bar
# CHECK: 00000000 *UND* 00000000 foo
# GOT: Relocations [
# GOT-NEXT: ]
# GOT: Primary GOT {
-# GOT-NEXT: Canonical gp value: 0x27FF0
+# GOT-NEXT: Canonical gp value: 0x28000
# GOT-NEXT: Reserved entries [
# GOT-NEXT: Entry {
-# GOT-NEXT: Address: 0x20000
+# GOT-NEXT: Address: 0x20010
# GOT-NEXT: Access: -32752
# GOT-NEXT: Initial: 0x0
# GOT-NEXT: Purpose: Lazy resolver
# GOT-NEXT: }
# GOT-NEXT: Entry {
-# GOT-NEXT: Address: 0x20004
+# GOT-NEXT: Address: 0x20014
# GOT-NEXT: Access: -32748
# GOT-NEXT: Initial: 0x80000000
# GOT-NEXT: Purpose: Module pointer (GNU extension)
@@ -44,24 +44,24 @@
# GOT-NEXT: ]
# GOT-NEXT: Local entries [
# GOT-NEXT: Entry {
-# GOT-NEXT: Address: 0x20008
+# GOT-NEXT: Address: 0x20018
# GOT-NEXT: Access: -32744
# GOT-NEXT: Initial: 0x10000
# GOT-NEXT: }
# GOT-NEXT: Entry {
-# GOT-NEXT: Address: 0x2000C
+# GOT-NEXT: Address: 0x2001C
# GOT-NEXT: Access: -32740
-# GOT-NEXT: Initial: 0x30000
+# GOT-NEXT: Initial: 0x20000
# GOT-NEXT: }
# GOT-NEXT: Entry {
-# GOT-NEXT: Address: 0x20010
+# GOT-NEXT: Address: 0x20020
# GOT-NEXT: Access: -32736
-# GOT-NEXT: Initial: 0x30004
+# GOT-NEXT: Initial: 0x20004
# GOT-NEXT: }
# GOT-NEXT: ]
# GOT-NEXT: Global entries [
# GOT-NEXT: Entry {
-# GOT-NEXT: Address: 0x20014
+# GOT-NEXT: Address: 0x20024
# GOT-NEXT: Access: -32732
# GOT-NEXT: Initial: 0x0
# GOT-NEXT: Value: 0x0
diff --git a/test/ELF/relro.s b/test/ELF/relro.s
index 692d6b2..5b040a2 100644
--- a/test/ELF/relro.s
+++ b/test/ELF/relro.s
@@ -11,7 +11,7 @@
// FULLRELRO: Section {
// FULLRELRO: Index: 9
-// FULLRELRO-NEXT: Name: .got
+// FULLRELRO-NEXT: Name: .got.plt
// FULLRELRO-NEXT: Type: SHT_PROGBITS
// FULLRELRO-NEXT: Flags [
// FULLRELRO-NEXT: SHF_ALLOC
@@ -19,25 +19,6 @@
// FULLRELRO-NEXT: ]
// FULLRELRO-NEXT: Address: 0x12110
// FULLRELRO-NEXT: Offset: 0x2110
-// FULLRELRO-NEXT: Size: 8
-// FULLRELRO-NEXT: Link: 0
-// FULLRELRO-NEXT: Info: 0
-// FULLRELRO-NEXT: AddressAlignment: 8
-// FULLRELRO-NEXT: EntrySize: 0
-// FULLRELRO-NEXT: SectionData (
-// FULLRELRO-NEXT: 0000: 00000000 00000000
-// FULLRELRO-NEXT: )
-// FULLRELRO-NEXT: }
-// FULLRELRO-NEXT: Section {
-// FULLRELRO-NEXT: Index: 10
-// FULLRELRO-NEXT: Name: .got.plt
-// FULLRELRO-NEXT: Type: SHT_PROGBITS
-// FULLRELRO-NEXT: Flags [
-// FULLRELRO-NEXT: SHF_ALLOC
-// FULLRELRO-NEXT: SHF_WRITE
-// FULLRELRO-NEXT: ]
-// FULLRELRO-NEXT: Address: 0x12118
-// FULLRELRO-NEXT: Offset: 0x2118
// FULLRELRO-NEXT: Size: 32
// FULLRELRO-NEXT: Link: 0
// FULLRELRO-NEXT: Info: 0
@@ -49,7 +30,7 @@
// FULLRELRO-NEXT: )
// FULLRELRO-NEXT: }
// FULLRELRO-NEXT: Section {
-// FULLRELRO-NEXT: Index: 11
+// FULLRELRO-NEXT: Index: 10
// FULLRELRO-NEXT: Name: .data
// FULLRELRO-NEXT: Type: SHT_PROGBITS
// FULLRELRO-NEXT: Flags [
@@ -68,7 +49,7 @@
// FULLRELRO-NEXT: )
// FULLRELRO-NEXT: }
// FULLRELRO-NEXT: Section {
-// FULLRELRO-NEXT: Index: 12
+// FULLRELRO-NEXT: Index: 11
// FULLRELRO-NEXT: Name: .foo
// FULLRELRO-NEXT: Type: SHT_PROGBITS
// FULLRELRO-NEXT: Flags [
More information about the llvm-commits
mailing list