| // 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_NULL = 0; |
| 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 kElfSectionTableAlignment = 4; |
| static const intptr_t kElfSectionTableEntrySize = 40; |
| static const intptr_t kElfProgramTableEntrySize = 32; |
| static const intptr_t kElfSymbolTableEntrySize = 16; |
| static const intptr_t kElfDynamicTableEntrySize = 8; |
| static const intptr_t kElfSymbolHashTableEntrySize = 4; |
| #else |
| static const intptr_t kElfHeaderSize = 64; |
| static const intptr_t kElfSectionTableAlignment = 8; |
| static const intptr_t kElfSectionTableEntrySize = 64; |
| static const intptr_t kElfProgramTableEntrySize = 56; |
| static const intptr_t kElfSymbolTableEntrySize = 24; |
| static const intptr_t kElfDynamicTableEntrySize = 16; |
| static const intptr_t kElfSymbolHashTableEntrySize = 4; |
| #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: |
| explicit StringTable(bool allocate) : text_(128) { |
| section_type = SHT_STRTAB; |
| section_flags = allocate ? SHF_ALLOC : 0; |
| 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; |
| section_entry_size = kElfSymbolHashTableEntrySize; |
| 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); |
| AddEntry(DT_NULL, 0); |
| } |
| |
| 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_; |
| }; |
| |
| // 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; |
| |
| static const intptr_t kProgramTableSegmentSize = kPageSize; |
| |
| 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(/* allocate= */ false); |
| shstrtab_->section_name = shstrtab_->AddString(".shstrtab"); |
| |
| symstrtab_ = new (zone_) StringTable(/* allocate= */ true); |
| symstrtab_->section_name = shstrtab_->AddString(".dynstr"); |
| |
| symtab_ = new (zone_) SymbolTable(); |
| symtab_->section_name = shstrtab_->AddString(".dynsym"); |
| |
| // Allocate regular segments after the program table. |
| memory_offset_ = kProgramTableSegmentSize; |
| } |
| |
| 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); |
| AddSection(symtab_); |
| AddSection(symstrtab_); |
| |
| symtab_->section_link = symstrtab_->section_index; |
| hash->section_link = symtab_->section_index; |
| |
| // Before finalizing the string table's memory size: |
| intptr_t name_dynamic = shstrtab_->AddString(".dynamic"); |
| |
| // Finalizes memory size of string and symbol tables. |
| AddSegment(hash); |
| AddSegment(symtab_); |
| AddSegment(symstrtab_); |
| |
| dynamic_ = new (zone_) DynamicTable(symstrtab_, symtab_, hash); |
| dynamic_->section_name = name_dynamic; |
| AddSection(dynamic_); |
| AddSegment(dynamic_); |
| |
| AddSection(shstrtab_); |
| shstrtab_->memory_offset = 0; // No segment. |
| |
| ComputeFileOffsets(); |
| |
| WriteHeader(); |
| WriteProgramTable(); |
| WriteSections(); |
| WriteSectionTable(); |
| } |
| |
| void Elf::ComputeFileOffsets() { |
| intptr_t file_offset = kElfHeaderSize; |
| |
| program_table_file_offset_ = file_offset; |
| program_table_file_size_ = |
| (segments_.length() + kNumImplicitSegments) * kElfProgramTableEntrySize; |
| file_offset += program_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, kElfSectionTableAlignment); |
| section_table_file_offset_ = file_offset; |
| section_table_file_size_ = |
| (sections_.length() + kNumInvalidSections) * kElfSectionTableEntrySize; |
| file_offset += section_table_file_size_; |
| } |
| |
| 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() { |
| ASSERT(stream_->position() == program_table_file_offset_); |
| |
| // Self-reference to program header table. Required by Android but not by |
| // Linux. 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_); // File offset. |
| WriteAddr(program_table_file_offset_); // Virtual address. |
| WriteAddr(program_table_file_offset_); // 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_); // File offset. |
| WriteAddr(program_table_file_offset_); // Virtual address. |
| WriteAddr(program_table_file_offset_); // 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); |
| } |
| // Load for self-reference to program header table. Required by Android but |
| // not by Linux. |
| { |
| // We pre-allocated the virtual memory space for the program table itself. |
| // Check that we didn't generate too many segments. Currently we generate a |
| // fixed num of segments based on the four pieces of a snapshot, but if we |
| // use more in the future we'll likely need to do something more compilated |
| // to generate DWARF without knowing a piece's virtual address in advance. |
| RELEASE_ASSERT((program_table_file_offset_ + program_table_file_size_) < |
| kProgramTableSegmentSize); |
| |
| ASSERT(kNumImplicitSegments == 3); |
| const intptr_t start = stream_->position(); |
| #if defined(TARGET_ARCH_IS_32_BIT) |
| WriteWord(PT_LOAD); |
| WriteOff(0); // File offset. |
| WriteAddr(0); // Virtual address. |
| WriteAddr(0); // Physical address, not used. |
| WriteWord(program_table_file_offset_ + program_table_file_size_); |
| WriteWord(program_table_file_offset_ + program_table_file_size_); |
| WriteWord(PF_R); |
| WriteWord(kPageSize); |
| #else |
| WriteWord(PT_LOAD); |
| WriteWord(PF_R); |
| WriteOff(0); // File offset. |
| WriteAddr(0); // Virtual address. |
| WriteAddr(0); // Physical address, not used. |
| WriteXWord(program_table_file_offset_ + program_table_file_size_); |
| WriteXWord(program_table_file_offset_ + 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); // Virtual address. |
| WriteAddr(section->memory_offset); // 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); // Virtual address. |
| WriteAddr(section->memory_offset); // 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); // Virtual address. |
| WriteAddr(dynamic_->memory_offset); // 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); // Virtual address. |
| WriteAddr(dynamic_->memory_offset); // 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); |
| } |
| } |
| |
| void Elf::WriteSectionTable() { |
| stream_->Align(kElfSectionTableAlignment); |
| |
| 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); |
| } |
| } |
| |
| } // namespace dart |