| // 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); |
| |
| // We don't bother with a separate .shstrtab since all our strings will fit |
| // in a single page. |
| strtab_ = new (zone_) StringTable(); |
| strtab_->section_name = strtab_->AddString(".dynstr"); |
| AddSection(strtab_); |
| |
| symtab_ = new (zone_) SymbolTable(); |
| symtab_->section_name = strtab_->AddString(".dynsym"); |
| symtab_->section_link = strtab_->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 = strtab_->AddString(".text"); |
| AddSection(image); |
| AddSegment(image); |
| |
| Symbol* symbol = new (zone_) Symbol(); |
| symbol->cstr = name; |
| symbol->name = strtab_->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 = strtab_->AddString(".rodata"); |
| AddSection(image); |
| AddSegment(image); |
| |
| Symbol* symbol = new (zone_) Symbol(); |
| symbol->cstr = name; |
| symbol->name = strtab_->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 = strtab_->AddString(name); |
| AddSection(image); |
| } |
| |
| void Elf::Finalize() { |
| SymbolHashTable* hash = new (zone_) SymbolHashTable(strtab_, symtab_); |
| hash->section_name = strtab_->AddString(".hash"); |
| AddSection(hash); |
| AddSegment(hash); |
| |
| // Before finalizing the string table's memory size: |
| intptr_t name_dynamic = strtab_->AddString(".dynamic"); |
| |
| // Finalizes memory size of string and symbol tables. |
| AddSegment(strtab_); |
| AddSegment(symtab_); |
| |
| dynamic_ = new (zone_) DynamicTable(strtab_, 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(strtab_->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 |