| // 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. |
| |
| #ifndef RUNTIME_VM_ELF_H_ |
| #define RUNTIME_VM_ELF_H_ |
| |
| #include "vm/allocation.h" |
| #include "vm/compiler/runtime_api.h" |
| #include "vm/datastream.h" |
| #include "vm/growable_array.h" |
| #include "vm/zone.h" |
| |
| namespace dart { |
| |
| #if defined(DART_PRECOMPILER) |
| |
| class Dwarf; |
| class ElfWriteStream; |
| class Section; |
| class Segment; |
| class StringTable; |
| class SymbolTable; |
| |
| class Elf : public ZoneAllocated { |
| public: |
| enum class Type { |
| // A snapshot that should include segment contents. |
| Snapshot, |
| // Separately compiled debugging information that should not include |
| // most segment contents. |
| DebugInfo, |
| }; |
| |
| Elf(Zone* zone, BaseWriteStream* stream, Type type, Dwarf* dwarf = nullptr); |
| |
| static constexpr intptr_t kPageSize = 16 * KB; |
| static constexpr uword kNoSectionStart = 0; |
| |
| bool IsStripped() const { return dwarf_ == nullptr; } |
| |
| Zone* zone() { return zone_; } |
| const Dwarf* dwarf() const { return dwarf_; } |
| Dwarf* dwarf() { return dwarf_; } |
| |
| // Returns the relocated address for the symbol with the given name or |
| // kNoSectionStart if the symbol was not found. |
| uword SymbolAddress(const char* name) const; |
| |
| // What the next memory offset for an appropriately aligned section would be. |
| // |
| // Only used by AssemblyImageWriter and BlobImageWriter methods. |
| intptr_t NextMemoryOffset(intptr_t alignment) const; |
| intptr_t AddText(const char* name, const uint8_t* bytes, intptr_t size); |
| intptr_t AddROData(const char* name, const uint8_t* bytes, intptr_t size); |
| void AddDebug(const char* name, const uint8_t* bytes, intptr_t size); |
| |
| // Adds a local symbol for the given offset and size in the "current" section, |
| // that is, the section index for the symbol is for the next added section. |
| void AddLocalSymbol(const char* name, |
| intptr_t type, |
| intptr_t offset, |
| intptr_t size); |
| |
| void Finalize(); |
| |
| private: |
| static constexpr const char* kBuildIdNoteName = ".note.gnu.build-id"; |
| |
| static Section* CreateBSS(Zone* zone, Type type, intptr_t size); |
| |
| // Adds the section and also creates a PT_LOAD segment for the section if it |
| // is an allocated section. |
| // |
| // For allocated sections, if symbol_name is provided, a symbol for the |
| // section will be added to the dynamic table (if allocated) and static |
| // table (if not stripped) during finalization. |
| // |
| // Returns the memory offset if the section is allocated. |
| intptr_t AddSection(Section* section, |
| const char* name, |
| const char* symbol_name = nullptr); |
| // Replaces [old_section] with [new_section] in all appropriate places. If the |
| // section is allocated, the memory size of the section must be the same as |
| // the original to ensure any already-calculated memory offsets are unchanged. |
| void ReplaceSection(Section* old_section, Section* new_section); |
| |
| void AddStaticSymbol(const char* name, |
| intptr_t binding, |
| intptr_t type, |
| intptr_t section_index, |
| intptr_t address, |
| intptr_t size); |
| void AddDynamicSymbol(const char* name, |
| intptr_t binding, |
| intptr_t type, |
| intptr_t section_index, |
| intptr_t address, |
| intptr_t size); |
| |
| Segment* LastLoadSegment() const; |
| const Section* FindSectionForAddress(intptr_t address) const; |
| Section* CreateBuildIdNote(const void* description_bytes, |
| intptr_t description_length); |
| Section* GenerateFinalBuildId(); |
| |
| void AddSectionSymbols(); |
| void FinalizeDwarfSections(); |
| void FinalizeProgramTable(); |
| void ComputeFileOffsets(); |
| |
| void FinalizeEhFrame(); |
| |
| void WriteHeader(ElfWriteStream* stream); |
| void WriteSectionTable(ElfWriteStream* stream); |
| void WriteProgramTable(ElfWriteStream* stream); |
| void WriteSections(ElfWriteStream* stream); |
| |
| Zone* const zone_; |
| BaseWriteStream* const unwrapped_stream_; |
| const Type type_; |
| |
| // If nullptr, then the ELF file should be stripped of static information like |
| // the static symbol table (and its corresponding string table). |
| Dwarf* const dwarf_; |
| |
| // We always create a BSS section for all Elf files, though it may be NOBITS |
| // if this is separate debugging information. |
| Section* const bss_; |
| |
| // 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. |
| StringTable* const shstrtab_; |
| StringTable* const dynstrtab_; |
| SymbolTable* const dynsym_; |
| |
| // The static tables are lazily created when static symbols are added. |
| StringTable* strtab_ = nullptr; |
| SymbolTable* symtab_ = nullptr; |
| |
| // We always create a GNU build ID for all Elf files. In order to create |
| // the appropriate offset to it in an InstructionsSection object, we create an |
| // initial build ID section as a placeholder and then replace that section |
| // during finalization once we have the information to calculate the real one. |
| Section* build_id_; |
| |
| GrowableArray<Section*> sections_; |
| GrowableArray<Segment*> segments_; |
| intptr_t memory_offset_; |
| intptr_t section_table_file_offset_ = -1; |
| intptr_t section_table_file_size_ = -1; |
| intptr_t program_table_file_offset_ = -1; |
| intptr_t program_table_file_size_ = -1; |
| }; |
| |
| #endif // DART_PRECOMPILER |
| |
| } // namespace dart |
| |
| #endif // RUNTIME_VM_ELF_H_ |