Create magic symbol to mark .symtab as sorted.
ELF symbols don't have to be sorted, but ART always sorts them.
This is very useful property if libunwindstack can rely on it.
(that is, it can binary search the table instead of linear)
Bug: 110133331
Test: art/test.py -b --host
Change-Id: I4d491096a5bd4ea738a45bbc64fc9dea91c45575
diff --git a/compiler/debug/elf_symtab_writer.h b/compiler/debug/elf_symtab_writer.h
index ac8c812..410f704 100644
--- a/compiler/debug/elf_symtab_writer.h
+++ b/compiler/debug/elf_symtab_writer.h
@@ -42,6 +42,11 @@
// Note that ARM's Streamline requires it to match function symbol.
constexpr bool kGenerateArmMappingSymbol = true;
+// Create magic symbol to let libunwindstack know that symtab is sorted by address.
+constexpr bool kGenerateSortedSymbol = true;
+constexpr const char kSortedSymbolName[] = "$android.symtab.sorted";
+constexpr size_t kSortedSymbolMinCount = 100; // Don't bother if the table is very small (JIT).
+
// Magic name for .symtab symbols which enumerate dex files used
// by this ELF file (currently mmapped inside the .dex section).
constexpr const char* kDexFileSymbolName = "$dexfile";
@@ -116,10 +121,14 @@
}
strtab->Start();
- strtab->Write(""); // strtab should start with empty string.
+ // Generate marker to annotate the symbol table as sorted (guaranteed by the ElfBuilder).
+ // Note that LOCAL symbols are sorted before GLOBAL ones, so don't mix the two types.
+ if (kGenerateSortedSymbol && debug_info.compiled_methods.size() >= kSortedSymbolMinCount) {
+ symtab->Add(strtab->Write(kSortedSymbolName), nullptr, 0, 0, STB_GLOBAL, STT_NOTYPE);
+ }
// Generate ARM mapping symbols. ELF local symbols must be added first.
if (mapping_symbol_address != std::numeric_limits<uint64_t>::max()) {
- symtab->Add(strtab->Write("$t"), text, mapping_symbol_address, 0, STB_LOCAL, STT_NOTYPE);
+ symtab->Add(strtab->Write("$t"), text, mapping_symbol_address, 0, STB_GLOBAL, STT_NOTYPE);
}
// Add symbols for compiled methods.
for (const MethodDebugInfo& info : debug_info.compiled_methods) {
diff --git a/libelffile/elf/elf_builder.h b/libelffile/elf/elf_builder.h
index 4dde150..086bd41 100644
--- a/libelffile/elf/elf_builder.h
+++ b/libelffile/elf/elf_builder.h
@@ -130,7 +130,7 @@
}
// Start writing file data of this section.
- void Start() {
+ virtual void Start() {
CHECK(owner_->current_section_ == nullptr);
Elf_Word align = AddSection();
CHECK_EQ(header_.sh_offset, 0u);
@@ -139,7 +139,7 @@
}
// Finish writing file data of this section.
- void End() {
+ virtual void End() {
CHECK(owner_->current_section_ == this);
Elf_Word position = GetPosition();
CHECK(header_.sh_size == 0u || header_.sh_size == position);
@@ -310,6 +310,11 @@
last_offset_ = 0;
}
+ void Start() {
+ Section::Start();
+ Write(""); // ELF specification requires that the section starts with empty string.
+ }
+
Elf_Word Write(std::string_view name) {
if (current_offset_ == 0) {
DCHECK(name.empty());
@@ -368,10 +373,13 @@
// Buffer symbol for this section. It will be written later.
void Add(Elf_Sym sym, const Section* section) {
- DCHECK(section != nullptr);
- DCHECK_LE(section->GetAddress(), sym.st_value);
- DCHECK_LE(sym.st_value, section->GetAddress() + section->header_.sh_size);
- sym.st_shndx = section->GetSectionIndex();
+ if (section != nullptr) {
+ DCHECK_LE(section->GetAddress(), sym.st_value);
+ DCHECK_LE(sym.st_value, section->GetAddress() + section->header_.sh_size);
+ sym.st_shndx = section->GetSectionIndex();
+ } else {
+ sym.st_shndx = SHN_UNDEF;
+ }
syms_.push_back(sym);
}