da0de06643
Android's strip incorrectly removes a single shared string table. Bug: https://github.com/dart-lang/sdk/issues/37146 Change-Id: I744937041b71d5653b60a837917901c1d91bc361 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/104643 Reviewed-by: Martin Kustermann <kustermann@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
756 lines
22 KiB
C++
756 lines
22 KiB
C++
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include "vm/elf.h"
|
|
|
|
#include "platform/text_buffer.h"
|
|
#include "vm/cpu.h"
|
|
#include "vm/thread.h"
|
|
|
|
namespace dart {
|
|
|
|
#define ELFCLASS32 1
|
|
#define ELFCLASS64 2
|
|
|
|
static const intptr_t ELFDATA2LSB = 1;
|
|
|
|
static const intptr_t ELFOSABI_SYSV = 0;
|
|
|
|
#define EF_ARM_ABI_FLOAT_HARD 0x00000400
|
|
#define EF_ARM_ABI_FLOAT_SOFT 0x00000200
|
|
#define EF_ARM_ABI 0x05000000
|
|
|
|
static const intptr_t ET_DYN = 3;
|
|
|
|
#define EM_386 3
|
|
#define EM_ARM 40
|
|
#define EM_X86_64 62
|
|
#define EM_AARCH64 183
|
|
|
|
static const intptr_t EV_CURRENT = 1;
|
|
|
|
static const intptr_t SHT_PROGBITS = 1;
|
|
static const intptr_t SHT_STRTAB = 3;
|
|
static const intptr_t SHT_HASH = 5;
|
|
static const intptr_t SHT_DYNSYM = 11;
|
|
static const intptr_t SHT_DYNAMIC = 6;
|
|
|
|
static const intptr_t SHF_WRITE = 0x1;
|
|
static const intptr_t SHF_ALLOC = 0x2;
|
|
static const intptr_t SHF_EXECINSTR = 0x4;
|
|
|
|
static const intptr_t SHN_UNDEF = 0;
|
|
|
|
static const intptr_t STN_UNDEF = 0;
|
|
|
|
static const intptr_t PT_LOAD = 1;
|
|
static const intptr_t PT_DYNAMIC = 2;
|
|
static const intptr_t PT_PHDR = 6;
|
|
|
|
static const intptr_t PF_X = 1;
|
|
static const intptr_t PF_W = 2;
|
|
static const intptr_t PF_R = 4;
|
|
|
|
static const intptr_t STB_GLOBAL = 1;
|
|
|
|
static const intptr_t STT_OBJECT = 1; // I.e., data.
|
|
static const intptr_t STT_FUNC = 2;
|
|
|
|
static const intptr_t DT_HASH = 4;
|
|
static const intptr_t DT_STRTAB = 5;
|
|
static const intptr_t DT_SYMTAB = 6;
|
|
static const intptr_t DT_STRSZ = 10;
|
|
static const intptr_t DT_SYMENT = 11;
|
|
|
|
#if defined(TARGET_ARCH_IS_32_BIT)
|
|
static const intptr_t kElfHeaderSize = 52;
|
|
static const intptr_t kElfSectionTableEntrySize = 40;
|
|
static const intptr_t kElfProgramTableEntrySize = 32;
|
|
static const intptr_t kElfSymbolTableEntrySize = 16;
|
|
static const intptr_t kElfDynamicTableEntrySize = 8;
|
|
#else
|
|
static const intptr_t kElfHeaderSize = 64;
|
|
static const intptr_t kElfSectionTableEntrySize = 64;
|
|
static const intptr_t kElfProgramTableEntrySize = 56;
|
|
static const intptr_t kElfSymbolTableEntrySize = 24;
|
|
static const intptr_t kElfDynamicTableEntrySize = 16;
|
|
#endif
|
|
|
|
static const intptr_t kPageSize = 4096;
|
|
|
|
class Section : public ZoneAllocated {
|
|
public:
|
|
Section() {}
|
|
|
|
virtual ~Section() {}
|
|
virtual void Write(Elf* stream) = 0;
|
|
|
|
// Linker view.
|
|
intptr_t section_name = 0; // Index into string table.
|
|
intptr_t section_type = 0;
|
|
intptr_t section_flags = 0;
|
|
intptr_t section_index = -1;
|
|
intptr_t section_link = SHN_UNDEF;
|
|
intptr_t section_info = 0;
|
|
intptr_t section_entry_size = 0;
|
|
intptr_t file_size = 0;
|
|
intptr_t file_offset = -1;
|
|
|
|
intptr_t alignment = 1;
|
|
|
|
// Loader view.
|
|
intptr_t segment_type = -1;
|
|
intptr_t segment_flags = 0;
|
|
intptr_t memory_size = 0;
|
|
intptr_t memory_offset = -1;
|
|
};
|
|
|
|
class ProgramBits : public Section {
|
|
public:
|
|
ProgramBits(bool allocate,
|
|
bool executable,
|
|
const uint8_t* bytes,
|
|
intptr_t size) {
|
|
section_type = SHT_PROGBITS;
|
|
if (allocate) {
|
|
section_flags = SHF_ALLOC;
|
|
if (executable) section_flags |= SHF_EXECINSTR;
|
|
|
|
segment_type = PT_LOAD;
|
|
segment_flags = PF_R;
|
|
if (executable) segment_flags |= PF_X;
|
|
}
|
|
|
|
bytes_ = bytes;
|
|
file_size = memory_size = size;
|
|
}
|
|
|
|
void Write(Elf* stream) { stream->WriteBytes(bytes_, memory_size); }
|
|
|
|
const uint8_t* bytes_;
|
|
};
|
|
|
|
class StringTable : public Section {
|
|
public:
|
|
StringTable() : text_(128) {
|
|
section_type = SHT_STRTAB;
|
|
section_flags = SHF_ALLOC;
|
|
segment_type = PT_LOAD;
|
|
segment_flags = PF_R;
|
|
|
|
text_.AddChar('\0');
|
|
memory_size = file_size = text_.length();
|
|
}
|
|
|
|
intptr_t AddString(const char* str) {
|
|
intptr_t offset = text_.length();
|
|
text_.AddString(str);
|
|
text_.AddChar('\0');
|
|
memory_size = file_size = text_.length();
|
|
return offset;
|
|
}
|
|
|
|
void Write(Elf* stream) {
|
|
stream->WriteBytes(reinterpret_cast<const uint8_t*>(text_.buf()),
|
|
text_.length());
|
|
}
|
|
|
|
TextBuffer text_;
|
|
};
|
|
|
|
class Symbol : public ZoneAllocated {
|
|
public:
|
|
const char* cstr;
|
|
intptr_t name;
|
|
intptr_t info;
|
|
intptr_t section;
|
|
intptr_t offset;
|
|
intptr_t size;
|
|
};
|
|
|
|
class SymbolTable : public Section {
|
|
public:
|
|
SymbolTable() {
|
|
section_type = SHT_DYNSYM;
|
|
section_flags = SHF_ALLOC;
|
|
segment_type = PT_LOAD;
|
|
segment_flags = PF_R;
|
|
|
|
section_entry_size = kElfSymbolTableEntrySize;
|
|
AddSymbol(NULL);
|
|
section_info = 1; // One "local" symbol, the reserved first entry.
|
|
}
|
|
|
|
void AddSymbol(Symbol* symbol) {
|
|
symbols_.Add(symbol);
|
|
memory_size += kElfSymbolTableEntrySize;
|
|
file_size += kElfSymbolTableEntrySize;
|
|
}
|
|
|
|
void Write(Elf* stream) {
|
|
// The first symbol table entry is reserved and must be all zeros.
|
|
{
|
|
const intptr_t start = stream->position();
|
|
#if defined(TARGET_ARCH_IS_32_BIT)
|
|
stream->WriteWord(0);
|
|
stream->WriteAddr(0);
|
|
stream->WriteWord(0);
|
|
stream->WriteByte(0);
|
|
stream->WriteByte(0);
|
|
stream->WriteHalf(0);
|
|
#else
|
|
stream->WriteWord(0);
|
|
stream->WriteByte(0);
|
|
stream->WriteByte(0);
|
|
stream->WriteHalf(0);
|
|
stream->WriteAddr(0);
|
|
stream->WriteXWord(0);
|
|
#endif
|
|
const intptr_t end = stream->position();
|
|
ASSERT((end - start) == kElfSymbolTableEntrySize);
|
|
}
|
|
|
|
for (intptr_t i = 1; i < symbols_.length(); i++) {
|
|
Symbol* symbol = symbols_[i];
|
|
const intptr_t start = stream->position();
|
|
#if defined(TARGET_ARCH_IS_32_BIT)
|
|
stream->WriteWord(symbol->name);
|
|
stream->WriteAddr(symbol->offset);
|
|
stream->WriteWord(symbol->size);
|
|
stream->WriteByte(symbol->info);
|
|
stream->WriteByte(0);
|
|
stream->WriteHalf(symbol->section);
|
|
#else
|
|
stream->WriteWord(symbol->name);
|
|
stream->WriteByte(symbol->info);
|
|
stream->WriteByte(0);
|
|
stream->WriteHalf(symbol->section);
|
|
stream->WriteAddr(symbol->offset);
|
|
stream->WriteXWord(symbol->size);
|
|
#endif
|
|
const intptr_t end = stream->position();
|
|
ASSERT((end - start) == kElfSymbolTableEntrySize);
|
|
}
|
|
}
|
|
|
|
intptr_t length() const { return symbols_.length(); }
|
|
Symbol* at(intptr_t i) const { return symbols_[i]; }
|
|
|
|
GrowableArray<Symbol*> symbols_;
|
|
};
|
|
|
|
static uint32_t ElfHash(const unsigned char* name) {
|
|
uint32_t h = 0;
|
|
while (*name) {
|
|
h = (h << 4) + *name++;
|
|
uint32_t g = h & 0xf0000000;
|
|
h ^= g;
|
|
h ^= g >> 24;
|
|
}
|
|
return h;
|
|
}
|
|
|
|
class SymbolHashTable : public Section {
|
|
public:
|
|
SymbolHashTable(StringTable* strtab, SymbolTable* symtab) {
|
|
section_type = SHT_HASH;
|
|
section_flags = SHF_ALLOC;
|
|
section_link = symtab->section_index;
|
|
segment_type = PT_LOAD;
|
|
segment_flags = PF_R;
|
|
|
|
nchain_ = symtab->length();
|
|
nbucket_ = symtab->length();
|
|
|
|
bucket_ = Thread::Current()->zone()->Alloc<int32_t>(nbucket_);
|
|
for (intptr_t i = 0; i < nbucket_; i++) {
|
|
bucket_[i] = STN_UNDEF;
|
|
}
|
|
|
|
chain_ = Thread::Current()->zone()->Alloc<int32_t>(nchain_);
|
|
for (intptr_t i = 0; i < nchain_; i++) {
|
|
chain_[i] = STN_UNDEF;
|
|
}
|
|
|
|
for (intptr_t i = 1; i < symtab->length(); i++) {
|
|
Symbol* symbol = symtab->at(i);
|
|
uint32_t hash = ElfHash((const unsigned char*)symbol->cstr);
|
|
uint32_t probe = hash % nbucket_;
|
|
chain_[i] = bucket_[probe]; // next = head
|
|
bucket_[probe] = i; // head = symbol
|
|
}
|
|
|
|
memory_size = file_size = 4 * (nbucket_ + nchain_ + 2);
|
|
}
|
|
|
|
void Write(Elf* stream) {
|
|
stream->WriteWord(nbucket_);
|
|
stream->WriteWord(nchain_);
|
|
for (intptr_t i = 0; i < nbucket_; i++) {
|
|
stream->WriteWord(bucket_[i]);
|
|
}
|
|
for (intptr_t i = 0; i < nchain_; i++) {
|
|
stream->WriteWord(chain_[i]);
|
|
}
|
|
}
|
|
|
|
private:
|
|
int32_t nbucket_;
|
|
int32_t nchain_;
|
|
int32_t* bucket_; // "Head"
|
|
int32_t* chain_; // "Next"
|
|
};
|
|
|
|
class DynamicTable : public Section {
|
|
public:
|
|
DynamicTable(StringTable* strtab,
|
|
SymbolTable* symtab,
|
|
SymbolHashTable* hash) {
|
|
section_type = SHT_DYNAMIC;
|
|
section_link = strtab->section_index;
|
|
section_flags = SHF_ALLOC | SHF_WRITE;
|
|
section_entry_size = kElfDynamicTableEntrySize;
|
|
|
|
segment_type = PT_LOAD;
|
|
segment_flags = PF_R | PF_W;
|
|
|
|
AddEntry(DT_HASH, hash->memory_offset);
|
|
AddEntry(DT_STRTAB, strtab->memory_offset);
|
|
AddEntry(DT_STRSZ, strtab->memory_size);
|
|
AddEntry(DT_SYMTAB, symtab->memory_offset);
|
|
AddEntry(DT_SYMENT, kElfSymbolTableEntrySize);
|
|
}
|
|
|
|
void Write(Elf* stream) {
|
|
for (intptr_t i = 0; i < entries_.length(); i++) {
|
|
const intptr_t start = stream->position();
|
|
#if defined(TARGET_ARCH_IS_32_BIT)
|
|
stream->WriteWord(entries_[i]->tag);
|
|
stream->WriteAddr(entries_[i]->value);
|
|
#else
|
|
stream->WriteXWord(entries_[i]->tag);
|
|
stream->WriteAddr(entries_[i]->value);
|
|
#endif
|
|
const intptr_t end = stream->position();
|
|
ASSERT((end - start) == kElfDynamicTableEntrySize);
|
|
}
|
|
}
|
|
|
|
class Entry {
|
|
public:
|
|
intptr_t tag;
|
|
intptr_t value;
|
|
};
|
|
|
|
void AddEntry(intptr_t tag, intptr_t value) {
|
|
Entry* entry = new Entry();
|
|
entry->tag = tag;
|
|
entry->value = value;
|
|
entries_.Add(entry);
|
|
|
|
memory_size += kElfDynamicTableEntrySize;
|
|
file_size += kElfDynamicTableEntrySize;
|
|
}
|
|
|
|
private:
|
|
GrowableArray<Entry*> entries_;
|
|
};
|
|
|
|
static uint8_t kNothing = 0;
|
|
|
|
// The first section must be written out and contains only zeros.
|
|
static const intptr_t kNumInvalidSections = 1;
|
|
|
|
// Extra segments put in the program table that aren't reified in
|
|
// Elf::segments_.
|
|
static const intptr_t kNumImplicitSegments = 3;
|
|
|
|
Elf::Elf(Zone* zone, StreamingWriteStream* stream)
|
|
: zone_(zone), stream_(stream), memory_offset_(0) {
|
|
// Assumed by various offset logic in this file.
|
|
ASSERT(stream_->position() == 0);
|
|
|
|
// All our strings would fit in a single page. However, we use separate
|
|
// .shstrtab and .dynstr to work around a bug in Android's strip utility.
|
|
shstrtab_ = new (zone_) StringTable();
|
|
shstrtab_->section_name = shstrtab_->AddString(".shstrtab");
|
|
AddSection(shstrtab_);
|
|
|
|
symstrtab_ = new (zone_) StringTable();
|
|
symstrtab_->section_name = shstrtab_->AddString(".dynstr");
|
|
AddSection(symstrtab_);
|
|
|
|
symtab_ = new (zone_) SymbolTable();
|
|
symtab_->section_name = shstrtab_->AddString(".dynsym");
|
|
symtab_->section_link = symstrtab_->section_index;
|
|
AddSection(symtab_);
|
|
|
|
// dlsym gets confused if a symbol's value is dso offset 0, treating this as a
|
|
// failed lookup instead of answering dso base + 0. dladdr answers the wrong
|
|
// dso base if we don't start allocating from 0 (answering the address of
|
|
// either the first or lowest PT_LOAD). Sacrifice the first page to work
|
|
// around these issues. (gcc places build metadata in the first page.)
|
|
AddROData("nothing", &kNothing, sizeof(kNothing));
|
|
}
|
|
|
|
void Elf::AddSection(Section* section) {
|
|
section->section_index = sections_.length() + kNumInvalidSections;
|
|
sections_.Add(section);
|
|
}
|
|
|
|
void Elf::AddSegment(Section* section) {
|
|
if (section->alignment < kPageSize) {
|
|
section->alignment = kPageSize;
|
|
}
|
|
|
|
memory_offset_ = Utils::RoundUp(memory_offset_, section->alignment);
|
|
section->memory_offset = memory_offset_;
|
|
memory_offset_ += section->memory_size;
|
|
segments_.Add(section);
|
|
memory_offset_ = Utils::RoundUp(memory_offset_, kPageSize);
|
|
}
|
|
|
|
intptr_t Elf::NextMemoryOffset() {
|
|
return memory_offset_;
|
|
}
|
|
|
|
intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) {
|
|
ProgramBits* image = new (zone_) ProgramBits(true, true, bytes, size);
|
|
image->section_name = shstrtab_->AddString(".text");
|
|
AddSection(image);
|
|
AddSegment(image);
|
|
|
|
Symbol* symbol = new (zone_) Symbol();
|
|
symbol->cstr = name;
|
|
symbol->name = symstrtab_->AddString(name);
|
|
symbol->info = (STB_GLOBAL << 4) | STT_FUNC;
|
|
symbol->section = image->section_index;
|
|
// For shared libraries, this is the offset from the DSO base. For static
|
|
// libraries, this is section relative.
|
|
symbol->offset = image->memory_offset;
|
|
symbol->size = size;
|
|
symtab_->AddSymbol(symbol);
|
|
|
|
return symbol->offset;
|
|
}
|
|
|
|
intptr_t Elf::AddROData(const char* name, const uint8_t* bytes, intptr_t size) {
|
|
ProgramBits* image = new (zone_) ProgramBits(true, false, bytes, size);
|
|
image->section_name = shstrtab_->AddString(".rodata");
|
|
AddSection(image);
|
|
AddSegment(image);
|
|
|
|
Symbol* symbol = new (zone_) Symbol();
|
|
symbol->cstr = name;
|
|
symbol->name = symstrtab_->AddString(name);
|
|
symbol->info = (STB_GLOBAL << 4) | STT_OBJECT;
|
|
symbol->section = image->section_index;
|
|
// For shared libraries, this is the offset from the DSO base. For static
|
|
// libraries, this is section relative.
|
|
symbol->offset = image->memory_offset;
|
|
symbol->size = size;
|
|
symtab_->AddSymbol(symbol);
|
|
|
|
return symbol->offset;
|
|
}
|
|
|
|
void Elf::AddDebug(const char* name, const uint8_t* bytes, intptr_t size) {
|
|
ProgramBits* image = new (zone_) ProgramBits(false, false, bytes, size);
|
|
image->section_name = shstrtab_->AddString(name);
|
|
AddSection(image);
|
|
}
|
|
|
|
void Elf::Finalize() {
|
|
SymbolHashTable* hash = new (zone_) SymbolHashTable(symstrtab_, symtab_);
|
|
hash->section_name = shstrtab_->AddString(".hash");
|
|
AddSection(hash);
|
|
AddSegment(hash);
|
|
|
|
// Before finalizing the string table's memory size:
|
|
intptr_t name_dynamic = shstrtab_->AddString(".dynamic");
|
|
|
|
// Finalizes memory size of string and symbol tables.
|
|
AddSegment(shstrtab_);
|
|
AddSegment(symstrtab_);
|
|
AddSegment(symtab_);
|
|
|
|
dynamic_ = new (zone_) DynamicTable(symstrtab_, symtab_, hash);
|
|
dynamic_->section_name = name_dynamic;
|
|
AddSection(dynamic_);
|
|
AddSegment(dynamic_);
|
|
|
|
ComputeFileOffsets();
|
|
|
|
WriteHeader();
|
|
WriteProgramTable();
|
|
WriteSectionTable();
|
|
WriteSections();
|
|
}
|
|
|
|
void Elf::ComputeFileOffsets() {
|
|
intptr_t file_offset = kElfHeaderSize;
|
|
|
|
file_offset = Utils::RoundUp(file_offset, kPageSize);
|
|
program_table_file_offset_ = file_offset;
|
|
program_table_file_size_ =
|
|
(segments_.length() + kNumImplicitSegments) * kElfProgramTableEntrySize;
|
|
file_offset += program_table_file_size_;
|
|
|
|
section_table_file_offset_ = file_offset;
|
|
section_table_file_size_ =
|
|
(sections_.length() + kNumInvalidSections) * kElfSectionTableEntrySize;
|
|
file_offset += section_table_file_size_;
|
|
|
|
for (intptr_t i = 0; i < sections_.length(); i++) {
|
|
Section* section = sections_[i];
|
|
file_offset = Utils::RoundUp(file_offset, section->alignment);
|
|
section->file_offset = file_offset;
|
|
file_offset += section->file_size;
|
|
file_offset = Utils::RoundUp(file_offset, section->alignment);
|
|
}
|
|
}
|
|
|
|
void Elf::WriteHeader() {
|
|
#if defined(TARGET_ARCH_IS_32_BIT)
|
|
uint8_t size = ELFCLASS32;
|
|
#else
|
|
uint8_t size = ELFCLASS64;
|
|
#endif
|
|
uint8_t e_ident[16] = {
|
|
0x7f, 'E', 'L', 'F', size, ELFDATA2LSB, EV_CURRENT, ELFOSABI_SYSV,
|
|
0, 0, 0, 0, 0, 0, 0, 0};
|
|
stream_->WriteBytes(e_ident, 16);
|
|
|
|
WriteHalf(ET_DYN); // Shared library.
|
|
|
|
#if defined(TARGET_ARCH_IA32)
|
|
WriteHalf(EM_386);
|
|
#elif defined(TARGET_ARCH_X64)
|
|
WriteHalf(EM_X86_64);
|
|
#elif defined(TARGET_ARCH_ARM)
|
|
WriteHalf(EM_ARM);
|
|
#elif defined(TARGET_ARCH_ARM64)
|
|
WriteHalf(EM_AARCH64);
|
|
#else
|
|
// E.g., DBC.
|
|
FATAL("Unknown ELF architecture");
|
|
#endif
|
|
|
|
WriteWord(EV_CURRENT); // Version
|
|
WriteAddr(0); // "Entry point"
|
|
WriteOff(program_table_file_offset_);
|
|
WriteOff(section_table_file_offset_);
|
|
|
|
#if defined(TARGET_ARCH_ARM)
|
|
uword flags = EF_ARM_ABI |
|
|
(TargetCPUFeatures::hardfp_supported() ? EF_ARM_ABI_FLOAT_HARD
|
|
: EF_ARM_ABI_FLOAT_SOFT);
|
|
#else
|
|
uword flags = 0;
|
|
#endif
|
|
WriteWord(flags);
|
|
|
|
WriteHalf(kElfHeaderSize);
|
|
WriteHalf(kElfProgramTableEntrySize);
|
|
WriteHalf(segments_.length() + kNumImplicitSegments);
|
|
WriteHalf(kElfSectionTableEntrySize);
|
|
WriteHalf(sections_.length() + kNumInvalidSections);
|
|
WriteHalf(shstrtab_->section_index);
|
|
|
|
ASSERT(stream_->position() == kElfHeaderSize);
|
|
}
|
|
|
|
void Elf::WriteProgramTable() {
|
|
stream_->Align(kPageSize);
|
|
|
|
ASSERT(stream_->position() == program_table_file_offset_);
|
|
|
|
// Self-reference to program header table that Android wants for some reason.
|
|
// Must appear before any PT_LOAD entries.
|
|
{
|
|
ASSERT(kNumImplicitSegments == 3);
|
|
const intptr_t start = stream_->position();
|
|
#if defined(TARGET_ARCH_IS_32_BIT)
|
|
WriteWord(PT_PHDR);
|
|
WriteOff(program_table_file_offset_);
|
|
WriteAddr(memory_offset_);
|
|
WriteAddr(0); // Physical address, not used.
|
|
WriteWord(program_table_file_size_);
|
|
WriteWord(program_table_file_size_);
|
|
WriteWord(PF_R);
|
|
WriteWord(kPageSize);
|
|
#else
|
|
WriteWord(PT_PHDR);
|
|
WriteWord(PF_R);
|
|
WriteOff(program_table_file_offset_);
|
|
WriteAddr(memory_offset_);
|
|
WriteAddr(0); // Physical address, not used.
|
|
WriteXWord(program_table_file_size_);
|
|
WriteXWord(program_table_file_size_);
|
|
WriteXWord(kPageSize);
|
|
#endif
|
|
const intptr_t end = stream_->position();
|
|
ASSERT((end - start) == kElfProgramTableEntrySize);
|
|
}
|
|
|
|
for (intptr_t i = 0; i < segments_.length(); i++) {
|
|
Section* section = segments_[i];
|
|
const intptr_t start = stream_->position();
|
|
#if defined(TARGET_ARCH_IS_32_BIT)
|
|
WriteWord(section->segment_type);
|
|
WriteOff(section->file_offset);
|
|
WriteAddr(section->memory_offset);
|
|
WriteAddr(0); // Physical address, not used.
|
|
WriteWord(section->file_size);
|
|
WriteWord(section->memory_size);
|
|
WriteWord(section->segment_flags);
|
|
WriteWord(section->alignment);
|
|
#else
|
|
WriteWord(section->segment_type);
|
|
WriteWord(section->segment_flags);
|
|
WriteOff(section->file_offset);
|
|
WriteAddr(section->memory_offset);
|
|
WriteAddr(0); // Physical address, not used.
|
|
WriteXWord(section->file_size);
|
|
WriteXWord(section->memory_size);
|
|
WriteXWord(section->alignment);
|
|
#endif
|
|
const intptr_t end = stream_->position();
|
|
ASSERT((end - start) == kElfProgramTableEntrySize);
|
|
}
|
|
|
|
// Special case: the dynamic section requires both LOAD and DYNAMIC program
|
|
// header table entries.
|
|
{
|
|
ASSERT(kNumImplicitSegments == 3);
|
|
const intptr_t start = stream_->position();
|
|
#if defined(TARGET_ARCH_IS_32_BIT)
|
|
WriteWord(PT_DYNAMIC);
|
|
WriteOff(dynamic_->file_offset);
|
|
WriteAddr(dynamic_->memory_offset);
|
|
WriteAddr(0); // Physical address, not used.
|
|
WriteWord(dynamic_->file_size);
|
|
WriteWord(dynamic_->memory_size);
|
|
WriteWord(dynamic_->segment_flags);
|
|
WriteWord(dynamic_->alignment);
|
|
#else
|
|
WriteWord(PT_DYNAMIC);
|
|
WriteWord(dynamic_->segment_flags);
|
|
WriteOff(dynamic_->file_offset);
|
|
WriteAddr(dynamic_->memory_offset);
|
|
WriteAddr(0); // Physical address, not used.
|
|
WriteXWord(dynamic_->file_size);
|
|
WriteXWord(dynamic_->memory_size);
|
|
WriteXWord(dynamic_->alignment);
|
|
#endif
|
|
const intptr_t end = stream_->position();
|
|
ASSERT((end - start) == kElfProgramTableEntrySize);
|
|
}
|
|
|
|
// Self-reference to program header table that Android wants for some reason.
|
|
{
|
|
ASSERT(kNumImplicitSegments == 3);
|
|
const intptr_t start = stream_->position();
|
|
#if defined(TARGET_ARCH_IS_32_BIT)
|
|
WriteWord(PT_LOAD);
|
|
WriteOff(program_table_file_offset_);
|
|
WriteAddr(memory_offset_);
|
|
WriteAddr(0); // Physical address, not used.
|
|
WriteWord(program_table_file_size_);
|
|
WriteWord(program_table_file_size_);
|
|
WriteWord(PF_R);
|
|
WriteWord(kPageSize);
|
|
#else
|
|
WriteWord(PT_LOAD);
|
|
WriteWord(PF_R);
|
|
WriteOff(program_table_file_offset_);
|
|
WriteAddr(memory_offset_);
|
|
WriteAddr(0); // Physical address, not used.
|
|
WriteXWord(program_table_file_size_);
|
|
WriteXWord(program_table_file_size_);
|
|
WriteXWord(kPageSize);
|
|
#endif
|
|
const intptr_t end = stream_->position();
|
|
ASSERT((end - start) == kElfProgramTableEntrySize);
|
|
}
|
|
}
|
|
|
|
void Elf::WriteSectionTable() {
|
|
ASSERT(stream_->position() == section_table_file_offset_);
|
|
|
|
{
|
|
// The first entry in the section table is reserved and must be all zeros.
|
|
ASSERT(kNumInvalidSections == 1);
|
|
const intptr_t start = stream_->position();
|
|
#if defined(TARGET_ARCH_IS_32_BIT)
|
|
WriteWord(0);
|
|
WriteWord(0);
|
|
WriteWord(0);
|
|
WriteAddr(0);
|
|
WriteOff(0);
|
|
WriteWord(0);
|
|
WriteWord(0);
|
|
WriteWord(0);
|
|
WriteWord(0);
|
|
WriteWord(0);
|
|
#else
|
|
WriteWord(0);
|
|
WriteWord(0);
|
|
WriteXWord(0);
|
|
WriteAddr(0);
|
|
WriteOff(0);
|
|
WriteXWord(0);
|
|
WriteWord(0);
|
|
WriteWord(0);
|
|
WriteXWord(0);
|
|
WriteXWord(0);
|
|
#endif
|
|
const intptr_t end = stream_->position();
|
|
ASSERT((end - start) == kElfSectionTableEntrySize);
|
|
}
|
|
|
|
for (intptr_t i = 0; i < sections_.length(); i++) {
|
|
Section* section = sections_[i];
|
|
const intptr_t start = stream_->position();
|
|
#if defined(TARGET_ARCH_IS_32_BIT)
|
|
WriteWord(section->section_name);
|
|
WriteWord(section->section_type);
|
|
WriteWord(section->section_flags);
|
|
WriteAddr(section->memory_offset);
|
|
WriteOff(section->file_offset);
|
|
WriteWord(section->file_size); // Has different meaning for BSS.
|
|
WriteWord(section->section_link);
|
|
WriteWord(section->section_info);
|
|
WriteWord(section->alignment);
|
|
WriteWord(section->section_entry_size);
|
|
#else
|
|
WriteWord(section->section_name);
|
|
WriteWord(section->section_type);
|
|
WriteXWord(section->section_flags);
|
|
WriteAddr(section->memory_offset);
|
|
WriteOff(section->file_offset);
|
|
WriteXWord(section->file_size); // Has different meaning for BSS.
|
|
WriteWord(section->section_link);
|
|
WriteWord(section->section_info);
|
|
WriteXWord(section->alignment);
|
|
WriteXWord(section->section_entry_size);
|
|
#endif
|
|
const intptr_t end = stream_->position();
|
|
ASSERT((end - start) == kElfSectionTableEntrySize);
|
|
}
|
|
}
|
|
|
|
void Elf::WriteSections() {
|
|
for (intptr_t i = 0; i < sections_.length(); i++) {
|
|
Section* section = sections_[i];
|
|
stream_->Align(section->alignment);
|
|
ASSERT(stream_->position() == section->file_offset);
|
|
section->Write(this);
|
|
ASSERT(stream_->position() == section->file_offset + section->file_size);
|
|
stream_->Align(section->alignment);
|
|
}
|
|
}
|
|
|
|
} // namespace dart
|