diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -82,9 +82,6 @@ void addSection(InputSection *IS); - // Location in the output buffer. - uint8_t *Loc = nullptr; - // The following members are normally only used in linker scripts. MemoryRegion *MemRegion = nullptr; MemoryRegion *LMARegion = nullptr; @@ -128,6 +125,7 @@ // globally accessible. Writer initializes them, so don't use them // until Writer is initialized. struct Out { + static uint8_t *Base; static uint8_t First; static PhdrEntry *TlsPhdr; static OutputSection *ElfHeader; diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -30,6 +30,7 @@ using namespace lld; using namespace lld::elf; +uint8_t *Out::Base; uint8_t Out::First; PhdrEntry *Out::TlsPhdr; OutputSection *Out::ElfHeader; @@ -222,8 +223,6 @@ if (Type == SHT_NOBITS) return; - Loc = Buf; - // If -compress-debug-section is specified and if this is a debug seciton, // we've already compressed section contents. If that's the case, // just write it down. diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -743,6 +743,7 @@ class EhFrameHeader final : public SyntheticSection { public: EhFrameHeader(); + void write(); void writeTo(uint8_t *Buf) override; size_t getSize() const override; bool empty() const override; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -509,7 +509,7 @@ // to get an FDE from an address to which FDE is applied. This function // returns a list of such pairs. std::vector EhFrameSection::getFdeData() const { - uint8_t *Buf = getParent()->Loc + OutSecOff; + uint8_t *Buf = Out::Base + getParent()->Offset + OutSecOff; std::vector Ret; uint64_t VA = In.EhFrameHdr->getVA(); @@ -595,6 +595,9 @@ // getOffset() takes care of discontiguous section pieces. for (EhInputSection *S : Sections) S->relocateAlloc(Buf, nullptr); + + if (In.EhFrameHdr && In.EhFrameHdr->getParent()) + In.EhFrameHdr->write(); } GotSection::GotSection() @@ -2667,11 +2670,20 @@ EhFrameHeader::EhFrameHeader() : 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. // Each entry of the search table consists of two values, // the starting PC from where FDEs covers, and the FDE's address. // It is sorted by PC. -void EhFrameHeader::writeTo(uint8_t *Buf) { +void EhFrameHeader::write() { + uint8_t *Buf = Out::Base + getParent()->Offset + OutSecOff; typedef EhFrameSection::FdeData FdeData; std::vector Fdes = In.EhFrame->getFdeData(); diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -98,7 +98,7 @@ if (!IS->getParent()) continue; - uint8_t *ISLoc = IS->getParent()->Loc + IS->OutSecOff; + uint8_t *ISLoc = Out::Base + IS->getParent()->Offset + IS->OutSecOff; if (ISLoc <= Loc && Loc < ISLoc + IS->getSize()) return {IS, IS->template getLocation(Loc - ISLoc) + ": "}; } diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -2407,16 +2407,14 @@ } template void Writer::writeHeader() { - uint8_t *Buf = Buffer->getBufferStart(); - // For executable segments, the trap instructions are written before writing // the header. Setting Elf header bytes to zero ensures that any unused bytes // in header are zero-cleared, instead of having trap instructions. - memset(Buf, 0, sizeof(Elf_Ehdr)); - memcpy(Buf, "\177ELF", 4); + memset(Out::Base, 0, sizeof(Elf_Ehdr)); + memcpy(Out::Base, "\177ELF", 4); // Write the ELF header. - auto *EHdr = reinterpret_cast(Buf); + auto *EHdr = reinterpret_cast(Out::Base); EHdr->e_ident[EI_CLASS] = Config->Is64 ? ELFCLASS64 : ELFCLASS32; EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB; EHdr->e_ident[EI_VERSION] = EV_CURRENT; @@ -2438,7 +2436,7 @@ } // Write the program header table. - auto *HBuf = reinterpret_cast(Buf + EHdr->e_phoff); + auto *HBuf = reinterpret_cast(Out::Base + EHdr->e_phoff); for (PhdrEntry *P : Phdrs) { HBuf->p_type = P->p_type; HBuf->p_flags = P->p_flags; @@ -2460,7 +2458,7 @@ // the value. The sentinel values and fields are: // e_shnum = 0, SHdrs[0].sh_size = number of sections. // e_shstrndx = SHN_XINDEX, SHdrs[0].sh_link = .shstrtab section index. - auto *SHdrs = reinterpret_cast(Buf + EHdr->e_shoff); + auto *SHdrs = reinterpret_cast(Out::Base + EHdr->e_shoff); size_t Num = OutputSections.size() + 1; if (Num >= SHN_LORESERVE) SHdrs->sh_size = Num; @@ -2494,18 +2492,19 @@ Expected> BufferOrErr = FileOutputBuffer::create(Config->OutputFile, FileSize, Flags); - if (!BufferOrErr) + if (!BufferOrErr) { error("failed to open " + Config->OutputFile + ": " + llvm::toString(BufferOrErr.takeError())); - else - Buffer = std::move(*BufferOrErr); + return; + } + Buffer = std::move(*BufferOrErr); + Out::Base = Buffer->getBufferStart(); } template void Writer::writeSectionsBinary() { - uint8_t *Buf = Buffer->getBufferStart(); for (OutputSection *Sec : OutputSections) if (Sec->Flags & SHF_ALLOC) - Sec->writeTo(Buf + Sec->Offset); + Sec->writeTo(Out::Base + Sec->Offset); } static void fillTrap(uint8_t *I, uint8_t *End) { @@ -2524,11 +2523,11 @@ return; // Fill the last page. - uint8_t *Buf = Buffer->getBufferStart(); for (PhdrEntry *P : Phdrs) if (P->p_type == PT_LOAD && (P->p_flags & PF_X)) - fillTrap(Buf + alignDown(P->p_offset + P->p_filesz, Target->PageSize), - Buf + alignTo(P->p_offset + P->p_filesz, Target->PageSize)); + fillTrap( + Out::Base + alignDown(P->p_offset + P->p_filesz, Target->PageSize), + Out::Base + 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 // an executable segment to ensure that other tools don't accidentally @@ -2544,27 +2543,16 @@ // Write section contents to a mmap'ed file. template void Writer::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 // ELf_Rel targets we might find out that we need to modify the relocated // section while doing it. for (OutputSection *Sec : OutputSections) if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) - Sec->writeTo(Buf + Sec->Offset); + Sec->writeTo(Out::Base + Sec->Offset); for (OutputSection *Sec : OutputSections) - if (Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA) - Sec->writeTo(Buf + 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(Buf + EhFrameHdr->Offset); + if (Sec->Type != SHT_REL && Sec->Type != SHT_RELA) + Sec->writeTo(Out::Base + Sec->Offset); } template void Writer::writeBuildId() { @@ -2572,9 +2560,7 @@ return; // Compute a hash of all sections of the output file. - uint8_t *Start = Buffer->getBufferStart(); - uint8_t *End = Start + FileSize; - In.BuildId->writeBuildId({Start, End}); + In.BuildId->writeBuildId({Out::Base, FileSize}); } template void elf::writeResult(); diff --git a/lld/test/ELF/linkerscript/eh-frame-merge.s b/lld/test/ELF/linkerscript/eh-frame-merge.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/linkerscript/eh-frame-merge.s @@ -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