mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-23 17:48:03 +00:00
[ELF] Emit the file header and program headers at the beginning of the first segment.
This is required for the loader to correctly set AT_PHDR. With this lld can correctly link against dietlibc and get to main. llvm-svn: 171709
This commit is contained in:
parent
00b702c95c
commit
1ac382f0c5
@ -747,6 +747,11 @@ public:
|
||||
this->_align2 = section->align2();
|
||||
}
|
||||
|
||||
/// Prepend a generic chunk to the segment.
|
||||
void prepend(Chunk<target_endianness, max_align, is64Bits> *c) {
|
||||
_sections.insert(_sections.begin(), c);
|
||||
}
|
||||
|
||||
/// Sort segments depending on the property
|
||||
/// If we have a Program Header segment, it should appear first
|
||||
/// If we have a INTERP segment, that should appear after the Program Header
|
||||
@ -869,27 +874,19 @@ public:
|
||||
}
|
||||
|
||||
/// \brief Assign virtual addresses to the slices
|
||||
void assignVirtualAddress(uint64_t &addr, bool isFirstSegment) {
|
||||
void assignVirtualAddress(uint64_t &addr) {
|
||||
for (auto sei = slices_begin(), see = slices_end(); sei != see; ++sei) {
|
||||
bool firstSlice = (sei == slices_begin());
|
||||
// The first segment has distinct since it contains the
|
||||
// ELF header and the Program Header, if we get to the first segment
|
||||
// and the first slice, set it to the baseaddress
|
||||
// which is the segment address
|
||||
if (isFirstSegment && firstSlice)
|
||||
(*sei)->setVAddr(this->virtualAddr());
|
||||
else {
|
||||
// Align to a page
|
||||
addr = llvm::RoundUpToAlignment(addr, _options.pageSize());
|
||||
// Align to the slice alignment
|
||||
addr = llvm::RoundUpToAlignment(addr, (*sei)->align2());
|
||||
}
|
||||
// Align to a page
|
||||
addr = llvm::RoundUpToAlignment(addr, _options.pageSize());
|
||||
// Align to the slice alignment
|
||||
addr = llvm::RoundUpToAlignment(addr, (*sei)->align2());
|
||||
|
||||
bool virtualAddressSet = false;
|
||||
for (auto si = (*sei)->sections_begin(), se = (*sei)->sections_end();
|
||||
si != se; ++si) {
|
||||
// Align the section address
|
||||
addr = llvm::RoundUpToAlignment(addr, (*si)->align2());
|
||||
if (!isFirstSegment && !virtualAddressSet) {
|
||||
if (!virtualAddressSet) {
|
||||
(*sei)->setVAddr(addr);
|
||||
virtualAddressSet = true;
|
||||
}
|
||||
@ -897,6 +894,8 @@ public:
|
||||
if (auto s =
|
||||
dyn_cast<Section<target_endianness, max_align, is64Bits>>(*si))
|
||||
s->assignVirtualAddress(addr);
|
||||
else
|
||||
addr += (*si)->memSize();
|
||||
(*si)->setMemSize(addr - (*si)->virtualAddr());
|
||||
}
|
||||
(*sei)->setMemSize(addr - (*sei)->virtualAddr());
|
||||
@ -1161,6 +1160,9 @@ public:
|
||||
ELFHeader()
|
||||
: Chunk<target_endianness, max_align, is64Bits>(
|
||||
"elfhdr", Chunk<target_endianness, max_align, is64Bits>::K_ELFHeader) {
|
||||
this->_align2 = is64Bits ? 8 : 4;
|
||||
this->_fsize = sizeof(Elf_Ehdr);
|
||||
this->_msize = sizeof(Elf_Ehdr);
|
||||
memset(_eh.e_ident, 0, llvm::ELF::EI_NIDENT);
|
||||
e_ident(ELF::EI_MAG0, 0x7f);
|
||||
e_ident(ELF::EI_MAG1, 'E');
|
||||
@ -1217,6 +1219,7 @@ public:
|
||||
: Chunk<target_endianness, max_align, is64Bits>(
|
||||
"elfphdr",
|
||||
Chunk<target_endianness, max_align, is64Bits>::K_ELFProgramHeader) {
|
||||
this->_align2 = is64Bits ? 8 : 4;
|
||||
resetProgramHeaders();
|
||||
}
|
||||
|
||||
@ -1245,6 +1248,10 @@ public:
|
||||
phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD) ?
|
||||
segment->pageSize() : (*sei)->align2();
|
||||
}
|
||||
|
||||
this->_fsize = fileSize();
|
||||
this->_msize = this->_fsize;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1252,13 +1259,8 @@ public:
|
||||
_phi = _ph.begin();
|
||||
}
|
||||
|
||||
void setVAddr(uint64_t addr) {
|
||||
this->_start = llvm::RoundUpToAlignment(addr, 8);
|
||||
this->_fsize = this->_start - addr;
|
||||
}
|
||||
|
||||
uint64_t fileSize() {
|
||||
return this->_fsize + (sizeof (Elf_Phdr) * _ph.size());
|
||||
return sizeof(Elf_Phdr) * _ph.size();
|
||||
}
|
||||
|
||||
static inline bool classof(
|
||||
@ -1745,27 +1747,27 @@ public:
|
||||
}
|
||||
|
||||
void assignVirtualAddress() {
|
||||
if (_segments.empty())
|
||||
return;
|
||||
|
||||
uint64_t virtualAddress = _options.baseAddress();
|
||||
|
||||
// Add the ELF Header
|
||||
if (_elfHeader) {
|
||||
_elfHeader->setFileOffset(0);
|
||||
_elfHeader->setVAddr(virtualAddress);
|
||||
}
|
||||
// Add the program header
|
||||
if (_programHeader) {
|
||||
_programHeader->setVAddr(
|
||||
uint64_t(virtualAddress + _elfHeader->fileSize()));
|
||||
_programHeader->setFileOffset(_elfHeader->fileSize());
|
||||
}
|
||||
// HACK: This is a super dirty hack. The elf header and program header are
|
||||
// not part of a section, but we need them to be loaded at the base address
|
||||
// so that AT_PHDR is set correctly by the loader and so they are accessible
|
||||
// at runtime. To do this we simply prepend them to the first Segment and
|
||||
// let the layout logic take care of it.
|
||||
_segments[0]->prepend(_programHeader);
|
||||
_segments[0]->prepend(_elfHeader);
|
||||
|
||||
bool newSegmentHeaderAdded = true;
|
||||
while (true && !_segments.empty()) {
|
||||
while (true) {
|
||||
for (auto si : _segments) {
|
||||
newSegmentHeaderAdded = _programHeader->addSegment(si);
|
||||
}
|
||||
if (!newSegmentHeaderAdded)
|
||||
break;
|
||||
uint64_t fileoffset = _elfHeader->fileSize() + _programHeader->fileSize();
|
||||
uint64_t fileoffset = 0;
|
||||
uint64_t address = virtualAddress;
|
||||
// Fix the offsets after adding the program header
|
||||
for (auto &si : _segments) {
|
||||
@ -1780,7 +1782,7 @@ public:
|
||||
// The first segment has the virtualAddress set to the base address as
|
||||
// we have added the file header and the program header dont align the
|
||||
// first segment to the pagesize
|
||||
(*si)->assignVirtualAddress(address, (si == _segments.begin()));
|
||||
(*si)->assignVirtualAddress(address);
|
||||
(*si)->setMemSize(address - virtualAddress);
|
||||
virtualAddress = llvm::RoundUpToAlignment(address, _options.pageSize());
|
||||
}
|
||||
@ -2136,9 +2138,6 @@ error_code ELFExecutableWriter<target_endianness, max_align, is64Bits>
|
||||
if (ec)
|
||||
return ec;
|
||||
|
||||
for (auto si = _layout->sections_begin(); si != _layout->sections_end(); ++si)
|
||||
(*si)->write(this, buffer);
|
||||
|
||||
_elfHeader->e_ident(ELF::EI_CLASS, (_options.is64Bit() ? ELF::ELFCLASS64
|
||||
: ELF::ELFCLASS32));
|
||||
_elfHeader->e_ident(ELF::EI_DATA, _options.endianness() == llvm::support::big
|
||||
@ -2159,9 +2158,16 @@ error_code ELFExecutableWriter<target_endianness, max_align, is64Bits>
|
||||
uint64_t virtualAddr = 0;
|
||||
_layout->findAtomAddrByName("_start", virtualAddr);
|
||||
_elfHeader->e_entry(virtualAddr);
|
||||
|
||||
// HACK: We have to write out the header and program header here even though
|
||||
// they are a member of a segment because only sections are written in the
|
||||
// following loop.
|
||||
_elfHeader->write(this, buffer);
|
||||
_programHeader->write(this, buffer);
|
||||
|
||||
for (auto si = _layout->sections_begin(); si != _layout->sections_end(); ++si)
|
||||
(*si)->write(this, buffer);
|
||||
|
||||
return buffer->commit();
|
||||
}
|
||||
|
||||
|
@ -3,17 +3,17 @@ RUN: lld-core -reader ELF -writer ELF -o %t1 %p/Inputs/phdr.i386 | elf-dump %t1
|
||||
ED: # Program Header 0
|
||||
ED: (('p_type', 0x00000001)
|
||||
ED: ('p_flags', 0x00000005)
|
||||
ED: ('p_offset', 0x00001000)
|
||||
ED: ('p_offset', 0x00000000)
|
||||
ED: ('p_vaddr', 0x00000000)
|
||||
ED: ('p_paddr', 0x00000000)
|
||||
ED: ('p_filesz', 0x00000025)
|
||||
ED: ('p_memsz', 0x00000025)
|
||||
ED: ('p_filesz', 0x000000d9)
|
||||
ED: ('p_memsz', 0x000000d9)
|
||||
ED: ('p_align', 0x00001000)
|
||||
ED: ),
|
||||
ED: # Program Header 1
|
||||
ED: (('p_type', 0x00000001)
|
||||
ED: ('p_flags', 0x00000006)
|
||||
ED: ('p_offset', 0x00002000)
|
||||
ED: ('p_offset', 0x00001000)
|
||||
ED: ('p_vaddr', 0x00001000)
|
||||
ED: ('p_paddr', 0x00001000)
|
||||
ED: ('p_filesz', 0x00000104)
|
||||
|
@ -1,9 +1,10 @@
|
||||
RUN: lld-core -reader ELF -writer ELF -o %t1 %p/Inputs/section-test.i386 | llvm-objdump -section-headers %t1 | FileCheck -check-prefix=OBJDUMP %s
|
||||
RUN: lld-core -reader ELF -writer ELF -o %t1 %p/Inputs/section-test.i386
|
||||
RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=OBJDUMP %s
|
||||
RUN: llvm-readobj %t1 | FileCheck -check-prefix=READOBJ %s
|
||||
RUN: elf-dump --dump-section %t1 | FileCheck -check-prefix=ED %s
|
||||
|
||||
OBJDUMP: 0 000000000 00000000000000000
|
||||
OBJDUMP: 1 .text 00000000a 00000000000000000 TEXT DATA
|
||||
OBJDUMP: 1 .text 00000000a 00000000000000074 TEXT DATA
|
||||
OBJDUMP: 2 .data 000000004 00000000000001000 DATA
|
||||
OBJDUMP: 3 .special 000000004 00000000000001004 DATA
|
||||
OBJDUMP: 4 .anotherspecial 000000004 00000000000001008 DATA
|
||||
@ -16,8 +17,8 @@ READOBJ: File Format : ELF32-i386
|
||||
READOBJ: Arch : i386
|
||||
READOBJ: Address Size: 32 bits
|
||||
READOBJ: Symbols
|
||||
READOBJ: baz FUNC 0 a 1000 global
|
||||
READOBJ: y DATA 1004 4 3008 global
|
||||
READOBJ: baz FUNC 74 a e8 global
|
||||
READOBJ: y DATA 1004 4 2008 global
|
||||
|
||||
ED: 'e_indent[EI_DATA]', 0x01
|
||||
ED: 'e_machine', 0x0003
|
||||
|
@ -1,11 +1,8 @@
|
||||
RUN: lld -flavor ld -target x86_64-linux -o %t && llvm-objdump -p %t \
|
||||
RUN: | FileCheck %s
|
||||
|
||||
CHECK: ELF64-x86-64
|
||||
|
||||
RUN: lld -flavor ld -target x86_64-linux -o %t1 %p/Inputs/relocs.x86-64 \
|
||||
RUN: && llvm-objdump -d %t1 | FileCheck %s -check-prefix=RELOCS
|
||||
|
||||
RELOCS: ELF64-x86-64
|
||||
|
||||
// R_X86_64_32S
|
||||
RELOCS: c7 04 25
|
||||
RELOCS-NOT: 00 00 00 00
|
||||
|
Loading…
x
Reference in New Issue
Block a user