summaryrefslogtreecommitdiffstats
path: root/compiler/elf_writer_quick.cc
diff options
context:
space:
mode:
authorDavid Srbecky <dsrbecky@google.com>2015-04-11 00:17:53 +0100
committerDavid Srbecky <dsrbecky@google.com>2015-04-11 19:14:10 +0100
commit2f6cdb01f74772c1c521a125776ef57ea3c73d43 (patch)
tree163f90841f02b9529997f4e3eea65e512e4795a3 /compiler/elf_writer_quick.cc
parent58565098b2298041ccc97371a3cc486df88d51b3 (diff)
downloadandroid_art-2f6cdb01f74772c1c521a125776ef57ea3c73d43.tar.gz
android_art-2f6cdb01f74772c1c521a125776ef57ea3c73d43.tar.bz2
android_art-2f6cdb01f74772c1c521a125776ef57ea3c73d43.zip
Relocate DWARF using .oat_patches.
The current solution is to hard-code knowledge of DWARF in the linker. This works for simple use of DWARF, but breaks as soon as I try to do anything more complex. Making the linker fully support DWARF would be non-trivial task and would be essentially rewrite. Using .oat_patches is much easier solution. Relocating .debug_* sections required extending .oat_patches to support more sections than just .text. I have encoded each section as null-terminated section name followed by ULEB128 deltas. The ULEB128 encoding shrinks .oat_patches for .text by factor of about 6 with 64-bit compiler, and factor of 3 with 32-bit compiler. On the other hand, it grows by the extra .oat_patches for DWARF which were not present before (if debug symbols are included). Overall, it is still a clear improvement even with the DWARF patches. Change-Id: I78ffeda0f8a3da03341995a3b5ef15c954e16e9f
Diffstat (limited to 'compiler/elf_writer_quick.cc')
-rw-r--r--compiler/elf_writer_quick.cc49
1 files changed, 40 insertions, 9 deletions
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index e9af25f293..da1f81a52e 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -74,6 +74,40 @@ static void WriteDebugSymbols(const CompilerDriver* compiler_driver,
Elf_Sym, Elf_Ehdr, Elf_Phdr, Elf_Shdr>* builder,
OatWriter* oat_writer);
+// Encode patch locations in .oat_patches format.
+template <typename Elf_Word, typename Elf_Sword, typename Elf_Addr,
+ typename Elf_Dyn, typename Elf_Sym, typename Elf_Ehdr,
+ typename Elf_Phdr, typename Elf_Shdr>
+void ElfWriterQuick<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn, Elf_Sym, Elf_Ehdr,
+ Elf_Phdr, Elf_Shdr>::EncodeOatPatches(const OatWriter::PatchLocationsMap& sections,
+ std::vector<uint8_t>* buffer) {
+ for (const auto& section : sections) {
+ const std::string& name = section.first;
+ std::vector<uintptr_t>* locations = section.second.get();
+ DCHECK(!name.empty());
+ std::sort(locations->begin(), locations->end());
+ // Reserve buffer space - guess 2 bytes per ULEB128.
+ buffer->reserve(buffer->size() + name.size() + locations->size() * 2);
+ // Write null-terminated section name.
+ const uint8_t* name_data = reinterpret_cast<const uint8_t*>(name.c_str());
+ buffer->insert(buffer->end(), name_data, name_data + name.size() + 1);
+ // Write placeholder for data length.
+ size_t length_pos = buffer->size();
+ EncodeUnsignedLeb128(buffer, UINT32_MAX);
+ // Write LEB128 encoded list of advances (deltas between consequtive addresses).
+ size_t data_pos = buffer->size();
+ uintptr_t address = 0; // relative to start of section.
+ for (uintptr_t location : *locations) {
+ DCHECK_LT(location - address, UINT32_MAX) << "Large gap between patch locations";
+ EncodeUnsignedLeb128(buffer, location - address);
+ address = location;
+ }
+ // Update length.
+ UpdateUnsignedLeb128(buffer->data() + length_pos, buffer->size() - data_pos);
+ }
+ buffer->push_back(0); // End of sections.
+}
+
template <typename Elf_Word, typename Elf_Sword, typename Elf_Addr,
typename Elf_Dyn, typename Elf_Sym, typename Elf_Ehdr,
typename Elf_Phdr, typename Elf_Shdr>
@@ -115,16 +149,13 @@ bool ElfWriterQuick<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn,
WriteDebugSymbols(compiler_driver_, builder.get(), oat_writer);
}
- if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation()) {
+ if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation() ||
+ // ElfWriter::Fixup will be called regardless and it needs to be able
+ // to patch debug sections so we have to include patches for them.
+ compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> oat_patches(
- ".oat_patches", SHT_OAT_PATCH, 0, NULL, 0, sizeof(uintptr_t), sizeof(uintptr_t));
- const std::vector<uintptr_t>& locations = oat_writer->GetAbsolutePatchLocations();
- const uint8_t* begin = reinterpret_cast<const uint8_t*>(&locations[0]);
- const uint8_t* end = begin + locations.size() * sizeof(locations[0]);
- oat_patches.GetBuffer()->assign(begin, end);
- if (debug) {
- LOG(INFO) << "Prepared .oat_patches for " << locations.size() << " patches.";
- }
+ ".oat_patches", SHT_OAT_PATCH, 0, NULL, 0, 1, 0);
+ EncodeOatPatches(oat_writer->GetAbsolutePatchLocations(), oat_patches.GetBuffer());
builder->RegisterRawSection(oat_patches);
}