Add binary search table to .eh_frame_hdr

The addresses in the search table must be relative to the start
of .eh_frame_hdr which results in yet another pointer type to patch.
I have moved the Patch method back to elf_writer_quick where
it can be specialized to one of the three pointer types.

The .eh_frame_hdr takes around 17% of .eh_frame now.

Change-Id: I4770d1355ded6cdff9489c33380f6b06c4e3f9fe
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 60f4d07..79f9955 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -107,12 +107,43 @@
   OatWriter* oat_writer_;
 };
 
+enum PatchResult {
+  kAbsoluteAddress,  // Absolute memory location.
+  kPointerRelativeAddress,  // Offset relative to the location of the pointer.
+  kSectionRelativeAddress,  // Offset relative to start of containing section.
+};
+
+// Patch memory addresses within a buffer.
+// It assumes that the unpatched addresses are offsets relative to base_address.
+// (which generally means method's low_pc relative to the start of .text)
+template <typename Elf_Addr, typename Address, PatchResult kPatchResult>
+static void Patch(const std::vector<uintptr_t>& patch_locations,
+                  Elf_Addr buffer_address, Elf_Addr base_address,
+                  std::vector<uint8_t>* buffer) {
+  for (uintptr_t location : patch_locations) {
+    typedef __attribute__((__aligned__(1))) Address UnalignedAddress;
+    auto* to_patch = reinterpret_cast<UnalignedAddress*>(buffer->data() + location);
+    switch (kPatchResult) {
+      case kAbsoluteAddress:
+        *to_patch = (base_address + *to_patch);
+        break;
+      case kPointerRelativeAddress:
+        *to_patch = (base_address + *to_patch) - (buffer_address + location);
+        break;
+      case kSectionRelativeAddress:
+        *to_patch = (base_address + *to_patch) - buffer_address;
+        break;
+    }
+  }
+}
+
 template <typename ElfTypes>
 bool ElfWriterQuick<ElfTypes>::Write(
     OatWriter* oat_writer,
     const std::vector<const DexFile*>& dex_files_unused ATTRIBUTE_UNUSED,
     const std::string& android_root_unused ATTRIBUTE_UNUSED,
     bool is_host_unused ATTRIBUTE_UNUSED) {
+  using Elf_Addr = typename ElfTypes::Addr;
   const InstructionSet isa = compiler_driver_->GetInstructionSet();
 
   // Setup the builder with the main OAT sections (.rodata .text .bss).
@@ -129,27 +160,25 @@
   // but they are registred with the builder only if they are used.
   using RawSection = typename ElfBuilder<ElfTypes>::RawSection;
   const auto* text = builder->GetText();
-  constexpr bool absolute = false;  // patch to make absolute addresses.
-  constexpr bool relative = true;  // patch to make relative addresses.
   const bool is64bit = Is64BitInstructionSet(isa);
-  RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC,
-                      nullptr, 0, kPageSize, 0, text, relative, is64bit);
-  RawSection eh_frame_hdr(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC,
-                          nullptr, 0, 4, 0);
-  RawSection debug_info(".debug_info", SHT_PROGBITS, 0,
-                        nullptr, 0, 1, 0, text, absolute, false /* 32bit */);
-  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_line(".debug_line", SHT_PROGBITS, 0,
-                        nullptr, 0, 1, 0, text, absolute, false /* 32bit */);
+  RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0,
+                      is64bit ? Patch<Elf_Addr, uint64_t, kPointerRelativeAddress> :
+                                Patch<Elf_Addr, uint32_t, kPointerRelativeAddress>,
+                      text);
+  RawSection eh_frame_hdr(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0,
+                          Patch<Elf_Addr, uint32_t, kSectionRelativeAddress>, text);
+  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_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0,
+                        Patch<Elf_Addr, uint32_t, kAbsoluteAddress>, text);
   if (!oat_writer->GetMethodDebugInfo().empty()) {
     if (compiler_driver_->GetCompilerOptions().GetIncludeCFI()) {
       dwarf::WriteEhFrame(
           compiler_driver_, oat_writer, dwarf::DW_EH_PE_pcrel,
           eh_frame.GetBuffer(), eh_frame.GetPatchLocations(),
-          eh_frame_hdr.GetBuffer());
+          eh_frame_hdr.GetBuffer(), eh_frame_hdr.GetPatchLocations());
       builder->RegisterSection(&eh_frame);
       builder->RegisterSection(&eh_frame_hdr);
     }