Split .oat_patches to multiple sections.
.oat_patches section currently contains encoded patch locations for
several other sections. Split it to several sections - one for each
of the destination sections. For example, .text.oat_patches section
contains patch locations for the .text section.
This ensures that if we strip some the sections using standard
tools, we strip the corresponding .oat_patches section as well.
It also makes the overall design simpler.
I should have done it this way in the first place.
Since ApplyOatPatches has been simplified and uses unaligned memory
access, this also fixes bug 21403573.
Bug:20556771
Bug:21403573
Change-Id: Iae7c423911507b524eec500e8d61744046fcd3ba
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 05b5c68..4a90b4e 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -19,6 +19,7 @@
#include <unordered_map>
#include <unordered_set>
+#include "base/casts.h"
#include "base/logging.h"
#include "base/unix_file/fd_file.h"
#include "compiled_method.h"
@@ -69,36 +70,17 @@
template <typename ElfTypes>
static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, OatWriter* oat_writer);
-// Encode patch locations in .oat_patches format.
+// Encode patch locations as LEB128 list of deltas between consecutive addresses.
template <typename ElfTypes>
-void ElfWriterQuick<ElfTypes>::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);
+void ElfWriterQuick<ElfTypes>::EncodeOatPatches(const std::vector<uintptr_t>& locations,
+ std::vector<uint8_t>* buffer) {
+ buffer->reserve(buffer->size() + locations.size() * 2); // guess 2 bytes per ULEB128.
+ uintptr_t address = 0; // relative to start of section.
+ for (uintptr_t location : locations) {
+ DCHECK_GE(location, address) << "Patch locations are not in sorted order";
+ EncodeUnsignedLeb128(buffer, dchecked_integral_cast<uint32_t>(location - address));
+ address = location;
}
- buffer->push_back(0); // End of sections.
}
class RodataWriter FINAL : public CodeOutput {
@@ -175,7 +157,7 @@
// Add debug sections.
// They are stack allocated here (in the same scope as the builder),
- // but they are registred with the builder only if they are used.
+ // but they are registered with the builder only if they are used.
using RawSection = typename ElfBuilder<ElfTypes>::RawSection;
const auto* text = builder->GetText();
const bool is64bit = Is64BitInstructionSet(isa);
@@ -190,12 +172,15 @@
is64bit ? Patch<Elf_Addr, uint64_t, kAbsoluteAddress> :
Patch<Elf_Addr, uint32_t, kAbsoluteAddress>,
text);
+ RawSection debug_frame_oat_patches(".debug_frame.oat_patches", SHT_OAT_PATCH);
RawSection debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0,
Patch<Elf_Addr, uint32_t, kAbsoluteAddress>, text);
- RawSection debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- RawSection debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ RawSection debug_info_oat_patches(".debug_info.oat_patches", SHT_OAT_PATCH);
+ RawSection debug_abbrev(".debug_abbrev", SHT_PROGBITS);
+ RawSection debug_str(".debug_str", SHT_PROGBITS);
RawSection debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0,
Patch<Elf_Addr, uint32_t, kAbsoluteAddress>, text);
+ RawSection debug_line_oat_patches(".debug_line.oat_patches", SHT_OAT_PATCH);
if (!oat_writer->GetMethodDebugInfo().empty()) {
if (compiler_driver_->GetCompilerOptions().GetIncludeCFI()) {
if (kCFIFormat == dwarf::DW_EH_FRAME_FORMAT) {
@@ -214,8 +199,9 @@
debug_frame.GetBuffer(), debug_frame.GetPatchLocations(),
nullptr, nullptr);
builder->RegisterSection(&debug_frame);
- *oat_writer->GetAbsolutePatchLocationsFor(".debug_frame") =
- *debug_frame.GetPatchLocations();
+ EncodeOatPatches(*debug_frame.GetPatchLocations(),
+ debug_frame_oat_patches.GetBuffer());
+ builder->RegisterSection(&debug_frame_oat_patches);
}
}
if (compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
@@ -229,24 +215,26 @@
debug_str.GetBuffer(),
debug_line.GetBuffer(), debug_line.GetPatchLocations());
builder->RegisterSection(&debug_info);
+ EncodeOatPatches(*debug_info.GetPatchLocations(),
+ debug_info_oat_patches.GetBuffer());
+ builder->RegisterSection(&debug_info_oat_patches);
builder->RegisterSection(&debug_abbrev);
builder->RegisterSection(&debug_str);
builder->RegisterSection(&debug_line);
- *oat_writer->GetAbsolutePatchLocationsFor(".debug_info") =
- *debug_info.GetPatchLocations();
- *oat_writer->GetAbsolutePatchLocationsFor(".debug_line") =
- *debug_line.GetPatchLocations();
+ EncodeOatPatches(*debug_line.GetPatchLocations(),
+ debug_line_oat_patches.GetBuffer());
+ builder->RegisterSection(&debug_line_oat_patches);
}
}
- // Add relocation section.
- RawSection oat_patches(".oat_patches", SHT_OAT_PATCH, 0, nullptr, 0, 1, 0);
- 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()) {
- EncodeOatPatches(oat_writer->GetAbsolutePatchLocations(), oat_patches.GetBuffer());
- builder->RegisterSection(&oat_patches);
+ // Add relocation section for .text.
+ RawSection text_oat_patches(".text.oat_patches", SHT_OAT_PATCH);
+ if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation()) {
+ // Note that ElfWriter::Fixup will be called regardless and therefore
+ // we need to include oat_patches for debug sections unconditionally.
+ EncodeOatPatches(oat_writer->GetAbsolutePatchLocations(),
+ text_oat_patches.GetBuffer());
+ builder->RegisterSection(&text_oat_patches);
}
return builder->Write(elf_file_);