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
diff --git a/compiler/cfi_test.h b/compiler/cfi_test.h
index 9181792..cdb1b9e 100644
--- a/compiler/cfi_test.h
+++ b/compiler/cfi_test.h
@@ -46,7 +46,9 @@
constexpr bool is64bit = false;
dwarf::DebugFrameOpCodeWriter<> initial_opcodes;
dwarf::WriteEhFrameCIE(is64bit, dwarf::Reg(8), initial_opcodes, &eh_frame_data_);
- dwarf::WriteEhFrameFDE(is64bit, 0, 0, actual_asm.size(), &actual_cfi, &eh_frame_data_);
+ std::vector<uintptr_t> eh_frame_patches;
+ dwarf::WriteEhFrameFDE(is64bit, 0, 0, actual_asm.size(), &actual_cfi,
+ &eh_frame_data_, &eh_frame_patches);
ReformatCfi(Objdump(false, "-W"), &lines);
// Pretty-print assembly.
auto* opts = new DisassemblerOptions(false, actual_asm.data(), true);
diff --git a/compiler/dwarf/debug_info_entry_writer.h b/compiler/dwarf/debug_info_entry_writer.h
index c0350b6..a2c9f5f 100644
--- a/compiler/dwarf/debug_info_entry_writer.h
+++ b/compiler/dwarf/debug_info_entry_writer.h
@@ -17,6 +17,7 @@
#ifndef ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
#define ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
+#include <cstdint>
#include <unordered_map>
#include "dwarf.h"
@@ -88,6 +89,7 @@
void WriteAddr(Attribute attrib, uint64_t value) {
AddAbbrevAttribute(attrib, DW_FORM_addr);
+ patch_locations_.push_back(this->data()->size());
if (is64bit_) {
this->PushUint64(value);
} else {
@@ -168,7 +170,11 @@
this->PushUint32(address);
}
- bool is64bit() const { return is64bit_; }
+ bool Is64bit() const { return is64bit_; }
+
+ const std::vector<uintptr_t>& GetPatchLocations() const {
+ return patch_locations_;
+ }
using Writer<Allocator>::data;
@@ -240,6 +246,7 @@
size_t abbrev_code_offset_ = 0; // Location to patch once we know the code.
bool inside_entry_ = false; // Entry ends at first child (if any).
bool has_children = true;
+ std::vector<uintptr_t> patch_locations_;
};
} // namespace dwarf
diff --git a/compiler/dwarf/debug_line_opcode_writer.h b/compiler/dwarf/debug_line_opcode_writer.h
index f34acee..77ed154 100644
--- a/compiler/dwarf/debug_line_opcode_writer.h
+++ b/compiler/dwarf/debug_line_opcode_writer.h
@@ -17,6 +17,8 @@
#ifndef ART_COMPILER_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
#define ART_COMPILER_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
+#include <cstdint>
+
#include "dwarf.h"
#include "writer.h"
@@ -119,10 +121,12 @@
if (use_64bit_address_) {
this->PushUleb128(1 + 8);
this->PushUint8(DW_LNE_set_address);
+ patch_locations_.push_back(this->data()->size());
this->PushUint64(absolute_address);
} else {
this->PushUleb128(1 + 4);
this->PushUint8(DW_LNE_set_address);
+ patch_locations_.push_back(this->data()->size());
this->PushUint32(absolute_address);
}
current_address_ = absolute_address;
@@ -204,6 +208,10 @@
return current_line_;
}
+ const std::vector<uintptr_t>& GetPatchLocations() const {
+ return patch_locations_;
+ }
+
using Writer<Allocator>::data;
DebugLineOpCodeWriter(bool use64bitAddress,
@@ -233,6 +241,7 @@
uint64_t current_address_;
int current_file_;
int current_line_;
+ std::vector<uintptr_t> patch_locations_;
DISALLOW_COPY_AND_ASSIGN(DebugLineOpCodeWriter);
};
diff --git a/compiler/dwarf/dwarf_test.cc b/compiler/dwarf/dwarf_test.cc
index ec18e96..fa12d7e 100644
--- a/compiler/dwarf/dwarf_test.cc
+++ b/compiler/dwarf/dwarf_test.cc
@@ -120,19 +120,27 @@
DebugFrameOpCodeWriter<> initial_opcodes;
WriteEhFrameCIE(is64bit, Reg(is64bit ? 16 : 8), initial_opcodes, &eh_frame_data_);
- WriteEhFrameFDE(is64bit, 0, 0x01000000, 0x01000000, opcodes.data(), &eh_frame_data_);
+ std::vector<uintptr_t> eh_frame_patches;
+ std::vector<uintptr_t> expected_patches { 28 }; // NOLINT
+ WriteEhFrameFDE(is64bit, 0, 0x01000000, 0x01000000, opcodes.data(),
+ &eh_frame_data_, &eh_frame_patches);
+
+ EXPECT_EQ(expected_patches, eh_frame_patches);
CheckObjdumpOutput(is64bit, "-W");
}
-// TODO: objdump seems to have trouble with 64bit CIE length.
-TEST_F(DwarfTest, DISABLED_DebugFrame64) {
+TEST_F(DwarfTest, DebugFrame64) {
constexpr bool is64bit = true;
DebugFrameOpCodeWriter<> initial_opcodes;
WriteEhFrameCIE(is64bit, Reg(16), initial_opcodes, &eh_frame_data_);
DebugFrameOpCodeWriter<> opcodes;
+ std::vector<uintptr_t> eh_frame_patches;
+ std::vector<uintptr_t> expected_patches { 32 }; // NOLINT
WriteEhFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000,
- opcodes.data(), &eh_frame_data_);
+ opcodes.data(), &eh_frame_data_, &eh_frame_patches);
DW_CHECK("FDE cie=00000000 pc=100000000000000..300000000000000");
+
+ EXPECT_EQ(expected_patches, eh_frame_patches);
CheckObjdumpOutput(is64bit, "-W");
}
@@ -184,7 +192,12 @@
DW_CHECK_NEXT("Entry\tDir\tTime\tSize\tName");
DW_CHECK_NEXT("1\t0\t1000\t2000\tfile.c");
- WriteDebugLineTable(include_directories, files, opcodes, &debug_line_data_);
+ std::vector<uintptr_t> debug_line_patches;
+ std::vector<uintptr_t> expected_patches { 87 }; // NOLINT
+ WriteDebugLineTable(include_directories, files, opcodes,
+ &debug_line_data_, &debug_line_patches);
+
+ EXPECT_EQ(expected_patches, debug_line_patches);
CheckObjdumpOutput(is64bit, "-W");
}
@@ -219,7 +232,10 @@
std::vector<std::string> directories;
std::vector<FileEntry> files { { "file.c", 0, 1000, 2000 } }; // NOLINT
- WriteDebugLineTable(directories, files, opcodes, &debug_line_data_);
+ std::vector<uintptr_t> debug_line_patches;
+ WriteDebugLineTable(directories, files, opcodes,
+ &debug_line_data_, &debug_line_patches);
+
CheckObjdumpOutput(is64bit, "-W -WL");
}
@@ -271,7 +287,12 @@
DW_CHECK_NEXT("DW_AT_high_pc DW_FORM_addr");
DW_CHECK("3 DW_TAG_compile_unit [has children]");
- dwarf::WriteDebugInfoCU(0 /* debug_abbrev_offset */, info, &debug_info_data_);
+ std::vector<uintptr_t> debug_info_patches;
+ std::vector<uintptr_t> expected_patches { 16, 20, 29, 33, 42, 46 }; // NOLINT
+ dwarf::WriteDebugInfoCU(0 /* debug_abbrev_offset */, info,
+ &debug_info_data_, &debug_info_patches);
+
+ EXPECT_EQ(expected_patches, debug_info_patches);
CheckObjdumpOutput(is64bit, "-W");
}
diff --git a/compiler/dwarf/headers.h b/compiler/dwarf/headers.h
index d866b91..d17d327 100644
--- a/compiler/dwarf/headers.h
+++ b/compiler/dwarf/headers.h
@@ -17,6 +17,8 @@
#ifndef ART_COMPILER_DWARF_HEADERS_H_
#define ART_COMPILER_DWARF_HEADERS_H_
+#include <cstdint>
+
#include "debug_frame_opcode_writer.h"
#include "debug_info_entry_writer.h"
#include "debug_line_opcode_writer.h"
@@ -26,6 +28,12 @@
namespace art {
namespace dwarf {
+// Note that all headers start with 32-bit length.
+// DWARF also supports 64-bit lengths, but we never use that.
+// It is intended to support very large debug sections (>4GB),
+// and compilers are expected *not* to use it by default.
+// In particular, it is not related to machine architecture.
+
// Write common information entry (CIE) to .eh_frame section.
template<typename Allocator>
void WriteEhFrameCIE(bool is64bit, Reg return_address_register,
@@ -33,15 +41,8 @@
std::vector<uint8_t>* eh_frame) {
Writer<> writer(eh_frame);
size_t cie_header_start_ = writer.data()->size();
- if (is64bit) {
- // TODO: This is not related to being 64bit.
- writer.PushUint32(0xffffffff);
- writer.PushUint64(0); // Length placeholder.
- writer.PushUint64(0); // CIE id.
- } else {
- writer.PushUint32(0); // Length placeholder.
- writer.PushUint32(0); // CIE id.
- }
+ writer.PushUint32(0); // Length placeholder.
+ writer.PushUint32(0); // CIE id.
writer.PushUint8(1); // Version.
writer.PushString("zR");
writer.PushUleb128(DebugFrameOpCodeWriter<Allocator>::kCodeAlignmentFactor);
@@ -55,11 +56,7 @@
}
writer.PushData(opcodes.data());
writer.Pad(is64bit ? 8 : 4);
- if (is64bit) {
- writer.UpdateUint64(cie_header_start_ + 4, writer.data()->size() - cie_header_start_ - 12);
- } else {
- writer.UpdateUint32(cie_header_start_, writer.data()->size() - cie_header_start_ - 4);
- }
+ writer.UpdateUint32(cie_header_start_, writer.data()->size() - cie_header_start_ - 4);
}
// Write frame description entry (FDE) to .eh_frame section.
@@ -67,20 +64,15 @@
void WriteEhFrameFDE(bool is64bit, size_t cie_offset,
uint64_t initial_address, uint64_t address_range,
const std::vector<uint8_t, Allocator>* opcodes,
- std::vector<uint8_t>* eh_frame) {
+ std::vector<uint8_t>* eh_frame,
+ std::vector<uintptr_t>* eh_frame_patches) {
Writer<> writer(eh_frame);
size_t fde_header_start = writer.data()->size();
- if (is64bit) {
- // TODO: This is not related to being 64bit.
- writer.PushUint32(0xffffffff);
- writer.PushUint64(0); // Length placeholder.
- uint64_t cie_pointer = writer.data()->size() - cie_offset;
- writer.PushUint64(cie_pointer);
- } else {
- writer.PushUint32(0); // Length placeholder.
- uint32_t cie_pointer = writer.data()->size() - cie_offset;
- writer.PushUint32(cie_pointer);
- }
+ writer.PushUint32(0); // Length placeholder.
+ uint32_t cie_pointer = writer.data()->size() - cie_offset;
+ writer.PushUint32(cie_pointer);
+ // Relocate initial_address, but not address_range (it is size).
+ eh_frame_patches->push_back(writer.data()->size());
if (is64bit) {
writer.PushUint64(initial_address);
writer.PushUint64(address_range);
@@ -91,26 +83,28 @@
writer.PushUleb128(0); // Augmentation data size.
writer.PushData(opcodes);
writer.Pad(is64bit ? 8 : 4);
- if (is64bit) {
- writer.UpdateUint64(fde_header_start + 4, writer.data()->size() - fde_header_start - 12);
- } else {
- writer.UpdateUint32(fde_header_start, writer.data()->size() - fde_header_start - 4);
- }
+ writer.UpdateUint32(fde_header_start, writer.data()->size() - fde_header_start - 4);
}
// Write compilation unit (CU) to .debug_info section.
template<typename Allocator>
void WriteDebugInfoCU(uint32_t debug_abbrev_offset,
const DebugInfoEntryWriter<Allocator>& entries,
- std::vector<uint8_t>* debug_info) {
+ std::vector<uint8_t>* debug_info,
+ std::vector<uintptr_t>* debug_info_patches) {
Writer<> writer(debug_info);
size_t start = writer.data()->size();
writer.PushUint32(0); // Length placeholder.
writer.PushUint16(3); // Version.
writer.PushUint32(debug_abbrev_offset);
- writer.PushUint8(entries.is64bit() ? 8 : 4);
+ writer.PushUint8(entries.Is64bit() ? 8 : 4);
+ size_t entries_offset = writer.data()->size();
writer.PushData(entries.data());
writer.UpdateUint32(start, writer.data()->size() - start - 4);
+ // Copy patch locations and make them relative to .debug_info section.
+ for (uintptr_t patch_location : entries.GetPatchLocations()) {
+ debug_info_patches->push_back(entries_offset + patch_location);
+ }
}
struct FileEntry {
@@ -125,7 +119,8 @@
void WriteDebugLineTable(const std::vector<std::string>& include_directories,
const std::vector<FileEntry>& files,
const DebugLineOpCodeWriter<Allocator>& opcodes,
- std::vector<uint8_t>* debug_line) {
+ std::vector<uint8_t>* debug_line,
+ std::vector<uintptr_t>* debug_line_patches) {
Writer<> writer(debug_line);
size_t header_start = writer.data()->size();
writer.PushUint32(0); // Section-length placeholder.
@@ -157,8 +152,13 @@
}
writer.PushUint8(0); // Terminate file list.
writer.UpdateUint32(header_length_pos, writer.data()->size() - header_length_pos - 4);
- writer.PushData(opcodes.data()->data(), opcodes.data()->size());
+ size_t opcodes_offset = writer.data()->size();
+ writer.PushData(opcodes.data());
writer.UpdateUint32(header_start, writer.data()->size() - header_start - 4);
+ // Copy patch locations and make them relative to .debug_line section.
+ for (uintptr_t patch_location : opcodes.GetPatchLocations()) {
+ debug_line_patches->push_back(opcodes_offset + patch_location);
+ }
}
} // namespace dwarf
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index 5e8e24b..6df5ea9 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -159,7 +159,7 @@
* @param debug_line Line number table.
*/
void WriteDebugSections(const CompilerDriver* compiler,
- const OatWriter* oat_writer,
+ OatWriter* oat_writer,
uint32_t text_section_offset,
std::vector<uint8_t>* eh_frame,
std::vector<uint8_t>* debug_info,
@@ -176,6 +176,7 @@
}
// Write .eh_frame section.
+ auto* eh_frame_patches = oat_writer->GetAbsolutePatchLocationsFor(".eh_frame");
size_t cie_offset = eh_frame->size();
WriteEhFrameCIE(isa, eh_frame);
for (const OatWriter::DebugInfo& mi : method_infos) {
@@ -183,7 +184,7 @@
if (opcodes != nullptr) {
WriteEhFrameFDE(Is64BitInstructionSet(isa), cie_offset,
text_section_offset + mi.low_pc_, mi.high_pc_ - mi.low_pc_,
- opcodes, eh_frame);
+ opcodes, eh_frame, eh_frame_patches);
}
}
@@ -211,7 +212,8 @@
info.EndTag(); // DW_TAG_subprogram
}
info.EndTag(); // DW_TAG_compile_unit
- WriteDebugInfoCU(debug_abbrev_offset, info, debug_info);
+ auto* debug_info_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_info");
+ WriteDebugInfoCU(debug_abbrev_offset, info, debug_info, debug_info_patches);
// TODO: in gdb info functions <regexp> - reports Java functions, but
// source file is <unknown> because .debug_line is formed as one
@@ -353,7 +355,8 @@
}
opcodes.AdvancePC(text_section_offset + cunit_high_pc);
opcodes.EndSequence();
- WriteDebugLineTable(directories, files, opcodes, debug_line);
+ auto* debug_line_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_line");
+ WriteDebugLineTable(directories, files, opcodes, debug_line, debug_line_patches);
}
} // namespace dwarf
diff --git a/compiler/elf_writer_debug.h b/compiler/elf_writer_debug.h
index 39a99d6..4f1e333 100644
--- a/compiler/elf_writer_debug.h
+++ b/compiler/elf_writer_debug.h
@@ -25,7 +25,7 @@
namespace dwarf {
void WriteDebugSections(const CompilerDriver* compiler,
- const OatWriter* oat_writer,
+ OatWriter* oat_writer,
uint32_t text_section_offset,
std::vector<uint8_t>* eh_frame_data,
std::vector<uint8_t>* debug_info_data,
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index e9af25f..da1f81a 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -74,6 +74,40 @@
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 @@
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);
}
diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h
index 4990ed0..811beb4 100644
--- a/compiler/elf_writer_quick.h
+++ b/compiler/elf_writer_quick.h
@@ -19,6 +19,7 @@
#include "elf_utils.h"
#include "elf_writer.h"
+#include "oat_writer.h"
namespace art {
@@ -36,6 +37,9 @@
const CompilerDriver& driver)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static void EncodeOatPatches(const OatWriter::PatchLocationsMap& sections,
+ std::vector<uint8_t>* buffer);
+
protected:
bool Write(OatWriter* oat_writer,
const std::vector<const DexFile*>& dex_files,
diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc
index 8e2d175..3e5ad7b 100644
--- a/compiler/elf_writer_test.cc
+++ b/compiler/elf_writer_test.cc
@@ -19,6 +19,9 @@
#include "base/stringprintf.h"
#include "base/unix_file/fd_file.h"
#include "common_compiler_test.h"
+#include "elf_file.h"
+#include "elf_file_impl.h"
+#include "elf_writer_quick.h"
#include "oat.h"
#include "utils.h"
@@ -85,4 +88,73 @@
}
}
+// Run only on host since we do unaligned memory accesses.
+#ifndef HAVE_ANDROID_OS
+
+static void PatchSection(const std::vector<uintptr_t>& patch_locations,
+ std::vector<uint8_t>* section, int32_t delta) {
+ for (uintptr_t location : patch_locations) {
+ *reinterpret_cast<int32_t*>(section->data() + location) += delta;
+ }
+}
+
+TEST_F(ElfWriterTest, EncodeDecodeOatPatches) {
+ std::vector<uint8_t> oat_patches; // Encoded patches.
+
+ // Encode patch locations for a few sections.
+ OatWriter::PatchLocationsMap sections;
+ std::vector<uintptr_t> patches0 { 0, 4, 8, 15, 128, 200 }; // NOLINT
+ sections.emplace(".section0", std::unique_ptr<std::vector<uintptr_t>>(
+ new std::vector<uintptr_t> { patches0 }));
+ std::vector<uintptr_t> patches1 { 8, 127 }; // NOLINT
+ sections.emplace(".section1", std::unique_ptr<std::vector<uintptr_t>>(
+ new std::vector<uintptr_t> { patches1 }));
+ std::vector<uintptr_t> patches2 { }; // NOLINT
+ sections.emplace(".section2", std::unique_ptr<std::vector<uintptr_t>>(
+ new std::vector<uintptr_t> { patches2 }));
+ ElfWriterQuick32::EncodeOatPatches(sections, &oat_patches);
+
+ // Create buffers to be patched.
+ std::vector<uint8_t> initial_data(256);
+ for (size_t i = 0; i < initial_data.size(); i++) {
+ initial_data[i] = i;
+ }
+ std::vector<uint8_t> section0_expected = initial_data;
+ std::vector<uint8_t> section1_expected = initial_data;
+ std::vector<uint8_t> section2_expected = initial_data;
+ std::vector<uint8_t> section0_actual = initial_data;
+ std::vector<uint8_t> section1_actual = initial_data;
+ std::vector<uint8_t> section2_actual = initial_data;
+
+ // Patch manually.
+ constexpr int32_t delta = 0x11235813;
+ PatchSection(patches0, §ion0_expected, delta);
+ PatchSection(patches1, §ion1_expected, delta);
+ PatchSection(patches2, §ion2_expected, delta);
+
+ // Decode and apply patch locations.
+ bool section0_successful = ElfFileImpl32::ApplyOatPatches(
+ oat_patches.data(), oat_patches.data() + oat_patches.size(),
+ ".section0", delta,
+ section0_actual.data(), section0_actual.data() + section0_actual.size());
+ EXPECT_TRUE(section0_successful);
+ EXPECT_EQ(section0_expected, section0_actual);
+
+ bool section1_successful = ElfFileImpl32::ApplyOatPatches(
+ oat_patches.data(), oat_patches.data() + oat_patches.size(),
+ ".section1", delta,
+ section1_actual.data(), section1_actual.data() + section1_actual.size());
+ EXPECT_TRUE(section1_successful);
+ EXPECT_EQ(section1_expected, section1_actual);
+
+ bool section2_successful = ElfFileImpl32::ApplyOatPatches(
+ oat_patches.data(), oat_patches.data() + oat_patches.size(),
+ ".section2", delta,
+ section2_actual.data(), section2_actual.data() + section2_actual.size());
+ EXPECT_TRUE(section2_successful);
+ EXPECT_EQ(section2_expected, section2_actual);
+}
+
+#endif
+
} // namespace art
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 5b4cc54..62c9836 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -350,7 +350,8 @@
public:
InitCodeMethodVisitor(OatWriter* writer, size_t offset)
: OatDexMethodVisitor(writer, offset) {
- writer_->absolute_patch_locations_.reserve(
+ text_absolute_patch_locations_ = writer->GetAbsolutePatchLocationsFor(".text");
+ text_absolute_patch_locations_->reserve(
writer_->compiler_driver_->GetNonRelativeLinkerPatchCount());
}
@@ -442,7 +443,7 @@
uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
for (const LinkerPatch& patch : compiled_method->GetPatches()) {
if (!patch.IsPcRelative()) {
- writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
+ text_absolute_patch_locations_->push_back(base_loc + patch.LiteralOffset());
}
}
}
@@ -532,6 +533,9 @@
// Deduplication is already done on a pointer basis by the compiler driver,
// so we can simply compare the pointers to find out if things are duplicated.
SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
+
+ // Patch locations for the .text section.
+ std::vector<uintptr_t>* text_absolute_patch_locations_;
};
template <typename DataAccess>
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 51bc9b4..cc2b39a 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <cstddef>
+#include <map>
#include <memory>
#include "linker/relative_patcher.h" // For linker::RelativePatcherTargetProvider.
@@ -81,6 +82,8 @@
//
class OatWriter {
public:
+ typedef std::map<std::string, std::unique_ptr<std::vector<uintptr_t>>> PatchLocationsMap;
+
OatWriter(const std::vector<const DexFile*>& dex_files,
uint32_t image_file_location_oat_checksum,
uintptr_t image_file_location_oat_begin,
@@ -102,10 +105,19 @@
return bss_size_;
}
- const std::vector<uintptr_t>& GetAbsolutePatchLocations() const {
+ const PatchLocationsMap& GetAbsolutePatchLocations() const {
return absolute_patch_locations_;
}
+ std::vector<uintptr_t>* GetAbsolutePatchLocationsFor(const char* section_name) {
+ auto it = absolute_patch_locations_.emplace(
+ std::string(section_name), std::unique_ptr<std::vector<uintptr_t>>());
+ if (it.second) { // Inserted new item.
+ it.first->second.reset(new std::vector<uintptr_t>());
+ }
+ return it.first->second.get();
+ }
+
void SetOatDataOffset(size_t oat_data_offset) {
oat_data_offset_ = oat_data_offset;
}
@@ -330,8 +342,9 @@
std::unique_ptr<linker::RelativePatcher> relative_patcher_;
- // The locations of absolute patches relative to the start of the executable section.
- std::vector<uintptr_t> absolute_patch_locations_;
+ // The locations of absolute patches relative to the start of section.
+ // The map's key is the ELF's section name (including the dot).
+ PatchLocationsMap absolute_patch_locations_;
// Map method reference to assigned offset.
// Wrap the map in a class implementing linker::RelativePatcherTargetProvider.