From 36cd2e22d407b5b71a0dbc4ddde01d2487fb034d Mon Sep 17 00:00:00 2001 From: Samir Jindel Date: Fri, 25 Oct 2019 11:53:14 +0000 Subject: [PATCH] [vm/aot] Expose static symbols in directly-generated ELF snapshots. Also use the function labels for Dwarf in Assembly snapshots to avoid creating duplicate labels. Fixes https://github.com/dart-lang/sdk/issues/38978 Issue https://github.com/dart-lang/sdk/issues/38526 Change-Id: Icafd3d3a86381990ec8097397a21b16ad4a7a766 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/122150 Reviewed-by: Ryan Macnak Commit-Queue: Samir Jindel --- runtime/platform/elf.h | 3 +- runtime/vm/dwarf.cc | 65 +++++++++++++++++---------- runtime/vm/dwarf.h | 4 +- runtime/vm/elf.cc | 82 +++++++++++++++++++++++---------- runtime/vm/elf.h | 10 ++++- runtime/vm/image_snapshot.cc | 87 +++++++++++++++++++----------------- runtime/vm/image_snapshot.h | 23 ++++++++++ 7 files changed, 183 insertions(+), 91 deletions(-) diff --git a/runtime/platform/elf.h b/runtime/platform/elf.h index 729ac7dcf56..939225ee12a 100644 --- a/runtime/platform/elf.h +++ b/runtime/platform/elf.h @@ -135,10 +135,11 @@ static const intptr_t PF_W = 2; static const intptr_t PF_R = 4; static const intptr_t SHT_PROGBITS = 1; +static const intptr_t SHT_SYMTAB = 2; 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 SHT_DYNSYM = 11; static const intptr_t SHF_WRITE = 0x1; static const intptr_t SHF_ALLOC = 0x2; diff --git a/runtime/vm/dwarf.cc b/runtime/vm/dwarf.cc index 213611431a2..cd5530d3639 100644 --- a/runtime/vm/dwarf.cc +++ b/runtime/vm/dwarf.cc @@ -6,6 +6,7 @@ #include "vm/code_descriptors.h" #include "vm/elf.h" +#include "vm/image_snapshot.h" #include "vm/object_store.h" namespace dart { @@ -254,6 +255,8 @@ void Dwarf::WriteCompilationUnit() { uint8_t* buffer = nullptr; WriteStream stream(&buffer, ZoneReallocate, 64 * KB); + AssemblyCodeNamer namer(zone_); + if (asm_stream_) { #if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS) Print(".section __DWARF,__debug_info,regular,debug\n"); @@ -314,8 +317,8 @@ void Dwarf::WriteCompilationUnit() { if (asm_stream_) { intptr_t last_code_index = codes_.length() - 1; const Code& last_code = *(codes_[last_code_index]); - Print(FORM_ADDR " .Lcode%" Pd " + %" Pd "\n", last_code_index, - last_code.Size()); + Print(FORM_ADDR " %s + %" Pd "\n", + namer.AssemblyNameFor(last_code_index, last_code), last_code.Size()); } else { addr(elf_->NextMemoryOffset()); } @@ -373,6 +376,7 @@ void Dwarf::WriteAbstractFunctions() { void Dwarf::WriteConcreteFunctions() { Function& function = Function::Handle(zone_); Script& script = Script::Handle(zone_); + AssemblyCodeNamer namer(zone_); for (intptr_t i = 0; i < codes_.length(); i++) { const Code& code = *(codes_[i]); RELEASE_ASSERT(!code.IsNull()); @@ -403,14 +407,13 @@ void Dwarf::WriteConcreteFunctions() { // DW_AT_low_pc if (asm_stream_) { - Print(FORM_ADDR " .Lcode%" Pd "\n", i); + const char* asm_name = namer.AssemblyNameFor(i, code); + // DW_AT_low_pc + Print(FORM_ADDR " %s\n", asm_name); + // DW_AT_high_pc + Print(FORM_ADDR " %s + %" Pd "\n", asm_name, code.Size()); } else { addr(code_offset); - } - // DW_AT_high_pc - if (asm_stream_) { - Print(FORM_ADDR " .Lcode%" Pd " + %" Pd "\n", i, code.Size()); - } else { addr(code_offset + code.Size()); } @@ -418,7 +421,7 @@ void Dwarf::WriteConcreteFunctions() { if (node != NULL) { for (InliningNode* child = node->children_head; child != NULL; child = child->children_next) { - WriteInliningNode(child, i, script); + WriteInliningNode(child, i, script, &namer); } } @@ -509,7 +512,8 @@ InliningNode* Dwarf::ExpandInliningTree(const Code& code) { void Dwarf::WriteInliningNode(InliningNode* node, intptr_t root_code_index, - const Script& parent_script) { + const Script& parent_script, + AssemblyCodeNamer* namer) { intptr_t file = LookupScript(parent_script); intptr_t line = node->call_pos.value(); intptr_t function_index = LookupFunction(node->function); @@ -527,20 +531,21 @@ void Dwarf::WriteInliningNode(InliningNode* node, } else { u4(abstract_origins_[function_index]); } - // DW_AT_low_pc + if (asm_stream_) { - Print(FORM_ADDR " .Lcode%" Pd " + %d\n", root_code_index, - node->start_pc_offset); + const char* asm_name = + namer->AssemblyNameFor(root_code_index, *codes_[root_code_index]); + // DW_AT_low_pc + Print(FORM_ADDR " %s + %d\n", asm_name, node->start_pc_offset); + // DW_AT_high_pc + Print(FORM_ADDR " %s + %d\n", asm_name, node->end_pc_offset); } else { + // DW_AT_low_pc addr(root_code_index + node->start_pc_offset); - } // DW_AT_high_pc - if (asm_stream_) { - Print(FORM_ADDR " .Lcode%" Pd " + %d\n", root_code_index, - node->end_pc_offset); - } else { addr(root_code_index + node->end_pc_offset); } + // DW_AT_call_file uleb128(file); // DW_AT_call_line @@ -548,7 +553,7 @@ void Dwarf::WriteInliningNode(InliningNode* node, for (InliningNode* child = node->children_head; child != NULL; child = child->children_next) { - WriteInliningNode(child, root_code_index, script); + WriteInliningNode(child, root_code_index, script, namer); } uleb128(0); // End of children. @@ -655,10 +660,16 @@ void Dwarf::WriteLines() { Array& functions = Array::Handle(zone_); GrowableArray function_stack(zone_, 8); GrowableArray token_positions(zone_, 8); + AssemblyCodeNamer namer(zone_); for (intptr_t i = 0; i < codes_.length(); i++) { const Code& code = *(codes_[i]); + const char* asm_name = nullptr; + if (asm_stream_ != nullptr) { + asm_name = namer.AssemblyNameFor(i, code); + } + CodeIndexPair* pair = code_to_index_.Lookup(&code); RELEASE_ASSERT(pair != NULL); intptr_t current_code_offset = pair->index_; @@ -723,15 +734,16 @@ void Dwarf::WriteLines() { u1(1 + sizeof(void*)); // that is 5 or 9 bytes long u1(DW_LNE_set_address); if (asm_stream_) { - Print(FORM_ADDR " .Lcode%" Pd " + %d\n", i, current_pc_offset); + Print(FORM_ADDR " %s + %d\n", asm_name, current_pc_offset); } else { addr(current_code_offset + current_pc_offset); } } else { u1(DW_LNS_advance_pc); if (asm_stream_) { - Print(".uleb128 .Lcode%" Pd " - .Lcode%" Pd " + %" Pd "\n", i, - previous_code_offset, + const char* previous_asm_name = namer.AssemblyNameFor( + previous_code_offset, *codes_[previous_code_offset]); + Print(".uleb128 %s - %s + %" Pd "\n", asm_name, previous_asm_name, current_pc_offset - previous_pc_offset); } else { intptr_t delta = current_code_offset - previous_code_offset + @@ -780,8 +792,13 @@ void Dwarf::WriteLines() { u1(DW_LNS_advance_pc); if (asm_stream_) { - Print(".uleb128 .Lcode%" Pd " - .Lcode%" Pd " + %" Pd "\n", last_code_index, - previous_code_offset, last_code.Size() - previous_pc_offset); + const char* last_asm_name = + namer.AssemblyNameFor(last_code_index, last_code); + ASSERT(previous_code_offset >= 0); + const char* previous_asm_name = namer.AssemblyNameFor( + previous_code_offset, *codes_[previous_code_offset]); + Print(".uleb128 %s - %s + %" Pd "\n", last_asm_name, previous_asm_name, + last_code.Size() - previous_pc_offset); } else { intptr_t delta = last_code_offset - previous_code_offset + last_code.Size() - previous_pc_offset; diff --git a/runtime/vm/dwarf.h b/runtime/vm/dwarf.h index 7d4f5b77407..14eac018cbc 100644 --- a/runtime/vm/dwarf.h +++ b/runtime/vm/dwarf.h @@ -16,6 +16,7 @@ namespace dart { class Elf; class InliningNode; +class AssemblyCodeNamer; struct ScriptIndexPair { // Typedefs needed for the DirectChainedHashMap template. @@ -285,7 +286,8 @@ class Dwarf : public ZoneAllocated { InliningNode* ExpandInliningTree(const Code& code); void WriteInliningNode(InliningNode* node, intptr_t root_code_index, - const Script& parent_script); + const Script& parent_script, + AssemblyCodeNamer* namer); void WriteLines(); Zone* const zone_; diff --git a/runtime/vm/elf.cc b/runtime/vm/elf.cc index 769f3d5720a..80ff999cddc 100644 --- a/runtime/vm/elf.cc +++ b/runtime/vm/elf.cc @@ -132,11 +132,19 @@ class Symbol : public ZoneAllocated { class SymbolTable : public Section { public: - SymbolTable() { - section_type = elf::SHT_DYNSYM; - section_flags = elf::SHF_ALLOC; - segment_type = elf::PT_LOAD; - segment_flags = elf::PF_R; + explicit SymbolTable(bool dynamic) { + if (dynamic) { + section_type = elf::SHT_DYNSYM; + section_flags = elf::SHF_ALLOC; + segment_type = elf::PT_LOAD; + segment_flags = elf::PF_R; + } else { + // No need to load the static symbol table at runtime since it's ignored + // by the dynamic linker. + section_type = elf::SHT_SYMTAB; + memory_offset = 0; + section_flags = 0; + } section_entry_size = kElfSymbolTableEntrySize; AddSymbol(NULL); @@ -339,11 +347,17 @@ Elf::Elf(Zone* zone, StreamingWriteStream* stream) shstrtab_ = new (zone_) StringTable(/* allocate= */ false); shstrtab_->section_name = shstrtab_->AddString(".shstrtab"); - symstrtab_ = new (zone_) StringTable(/* allocate= */ true); - symstrtab_->section_name = shstrtab_->AddString(".dynstr"); + dynstrtab_ = new (zone_) StringTable(/* allocate= */ true); + dynstrtab_->section_name = shstrtab_->AddString(".dynstr"); - symtab_ = new (zone_) SymbolTable(); - symtab_->section_name = shstrtab_->AddString(".dynsym"); + dynsym_ = new (zone_) SymbolTable(/*dynamic=*/true); + dynsym_->section_name = shstrtab_->AddString(".dynsym"); + + strtab_ = new (zone_) StringTable(/* allocate= */ false); + strtab_->section_name = shstrtab_->AddString(".strtab"); + + symtab_ = new (zone_) SymbolTable(/*dynamic=*/false); + symtab_->section_name = shstrtab_->AddString(".symtab"); // Allocate regular segments after the program table. memory_offset_ = kProgramTableSegmentSize; @@ -366,10 +380,14 @@ void Elf::AddSegment(Section* section) { memory_offset_ = Utils::RoundUp(memory_offset_, kPageSize); } -intptr_t Elf::NextMemoryOffset() { +intptr_t Elf::NextMemoryOffset() const { return memory_offset_; } +intptr_t Elf::NextSectionIndex() const { + return sections_.length() + kNumInvalidSections; +} + intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) { ProgramBits* image = new (zone_) ProgramBits(true, true, false, bytes, size); image->section_name = shstrtab_->AddString(".text"); @@ -378,18 +396,33 @@ intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) { Symbol* symbol = new (zone_) Symbol(); symbol->cstr = name; - symbol->name = symstrtab_->AddString(name); + symbol->name = dynstrtab_->AddString(name); symbol->info = (elf::STB_GLOBAL << 4) | elf::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); + dynsym_->AddSymbol(symbol); return symbol->offset; } +void Elf::AddStaticSymbol(intptr_t section, + const char* name, + size_t memory_offset) { + Symbol* symbol = new (zone_) Symbol(); + symbol->cstr = name; + symbol->name = strtab_->AddString(name); + symbol->info = (elf::STB_GLOBAL << 4) | elf::STT_FUNC; + symbol->section = section; + // For shared libraries, this is the offset from the DSO base. For static + // libraries, this is section relative. + symbol->offset = memory_offset; + symbol->size = 0; + symtab_->AddSymbol(symbol); +} + intptr_t Elf::AddBSSData(const char* name, intptr_t size) { // Ideally the BSS segment would take no space in the object, but Android's // "strip" utility truncates the memory-size of our segments to their @@ -407,14 +440,14 @@ intptr_t Elf::AddBSSData(const char* name, intptr_t size) { Symbol* symbol = new (zone_) Symbol(); symbol->cstr = name; - symbol->name = symstrtab_->AddString(name); + symbol->name = dynstrtab_->AddString(name); symbol->info = (elf::STB_GLOBAL << 4) | elf::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); + dynsym_->AddSymbol(symbol); return symbol->offset; } @@ -427,14 +460,14 @@ intptr_t Elf::AddROData(const char* name, const uint8_t* bytes, intptr_t size) { Symbol* symbol = new (zone_) Symbol(); symbol->cstr = name; - symbol->name = symstrtab_->AddString(name); + symbol->name = dynstrtab_->AddString(name); symbol->info = (elf::STB_GLOBAL << 4) | elf::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); + dynsym_->AddSymbol(symbol); return symbol->offset; } @@ -447,25 +480,28 @@ void Elf::AddDebug(const char* name, const uint8_t* bytes, intptr_t size) { } void Elf::Finalize() { - SymbolHashTable* hash = new (zone_) SymbolHashTable(symstrtab_, symtab_); + SymbolHashTable* hash = new (zone_) SymbolHashTable(dynstrtab_, dynsym_); hash->section_name = shstrtab_->AddString(".hash"); AddSection(hash); + AddSection(dynsym_); + AddSection(dynstrtab_); + AddSection(strtab_); AddSection(symtab_); - AddSection(symstrtab_); - symtab_->section_link = symstrtab_->section_index; - hash->section_link = symtab_->section_index; + dynsym_->section_link = dynstrtab_->section_index; + hash->section_link = dynsym_->section_index; + symtab_->section_link = strtab_->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_); + AddSegment(dynsym_); + AddSegment(dynstrtab_); - dynamic_ = new (zone_) DynamicTable(symstrtab_, symtab_, hash); + dynamic_ = new (zone_) DynamicTable(dynstrtab_, dynsym_, hash); dynamic_->section_name = name_dynamic; AddSection(dynamic_); AddSegment(dynamic_); diff --git a/runtime/vm/elf.h b/runtime/vm/elf.h index 882c9177b23..b328e0f2873 100644 --- a/runtime/vm/elf.h +++ b/runtime/vm/elf.h @@ -25,11 +25,15 @@ class Elf : public ZoneAllocated { static const intptr_t kPageSize = 4096; - intptr_t NextMemoryOffset(); + intptr_t NextMemoryOffset() const; + intptr_t NextSectionIndex() 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); intptr_t AddBSSData(const char* name, intptr_t size); void AddDebug(const char* name, const uint8_t* bytes, intptr_t size); + void AddStaticSymbol(intptr_t section, + const char* name, + size_t memory_offset); void Finalize(); @@ -79,7 +83,9 @@ class Elf : public ZoneAllocated { intptr_t program_table_file_offset_; intptr_t program_table_file_size_; StringTable* shstrtab_; - StringTable* symstrtab_; + StringTable* dynstrtab_; + SymbolTable* dynsym_; + StringTable* strtab_; SymbolTable* symtab_; DynamicTable* dynamic_; }; diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc index e9cc8ca6869..f04309681e0 100644 --- a/runtime/vm/image_snapshot.cc +++ b/runtime/vm/image_snapshot.cc @@ -492,6 +492,40 @@ static const char* NameOfStubIsolateSpecificStub(ObjectStore* object_store, } #endif // !defined(DART_PRECOMPILED_RUNTIME) +const char* AssemblyCodeNamer::AssemblyNameFor(intptr_t code_index, + const Code& code) { + ASSERT(!code.IsNull()); + owner_ = code.owner(); + if (owner_.IsNull()) { + insns_ = code.instructions(); + const char* name = StubCode::NameOfStub(insns_.EntryPoint()); + if (name != nullptr) { + return OS::SCreate(zone_, "Precompiled_Stub_%s", name); + } else { + if (name == nullptr) { + name = NameOfStubIsolateSpecificStub(store_, code); + } + ASSERT(name != nullptr); + return OS::SCreate(zone_, "Precompiled__%s", name); + } + } else if (owner_.IsClass()) { + string_ = Class::Cast(owner_).Name(); + const char* name = string_.ToCString(); + EnsureAssemblerIdentifier(const_cast(name)); + return OS::SCreate(zone_, "Precompiled_AllocationStub_%s_%" Pd, name, + code_index); + } else if (owner_.IsAbstractType()) { + const char* name = namer_.StubNameForType(AbstractType::Cast(owner_)); + return OS::SCreate(zone_, "Precompiled_%s", name); + } else if (owner_.IsFunction()) { + const char* name = Function::Cast(owner_).ToQualifiedCString(); + EnsureAssemblerIdentifier(const_cast(name)); + return OS::SCreate(zone_, "Precompiled_%s_%" Pd, name, code_index); + } else { + UNREACHABLE(); + } +} + void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { #if defined(DART_PRECOMPILED_RUNTIME) UNREACHABLE(); @@ -532,13 +566,8 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { FrameUnwindPrologue(); - Object& owner = Object::Handle(zone); - String& str = String::Handle(zone); PcDescriptors& descriptors = PcDescriptors::Handle(zone); - - ObjectStore* object_store = Isolate::Current()->object_store(); - - TypeTestingStubNamer tts; + AssemblyCodeNamer namer(zone); intptr_t text_offset = 0; ASSERT(offset_space_ != V8SnapshotProfileWriter::kSnapshot); @@ -620,45 +649,16 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { compiler::target::Instructions::HeaderSize()); } - // 2. Write a label at the entry point. - // Linux's perf uses these labels. - ASSERT(!code.IsNull()); - owner = code.owner(); - if (owner.IsNull()) { - const char* name = StubCode::NameOfStub(insns.EntryPoint()); - if (name != nullptr) { - assembly_stream_.Print("Precompiled_Stub_%s:\n", name); - } else { - if (name == nullptr) { - name = NameOfStubIsolateSpecificStub(object_store, code); - } - ASSERT(name != nullptr); - assembly_stream_.Print("Precompiled__%s:\n", name); - } - } else if (owner.IsClass()) { - str = Class::Cast(owner).Name(); - const char* name = str.ToCString(); - EnsureAssemblerIdentifier(const_cast(name)); - assembly_stream_.Print("Precompiled_AllocationStub_%s_%" Pd ":\n", name, - i); - } else if (owner.IsAbstractType()) { - const char* name = tts.StubNameForType(AbstractType::Cast(owner)); - assembly_stream_.Print("Precompiled_%s:\n", name); - } else if (owner.IsFunction()) { - const char* name = Function::Cast(owner).ToQualifiedCString(); - EnsureAssemblerIdentifier(const_cast(name)); - assembly_stream_.Print("Precompiled_%s_%" Pd ":\n", name, i); - } else { - UNREACHABLE(); - } - + intptr_t dwarf_index = i; #ifdef DART_PRECOMPILER // Create a label for use by DWARF. if ((dwarf_ != nullptr) && !code.IsNull()) { - const intptr_t dwarf_index = dwarf_->AddCode(code); - assembly_stream_.Print(".Lcode%" Pd ":\n", dwarf_index); + dwarf_index = dwarf_->AddCode(code); } #endif + // 2. Write a label at the entry point. + // Linux's perf uses these labels. + assembly_stream_.Print("%s:\n", namer.AssemblyNameFor(dwarf_index, code)); { // 3. Write from the payload start to payload end. @@ -888,6 +888,7 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { #if defined(DART_PRECOMPILER) PcDescriptors& descriptors = PcDescriptors::Handle(); + AssemblyCodeNamer namer(Thread::Current()->zone()); #endif NoSafepointScope no_safepoint; @@ -973,6 +974,12 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { #endif // defined(IS_SIMARM_X64) #if defined(DART_PRECOMPILER) + if (elf_ != nullptr && dwarf_ != nullptr) { + elf_->AddStaticSymbol(elf_->NextSectionIndex(), + namer.AssemblyNameFor(i, code), + segment_base + payload_stream_start); + } + // Don't patch the relocation if we're not generating ELF. The regular blobs // format does not yet support these relocations. Use // Code::VerifyBSSRelocations to check whether the relocations are patched diff --git a/runtime/vm/image_snapshot.h b/runtime/vm/image_snapshot.h index be9c6afaf2b..783577868f2 100644 --- a/runtime/vm/image_snapshot.h +++ b/runtime/vm/image_snapshot.h @@ -17,6 +17,7 @@ #include "vm/hash_map.h" #include "vm/object.h" #include "vm/reusable_handles.h" +#include "vm/type_testing_stubs.h" #include "vm/v8_snapshot_writer.h" namespace dart { @@ -291,6 +292,28 @@ class TraceImageObjectScope { intptr_t start_offset_; }; +class AssemblyCodeNamer { + public: + explicit AssemblyCodeNamer(Zone* zone) + : zone_(zone), + owner_(Object::Handle(zone)), + string_(String::Handle(zone)), + insns_(Instructions::Handle(zone)), + store_(Isolate::Current()->object_store()) {} + + const char* StubNameForType(const AbstractType& type) const; + + const char* AssemblyNameFor(intptr_t code_index, const Code& code); + + private: + Zone* const zone_; + Object& owner_; + String& string_; + Instructions& insns_; + ObjectStore* const store_; + TypeTestingStubNamer namer_; +}; + class AssemblyImageWriter : public ImageWriter { public: AssemblyImageWriter(Thread* thread,