mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-05 23:52:45 +00:00
ELF: Write .eh_frame_hdr explicitly after writing .eh_frame.
This lets us remove the special case from Writer::writeSections(), and also fixes a bug where .eh_frame_hdr isn't necessarily written in the correct order if a linker script moves .eh_frame and .eh_frame_hdr into the same output section. Differential Revision: https://reviews.llvm.org/D58795 llvm-svn: 355153
This commit is contained in:
parent
701593f1db
commit
7fb9eabda5
@ -30,6 +30,7 @@ using namespace llvm::ELF;
|
|||||||
using namespace lld;
|
using namespace lld;
|
||||||
using namespace lld::elf;
|
using namespace lld::elf;
|
||||||
|
|
||||||
|
uint8_t *Out::BufferStart;
|
||||||
uint8_t Out::First;
|
uint8_t Out::First;
|
||||||
PhdrEntry *Out::TlsPhdr;
|
PhdrEntry *Out::TlsPhdr;
|
||||||
OutputSection *Out::ElfHeader;
|
OutputSection *Out::ElfHeader;
|
||||||
@ -222,8 +223,6 @@ template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
|
|||||||
if (Type == SHT_NOBITS)
|
if (Type == SHT_NOBITS)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Loc = Buf;
|
|
||||||
|
|
||||||
// If -compress-debug-section is specified and if this is a debug seciton,
|
// If -compress-debug-section is specified and if this is a debug seciton,
|
||||||
// we've already compressed section contents. If that's the case,
|
// we've already compressed section contents. If that's the case,
|
||||||
// just write it down.
|
// just write it down.
|
||||||
|
@ -82,9 +82,6 @@ public:
|
|||||||
|
|
||||||
void addSection(InputSection *IS);
|
void addSection(InputSection *IS);
|
||||||
|
|
||||||
// Location in the output buffer.
|
|
||||||
uint8_t *Loc = nullptr;
|
|
||||||
|
|
||||||
// The following members are normally only used in linker scripts.
|
// The following members are normally only used in linker scripts.
|
||||||
MemoryRegion *MemRegion = nullptr;
|
MemoryRegion *MemRegion = nullptr;
|
||||||
MemoryRegion *LMARegion = nullptr;
|
MemoryRegion *LMARegion = nullptr;
|
||||||
@ -128,6 +125,7 @@ std::vector<InputSection *> getInputSections(OutputSection* OS);
|
|||||||
// globally accessible. Writer initializes them, so don't use them
|
// globally accessible. Writer initializes them, so don't use them
|
||||||
// until Writer is initialized.
|
// until Writer is initialized.
|
||||||
struct Out {
|
struct Out {
|
||||||
|
static uint8_t *BufferStart;
|
||||||
static uint8_t First;
|
static uint8_t First;
|
||||||
static PhdrEntry *TlsPhdr;
|
static PhdrEntry *TlsPhdr;
|
||||||
static OutputSection *ElfHeader;
|
static OutputSection *ElfHeader;
|
||||||
|
@ -509,7 +509,7 @@ void EhFrameSection::finalizeContents() {
|
|||||||
// to get an FDE from an address to which FDE is applied. This function
|
// to get an FDE from an address to which FDE is applied. This function
|
||||||
// returns a list of such pairs.
|
// returns a list of such pairs.
|
||||||
std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const {
|
std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const {
|
||||||
uint8_t *Buf = getParent()->Loc + OutSecOff;
|
uint8_t *Buf = Out::BufferStart + getParent()->Offset + OutSecOff;
|
||||||
std::vector<FdeData> Ret;
|
std::vector<FdeData> Ret;
|
||||||
|
|
||||||
uint64_t VA = In.EhFrameHdr->getVA();
|
uint64_t VA = In.EhFrameHdr->getVA();
|
||||||
@ -595,6 +595,9 @@ void EhFrameSection::writeTo(uint8_t *Buf) {
|
|||||||
// getOffset() takes care of discontiguous section pieces.
|
// getOffset() takes care of discontiguous section pieces.
|
||||||
for (EhInputSection *S : Sections)
|
for (EhInputSection *S : Sections)
|
||||||
S->relocateAlloc(Buf, nullptr);
|
S->relocateAlloc(Buf, nullptr);
|
||||||
|
|
||||||
|
if (In.EhFrameHdr && In.EhFrameHdr->getParent())
|
||||||
|
In.EhFrameHdr->write();
|
||||||
}
|
}
|
||||||
|
|
||||||
GotSection::GotSection()
|
GotSection::GotSection()
|
||||||
@ -2667,11 +2670,20 @@ bool GdbIndexSection::empty() const { return Chunks.empty(); }
|
|||||||
EhFrameHeader::EhFrameHeader()
|
EhFrameHeader::EhFrameHeader()
|
||||||
: SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {}
|
: SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {}
|
||||||
|
|
||||||
|
void EhFrameHeader::writeTo(uint8_t *Buf) {
|
||||||
|
// Unlike most sections, the EhFrameHeader section is written while writing
|
||||||
|
// another section, namely EhFrameSection, which calls the write() function
|
||||||
|
// below from its writeTo() function. This is necessary because the contents
|
||||||
|
// of EhFrameHeader depend on the relocated contents of EhFrameSection and we
|
||||||
|
// don't know which order the sections will be written in.
|
||||||
|
}
|
||||||
|
|
||||||
// .eh_frame_hdr contains a binary search table of pointers to FDEs.
|
// .eh_frame_hdr contains a binary search table of pointers to FDEs.
|
||||||
// Each entry of the search table consists of two values,
|
// Each entry of the search table consists of two values,
|
||||||
// the starting PC from where FDEs covers, and the FDE's address.
|
// the starting PC from where FDEs covers, and the FDE's address.
|
||||||
// It is sorted by PC.
|
// It is sorted by PC.
|
||||||
void EhFrameHeader::writeTo(uint8_t *Buf) {
|
void EhFrameHeader::write() {
|
||||||
|
uint8_t *Buf = Out::BufferStart + getParent()->Offset + OutSecOff;
|
||||||
typedef EhFrameSection::FdeData FdeData;
|
typedef EhFrameSection::FdeData FdeData;
|
||||||
|
|
||||||
std::vector<FdeData> Fdes = In.EhFrame->getFdeData();
|
std::vector<FdeData> Fdes = In.EhFrame->getFdeData();
|
||||||
|
@ -743,6 +743,7 @@ private:
|
|||||||
class EhFrameHeader final : public SyntheticSection {
|
class EhFrameHeader final : public SyntheticSection {
|
||||||
public:
|
public:
|
||||||
EhFrameHeader();
|
EhFrameHeader();
|
||||||
|
void write();
|
||||||
void writeTo(uint8_t *Buf) override;
|
void writeTo(uint8_t *Buf) override;
|
||||||
size_t getSize() const override;
|
size_t getSize() const override;
|
||||||
bool empty() const override;
|
bool empty() const override;
|
||||||
|
@ -98,7 +98,7 @@ template <class ELFT> static ErrorPlace getErrPlace(const uint8_t *Loc) {
|
|||||||
if (!IS->getParent())
|
if (!IS->getParent())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uint8_t *ISLoc = IS->getParent()->Loc + IS->OutSecOff;
|
uint8_t *ISLoc = Out::BufferStart + IS->getParent()->Offset + IS->OutSecOff;
|
||||||
if (ISLoc <= Loc && Loc < ISLoc + IS->getSize())
|
if (ISLoc <= Loc && Loc < ISLoc + IS->getSize())
|
||||||
return {IS, IS->template getLocation<ELFT>(Loc - ISLoc) + ": "};
|
return {IS, IS->template getLocation<ELFT>(Loc - ISLoc) + ": "};
|
||||||
}
|
}
|
||||||
|
@ -2407,16 +2407,14 @@ static uint8_t getAbiVersion() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT> void Writer<ELFT>::writeHeader() {
|
template <class ELFT> void Writer<ELFT>::writeHeader() {
|
||||||
uint8_t *Buf = Buffer->getBufferStart();
|
|
||||||
|
|
||||||
// For executable segments, the trap instructions are written before writing
|
// For executable segments, the trap instructions are written before writing
|
||||||
// the header. Setting Elf header bytes to zero ensures that any unused bytes
|
// the header. Setting Elf header bytes to zero ensures that any unused bytes
|
||||||
// in header are zero-cleared, instead of having trap instructions.
|
// in header are zero-cleared, instead of having trap instructions.
|
||||||
memset(Buf, 0, sizeof(Elf_Ehdr));
|
memset(Out::BufferStart, 0, sizeof(Elf_Ehdr));
|
||||||
memcpy(Buf, "\177ELF", 4);
|
memcpy(Out::BufferStart, "\177ELF", 4);
|
||||||
|
|
||||||
// Write the ELF header.
|
// Write the ELF header.
|
||||||
auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
|
auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Out::BufferStart);
|
||||||
EHdr->e_ident[EI_CLASS] = Config->Is64 ? ELFCLASS64 : ELFCLASS32;
|
EHdr->e_ident[EI_CLASS] = Config->Is64 ? ELFCLASS64 : ELFCLASS32;
|
||||||
EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB;
|
EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB;
|
||||||
EHdr->e_ident[EI_VERSION] = EV_CURRENT;
|
EHdr->e_ident[EI_VERSION] = EV_CURRENT;
|
||||||
@ -2438,7 +2436,7 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write the program header table.
|
// Write the program header table.
|
||||||
auto *HBuf = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
|
auto *HBuf = reinterpret_cast<Elf_Phdr *>(Out::BufferStart + EHdr->e_phoff);
|
||||||
for (PhdrEntry *P : Phdrs) {
|
for (PhdrEntry *P : Phdrs) {
|
||||||
HBuf->p_type = P->p_type;
|
HBuf->p_type = P->p_type;
|
||||||
HBuf->p_flags = P->p_flags;
|
HBuf->p_flags = P->p_flags;
|
||||||
@ -2460,7 +2458,7 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
|
|||||||
// the value. The sentinel values and fields are:
|
// the value. The sentinel values and fields are:
|
||||||
// e_shnum = 0, SHdrs[0].sh_size = number of sections.
|
// e_shnum = 0, SHdrs[0].sh_size = number of sections.
|
||||||
// e_shstrndx = SHN_XINDEX, SHdrs[0].sh_link = .shstrtab section index.
|
// e_shstrndx = SHN_XINDEX, SHdrs[0].sh_link = .shstrtab section index.
|
||||||
auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
|
auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Out::BufferStart + EHdr->e_shoff);
|
||||||
size_t Num = OutputSections.size() + 1;
|
size_t Num = OutputSections.size() + 1;
|
||||||
if (Num >= SHN_LORESERVE)
|
if (Num >= SHN_LORESERVE)
|
||||||
SHdrs->sh_size = Num;
|
SHdrs->sh_size = Num;
|
||||||
@ -2494,18 +2492,19 @@ template <class ELFT> void Writer<ELFT>::openFile() {
|
|||||||
Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
|
Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
|
||||||
FileOutputBuffer::create(Config->OutputFile, FileSize, Flags);
|
FileOutputBuffer::create(Config->OutputFile, FileSize, Flags);
|
||||||
|
|
||||||
if (!BufferOrErr)
|
if (!BufferOrErr) {
|
||||||
error("failed to open " + Config->OutputFile + ": " +
|
error("failed to open " + Config->OutputFile + ": " +
|
||||||
llvm::toString(BufferOrErr.takeError()));
|
llvm::toString(BufferOrErr.takeError()));
|
||||||
else
|
return;
|
||||||
Buffer = std::move(*BufferOrErr);
|
}
|
||||||
|
Buffer = std::move(*BufferOrErr);
|
||||||
|
Out::BufferStart = Buffer->getBufferStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT> void Writer<ELFT>::writeSectionsBinary() {
|
template <class ELFT> void Writer<ELFT>::writeSectionsBinary() {
|
||||||
uint8_t *Buf = Buffer->getBufferStart();
|
|
||||||
for (OutputSection *Sec : OutputSections)
|
for (OutputSection *Sec : OutputSections)
|
||||||
if (Sec->Flags & SHF_ALLOC)
|
if (Sec->Flags & SHF_ALLOC)
|
||||||
Sec->writeTo<ELFT>(Buf + Sec->Offset);
|
Sec->writeTo<ELFT>(Out::BufferStart + Sec->Offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fillTrap(uint8_t *I, uint8_t *End) {
|
static void fillTrap(uint8_t *I, uint8_t *End) {
|
||||||
@ -2524,11 +2523,12 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Fill the last page.
|
// Fill the last page.
|
||||||
uint8_t *Buf = Buffer->getBufferStart();
|
|
||||||
for (PhdrEntry *P : Phdrs)
|
for (PhdrEntry *P : Phdrs)
|
||||||
if (P->p_type == PT_LOAD && (P->p_flags & PF_X))
|
if (P->p_type == PT_LOAD && (P->p_flags & PF_X))
|
||||||
fillTrap(Buf + alignDown(P->p_offset + P->p_filesz, Target->PageSize),
|
fillTrap(Out::BufferStart +
|
||||||
Buf + alignTo(P->p_offset + P->p_filesz, Target->PageSize));
|
alignDown(P->p_offset + P->p_filesz, Target->PageSize),
|
||||||
|
Out::BufferStart +
|
||||||
|
alignTo(P->p_offset + P->p_filesz, Target->PageSize));
|
||||||
|
|
||||||
// Round up the file size of the last segment to the page boundary iff it is
|
// Round up the file size of the last segment to the page boundary iff it is
|
||||||
// an executable segment to ensure that other tools don't accidentally
|
// an executable segment to ensure that other tools don't accidentally
|
||||||
@ -2544,27 +2544,16 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
|
|||||||
|
|
||||||
// Write section contents to a mmap'ed file.
|
// Write section contents to a mmap'ed file.
|
||||||
template <class ELFT> void Writer<ELFT>::writeSections() {
|
template <class ELFT> void Writer<ELFT>::writeSections() {
|
||||||
uint8_t *Buf = Buffer->getBufferStart();
|
|
||||||
|
|
||||||
OutputSection *EhFrameHdr = nullptr;
|
|
||||||
if (In.EhFrameHdr && !In.EhFrameHdr->empty())
|
|
||||||
EhFrameHdr = In.EhFrameHdr->getParent();
|
|
||||||
|
|
||||||
// In -r or -emit-relocs mode, write the relocation sections first as in
|
// In -r or -emit-relocs mode, write the relocation sections first as in
|
||||||
// ELf_Rel targets we might find out that we need to modify the relocated
|
// ELf_Rel targets we might find out that we need to modify the relocated
|
||||||
// section while doing it.
|
// section while doing it.
|
||||||
for (OutputSection *Sec : OutputSections)
|
for (OutputSection *Sec : OutputSections)
|
||||||
if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
|
if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
|
||||||
Sec->writeTo<ELFT>(Buf + Sec->Offset);
|
Sec->writeTo<ELFT>(Out::BufferStart + Sec->Offset);
|
||||||
|
|
||||||
for (OutputSection *Sec : OutputSections)
|
for (OutputSection *Sec : OutputSections)
|
||||||
if (Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA)
|
if (Sec->Type != SHT_REL && Sec->Type != SHT_RELA)
|
||||||
Sec->writeTo<ELFT>(Buf + Sec->Offset);
|
Sec->writeTo<ELFT>(Out::BufferStart + Sec->Offset);
|
||||||
|
|
||||||
// The .eh_frame_hdr depends on .eh_frame section contents, therefore
|
|
||||||
// it should be written after .eh_frame is written.
|
|
||||||
if (EhFrameHdr)
|
|
||||||
EhFrameHdr->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT> void Writer<ELFT>::writeBuildId() {
|
template <class ELFT> void Writer<ELFT>::writeBuildId() {
|
||||||
@ -2572,9 +2561,7 @@ template <class ELFT> void Writer<ELFT>::writeBuildId() {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Compute a hash of all sections of the output file.
|
// Compute a hash of all sections of the output file.
|
||||||
uint8_t *Start = Buffer->getBufferStart();
|
In.BuildId->writeBuildId({Out::BufferStart, FileSize});
|
||||||
uint8_t *End = Start + FileSize;
|
|
||||||
In.BuildId->writeBuildId({Start, End});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template void elf::writeResult<ELF32LE>();
|
template void elf::writeResult<ELF32LE>();
|
||||||
|
20
lld/test/ELF/linkerscript/eh-frame-merge.s
Normal file
20
lld/test/ELF/linkerscript/eh-frame-merge.s
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# REQUIRES: x86
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
|
||||||
|
# RUN: echo "SECTIONS { .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame) } }" > %t.script
|
||||||
|
# RUN: ld.lld -o %t --no-threads --eh-frame-hdr --script %t.script %t.o
|
||||||
|
# RUN: llvm-readobj -s -u %t | FileCheck %s
|
||||||
|
|
||||||
|
# CHECK: Name: .dah
|
||||||
|
# CHECK-NOT: Section
|
||||||
|
# CHECK: Address: 0x4D
|
||||||
|
|
||||||
|
# CHECK: initial_location: 0x4d
|
||||||
|
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
nop
|
||||||
|
|
||||||
|
.section .dah,"ax",@progbits
|
||||||
|
.cfi_startproc
|
||||||
|
nop
|
||||||
|
.cfi_endproc
|
Loading…
Reference in New Issue
Block a user