[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 <rmacnak@google.com>
Commit-Queue: Samir Jindel <sjindel@google.com>
This commit is contained in:
Samir Jindel
2019-10-25 11:53:14 +00:00
committed by commit-bot@chromium.org
parent 165196dbc0
commit 36cd2e22d4
7 changed files with 183 additions and 91 deletions
+2 -1
View File
@@ -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;
+41 -24
View File
@@ -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<const Function*> function_stack(zone_, 8);
GrowableArray<TokenPosition> 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;
+3 -1
View File
@@ -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_;
+59 -23
View File
@@ -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_);
+8 -2
View File
@@ -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_;
};
+47 -40
View File
@@ -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<char*>(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<char*>(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<char*>(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<char*>(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
+23
View File
@@ -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,