forked from OSchip/llvm-project
Reapply r257753 with fix:
Added check for terminator CIE/FDE which has zero data size. void EHOutputSection<ELFT>::addSectionAux( ... // If CIE/FDE data length is zero then Length is 4, this // shall be considered a terminator and processing shall end. if (Length == 4) break; ... After this "Bug 25923 - lld/ELF2 linked application crashes if exceptions were used." is fixed for me. Self link of clang also works. Initial commit message: [ELF] - implemented --eh-frame-hdr command line option. --eh-frame-hdr Request creation of ".eh_frame_hdr" section and ELF "PT_GNU_EH_FRAME" segment header. Both gold and the GNU linker support an option --eh-frame-hdr which tell them to construct a header for all the .eh_frame sections. This header is placed in a section named .eh_frame_hdr and also in a PT_GNU_EH_FRAME segment. At runtime the unwinder can find all the PT_GNU_EH_FRAME segments by calling dl_iterate_phdr. This section contains a lookup table for quick binary search of FDEs. Detailed info can be found here: http://www.airs.com/blog/archives/462 Differential revision: http://reviews.llvm.org/D15712 llvm-svn: 257889
This commit is contained in:
parent
9258e013a2
commit
f6bc65a3b2
|
@ -57,6 +57,7 @@ struct Configuration {
|
|||
bool DiscardAll;
|
||||
bool DiscardLocals;
|
||||
bool DiscardNone;
|
||||
bool EhFrameHdr;
|
||||
bool EnableNewDtags;
|
||||
bool ExportDynamic;
|
||||
bool GcSections;
|
||||
|
|
|
@ -189,6 +189,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
|
|||
Config->DiscardAll = Args.hasArg(OPT_discard_all);
|
||||
Config->DiscardLocals = Args.hasArg(OPT_discard_locals);
|
||||
Config->DiscardNone = Args.hasArg(OPT_discard_none);
|
||||
Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr);
|
||||
Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);
|
||||
Config->ExportDynamic = Args.hasArg(OPT_export_dynamic);
|
||||
Config->GcSections = Args.hasArg(OPT_gc_sections);
|
||||
|
|
|
@ -36,6 +36,9 @@ def discard_none : Flag<["-"], "discard-none">,
|
|||
def dynamic_linker : Separate<["--", "-"], "dynamic-linker">,
|
||||
HelpText<"Which dynamic linker to use">;
|
||||
|
||||
def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">,
|
||||
HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">;
|
||||
|
||||
def enable_new_dtags : Flag<["--"], "enable-new-dtags">,
|
||||
HelpText<"Enable new dynamic tags">;
|
||||
|
||||
|
@ -154,7 +157,6 @@ def start_group_paren: Flag<["-"], "(">;
|
|||
|
||||
// Options listed below are silently ignored for now for compatibility.
|
||||
def build_id : Flag<["--"], "build-id">;
|
||||
def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">;
|
||||
def fatal_warnings : Flag<["--"], "fatal-warnings">;
|
||||
def no_add_needed : Flag<["--"], "no-add-needed">;
|
||||
def no_fatal_warnings : Flag<["--"], "no-fatal-warnings">;
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
#include "Config.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "Target.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <map>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::object;
|
||||
|
@ -755,6 +757,99 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
WriteVal(DT_NULL, 0);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
EhFrameHeader<ELFT>::EhFrameHeader()
|
||||
: OutputSectionBase<ELFT>(".eh_frame_hdr", llvm::ELF::SHT_PROGBITS,
|
||||
SHF_ALLOC) {
|
||||
// It's a 4 bytes of header + pointer to the contents of the .eh_frame section
|
||||
// + the number of FDE pointers in the table.
|
||||
this->Header.sh_size = 12;
|
||||
}
|
||||
|
||||
// We have to get PC values of FDEs. They depend on relocations
|
||||
// which are target specific, so we run this code after performing
|
||||
// all relocations. We read the values from ouput buffer according to the
|
||||
// encoding given for FDEs. Return value is an offset to the initial PC value
|
||||
// for the FDE.
|
||||
template <class ELFT>
|
||||
typename EhFrameHeader<ELFT>::uintX_t
|
||||
EhFrameHeader<ELFT>::getFdePc(uintX_t EhVA, const FdeData &F) {
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
assert((F.Enc & 0xF0) != dwarf::DW_EH_PE_datarel);
|
||||
|
||||
uintX_t FdeOff = EhVA + F.Off + 8;
|
||||
switch (F.Enc & 0xF) {
|
||||
case dwarf::DW_EH_PE_udata2:
|
||||
case dwarf::DW_EH_PE_sdata2:
|
||||
return FdeOff + read16<E>(F.PCRel);
|
||||
case dwarf::DW_EH_PE_udata4:
|
||||
case dwarf::DW_EH_PE_sdata4:
|
||||
return FdeOff + read32<E>(F.PCRel);
|
||||
case dwarf::DW_EH_PE_udata8:
|
||||
case dwarf::DW_EH_PE_sdata8:
|
||||
return FdeOff + read64<E>(F.PCRel);
|
||||
case dwarf::DW_EH_PE_absptr:
|
||||
if (sizeof(uintX_t) == 8)
|
||||
return FdeOff + read64<E>(F.PCRel);
|
||||
return FdeOff + read32<E>(F.PCRel);
|
||||
}
|
||||
error("unknown FDE size encoding");
|
||||
}
|
||||
|
||||
template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
|
||||
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));
|
||||
|
||||
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;
|
||||
|
||||
// InitialPC -> Offset in .eh_frame, sorted by InitialPC.
|
||||
std::map<uintX_t, size_t> PcToOffset;
|
||||
for (const FdeData &F : FdeList)
|
||||
PcToOffset[getFdePc(EhVA, F)] = F.Off;
|
||||
|
||||
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);
|
||||
// The last four bytes are an offset to the FDE data itself.
|
||||
write32<E>(Buf + 4, EhVA + I.second - VA);
|
||||
Buf += 8;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void EhFrameHeader<ELFT>::assignEhFrame(EHOutputSection<ELFT> *Sec) {
|
||||
if (this->Sec && this->Sec != Sec) {
|
||||
warning("multiple .eh_frame sections not supported for .eh_frame_hdr");
|
||||
Live = false;
|
||||
return;
|
||||
}
|
||||
Live = Config->EhFrameHdr;
|
||||
this->Sec = Sec;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void EhFrameHeader<ELFT>::addFde(uint8_t Enc, size_t Off, uint8_t *PCRel) {
|
||||
if (Live && (Enc & 0xF0) == dwarf::DW_EH_PE_datarel)
|
||||
error("DW_EH_PE_datarel encoding unsupported for FDEs by .eh_frame_hdr");
|
||||
FdeList.push_back(FdeData{Enc, Off, PCRel});
|
||||
}
|
||||
|
||||
template <class ELFT> void EhFrameHeader<ELFT>::reserveFde() {
|
||||
// Each FDE entry is 8 bytes long:
|
||||
// The first four bytes are an offset to the initial PC value for the FDE. The
|
||||
// last four byte are an offset to the FDE data itself.
|
||||
this->Header.sh_size += 8;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type,
|
||||
uintX_t Flags)
|
||||
|
@ -908,7 +1003,9 @@ template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
template <class ELFT>
|
||||
EHOutputSection<ELFT>::EHOutputSection(StringRef Name, uint32_t Type,
|
||||
uintX_t Flags)
|
||||
: OutputSectionBase<ELFT>(Name, Type, Flags) {}
|
||||
: OutputSectionBase<ELFT>(Name, Type, Flags) {
|
||||
Out<ELFT>::EhFrameHdr->assignEhFrame(this);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
EHRegion<ELFT>::EHRegion(EHInputSection<ELFT> *S, unsigned Index)
|
||||
|
@ -927,6 +1024,107 @@ template <class ELFT>
|
|||
Cie<ELFT>::Cie(EHInputSection<ELFT> *S, unsigned Index)
|
||||
: EHRegion<ELFT>(S, Index) {}
|
||||
|
||||
// Read a byte and advance D by one byte.
|
||||
static uint8_t readByte(ArrayRef<uint8_t> &D) {
|
||||
if (D.empty())
|
||||
error("corrupted or unsupported CIE information");
|
||||
uint8_t B = D.front();
|
||||
D = D.slice(1);
|
||||
return B;
|
||||
}
|
||||
|
||||
static void skipLeb128(ArrayRef<uint8_t> &D) {
|
||||
while (!D.empty()) {
|
||||
uint8_t Val = D.front();
|
||||
D = D.slice(1);
|
||||
if ((Val & 0x80) == 0)
|
||||
return;
|
||||
}
|
||||
error("corrupted or unsupported CIE information");
|
||||
}
|
||||
|
||||
template <class ELFT> static unsigned getSizeForEncoding(unsigned Enc) {
|
||||
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
|
||||
switch (Enc & 0x0f) {
|
||||
default:
|
||||
error("unknown FDE encoding");
|
||||
case dwarf::DW_EH_PE_absptr:
|
||||
case dwarf::DW_EH_PE_signed:
|
||||
return sizeof(uintX_t);
|
||||
case dwarf::DW_EH_PE_udata2:
|
||||
case dwarf::DW_EH_PE_sdata2:
|
||||
return 2;
|
||||
case dwarf::DW_EH_PE_udata4:
|
||||
case dwarf::DW_EH_PE_sdata4:
|
||||
return 4;
|
||||
case dwarf::DW_EH_PE_udata8:
|
||||
case dwarf::DW_EH_PE_sdata8:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
uint8_t EHOutputSection<ELFT>::getFdeEncoding(ArrayRef<uint8_t> D) {
|
||||
auto Check = [](bool C) {
|
||||
if (!C)
|
||||
error("corrupted or unsupported CIE information");
|
||||
};
|
||||
|
||||
Check(D.size() >= 8);
|
||||
D = D.slice(8);
|
||||
|
||||
uint8_t Version = readByte(D);
|
||||
if (Version != 1 && Version != 3)
|
||||
error("FDE version 1 or 3 expected, but got " + Twine((unsigned)Version));
|
||||
|
||||
auto AugEnd = std::find(D.begin() + 1, D.end(), '\0');
|
||||
Check(AugEnd != D.end());
|
||||
ArrayRef<uint8_t> AugString(D.begin(), AugEnd - D.begin());
|
||||
D = D.slice(AugString.size() + 1);
|
||||
|
||||
// Code alignment factor should always be 1 for .eh_frame.
|
||||
if (readByte(D) != 1)
|
||||
error("CIE code alignment must be 1");
|
||||
// Skip data alignment factor
|
||||
skipLeb128(D);
|
||||
|
||||
// Skip the return address register. In CIE version 1 this is a single
|
||||
// byte. In CIE version 3 this is an unsigned LEB128.
|
||||
if (Version == 1)
|
||||
readByte(D);
|
||||
else
|
||||
skipLeb128(D);
|
||||
|
||||
while (!AugString.empty()) {
|
||||
switch (readByte(AugString)) {
|
||||
case 'z':
|
||||
skipLeb128(D);
|
||||
break;
|
||||
case 'R':
|
||||
return readByte(D);
|
||||
case 'P': {
|
||||
uint8_t Enc = readByte(D);
|
||||
if ((Enc & 0xf0) == dwarf::DW_EH_PE_aligned)
|
||||
error("DW_EH_PE_aligned encoding for address of a personality routine "
|
||||
"handler not supported");
|
||||
unsigned EncSize = getSizeForEncoding<ELFT>(Enc);
|
||||
Check(D.size() >= EncSize);
|
||||
D = D.slice(EncSize);
|
||||
break;
|
||||
}
|
||||
case 'S':
|
||||
case 'L':
|
||||
// L: Language Specific Data Area (LSDA) encoding
|
||||
// S: This CIE represents a stack frame for the invocation of a signal
|
||||
// handler
|
||||
break;
|
||||
default:
|
||||
error("unknown .eh_frame augmentation string value");
|
||||
}
|
||||
}
|
||||
return dwarf::DW_EH_PE_absptr;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
template <bool IsRela>
|
||||
void EHOutputSection<ELFT>::addSectionAux(
|
||||
|
@ -953,6 +1151,10 @@ void EHOutputSection<ELFT>::addSectionAux(
|
|||
S->Offsets.push_back(std::make_pair(Offset, -1));
|
||||
|
||||
uintX_t Length = readEntryLength(D);
|
||||
// If CIE/FDE data length is zero then Length is 4, this
|
||||
// shall be considered a terminator and processing shall end.
|
||||
if (Length == 4)
|
||||
break;
|
||||
StringRef Entry((const char *)D.data(), Length);
|
||||
|
||||
while (RelI != RelE && RelI->r_offset < Offset)
|
||||
|
@ -964,6 +1166,8 @@ void EHOutputSection<ELFT>::addSectionAux(
|
|||
if (ID == 0) {
|
||||
// CIE
|
||||
Cie<ELFT> C(S, Index);
|
||||
if (Config->EhFrameHdr)
|
||||
C.FdeEncoding = getFdeEncoding(D);
|
||||
|
||||
StringRef Personality;
|
||||
if (HasReloc) {
|
||||
|
@ -989,6 +1193,7 @@ void EHOutputSection<ELFT>::addSectionAux(
|
|||
if (I == OffsetToIndex.end())
|
||||
error("Invalid CIE reference");
|
||||
Cies[I->second].Fdes.push_back(EHRegion<ELFT>(S, Index));
|
||||
Out<ELFT>::EhFrameHdr->reserveFde();
|
||||
this->Header.sh_size += alignTo(Length, sizeof(uintX_t));
|
||||
}
|
||||
}
|
||||
|
@ -1062,6 +1267,7 @@ template <class ELFT> void EHOutputSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
uintX_t Len = writeAlignedCieOrFde<ELFT>(F.data(), Buf + Offset);
|
||||
write32<E>(Buf + Offset + 4, Offset + 4 - CieOffset); // Pointer
|
||||
F.S->Offsets[F.Index].second = Offset;
|
||||
Out<ELFT>::EhFrameHdr->addFde(C.FdeEncoding, Offset, Buf + Offset + 8);
|
||||
Offset += Len;
|
||||
}
|
||||
}
|
||||
|
@ -1455,6 +1661,11 @@ template class OutputSectionBase<ELF32BE>;
|
|||
template class OutputSectionBase<ELF64LE>;
|
||||
template class OutputSectionBase<ELF64BE>;
|
||||
|
||||
template class EhFrameHeader<ELF32LE>;
|
||||
template class EhFrameHeader<ELF32BE>;
|
||||
template class EhFrameHeader<ELF64LE>;
|
||||
template class EhFrameHeader<ELF64BE>;
|
||||
|
||||
template class GotPltSection<ELF32LE>;
|
||||
template class GotPltSection<ELF32BE>;
|
||||
template class GotPltSection<ELF64LE>;
|
||||
|
|
|
@ -287,6 +287,7 @@ template <class ELFT> struct EHRegion {
|
|||
template <class ELFT> struct Cie : public EHRegion<ELFT> {
|
||||
Cie(EHInputSection<ELFT> *S, unsigned Index);
|
||||
std::vector<EHRegion<ELFT>> Fdes;
|
||||
uint8_t FdeEncoding;
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
|
@ -308,6 +309,7 @@ public:
|
|||
void addSection(InputSectionBase<ELFT> *S) override;
|
||||
|
||||
private:
|
||||
uint8_t getFdeEncoding(ArrayRef<uint8_t> D);
|
||||
uintX_t readEntryLength(ArrayRef<uint8_t> D);
|
||||
|
||||
std::vector<EHInputSection<ELFT> *> Sections;
|
||||
|
@ -429,6 +431,46 @@ private:
|
|||
uint32_t GprMask = 0;
|
||||
};
|
||||
|
||||
// --eh-frame-hdr option tells linker to construct a header for all the
|
||||
// .eh_frame sections. This header is placed to a section named .eh_frame_hdr
|
||||
// and also to a PT_GNU_EH_FRAME segment.
|
||||
// At runtime the unwinder then can find all the PT_GNU_EH_FRAME segments by
|
||||
// calling dl_iterate_phdr.
|
||||
// This section contains a lookup table for quick binary search of FDEs.
|
||||
// Detailed info about internals can be found in Ian Lance Taylor's blog:
|
||||
// http://www.airs.com/blog/archives/460 (".eh_frame")
|
||||
// http://www.airs.com/blog/archives/462 (".eh_frame_hdr")
|
||||
template <class ELFT>
|
||||
class EhFrameHeader final : public OutputSectionBase<ELFT> {
|
||||
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
|
||||
|
||||
public:
|
||||
EhFrameHeader();
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
|
||||
void addFde(uint8_t Enc, size_t Off, uint8_t *PCRel);
|
||||
void assignEhFrame(EHOutputSection<ELFT> *Sec);
|
||||
void reserveFde();
|
||||
|
||||
bool Live = false;
|
||||
|
||||
private:
|
||||
struct FdeData {
|
||||
uint8_t Enc;
|
||||
size_t Off;
|
||||
uint8_t *PCRel;
|
||||
};
|
||||
|
||||
uintX_t getFdePc(uintX_t EhVA, const FdeData &F);
|
||||
|
||||
EHOutputSection<ELFT> *Sec = nullptr;
|
||||
std::vector<FdeData> FdeList;
|
||||
};
|
||||
|
||||
inline uint64_t align(uint64_t Value, uint64_t Align) {
|
||||
return llvm::RoundUpToAlignment(Value, Align);
|
||||
}
|
||||
|
||||
// All output sections that are hadnled by the linker specially are
|
||||
// globally accessible. Writer initializes them, so don't use them
|
||||
// until Writer is initialized.
|
||||
|
@ -436,6 +478,7 @@ template <class ELFT> struct Out {
|
|||
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Phdr Elf_Phdr;
|
||||
static DynamicSection<ELFT> *Dynamic;
|
||||
static EhFrameHeader<ELFT> *EhFrameHdr;
|
||||
static GnuHashTableSection<ELFT> *GnuHashTab;
|
||||
static GotPltSection<ELFT> *GotPlt;
|
||||
static GotSection<ELFT> *Got;
|
||||
|
@ -457,6 +500,7 @@ template <class ELFT> struct Out {
|
|||
};
|
||||
|
||||
template <class ELFT> DynamicSection<ELFT> *Out<ELFT>::Dynamic;
|
||||
template <class ELFT> EhFrameHeader<ELFT> *Out<ELFT>::EhFrameHdr;
|
||||
template <class ELFT> GnuHashTableSection<ELFT> *Out<ELFT>::GnuHashTab;
|
||||
template <class ELFT> GotPltSection<ELFT> *Out<ELFT>::GotPlt;
|
||||
template <class ELFT> GotSection<ELFT> *Out<ELFT>::Got;
|
||||
|
|
|
@ -140,6 +140,8 @@ template <class ELFT> void elf2::writeResult(SymbolTable<ELFT> *Symtab) {
|
|||
Out<ELFT>::RelaPlt = &RelaPlt;
|
||||
DynamicSection<ELFT> Dynamic(*Symtab);
|
||||
Out<ELFT>::Dynamic = &Dynamic;
|
||||
EhFrameHeader<ELFT> EhFrameHdr;
|
||||
Out<ELFT>::EhFrameHdr = &EhFrameHdr;
|
||||
|
||||
Writer<ELFT>(*Symtab).run();
|
||||
}
|
||||
|
@ -914,6 +916,9 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
|
|||
Add(Out<ELFT>::GotPlt);
|
||||
if (!Out<ELFT>::Plt->empty())
|
||||
Add(Out<ELFT>::Plt);
|
||||
|
||||
if (Out<ELFT>::EhFrameHdr->Live)
|
||||
Add(Out<ELFT>::EhFrameHdr);
|
||||
}
|
||||
|
||||
// The linker is expected to define SECNAME_start and SECNAME_end
|
||||
|
@ -1113,6 +1118,12 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
|||
*PH = GnuRelroPhdr;
|
||||
}
|
||||
|
||||
if (Out<ELFT>::EhFrameHdr->Live) {
|
||||
Elf_Phdr *PH = &Phdrs[++PhdrIdx];
|
||||
PH->p_type = PT_GNU_EH_FRAME;
|
||||
copyPhdr(PH, 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) {
|
||||
|
@ -1162,6 +1173,8 @@ template <class ELFT> int Writer<ELFT>::getPhdrsNum() const {
|
|||
++I;
|
||||
if (HasRelro)
|
||||
++I;
|
||||
if (Out<ELFT>::EhFrameHdr->Live)
|
||||
++I;
|
||||
return I;
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,6 @@
|
|||
// REQUIRES: x86
|
||||
// RUN: not ld.lld --eh-frame-hdr %p/Inputs/invalid-cie-version2.elf -o %t >& %t.log
|
||||
// RUN: FileCheck %s < %t.log
|
||||
|
||||
// invalid-cie-version2.elf contains unsupported version of CIE = 2.
|
||||
// CHECK: FDE version 1 or 3 expected, but got 2
|
|
@ -0,0 +1,19 @@
|
|||
// REQUIRES: x86
|
||||
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
|
||||
// RUN: ld.lld --eh-frame-hdr %t.o -o %t
|
||||
// RUN: llvm-readobj -s -program-headers %t | FileCheck %s --check-prefix=NOHDR
|
||||
|
||||
.section foo,"ax",@progbits
|
||||
nop
|
||||
|
||||
.text
|
||||
.globl _start;
|
||||
_start:
|
||||
|
||||
// There is no .eh_frame section,
|
||||
// therefore .eh_frame_hdr also not created.
|
||||
// NOHDR: Sections [
|
||||
// NOHDR-NOT: Name: .eh_frame
|
||||
// NOHDR-NOT: Name: .eh_frame_hdr
|
||||
// NOHDR: ProgramHeaders [
|
||||
// NOHDR-NOT: PT_GNU_EH_FRAME
|
|
@ -0,0 +1,127 @@
|
|||
// REQUIRES: x86
|
||||
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
|
||||
// RUN: ld.lld %t.o -o %t
|
||||
// RUN: llvm-readobj -file-headers -s -section-data -program-headers -symbols %t | FileCheck %s --check-prefix=NOHDR
|
||||
// RUN: ld.lld --eh-frame-hdr %t.o -o %t
|
||||
// RUN: llvm-readobj -file-headers -s -section-data -program-headers -symbols %t | FileCheck %s --check-prefix=HDR
|
||||
// RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=HDRDISASM
|
||||
|
||||
.section foo,"ax",@progbits
|
||||
.cfi_startproc
|
||||
nop
|
||||
.cfi_endproc
|
||||
|
||||
.section bar,"ax",@progbits
|
||||
.cfi_startproc
|
||||
nop
|
||||
.cfi_endproc
|
||||
|
||||
.section dah,"ax",@progbits
|
||||
.cfi_startproc
|
||||
nop
|
||||
.cfi_endproc
|
||||
|
||||
.text
|
||||
.globl _start;
|
||||
_start:
|
||||
|
||||
// NOHDR: Sections [
|
||||
// NOHDR-NOT: Name: .eh_frame_hdr
|
||||
// NOHDR: ProgramHeaders [
|
||||
// NOHDR-NOT: PT_GNU_EH_FRAME
|
||||
|
||||
//HDRDISASM: Disassembly of section foo:
|
||||
//HDRDISASM-NEXT: foo:
|
||||
//HDRDISASM-NEXT: 11000: 90 nop
|
||||
//HDRDISASM-NEXT: Disassembly of section bar:
|
||||
//HDRDISASM-NEXT: bar:
|
||||
//HDRDISASM-NEXT: 11001: 90 nop
|
||||
//HDRDISASM-NEXT: Disassembly of section dah:
|
||||
//HDRDISASM-NEXT: dah:
|
||||
//HDRDISASM-NEXT: 11002: 90 nop
|
||||
|
||||
// HDR: Sections [
|
||||
// HDR: Section {
|
||||
// HDR: Index: 1
|
||||
// HDR-NEXT: Name: .eh_frame
|
||||
// HDR-NEXT: Type: SHT_X86_64_UNWIND
|
||||
// HDR-NEXT: Flags [
|
||||
// HDR-NEXT: SHF_ALLOC
|
||||
// HDR-NEXT: ]
|
||||
// HDR-NEXT: Address: 0x10158
|
||||
// HDR-NEXT: Offset: 0x158
|
||||
// HDR-NEXT: Size: 96
|
||||
// HDR-NEXT: Link: 0
|
||||
// HDR-NEXT: Info: 0
|
||||
// HDR-NEXT: AddressAlignment: 8
|
||||
// HDR-NEXT: EntrySize: 0
|
||||
// HDR-NEXT: SectionData (
|
||||
// HDR-NEXT: 0000: 14000000 00000000 017A5200 01781001 |
|
||||
// HDR-NEXT: 0010: 1B0C0708 90010000 14000000 1C000000 |
|
||||
// HDR-NEXT: 0020: 880E0000 01000000 00000000 00000000 |
|
||||
// HDR-NEXT: 0030: 14000000 34000000 710E0000 01000000 |
|
||||
// HDR-NEXT: 0040: 00000000 00000000 14000000 4C000000 |
|
||||
// HDR-NEXT: 0050: 5A0E0000 01000000 00000000 00000000 |
|
||||
// CIE: 14000000 00000000 017A5200 01781001 1B0C0708 90010000
|
||||
// FDE(1): 14000000 1C000000 880E0000 01000000 00000000 00000000
|
||||
// address of data (starts with 0x880E0000) = 0x10158 + 0x0020 = 0x10178
|
||||
// The starting address to which this FDE applies = 0xE88 + 0x10178 = 0x11000
|
||||
// The number of bytes after the start address to which this FDE applies = 0x01000000 = 1
|
||||
// FDE(2): 14000000 34000000 710E0000 01000000 00000000 00000000
|
||||
// address of data (starts with 0x710E0000) = 0x10158 + 0x0038 = 0x10190
|
||||
// The starting address to which this FDE applies = 0xE71 + 0x10190 = 0x11001
|
||||
// The number of bytes after the start address to which this FDE applies = 0x01000000 = 1
|
||||
// FDE(3): 14000000 4C000000 5A0E0000 01000000 00000000 00000000
|
||||
// address of data (starts with 0x5A0E0000) = 0x10158 + 0x0050 = 0x101A8
|
||||
// The starting address to which this FDE applies = 0xE5A + 0x101A8 = 0x11002
|
||||
// The number of bytes after the start address to which this FDE applies = 0x01000000 = 1
|
||||
// HDR-NEXT: )
|
||||
// HDR-NEXT: }
|
||||
// HDR-NEXT: Section {
|
||||
// HDR-NEXT: Index: 2
|
||||
// HDR-NEXT: Name: .eh_frame_hdr
|
||||
// HDR-NEXT: Type: SHT_PROGBITS
|
||||
// HDR-NEXT: Flags [
|
||||
// HDR-NEXT: SHF_ALLOC
|
||||
// HDR-NEXT: ]
|
||||
// HDR-NEXT: Address: 0x101B8
|
||||
// HDR-NEXT: Offset: 0x1B8
|
||||
// HDR-NEXT: Size: 36
|
||||
// HDR-NEXT: Link: 0
|
||||
// HDR-NEXT: Info: 0
|
||||
// HDR-NEXT: AddressAlignment: 0
|
||||
// HDR-NEXT: EntrySize: 0
|
||||
// HDR-NEXT: SectionData (
|
||||
// HDR-NEXT: 0000: 011B033B 9CFFFFFF 03000000 480E0000 |
|
||||
// HDR-NEXT: 0010: B8FFFFFF 490E0000 D0FFFFFF 4A0E0000 |
|
||||
// HDR-NEXT: 0020: E8FFFFFF |
|
||||
// Header (always 4 bytes): 0x011B033B
|
||||
// 9CFFFFFF = .eh_frame(0x10158) - .eh_frame_hdr(0x101B8) - 4
|
||||
// 03000000 = 3 = the number of FDE pointers in the table.
|
||||
// Entry(1): 480E0000 B8FFFFFF
|
||||
// 480E0000 = 0x11000 - .eh_frame_hdr(0x101B8) = 0xE48
|
||||
// B8FFFFFF = address of FDE(1) - .eh_frame_hdr(0x101B8) =
|
||||
// = .eh_frame(0x10158) + 24 - 0x101B8 = 0xFFFFFFB8
|
||||
// Entry(2): 490E0000 D0FFFFFF
|
||||
// 490E0000 = 0x11001 - .eh_frame_hdr(0x101B8) = 0xE49
|
||||
// D0FFFFFF = address of FDE(2) - .eh_frame_hdr(0x101B8) =
|
||||
// = .eh_frame(0x10158) + 24 + 24 - 0x101B8 = 0xFFFFFFD0
|
||||
// Entry(3): 4A0E0000 E8FFFFFF
|
||||
// 4A0E0000 = 0x11002 - .eh_frame_hdr(0x101B8) = 0xE4A
|
||||
// E8FFFFFF = address of FDE(2) - .eh_frame_hdr(0x101B8) =
|
||||
// = .eh_frame(0x10158) + 24 + 24 - 0x101B8 = 0xFFFFFFE8
|
||||
// HDR-NEXT: )
|
||||
// HDR-NEXT: }
|
||||
// HDR: ProgramHeaders [
|
||||
// HDR: ProgramHeader {
|
||||
// HDR: Type: PT_GNU_EH_FRAME
|
||||
// HDR-NEXT: Offset: 0x1B8
|
||||
// HDR-NEXT: VirtualAddress: 0x101B8
|
||||
// HDR-NEXT: PhysicalAddress: 0x101B8
|
||||
// HDR-NEXT: FileSize: 36
|
||||
// HDR-NEXT: MemSize: 36
|
||||
// HDR-NEXT: Flags [
|
||||
// HDR-NEXT: PF_R
|
||||
// HDR-NEXT: ]
|
||||
// HDR-NEXT: Alignment: 1
|
||||
// HDR-NEXT: }
|
Loading…
Reference in New Issue