Merge "Handlerize methods across some GC points."
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index e4be21b..55a4821 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -122,7 +122,11 @@
 endif
 
 # Clang on the target. Target builds use GCC by default.
+ifneq ($(USE_CLANG_PLATFORM_BUILD),)
+ART_TARGET_CLANG := $(USE_CLANG_PLATFORM_BUILD)
+else
 ART_TARGET_CLANG := false
+endif
 ART_TARGET_CLANG_arm :=
 ART_TARGET_CLANG_arm64 :=
 ART_TARGET_CLANG_mips :=
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 8b5e6d5..133044a 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -125,8 +125,6 @@
 	utils/scoped_arena_allocator.cc \
 	buffered_output_stream.cc \
 	compiler.cc \
-	elf_fixup.cc \
-	elf_stripper.cc \
 	elf_writer.cc \
 	elf_writer_quick.cc \
 	file_output_stream.cc \
diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc
index eb0806b..e411164 100644
--- a/compiler/dex/local_value_numbering.cc
+++ b/compiler/dex/local_value_numbering.cc
@@ -1463,14 +1463,12 @@
       // Intentional fall-through.
     case Instruction::INVOKE_STATIC:
     case Instruction::INVOKE_STATIC_RANGE:
-      if ((mir->optimization_flags & MIR_INLINED) == 0) {
-        // Make ref args aliasing.
-        for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
-          uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
-          non_aliasing_refs_.erase(reg);
-        }
-        HandleInvokeOrClInitOrAcquireOp(mir);
+      // Make ref args aliasing.
+      for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
+        uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
+        non_aliasing_refs_.erase(reg);
       }
+      HandleInvokeOrClInitOrAcquireOp(mir);
       break;
 
     case Instruction::MOVE_RESULT:
diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc
index 246ae44..51b6709 100644
--- a/compiler/dex/mir_dataflow.cc
+++ b/compiler/dex/mir_dataflow.cc
@@ -1163,7 +1163,7 @@
     if (!MIR::DecodedInstruction::IsPseudoMirOp(mir->dalvikInsn.opcode)) {
       int flags = mir->dalvikInsn.FlagsOf();
 
-      if ((flags & Instruction::kInvoke) != 0 && (mir->optimization_flags & MIR_INLINED) == 0) {
+      if ((flags & Instruction::kInvoke) != 0) {
         attributes_ &= ~METHOD_IS_LEAF;
       }
     }
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 1a4b23e..bf09446 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -845,7 +845,7 @@
   RegLocation rl_object = LoadValue(rl_src_obj, kRefReg);
   RegLocation rl_new_value;
   if (!is_long) {
-    rl_new_value = LoadValue(rl_src_new_value);
+    rl_new_value = LoadValue(rl_src_new_value, LocToRegClass(rl_src_new_value));
   } else if (load_early) {
     rl_new_value = LoadValueWide(rl_src_new_value, kCoreReg);
   }
@@ -868,7 +868,7 @@
 
   RegLocation rl_expected;
   if (!is_long) {
-    rl_expected = LoadValue(rl_src_expected);
+    rl_expected = LoadValue(rl_src_expected, LocToRegClass(rl_src_new_value));
   } else if (load_early) {
     rl_expected = LoadValueWide(rl_src_expected, kCoreReg);
   } else {
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index 88123e1..97f3994 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -925,7 +925,7 @@
 
 LIR* Arm64Mir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
   ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
-  return RawLIR(current_dalvik_offset_, WIDE(kA64Ldr2rp), reg.GetReg(), 0, 0, 0, 0, target);
+  return RawLIR(current_dalvik_offset_, kA64Ldr2rp, As32BitReg(reg).GetReg(), 0, 0, 0, 0, target);
 }
 
 LIR* Arm64Mir2Lir::OpVldm(RegStorage r_base, int count) {
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index f305017..e18116e 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -447,15 +447,16 @@
   buf.push_back((data >> 24) & 0xff);
 }
 
-// Push 8 bytes on 64-bit target systems; 4 on 32-bit target systems.
-static void PushPointer(std::vector<uint8_t>&buf, const void* pointer, bool target64) {
-  uint64_t data = reinterpret_cast<uintptr_t>(pointer);
-  if (target64) {
-    Push32(buf, data & 0xFFFFFFFF);
-    Push32(buf, (data >> 32) & 0xFFFFFFFF);
-  } else {
-    Push32(buf, static_cast<uint32_t>(data));
-  }
+/**
+ * @brief Push a compressed reference which needs patching at link/patchoat-time.
+ * @details This needs to be kept consistent with the code which actually does the patching in
+ *   oat_writer.cc and in the patchoat tool.
+ */
+static void PushUnpatchedReference(std::vector<uint8_t>&buf) {
+  // Note that we can safely initialize the patches to zero. The code deduplication mechanism takes
+  // the patches into account when determining whether two pieces of codes are functionally
+  // equivalent.
+  Push32(buf, UINT32_C(0));
 }
 
 static void AlignBuffer(std::vector<uint8_t>&buf, size_t offset) {
@@ -481,9 +482,7 @@
         reinterpret_cast<const DexFile*>(UnwrapPointer(data_lir->operands[1]));
     patches_.push_back(LinkerPatch::CodePatch(code_buffer_.size(),
                                               target_dex_file, target_method_idx));
-    const DexFile::MethodId& target_method_id = target_dex_file->GetMethodId(target_method_idx);
-    // unique value based on target to ensure code deduplication works
-    PushPointer(code_buffer_, &target_method_id, cu_->target64);
+    PushUnpatchedReference(code_buffer_);
     data_lir = NEXT_LIR(data_lir);
   }
   data_lir = method_literal_list_;
@@ -493,9 +492,7 @@
         reinterpret_cast<const DexFile*>(UnwrapPointer(data_lir->operands[1]));
     patches_.push_back(LinkerPatch::MethodPatch(code_buffer_.size(),
                                                 target_dex_file, target_method_idx));
-    const DexFile::MethodId& target_method_id = target_dex_file->GetMethodId(target_method_idx);
-    // unique value based on target to ensure code deduplication works
-    PushPointer(code_buffer_, &target_method_id, cu_->target64);
+    PushUnpatchedReference(code_buffer_);
     data_lir = NEXT_LIR(data_lir);
   }
   // Push class literals.
@@ -506,9 +503,7 @@
       reinterpret_cast<const DexFile*>(UnwrapPointer(data_lir->operands[1]));
     patches_.push_back(LinkerPatch::TypePatch(code_buffer_.size(),
                                               class_dex_file, target_type_idx));
-    const DexFile::TypeId& target_method_id = class_dex_file->GetTypeId(target_type_idx);
-    // unique value based on target to ensure code deduplication works
-    PushPointer(code_buffer_, &target_method_id, cu_->target64);
+    PushUnpatchedReference(code_buffer_);
     data_lir = NEXT_LIR(data_lir);
   }
 }
@@ -772,7 +767,9 @@
 /* Determine the offset of each literal field */
 int Mir2Lir::AssignLiteralOffset(CodeOffset offset) {
   offset = AssignLiteralOffsetCommon(literal_list_, offset);
-  unsigned int ptr_size = GetInstructionSetPointerSize(cu_->instruction_set);
+  constexpr unsigned int ptr_size = sizeof(uint32_t);
+  COMPILE_ASSERT(ptr_size >= sizeof(mirror::HeapReference<mirror::Object>),
+                 ptr_size_cannot_hold_a_heap_reference);
   offset = AssignLiteralPointerOffsetCommon(code_literal_list_, offset, ptr_size);
   offset = AssignLiteralPointerOffsetCommon(method_literal_list_, offset, ptr_size);
   offset = AssignLiteralPointerOffsetCommon(class_literal_list_, offset, ptr_size);
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 2523380..0f1d765 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -566,7 +566,6 @@
       break;
   }
   if (result) {
-    invoke->optimization_flags |= MIR_INLINED;
     // If the invoke has not been eliminated yet, check now whether we should do it.
     // This is done so that dataflow analysis does not get tripped up seeing nop invoke.
     if (static_cast<int>(invoke->dalvikInsn.opcode) != kMirOpNop) {
@@ -583,7 +582,6 @@
       }
     }
     if (move_result != nullptr) {
-      move_result->optimization_flags |= MIR_INLINED;
       move_result->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
     }
   }
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 9f7a881..3f7ecfe 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -214,9 +214,8 @@
 void Mir2Lir::GenCompareAndBranch(Instruction::Code opcode, RegLocation rl_src1,
                                   RegLocation rl_src2, LIR* taken,
                                   LIR* fall_through) {
-  DCHECK(!rl_src1.fp);
-  DCHECK(!rl_src2.fp);
   ConditionCode cond;
+  RegisterClass reg_class = (rl_src1.ref || rl_src2.ref) ? kRefReg : kCoreReg;
   switch (opcode) {
     case Instruction::IF_EQ:
       cond = kCondEq;
@@ -249,7 +248,7 @@
     cond = FlipComparisonOrder(cond);
   }
 
-  rl_src1 = LoadValue(rl_src1);
+  rl_src1 = LoadValue(rl_src1, reg_class);
   // Is this really an immediate comparison?
   if (rl_src2.is_const) {
     // If it's already live in a register or not easily materialized, just keep going
@@ -273,15 +272,15 @@
     }
   }
 
-  rl_src2 = LoadValue(rl_src2);
+  rl_src2 = LoadValue(rl_src2, reg_class);
   OpCmpBranch(cond, rl_src1.reg, rl_src2.reg, taken);
 }
 
 void Mir2Lir::GenCompareZeroAndBranch(Instruction::Code opcode, RegLocation rl_src, LIR* taken,
                                       LIR* fall_through) {
   ConditionCode cond;
-  DCHECK(!rl_src.fp);
-  rl_src = LoadValue(rl_src);
+  RegisterClass reg_class = rl_src.ref ? kRefReg : kCoreReg;
+  rl_src = LoadValue(rl_src, reg_class);
   switch (opcode) {
     case Instruction::IF_EQZ:
       cond = kCondEq;
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 67a75cb..bafb57d 100755
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -1643,7 +1643,7 @@
       FreeTemp(rl_temp_offset);
     }
   } else {
-    rl_value = LoadValue(rl_src_value);
+    rl_value = LoadValue(rl_src_value, LocToRegClass(rl_src_value));
     if (rl_value.ref) {
       StoreRefIndexed(rl_object.reg, rl_offset.reg, rl_value.reg, 0);
     } else {
@@ -1666,16 +1666,6 @@
 }
 
 void Mir2Lir::GenInvoke(CallInfo* info) {
-  if ((info->opt_flags & MIR_INLINED) != 0) {
-    // Already inlined but we may still need the null check.
-    if (info->type != kStatic &&
-        ((cu_->disable_opt & (1 << kNullCheckElimination)) != 0 ||
-         (info->opt_flags & MIR_IGNORE_NULL_CHECK) == 0))  {
-      RegLocation rl_obj = LoadValue(info->args[0], kRefReg);
-      GenNullCheck(rl_obj.reg);
-    }
-    return;
-  }
   DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
   if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file)
       ->GenIntrinsic(this, info)) {
diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc
index e5798fd..39b40a0 100644
--- a/compiler/dex/quick/gen_loadstore.cc
+++ b/compiler/dex/quick/gen_loadstore.cc
@@ -166,10 +166,6 @@
   return rl_src;
 }
 
-RegLocation Mir2Lir::LoadValue(RegLocation rl_src) {
-  return LoadValue(rl_src, LocToRegClass(rl_src));
-}
-
 void Mir2Lir::StoreValue(RegLocation rl_dest, RegLocation rl_src) {
   /*
    * Sanity checking - should never try to store to the same
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 6942c0f..e7160ad 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -500,17 +500,11 @@
       break;
 
     case Instruction::MOVE_RESULT_WIDE:
-      if ((opt_flags & MIR_INLINED) != 0) {
-        break;  // Nop - combined w/ previous invoke.
-      }
       StoreValueWide(rl_dest, GetReturnWide(LocToRegClass(rl_dest)));
       break;
 
     case Instruction::MOVE_RESULT:
     case Instruction::MOVE_RESULT_OBJECT:
-      if ((opt_flags & MIR_INLINED) != 0) {
-        break;  // Nop - combined w/ previous invoke.
-      }
       StoreValue(rl_dest, GetReturn(LocToRegClass(rl_dest)));
       break;
 
@@ -867,7 +861,7 @@
 
     case Instruction::INVOKE_STATIC_RANGE:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kStatic, true));
-      if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+      if (!kLeafOptimization) {
         // If the invocation is not inlined, we can assume there is already a
         // suspend check at the return site
         mir_graph_->AppendGenSuspendTestList(bb);
@@ -875,59 +869,59 @@
       break;
     case Instruction::INVOKE_STATIC:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kStatic, false));
-      if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+      if (!kLeafOptimization) {
         mir_graph_->AppendGenSuspendTestList(bb);
       }
       break;
 
     case Instruction::INVOKE_DIRECT:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kDirect, false));
-      if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+      if (!kLeafOptimization) {
         mir_graph_->AppendGenSuspendTestList(bb);
       }
       break;
     case Instruction::INVOKE_DIRECT_RANGE:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kDirect, true));
-      if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+      if (!kLeafOptimization) {
         mir_graph_->AppendGenSuspendTestList(bb);
       }
       break;
 
     case Instruction::INVOKE_VIRTUAL:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kVirtual, false));
-      if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+      if (!kLeafOptimization) {
         mir_graph_->AppendGenSuspendTestList(bb);
       }
       break;
     case Instruction::INVOKE_VIRTUAL_RANGE:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kVirtual, true));
-      if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+      if (!kLeafOptimization) {
         mir_graph_->AppendGenSuspendTestList(bb);
       }
       break;
 
     case Instruction::INVOKE_SUPER:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kSuper, false));
-      if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+      if (!kLeafOptimization) {
         mir_graph_->AppendGenSuspendTestList(bb);
       }
       break;
     case Instruction::INVOKE_SUPER_RANGE:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kSuper, true));
-      if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+      if (!kLeafOptimization) {
         mir_graph_->AppendGenSuspendTestList(bb);
       }
       break;
 
     case Instruction::INVOKE_INTERFACE:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kInterface, false));
-      if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+      if (!kLeafOptimization) {
         mir_graph_->AppendGenSuspendTestList(bb);
       }
       break;
     case Instruction::INVOKE_INTERFACE_RANGE:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kInterface, true));
-      if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+      if (!kLeafOptimization) {
         mir_graph_->AppendGenSuspendTestList(bb);
       }
       break;
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 67a8c0f..3de4c56 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -1008,8 +1008,6 @@
     }
     // Load Dalvik value with 32-bit memory storage.  If compressed object reference, decompress.
     virtual RegLocation LoadValue(RegLocation rl_src, RegisterClass op_kind);
-    // Same as above, but derive the target register class from the location record.
-    virtual RegLocation LoadValue(RegLocation rl_src);
     // Load Dalvik value with 64-bit memory storage.
     virtual RegLocation LoadValueWide(RegLocation rl_src, RegisterClass op_kind);
     // Load Dalvik value with 32-bit memory storage.  If compressed object reference, decompress.
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 4357657..8638204 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1155,7 +1155,7 @@
     LockTemp(rs_r0);
 
     RegLocation rl_object = LoadValue(rl_src_obj, kRefReg);
-    RegLocation rl_new_value = LoadValue(rl_src_new_value);
+    RegLocation rl_new_value = LoadValue(rl_src_new_value, LocToRegClass(rl_src_new_value));
 
     if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
       // Mark card for object assuming new value is stored.
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index 30384ec..6898b50 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -1113,20 +1113,18 @@
   }
 
   uint32_t index = mir->dalvikInsn.vB;
-  if (!(mir->optimization_flags & MIR_INLINED)) {
-    DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
-    DexFileMethodInliner* method_inliner =
-      cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file);
-    InlineMethod method;
-    if (method_inliner->IsIntrinsic(index, &method)) {
-      switch (method.opcode) {
-        case kIntrinsicAbsDouble:
-        case kIntrinsicMinMaxDouble:
-          store_method_addr_ = true;
-          break;
-        default:
-          break;
-      }
+  DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
+  DexFileMethodInliner* method_inliner =
+    cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file);
+  InlineMethod method;
+  if (method_inliner->IsIntrinsic(index, &method)) {
+    switch (method.opcode) {
+      case kIntrinsicAbsDouble:
+      case kIntrinsicMinMaxDouble:
+        store_method_addr_ = true;
+        break;
+      default:
+        break;
     }
   }
 }
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 3be2478..74ee038 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -1094,7 +1094,8 @@
     elf_header_.e_ident[EI_MAG1]       = ELFMAG1;
     elf_header_.e_ident[EI_MAG2]       = ELFMAG2;
     elf_header_.e_ident[EI_MAG3]       = ELFMAG3;
-    elf_header_.e_ident[EI_CLASS]      = ELFCLASS32;
+    elf_header_.e_ident[EI_CLASS]      = (sizeof(Elf_Addr) == sizeof(Elf32_Addr))
+                                         ? ELFCLASS32 : ELFCLASS64;;
     elf_header_.e_ident[EI_DATA]       = ELFDATA2LSB;
     elf_header_.e_ident[EI_VERSION]    = EV_CURRENT;
     elf_header_.e_ident[EI_OSABI]      = ELFOSABI_LINUX;
diff --git a/compiler/elf_fixup.cc b/compiler/elf_fixup.cc
deleted file mode 100644
index 0d34879..0000000
--- a/compiler/elf_fixup.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "elf_fixup.h"
-
-#include <inttypes.h>
-#include <memory>
-
-#include "base/logging.h"
-#include "base/stringprintf.h"
-#include "elf_file.h"
-#include "elf_writer.h"
-
-namespace art {
-
-static const bool DEBUG_FIXUP = false;
-
-bool ElfFixup::Fixup(File* file, uintptr_t oat_data_begin) {
-  std::string error_msg;
-  std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, &error_msg));
-  CHECK(elf_file.get() != nullptr) << error_msg;
-
-  // Lookup "oatdata" symbol address.
-  Elf32_Addr oatdata_address = ElfWriter::GetOatDataAddress(elf_file.get());
-  Elf32_Off base_address = oat_data_begin - oatdata_address;
-
-  if (!FixupDynamic(*elf_file.get(), base_address)) {
-    LOG(WARNING) << "Failed to fixup .dynamic in " << file->GetPath();
-    return false;
-  }
-  if (!FixupSectionHeaders(*elf_file.get(), base_address)) {
-    LOG(WARNING) << "Failed to fixup section headers in " << file->GetPath();
-    return false;
-  }
-  if (!FixupProgramHeaders(*elf_file.get(), base_address)) {
-    LOG(WARNING) << "Failed to fixup program headers in " << file->GetPath();
-    return false;
-  }
-  if (!FixupSymbols(*elf_file.get(), base_address, true)) {
-    LOG(WARNING) << "Failed to fixup .dynsym in " << file->GetPath();
-    return false;
-  }
-  if (!FixupSymbols(*elf_file.get(), base_address, false)) {
-    LOG(WARNING) << "Failed to fixup .symtab in " << file->GetPath();
-    return false;
-  }
-  if (!FixupRelocations(*elf_file.get(), base_address)) {
-    LOG(WARNING) << "Failed to fixup .rel.dyn in " << file->GetPath();
-    return false;
-  }
-  if (!elf_file->FixupDebugSections(base_address)) {
-    LOG(WARNING) << "Failed to fixup debug sections in " << file->GetPath();
-    return false;
-  }
-  return true;
-}
-
-
-bool ElfFixup::FixupDynamic(ElfFile& elf_file, uintptr_t base_address) {
-  for (Elf32_Word i = 0; i < elf_file.GetDynamicNum(); i++) {
-    Elf32_Dyn& elf_dyn = elf_file.GetDynamic(i);
-    Elf32_Word d_tag = elf_dyn.d_tag;
-    if (IsDynamicSectionPointer(d_tag, elf_file.GetHeader().e_machine)) {
-      uint32_t d_ptr = elf_dyn.d_un.d_ptr;
-      if (DEBUG_FIXUP) {
-        LOG(INFO) << StringPrintf("In %s moving Elf32_Dyn[%d] from 0x%08x to 0x%08" PRIxPTR,
-                                  elf_file.GetFile().GetPath().c_str(), i,
-                                  d_ptr, d_ptr + base_address);
-      }
-      d_ptr += base_address;
-      elf_dyn.d_un.d_ptr = d_ptr;
-    }
-  }
-  return true;
-}
-
-bool ElfFixup::FixupSectionHeaders(ElfFile& elf_file, uintptr_t base_address) {
-  for (Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) {
-    Elf32_Shdr* sh = elf_file.GetSectionHeader(i);
-    CHECK(sh != nullptr);
-    // 0 implies that the section will not exist in the memory of the process
-    if (sh->sh_addr == 0) {
-      continue;
-    }
-    if (DEBUG_FIXUP) {
-      LOG(INFO) << StringPrintf("In %s moving Elf32_Shdr[%d] from 0x%08x to 0x%08" PRIxPTR,
-                                elf_file.GetFile().GetPath().c_str(), i,
-                                sh->sh_addr, sh->sh_addr + base_address);
-    }
-    sh->sh_addr += base_address;
-  }
-  return true;
-}
-
-bool ElfFixup::FixupProgramHeaders(ElfFile& elf_file, uintptr_t base_address) {
-  // TODO: ELFObjectFile doesn't have give to Elf32_Phdr, so we do that ourselves for now.
-  for (Elf32_Word i = 0; i < elf_file.GetProgramHeaderNum(); i++) {
-    Elf32_Phdr* ph = elf_file.GetProgramHeader(i);
-    CHECK(ph != nullptr);
-    CHECK_EQ(ph->p_vaddr, ph->p_paddr) << elf_file.GetFile().GetPath() << " i=" << i;
-    CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1))))
-            << elf_file.GetFile().GetPath() << " i=" << i;
-    if (DEBUG_FIXUP) {
-      LOG(INFO) << StringPrintf("In %s moving Elf32_Phdr[%d] from 0x%08x to 0x%08" PRIxPTR,
-                                elf_file.GetFile().GetPath().c_str(), i,
-                                ph->p_vaddr, ph->p_vaddr + base_address);
-    }
-    ph->p_vaddr += base_address;
-    ph->p_paddr += base_address;
-    CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1))))
-            << elf_file.GetFile().GetPath() << " i=" << i;
-  }
-  return true;
-}
-
-bool ElfFixup::FixupSymbols(ElfFile& elf_file, uintptr_t base_address, bool dynamic) {
-  Elf32_Word section_type = dynamic ? SHT_DYNSYM : SHT_SYMTAB;
-  // TODO: Unfortunate ELFObjectFile has protected symbol access, so use ElfFile
-  Elf32_Shdr* symbol_section = elf_file.FindSectionByType(section_type);
-  if (symbol_section == nullptr) {
-    // file is missing optional .symtab
-    CHECK(!dynamic) << elf_file.GetFile().GetPath();
-    return true;
-  }
-  for (uint32_t i = 0; i < elf_file.GetSymbolNum(*symbol_section); i++) {
-    Elf32_Sym* symbol = elf_file.GetSymbol(section_type, i);
-    CHECK(symbol != nullptr);
-    if (symbol->st_value != 0) {
-      if (DEBUG_FIXUP) {
-        LOG(INFO) << StringPrintf("In %s moving Elf32_Sym[%d] from 0x%08x to 0x%08" PRIxPTR,
-                                  elf_file.GetFile().GetPath().c_str(), i,
-                                  symbol->st_value, symbol->st_value + base_address);
-      }
-      symbol->st_value += base_address;
-    }
-  }
-  return true;
-}
-
-bool ElfFixup::FixupRelocations(ElfFile& elf_file, uintptr_t base_address) {
-  for (Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) {
-    Elf32_Shdr* sh = elf_file.GetSectionHeader(i);
-    CHECK(sh != nullptr);
-    if (sh->sh_type == SHT_REL) {
-      for (uint32_t i = 0; i < elf_file.GetRelNum(*sh); i++) {
-        Elf32_Rel& rel = elf_file.GetRel(*sh, i);
-        if (DEBUG_FIXUP) {
-          LOG(INFO) << StringPrintf("In %s moving Elf32_Rel[%d] from 0x%08x to 0x%08" PRIxPTR,
-                                    elf_file.GetFile().GetPath().c_str(), i,
-                                    rel.r_offset, rel.r_offset + base_address);
-        }
-        rel.r_offset += base_address;
-      }
-    } else if (sh->sh_type == SHT_RELA) {
-      for (uint32_t i = 0; i < elf_file.GetRelaNum(*sh); i++) {
-        Elf32_Rela& rela = elf_file.GetRela(*sh, i);
-        if (DEBUG_FIXUP) {
-          LOG(INFO) << StringPrintf("In %s moving Elf32_Rela[%d] from 0x%08x to 0x%08" PRIxPTR,
-                                    elf_file.GetFile().GetPath().c_str(), i,
-                                    rela.r_offset, rela.r_offset + base_address);
-        }
-        rela.r_offset += base_address;
-      }
-    }
-  }
-  return true;
-}
-
-}  // namespace art
diff --git a/compiler/elf_fixup.h b/compiler/elf_fixup.h
deleted file mode 100644
index 1abf06b..0000000
--- a/compiler/elf_fixup.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_ELF_FIXUP_H_
-#define ART_COMPILER_ELF_FIXUP_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "os.h"
-
-namespace art {
-
-class ElfFile;
-
-class ElfFixup {
- public:
-  // Fixup an ELF file so that that oat header will be loaded at oat_begin.
-  // Returns true on success, false on failure.
-  static bool Fixup(File* file, uintptr_t oat_data_begin);
-
- private:
-  // Fixup .dynamic d_ptr values for the expected base_address.
-  static bool FixupDynamic(ElfFile& elf_file, uintptr_t base_address);
-
-  // Fixup Elf32_Shdr p_vaddr to load at the desired address.
-  static bool FixupSectionHeaders(ElfFile& elf_file, uintptr_t base_address);
-
-  // Fixup Elf32_Phdr p_vaddr to load at the desired address.
-  static bool FixupProgramHeaders(ElfFile& elf_file, uintptr_t base_address);
-
-  // Fixup symbol table
-  static bool FixupSymbols(ElfFile& elf_file, uintptr_t base_address, bool dynamic);
-
-  // Fixup dynamic relocations
-  static bool FixupRelocations(ElfFile& elf_file, uintptr_t base_address);
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ElfFixup);
-};
-
-}  // namespace art
-
-#endif  // ART_COMPILER_ELF_FIXUP_H_
diff --git a/compiler/elf_stripper.cc b/compiler/elf_stripper.cc
deleted file mode 100644
index 457d8a0..0000000
--- a/compiler/elf_stripper.cc
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "elf_stripper.h"
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <memory>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/stringprintf.h"
-#include "elf_file.h"
-#include "elf_utils.h"
-#include "utils.h"
-
-namespace art {
-
-bool ElfStripper::Strip(File* file, std::string* error_msg) {
-  std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, error_msg));
-  if (elf_file.get() == nullptr) {
-    return false;
-  }
-
-  // ELF files produced by MCLinker look roughly like this
-  //
-  // +------------+
-  // | Elf32_Ehdr | contains number of Elf32_Shdr and offset to first
-  // +------------+
-  // | Elf32_Phdr | program headers
-  // | Elf32_Phdr |
-  // | ...        |
-  // | Elf32_Phdr |
-  // +------------+
-  // | section    | mixture of needed and unneeded sections
-  // +------------+
-  // | section    |
-  // +------------+
-  // | ...        |
-  // +------------+
-  // | section    |
-  // +------------+
-  // | Elf32_Shdr | section headers
-  // | Elf32_Shdr |
-  // | ...        | contains offset to section start
-  // | Elf32_Shdr |
-  // +------------+
-  //
-  // To strip:
-  // - leave the Elf32_Ehdr and Elf32_Phdr values in place.
-  // - walk the sections making a new set of Elf32_Shdr section headers for what we want to keep
-  // - move the sections are keeping up to fill in gaps of sections we want to strip
-  // - write new Elf32_Shdr section headers to end of file, updating Elf32_Ehdr
-  // - truncate rest of file
-  //
-
-  std::vector<Elf32_Shdr> section_headers;
-  std::vector<Elf32_Word> section_headers_original_indexes;
-  section_headers.reserve(elf_file->GetSectionHeaderNum());
-
-
-  Elf32_Shdr* string_section = elf_file->GetSectionNameStringSection();
-  CHECK(string_section != nullptr);
-  for (Elf32_Word i = 0; i < elf_file->GetSectionHeaderNum(); i++) {
-    Elf32_Shdr* sh = elf_file->GetSectionHeader(i);
-    CHECK(sh != nullptr);
-    const char* name = elf_file->GetString(*string_section, sh->sh_name);
-    if (name == nullptr) {
-      CHECK_EQ(0U, i);
-      section_headers.push_back(*sh);
-      section_headers_original_indexes.push_back(0);
-      continue;
-    }
-    if (StartsWith(name, ".debug")
-        || (strcmp(name, ".strtab") == 0)
-        || (strcmp(name, ".symtab") == 0)) {
-      continue;
-    }
-    section_headers.push_back(*sh);
-    section_headers_original_indexes.push_back(i);
-  }
-  CHECK_NE(0U, section_headers.size());
-  CHECK_EQ(section_headers.size(), section_headers_original_indexes.size());
-
-  // section 0 is the NULL section, sections start at offset of first section
-  CHECK(elf_file->GetSectionHeader(1) != nullptr);
-  Elf32_Off offset = elf_file->GetSectionHeader(1)->sh_offset;
-  for (size_t i = 1; i < section_headers.size(); i++) {
-    Elf32_Shdr& new_sh = section_headers[i];
-    Elf32_Shdr* old_sh = elf_file->GetSectionHeader(section_headers_original_indexes[i]);
-    CHECK(old_sh != nullptr);
-    CHECK_EQ(new_sh.sh_name, old_sh->sh_name);
-    if (old_sh->sh_addralign > 1) {
-      offset = RoundUp(offset, old_sh->sh_addralign);
-    }
-    if (old_sh->sh_offset == offset) {
-      // already in place
-      offset += old_sh->sh_size;
-      continue;
-    }
-    // shift section earlier
-    memmove(elf_file->Begin() + offset,
-            elf_file->Begin() + old_sh->sh_offset,
-            old_sh->sh_size);
-    new_sh.sh_offset = offset;
-    offset += old_sh->sh_size;
-  }
-
-  Elf32_Off shoff = offset;
-  size_t section_headers_size_in_bytes = section_headers.size() * sizeof(Elf32_Shdr);
-  memcpy(elf_file->Begin() + offset, &section_headers[0], section_headers_size_in_bytes);
-  offset += section_headers_size_in_bytes;
-
-  elf_file->GetHeader().e_shnum = section_headers.size();
-  elf_file->GetHeader().e_shoff = shoff;
-  int result = ftruncate(file->Fd(), offset);
-  if (result != 0) {
-    *error_msg = StringPrintf("Failed to truncate while stripping ELF file: '%s': %s",
-                              file->GetPath().c_str(), strerror(errno));
-    return false;
-  }
-  return true;
-}
-
-}  // namespace art
diff --git a/compiler/elf_stripper.h b/compiler/elf_stripper.h
deleted file mode 100644
index f1a1d46..0000000
--- a/compiler/elf_stripper.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_ELF_STRIPPER_H_
-#define ART_COMPILER_ELF_STRIPPER_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "os.h"
-
-namespace art {
-
-class ElfStripper {
- public:
-  // Strip an ELF file of unneeded debugging information.
-  // Returns true on success, false on failure.
-  static bool Strip(File* file, std::string* error_msg);
-
- private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ElfStripper);
-};
-
-}  // namespace art
-
-#endif  // ART_COMPILER_ELF_STRIPPER_H_
diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc
index 55ee18e..47402f3 100644
--- a/compiler/elf_writer.cc
+++ b/compiler/elf_writer.cc
@@ -30,8 +30,8 @@
 
 namespace art {
 
-uint32_t ElfWriter::GetOatDataAddress(ElfFile* elf_file) {
-  Elf32_Addr oatdata_address = elf_file->FindSymbolAddress(SHT_DYNSYM,
+uintptr_t ElfWriter::GetOatDataAddress(ElfFile* elf_file) {
+  uintptr_t oatdata_address = elf_file->FindSymbolAddress(SHT_DYNSYM,
                                                            "oatdata",
                                                            false);
   CHECK_NE(0U, oatdata_address);
@@ -51,4 +51,16 @@
   CHECK_NE(0U, oat_data_offset);
 }
 
+bool ElfWriter::Fixup(File* file, uintptr_t oat_data_begin) {
+  std::string error_msg;
+  std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, &error_msg));
+  CHECK(elf_file.get() != nullptr) << error_msg;
+
+  // Lookup "oatdata" symbol address.
+  uintptr_t oatdata_address = ElfWriter::GetOatDataAddress(elf_file.get());
+  uintptr_t base_address = oat_data_begin - oatdata_address;
+
+  return elf_file->Fixup(base_address);
+}
+
 }  // namespace art
diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h
index 03b965a..033c1f8 100644
--- a/compiler/elf_writer.h
+++ b/compiler/elf_writer.h
@@ -42,7 +42,9 @@
                                    size_t& oat_data_offset);
 
   // Returns runtime oat_data runtime address for an opened ElfFile.
-  static uint32_t GetOatDataAddress(ElfFile* elf_file);
+  static uintptr_t GetOatDataAddress(ElfFile* elf_file);
+
+  static bool Fixup(File* file, uintptr_t oat_data_begin);
 
  protected:
   ElfWriter(const CompilerDriver& driver, File* elf_file)
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index 2a37049..5834e8e 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -23,7 +23,7 @@
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
 #include "common_compiler_test.h"
-#include "elf_fixup.h"
+#include "elf_writer.h"
 #include "gc/space/image_space.h"
 #include "image_writer.h"
 #include "lock_word.h"
@@ -101,7 +101,7 @@
     bool success_image =
         writer.Write(image_file.GetFilename(), dup_oat->GetPath(), dup_oat->GetPath());
     ASSERT_TRUE(success_image);
-    bool success_fixup = ElfFixup::Fixup(dup_oat.get(), writer.GetOatDataBegin());
+    bool success_fixup = ElfWriter::Fixup(dup_oat.get(), writer.GetOatDataBegin());
     ASSERT_TRUE(success_fixup);
   }
 
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 1c8b8d5..6fff5f4 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -811,11 +811,12 @@
 }
 
 static OatHeader* GetOatHeaderFromElf(ElfFile* elf) {
-  Elf32_Shdr* data_sec = elf->FindSectionByName(".rodata");
-  if (data_sec == nullptr) {
+  uint64_t data_sec_offset;
+  bool has_data_sec = elf->GetSectionOffsetAndSize(".rodata", &data_sec_offset, nullptr);
+  if (!has_data_sec) {
     return nullptr;
   }
-  return reinterpret_cast<OatHeader*>(elf->Begin() + data_sec->sh_offset);
+  return reinterpret_cast<OatHeader*>(elf->Begin() + data_sec_offset);
 }
 
 void ImageWriter::SetOatChecksumFromElfFile(File* elf_file) {
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 1876cb9..2aa04d4 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -611,7 +611,7 @@
   DCHECK(cond->IsCondition());
   HCondition* condition = cond->AsCondition();
   if (condition->NeedsMaterialization()) {
-    locations->SetInAt(0, Location::RequiresRegister());
+    locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
   }
 }
 
@@ -657,8 +657,8 @@
 void LocationsBuilderARM::VisitCondition(HCondition* comp) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
+  locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)), Location::kDiesAtEntry);
   if (comp->NeedsMaterialization()) {
     locations->SetOut(Location::RequiresRegister());
   }
@@ -960,8 +960,9 @@
   switch (add->GetResultType()) {
     case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
-      locations->SetInAt(0, Location::RequiresRegister());
-      locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
+      bool dies_at_entry = add->GetResultType() != Primitive::kPrimLong;
+      locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
+      locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)), dies_at_entry);
       locations->SetOut(Location::RequiresRegister());
       break;
     }
@@ -1020,8 +1021,9 @@
   switch (sub->GetResultType()) {
     case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
-      locations->SetInAt(0, Location::RequiresRegister());
-      locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
+      bool dies_at_entry = sub->GetResultType() != Primitive::kPrimLong;
+      locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
+      locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)), dies_at_entry);
       locations->SetOut(Location::RequiresRegister());
       break;
     }
@@ -1116,7 +1118,7 @@
 void LocationsBuilderARM::VisitNot(HNot* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -1129,8 +1131,8 @@
 void LocationsBuilderARM::VisitCompare(HCompare* compare) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
+  locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry);
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -1186,10 +1188,12 @@
 void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RequiresRegister());
+  bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
+  bool dies_at_entry = !is_object_type;
+  locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
+  locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
   // Temporary registers for the write barrier.
-  if (instruction->GetFieldType() == Primitive::kPrimNot) {
+  if (is_object_type) {
     locations->AddTemp(Location::RequiresRegister());
     locations->AddTemp(Location::RequiresRegister());
   }
@@ -1246,7 +1250,7 @@
 void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -1328,8 +1332,9 @@
 void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
+  locations->SetInAt(
+      1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -1439,9 +1444,10 @@
     locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1)));
     locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2)));
   } else {
-    locations->SetInAt(0, Location::RequiresRegister());
-    locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
-    locations->SetInAt(2, Location::RequiresRegister());
+    locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
+    locations->SetInAt(
+        1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
+    locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
   }
 }
 
@@ -1527,7 +1533,7 @@
 void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -1610,13 +1616,12 @@
       new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
   codegen_->AddSlowPath(slow_path);
 
-  __ AddConstant(R4, R4, -1);
-  __ cmp(R4, ShifterOperand(0));
+  __ subs(R4, R4, ShifterOperand(1));
   if (successor == nullptr) {
-    __ b(slow_path->GetEntryLabel(), LE);
+    __ b(slow_path->GetEntryLabel(), EQ);
     __ Bind(slow_path->GetReturnLabel());
   } else {
-    __ b(codegen_->GetLabelOf(successor), GT);
+    __ b(codegen_->GetLabelOf(successor), NE);
     __ b(slow_path->GetEntryLabel());
   }
 }
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index ea67dfd..6791003 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -563,7 +563,7 @@
   DCHECK(cond->IsCondition());
   HCondition* condition = cond->AsCondition();
   if (condition->NeedsMaterialization()) {
-    locations->SetInAt(0, Location::Any());
+    locations->SetInAt(0, Location::Any(), Location::kDiesAtEntry);
   }
 }
 
@@ -650,8 +650,8 @@
 void LocationsBuilderX86::VisitCondition(HCondition* comp) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::Any());
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
+  locations->SetInAt(1, Location::Any(), Location::kDiesAtEntry);
   if (comp->NeedsMaterialization()) {
     locations->SetOut(Location::RequiresRegister());
   }
@@ -1094,8 +1094,8 @@
 void LocationsBuilderX86::VisitCompare(HCompare* compare) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::Any());
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
+  locations->SetInAt(1, Location::Any(), Location::kDiesAtEntry);
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -1159,14 +1159,16 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   Primitive::Type field_type = instruction->GetFieldType();
+  bool is_object_type = field_type == Primitive::kPrimNot;
+  bool dies_at_entry = !is_object_type;
   if (field_type == Primitive::kPrimBoolean || field_type == Primitive::kPrimByte) {
     // Ensure the value is in a byte register.
-    locations->SetInAt(1, X86CpuLocation(EAX));
+    locations->SetInAt(1, X86CpuLocation(EAX), dies_at_entry);
   } else {
-    locations->SetInAt(1, Location::RequiresRegister());
+    locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
   }
   // Temporary registers for the write barrier.
-  if (field_type == Primitive::kPrimNot) {
+  if (is_object_type) {
     locations->AddTemp(Location::RequiresRegister());
     // Ensure the card is in a byte register.
     locations->AddTemp(X86CpuLocation(ECX));
@@ -1238,7 +1240,7 @@
 void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -1324,8 +1326,9 @@
 void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
+  locations->SetInAt(
+      1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -1433,13 +1436,16 @@
     locations->SetInAt(1, X86CpuLocation(calling_convention.GetRegisterAt(1)));
     locations->SetInAt(2, X86CpuLocation(calling_convention.GetRegisterAt(2)));
   } else {
-    locations->SetInAt(0, Location::RequiresRegister());
-    locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+    // We need the inputs to be different than the output in case of long operation.
+    bool dies_at_entry = value_type != Primitive::kPrimLong;
+    locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
+    locations->SetInAt(
+        1, Location::RegisterOrConstant(instruction->InputAt(1)), dies_at_entry);
     if (value_type == Primitive::kPrimBoolean || value_type == Primitive::kPrimByte) {
       // Ensure the value is in a byte register.
-      locations->SetInAt(2, X86CpuLocation(EAX));
+      locations->SetInAt(2, X86CpuLocation(EAX), dies_at_entry);
     } else {
-      locations->SetInAt(2, Location::RequiresRegister());
+      locations->SetInAt(2, Location::RequiresRegister(), dies_at_entry);
     }
   }
 }
@@ -1523,7 +1529,7 @@
 
 void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
-  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
   locations->SetOut(Location::RequiresRegister());
   instruction->SetLocations(locations);
 }
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 78c7d9d..e0e0c79 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -446,7 +446,7 @@
   DCHECK(cond->IsCondition());
   HCondition* condition = cond->AsCondition();
   if (condition->NeedsMaterialization()) {
-    locations->SetInAt(0, Location::Any());
+    locations->SetInAt(0, Location::Any(), Location::kDiesAtEntry);
   }
 }
 
@@ -530,8 +530,8 @@
 void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::Any());
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
+  locations->SetInAt(1, Location::Any(), Location::kDiesAtEntry);
   if (comp->NeedsMaterialization()) {
     locations->SetOut(Location::RequiresRegister());
   }
@@ -608,8 +608,8 @@
 void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
+  locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry);
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -970,6 +970,9 @@
 void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->AddTemp(X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
+  locations->AddTemp(X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
   locations->SetOut(X86_64CpuLocation(RAX));
 }
 
@@ -1031,10 +1034,13 @@
 void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RequiresRegister());
-  // Temporary registers for the write barrier.
-  if (instruction->GetFieldType() == Primitive::kPrimNot) {
+  Primitive::Type field_type = instruction->GetFieldType();
+  bool is_object_type = field_type == Primitive::kPrimNot;
+  bool dies_at_entry = !is_object_type;
+  locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
+  locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
+  if (is_object_type) {
+    // Temporary registers for the write barrier.
     locations->AddTemp(Location::RequiresRegister());
     locations->AddTemp(Location::RequiresRegister());
   }
@@ -1088,7 +1094,7 @@
 void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -1167,8 +1173,9 @@
 void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
+  locations->SetInAt(
+      1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -1272,9 +1279,10 @@
     locations->SetInAt(1, X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
     locations->SetInAt(2, X86_64CpuLocation(calling_convention.GetRegisterAt(2)));
   } else {
-    locations->SetInAt(0, Location::RequiresRegister());
-    locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
-    locations->SetInAt(2, Location::RequiresRegister());
+    locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
+    locations->SetInAt(
+        1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
+    locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
   }
 }
 
@@ -1354,7 +1362,7 @@
 void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
   locations->SetOut(Location::RequiresRegister());
 }
 
diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc
index 03f8625..8be4746 100644
--- a/compiler/optimizing/live_ranges_test.cc
+++ b/compiler/optimizing/live_ranges_test.cc
@@ -268,7 +268,7 @@
   range = interval->GetFirstRange();
   // Instruction is consumed by the if.
   ASSERT_EQ(14u, range->GetStart());
-  ASSERT_EQ(17u, range->GetEnd());
+  ASSERT_EQ(16u, range->GetEnd());
   ASSERT_TRUE(range->GetNext() == nullptr);
 }
 
diff --git a/compiler/optimizing/locations.cc b/compiler/optimizing/locations.cc
index 1c36cdf..114d69c 100644
--- a/compiler/optimizing/locations.cc
+++ b/compiler/optimizing/locations.cc
@@ -25,13 +25,16 @@
       temps_(instruction->GetBlock()->GetGraph()->GetArena(), 0),
       environment_(instruction->GetBlock()->GetGraph()->GetArena(),
                    instruction->EnvironmentSize()),
+      dies_at_entry_(instruction->GetBlock()->GetGraph()->GetArena(), instruction->InputCount()),
       call_kind_(call_kind),
       stack_mask_(nullptr),
       register_mask_(0),
       live_registers_() {
   inputs_.SetSize(instruction->InputCount());
+  dies_at_entry_.SetSize(instruction->InputCount());
   for (size_t i = 0; i < instruction->InputCount(); ++i) {
     inputs_.Put(i, Location());
+    dies_at_entry_.Put(i, false);
   }
   environment_.SetSize(instruction->EnvironmentSize());
   for (size_t i = 0; i < instruction->EnvironmentSize(); ++i) {
diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h
index f358e05..8d0715a 100644
--- a/compiler/optimizing/locations.h
+++ b/compiler/optimizing/locations.h
@@ -34,6 +34,8 @@
  */
 class Location : public ValueObject {
  public:
+  static constexpr bool kDiesAtEntry = true;
+
   enum Kind {
     kInvalid = 0,
     kConstant = 1,
@@ -312,7 +314,8 @@
 
   LocationSummary(HInstruction* instruction, CallKind call_kind = kNoCall);
 
-  void SetInAt(uint32_t at, Location location) {
+  void SetInAt(uint32_t at, Location location, bool dies_at_entry = false) {
+    dies_at_entry_.Put(at, dies_at_entry);
     inputs_.Put(at, location);
   }
 
@@ -390,10 +393,12 @@
   bool InputOverlapsWithOutputOrTemp(uint32_t input, bool is_environment) const {
     if (is_environment) return true;
     Location location = Out();
-    // TODO: Add more policies.
     if (input == 0 && location.IsUnallocated() && location.GetPolicy() == Location::kSameAsFirstInput) {
       return false;
     }
+    if (dies_at_entry_.Get(input)) {
+      return false;
+    }
     return true;
   }
 
@@ -401,6 +406,7 @@
   GrowableArray<Location> inputs_;
   GrowableArray<Location> temps_;
   GrowableArray<Location> environment_;
+  GrowableArray<bool> dies_at_entry_;
   Location output_;
   const CallKind call_kind_;
 
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 09825e2..e1f513d 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -44,8 +44,7 @@
 #include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
-#include "elf_fixup.h"
-#include "elf_stripper.h"
+#include "elf_writer.h"
 #include "gc/space/image_space.h"
 #include "gc/space/space-inl.h"
 #include "image_writer.h"
@@ -472,7 +471,7 @@
       PLOG(ERROR) << "Failed to open ELF file: " << oat_filename;
       return false;
     }
-    if (!ElfFixup::Fixup(oat_file.get(), oat_data_begin)) {
+    if (!ElfWriter::Fixup(oat_file.get(), oat_data_begin)) {
       LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath();
       return false;
     }
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 50b4ece..bbaf0e4 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -29,6 +29,7 @@
 #include "base/stringprintf.h"
 #include "elf_utils.h"
 #include "elf_file.h"
+#include "elf_file_impl.h"
 #include "gc/space/image_space.h"
 #include "image.h"
 #include "instruction_set.h"
@@ -467,15 +468,16 @@
   return true;
 }
 
-template <typename ptr_t>
-bool PatchOat::CheckOatFile(const Elf32_Shdr& patches_sec) {
-  if (patches_sec.sh_type != SHT_OAT_PATCH) {
+template <typename ElfFileImpl, typename ptr_t>
+bool PatchOat::CheckOatFile(ElfFileImpl* oat_file) {
+  auto patches_sec = oat_file->FindSectionByName(".oat_patches");
+  if (patches_sec->sh_type != SHT_OAT_PATCH) {
     return false;
   }
-  ptr_t* patches = reinterpret_cast<ptr_t*>(oat_file_->Begin() + patches_sec.sh_offset);
-  ptr_t* patches_end = patches + (patches_sec.sh_size / sizeof(ptr_t));
-  Elf32_Shdr* oat_data_sec = oat_file_->FindSectionByName(".rodata");
-  Elf32_Shdr* oat_text_sec = oat_file_->FindSectionByName(".text");
+  ptr_t* patches = reinterpret_cast<ptr_t*>(oat_file->Begin() + patches_sec->sh_offset);
+  ptr_t* patches_end = patches + (patches_sec->sh_size / sizeof(ptr_t));
+  auto oat_data_sec = oat_file->FindSectionByName(".rodata");
+  auto oat_text_sec = oat_file->FindSectionByName(".text");
   if (oat_data_sec == nullptr) {
     return false;
   }
@@ -495,14 +497,15 @@
   return true;
 }
 
-bool PatchOat::PatchOatHeader() {
-  Elf32_Shdr *rodata_sec = oat_file_->FindSectionByName(".rodata");
+template <typename ElfFileImpl>
+bool PatchOat::PatchOatHeader(ElfFileImpl* oat_file) {
+  auto rodata_sec = oat_file->FindSectionByName(".rodata");
   if (rodata_sec == nullptr) {
     return false;
   }
-  OatHeader* oat_header = reinterpret_cast<OatHeader*>(oat_file_->Begin() + rodata_sec->sh_offset);
+  OatHeader* oat_header = reinterpret_cast<OatHeader*>(oat_file->Begin() + rodata_sec->sh_offset);
   if (!oat_header->IsValid()) {
-    LOG(ERROR) << "Elf file " << oat_file_->GetFile().GetPath() << " has an invalid oat header";
+    LOG(ERROR) << "Elf file " << oat_file->GetFile().GetPath() << " has an invalid oat header";
     return false;
   }
   oat_header->RelocateOat(delta_);
@@ -510,28 +513,31 @@
 }
 
 bool PatchOat::PatchElf() {
+  if (oat_file_->is_elf64_)
+    return PatchElf<ElfFileImpl64>(oat_file_->GetImpl64());
+  else
+    return PatchElf<ElfFileImpl32>(oat_file_->GetImpl32());
+}
+
+template <typename ElfFileImpl>
+bool PatchOat::PatchElf(ElfFileImpl* oat_file) {
   TimingLogger::ScopedTiming t("Fixup Elf Text Section", timings_);
-  if (!PatchTextSection()) {
+  if (!PatchTextSection<ElfFileImpl>(oat_file)) {
     return false;
   }
 
-  if (!PatchOatHeader()) {
+  if (!PatchOatHeader<ElfFileImpl>(oat_file)) {
     return false;
   }
 
   bool need_fixup = false;
-  t.NewTiming("Fixup Elf Headers");
-  // Fixup Phdr's
-  for (unsigned int i = 0; i < oat_file_->GetProgramHeaderNum(); i++) {
-    Elf32_Phdr* hdr = oat_file_->GetProgramHeader(i);
-    CHECK(hdr != nullptr);
+  for (unsigned int i = 0; i < oat_file->GetProgramHeaderNum(); i++) {
+    auto hdr = oat_file->GetProgramHeader(i);
     if (hdr->p_vaddr != 0 && hdr->p_vaddr != hdr->p_offset) {
       need_fixup = true;
-      hdr->p_vaddr += delta_;
     }
     if (hdr->p_paddr != 0 && hdr->p_paddr != hdr->p_offset) {
       need_fixup = true;
-      hdr->p_paddr += delta_;
     }
   }
   if (!need_fixup) {
@@ -539,67 +545,39 @@
     // their addr. Therefore we do not need to update these parts.
     return true;
   }
+
+  t.NewTiming("Fixup Elf Headers");
+  // Fixup Phdr's
+  oat_file->FixupProgramHeaders(delta_);
+
   t.NewTiming("Fixup Section Headers");
-  for (unsigned int i = 0; i < oat_file_->GetSectionHeaderNum(); i++) {
-    Elf32_Shdr* hdr = oat_file_->GetSectionHeader(i);
-    CHECK(hdr != nullptr);
-    if (hdr->sh_addr != 0) {
-      hdr->sh_addr += delta_;
-    }
-  }
+  // Fixup Shdr's
+  oat_file->FixupSectionHeaders(delta_);
 
   t.NewTiming("Fixup Dynamics");
-  for (Elf32_Word i = 0; i < oat_file_->GetDynamicNum(); i++) {
-    Elf32_Dyn& dyn = oat_file_->GetDynamic(i);
-    if (IsDynamicSectionPointer(dyn.d_tag, oat_file_->GetHeader().e_machine)) {
-      dyn.d_un.d_ptr += delta_;
-    }
-  }
+  oat_file->FixupDynamic(delta_);
 
   t.NewTiming("Fixup Elf Symbols");
   // Fixup dynsym
-  Elf32_Shdr* dynsym_sec = oat_file_->FindSectionByName(".dynsym");
-  CHECK(dynsym_sec != nullptr);
-  if (!PatchSymbols(dynsym_sec)) {
+  if (!oat_file->FixupSymbols(delta_, true)) {
     return false;
   }
-
   // Fixup symtab
-  Elf32_Shdr* symtab_sec = oat_file_->FindSectionByName(".symtab");
-  if (symtab_sec != nullptr) {
-    if (!PatchSymbols(symtab_sec)) {
-      return false;
-    }
+  if (!oat_file->FixupSymbols(delta_, false)) {
+    return false;
   }
 
   t.NewTiming("Fixup Debug Sections");
-  if (!oat_file_->FixupDebugSections(delta_)) {
+  if (!oat_file->FixupDebugSections(delta_)) {
     return false;
   }
 
   return true;
 }
 
-bool PatchOat::PatchSymbols(Elf32_Shdr* section) {
-  Elf32_Sym* syms = reinterpret_cast<Elf32_Sym*>(oat_file_->Begin() + section->sh_offset);
-  const Elf32_Sym* last_sym =
-      reinterpret_cast<Elf32_Sym*>(oat_file_->Begin() + section->sh_offset + section->sh_size);
-  CHECK_EQ(section->sh_size % sizeof(Elf32_Sym), 0u)
-      << "Symtab section size is not multiple of symbol size";
-  for (; syms < last_sym; syms++) {
-    uint8_t sttype = ELF32_ST_TYPE(syms->st_info);
-    Elf32_Word shndx = syms->st_shndx;
-    if (shndx != SHN_ABS && shndx != SHN_COMMON && shndx != SHN_UNDEF &&
-        (sttype == STT_FUNC || sttype == STT_OBJECT)) {
-      CHECK_NE(syms->st_value, 0u);
-      syms->st_value += delta_;
-    }
-  }
-  return true;
-}
-
-bool PatchOat::PatchTextSection() {
-  Elf32_Shdr* patches_sec = oat_file_->FindSectionByName(".oat_patches");
+template <typename ElfFileImpl>
+bool PatchOat::PatchTextSection(ElfFileImpl* oat_file) {
+  auto patches_sec = oat_file->FindSectionByName(".oat_patches");
   if (patches_sec == nullptr) {
     LOG(ERROR) << ".oat_patches section not found. Aborting patch";
     return false;
@@ -611,9 +589,9 @@
 
   switch (patches_sec->sh_entsize) {
     case sizeof(uint32_t):
-      return PatchTextSection<uint32_t>(*patches_sec);
+      return PatchTextSection<ElfFileImpl, uint32_t>(oat_file);
     case sizeof(uint64_t):
-      return PatchTextSection<uint64_t>(*patches_sec);
+      return PatchTextSection<ElfFileImpl, uint64_t>(oat_file);
     default:
       LOG(ERROR) << ".oat_patches Entsize of " << patches_sec->sh_entsize << "bits "
                  << "is not valid";
@@ -621,14 +599,16 @@
   }
 }
 
-template <typename ptr_t>
-bool PatchOat::PatchTextSection(const Elf32_Shdr& patches_sec) {
-  DCHECK(CheckOatFile<ptr_t>(patches_sec)) << "Oat file invalid";
-  ptr_t* patches = reinterpret_cast<ptr_t*>(oat_file_->Begin() + patches_sec.sh_offset);
-  ptr_t* patches_end = patches + (patches_sec.sh_size / sizeof(ptr_t));
-  Elf32_Shdr* oat_text_sec = oat_file_->FindSectionByName(".text");
+template <typename ElfFileImpl, typename patch_loc_t>
+bool PatchOat::PatchTextSection(ElfFileImpl* oat_file) {
+  bool oat_file_valid = CheckOatFile<ElfFileImpl, patch_loc_t>(oat_file);
+  CHECK(oat_file_valid) << "Oat file invalid";
+  auto patches_sec = oat_file->FindSectionByName(".oat_patches");
+  patch_loc_t* patches = reinterpret_cast<patch_loc_t*>(oat_file->Begin() + patches_sec->sh_offset);
+  patch_loc_t* patches_end = patches + (patches_sec->sh_size / sizeof(patch_loc_t));
+  auto oat_text_sec = oat_file->FindSectionByName(".text");
   CHECK(oat_text_sec != nullptr);
-  byte* to_patch = oat_file_->Begin() + oat_text_sec->sh_offset;
+  byte* to_patch = oat_file->Begin() + oat_text_sec->sh_offset;
   uintptr_t to_patch_end = reinterpret_cast<uintptr_t>(to_patch) + oat_text_sec->sh_size;
 
   for (; patches < patches_end; patches++) {
@@ -768,7 +748,7 @@
     if (f.get() != nullptr) {
       if (fchmod(f->Fd(), 0644) != 0) {
         PLOG(ERROR) << "Unable to make " << name << " world readable";
-        unlink(name);
+        TEMP_FAILURE_RETRY(unlink(name));
         return nullptr;
       }
     }
@@ -1086,11 +1066,11 @@
     if (!success) {
       if (new_oat_out) {
         CHECK(!output_oat_filename.empty());
-        unlink(output_oat_filename.c_str());
+        TEMP_FAILURE_RETRY(unlink(output_oat_filename.c_str()));
       }
       if (new_image_out) {
         CHECK(!output_image_filename.empty());
-        unlink(output_image_filename.c_str());
+        TEMP_FAILURE_RETRY(unlink(output_image_filename.c_str()));
       }
     }
     if (dump_timings) {
diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h
index 9086d58..7dd95f5 100644
--- a/patchoat/patchoat.h
+++ b/patchoat/patchoat.h
@@ -76,12 +76,15 @@
 
   // Patches oat in place, modifying the oat_file given to the constructor.
   bool PatchElf();
-  bool PatchTextSection();
+  template <typename ElfFileImpl>
+  bool PatchElf(ElfFileImpl* oat_file);
+  template <typename ElfFileImpl>
+  bool PatchTextSection(ElfFileImpl* oat_file);
   // Templatized version to actually do the patching with the right sized offsets.
-  template <typename ptr_t> bool PatchTextSection(const Elf32_Shdr& patches_sec);
-  template <typename ptr_t> bool CheckOatFile(const Elf32_Shdr& patches_sec);
-  bool PatchOatHeader();
-  bool PatchSymbols(Elf32_Shdr* section);
+  template <typename ElfFileImpl, typename patch_loc_t> bool PatchTextSection(ElfFileImpl* oat_file);
+  template <typename ElfFileImpl, typename patch_loc_t> bool CheckOatFile(ElfFileImpl* oat_filec);
+  template <typename ElfFileImpl>
+  bool PatchOatHeader(ElfFileImpl* oat_file);
 
   bool PatchImage() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/elf.h b/runtime/elf.h
index 6e007a2..60b5248 100644
--- a/runtime/elf.h
+++ b/runtime/elf.h
@@ -1411,6 +1411,7 @@
 
 // BEGIN android-added for <elf.h> compat
 static inline unsigned char ELF32_ST_TYPE(unsigned char st_info) { return st_info & 0x0f; }
+static inline unsigned char ELF64_ST_TYPE(unsigned char st_info) { return st_info & 0x0f; }
 // END android-added for <elf.h> compat
 
 // Symbol table entries for ELF64.
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 65a557b..3b8358d 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -16,6 +16,7 @@
 
 #include "elf_file.h"
 
+#include <inttypes.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -106,7 +107,12 @@
   delete entry;
 }
 
-ElfFile::ElfFile(File* file, bool writable, bool program_header_only)
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::ElfFileImpl(File* file, bool writable, bool program_header_only)
   : file_(file),
     writable_(writable),
     program_header_only_(program_header_only),
@@ -128,9 +134,20 @@
   CHECK(file != nullptr);
 }
 
-ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only,
-                       std::string* error_msg) {
-  std::unique_ptr<ElfFile> elf_file(new ElfFile(file, writable, program_header_only));
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>*
+    ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::Open(File* file, bool writable, bool program_header_only,
+           std::string* error_msg) {
+  std::unique_ptr<ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>>
+    elf_file(new ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+                 Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+                 (file, writable, program_header_only));
   int prot;
   int flags;
   if (writable) {
@@ -146,15 +163,31 @@
   return elf_file.release();
 }
 
-ElfFile* ElfFile::Open(File* file, int prot, int flags, std::string* error_msg) {
-  std::unique_ptr<ElfFile> elf_file(new ElfFile(file, (prot & PROT_WRITE) == PROT_WRITE, false));
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>*
+    ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::Open(File* file, int prot, int flags, std::string* error_msg) {
+  std::unique_ptr<ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>>
+    elf_file(new ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+                 Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+                 (file, (prot & PROT_WRITE) == PROT_WRITE, false));
   if (!elf_file->Setup(prot, flags, error_msg)) {
     return nullptr;
   }
   return elf_file.release();
 }
 
-bool ElfFile::Setup(int prot, int flags, std::string* error_msg) {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::Setup(int prot, int flags, std::string* error_msg) {
   int64_t temp_file_length = file_->GetLength();
   if (temp_file_length < 0) {
     errno = -temp_file_length;
@@ -163,16 +196,16 @@
     return false;
   }
   size_t file_length = static_cast<size_t>(temp_file_length);
-  if (file_length < sizeof(Elf32_Ehdr)) {
+  if (file_length < sizeof(Elf_Ehdr)) {
     *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF header of "
-                              "%zd bytes: '%s'", file_length, sizeof(Elf32_Ehdr),
+                              "%zd bytes: '%s'", file_length, sizeof(Elf_Ehdr),
                               file_->GetPath().c_str());
     return false;
   }
 
   if (program_header_only_) {
     // first just map ELF header to get program header size information
-    size_t elf_header_size = sizeof(Elf32_Ehdr);
+    size_t elf_header_size = sizeof(Elf_Ehdr);
     if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, file_->Fd(), 0,
                                 file_->GetPath().c_str(), error_msg),
                 error_msg)) {
@@ -183,7 +216,7 @@
     if (file_length < program_header_size) {
       *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF program "
                                 "header of %zd bytes: '%s'", file_length,
-                                sizeof(Elf32_Ehdr), file_->GetPath().c_str());
+                                sizeof(Elf_Ehdr), file_->GetPath().c_str());
       return false;
     }
     if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file_->Fd(), 0,
@@ -215,7 +248,7 @@
     }
 
     // Find shstrtab.
-    Elf32_Shdr* shstrtab_section_header = GetSectionNameStringSection();
+    Elf_Shdr* shstrtab_section_header = GetSectionNameStringSection();
     if (shstrtab_section_header == nullptr) {
       *error_msg = StringPrintf("Failed to find shstrtab section header in ELF file: '%s'",
                                 file_->GetPath().c_str());
@@ -236,8 +269,8 @@
     }
 
     // Find other sections from section headers
-    for (Elf32_Word i = 0; i < GetSectionHeaderNum(); i++) {
-      Elf32_Shdr* section_header = GetSectionHeader(i);
+    for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) {
+      Elf_Shdr* section_header = GetSectionHeader(i);
       if (section_header == nullptr) {
         *error_msg = StringPrintf("Failed to find section header for section %d in ELF file: '%s'",
                                   i, file_->GetPath().c_str());
@@ -311,7 +344,12 @@
   return true;
 }
 
-ElfFile::~ElfFile() {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::~ElfFileImpl() {
   STLDeleteElements(&segments_);
   delete symtab_symbol_table_;
   delete dynsym_symbol_table_;
@@ -321,8 +359,13 @@
   }
 }
 
-bool ElfFile::CheckAndSet(Elf32_Off offset, const char* label,
-                          byte** target, std::string* error_msg) {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::CheckAndSet(Elf32_Off offset, const char* label,
+                  byte** target, std::string* error_msg) {
   if (Begin() + offset >= End()) {
     *error_msg = StringPrintf("Offset %d is out of range for %s in ELF file: '%s'", offset, label,
                               file_->GetPath().c_str());
@@ -332,18 +375,23 @@
   return true;
 }
 
-bool ElfFile::CheckSectionsLinked(const byte* source, const byte* target) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::CheckSectionsLinked(const byte* source, const byte* target) const {
   // Only works in whole-program mode, as we need to iterate over the sections.
   // Note that we normally can't search by type, as duplicates are allowed for most section types.
   if (program_header_only_) {
     return true;
   }
 
-  Elf32_Shdr* source_section = nullptr;
-  Elf32_Word target_index = 0;
+  Elf_Shdr* source_section = nullptr;
+  Elf_Word target_index = 0;
   bool target_found = false;
-  for (Elf32_Word i = 0; i < GetSectionHeaderNum(); i++) {
-    Elf32_Shdr* section_header = GetSectionHeader(i);
+  for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) {
+    Elf_Shdr* section_header = GetSectionHeader(i);
 
     if (Begin() + section_header->sh_offset == source) {
       // Found the source.
@@ -363,7 +411,12 @@
   return target_found && source_section != nullptr && source_section->sh_link == target_index;
 }
 
-bool ElfFile::CheckSectionsExist(std::string* error_msg) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::CheckSectionsExist(std::string* error_msg) const {
   if (!program_header_only_) {
     // If in full mode, need section headers.
     if (section_headers_start_ == nullptr) {
@@ -432,7 +485,12 @@
   return true;
 }
 
-bool ElfFile::SetMap(MemMap* map, std::string* error_msg) {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::SetMap(MemMap* map, std::string* error_msg) {
   if (map == nullptr) {
     // MemMap::Open should have already set an error.
     DCHECK(!error_msg->empty());
@@ -442,7 +500,7 @@
   CHECK(map_.get() != nullptr) << file_->GetPath();
   CHECK(map_->Begin() != nullptr) << file_->GetPath();
 
-  header_ = reinterpret_cast<Elf32_Ehdr*>(map_->Begin());
+  header_ = reinterpret_cast<Elf_Ehdr*>(map_->Begin());
   if ((ELFMAG0 != header_->e_ident[EI_MAG0])
       || (ELFMAG1 != header_->e_ident[EI_MAG1])
       || (ELFMAG2 != header_->e_ident[EI_MAG2])
@@ -456,9 +514,10 @@
                               header_->e_ident[EI_MAG3]);
     return false;
   }
-  if (ELFCLASS32 != header_->e_ident[EI_CLASS]) {
+  uint8_t elf_class = (sizeof(Elf_Addr) == sizeof(Elf64_Addr)) ? ELFCLASS64 : ELFCLASS32;
+  if (elf_class != header_->e_ident[EI_CLASS]) {
     *error_msg = StringPrintf("Failed to find expected EI_CLASS value %d in %s, found %d",
-                              ELFCLASS32,
+                              elf_class,
                               file_->GetPath().c_str(),
                               header_->e_ident[EI_CLASS]);
     return false;
@@ -495,7 +554,7 @@
     *error_msg = StringPrintf("Failed to find expected e_entry value %d in %s, found %d",
                               0,
                               file_->GetPath().c_str(),
-                              header_->e_entry);
+                              static_cast<int32_t>(header_->e_entry));
     return false;
   }
   if (0 == header_->e_phoff) {
@@ -548,15 +607,15 @@
 
   if (!program_header_only_) {
     if (header_->e_phoff >= Size()) {
-      *error_msg = StringPrintf("Failed to find e_phoff value %d less than %zd in %s",
-                                header_->e_phoff,
+      *error_msg = StringPrintf("Failed to find e_phoff value %" PRIu64 " less than %zd in %s",
+                                static_cast<uint64_t>(header_->e_phoff),
                                 Size(),
                                 file_->GetPath().c_str());
       return false;
     }
     if (header_->e_shoff >= Size()) {
-      *error_msg = StringPrintf("Failed to find e_shoff value %d less than %zd in %s",
-                                header_->e_shoff,
+      *error_msg = StringPrintf("Failed to find e_shoff value %" PRIu64 " less than %zd in %s",
+                                static_cast<uint64_t>(header_->e_shoff),
                                 Size(),
                                 file_->GetPath().c_str());
       return false;
@@ -565,39 +624,64 @@
   return true;
 }
 
-
-Elf32_Ehdr& ElfFile::GetHeader() const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Ehdr& ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetHeader() const {
   CHECK(header_ != nullptr);  // Header has been checked in SetMap. This is a sanity check.
   return *header_;
 }
 
-byte* ElfFile::GetProgramHeadersStart() const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+byte* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetProgramHeadersStart() const {
   CHECK(program_headers_start_ != nullptr);  // Header has been set in Setup. This is a sanity
                                              // check.
   return program_headers_start_;
 }
 
-byte* ElfFile::GetSectionHeadersStart() const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+byte* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSectionHeadersStart() const {
   CHECK(!program_header_only_);              // Only used in "full" mode.
   CHECK(section_headers_start_ != nullptr);  // Is checked in CheckSectionsExist. Sanity check.
   return section_headers_start_;
 }
 
-Elf32_Phdr& ElfFile::GetDynamicProgramHeader() const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Phdr& ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetDynamicProgramHeader() const {
   CHECK(dynamic_program_header_ != nullptr);  // Is checked in CheckSectionsExist. Sanity check.
   return *dynamic_program_header_;
 }
 
-Elf32_Dyn* ElfFile::GetDynamicSectionStart() const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Dyn* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetDynamicSectionStart() const {
   CHECK(dynamic_section_start_ != nullptr);  // Is checked in CheckSectionsExist. Sanity check.
   return dynamic_section_start_;
 }
 
-static bool IsSymbolSectionType(Elf32_Word section_type) {
-  return ((section_type == SHT_SYMTAB) || (section_type == SHT_DYNSYM));
-}
-
-Elf32_Sym* ElfFile::GetSymbolSectionStart(Elf32_Word section_type) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Sym* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSymbolSectionStart(Elf_Word section_type) const {
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
   switch (section_type) {
     case SHT_SYMTAB: {
@@ -615,7 +699,12 @@
   }
 }
 
-const char* ElfFile::GetStringSectionStart(Elf32_Word section_type) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+const char* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetStringSectionStart(Elf_Word section_type) const {
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
   switch (section_type) {
     case SHT_SYMTAB: {
@@ -631,7 +720,12 @@
   }
 }
 
-const char* ElfFile::GetString(Elf32_Word section_type, Elf32_Word i) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+const char* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetString(Elf_Word section_type, Elf_Word i) const {
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
   if (i == 0) {
     return nullptr;
@@ -646,19 +740,39 @@
 // WARNING: The following methods do not check for an error condition (non-existent hash section).
 //          It is the caller's job to do this.
 
-Elf32_Word* ElfFile::GetHashSectionStart() const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Word* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetHashSectionStart() const {
   return hash_section_start_;
 }
 
-Elf32_Word ElfFile::GetHashBucketNum() const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetHashBucketNum() const {
   return GetHashSectionStart()[0];
 }
 
-Elf32_Word ElfFile::GetHashChainNum() const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetHashChainNum() const {
   return GetHashSectionStart()[1];
 }
 
-Elf32_Word ElfFile::GetHashBucket(size_t i, bool* ok) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetHashBucket(size_t i, bool* ok) const {
   if (i >= GetHashBucketNum()) {
     *ok = false;
     return 0;
@@ -668,7 +782,12 @@
   return GetHashSectionStart()[2 + i];
 }
 
-Elf32_Word ElfFile::GetHashChain(size_t i, bool* ok) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetHashChain(size_t i, bool* ok) const {
   if (i >= GetHashBucketNum()) {
     *ok = false;
     return 0;
@@ -678,22 +797,37 @@
   return GetHashSectionStart()[2 + GetHashBucketNum() + i];
 }
 
-Elf32_Word ElfFile::GetProgramHeaderNum() const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetProgramHeaderNum() const {
   return GetHeader().e_phnum;
 }
 
-Elf32_Phdr* ElfFile::GetProgramHeader(Elf32_Word i) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Phdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetProgramHeader(Elf_Word i) const {
   CHECK_LT(i, GetProgramHeaderNum()) << file_->GetPath();  // Sanity check for caller.
   byte* program_header = GetProgramHeadersStart() + (i * GetHeader().e_phentsize);
   if (program_header >= End()) {
     return nullptr;  // Failure condition.
   }
-  return reinterpret_cast<Elf32_Phdr*>(program_header);
+  return reinterpret_cast<Elf_Phdr*>(program_header);
 }
 
-Elf32_Phdr* ElfFile::FindProgamHeaderByType(Elf32_Word type) const {
-  for (Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) {
-    Elf32_Phdr* program_header = GetProgramHeader(i);
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Phdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindProgamHeaderByType(Elf_Word type) const {
+  for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
+    Elf_Phdr* program_header = GetProgramHeader(i);
     if (program_header->p_type == type) {
       return program_header;
     }
@@ -701,11 +835,21 @@
   return nullptr;
 }
 
-Elf32_Word ElfFile::GetSectionHeaderNum() const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSectionHeaderNum() const {
   return GetHeader().e_shnum;
 }
 
-Elf32_Shdr* ElfFile::GetSectionHeader(Elf32_Word i) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Shdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSectionHeader(Elf_Word i) const {
   // Can only access arbitrary sections when we have the whole file, not just program header.
   // Even if we Load(), it doesn't bring in all the sections.
   CHECK(!program_header_only_) << file_->GetPath();
@@ -716,15 +860,20 @@
   if (section_header >= End()) {
     return nullptr;  // Failure condition.
   }
-  return reinterpret_cast<Elf32_Shdr*>(section_header);
+  return reinterpret_cast<Elf_Shdr*>(section_header);
 }
 
-Elf32_Shdr* ElfFile::FindSectionByType(Elf32_Word type) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Shdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindSectionByType(Elf_Word type) const {
   // Can only access arbitrary sections when we have the whole file, not just program header.
   // We could change this to switch on known types if they were detected during loading.
   CHECK(!program_header_only_) << file_->GetPath();
-  for (Elf32_Word i = 0; i < GetSectionHeaderNum(); i++) {
-    Elf32_Shdr* section_header = GetSectionHeader(i);
+  for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) {
+    Elf_Shdr* section_header = GetSectionHeader(i);
     if (section_header->sh_type == type) {
       return section_header;
     }
@@ -746,16 +895,26 @@
   return h;
 }
 
-Elf32_Shdr* ElfFile::GetSectionNameStringSection() const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Shdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSectionNameStringSection() const {
   return GetSectionHeader(GetHeader().e_shstrndx);
 }
 
-const byte* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+const byte* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindDynamicSymbolAddress(const std::string& symbol_name) const {
   // Check that we have a hash section.
   if (GetHashSectionStart() == nullptr) {
     return nullptr;  // Failure condition.
   }
-  const Elf32_Sym* sym = FindDynamicSymbol(symbol_name);
+  const Elf_Sym* sym = FindDynamicSymbol(symbol_name);
   if (sym != nullptr) {
     return base_address_ + sym->st_value;
   } else {
@@ -764,20 +923,25 @@
 }
 
 // WARNING: Only called from FindDynamicSymbolAddress. Elides check for hash section.
-const Elf32_Sym* ElfFile::FindDynamicSymbol(const std::string& symbol_name) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+const Elf_Sym* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindDynamicSymbol(const std::string& symbol_name) const {
   if (GetHashBucketNum() == 0) {
     // No dynamic symbols at all.
     return nullptr;
   }
-  Elf32_Word hash = elfhash(symbol_name.c_str());
-  Elf32_Word bucket_index = hash % GetHashBucketNum();
+  Elf_Word hash = elfhash(symbol_name.c_str());
+  Elf_Word bucket_index = hash % GetHashBucketNum();
   bool ok;
-  Elf32_Word symbol_and_chain_index = GetHashBucket(bucket_index, &ok);
+  Elf_Word symbol_and_chain_index = GetHashBucket(bucket_index, &ok);
   if (!ok) {
     return nullptr;
   }
   while (symbol_and_chain_index != 0 /* STN_UNDEF */) {
-    Elf32_Sym* symbol = GetSymbol(SHT_DYNSYM, symbol_and_chain_index);
+    Elf_Sym* symbol = GetSymbol(SHT_DYNSYM, symbol_and_chain_index);
     if (symbol == nullptr) {
       return nullptr;  // Failure condition.
     }
@@ -793,23 +957,49 @@
   return nullptr;
 }
 
-Elf32_Word ElfFile::GetSymbolNum(Elf32_Shdr& section_header) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::IsSymbolSectionType(Elf_Word section_type) {
+  return ((section_type == SHT_SYMTAB) || (section_type == SHT_DYNSYM));
+}
+
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSymbolNum(Elf_Shdr& section_header) const {
   CHECK(IsSymbolSectionType(section_header.sh_type))
       << file_->GetPath() << " " << section_header.sh_type;
   CHECK_NE(0U, section_header.sh_entsize) << file_->GetPath();
   return section_header.sh_size / section_header.sh_entsize;
 }
 
-Elf32_Sym* ElfFile::GetSymbol(Elf32_Word section_type,
-                              Elf32_Word i) const {
-  Elf32_Sym* sym_start = GetSymbolSectionStart(section_type);
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Sym* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSymbol(Elf_Word section_type,
+                Elf_Word i) const {
+  Elf_Sym* sym_start = GetSymbolSectionStart(section_type);
   if (sym_start == nullptr) {
     return nullptr;
   }
   return sym_start + i;
 }
 
-ElfFile::SymbolTable** ElfFile::GetSymbolTable(Elf32_Word section_type) {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+typename ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::SymbolTable** ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSymbolTable(Elf_Word section_type) {
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
   switch (section_type) {
     case SHT_SYMTAB: {
@@ -825,9 +1015,14 @@
   }
 }
 
-Elf32_Sym* ElfFile::FindSymbolByName(Elf32_Word section_type,
-                                     const std::string& symbol_name,
-                                     bool build_map) {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Sym* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindSymbolByName(Elf_Word section_type,
+                       const std::string& symbol_name,
+                       bool build_map) {
   CHECK(!program_header_only_) << file_->GetPath();
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
 
@@ -836,20 +1031,22 @@
     if (*symbol_table == nullptr) {
       DCHECK(build_map);
       *symbol_table = new SymbolTable;
-      Elf32_Shdr* symbol_section = FindSectionByType(section_type);
+      Elf_Shdr* symbol_section = FindSectionByType(section_type);
       if (symbol_section == nullptr) {
         return nullptr;  // Failure condition.
       }
-      Elf32_Shdr* string_section = GetSectionHeader(symbol_section->sh_link);
+      Elf_Shdr* string_section = GetSectionHeader(symbol_section->sh_link);
       if (string_section == nullptr) {
         return nullptr;  // Failure condition.
       }
       for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
-        Elf32_Sym* symbol = GetSymbol(section_type, i);
+        Elf_Sym* symbol = GetSymbol(section_type, i);
         if (symbol == nullptr) {
           return nullptr;  // Failure condition.
         }
-        unsigned char type = ELF32_ST_TYPE(symbol->st_info);
+        unsigned char type = (sizeof(Elf_Addr) == sizeof(Elf64_Addr))
+                             ? ELF64_ST_TYPE(symbol->st_info)
+                             : ELF32_ST_TYPE(symbol->st_info);
         if (type == STT_NOTYPE) {
           continue;
         }
@@ -857,7 +1054,7 @@
         if (name == nullptr) {
           continue;
         }
-        std::pair<SymbolTable::iterator, bool> result =
+        std::pair<typename SymbolTable::iterator, bool> result =
             (*symbol_table)->insert(std::make_pair(name, symbol));
         if (!result.second) {
           // If a duplicate, make sure it has the same logical value. Seen on x86.
@@ -872,7 +1069,7 @@
       }
     }
     CHECK(*symbol_table != nullptr);
-    SymbolTable::const_iterator it = (*symbol_table)->find(symbol_name);
+    typename SymbolTable::const_iterator it = (*symbol_table)->find(symbol_name);
     if (it == (*symbol_table)->end()) {
       return nullptr;
     }
@@ -880,16 +1077,16 @@
   }
 
   // Fall back to linear search
-  Elf32_Shdr* symbol_section = FindSectionByType(section_type);
+  Elf_Shdr* symbol_section = FindSectionByType(section_type);
   if (symbol_section == nullptr) {
     return nullptr;
   }
-  Elf32_Shdr* string_section = GetSectionHeader(symbol_section->sh_link);
+  Elf_Shdr* string_section = GetSectionHeader(symbol_section->sh_link);
   if (string_section == nullptr) {
     return nullptr;
   }
   for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
-    Elf32_Sym* symbol = GetSymbol(section_type, i);
+    Elf_Sym* symbol = GetSymbol(section_type, i);
     if (symbol == nullptr) {
       return nullptr;  // Failure condition.
     }
@@ -904,20 +1101,30 @@
   return nullptr;
 }
 
-Elf32_Addr ElfFile::FindSymbolAddress(Elf32_Word section_type,
-                                      const std::string& symbol_name,
-                                      bool build_map) {
-  Elf32_Sym* symbol = FindSymbolByName(section_type, symbol_name, build_map);
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Addr ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindSymbolAddress(Elf_Word section_type,
+                        const std::string& symbol_name,
+                        bool build_map) {
+  Elf_Sym* symbol = FindSymbolByName(section_type, symbol_name, build_map);
   if (symbol == nullptr) {
     return 0;
   }
   return symbol->st_value;
 }
 
-const char* ElfFile::GetString(Elf32_Shdr& string_section, Elf32_Word i) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+const char* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetString(Elf_Shdr& string_section, Elf_Word i) const {
   CHECK(!program_header_only_) << file_->GetPath();
   // TODO: remove this static_cast from enum when using -std=gnu++0x
-  if (static_cast<Elf32_Word>(SHT_STRTAB) != string_section.sh_type) {
+  if (static_cast<Elf_Word>(SHT_STRTAB) != string_section.sh_type) {
     return nullptr;  // Failure condition.
   }
   if (i >= string_section.sh_size) {
@@ -934,18 +1141,33 @@
   return reinterpret_cast<const char*>(string);
 }
 
-Elf32_Word ElfFile::GetDynamicNum() const {
-  return GetDynamicProgramHeader().p_filesz / sizeof(Elf32_Dyn);
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetDynamicNum() const {
+  return GetDynamicProgramHeader().p_filesz / sizeof(Elf_Dyn);
 }
 
-Elf32_Dyn& ElfFile::GetDynamic(Elf32_Word i) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Dyn& ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetDynamic(Elf_Word i) const {
   CHECK_LT(i, GetDynamicNum()) << file_->GetPath();
   return *(GetDynamicSectionStart() + i);
 }
 
-Elf32_Dyn* ElfFile::FindDynamicByType(Elf32_Sword type) const {
-  for (Elf32_Word i = 0; i < GetDynamicNum(); i++) {
-    Elf32_Dyn* dyn = &GetDynamic(i);
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Dyn* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindDynamicByType(Elf_Sword type) const {
+  for (Elf_Word i = 0; i < GetDynamicNum(); i++) {
+    Elf_Dyn* dyn = &GetDynamic(i);
     if (dyn->d_tag == type) {
       return dyn;
     }
@@ -953,8 +1175,13 @@
   return NULL;
 }
 
-Elf32_Word ElfFile::FindDynamicValueByType(Elf32_Sword type) const {
-  Elf32_Dyn* dyn = FindDynamicByType(type);
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindDynamicValueByType(Elf_Sword type) const {
+  Elf_Dyn* dyn = FindDynamicByType(type);
   if (dyn == NULL) {
     return 0;
   } else {
@@ -962,53 +1189,88 @@
   }
 }
 
-Elf32_Rel* ElfFile::GetRelSectionStart(Elf32_Shdr& section_header) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Rel* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetRelSectionStart(Elf_Shdr& section_header) const {
   CHECK(SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
-  return reinterpret_cast<Elf32_Rel*>(Begin() + section_header.sh_offset);
+  return reinterpret_cast<Elf_Rel*>(Begin() + section_header.sh_offset);
 }
 
-Elf32_Word ElfFile::GetRelNum(Elf32_Shdr& section_header) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetRelNum(Elf_Shdr& section_header) const {
   CHECK(SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
   CHECK_NE(0U, section_header.sh_entsize) << file_->GetPath();
   return section_header.sh_size / section_header.sh_entsize;
 }
 
-Elf32_Rel& ElfFile::GetRel(Elf32_Shdr& section_header, Elf32_Word i) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Rel& ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetRel(Elf_Shdr& section_header, Elf_Word i) const {
   CHECK(SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
   CHECK_LT(i, GetRelNum(section_header)) << file_->GetPath();
   return *(GetRelSectionStart(section_header) + i);
 }
 
-Elf32_Rela* ElfFile::GetRelaSectionStart(Elf32_Shdr& section_header) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Rela* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+  Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+  ::GetRelaSectionStart(Elf_Shdr& section_header) const {
   CHECK(SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
-  return reinterpret_cast<Elf32_Rela*>(Begin() + section_header.sh_offset);
+  return reinterpret_cast<Elf_Rela*>(Begin() + section_header.sh_offset);
 }
 
-Elf32_Word ElfFile::GetRelaNum(Elf32_Shdr& section_header) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetRelaNum(Elf_Shdr& section_header) const {
   CHECK(SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
   return section_header.sh_size / section_header.sh_entsize;
 }
 
-Elf32_Rela& ElfFile::GetRela(Elf32_Shdr& section_header, Elf32_Word i) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Rela& ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetRela(Elf_Shdr& section_header, Elf_Word i) const {
   CHECK(SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
   CHECK_LT(i, GetRelaNum(section_header)) << file_->GetPath();
   return *(GetRelaSectionStart(section_header) + i);
 }
 
 // Base on bionic phdr_table_get_load_size
-size_t ElfFile::GetLoadedSize() const {
-  Elf32_Addr min_vaddr = 0xFFFFFFFFu;
-  Elf32_Addr max_vaddr = 0x00000000u;
-  for (Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) {
-    Elf32_Phdr* program_header = GetProgramHeader(i);
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+size_t ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetLoadedSize() const {
+  Elf_Addr min_vaddr = 0xFFFFFFFFu;
+  Elf_Addr max_vaddr = 0x00000000u;
+  for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
+    Elf_Phdr* program_header = GetProgramHeader(i);
     if (program_header->p_type != PT_LOAD) {
       continue;
     }
-    Elf32_Addr begin_vaddr = program_header->p_vaddr;
+    Elf_Addr begin_vaddr = program_header->p_vaddr;
     if (begin_vaddr < min_vaddr) {
        min_vaddr = begin_vaddr;
     }
-    Elf32_Addr end_vaddr = program_header->p_vaddr + program_header->p_memsz;
+    Elf_Addr end_vaddr = program_header->p_vaddr + program_header->p_memsz;
     if (end_vaddr > max_vaddr) {
       max_vaddr = end_vaddr;
     }
@@ -1020,7 +1282,12 @@
   return loaded_size;
 }
 
-bool ElfFile::Load(bool executable, std::string* error_msg) {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::Load(bool executable, std::string* error_msg) {
   CHECK(program_header_only_) << file_->GetPath();
 
   if (executable) {
@@ -1057,8 +1324,8 @@
   }
 
   bool reserved = false;
-  for (Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) {
-    Elf32_Phdr* program_header = GetProgramHeader(i);
+  for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
+    Elf_Phdr* program_header = GetProgramHeader(i);
     if (program_header == nullptr) {
       *error_msg = StringPrintf("No program header for entry %d in ELF file %s.",
                                 i, file_->GetPath().c_str());
@@ -1137,8 +1404,8 @@
     }
     if (file_length < (program_header->p_offset + program_header->p_memsz)) {
       *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF segment "
-                                "%d of %d bytes: '%s'", file_length, i,
-                                program_header->p_offset + program_header->p_memsz,
+                                "%d of %" PRIu64 " bytes: '%s'", file_length, i,
+                                static_cast<uint64_t>(program_header->p_offset + program_header->p_memsz),
                                 file_->GetPath().c_str());
       return false;
     }
@@ -1170,10 +1437,10 @@
                               file_->GetPath().c_str());
     return false;
   }
-  dynamic_section_start_ = reinterpret_cast<Elf32_Dyn*>(dsptr);
+  dynamic_section_start_ = reinterpret_cast<Elf_Dyn*>(dsptr);
 
-  for (Elf32_Word i = 0; i < GetDynamicNum(); i++) {
-    Elf32_Dyn& elf_dyn = GetDynamic(i);
+  for (Elf_Word i = 0; i < GetDynamicNum(); i++) {
+    Elf_Dyn& elf_dyn = GetDynamic(i);
     byte* d_ptr = base_address_ + elf_dyn.d_un.d_ptr;
     switch (elf_dyn.d_tag) {
       case DT_HASH: {
@@ -1182,7 +1449,7 @@
                                     d_ptr, file_->GetPath().c_str());
           return false;
         }
-        hash_section_start_ = reinterpret_cast<Elf32_Word*>(d_ptr);
+        hash_section_start_ = reinterpret_cast<Elf_Word*>(d_ptr);
         break;
       }
       case DT_STRTAB: {
@@ -1200,7 +1467,7 @@
                                     d_ptr, file_->GetPath().c_str());
           return false;
         }
-        dynsym_section_start_ = reinterpret_cast<Elf32_Sym*>(d_ptr);
+        dynsym_section_start_ = reinterpret_cast<Elf_Sym*>(d_ptr);
         break;
       }
       case DT_NULL: {
@@ -1228,7 +1495,12 @@
   return true;
 }
 
-bool ElfFile::ValidPointer(const byte* start) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::ValidPointer(const byte* start) const {
   for (size_t i = 0; i < segments_.size(); ++i) {
     const MemMap* segment = segments_[i];
     if (segment->Begin() <= start && start < segment->End()) {
@@ -1239,14 +1511,19 @@
 }
 
 
-Elf32_Shdr* ElfFile::FindSectionByName(const std::string& name) const {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+Elf_Shdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindSectionByName(const std::string& name) const {
   CHECK(!program_header_only_);
-  Elf32_Shdr* shstrtab_sec = GetSectionNameStringSection();
+  Elf_Shdr* shstrtab_sec = GetSectionNameStringSection();
   if (shstrtab_sec == nullptr) {
     return nullptr;
   }
   for (uint32_t i = 0; i < GetSectionHeaderNum(); i++) {
-    Elf32_Shdr* shdr = GetSectionHeader(i);
+    Elf_Shdr* shdr = GetSectionHeader(i);
     if (shdr == nullptr) {
       return nullptr;
     }
@@ -1731,14 +2008,19 @@
   return true;
 }
 
-bool ElfFile::FixupDebugSections(off_t base_address_delta) {
-  const Elf32_Shdr* debug_info = FindSectionByName(".debug_info");
-  const Elf32_Shdr* debug_abbrev = FindSectionByName(".debug_abbrev");
-  const Elf32_Shdr* eh_frame = FindSectionByName(".eh_frame");
-  const Elf32_Shdr* debug_str = FindSectionByName(".debug_str");
-  const Elf32_Shdr* debug_line = FindSectionByName(".debug_line");
-  const Elf32_Shdr* strtab_sec = FindSectionByName(".strtab");
-  const Elf32_Shdr* symtab_sec = FindSectionByName(".symtab");
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FixupDebugSections(off_t base_address_delta) {
+  const Elf_Shdr* debug_info = FindSectionByName(".debug_info");
+  const Elf_Shdr* debug_abbrev = FindSectionByName(".debug_abbrev");
+  const Elf_Shdr* eh_frame = FindSectionByName(".eh_frame");
+  const Elf_Shdr* debug_str = FindSectionByName(".debug_str");
+  const Elf_Shdr* debug_line = FindSectionByName(".debug_line");
+  const Elf_Shdr* strtab_sec = FindSectionByName(".strtab");
+  const Elf_Shdr* symtab_sec = FindSectionByName(".symtab");
 
   if (debug_info == nullptr || debug_abbrev == nullptr ||
       debug_str == nullptr || strtab_sec == nullptr || symtab_sec == nullptr) {
@@ -1781,7 +2063,12 @@
   return FixupDebugInfo(base_address_delta, info_iter.get());
 }
 
-void ElfFile::GdbJITSupport() {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+void ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GdbJITSupport() {
   // We only get here if we only are mapping the program header.
   DCHECK(program_header_only_);
 
@@ -1789,15 +2076,18 @@
   std::string error_msg;
   // Make it MAP_PRIVATE so we can just give it to gdb if all the necessary
   // sections are there.
-  std::unique_ptr<ElfFile> all_ptr(Open(const_cast<File*>(file_), PROT_READ | PROT_WRITE,
-                                        MAP_PRIVATE, &error_msg));
+  std::unique_ptr<ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+      Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>>
+      all_ptr(Open(const_cast<File*>(file_), PROT_READ | PROT_WRITE,
+                   MAP_PRIVATE, &error_msg));
   if (all_ptr.get() == nullptr) {
     return;
   }
-  ElfFile& all = *all_ptr;
+  ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+      Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>& all = *all_ptr;
 
   // We need the eh_frame for gdb but debug info might be present without it.
-  const Elf32_Shdr* eh_frame = all.FindSectionByName(".eh_frame");
+  const Elf_Shdr* eh_frame = all.FindSectionByName(".eh_frame");
   if (eh_frame == nullptr) {
     return;
   }
@@ -1806,7 +2096,7 @@
   // We need to add in a strtab and symtab to the image.
   // all is MAP_PRIVATE so it can be written to freely.
   // We also already have strtab and symtab so we are fine there.
-  Elf32_Ehdr& elf_hdr = all.GetHeader();
+  Elf_Ehdr& elf_hdr = all.GetHeader();
   elf_hdr.e_entry = 0;
   elf_hdr.e_phoff = 0;
   elf_hdr.e_phnum = 0;
@@ -1824,4 +2114,477 @@
   gdb_file_mapping_.reset(all_ptr.release());
 }
 
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::Strip(std::string* error_msg) {
+  // ELF files produced by MCLinker look roughly like this
+  //
+  // +------------+
+  // | Elf_Ehdr   | contains number of Elf_Shdr and offset to first
+  // +------------+
+  // | Elf_Phdr   | program headers
+  // | Elf_Phdr   |
+  // | ...        |
+  // | Elf_Phdr   |
+  // +------------+
+  // | section    | mixture of needed and unneeded sections
+  // +------------+
+  // | section    |
+  // +------------+
+  // | ...        |
+  // +------------+
+  // | section    |
+  // +------------+
+  // | Elf_Shdr   | section headers
+  // | Elf_Shdr   |
+  // | ...        | contains offset to section start
+  // | Elf_Shdr   |
+  // +------------+
+  //
+  // To strip:
+  // - leave the Elf_Ehdr and Elf_Phdr values in place.
+  // - walk the sections making a new set of Elf_Shdr section headers for what we want to keep
+  // - move the sections are keeping up to fill in gaps of sections we want to strip
+  // - write new Elf_Shdr section headers to end of file, updating Elf_Ehdr
+  // - truncate rest of file
+  //
+
+  std::vector<Elf_Shdr> section_headers;
+  std::vector<Elf_Word> section_headers_original_indexes;
+  section_headers.reserve(GetSectionHeaderNum());
+
+
+  Elf_Shdr* string_section = GetSectionNameStringSection();
+  CHECK(string_section != nullptr);
+  for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) {
+    Elf_Shdr* sh = GetSectionHeader(i);
+    CHECK(sh != nullptr);
+    const char* name = GetString(*string_section, sh->sh_name);
+    if (name == nullptr) {
+      CHECK_EQ(0U, i);
+      section_headers.push_back(*sh);
+      section_headers_original_indexes.push_back(0);
+      continue;
+    }
+    if (StartsWith(name, ".debug")
+        || (strcmp(name, ".strtab") == 0)
+        || (strcmp(name, ".symtab") == 0)) {
+      continue;
+    }
+    section_headers.push_back(*sh);
+    section_headers_original_indexes.push_back(i);
+  }
+  CHECK_NE(0U, section_headers.size());
+  CHECK_EQ(section_headers.size(), section_headers_original_indexes.size());
+
+  // section 0 is the NULL section, sections start at offset of first section
+  CHECK(GetSectionHeader(1) != nullptr);
+  Elf_Off offset = GetSectionHeader(1)->sh_offset;
+  for (size_t i = 1; i < section_headers.size(); i++) {
+    Elf_Shdr& new_sh = section_headers[i];
+    Elf_Shdr* old_sh = GetSectionHeader(section_headers_original_indexes[i]);
+    CHECK(old_sh != nullptr);
+    CHECK_EQ(new_sh.sh_name, old_sh->sh_name);
+    if (old_sh->sh_addralign > 1) {
+      offset = RoundUp(offset, old_sh->sh_addralign);
+    }
+    if (old_sh->sh_offset == offset) {
+      // already in place
+      offset += old_sh->sh_size;
+      continue;
+    }
+    // shift section earlier
+    memmove(Begin() + offset,
+            Begin() + old_sh->sh_offset,
+            old_sh->sh_size);
+    new_sh.sh_offset = offset;
+    offset += old_sh->sh_size;
+  }
+
+  Elf_Off shoff = offset;
+  size_t section_headers_size_in_bytes = section_headers.size() * sizeof(Elf_Shdr);
+  memcpy(Begin() + offset, &section_headers[0], section_headers_size_in_bytes);
+  offset += section_headers_size_in_bytes;
+
+  GetHeader().e_shnum = section_headers.size();
+  GetHeader().e_shoff = shoff;
+  int result = ftruncate(file_->Fd(), offset);
+  if (result != 0) {
+    *error_msg = StringPrintf("Failed to truncate while stripping ELF file: '%s': %s",
+                              file_->GetPath().c_str(), strerror(errno));
+    return false;
+  }
+  return true;
+}
+
+static const bool DEBUG_FIXUP = false;
+
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::Fixup(uintptr_t base_address) {
+  if (!FixupDynamic(base_address)) {
+    LOG(WARNING) << "Failed to fixup .dynamic in " << file_->GetPath();
+    return false;
+  }
+  if (!FixupSectionHeaders(base_address)) {
+    LOG(WARNING) << "Failed to fixup section headers in " << file_->GetPath();
+    return false;
+  }
+  if (!FixupProgramHeaders(base_address)) {
+    LOG(WARNING) << "Failed to fixup program headers in " << file_->GetPath();
+    return false;
+  }
+  if (!FixupSymbols(base_address, true)) {
+    LOG(WARNING) << "Failed to fixup .dynsym in " << file_->GetPath();
+    return false;
+  }
+  if (!FixupSymbols(base_address, false)) {
+    LOG(WARNING) << "Failed to fixup .symtab in " << file_->GetPath();
+    return false;
+  }
+  if (!FixupRelocations(base_address)) {
+    LOG(WARNING) << "Failed to fixup .rel.dyn in " << file_->GetPath();
+    return false;
+  }
+  if (!FixupDebugSections(base_address)) {
+    LOG(WARNING) << "Failed to fixup debug sections in " << file_->GetPath();
+    return false;
+  }
+  return true;
+}
+
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FixupDynamic(uintptr_t base_address) {
+  for (Elf_Word i = 0; i < GetDynamicNum(); i++) {
+    Elf_Dyn& elf_dyn = GetDynamic(i);
+    Elf_Word d_tag = elf_dyn.d_tag;
+    if (IsDynamicSectionPointer(d_tag, GetHeader().e_machine)) {
+      Elf_Addr d_ptr = elf_dyn.d_un.d_ptr;
+      if (DEBUG_FIXUP) {
+        LOG(INFO) << StringPrintf("In %s moving Elf_Dyn[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
+                                  GetFile().GetPath().c_str(), i,
+                                  static_cast<uint64_t>(d_ptr),
+                                  static_cast<uint64_t>(d_ptr + base_address));
+      }
+      d_ptr += base_address;
+      elf_dyn.d_un.d_ptr = d_ptr;
+    }
+  }
+  return true;
+}
+
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FixupSectionHeaders(uintptr_t base_address) {
+  for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) {
+    Elf_Shdr* sh = GetSectionHeader(i);
+    CHECK(sh != nullptr);
+    // 0 implies that the section will not exist in the memory of the process
+    if (sh->sh_addr == 0) {
+      continue;
+    }
+    if (DEBUG_FIXUP) {
+      LOG(INFO) << StringPrintf("In %s moving Elf_Shdr[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
+                                GetFile().GetPath().c_str(), i,
+                                static_cast<uint64_t>(sh->sh_addr),
+                                static_cast<uint64_t>(sh->sh_addr + base_address));
+    }
+    sh->sh_addr += base_address;
+  }
+  return true;
+}
+
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FixupProgramHeaders(uintptr_t base_address) {
+  // TODO: ELFObjectFile doesn't have give to Elf_Phdr, so we do that ourselves for now.
+  for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
+    Elf_Phdr* ph = GetProgramHeader(i);
+    CHECK(ph != nullptr);
+    CHECK_EQ(ph->p_vaddr, ph->p_paddr) << GetFile().GetPath() << " i=" << i;
+    CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1))))
+            << GetFile().GetPath() << " i=" << i;
+    if (DEBUG_FIXUP) {
+      LOG(INFO) << StringPrintf("In %s moving Elf_Phdr[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
+                                GetFile().GetPath().c_str(), i,
+                                static_cast<uint64_t>(ph->p_vaddr),
+                                static_cast<uint64_t>(ph->p_vaddr + base_address));
+    }
+    ph->p_vaddr += base_address;
+    ph->p_paddr += base_address;
+    CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1))))
+            << GetFile().GetPath() << " i=" << i;
+  }
+  return true;
+}
+
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FixupSymbols(uintptr_t base_address, bool dynamic) {
+  Elf_Word section_type = dynamic ? SHT_DYNSYM : SHT_SYMTAB;
+  // TODO: Unfortunate ELFObjectFile has protected symbol access, so use ElfFile
+  Elf_Shdr* symbol_section = FindSectionByType(section_type);
+  if (symbol_section == nullptr) {
+    // file is missing optional .symtab
+    CHECK(!dynamic) << GetFile().GetPath();
+    return true;
+  }
+  for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
+    Elf_Sym* symbol = GetSymbol(section_type, i);
+    CHECK(symbol != nullptr);
+    if (symbol->st_value != 0) {
+      if (DEBUG_FIXUP) {
+        LOG(INFO) << StringPrintf("In %s moving Elf_Sym[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
+                                  GetFile().GetPath().c_str(), i,
+                                  static_cast<uint64_t>(symbol->st_value),
+                                  static_cast<uint64_t>(symbol->st_value + base_address));
+      }
+      symbol->st_value += base_address;
+    }
+  }
+  return true;
+}
+
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FixupRelocations(uintptr_t base_address) {
+  for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) {
+    Elf_Shdr* sh = GetSectionHeader(i);
+    CHECK(sh != nullptr);
+    if (sh->sh_type == SHT_REL) {
+      for (uint32_t i = 0; i < GetRelNum(*sh); i++) {
+        Elf_Rel& rel = GetRel(*sh, i);
+        if (DEBUG_FIXUP) {
+          LOG(INFO) << StringPrintf("In %s moving Elf_Rel[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
+                                    GetFile().GetPath().c_str(), i,
+                                    static_cast<uint64_t>(rel.r_offset),
+                                    static_cast<uint64_t>(rel.r_offset + base_address));
+        }
+        rel.r_offset += base_address;
+      }
+    } else if (sh->sh_type == SHT_RELA) {
+      for (uint32_t i = 0; i < GetRelaNum(*sh); i++) {
+        Elf_Rela& rela = GetRela(*sh, i);
+        if (DEBUG_FIXUP) {
+          LOG(INFO) << StringPrintf("In %s moving Elf_Rela[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
+                                    GetFile().GetPath().c_str(), i,
+                                    static_cast<uint64_t>(rela.r_offset),
+                                    static_cast<uint64_t>(rela.r_offset + base_address));
+        }
+        rela.r_offset += base_address;
+      }
+    }
+  }
+  return true;
+}
+
+// Explicit instantiations
+template class ElfFileImpl<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Word,
+    Elf32_Sword, Elf32_Addr, Elf32_Sym, Elf32_Rel, Elf32_Rela, Elf32_Dyn, Elf32_Off>;
+template class ElfFileImpl<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Word,
+    Elf64_Sword, Elf64_Addr, Elf64_Sym, Elf64_Rel, Elf64_Rela, Elf64_Dyn, Elf64_Off>;
+
+ElfFile::ElfFile(ElfFileImpl32* elf32) : is_elf64_(false) {
+  CHECK_NE(elf32, static_cast<ElfFileImpl32*>(nullptr));
+  elf_.elf32_ = elf32;
+}
+
+ElfFile::ElfFile(ElfFileImpl64* elf64) : is_elf64_(true) {
+  CHECK_NE(elf64, static_cast<ElfFileImpl64*>(nullptr));
+  elf_.elf64_ = elf64;
+}
+
+ElfFile::~ElfFile() {
+  if (is_elf64_) {
+    CHECK_NE(elf_.elf64_, static_cast<ElfFileImpl64*>(nullptr));
+    delete elf_.elf64_;
+  } else {
+    CHECK_NE(elf_.elf32_, static_cast<ElfFileImpl32*>(nullptr));
+    delete elf_.elf32_;
+  }
+}
+
+ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only, std::string* error_msg) {
+  if (file->GetLength() < EI_NIDENT) {
+    *error_msg = StringPrintf("File %s is too short to be a valid ELF file",
+                              file->GetPath().c_str());
+    return nullptr;
+  }
+  std::unique_ptr<MemMap> map(MemMap::MapFile(EI_NIDENT, PROT_READ, MAP_PRIVATE, file->Fd(), 0,
+                                              file->GetPath().c_str(), error_msg));
+  if (map == nullptr && map->Size() != EI_NIDENT) {
+    return nullptr;
+  }
+  byte *header = map->Begin();
+  if (header[EI_CLASS] == ELFCLASS64) {
+    ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file, writable, program_header_only, error_msg);
+    if (elf_file_impl == nullptr)
+      return nullptr;
+    return new ElfFile(elf_file_impl);
+  } else if (header[EI_CLASS] == ELFCLASS32) {
+    ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file, writable, program_header_only, error_msg);
+    if (elf_file_impl == nullptr)
+      return nullptr;
+    return new ElfFile(elf_file_impl);
+  } else {
+    *error_msg = StringPrintf("Failed to find expected EI_CLASS value %d or %d in %s, found %d",
+                              ELFCLASS32, ELFCLASS64,
+                              file->GetPath().c_str(),
+                              header[EI_CLASS]);
+    return nullptr;
+  }
+}
+
+ElfFile* ElfFile::Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg) {
+  if (file->GetLength() < EI_NIDENT) {
+    *error_msg = StringPrintf("File %s is too short to be a valid ELF file",
+                              file->GetPath().c_str());
+    return nullptr;
+  }
+  std::unique_ptr<MemMap> map(MemMap::MapFile(EI_NIDENT, PROT_READ, MAP_PRIVATE, file->Fd(), 0,
+                                              file->GetPath().c_str(), error_msg));
+  if (map == nullptr && map->Size() != EI_NIDENT) {
+    return nullptr;
+  }
+  byte *header = map->Begin();
+  if (header[EI_CLASS] == ELFCLASS64) {
+    ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file, mmap_prot, mmap_flags, error_msg);
+    if (elf_file_impl == nullptr)
+      return nullptr;
+    return new ElfFile(elf_file_impl);
+  } else if (header[EI_CLASS] == ELFCLASS32) {
+    ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file, mmap_prot, mmap_flags, error_msg);
+    if (elf_file_impl == nullptr)
+      return nullptr;
+    return new ElfFile(elf_file_impl);
+  } else {
+    *error_msg = StringPrintf("Failed to find expected EI_CLASS value %d or %d in %s, found %d",
+                              ELFCLASS32, ELFCLASS64,
+                              file->GetPath().c_str(),
+                              header[EI_CLASS]);
+    return nullptr;
+  }
+}
+
+#define DELEGATE_TO_IMPL(func, ...) \
+  if (is_elf64_) { \
+    CHECK_NE(elf_.elf64_, static_cast<ElfFileImpl64*>(nullptr)); \
+    return elf_.elf64_->func(__VA_ARGS__); \
+  } else { \
+    CHECK_NE(elf_.elf32_, static_cast<ElfFileImpl32*>(nullptr)); \
+    return elf_.elf32_->func(__VA_ARGS__); \
+  }
+
+bool ElfFile::Load(bool executable, std::string* error_msg) {
+  DELEGATE_TO_IMPL(Load, executable, error_msg);
+}
+
+const byte* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) const {
+  DELEGATE_TO_IMPL(FindDynamicSymbolAddress, symbol_name);
+}
+
+size_t ElfFile::Size() const {
+  DELEGATE_TO_IMPL(Size);
+}
+
+byte* ElfFile::Begin() const {
+  DELEGATE_TO_IMPL(Begin);
+}
+
+byte* ElfFile::End() const {
+  DELEGATE_TO_IMPL(End);
+}
+
+const File& ElfFile::GetFile() const {
+  DELEGATE_TO_IMPL(GetFile);
+}
+
+bool ElfFile::GetSectionOffsetAndSize(const char* section_name, uint64_t* offset, uint64_t* size) {
+  if (is_elf64_) {
+    CHECK_NE(elf_.elf64_, static_cast<ElfFileImpl64*>(nullptr));
+
+    Elf64_Shdr *shdr = elf_.elf64_->FindSectionByName(section_name);
+    if (shdr == nullptr)
+      return false;
+
+    if (offset != nullptr)
+      *offset = shdr->sh_offset;
+    if (size != nullptr)
+      *size = shdr->sh_size;
+    return true;
+  } else {
+    CHECK_NE(elf_.elf32_, static_cast<ElfFileImpl32*>(nullptr));
+
+    Elf32_Shdr *shdr = elf_.elf32_->FindSectionByName(section_name);
+    if (shdr == nullptr)
+      return false;
+
+    if (offset != nullptr)
+      *offset = shdr->sh_offset;
+    if (size != nullptr)
+      *size = shdr->sh_size;
+    return true;
+  }
+}
+
+uint64_t ElfFile::FindSymbolAddress(unsigned section_type,
+                                    const std::string& symbol_name,
+                                    bool build_map) {
+  DELEGATE_TO_IMPL(FindSymbolAddress, section_type, symbol_name, build_map);
+}
+
+size_t ElfFile::GetLoadedSize() const {
+  DELEGATE_TO_IMPL(GetLoadedSize);
+}
+
+bool ElfFile::Strip(File* file, std::string* error_msg) {
+  std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, error_msg));
+  if (elf_file.get() == nullptr) {
+    return false;
+  }
+
+  if (elf_file->is_elf64_)
+    return elf_file->elf_.elf64_->Strip(error_msg);
+  else
+    return elf_file->elf_.elf32_->Strip(error_msg);
+}
+
+bool ElfFile::Fixup(uintptr_t base_address) {
+  DELEGATE_TO_IMPL(Fixup, base_address);
+}
+
+ElfFileImpl32* ElfFile::GetImpl32() const {
+  CHECK(!is_elf64_);
+  CHECK_NE(elf_.elf32_, static_cast<ElfFileImpl32*>(nullptr));
+  return elf_.elf32_;
+}
+
+ElfFileImpl64* ElfFile::GetImpl64() const {
+  CHECK(is_elf64_);
+  CHECK_NE(elf_.elf64_, static_cast<ElfFileImpl64*>(nullptr));
+  return elf_.elf64_;
+}
+
 }  // namespace art
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index 916d693..ea6538b 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -17,24 +17,13 @@
 #ifndef ART_RUNTIME_ELF_FILE_H_
 #define ART_RUNTIME_ELF_FILE_H_
 
-#include <map>
-#include <memory>
-#include <vector>
+#include <string>
 
 #include "base/unix_file/fd_file.h"
-#include "globals.h"
-#include "elf_utils.h"
-#include "mem_map.h"
-#include "os.h"
+#include "elf_file_impl.h"
 
 namespace art {
 
-// Interface to GDB JIT for backtrace information.
-extern "C" {
-  struct JITCodeEntry;
-}
-
-
 // Used for compile time and runtime for ElfFile access. Because of
 // the need for use at runtime, cannot directly use LLVM classes such as
 // ELFObjectFile.
@@ -46,162 +35,50 @@
   static ElfFile* Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg);
   ~ElfFile();
 
+  const bool is_elf64_;
+
   // Load segments into memory based on PT_LOAD program headers
-
-  const File& GetFile() const {
-    return *file_;
-  }
-
-  byte* Begin() const {
-    return map_->Begin();
-  }
-
-  byte* End() const {
-    return map_->End();
-  }
-
-  size_t Size() const {
-    return map_->Size();
-  }
-
-  Elf32_Ehdr& GetHeader() const;
-
-  Elf32_Word GetProgramHeaderNum() const;
-  Elf32_Phdr* GetProgramHeader(Elf32_Word) const;
-
-  Elf32_Word GetSectionHeaderNum() const;
-  Elf32_Shdr* GetSectionHeader(Elf32_Word) const;
-  Elf32_Shdr* FindSectionByType(Elf32_Word type) const;
-  Elf32_Shdr* FindSectionByName(const std::string& name) const;
-
-  Elf32_Shdr* GetSectionNameStringSection() const;
-
-  // Find .dynsym using .hash for more efficient lookup than FindSymbolAddress.
-  const byte* FindDynamicSymbolAddress(const std::string& symbol_name) const;
-
-  Elf32_Word GetSymbolNum(Elf32_Shdr&) const;
-  Elf32_Sym* GetSymbol(Elf32_Word section_type, Elf32_Word i) const;
-
-  // Find address of symbol in specified table, returning 0 if it is
-  // not found. See FindSymbolByName for an explanation of build_map.
-  Elf32_Addr FindSymbolAddress(Elf32_Word section_type,
-                               const std::string& symbol_name,
-                               bool build_map);
-
-  // Lookup a string given string section and offset. Returns nullptr for
-  // special 0 offset.
-  const char* GetString(Elf32_Shdr&, Elf32_Word) const;
-
-  Elf32_Word GetDynamicNum() const;
-  Elf32_Dyn& GetDynamic(Elf32_Word) const;
-
-  Elf32_Word GetRelNum(Elf32_Shdr&) const;
-  Elf32_Rel& GetRel(Elf32_Shdr&, Elf32_Word) const;
-
-  Elf32_Word GetRelaNum(Elf32_Shdr&) const;
-  Elf32_Rela& GetRela(Elf32_Shdr&, Elf32_Word) const;
-
-  // Returns the expected size when the file is loaded at runtime
-  size_t GetLoadedSize() const;
-
-  // Load segments into memory based on PT_LOAD program headers.
-  // executable is true at run time, false at compile time.
   bool Load(bool executable, std::string* error_msg);
 
-  bool FixupDebugSections(off_t base_address_delta);
+  const byte* FindDynamicSymbolAddress(const std::string& symbol_name) const;
+
+  size_t Size() const;
+
+  byte* Begin() const;
+
+  byte* End() const;
+
+  const File& GetFile() const;
+
+  bool GetSectionOffsetAndSize(const char* section_name, uint64_t* offset, uint64_t* size);
+
+  uint64_t FindSymbolAddress(unsigned section_type,
+                             const std::string& symbol_name,
+                             bool build_map);
+
+  size_t GetLoadedSize() const;
+
+  // Strip an ELF file of unneeded debugging information.
+  // Returns true on success, false on failure.
+  static bool Strip(File* file, std::string* error_msg);
+
+  // Fixup an ELF file so that that oat header will be loaded at oat_begin.
+  // Returns true on success, false on failure.
+  static bool Fixup(File* file, uintptr_t oat_data_begin);
+
+  bool Fixup(uintptr_t base_address);
+
+  ElfFileImpl32* GetImpl32() const;
+  ElfFileImpl64* GetImpl64() const;
 
  private:
-  ElfFile(File* file, bool writable, bool program_header_only);
+  explicit ElfFile(ElfFileImpl32* elf32);
+  explicit ElfFile(ElfFileImpl64* elf64);
 
-  bool Setup(int prot, int flags, std::string* error_msg);
-
-  bool SetMap(MemMap* map, std::string* error_msg);
-
-  byte* GetProgramHeadersStart() const;
-  byte* GetSectionHeadersStart() const;
-  Elf32_Phdr& GetDynamicProgramHeader() const;
-  Elf32_Dyn* GetDynamicSectionStart() const;
-  Elf32_Sym* GetSymbolSectionStart(Elf32_Word section_type) const;
-  const char* GetStringSectionStart(Elf32_Word section_type) const;
-  Elf32_Rel* GetRelSectionStart(Elf32_Shdr&) const;
-  Elf32_Rela* GetRelaSectionStart(Elf32_Shdr&) const;
-  Elf32_Word* GetHashSectionStart() const;
-  Elf32_Word GetHashBucketNum() const;
-  Elf32_Word GetHashChainNum() const;
-  Elf32_Word GetHashBucket(size_t i, bool* ok) const;
-  Elf32_Word GetHashChain(size_t i, bool* ok) const;
-
-  typedef std::map<std::string, Elf32_Sym*> SymbolTable;
-  SymbolTable** GetSymbolTable(Elf32_Word section_type);
-
-  bool ValidPointer(const byte* start) const;
-
-  const Elf32_Sym* FindDynamicSymbol(const std::string& symbol_name) const;
-
-  // Check that certain sections and their dependencies exist.
-  bool CheckSectionsExist(std::string* error_msg) const;
-
-  // Check that the link of the first section links to the second section.
-  bool CheckSectionsLinked(const byte* source, const byte* target) const;
-
-  // Check whether the offset is in range, and set to target to Begin() + offset if OK.
-  bool CheckAndSet(Elf32_Off offset, const char* label, byte** target, std::string* error_msg);
-
-  // Find symbol in specified table, returning nullptr if it is not found.
-  //
-  // If build_map is true, builds a map to speed repeated access. The
-  // map does not included untyped symbol values (aka STT_NOTYPE)
-  // since they can contain duplicates. If build_map is false, the map
-  // will be used if it was already created. Typically build_map
-  // should be set unless only a small number of symbols will be
-  // looked up.
-  Elf32_Sym* FindSymbolByName(Elf32_Word section_type,
-                              const std::string& symbol_name,
-                              bool build_map);
-
-  Elf32_Phdr* FindProgamHeaderByType(Elf32_Word type) const;
-
-  Elf32_Dyn* FindDynamicByType(Elf32_Sword type) const;
-  Elf32_Word FindDynamicValueByType(Elf32_Sword type) const;
-
-  // Lookup a string by section type. Returns nullptr for special 0 offset.
-  const char* GetString(Elf32_Word section_type, Elf32_Word) const;
-
-  const File* const file_;
-  const bool writable_;
-  const bool program_header_only_;
-
-  // ELF header mapping. If program_header_only_ is false, will
-  // actually point to the entire elf file.
-  std::unique_ptr<MemMap> map_;
-  Elf32_Ehdr* header_;
-  std::vector<MemMap*> segments_;
-
-  // Pointer to start of first PT_LOAD program segment after Load()
-  // when program_header_only_ is true.
-  byte* base_address_;
-
-  // The program header should always available but use GetProgramHeadersStart() to be sure.
-  byte* program_headers_start_;
-
-  // Conditionally available values. Use accessors to ensure they exist if they are required.
-  byte* section_headers_start_;
-  Elf32_Phdr* dynamic_program_header_;
-  Elf32_Dyn* dynamic_section_start_;
-  Elf32_Sym* symtab_section_start_;
-  Elf32_Sym* dynsym_section_start_;
-  char* strtab_section_start_;
-  char* dynstr_section_start_;
-  Elf32_Word* hash_section_start_;
-
-  SymbolTable* symtab_symbol_table_;
-  SymbolTable* dynsym_symbol_table_;
-
-  // Support for GDB JIT
-  byte* jit_elf_image_;
-  JITCodeEntry* jit_gdb_entry_;
-  std::unique_ptr<ElfFile> gdb_file_mapping_;
-  void GdbJITSupport();
+  union ElfFileContainer {
+    ElfFileImpl32* elf32_;
+    ElfFileImpl64* elf64_;
+  } elf_;
 };
 
 }  // namespace art
diff --git a/runtime/elf_file_impl.h b/runtime/elf_file_impl.h
new file mode 100644
index 0000000..942dc291
--- /dev/null
+++ b/runtime/elf_file_impl.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_ELF_FILE_IMPL_H_
+#define ART_RUNTIME_ELF_FILE_IMPL_H_
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/unix_file/fd_file.h"
+#include "globals.h"
+#include "elf_utils.h"
+#include "mem_map.h"
+#include "os.h"
+
+namespace art {
+
+extern "C" {
+  struct JITCodeEntry;
+}
+
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+class ElfFileImpl {
+ public:
+  static ElfFileImpl* Open(File* file, bool writable, bool program_header_only, std::string* error_msg);
+  static ElfFileImpl* Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg);
+  ~ElfFileImpl();
+
+  const File& GetFile() const {
+    return *file_;
+  }
+
+  byte* Begin() const {
+    return map_->Begin();
+  }
+
+  byte* End() const {
+    return map_->End();
+  }
+
+  size_t Size() const {
+    return map_->Size();
+  }
+
+  Elf_Ehdr& GetHeader() const;
+
+  Elf_Word GetProgramHeaderNum() const;
+  Elf_Phdr* GetProgramHeader(Elf_Word) const;
+
+  Elf_Word GetSectionHeaderNum() const;
+  Elf_Shdr* GetSectionHeader(Elf_Word) const;
+  Elf_Shdr* FindSectionByType(Elf_Word type) const;
+  Elf_Shdr* FindSectionByName(const std::string& name) const;
+
+  Elf_Shdr* GetSectionNameStringSection() const;
+
+  // Find .dynsym using .hash for more efficient lookup than FindSymbolAddress.
+  const byte* FindDynamicSymbolAddress(const std::string& symbol_name) const;
+
+  static bool IsSymbolSectionType(Elf_Word section_type);
+  Elf_Word GetSymbolNum(Elf_Shdr&) const;
+  Elf_Sym* GetSymbol(Elf_Word section_type, Elf_Word i) const;
+
+  // Find address of symbol in specified table, returning 0 if it is
+  // not found. See FindSymbolByName for an explanation of build_map.
+  Elf_Addr FindSymbolAddress(Elf_Word section_type,
+                             const std::string& symbol_name,
+                             bool build_map);
+
+  // Lookup a string given string section and offset. Returns nullptr for
+  // special 0 offset.
+  const char* GetString(Elf_Shdr&, Elf_Word) const;
+
+  Elf_Word GetDynamicNum() const;
+  Elf_Dyn& GetDynamic(Elf_Word) const;
+
+  Elf_Word GetRelNum(Elf_Shdr&) const;
+  Elf_Rel& GetRel(Elf_Shdr&, Elf_Word) const;
+
+  Elf_Word GetRelaNum(Elf_Shdr&) const;
+  Elf_Rela& GetRela(Elf_Shdr&, Elf_Word) const;
+
+  // Returns the expected size when the file is loaded at runtime
+  size_t GetLoadedSize() const;
+
+  // Load segments into memory based on PT_LOAD program headers.
+  // executable is true at run time, false at compile time.
+  bool Load(bool executable, std::string* error_msg);
+
+  bool Fixup(uintptr_t base_address);
+  bool FixupDynamic(uintptr_t base_address);
+  bool FixupSectionHeaders(uintptr_t base_address);
+  bool FixupProgramHeaders(uintptr_t base_address);
+  bool FixupSymbols(uintptr_t base_address, bool dynamic);
+  bool FixupRelocations(uintptr_t base_address);
+  bool FixupDebugSections(off_t base_address_delta);
+
+  bool Strip(std::string* error_msg);
+
+ private:
+  ElfFileImpl(File* file, bool writable, bool program_header_only);
+
+  bool Setup(int prot, int flags, std::string* error_msg);
+
+  bool SetMap(MemMap* map, std::string* error_msg);
+
+  byte* GetProgramHeadersStart() const;
+  byte* GetSectionHeadersStart() const;
+  Elf_Phdr& GetDynamicProgramHeader() const;
+  Elf_Dyn* GetDynamicSectionStart() const;
+  Elf_Sym* GetSymbolSectionStart(Elf_Word section_type) const;
+  const char* GetStringSectionStart(Elf_Word section_type) const;
+  Elf_Rel* GetRelSectionStart(Elf_Shdr&) const;
+  Elf_Rela* GetRelaSectionStart(Elf_Shdr&) const;
+  Elf_Word* GetHashSectionStart() const;
+  Elf_Word GetHashBucketNum() const;
+  Elf_Word GetHashChainNum() const;
+  Elf_Word GetHashBucket(size_t i, bool* ok) const;
+  Elf_Word GetHashChain(size_t i, bool* ok) const;
+
+  typedef std::map<std::string, Elf_Sym*> SymbolTable;
+  SymbolTable** GetSymbolTable(Elf_Word section_type);
+
+  bool ValidPointer(const byte* start) const;
+
+  const Elf_Sym* FindDynamicSymbol(const std::string& symbol_name) const;
+
+  // Check that certain sections and their dependencies exist.
+  bool CheckSectionsExist(std::string* error_msg) const;
+
+  // Check that the link of the first section links to the second section.
+  bool CheckSectionsLinked(const byte* source, const byte* target) const;
+
+  // Check whether the offset is in range, and set to target to Begin() + offset if OK.
+  bool CheckAndSet(Elf32_Off offset, const char* label, byte** target, std::string* error_msg);
+
+  // Find symbol in specified table, returning nullptr if it is not found.
+  //
+  // If build_map is true, builds a map to speed repeated access. The
+  // map does not included untyped symbol values (aka STT_NOTYPE)
+  // since they can contain duplicates. If build_map is false, the map
+  // will be used if it was already created. Typically build_map
+  // should be set unless only a small number of symbols will be
+  // looked up.
+  Elf_Sym* FindSymbolByName(Elf_Word section_type,
+                            const std::string& symbol_name,
+                            bool build_map);
+
+  Elf_Phdr* FindProgamHeaderByType(Elf_Word type) const;
+
+  Elf_Dyn* FindDynamicByType(Elf_Sword type) const;
+  Elf_Word FindDynamicValueByType(Elf_Sword type) const;
+
+  // Lookup a string by section type. Returns nullptr for special 0 offset.
+  const char* GetString(Elf_Word section_type, Elf_Word) const;
+
+  const File* const file_;
+  const bool writable_;
+  const bool program_header_only_;
+
+  // ELF header mapping. If program_header_only_ is false, will
+  // actually point to the entire elf file.
+  std::unique_ptr<MemMap> map_;
+  Elf_Ehdr* header_;
+  std::vector<MemMap*> segments_;
+
+  // Pointer to start of first PT_LOAD program segment after Load()
+  // when program_header_only_ is true.
+  byte* base_address_;
+
+  // The program header should always available but use GetProgramHeadersStart() to be sure.
+  byte* program_headers_start_;
+
+  // Conditionally available values. Use accessors to ensure they exist if they are required.
+  byte* section_headers_start_;
+  Elf_Phdr* dynamic_program_header_;
+  Elf_Dyn* dynamic_section_start_;
+  Elf_Sym* symtab_section_start_;
+  Elf_Sym* dynsym_section_start_;
+  char* strtab_section_start_;
+  char* dynstr_section_start_;
+  Elf_Word* hash_section_start_;
+
+  SymbolTable* symtab_symbol_table_;
+  SymbolTable* dynsym_symbol_table_;
+
+  // Support for GDB JIT
+  byte* jit_elf_image_;
+  JITCodeEntry* jit_gdb_entry_;
+  std::unique_ptr<ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+                  Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel,
+                  Elf_Rela, Elf_Dyn, Elf_Off>> gdb_file_mapping_;
+  void GdbJITSupport();
+};
+
+// Explicitly instantiated in elf_file.cc
+typedef ElfFileImpl<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Word, Elf32_Sword,
+                    Elf32_Addr, Elf32_Sym, Elf32_Rel, Elf32_Rela, Elf32_Dyn, Elf32_Off> ElfFileImpl32;
+typedef ElfFileImpl<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Word, Elf64_Sword,
+                    Elf64_Addr, Elf64_Sym, Elf64_Rel, Elf64_Rela, Elf64_Dyn, Elf64_Off> ElfFileImpl64;
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ELF_FILE_IMPL_H_
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 661de68..3d3ae16 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -553,10 +553,6 @@
                                                              allocator_type, VoidFunctor());
   if (add_finalizer && LIKELY(obj != nullptr)) {
     heap->AddFinalizerReference(self, &obj);
-    if (UNLIKELY(self->IsExceptionPending())) {
-      // Failed to allocate finalizer reference, it means that whole allocation failed
-      obj = nullptr;
-    }
   }
   return obj;
 }
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index a896f3e..a8a8307 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -47,9 +47,11 @@
                                   std::string* error_msg) {
   std::unique_ptr<OatFile> oat_file(new OatFile(location, false));
   oat_file->elf_file_.reset(elf_file);
-  Elf32_Shdr* hdr = elf_file->FindSectionByName(".rodata");
-  oat_file->begin_ = elf_file->Begin() + hdr->sh_offset;
-  oat_file->end_ = elf_file->Begin() + hdr->sh_size + hdr->sh_offset;
+  uint64_t offset, size;
+  bool has_section = elf_file->GetSectionOffsetAndSize(".rodata", &offset, &size);
+  CHECK(has_section);
+  oat_file->begin_ = elf_file->Begin() + offset;
+  oat_file->end_ = elf_file->Begin() + size + offset;
   return oat_file->Setup(error_msg) ? oat_file.release() : nullptr;
 }
 
diff --git a/test/005-annotations/build b/test/005-annotations/build
index 1690213..2474055 100644
--- a/test/005-annotations/build
+++ b/test/005-annotations/build
@@ -23,5 +23,6 @@
 ${JAVAC} -d classes `find src -name '*.java'`
 
 # ...but not at run time.
-rm classes/android/test/anno/MissingAnnotation.class
+rm 'classes/android/test/anno/MissingAnnotation.class'
+rm 'classes/android/test/anno/ClassWithInnerAnnotationClass$MissingInnerAnnotationClass.class'
 ${DX} -JXmx256m --debug --dex --output=$TEST_NAME.jar classes
diff --git a/test/005-annotations/src/android/test/anno/ClassWithInnerAnnotationClass.java b/test/005-annotations/src/android/test/anno/ClassWithInnerAnnotationClass.java
new file mode 100644
index 0000000..c69e01a
--- /dev/null
+++ b/test/005-annotations/src/android/test/anno/ClassWithInnerAnnotationClass.java
@@ -0,0 +1,8 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+public class ClassWithInnerAnnotationClass {
+  @Retention(RetentionPolicy.SOURCE)
+  public @interface MissingInnerAnnotationClass {}
+}
diff --git a/test/005-annotations/src/android/test/anno/TestAnnotations.java b/test/005-annotations/src/android/test/anno/TestAnnotations.java
index 4eabb12..1deff33 100644
--- a/test/005-annotations/src/android/test/anno/TestAnnotations.java
+++ b/test/005-annotations/src/android/test/anno/TestAnnotations.java
@@ -149,26 +149,24 @@
 
         testArrays();
         testArrayProblem();
-        //System.exit(0);
 
         System.out.println(
             "AnnoSimpleField " + AnnoSimpleField.class.isAnnotation() +
             ", SimplyNoted " + SimplyNoted.class.isAnnotation());
 
-        Class clazz;
-        clazz = SimplyNoted.class;
-        printAnnotations(clazz);
-        clazz = INoted.class;
-        printAnnotations(clazz);
-        clazz = SubNoted.class;
-        printAnnotations(clazz);
-        clazz = FullyNoted.class;
-        printAnnotations(clazz);
+        printAnnotations(SimplyNoted.class);
+        printAnnotations(INoted.class);
+        printAnnotations(SubNoted.class);
+        printAnnotations(FullyNoted.class);
 
-        Annotation anno;
+        try {
+            ClassWithInnerAnnotationClass.class.getDeclaredClasses();
+            throw new AssertionError();
+        } catch (NoClassDefFoundError expected) {
+        }
 
         // this is expected to be non-null
-        anno = SimplyNoted.class.getAnnotation(AnnoSimpleType.class);
+        Annotation anno = SimplyNoted.class.getAnnotation(AnnoSimpleType.class);
         System.out.println("SimplyNoted.get(AnnoSimpleType) = " + anno);
         // this is non-null if the @Inherited tag is present
         anno = SubNoted.class.getAnnotation(AnnoSimpleType.class);
diff --git a/test/080-oom-throw/src/Main.java b/test/080-oom-throw/src/Main.java
index 63c5215..c93f8bb 100644
--- a/test/080-oom-throw/src/Main.java
+++ b/test/080-oom-throw/src/Main.java
@@ -15,15 +15,13 @@
  */
 
 public class Main {
-    static char [][] holder;
-
     static class ArrayMemEater {
         static boolean sawOome;
 
         static void blowup(char[][] holder) {
             try {
                 for (int i = 0; i < holder.length; ++i) {
-                    holder[i] = new char[1022 * 1024];
+                    holder[i] = new char[1024 * 1024];
                 }
             } catch (OutOfMemoryError oome) {
                 ArrayMemEater.sawOome = true;
@@ -52,30 +50,8 @@
         }
     }
 
-    static class InstanceFinalizerMemEater {
-        static boolean sawOome;
-        static InstanceFinalizerMemEater hook;
-
-        InstanceFinalizerMemEater next;
-
-        static InstanceFinalizerMemEater allocate() {
-            try {
-                return new InstanceFinalizerMemEater();
-            } catch (OutOfMemoryError e) {
-                InstanceFinalizerMemEater.sawOome = true;
-                return null;
-            }
-        }
-
-        static void confuseCompilerOptimization(InstanceFinalizerMemEater instance) {
-            hook = instance;
-        }
-
-        protected void finalize() {}
-    }
-
-    static boolean triggerArrayOOM(char[][] holder) {
-        ArrayMemEater.blowup(holder);
+    static boolean triggerArrayOOM() {
+        ArrayMemEater.blowup(new char[128 * 1024][]);
         return ArrayMemEater.sawOome;
     }
 
@@ -91,29 +67,11 @@
         return InstanceMemEater.sawOome;
     }
 
-    static boolean triggerInstanceFinalizerOOM() {
-        InstanceFinalizerMemEater memEater = InstanceFinalizerMemEater.allocate();
-        InstanceFinalizerMemEater lastMemEater = memEater;
-        do {
-            lastMemEater.next = InstanceFinalizerMemEater.allocate();
-            lastMemEater = lastMemEater.next;
-        } while (lastMemEater != null);
-        memEater.confuseCompilerOptimization(memEater);
-        InstanceFinalizerMemEater.hook = null;
-        return InstanceFinalizerMemEater.sawOome;
-    }
-
     public static void main(String[] args) {
-        // Keep holder alive to make instance OOM happen faster
-        holder = new char[128 * 1024][];
-        if (triggerArrayOOM(holder)) {
+        if (triggerArrayOOM()) {
             System.out.println("NEW_ARRAY correctly threw OOME");
         }
 
-        if (!triggerInstanceFinalizerOOM()) {
-            System.out.println("NEW_INSTANCE (finalize) did not threw OOME");
-        }
-
         if (triggerInstanceOOM()) {
             System.out.println("NEW_INSTANCE correctly threw OOME");
         }
diff --git a/test/etc/host-run-test-jar b/test/etc/host-run-test-jar
index c020478..6ee1dcd 100755
--- a/test/etc/host-run-test-jar
+++ b/test/etc/host-run-test-jar
@@ -39,6 +39,9 @@
     elif [ "x$1" = "x--prebuild" ]; then
         PREBUILD="y"
         shift
+    elif [ "x$1" = "x--no-prebuild" ]; then
+        PREBUILD="n"
+        shift
     elif [ "x$1" = "x--no-dex2oat" ]; then
         DEX2OAT="-Xcompiler:${FALSE_BIN}"
         shift
diff --git a/test/etc/push-and-run-prebuilt-test-jar b/test/etc/push-and-run-prebuilt-test-jar
deleted file mode 100755
index 91b8a0f..0000000
--- a/test/etc/push-and-run-prebuilt-test-jar
+++ /dev/null
@@ -1,230 +0,0 @@
-#!/bin/sh
-#
-# Run the code in test.jar on the device. The jar should contain a top-level
-# class named Main to run.
-
-msg() {
-    if [ "$QUIET" = "n" ]; then
-        echo "$@"
-    fi
-}
-
-ARCHITECTURES_32="(arm|x86|mips|none)"
-ARCHITECTURES_64="(arm64|x86_64|none)"
-ARCHITECTURES_PATTERN="${ARCHITECTURES_32}"
-RELOCATE="y"
-GDB="n"
-DEBUGGER="n"
-INTERPRETER="n"
-VERIFY="y"
-OPTIMIZE="y"
-ZYGOTE=""
-QUIET="n"
-DEV_MODE="n"
-INVOKE_WITH=""
-FLAGS=""
-TARGET_SUFFIX="32"
-GDB_TARGET_SUFFIX=""
-COMPILE_FLAGS=""
-FALSE_BIN="/system/bin/false"
-PATCHOAT=""
-DEX2OAT=""
-HAVE_IMAGE="y"
-
-while true; do
-    if [ "x$1" = "x--quiet" ]; then
-        QUIET="y"
-        shift
-    elif [ "x$1" = "x--lib" ]; then
-        shift
-        if [ "x$1" = "x" ]; then
-            echo "$0 missing argument to --lib" 1>&2
-            exit 1
-        fi
-        LIB="$1"
-        shift
-    elif [ "x$1" = "x-Xcompiler-option" ]; then
-        shift
-        option="$1"
-        FLAGS="${FLAGS} -Xcompiler-option $option"
-        COMPILE_FLAGS="${COMPILE_FLAGS} $option"
-        shift
-    elif [ "x$1" = "x--runtime-option" ]; then
-        shift
-        option="$1"
-        FLAGS="${FLAGS} $option"
-        shift
-    elif [ "x$1" = "x--boot" ]; then
-        shift
-        BOOT_OPT="$1"
-        BUILD_BOOT_OPT="--boot-image=${1#-Ximage:}"
-        shift
-    elif [ "x$1" = "x--no-dex2oat" ]; then
-        DEX2OAT="-Xcompiler:${FALSE_BIN}"
-        shift
-    elif [ "x$1" = "x--no-patchoat" ]; then
-        PATCHOAT="-Xpatchoat:${FALSE_BIN}"
-        shift
-    elif [ "x$1" = "x--relocate" ]; then
-        RELOCATE="y"
-        shift
-    elif [ "x$1" = "x--no-relocate" ]; then
-        RELOCATE="n"
-        shift
-    elif [ "x$1" = "x--no-image" ]; then
-        HAVE_IMAGE="n"
-        shift
-    elif [ "x$1" = "x--debug" ]; then
-        DEBUGGER="y"
-        shift
-    elif [ "x$1" = "x--gdb" ]; then
-        GDB="y"
-        DEV_MODE="y"
-        shift
-    elif [ "x$1" = "x--zygote" ]; then
-        ZYGOTE="--zygote"
-        msg "Spawning from zygote"
-        shift
-    elif [ "x$1" = "x--dev" ]; then
-        DEV_MODE="y"
-        shift
-    elif [ "x$1" = "x--interpreter" ]; then
-        INTERPRETER="y"
-        shift
-    elif [ "x$1" = "x--invoke-with" ]; then
-        shift
-        if [ "x$1" = "x" ]; then
-            echo "$0 missing argument to --invoke-with" 1>&2
-            exit 1
-        fi
-        if [ "x$INVOKE_WITH" = "x" ]; then
-            INVOKE_WITH="$1"
-        else
-            INVOKE_WITH="$INVOKE_WITH $1"
-        fi
-        shift
-    elif [ "x$1" = "x--no-verify" ]; then
-        VERIFY="n"
-        shift
-    elif [ "x$1" = "x--no-optimize" ]; then
-        OPTIMIZE="n"
-        shift
-    elif [ "x$1" = "x--" ]; then
-        shift
-        break
-    elif [ "x$1" = "x--64" ]; then
-        TARGET_SUFFIX="64"
-        GDB_TARGET_SUFFIX="64"
-        ARCHITECTURES_PATTERN="${ARCHITECTURES_64}"
-        shift
-    elif expr "x$1" : "x--" >/dev/null 2>&1; then
-        echo "unknown $0 option: $1" 1>&2
-        exit 1
-    else
-        break
-    fi
-done
-
-if [ "$ZYGOTE" = "" ]; then
-    if [ "$OPTIMIZE" = "y" ]; then
-        if [ "$VERIFY" = "y" ]; then
-            DEX_OPTIMIZE="-Xdexopt:verified"
-        else
-            DEX_OPTIMIZE="-Xdexopt:all"
-        fi
-        msg "Performing optimizations"
-    else
-        DEX_OPTIMIZE="-Xdexopt:none"
-        msg "Skipping optimizations"
-    fi
-
-    if [ "$VERIFY" = "y" ]; then
-        DEX_VERIFY=""
-        msg "Performing verification"
-    else
-        DEX_VERIFY="-Xverify:none"
-        msg "Skipping verification"
-    fi
-fi
-
-msg "------------------------------"
-
-if [ "$HAVE_IMAGE" = "n" ]; then
-    BOOT_OPT="-Ximage:/system/non-existant/core.art"
-fi
-
-ARCH=$(adb shell ls -F /data/dalvik-cache | grep -Ewo "${ARCHITECTURES_PATTERN}")
-if [ x"$ARCH" = "x" ]; then
-  echo "Unable to determine architecture"
-  exit 1
-fi
-
-if [ "$QUIET" = "n" ]; then
-  adb shell rm -r $DEX_LOCATION
-  adb shell mkdir -p $DEX_LOCATION
-  adb push $TEST_NAME.jar $DEX_LOCATION
-  adb push $TEST_NAME-ex.jar $DEX_LOCATION
-else
-  adb shell rm -r $DEX_LOCATION >/dev/null 2>&1
-  adb shell mkdir -p $DEX_LOCATION >/dev/null 2>&1
-  adb push $TEST_NAME.jar $DEX_LOCATION >/dev/null 2>&1
-  adb push $TEST_NAME-ex.jar $DEX_LOCATION >/dev/null 2>&1
-fi
-
-if [ "$DEBUGGER" = "y" ]; then
-  # Use this instead for ddms and connect by running 'ddms':
-  # DEBUGGER_OPTS="-agentlib:jdwp=transport=dt_android_adb,server=y,suspend=y"
-  # TODO: add a separate --ddms option?
-
-  PORT=12345
-  msg "Waiting for jdb to connect:"
-  msg "    adb forward tcp:$PORT tcp:$PORT"
-  msg "    jdb -attach localhost:$PORT"
-  DEBUGGER_OPTS="-agentlib:jdwp=transport=dt_socket,address=$PORT,server=y,suspend=y"
-fi
-
-if [ "$GDB" = "y" ]; then
-    gdb="gdbserver$GDB_TARGET_SUFFIX :5039"
-    gdbargs="$exe"
-fi
-
-if [ "$INTERPRETER" = "y" ]; then
-    INT_OPTS="-Xint"
-    COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=interpret-only"
-fi
-
-JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"
-
-if [ "$RELOCATE" = "y" ]; then
-    RELOCATE_OPT="-Xrelocate"
-    BUILD_RELOCATE_OPT="--runtime-arg -Xnorelocate"
-    COMPILE_FLAGS="${COMPILE_FLAGS} --include-patch-information"
-    FLAGS="${FLAGS} -Xcompiler-option --include-patch-information"
-else
-    RELOCATE_OPT="-Xnorelocate"
-    BUILD_RELOCATE_OPT="--runtime-arg -Xnorelocate"
-fi
-
-# This is due to the fact this cmdline can get longer than the longest allowed
-# adb command and there is no way to get the exit status from a adb shell
-# command.
-cmdline="cd $DEX_LOCATION && export ANDROID_DATA=$DEX_LOCATION && export DEX_LOCATION=$DEX_LOCATION && \
-    mkdir -p $DEX_LOCATION/dalvik-cache/$ARCH/ && \
-    $INVOKE_WITH /system/bin/dex2oatd $COMPILE_FLAGS $BUILD_BOOT_OPT $BUILD_RELOCATE_OPT  --runtime-arg -classpath --runtime-arg $DEX_LOCATION/$TEST_NAME.jar --dex-file=$DEX_LOCATION/$TEST_NAME.jar --oat-file=$DEX_LOCATION/dalvik-cache/$ARCH/$(echo $DEX_LOCATION/$TEST_NAME.jar/classes.dex | cut -d/ -f 2- | sed "s:/:@:g") --instruction-set=$ARCH && \
-    $INVOKE_WITH $gdb /system/bin/dalvikvm$TARGET_SUFFIX $FLAGS $gdbargs -XXlib:$LIB $PATCHOAT $DEX2OAT $ZYGOTE $JNI_OPTS $RELOCATE_OPT $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar Main $@"
-cmdfile=$(tempfile -p "cmd-" -s "-$TEST_NAME")
-echo "$cmdline" > $cmdfile
-
-if [ "$DEV_MODE" = "y" ]; then
-  echo $cmdline
-fi
-
-if [ "$QUIET" = "n" ]; then
-  adb push $cmdfile $DEX_LOCATION/cmdline.sh
-else
-  adb push $cmdfile $DEX_LOCATION/cmdline.sh > /dev/null 2>&1
-fi
-
-adb shell sh $DEX_LOCATION/cmdline.sh
-
-rm -f $cmdfile
diff --git a/test/etc/push-and-run-test-jar b/test/etc/push-and-run-test-jar
index e398b5d..d3ad71f 100755
--- a/test/etc/push-and-run-test-jar
+++ b/test/etc/push-and-run-test-jar
@@ -9,6 +9,9 @@
     fi
 }
 
+ARCHITECTURES_32="(arm|x86|mips|none)"
+ARCHITECTURES_64="(arm64|x86_64|none)"
+ARCHITECTURES_PATTERN="${ARCHITECTURES_32}"
 RELOCATE="y"
 GDB="n"
 DEBUGGER="n"
@@ -22,10 +25,12 @@
 FLAGS=""
 TARGET_SUFFIX="32"
 GDB_TARGET_SUFFIX=""
+COMPILE_FLAGS=""
 FALSE_BIN="/system/bin/false"
 PATCHOAT=""
 DEX2OAT=""
 HAVE_IMAGE="y"
+PREBUILD="y"
 
 while true; do
     if [ "x$1" = "x--quiet" ]; then
@@ -43,15 +48,7 @@
         shift
         option="$1"
         FLAGS="${FLAGS} -Xcompiler-option $option"
-        shift
-    elif [ "x$1" = "x--no-image" ]; then
-        HAVE_IMAGE="n"
-        shift
-    elif [ "x$1" = "x--no-dex2oat" ]; then
-        DEX2OAT="-Xcompiler:${FALSE_BIN}"
-        shift
-    elif [ "x$1" = "x--no-patchoat" ]; then
-        PATCHOAT="-Xpatchoat:${FALSE_BIN}"
+        COMPILE_FLAGS="${COMPILE_FLAGS} $option"
         shift
     elif [ "x$1" = "x--runtime-option" ]; then
         shift
@@ -61,6 +58,28 @@
     elif [ "x$1" = "x--boot" ]; then
         shift
         BOOT_OPT="$1"
+        BUILD_BOOT_OPT="--boot-image=${1#-Ximage:}"
+        shift
+    elif [ "x$1" = "x--no-dex2oat" ]; then
+        DEX2OAT="-Xcompiler:${FALSE_BIN}"
+        shift
+    elif [ "x$1" = "x--no-patchoat" ]; then
+        PATCHOAT="-Xpatchoat:${FALSE_BIN}"
+        shift
+    elif [ "x$1" = "x--relocate" ]; then
+        RELOCATE="y"
+        shift
+    elif [ "x$1" = "x--no-relocate" ]; then
+        RELOCATE="n"
+        shift
+    elif [ "x$1" = "x--prebuild" ]; then
+        PREBUILD="y"
+        shift
+    elif [ "x$1" = "x--no-prebuild" ]; then
+        PREBUILD="n"
+        shift
+    elif [ "x$1" = "x--no-image" ]; then
+        HAVE_IMAGE="n"
         shift
     elif [ "x$1" = "x--debug" ]; then
         DEBUGGER="y"
@@ -76,12 +95,6 @@
     elif [ "x$1" = "x--dev" ]; then
         DEV_MODE="y"
         shift
-    elif [ "x$1" = "x--relocate" ]; then
-        RELOCATE="y"
-        shift
-    elif [ "x$1" = "x--no-relocate" ]; then
-        RELOCATE="n"
-        shift
     elif [ "x$1" = "x--interpreter" ]; then
         INTERPRETER="y"
         shift
@@ -109,6 +122,7 @@
     elif [ "x$1" = "x--64" ]; then
         TARGET_SUFFIX="64"
         GDB_TARGET_SUFFIX="64"
+        ARCHITECTURES_PATTERN="${ARCHITECTURES_64}"
         shift
     elif expr "x$1" : "x--" >/dev/null 2>&1; then
         echo "unknown $0 option: $1" 1>&2
@@ -146,6 +160,12 @@
     BOOT_OPT="-Ximage:/system/non-existant/core.art"
 fi
 
+ARCH=$(adb shell ls -F /data/dalvik-cache | grep -Ewo "${ARCHITECTURES_PATTERN}")
+if [ x"$ARCH" = "x" ]; then
+  echo "Unable to determine architecture"
+  exit 1
+fi
+
 if [ "$QUIET" = "n" ]; then
   adb shell rm -r $DEX_LOCATION
   adb shell mkdir -p $DEX_LOCATION
@@ -177,21 +197,66 @@
 
 if [ "$INTERPRETER" = "y" ]; then
     INT_OPTS="-Xint"
+    COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=interpret-only"
 fi
 
 JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"
 
 if [ "$RELOCATE" = "y" ]; then
-  RELOCATE_OPT="-Xrelocate"
-  FLAGS="${FLAGS} -Xcompiler-option --include-patch-information"
+    RELOCATE_OPT="-Xrelocate"
+    BUILD_RELOCATE_OPT="--runtime-arg -Xnorelocate"
+    COMPILE_FLAGS="${COMPILE_FLAGS} --include-patch-information"
+    FLAGS="${FLAGS} -Xcompiler-option --include-patch-information"
 else
-  RELOCATE_OPT="-Xnorelocate"
+    RELOCATE_OPT="-Xnorelocate"
+    BUILD_RELOCATE_OPT="--runtime-arg -Xnorelocate"
 fi
 
-cmdline="cd $DEX_LOCATION && export ANDROID_DATA=$DEX_LOCATION && export DEX_LOCATION=$DEX_LOCATION && \
-    $INVOKE_WITH $gdb /system/bin/dalvikvm$TARGET_SUFFIX $FLAGS $gdbargs -XXlib:$LIB $PATCHOAT $DEX2OAT $ZYGOTE $JNI_OPTS $RELOCATE_OPT $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar Main"
+# Create a script with the command. The command can get longer than the longest
+# allowed adb command and there is no way to get the exit status from a adb shell
+# command.
+cmdline="cd $DEX_LOCATION && \
+         export ANDROID_DATA=$DEX_LOCATION && \
+         export DEX_LOCATION=$DEX_LOCATION && "
+if [ "$PREBUILD" = "y" ]; then
+  cmdline+="mkdir -p $DEX_LOCATION/dalvik-cache/$ARCH/ && \
+            $INVOKE_WITH /system/bin/dex2oatd \
+                $COMPILE_FLAGS \
+                $BUILD_BOOT_OPT \
+                $BUILD_RELOCATE_OPT  \
+                --runtime-arg -classpath --runtime-arg $DEX_LOCATION/$TEST_NAME.jar \
+                --dex-file=$DEX_LOCATION/$TEST_NAME.jar \
+                --oat-file=$DEX_LOCATION/dalvik-cache/$ARCH/$(echo $DEX_LOCATION/$TEST_NAME.jar/classes.dex | cut -d/ -f 2- | sed "s:/:@:g") \
+                --instruction-set=$ARCH && "
+fi
+
+cmdline+="$INVOKE_WITH $gdb /system/bin/dalvikvm$TARGET_SUFFIX \
+            $FLAGS \
+            $gdbargs \
+            -XXlib:$LIB \
+            $PATCHOAT \
+            $DEX2OAT \
+            $ZYGOTE \
+            $JNI_OPTS \
+            $RELOCATE_OPT \
+            $INT_OPTS \
+            $DEBUGGER_OPTS \
+            $BOOT_OPT \
+            -cp $DEX_LOCATION/$TEST_NAME.jar Main"
+
+cmdfile=$(tempfile -p "cmd-" -s "-$TEST_NAME")
+echo "$cmdline" > $cmdfile
+
 if [ "$DEV_MODE" = "y" ]; then
-  echo $cmdline "$@"
+  echo $cmdline
 fi
 
-adb shell $cmdline "$@"
+if [ "$QUIET" = "n" ]; then
+  adb push $cmdfile $DEX_LOCATION/cmdline.sh
+else
+  adb push $cmdfile $DEX_LOCATION/cmdline.sh > /dev/null 2>&1
+fi
+
+adb shell sh $DEX_LOCATION/cmdline.sh
+
+rm -f $cmdfile
diff --git a/test/run-test b/test/run-test
index b140fbf..f9f45fc 100755
--- a/test/run-test
+++ b/test/run-test
@@ -93,6 +93,7 @@
     elif [ "x$1" = "x--jvm" ]; then
         target_mode="no"
         runtime="jvm"
+        prebuild_mode="no"
         NEED_DEX="false"
         shift
     elif [ "x$1" = "x-O" ]; then
@@ -118,9 +119,11 @@
         relocate="no"
         shift
     elif [ "x$1" = "x--prebuild" ]; then
+        run_args="${run_args} --prebuild"
         prebuild_mode="yes"
         shift;
     elif [ "x$1" = "x--no-prebuild" ]; then
+        run_args="${run_args} --no-prebuild"
         prebuild_mode="no"
         shift;
     elif [ "x$1" = "x--gcverify" ]; then
@@ -263,13 +266,6 @@
         fi
     else
         RUN="${progdir}/etc/host-run-test-jar"
-        if [ "$prebuild_mode" = "yes" ]; then
-            run_args="${run_args} --prebuild"
-        fi
-    fi
-else
-    if [ "$prebuild_mode" = "yes" ]; then
-        RUN="${progdir}/etc/push-and-run-prebuilt-test-jar"
     fi
 fi