patched_(false), patch_(patch), patch_base_section_(patch_base_section) {
}
+ RawSection(const std::string& name, Elf_Word type)
+ : RawSection(name, type, 0, nullptr, 0, 1, 0, nullptr, nullptr) {
+ }
+
Elf_Word GetSize() const OVERRIDE {
return buffer_.size();
}
template<typename T>
static bool WriteArray(File* elf_file, const T* data, size_t count) {
- DCHECK(data != nullptr);
- if (!elf_file->WriteFully(data, count * sizeof(T))) {
- PLOG(ERROR) << "Failed to write to file " << elf_file->GetPath();
- return false;
+ if (count != 0) {
+ DCHECK(data != nullptr);
+ if (!elf_file->WriteFully(data, count * sizeof(T))) {
+ PLOG(ERROR) << "Failed to write to file " << elf_file->GetPath();
+ return false;
+ }
}
return true;
}
#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"
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 {
// 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);
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) {
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()) {
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_);
const CompilerDriver& driver)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static void EncodeOatPatches(const OatWriter::PatchLocationsMap& sections,
+ static void EncodeOatPatches(const std::vector<uintptr_t>& locations,
std::vector<uint8_t>* buffer);
protected:
}
}
-// 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;
+ const std::vector<std::vector<uintptr_t>> test_data {
+ { 0, 4, 8, 15, 128, 200 },
+ { 8, 8 + 127 },
+ { 8, 8 + 128 },
+ { },
+ };
+ for (const auto& patch_locations : test_data) {
+ constexpr int32_t delta = 0x11235813;
+
+ // Encode patch locations.
+ std::vector<uint8_t> oat_patches;
+ ElfWriterQuick32::EncodeOatPatches(patch_locations, &oat_patches);
+
+ // Create buffer to be patched.
+ std::vector<uint8_t> initial_data(256);
+ for (size_t i = 0; i < initial_data.size(); i++) {
+ initial_data[i] = i;
+ }
+
+ // Patch manually.
+ std::vector<uint8_t> expected = initial_data;
+ for (uintptr_t location : patch_locations) {
+ typedef __attribute__((__aligned__(1))) uint32_t UnalignedAddress;
+ *reinterpret_cast<UnalignedAddress*>(expected.data() + location) += delta;
+ }
+
+ // Decode and apply patch locations.
+ std::vector<uint8_t> actual = initial_data;
+ ElfFileImpl32::ApplyOatPatches(
+ oat_patches.data(), oat_patches.data() + oat_patches.size(), delta,
+ actual.data(), actual.data() + actual.size());
+
+ EXPECT_EQ(expected, actual);
}
- 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
public:
InitCodeMethodVisitor(OatWriter* writer, size_t offset)
: OatDexMethodVisitor(writer, offset),
- text_absolute_patch_locations_(writer->GetAbsolutePatchLocationsFor(".text")),
debuggable_(writer->GetCompilerDriver()->GetCompilerOptions().GetDebuggable()) {
- text_absolute_patch_locations_->reserve(
+ writer_->absolute_patch_locations_.reserve(
writer_->compiler_driver_->GetNonRelativeLinkerPatchCount());
}
uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
for (const LinkerPatch& patch : compiled_method->GetPatches()) {
if (!patch.IsPcRelative()) {
- text_absolute_patch_locations_->push_back(base_loc + patch.LiteralOffset());
+ writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
}
}
}
// 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>* const text_absolute_patch_locations_;
-
// Cache of compiler's --debuggable option.
const bool debuggable_;
};
#include <stdint.h>
#include <cstddef>
-#include <map>
#include <memory>
#include "linker/relative_patcher.h" // For linker::RelativePatcherTargetProvider.
//
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,
return bss_size_;
}
- const PatchLocationsMap& GetAbsolutePatchLocations() const {
+ const std::vector<uintptr_t>& 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();
- }
-
bool WriteRodata(OutputStream* out);
bool WriteCode(OutputStream* out);
std::unique_ptr<linker::RelativePatcher> relative_patcher_;
- // 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_;
+ // The locations of absolute patches relative to the start of the executable section.
+ std::vector<uintptr_t> absolute_patch_locations_;
// Map method reference to assigned offset.
// Wrap the map in a class implementing linker::RelativePatcherTargetProvider.
}
template <typename ElfTypes>
-bool ElfFileImpl<ElfTypes>::FixupDebugSections(typename std::make_signed<Elf_Off>::type base_address_delta) {
+bool ElfFileImpl<ElfTypes>::FixupDebugSections(Elf_Addr base_address_delta) {
if (base_address_delta == 0) {
return true;
}
- if (FindSectionByName(".debug_frame") != nullptr) {
- if (!ApplyOatPatchesTo(".debug_frame", base_address_delta)) {
- return false;
- }
- }
- if (FindSectionByName(".debug_info") != nullptr) {
- if (!ApplyOatPatchesTo(".debug_info", base_address_delta)) {
- return false;
- }
- }
- if (FindSectionByName(".debug_line") != nullptr) {
- if (!ApplyOatPatchesTo(".debug_line", base_address_delta)) {
- return false;
- }
- }
- return true;
+ return ApplyOatPatchesTo(".debug_frame", base_address_delta) &&
+ ApplyOatPatchesTo(".debug_info", base_address_delta) &&
+ ApplyOatPatchesTo(".debug_line", base_address_delta);
}
template <typename ElfTypes>
bool ElfFileImpl<ElfTypes>::ApplyOatPatchesTo(
- const char* target_section_name,
- typename std::make_signed<Elf_Off>::type delta) {
- auto patches_section = FindSectionByName(".oat_patches");
+ const char* target_section_name, Elf_Addr delta) {
+ auto target_section = FindSectionByName(target_section_name);
+ if (target_section == nullptr) {
+ return true;
+ }
+ std::string patches_name = target_section_name + std::string(".oat_patches");
+ auto patches_section = FindSectionByName(patches_name.c_str());
if (patches_section == nullptr) {
- LOG(ERROR) << ".oat_patches section not found.";
+ LOG(ERROR) << patches_name << " section not found.";
return false;
}
if (patches_section->sh_type != SHT_OAT_PATCH) {
- LOG(ERROR) << "Unexpected type of .oat_patches.";
- return false;
- }
- auto target_section = FindSectionByName(target_section_name);
- if (target_section == nullptr) {
- LOG(ERROR) << target_section_name << " section not found.";
+ LOG(ERROR) << "Unexpected type of " << patches_name;
return false;
}
- if (!ApplyOatPatches(
+ ApplyOatPatches(
Begin() + patches_section->sh_offset,
Begin() + patches_section->sh_offset + patches_section->sh_size,
- target_section_name, delta,
+ delta,
Begin() + target_section->sh_offset,
- Begin() + target_section->sh_offset + target_section->sh_size)) {
- LOG(ERROR) << target_section_name << " section not found in .oat_patches.";
- }
+ Begin() + target_section->sh_offset + target_section->sh_size);
return true;
}
-// Apply .oat_patches to given section.
+// Apply LEB128 encoded patches to given section.
template <typename ElfTypes>
-bool ElfFileImpl<ElfTypes>::ApplyOatPatches(
- const uint8_t* patches, const uint8_t* patches_end,
- const char* target_section_name,
- typename std::make_signed<Elf_Off>::type delta,
+void ElfFileImpl<ElfTypes>::ApplyOatPatches(
+ const uint8_t* patches, const uint8_t* patches_end, Elf_Addr delta,
uint8_t* to_patch, const uint8_t* to_patch_end) {
- // Read null-terminated section name.
- const char* section_name;
- while ((section_name = reinterpret_cast<const char*>(patches))[0] != '\0') {
- patches += strlen(section_name) + 1;
- uint32_t length = DecodeUnsignedLeb128(&patches);
- const uint8_t* next_section = patches + length;
- // Is it the section we want to patch?
- if (strcmp(section_name, target_section_name) == 0) {
- // Read LEB128 encoded list of advances.
- while (patches < next_section) {
- DCHECK_LT(patches, patches_end) << "Unexpected end of .oat_patches.";
- to_patch += DecodeUnsignedLeb128(&patches);
- DCHECK_LT(to_patch, to_patch_end) << "Patch past the end of " << section_name;
- // TODO: 32-bit vs 64-bit. What is the right type to use here?
- auto* patch_loc = reinterpret_cast<typename std::make_signed<Elf_Off>::type*>(to_patch);
- *patch_loc += delta;
- }
- return true;
- }
- patches = next_section;
+ typedef __attribute__((__aligned__(1))) Elf_Addr UnalignedAddress;
+ while (patches < patches_end) {
+ to_patch += DecodeUnsignedLeb128(&patches);
+ DCHECK_LE(patches, patches_end) << "Unexpected end of patch list.";
+ DCHECK_LT(to_patch, to_patch_end) << "Patch past the end of section.";
+ *reinterpret_cast<UnalignedAddress*>(to_patch) += delta;
}
- return false;
}
template <typename ElfTypes>
bool FixupProgramHeaders(Elf_Addr base_address);
bool FixupSymbols(Elf_Addr base_address, bool dynamic);
bool FixupRelocations(Elf_Addr base_address);
- bool FixupDebugSections(typename std::make_signed<Elf_Off>::type base_address_delta);
- bool ApplyOatPatchesTo(const char* target_section_name,
- typename std::make_signed<Elf_Off>::type base_address_delta);
- static bool ApplyOatPatches(const uint8_t* patches, const uint8_t* patches_end,
- const char* target_section_name,
- typename std::make_signed<Elf_Off>::type delta,
+ bool FixupDebugSections(Elf_Addr base_address_delta);
+ bool ApplyOatPatchesTo(const char* target_section_name, Elf_Addr base_address_delta);
+ static void ApplyOatPatches(const uint8_t* patches, const uint8_t* patches_end, Elf_Addr delta,
uint8_t* to_patch, const uint8_t* to_patch_end);
bool Strip(std::string* error_msg);