1b50200abd
Before, picking a symbol name for a Code object when generating assembly required adding a placeholder entry in the Dwarf object, because the Dwarf object separately used a SnapshotTextObjectNamer to determine the appropriate symbol name to use in relocations. Instead, now the ImageWriter subclasses are entirely responsible for creating the symbol name for a given Code object, and that name is passed when adding the Code object to the Dwarf object. For Elf output, we eagerly create symbols for sections and Code objects again in the appropriate symbol table, and so looking up the start of a given section or Code object can be done simply by asking for the corresponding symbol's address, removing special case methods and other workarounds. We also clean up the generated static and dynamic symbol tables by only generating local symbols for Code objects and BSS sections (these are local in assembly output also), and only adding global symbols to the dynamic symbol table. Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-mac-release-simarm64-try,vm-kernel-mac-debug-x64-try,vm-kernel-win-debug-x64-try,vm-kernel-precomp-win-release-x64-try Change-Id: Ie40c0c836681e98f345483136bb6860e5588ef30 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/166002 Reviewed-by: Martin Kustermann <kustermann@google.com>
155 lines
5.5 KiB
C++
155 lines
5.5 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.
|
|
|
|
#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 {
|
|
|
|
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 = 4096;
|
|
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 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;
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_ELF_H_
|