forked from OSchip/llvm-project
Split the creation of program headers in a few steps.
IMHO this makes the code easier to read and should help with linker scripts. This is strongly based on D16575. The main differences are: We record a range of sections, not every section in a program header. scanHeaders takes case of deciding what goes in every program header, including PT_GNU_RELRO We create dummy sections for the start of the file With this, program header creation has 3 isolated stages: Map sections to program headers. Assign addresses to *sections* Looking at sections find the address and size of each program header. Thanks to George Rimar for the initial version. llvm-svn: 260453
This commit is contained in:
parent
b4a5aa239c
commit
4fc6044a5e
|
@ -94,7 +94,7 @@ public:
|
|||
}
|
||||
|
||||
virtual void finalize() {}
|
||||
virtual void writeTo(uint8_t *Buf) = 0;
|
||||
virtual void writeTo(uint8_t *Buf) {}
|
||||
virtual ~OutputSectionBase() = default;
|
||||
|
||||
protected:
|
||||
|
@ -540,6 +540,8 @@ template <class ELFT> struct Out {
|
|||
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;
|
||||
|
@ -562,6 +564,8 @@ 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
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#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"
|
||||
|
@ -41,6 +42,19 @@ public:
|
|||
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();
|
||||
|
@ -52,7 +66,7 @@ private:
|
|||
|
||||
void scanRelocs(InputSection<ELFT> &C);
|
||||
void scanRelocs(InputSectionBase<ELFT> &S, const Elf_Shdr &RelSec);
|
||||
void updateRelro(Elf_Phdr *Cur, Elf_Phdr *GnuRelroPhdr, uintX_t VA);
|
||||
void createPhdrs();
|
||||
void assignAddresses();
|
||||
void buildSectionMap();
|
||||
void fixAbsoluteSymbols();
|
||||
|
@ -67,7 +81,6 @@ private:
|
|||
bool isOutputDynamic() const {
|
||||
return !Symtab.getSharedFiles().empty() || Config->Shared;
|
||||
}
|
||||
int getPhdrsNum() const;
|
||||
|
||||
OutputSection<ELFT> *getBss();
|
||||
void addCommonSymbols(std::vector<DefinedCommon *> &Syms);
|
||||
|
@ -78,18 +91,22 @@ private:
|
|||
BumpPtrAllocator Alloc;
|
||||
std::vector<OutputSectionBase<ELFT> *> OutputSections;
|
||||
std::vector<std::unique_ptr<OutputSectionBase<ELFT>>> OwningSections;
|
||||
unsigned getNumSections() const { return OutputSections.size() + 1; }
|
||||
|
||||
// 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);
|
||||
}
|
||||
unsigned getNumSections() const {
|
||||
return OutputSections.size() + 1 - NumDummySections;
|
||||
}
|
||||
|
||||
void addRelIpltSymbols();
|
||||
void addStartEndSymbols();
|
||||
void addStartStopSymbols(OutputSectionBase<ELFT> *Sec);
|
||||
void setPhdr(Elf_Phdr *PH, uint32_t Type, uint32_t Flags, uintX_t FileOff,
|
||||
uintX_t VA, uintX_t Size, uintX_t Align);
|
||||
void copyPhdr(Elf_Phdr *PH, OutputSectionBase<ELFT> *From);
|
||||
|
||||
bool HasRelro = false;
|
||||
SymbolTable<ELFT> &Symtab;
|
||||
std::vector<Elf_Phdr> Phdrs;
|
||||
std::vector<Phdr> Phdrs;
|
||||
|
||||
uintX_t FileSize;
|
||||
uintX_t SectionHeaderOff;
|
||||
|
@ -105,6 +122,8 @@ private:
|
|||
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);
|
||||
|
@ -117,6 +136,10 @@ template <class ELFT> void elf2::writeResult(SymbolTable<ELFT> *Symtab) {
|
|||
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;
|
||||
|
@ -159,6 +182,8 @@ template <class ELFT> void elf2::writeResult(SymbolTable<ELFT> *Symtab) {
|
|||
Out<ELFT>::Opd = nullptr;
|
||||
Out<ELFT>::OpdBuf = nullptr;
|
||||
Out<ELFT>::TlsPhdr = nullptr;
|
||||
Out<ELFT>::ElfHeader = &ElfHeader;
|
||||
Out<ELFT>::ProgramHeaders = &ProgramHeaders;
|
||||
|
||||
Writer<ELFT>(*Symtab).run();
|
||||
}
|
||||
|
@ -171,6 +196,7 @@ template <class ELFT> void Writer<ELFT>::run() {
|
|||
addReservedSymbols();
|
||||
if (!createSections())
|
||||
return;
|
||||
createPhdrs();
|
||||
assignAddresses();
|
||||
fixAbsoluteSymbols();
|
||||
if (!openFile())
|
||||
|
@ -547,6 +573,8 @@ static int getPPC64SectionRank(StringRef SectionName) {
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -889,6 +917,9 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
|
|||
|
||||
// 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);
|
||||
|
||||
// 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())
|
||||
|
@ -994,12 +1025,10 @@ template <class ELFT> bool Writer<ELFT>::createSections() {
|
|||
std::stable_sort(OutputSections.begin(), OutputSections.end(),
|
||||
compareSections<ELFT>);
|
||||
|
||||
for (unsigned I = 0, N = OutputSections.size(); I < N; ++I) {
|
||||
OutputSections[I]->SectionIndex = I + 1;
|
||||
HasRelro |= (Config->ZRelro && isRelroSection(OutputSections[I]));
|
||||
}
|
||||
for (unsigned I = NumDummySections, N = OutputSections.size(); I < N; ++I)
|
||||
OutputSections[I]->SectionIndex = I + 1 - NumDummySections;
|
||||
|
||||
for (OutputSectionBase<ELFT> *Sec : OutputSections)
|
||||
for (OutputSectionBase<ELFT> *Sec : getSections())
|
||||
Sec->setSHName(Out<ELFT>::ShStrTab->addString(Sec->getName()));
|
||||
|
||||
// Finalizers fix each section's size.
|
||||
|
@ -1165,141 +1194,150 @@ static uint32_t getAmdgpuPhdr(OutputSectionBase<ELFT> *Sec) {
|
|||
return PT_LOAD;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void Writer<ELFT>::updateRelro(Elf_Phdr *Cur, Elf_Phdr *GnuRelroPhdr,
|
||||
uintX_t VA) {
|
||||
if (!GnuRelroPhdr->p_type)
|
||||
setPhdr(GnuRelroPhdr, PT_GNU_RELRO, PF_R, Cur->p_offset, Cur->p_vaddr,
|
||||
VA - Cur->p_vaddr, 1 /*p_align*/);
|
||||
GnuRelroPhdr->p_filesz = VA - Cur->p_vaddr;
|
||||
GnuRelroPhdr->p_memsz = VA - Cur->p_vaddr;
|
||||
}
|
||||
// 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);
|
||||
};
|
||||
|
||||
// Visits all sections to create PHDRs and to assign incremental,
|
||||
// non-overlapping addresses to output sections.
|
||||
template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
||||
uintX_t VA = Target->getVAStart() + sizeof(Elf_Ehdr);
|
||||
uintX_t FileOff = sizeof(Elf_Ehdr);
|
||||
|
||||
// Calculate and reserve the space for the program header first so that
|
||||
// the first section can start right after the program header.
|
||||
Phdrs.resize(getPhdrsNum());
|
||||
size_t PhdrSize = sizeof(Elf_Phdr) * Phdrs.size();
|
||||
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.
|
||||
setPhdr(&Phdrs[0], PT_PHDR, PF_R, FileOff, VA, PhdrSize,
|
||||
/*Align=*/sizeof(uintX_t));
|
||||
FileOff += PhdrSize;
|
||||
VA += PhdrSize;
|
||||
Phdr &Hdr = *AddHdr(PT_PHDR, PF_R);
|
||||
AddSec(Hdr, Out<ELFT>::ProgramHeaders);
|
||||
|
||||
// PT_INTERP must be the second entry if exists.
|
||||
int PhdrIdx = 0;
|
||||
Elf_Phdr *Interp = nullptr;
|
||||
if (needsInterpSection())
|
||||
Interp = &Phdrs[++PhdrIdx];
|
||||
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.
|
||||
setPhdr(&Phdrs[++PhdrIdx], PT_LOAD, PF_R, 0, Target->getVAStart(), FileOff,
|
||||
Target->PageSize);
|
||||
uintX_t Flags = PF_R;
|
||||
Phdr *Load = AddHdr(PT_LOAD, Flags);
|
||||
AddSec(*Load, Out<ELFT>::ElfHeader);
|
||||
|
||||
Elf_Phdr GnuRelroPhdr = {};
|
||||
Elf_Phdr TlsPhdr{};
|
||||
bool RelroAligned = false;
|
||||
uintX_t ThreadBssOffset = 0;
|
||||
// Create phdrs as we assign VAs and file offsets to all output sections.
|
||||
Phdr TlsHdr(PT_TLS, PF_R);
|
||||
Phdr RelRo(PT_GNU_RELRO, PF_R);
|
||||
for (OutputSectionBase<ELFT> *Sec : OutputSections) {
|
||||
Elf_Phdr *PH = &Phdrs[PhdrIdx];
|
||||
if (needsPhdr<ELFT>(Sec)) {
|
||||
uintX_t Flags = toPhdrFlags(Sec->getFlags());
|
||||
bool InRelRo = Config->ZRelro && (Flags & PF_W) && isRelroSection(Sec);
|
||||
bool FirstNonRelRo = GnuRelroPhdr.p_type && !InRelRo && !RelroAligned;
|
||||
if (FirstNonRelRo || PH->p_flags != Flags) {
|
||||
VA = alignTo(VA, Target->PageSize);
|
||||
FileOff = alignTo(FileOff, Target->PageSize);
|
||||
if (FirstNonRelRo)
|
||||
RelroAligned = true;
|
||||
}
|
||||
if (!needsPhdr<ELFT>(Sec))
|
||||
break;
|
||||
|
||||
if (PH->p_flags != Flags) {
|
||||
// Flags changed. Create a new PT_LOAD.
|
||||
PH = &Phdrs[++PhdrIdx];
|
||||
uint32_t PTType = (Config->EMachine != EM_AMDGPU) ? (uint32_t)PT_LOAD
|
||||
: getAmdgpuPhdr(Sec);
|
||||
setPhdr(PH, PTType, Flags, FileOff, VA, 0, Target->PageSize);
|
||||
}
|
||||
|
||||
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 = alignTo(VA, Sec->getAlign());
|
||||
uintX_t TVA = alignTo(VA + ThreadBssOffset, Sec->getAlign());
|
||||
Sec->setVA(TVA);
|
||||
TlsPhdr.p_memsz += Sec->getSize();
|
||||
if (Sec->getType() == SHT_NOBITS) {
|
||||
ThreadBssOffset = TVA - VA + Sec->getSize();
|
||||
} else {
|
||||
TlsPhdr.p_filesz += Sec->getSize();
|
||||
VA += Sec->getSize();
|
||||
}
|
||||
TlsPhdr.p_align = std::max<uintX_t>(TlsPhdr.p_align, Sec->getAlign());
|
||||
} else {
|
||||
VA = alignTo(VA, Sec->getAlign());
|
||||
Sec->setVA(VA);
|
||||
VA += Sec->getSize();
|
||||
}
|
||||
if (InRelRo)
|
||||
updateRelro(PH, &GnuRelroPhdr, VA);
|
||||
// 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;
|
||||
}
|
||||
// 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 (Sec->getType() == SHT_NOBITS)
|
||||
continue;
|
||||
}
|
||||
|
||||
FileOff = alignTo(FileOff, Sec->getAlign());
|
||||
Sec->setFileOffset(FileOff);
|
||||
if (Sec->getType() != SHT_NOBITS)
|
||||
FileOff += Sec->getSize();
|
||||
if (needsPhdr<ELFT>(Sec)) {
|
||||
PH->p_filesz = FileOff - PH->p_offset;
|
||||
PH->p_memsz = VA - PH->p_vaddr;
|
||||
}
|
||||
AddSec(*Load, Sec);
|
||||
|
||||
if (isRelroSection(Sec))
|
||||
AddSec(RelRo, Sec);
|
||||
}
|
||||
|
||||
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 = alignTo(TlsPhdr.p_memsz, TlsPhdr.p_align);
|
||||
Phdrs[++PhdrIdx] = TlsPhdr;
|
||||
Out<ELFT>::TlsPhdr = &Phdrs[PhdrIdx];
|
||||
}
|
||||
// Add the TLS segment unless it's empty.
|
||||
if (TlsHdr.First)
|
||||
Phdrs.push_back(std::move(TlsHdr));
|
||||
|
||||
// Add an entry for .dynamic.
|
||||
if (isOutputDynamic()) {
|
||||
Elf_Phdr *PH = &Phdrs[++PhdrIdx];
|
||||
PH->p_type = PT_DYNAMIC;
|
||||
copyPhdr(PH, Out<ELFT>::Dynamic);
|
||||
Phdr &H = *AddHdr(PT_DYNAMIC, toPhdrFlags(Out<ELFT>::Dynamic->getFlags()));
|
||||
AddSec(H, Out<ELFT>::Dynamic);
|
||||
}
|
||||
|
||||
if (HasRelro) {
|
||||
Elf_Phdr *PH = &Phdrs[++PhdrIdx];
|
||||
*PH = GnuRelroPhdr;
|
||||
}
|
||||
// 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) {
|
||||
Elf_Phdr *PH = &Phdrs[++PhdrIdx];
|
||||
PH->p_type = PT_GNU_EH_FRAME;
|
||||
copyPhdr(PH, Out<ELFT>::EhFrameHdr);
|
||||
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) {
|
||||
Elf_Phdr *PH = &Phdrs[++PhdrIdx];
|
||||
PH->p_type = PT_GNU_STACK;
|
||||
PH->p_flags = PF_R | PF_W;
|
||||
if (!Config->ZExecStack)
|
||||
AddHdr(PT_GNU_STACK, PF_R | PF_W);
|
||||
}
|
||||
|
||||
// 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
|
||||
// and is not tls, we have to align it to a page. We don't have to
|
||||
// align tls since TLS NOBITS takes no space.
|
||||
auto I = std::find(OutputSections.begin(), OutputSections.end(), P.Last);
|
||||
++I;
|
||||
if (I != OutputSections.end() && needsPhdr(*I) &&
|
||||
!((*I)->getFlags() & SHF_TLS))
|
||||
PageAlign.insert(*I);
|
||||
}
|
||||
|
||||
// FIXME: why create empty PT_LOAD?
|
||||
if (P.H.p_type == PT_LOAD && P.First)
|
||||
PageAlign.insert(P.First);
|
||||
}
|
||||
|
||||
// Fix up PT_INTERP as we now know the address of .interp section.
|
||||
if (Interp) {
|
||||
Interp->p_type = PT_INTERP;
|
||||
copyPhdr(Interp, Out<ELFT>::Interp);
|
||||
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);
|
||||
|
||||
FileOff = alignTo(FileOff, Align);
|
||||
Sec->setFileOffset(FileOff);
|
||||
if (Sec->getType() != SHT_NOBITS)
|
||||
FileOff += Sec->getSize();
|
||||
|
||||
// We only assign VAs to allocated sections.
|
||||
if (needsPhdr<ELFT>(Sec)) {
|
||||
// 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.
|
||||
bool IsTls = Sec->getFlags() & SHF_TLS;
|
||||
if (IsTls && Sec->getType() == SHT_NOBITS) {
|
||||
uintX_t TVA = VA + ThreadBssOffset;
|
||||
TVA = alignTo(TVA, Align);
|
||||
Sec->setVA(TVA);
|
||||
ThreadBssOffset = TVA - VA + Sec->getSize();
|
||||
} else {
|
||||
VA = alignTo(VA, Align);
|
||||
Sec->setVA(VA);
|
||||
VA += Sec->getSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add space for section headers.
|
||||
|
@ -1309,37 +1347,31 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
|||
// Update "_end" and "end" symbols so that they
|
||||
// point to the end of the data segment.
|
||||
ElfSym<ELFT>::End.st_value = VA;
|
||||
}
|
||||
|
||||
// Returns the number of PHDR entries.
|
||||
template <class ELFT> int Writer<ELFT>::getPhdrsNum() const {
|
||||
bool Tls = false;
|
||||
int I = 2; // 2 for PT_PHDR and first PT_LOAD
|
||||
if (needsInterpSection())
|
||||
++I;
|
||||
if (isOutputDynamic())
|
||||
++I;
|
||||
if (!Config->ZExecStack)
|
||||
++I;
|
||||
uintX_t Last = PF_R;
|
||||
for (OutputSectionBase<ELFT> *Sec : OutputSections) {
|
||||
if (!needsPhdr<ELFT>(Sec))
|
||||
continue;
|
||||
if (Sec->getFlags() & SHF_TLS)
|
||||
Tls = true;
|
||||
uintX_t Flags = toPhdrFlags(Sec->getFlags());
|
||||
if (Last != Flags) {
|
||||
Last = Flags;
|
||||
++I;
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (Tls)
|
||||
++I;
|
||||
if (HasRelro)
|
||||
++I;
|
||||
if (Out<ELFT>::EhFrameHdr->Live)
|
||||
++I;
|
||||
return I;
|
||||
}
|
||||
|
||||
static uint32_t getELFFlags() {
|
||||
|
@ -1412,11 +1444,13 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
|
|||
EHdr->e_shstrndx = Out<ELFT>::ShStrTab->SectionIndex;
|
||||
|
||||
// Write the program header table.
|
||||
memcpy(Buf + EHdr->e_phoff, &Phdrs[0], Phdrs.size() * sizeof(Phdrs[0]));
|
||||
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 : OutputSections)
|
||||
for (OutputSectionBase<ELFT> *Sec : getSections())
|
||||
Sec->writeHeaderTo(++SHdrs);
|
||||
}
|
||||
|
||||
|
@ -1446,31 +1480,6 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
|
|||
Sec->writeTo(Buf + Sec->getFileOff());
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void Writer<ELFT>::setPhdr(Elf_Phdr *PH, uint32_t Type, uint32_t Flags,
|
||||
uintX_t FileOff, uintX_t VA, uintX_t Size,
|
||||
uintX_t Align) {
|
||||
PH->p_type = Type;
|
||||
PH->p_flags = Flags;
|
||||
PH->p_offset = FileOff;
|
||||
PH->p_vaddr = VA;
|
||||
PH->p_paddr = VA;
|
||||
PH->p_filesz = Size;
|
||||
PH->p_memsz = Size;
|
||||
PH->p_align = Align;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void Writer<ELFT>::copyPhdr(Elf_Phdr *PH, OutputSectionBase<ELFT> *From) {
|
||||
PH->p_flags = toPhdrFlags(From->getFlags());
|
||||
PH->p_offset = From->getFileOff();
|
||||
PH->p_vaddr = From->getVA();
|
||||
PH->p_paddr = From->getVA();
|
||||
PH->p_filesz = From->getSize();
|
||||
PH->p_memsz = From->getSize();
|
||||
PH->p_align = From->getAlign();
|
||||
}
|
||||
|
||||
template <class ELFT> void Writer<ELFT>::buildSectionMap() {
|
||||
for (const std::pair<StringRef, std::vector<StringRef>> &OutSec :
|
||||
Config->OutputSections)
|
||||
|
|
Loading…
Reference in New Issue