Remove ExtractCodeAndPrelink and switch Portable to MCLinker

Change-Id: Ia2459c7da6b79e0a1c0f1148c6e28ad9cbbe27a2
diff --git a/Android.mk b/Android.mk
index 38c0419..16a2c12 100644
--- a/Android.mk
+++ b/Android.mk
@@ -313,25 +313,32 @@
 dump-oat-core: dump-oat-core-host dump-oat-core-target
 
 .PHONY: dump-oat-core-host
+ifeq ($(ART_BUILD_HOST),true)
 dump-oat-core-host: $(HOST_CORE_IMG_OUT) $(OATDUMP)
 	$(OATDUMP) --image=$(HOST_CORE_IMG_OUT) --output=/tmp/core.host.oatdump.txt --host-prefix=""
 	@echo Output in /tmp/core.host.oatdump.txt
+endif
 
 .PHONY: dump-oat-core-target
+ifeq ($(ART_BUILD_TARGET),true)
 dump-oat-core-target: $(TARGET_CORE_IMG_OUT) $(OATDUMP)
 	$(OATDUMP) --image=$(TARGET_CORE_IMG_OUT) --output=/tmp/core.target.oatdump.txt
 	@echo Output in /tmp/core.target.oatdump.txt
+endif
 
 .PHONY: dump-oat-boot
+ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
 dump-oat-boot: $(TARGET_BOOT_IMG_OUT) $(OATDUMP)
 	$(OATDUMP) --image=$(TARGET_BOOT_IMG_OUT) --output=/tmp/boot.oatdump.txt
 	@echo Output in /tmp/boot.oatdump.txt
+endif
 
 .PHONY: dump-oat-Calculator
+ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
 dump-oat-Calculator: $(TARGET_OUT_APPS)/Calculator.apk.oat $(TARGET_BOOT_IMG_OUT) $(OATDUMP)
 	$(OATDUMP) --oat-file=$< --output=/tmp/Calculator.oatdump.txt
 	@echo Output in /tmp/Calculator.oatdump.txt
-
+endif
 
 ########################################################################
 # cpplint target
diff --git a/build/Android.common.mk b/build/Android.common.mk
index f30cf01..43755b4 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -141,7 +141,6 @@
 	src/common_throws.cc \
 	src/compiled_method.cc \
 	src/compiler/driver/compiler_driver.cc \
-	src/compiler/llvm/procedure_linkage_table.cc \
 	src/compiler/llvm/runtime_support_llvm.cc \
 	src/debugger.cc \
 	src/dex_file.cc \
@@ -379,6 +378,7 @@
 	src/compiler/jni/jni_compiler_test.cc \
 	src/dex_file_test.cc \
 	src/dex_instruction_visitor_test.cc \
+	src/dex_method_iterator_test.cc \
 	src/elf_writer_test.cc \
 	src/exception_test.cc \
 	src/gc/space_bitmap_test.cc \
@@ -447,15 +447,21 @@
 
 ART_BUILD_TARGET := false
 ART_BUILD_HOST := false
+ART_BUILD_NDEBUG := false
+ART_BUILD_DEBUG := false
 ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
   ART_BUILD_TARGET := true
+  ART_BUILD_NDEBUG := true
 endif
 ifeq ($(ART_BUILD_TARGET_DEBUG),true)
   ART_BUILD_TARGET := true
+  ART_BUILD_DEBUG := true
 endif
 ifeq ($(ART_BUILD_HOST_NDEBUG),true)
   ART_BUILD_HOST := true
+  ART_BUILD_NDEBUG := true
 endif
 ifeq ($(ART_BUILD_HOST_DEBUG),true)
   ART_BUILD_HOST := true
+  ART_BUILD_DEBUG := true
 endif
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index 730c980..afb335e 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -112,13 +112,20 @@
   $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),target,debug))
   $(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),target,debug))
 endif
-ifeq ($(ART_BUILD_HOST_NDEBUG),true)
+
+# We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
+ifeq ($(ART_BUILD_NDEBUG),true)
   $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),host,ndebug))
+endif
+ifeq ($(ART_BUILD_NDEBUG),true)
+  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),host,debug))
+endif
+
+ifeq ($(ART_BUILD_HOST_NDEBUG),true)
   $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),host,ndebug))
   $(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),host,ndebug))
 endif
 ifeq ($(ART_BUILD_HOST_DEBUG),true)
-  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),host,debug))
   $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),host,debug))
   $(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),host,debug))
 endif
diff --git a/build/Android.libart-compiler.mk b/build/Android.libart-compiler.mk
index 9e11e22..8f0ccf8 100644
--- a/build/Android.libart-compiler.mk
+++ b/build/Android.libart-compiler.mk
@@ -48,6 +48,7 @@
 	src/compiler/dex/ralloc.cc \
 	src/compiler/dex/ssa_transformation.cc \
 	src/compiler/dex/write_elf.cc \
+	src/compiler/driver/dex_compilation_unit.cc \
 	src/compiler/invoke_stubs/portable/stub_compiler.cc \
 	src/compiler/invoke_stubs/quick/jni_internal_arm.cc \
 	src/compiler/invoke_stubs/quick/jni_internal_mips.cc \
@@ -184,9 +185,22 @@
 ifeq ($(ART_BUILD_TARGET_DEBUG),true)
   $(eval $(call build-libart-compiler,target,debug))
 endif
-ifeq ($(ART_BUILD_HOST_NDEBUG),true)
+# We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
+ifeq ($(ART_BUILD_NDEBUG),true)
   $(eval $(call build-libart-compiler,host,ndebug))
 endif
-ifeq ($(ART_BUILD_HOST_DEBUG),true)
+ifeq ($(ART_BUILD_DEBUG),true)
   $(eval $(call build-libart-compiler,host,debug))
 endif
+
+# Rule to build /system/lib/libcompiler-rt.a
+# Usually static libraries are not installed on the device.
+ifeq ($(ART_USE_PORTABLE_COMPILER),true)
+ifeq ($(ART_BUILD_TARGET),true)
+# TODO: Move to external/compiler-rt
+$(eval $(call copy-one-file, $(call intermediates-dir-for,STATIC_LIBRARIES,libcompiler-rt,,)/libcompiler-rt.a, $(TARGET_OUT_SHARED_LIBRARIES)/libcompiler-rt.a))
+
+$(DEX2OAT): $(TARGET_OUT_SHARED_LIBRARIES)/libcompiler-rt.a
+
+endif
+endif
diff --git a/build/Android.libart.mk b/build/Android.libart.mk
index 630f05a..67461be 100644
--- a/build/Android.libart.mk
+++ b/build/Android.libart.mk
@@ -120,9 +120,11 @@
 ifeq ($(ART_BUILD_TARGET_DEBUG),true)
   $(eval $(call build-libart,target,debug))
 endif
-ifeq ($(ART_BUILD_HOST_NDEBUG),true)
+
+# We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
+ifeq ($(ART_BUILD_NDEBUG),true)
   $(eval $(call build-libart,host,ndebug))
 endif
-ifeq ($(ART_BUILD_HOST_DEBUG),true)
+ifeq ($(ART_BUILD_DEBUG),true)
   $(eval $(call build-libart,host,debug))
 endif
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index b4e1266..feeede5 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -16,11 +16,19 @@
 
 # DEX2OAT defined in build/core/config.mk
 DEX2OATD := $(HOST_OUT_EXECUTABLES)/dex2oatd$(HOST_EXECUTABLE_SUFFIX)
+
+LIBART_COMPILER := $(HOST_OUT_SHARED_LIBRARIES)/libart-compiler$(HOST_SHLIB_SUFFIX)
+LIBARTD_COMPILER := $(HOST_OUT_SHARED_LIBRARIES)/libartd-compiler$(HOST_SHLIB_SUFFIX)
+
 # TODO: for now, override with debug version for better error reporting
 DEX2OAT := $(DEX2OATD)
+LIBART_COMPILER := $(LIBARTD_COMPILER)
 
-DEX2OAT_DEPENDENCY := | $(DEX2OAT)  # by default, do not run rerun dex2oat if the tool changes
-# DEX2OAT_DEPENDENCY := $(DEX2OAT)  # uncomment to force dex2oat to rerun on after all changes
+# By default, do not run rerun dex2oat if the tool changes.
+# Comment out the | to force dex2oat to rerun on after all changes.
+DEX2OAT_DEPENDENCY := |
+DEX2OAT_DEPENDENCY += $(DEX2OAT)
+DEX2OAT_DEPENDENCY += $(LIBART_COMPILER)
 
 OATDUMP := $(HOST_OUT_EXECUTABLES)/oatdump$(HOST_EXECUTABLE_SUFFIX)
 OATDUMPD := $(HOST_OUT_EXECUTABLES)/oatdumpd$(HOST_EXECUTABLE_SUFFIX)
@@ -52,7 +60,7 @@
 $(HOST_CORE_IMG_OUT): $(HOST_CORE_DEX_FILES) $(DEX2OAT_DEPENDENCY)
 	@echo "host dex2oat: $@ ($?)"
 	@mkdir -p $(dir $@)
-	$(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(HOST_CORE_DEX_FILES)) $(addprefix --dex-location=,$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$(HOST_CORE_OAT_OUT) --oat-location=$(HOST_CORE_OAT) --image=$(HOST_CORE_IMG_OUT) --base=$(IMG_HOST_BASE_ADDRESS) --instruction-set=$(HOST_ARCH)
+	$(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(HOST_CORE_DEX_FILES)) $(addprefix --dex-location=,$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$(HOST_CORE_OAT_OUT) --oat-location=$(HOST_CORE_OAT) --image=$(HOST_CORE_IMG_OUT) --base=$(IMG_HOST_BASE_ADDRESS) --instruction-set=$(HOST_ARCH) --host
 
 $(TARGET_CORE_IMG_OUT): $(TARGET_CORE_DEX_FILES) $(DEX2OAT_DEPENDENCY)
 	@echo "target dex2oat: $@ ($?)"
@@ -80,18 +88,22 @@
 TARGET_BOOT_IMG_OUT := $(DEFAULT_DEX_PREOPT_IMAGE)
 TARGET_BOOT_OAT_OUT := $(patsubst %.art,%.oat,$(TARGET_BOOT_IMG_OUT))
 TARGET_BOOT_OAT := $(subst $(PRODUCT_OUT),,$(TARGET_BOOT_OAT_OUT))
+TARGET_BOOT_OAT_UNSTRIPPED_OUT := $(TARGET_OUT_UNSTRIPPED)$(TARGET_BOOT_OAT)
 
 $(TARGET_BOOT_IMG_OUT): $(TARGET_BOOT_DEX_FILES) $(DEX2OAT_DEPENDENCY)
 	@echo "target dex2oat: $@ ($?)"
 	@mkdir -p $(dir $@)
-	$(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms256m --runtime-arg -Xmx256m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(TARGET_BOOT_DEX_FILES)) $(addprefix --dex-location=,$(TARGET_BOOT_DEX_LOCATIONS)) --oat-file=$(TARGET_BOOT_OAT_OUT) --oat-location=$(TARGET_BOOT_OAT) --image=$(TARGET_BOOT_IMG_OUT) --base=$(IMG_TARGET_BASE_ADDRESS) --instruction-set=$(TARGET_ARCH) --host-prefix=$(PRODUCT_OUT)
+	@mkdir -p $(dir $(TARGET_BOOT_OAT_UNSTRIPPED_OUT))
+	$(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms256m --runtime-arg -Xmx256m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(TARGET_BOOT_DEX_FILES)) $(addprefix --dex-location=,$(TARGET_BOOT_DEX_LOCATIONS)) --oat-symbols=$(TARGET_BOOT_OAT_UNSTRIPPED_OUT) --oat-file=$(TARGET_BOOT_OAT_OUT) --oat-location=$(TARGET_BOOT_OAT) --image=$(TARGET_BOOT_IMG_OUT) --base=$(IMG_TARGET_BASE_ADDRESS) --instruction-set=$(TARGET_ARCH) --host-prefix=$(PRODUCT_OUT)
 
-$(TARGET_BOOT_OAT_OUT): $(TARGET_BOOT_IMG_OUT)
+$(TARGET_BOOT_OAT_UNSTRIPPED_OUT): $(TARGET_BOOT_IMG_OUT)
 
-ifeq ($(ART_BUILD_TARGET),true)
+$(TARGET_BOOT_OAT_OUT): $(TARGET_BOOT_OAT_UNSTRIPPED_OUT)
+
+ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
 include $(CLEAR_VARS)
 LOCAL_MODULE := boot.art
 LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_BOOT_IMG_OUT)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_BOOT_IMG_OUT) $(TARGET_BOOT_OAT_OUT)
 include $(BUILD_PHONY_PACKAGE)
 endif
diff --git a/build/Android.oattest.mk b/build/Android.oattest.mk
index 744a01d..c2163bd 100644
--- a/build/Android.oattest.mk
+++ b/build/Android.oattest.mk
@@ -23,27 +23,31 @@
 # $(2): input test directory
 # $(3): target output module path (default module path is used on host)
 define build-art-test-dex
-  include $(CLEAR_VARS)
-  LOCAL_MODULE := $(1)-$(2)
-  LOCAL_MODULE_TAGS := tests
-  LOCAL_SRC_FILES := $(call all-java-files-under, test/$(2))
-  LOCAL_JAVA_LIBRARIES := $(TARGET_CORE_JARS)
-  LOCAL_NO_STANDARD_LIBRARIES := true
-  LOCAL_MODULE_PATH := $(3)
-  LOCAL_DEX_PREOPT_IMAGE := $(TARGET_CORE_IMG_OUT)
-  LOCAL_DEX_PREOPT := false
-  include $(BUILD_JAVA_LIBRARY)
-  ART_TEST_TARGET_DEX_FILES += $(3)/$$(LOCAL_MODULE).jar
+  ifeq ($(ART_BUILD_TARGET),true)
+    include $(CLEAR_VARS)
+    LOCAL_MODULE := $(1)-$(2)
+    LOCAL_MODULE_TAGS := tests
+    LOCAL_SRC_FILES := $(call all-java-files-under, test/$(2))
+    LOCAL_JAVA_LIBRARIES := $(TARGET_CORE_JARS)
+    LOCAL_NO_STANDARD_LIBRARIES := true
+    LOCAL_MODULE_PATH := $(3)
+    LOCAL_DEX_PREOPT_IMAGE := $(TARGET_CORE_IMG_OUT)
+    LOCAL_DEX_PREOPT := false
+    include $(BUILD_JAVA_LIBRARY)
+    ART_TEST_TARGET_DEX_FILES += $(3)/$$(LOCAL_MODULE).jar
+  endif
 
-  include $(CLEAR_VARS)
-  LOCAL_MODULE := $(1)-$(2)
-  LOCAL_SRC_FILES := $(call all-java-files-under, test/$(2))
-  LOCAL_JAVA_LIBRARIES := $(HOST_CORE_JARS)
-  LOCAL_NO_STANDARD_LIBRARIES := true
-  LOCAL_DEX_PREOPT_IMAGE := $(HOST_CORE_IMG_OUT)
-  LOCAL_BUILD_HOST_DEX := true
-  include $(BUILD_HOST_JAVA_LIBRARY)
-  ART_TEST_HOST_DEX_FILES += $$(LOCAL_MODULE_PATH)/$$(LOCAL_MODULE).jar
+  ifeq ($(ART_BUILD_HOST),true)
+    include $(CLEAR_VARS)
+    LOCAL_MODULE := $(1)-$(2)
+    LOCAL_SRC_FILES := $(call all-java-files-under, test/$(2))
+    LOCAL_JAVA_LIBRARIES := $(HOST_CORE_JARS)
+    LOCAL_NO_STANDARD_LIBRARIES := true
+    LOCAL_DEX_PREOPT_IMAGE := $(HOST_CORE_IMG_OUT)
+    LOCAL_BUILD_HOST_DEX := true
+    include $(BUILD_HOST_JAVA_LIBRARY)
+    ART_TEST_HOST_DEX_FILES += $$(LOCAL_MODULE_PATH)/$$(LOCAL_MODULE).jar
+  endif
 endef
 $(foreach dir,$(TEST_DEX_DIRECTORIES), $(eval $(call build-art-test-dex,art-test-dex,$(dir),$(ART_NATIVETEST_OUT))))
 $(foreach dir,$(TEST_OAT_DIRECTORIES), $(eval $(call build-art-test-dex,oat-test-dex,$(dir),$(ART_TEST_OUT))))
@@ -66,7 +70,7 @@
 	$(hide) rm /tmp/test-art-target-oat-$(1)
 
 $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar.oat: $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar $(HOST_CORE_IMG_OUT) | $(DEX2OAT)
-	$(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --boot-image=$(HOST_CORE_IMG_OUT) --dex-file=$$< --oat-file=$$@ --instruction-set=$(HOST_ARCH) --host-prefix=""
+	$(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --boot-image=$(HOST_CORE_IMG_OUT) --dex-file=$$< --oat-file=$$@ --instruction-set=$(HOST_ARCH) --host --host-prefix=""
 
 .PHONY: test-art-host-oat-$(1)
 test-art-host-oat-$(1): $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar.oat test-art-host-dependencies
diff --git a/src/class_linker.cc b/src/class_linker.cc
index ca7cc00..4a07eba 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -659,6 +659,9 @@
                        << " --runtime-arg -Xmx64m"
                        << " --runtime-arg -classpath"
                        << " --runtime-arg " << class_path
+#if !defined(ART_TARGET)
+                       << " --host"
+#endif
                        << " " << boot_image_option
                        << " " << dex_file_option
                        << " " << oat_fd_option
@@ -669,6 +672,9 @@
           "--runtime-arg", "-Xmx64m",
           "--runtime-arg", "-classpath",
           "--runtime-arg", class_path,
+#if !defined(ART_TARGET)
+          "--host",
+#endif
           boot_image_option,
           dex_file_option,
           oat_fd_option,
@@ -815,12 +821,7 @@
     LOG(ERROR) << "Failed to generate oat file: " << oat_location;
     return NULL;
   }
-  // Open the oat from file descriptor we passed to GenerateOatFile
-  if (lseek(file->Fd(), 0, SEEK_SET) != 0) {
-    LOG(ERROR) << "Failed to seek to start of generated oat file: " << oat_location;
-    return NULL;
-  }
-  const OatFile* oat_file = OatFile::Open(file.get(), oat_location, NULL, false);
+  const OatFile* oat_file = OatFile::Open(oat_location, oat_location, NULL);
   if (oat_file == NULL) {
     LOG(ERROR) << "Failed to open generated oat file: " << oat_location;
     return NULL;
@@ -1624,7 +1625,7 @@
   // Every kind of method should at least get an invoke stub from the oat_method.
   // non-abstract methods also get their code pointers.
   const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
-  oat_method.LinkMethodPointers(method.get());
+  oat_method.LinkMethod(method.get());
 
   Runtime* runtime = Runtime::Current();
   if (method->IsAbstract()) {
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 893e7a4..e9ba70a 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -368,7 +368,7 @@
     if (!klass->IsClassClass() && !is_static) {
       size_t expected_size = is_static ? klass->GetClassSize(): klass->GetObjectSize();
       if (sizeof(T) != expected_size) {
-        LG << "Class size mismatch:"
+        LOG(ERROR) << "Class size mismatch:"
            << " class=" << class_descriptor
            << " Java=" << expected_size
            << " C++=" << sizeof(T);
@@ -378,7 +378,7 @@
 
     size_t num_fields = is_static ? klass->NumStaticFields() : klass->NumInstanceFields();
     if (offsets.size() != num_fields) {
-      LG << "Field count mismatch:"
+      LOG(ERROR) << "Field count mismatch:"
          << " class=" << class_descriptor
          << " Java=" << num_fields
          << " C++=" << offsets.size();
@@ -401,9 +401,9 @@
         fh.ChangeField(field);
         StringPiece field_name(fh.GetName());
         if (field_name != offsets[i].java_name) {
-          LG << "JAVA FIELD ORDER MISMATCH NEXT LINE:";
+          LOG(ERROR) << "JAVA FIELD ORDER MISMATCH NEXT LINE:";
         }
-        LG << "Java field order:"
+        LOG(ERROR) << "Java field order:"
            << " i=" << i << " class=" << class_descriptor
            << " Java=" << field_name
            << " CheckOffsets=" << offset.java_name;
@@ -422,9 +422,9 @@
         CheckOffset& offset = offsets[i];
         Field* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i);
         if (field->GetOffset().Uint32Value() != offset.cpp_offset) {
-          LG << "OFFSET MISMATCH NEXT LINE:";
+          LOG(ERROR) << "OFFSET MISMATCH NEXT LINE:";
         }
-        LG << "Offset: class=" << class_descriptor << " field=" << offset.java_name
+        LOG(ERROR) << "Offset: class=" << class_descriptor << " field=" << offset.java_name
            << " Java=" << field->GetOffset().Uint32Value() << " C++=" << offset.cpp_offset;
       }
     }
diff --git a/src/common_test.h b/src/common_test.h
index 0d3795e..0167424 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -246,7 +246,7 @@
                                                       &compiled_method->GetVmapTable()[0],
                                                       NULL,
                                                       method_invoke_stub);
-      oat_method.LinkMethodPointers(method);
+      oat_method.LinkMethod(method);
     } else {
       MakeExecutable(runtime_->GetAbstractMethodErrorStubArray());
       const void* method_code = runtime_->GetAbstractMethodErrorStubArray()->GetData();
@@ -259,7 +259,7 @@
                                                       NULL,
                                                       NULL,
                                                       method_invoke_stub);
-      oat_method.LinkMethodPointers(method);
+      oat_method.LinkMethod(method);
     }
   }
 
@@ -434,12 +434,16 @@
   }
 
   std::string GetLibCoreDexFileName() {
+    return GetDexFileName("core");
+  }
+
+  std::string GetDexFileName(const std::string& jar_prefix) {
     if (IsHost()) {
       const char* host_dir = getenv("ANDROID_HOST_OUT");
       CHECK(host_dir != NULL);
-      return StringPrintf("%s/framework/core-hostdex.jar", host_dir);
+      return StringPrintf("%s/framework/%s-hostdex.jar", host_dir, jar_prefix.c_str());
     }
-    return StringPrintf("%s/framework/core.jar", GetAndroidRoot());
+    return StringPrintf("%s/framework/%s.jar", GetAndroidRoot(), jar_prefix.c_str());
   }
 
   const DexFile* OpenTestDexFile(const char* name) {
@@ -585,6 +589,16 @@
   DISALLOW_COPY_AND_ASSIGN(CheckJniAbortCatcher);
 };
 
+// TODO: These tests were disabled for portable when we went to having
+// MCLinker link LLVM ELF output because we no longer just have code
+// blobs in memory. We'll need to dlopen to load and relocate
+// temporary output to resurrect these tests.
+#if defined(ART_USE_PORTABLE_COMPILER)
+#define TEST_DISABLED_FOR_PORTABLE() printf("WARNING: TEST DISABLED FOR PORTABLE\n"); return
+#else
+#define TEST_DISABLED_FOR_PORTABLE()
+#endif
+
 }  // namespace art
 
 namespace std {
diff --git a/src/compiled_method.cc b/src/compiled_method.cc
index 4de2a3f..36c4eea 100644
--- a/src/compiled_method.cc
+++ b/src/compiled_method.cc
@@ -18,6 +18,26 @@
 
 namespace art {
 
+CompiledCode::CompiledCode(InstructionSet instruction_set, const std::vector<uint8_t>& code)
+    : instruction_set_(instruction_set), code_(code)
+{
+  CHECK_NE(code.size(), 0U);
+}
+
+CompiledCode::CompiledCode(InstructionSet instruction_set,
+                           const std::string& elf_object,
+                           const std::string& symbol)
+    : instruction_set_(instruction_set), symbol_(symbol) {
+  CHECK_NE(elf_object.size(), 0U);
+  CHECK_NE(symbol.size(), 0U);
+  // TODO: we shouldn't just shove ELF objects in as "code" but
+  // change to have different kinds of compiled methods.  This is
+  // being deferred until we work on hybrid execution or at least
+  // until we work on batch compilation.
+  code_.resize(elf_object.size());
+  memcpy(&code_[0], &elf_object[0], elf_object.size());
+}
+
 uint32_t CompiledCode::AlignCode(uint32_t offset) const {
   return AlignCode(offset, instruction_set_);
 }
@@ -72,6 +92,22 @@
   }
 }
 
+#if defined(ART_USE_PORTABLE_COMPILER)
+const std::string& CompiledCode::GetSymbol() const {
+  CHECK_NE(0U, symbol_.size());
+  return symbol_;
+}
+
+const std::vector<uint32_t>& CompiledCode::GetOatdataOffsetsToCompliledCodeOffset() const {
+  CHECK_NE(0U, oatdata_offsets_to_compiled_code_offset_.size()) << symbol_;
+  return oatdata_offsets_to_compiled_code_offset_;
+}
+
+void CompiledCode::AddOatdataOffsetToCompliledCodeOffset(uint32_t offset) {
+  oatdata_offsets_to_compiled_code_offset_.push_back(offset);
+}
+#endif
+
 CompiledMethod::CompiledMethod(InstructionSet instruction_set,
                                const std::vector<uint8_t>& code,
                                const size_t frame_size_in_bytes,
@@ -80,20 +116,15 @@
                                const std::vector<uint32_t>& mapping_table,
                                const std::vector<uint16_t>& vmap_table,
                                const std::vector<uint8_t>& native_gc_map)
-    : CompiledCode(instruction_set), frame_size_in_bytes_(frame_size_in_bytes),
+    : CompiledCode(instruction_set, code), frame_size_in_bytes_(frame_size_in_bytes),
       core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
       native_gc_map_(native_gc_map)
 {
-  CHECK_NE(code.size(), 0U);
   DCHECK_EQ(vmap_table.size(),
             static_cast<uint32_t>(__builtin_popcount(core_spill_mask)
                                   + __builtin_popcount(fp_spill_mask)));
   CHECK_LE(vmap_table.size(), (1U << 16) - 1); // length must fit in 2^16-1
 
-  size_t code_byte_count = code.size() * sizeof(code[0]);
-  std::vector<uint8_t> byte_code(code_byte_count);
-  memcpy(&byte_code[0], &code[0], code_byte_count);
-
   std::vector<uint32_t> length_prefixed_mapping_table;
   length_prefixed_mapping_table.push_back(mapping_table.size());
   length_prefixed_mapping_table.insert(length_prefixed_mapping_table.end(),
@@ -109,7 +140,6 @@
   DCHECK_EQ(vmap_table.size() + 1, length_prefixed_vmap_table.size());
   DCHECK_EQ(vmap_table.size(), length_prefixed_vmap_table[0]);
 
-  SetCode(byte_code);
   mapping_table_ = length_prefixed_mapping_table;
   vmap_table_ = length_prefixed_vmap_table;
   DCHECK_EQ(vmap_table_[0], static_cast<uint32_t>(__builtin_popcount(core_spill_mask) + __builtin_popcount(fp_spill_mask)));
@@ -122,16 +152,15 @@
                                const uint32_t fp_spill_mask)
     : CompiledCode(instruction_set, code),
       frame_size_in_bytes_(frame_size_in_bytes),
-      core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask) {
-}
-
-CompiledInvokeStub::CompiledInvokeStub(InstructionSet instruction_set)
-    : CompiledCode(instruction_set) {
-}
+      core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask) {}
 
 CompiledInvokeStub::CompiledInvokeStub(InstructionSet instruction_set,
                                        const std::vector<uint8_t>& code)
-    : CompiledCode(instruction_set, code) {
-}
+    : CompiledCode(instruction_set, code) {}
+
+CompiledInvokeStub::CompiledInvokeStub(InstructionSet instruction_set,
+                                       const std::string& elf_object,
+                                       const std::string& symbol)
+    : CompiledCode(instruction_set, elf_object, symbol) {}
 
 }  // namespace art
diff --git a/src/compiled_method.h b/src/compiled_method.h
index b7a2f9c..c05aba1 100644
--- a/src/compiled_method.h
+++ b/src/compiled_method.h
@@ -17,6 +17,7 @@
 #ifndef ART_SRC_COMPILED_METHOD_H_
 #define ART_SRC_COMPILED_METHOD_H_
 
+#include <string>
 #include <vector>
 
 #include "instruction_set.h"
@@ -31,14 +32,13 @@
 
 class CompiledCode {
  public:
-  CompiledCode(InstructionSet instruction_set)
-      : instruction_set_(instruction_set) {
-  }
+  // For Quick to supply an code blob
+  CompiledCode(InstructionSet instruction_set, const std::vector<uint8_t>& code);
 
-  CompiledCode(InstructionSet instruction_set, const std::vector<uint8_t>& code)
-      : instruction_set_(instruction_set), code_(code) {
-    CHECK_NE(code.size(), 0U);
-  }
+  // For Portable to supply an ELF object
+  CompiledCode(InstructionSet instruction_set,
+               const std::string& elf_object,
+               const std::string &symbol);
 
   InstructionSet GetInstructionSet() const {
     return instruction_set_;
@@ -73,9 +73,26 @@
   static const void* CodePointer(const void* code_pointer,
                                  InstructionSet instruction_set);
 
+#if defined(ART_USE_PORTABLE_COMPILER)
+  const std::string& GetSymbol() const;
+  const std::vector<uint32_t>& GetOatdataOffsetsToCompliledCodeOffset() const;
+  void AddOatdataOffsetToCompliledCodeOffset(uint32_t offset);
+#endif
+
  private:
   const InstructionSet instruction_set_;
+  
+  // Used to store the PIC code for Quick and an ELF image for portable.
   std::vector<uint8_t> code_;
+
+  // Used for the Portable ELF symbol name.
+  std::string symbol_;
+
+  // There are offsets from the oatdata symbol to where the offset to
+  // the compiled method will be found. These are computed by the
+  // OatWriter and then used by the ElfWriter to add relocations so
+  // that MCLinker can update the values to the location in the linked .so.
+  std::vector<uint32_t> oatdata_offsets_to_compiled_code_offset_;
 };
 
 class CompiledMethod : public CompiledCode {
@@ -97,19 +114,21 @@
                  const uint32_t core_spill_mask,
                  const uint32_t fp_spill_mask);
 
-  // Constructs a CompiledMethod for the LLVM compiler.
+  // Constructs a CompiledMethod for the Portable compiler.
   CompiledMethod(InstructionSet instruction_set,
-                 const std::vector<uint8_t>& code,
-                 const std::vector<uint8_t>& gc_map)
-      : CompiledCode(instruction_set, code),
+                 const std::string& code,
+                 const std::vector<uint8_t>& gc_map,
+                 const std::string& symbol)
+      : CompiledCode(instruction_set, code, symbol),
         frame_size_in_bytes_(kStackAlignment), core_spill_mask_(0),
         fp_spill_mask_(0), native_gc_map_(gc_map) {
   }
 
-  // Constructs a CompiledMethod for the LLVM JniCompiler.
+  // Constructs a CompiledMethod for the Portable JniCompiler.
   CompiledMethod(InstructionSet instruction_set,
-                 const std::vector<uint8_t>& code)
-      : CompiledCode(instruction_set, code),
+                 const std::string& code,
+                 const std::string& symbol)
+      : CompiledCode(instruction_set, code, symbol),
         frame_size_in_bytes_(kStackAlignment), core_spill_mask_(0),
         fp_spill_mask_(0) {
   }
@@ -151,11 +170,15 @@
 
 class CompiledInvokeStub : public CompiledCode {
  public:
-  explicit CompiledInvokeStub(InstructionSet instruction_set);
-
+  // Used by Quick to provide a blob of code.
   explicit CompiledInvokeStub(InstructionSet instruction_set,
                               const std::vector<uint8_t>& code);
 
+  // Used by Portable to provide ELF object.
+  explicit CompiledInvokeStub(InstructionSet instruction_set,
+                              const std::string& elf_object,
+                              const std::string& symbol);
+
   ~CompiledInvokeStub() {}
 };
 
diff --git a/src/compiler/dex/compiler_ir.h b/src/compiler/dex/compiler_ir.h
index 4ab98a6..f8cdd34 100644
--- a/src/compiler/dex/compiler_ir.h
+++ b/src/compiler/dex/compiler_ir.h
@@ -18,15 +18,18 @@
 #define ART_SRC_COMPILER_DEX_COMPILER_IR_H_
 
 #include <vector>
-#include "dex_instruction.h"
+
+#include <llvm/Module.h>
+
+#include "compiler/dex/quick/codegen.h"
 #include "compiler/driver/compiler_driver.h"
 #include "compiler/driver/dex_compilation_unit.h"
-#include "compiler_utility.h"
-#include "safe_map.h"
-#include "compiler/llvm/ir_builder.h"
 #include "compiler/llvm/intrinsic_helper.h"
-#include "llvm/Module.h"
+#include "compiler/llvm/ir_builder.h"
 #include "compiler_enums.h"
+#include "compiler_utility.h"
+#include "dex_instruction.h"
+#include "safe_map.h"
 
 namespace art {
 
@@ -43,6 +46,9 @@
 struct ArenaBitVector;
 struct LIR;
 class LLVMInfo;
+namespace llvm {
+class LlvmCompilationUnit;
+}  // namespace llvm
 
 struct PromotionMap {
   RegLocationType core_location:3;
@@ -348,6 +354,7 @@
       mstats(NULL),
       checkstats(NULL),
       gen_bitcode(false),
+      llvm_compilation_unit(NULL),
       llvm_info(NULL),
       context(NULL),
       module(NULL),
@@ -507,7 +514,11 @@
   Memstats* mstats;
   Checkstats* checkstats;
   bool gen_bitcode;
+
+  // Fields for Portable
+  llvm::LlvmCompilationUnit* llvm_compilation_unit;
   LLVMInfo* llvm_info;
+  std::string symbol;
   ::llvm::LLVMContext* context;
   ::llvm::Module* module;
   ::llvm::Function* func;
@@ -516,6 +527,7 @@
   ::llvm::BasicBlock* placeholder_bb;
   ::llvm::BasicBlock* entry_bb;
   ::llvm::BasicBlock* entryTarget_bb;
+
   std::string bitcode_filename;
   GrowableList llvm_values;
   int32_t temp_name;
diff --git a/src/compiler/dex/dataflow.cc b/src/compiler/dex/dataflow.cc
index ac3116e..f0f177a 100644
--- a/src/compiler/dex/dataflow.cc
+++ b/src/compiler/dex/dataflow.cc
@@ -2491,10 +2491,7 @@
       LOG(WARNING) << "Unexpected invoke op: " << opcode;
       return false;
   }
-  DexCompilationUnit m_unit(cu->class_loader, cu->class_linker,
-                            *cu->dex_file, cu->code_item,
-                            cu->class_def_idx, cu->method_idx,
-                            cu->access_flags);
+  DexCompilationUnit m_unit(cu);
   // TODO: add a flag so we don't counts the stats for this twice
   uint32_t dex_method_idx = mir->dalvikInsn.vB;
   int vtable_idx;
diff --git a/src/compiler/dex/frontend.cc b/src/compiler/dex/frontend.cc
index 482804c..5b8faf4 100644
--- a/src/compiler/dex/frontend.cc
+++ b/src/compiler/dex/frontend.cc
@@ -14,8 +14,13 @@
  * limitations under the License.
  */
 
+#include <llvm/Support/Threading.h>
+
 #include "compiler/driver/compiler_driver.h"
 #include "compiler_internals.h"
+#if defined(ART_USE_PORTABLE_COMPILER)
+#include "compiler/llvm/llvm_compilation_unit.h"
+#endif
 #include "dataflow.h"
 #include "ssa_transformation.h"
 #include "leb128.h"
@@ -25,8 +30,6 @@
 #include "portable/mir_to_gbc.h"
 #include "quick/mir_to_lir.h"
 
-#include <llvm/Support/Threading.h>
-
 namespace {
 #if !defined(ART_USE_PORTABLE_COMPILER)
   pthread_once_t llvm_multi_init = PTHREAD_ONCE_INIT;
@@ -782,8 +785,11 @@
                                      const DexFile::CodeItem* code_item,
                                      uint32_t access_flags, InvokeType invoke_type,
                                      uint32_t class_def_idx, uint32_t method_idx,
-                                     jobject class_loader, const DexFile& dex_file,
-                                     LLVMInfo* llvm_info)
+                                     jobject class_loader, const DexFile& dex_file
+#if defined(ART_USE_PORTABLE_COMPILER)
+                                     , llvm::LlvmCompilationUnit* llvm_compilation_unit
+#endif
+)
 {
   VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
 
@@ -818,7 +824,11 @@
   if ((compiler_backend == kQuickGBC) || (compiler_backend == kPortable)) {
     cu->gen_bitcode = true;
   }
-  cu->llvm_info = llvm_info;
+#if defined(ART_USE_PORTABLE_COMPILER)
+  cu->llvm_compilation_unit = llvm_compilation_unit;
+  cu->llvm_info = llvm_compilation_unit->GetQuickContext();
+  cu->symbol = llvm_compilation_unit->GetDexCompilationUnit()->GetSymbol();
+#endif
   /* Adjust this value accordingly once inlining is performed */
   cu->num_dalvik_registers = code_item->registers_size_;
   // TODO: set this from command line
@@ -1137,6 +1147,7 @@
   }
 
 
+#if defined(ART_USE_PORTABLE_COMPILER)
   /* Go the LLVM path? */
   if (cu->gen_bitcode) {
     // MIR->Bitcode
@@ -1148,7 +1159,9 @@
     }
     // Bitcode->LIR
     MethodBitcode2LIR(cu.get());
-  } else {
+  } else
+#endif
+  {
     if (special_case != kNoHandler) {
       /*
        * Custom codegen for special cases.  If for any reason the
@@ -1231,13 +1244,20 @@
 CompiledMethod* CompileOneMethod(CompilerDriver& compiler,
                                  const CompilerBackend backend,
                                  const DexFile::CodeItem* code_item,
-                                 uint32_t access_flags, InvokeType invoke_type,
-                                 uint32_t class_def_idx, uint32_t method_idx, jobject class_loader,
+                                 uint32_t access_flags,
+                                 InvokeType invoke_type,
+                                 uint32_t class_def_idx,
+                                 uint32_t method_idx,
+                                 jobject class_loader,
                                  const DexFile& dex_file,
-                                 LLVMInfo* llvm_info)
+                                 llvm::LlvmCompilationUnit* llvm_compilation_unit)
 {
   return CompileMethod(compiler, backend, code_item, access_flags, invoke_type, class_def_idx,
-                       method_idx, class_loader, dex_file, llvm_info);
+                       method_idx, class_loader, dex_file
+#if defined(ART_USE_PORTABLE_COMPILER)
+                       , llvm_compilation_unit
+#endif
+                       );
 }
 
 }  // namespace art
diff --git a/src/compiler/dex/portable/mir_to_gbc.cc b/src/compiler/dex/portable/mir_to_gbc.cc
index 8319b4d..e6900df 100644
--- a/src/compiler/dex/portable/mir_to_gbc.cc
+++ b/src/compiler/dex/portable/mir_to_gbc.cc
@@ -33,6 +33,8 @@
 #include "compiler/dex/quick/codegen_util.h"
 #include "compiler/dex/quick/local_optimizations.h"
 #include "compiler/dex/quick/ralloc_util.h"
+#include "compiler/llvm/llvm_compilation_unit.h"
+#include "compiler/llvm/utils_llvm.h"
 
 static const char* kLabelFormat = "%c0x%x_%d";
 static const char kInvalidBlock = 0xff;
@@ -1982,17 +1984,14 @@
 }
 
 static bool CreateFunction(CompilationUnit* cu) {
-  std::string func_name(PrettyMethod(cu->method_idx, *cu->dex_file,
-                                     /* with_signature */ false));
   ::llvm::FunctionType* func_type = GetFunctionType(cu);
-
   if (func_type == NULL) {
     return false;
   }
 
   cu->func = ::llvm::Function::Create(func_type,
-                                       ::llvm::Function::ExternalLinkage,
-                                       func_name, cu->module);
+                                      ::llvm::Function::InternalLinkage,
+                                      cu->symbol, cu->module);
 
   ::llvm::Function::arg_iterator arg_iter(cu->func->arg_begin());
   ::llvm::Function::arg_iterator arg_end(cu->func->arg_end());
diff --git a/src/compiler/dex/quick/codegen.h b/src/compiler/dex/quick/codegen.h
index 63c8460..21290ca 100644
--- a/src/compiler/dex/quick/codegen.h
+++ b/src/compiler/dex/quick/codegen.h
@@ -17,6 +17,8 @@
 #ifndef ART_SRC_COMPILER_DEX_QUICK_CODEGEN_H_
 #define ART_SRC_COMPILER_DEX_QUICK_CODEGEN_H_
 
+#include "invoke_type.h"
+#include "compiler/dex/compiler_enums.h"
 #include "compiler/dex/compiler_ir.h"
 
 namespace art {
@@ -82,6 +84,14 @@
 #define REG_USE12            (REG_USE1 | REG_USE2)
 #define REG_USE23            (REG_USE2 | REG_USE3)
 
+struct BasicBlock;
+struct CallInfo;
+struct CompilationUnit;
+struct LIR;
+struct MIR;
+struct RegLocation;
+struct RegisterInfo;
+
 typedef int (*NextCallInsn)(CompilationUnit*, CallInfo*, int, uint32_t dex_idx,
                             uint32_t method_idx, uintptr_t direct_code,
                             uintptr_t direct_method, InvokeType type);
diff --git a/src/compiler/dex/quick/codegen_util.cc b/src/compiler/dex/quick/codegen_util.cc
index 5f8f6ef..110146f 100644
--- a/src/compiler/dex/quick/codegen_util.cc
+++ b/src/compiler/dex/quick/codegen_util.cc
@@ -54,10 +54,7 @@
 bool FastInstance(CompilationUnit* cu,  uint32_t field_idx,
                   int& field_offset, bool& is_volatile, bool is_put)
 {
-  DexCompilationUnit m_unit(cu->class_loader, cu->class_linker,
-                            *cu->dex_file, cu->code_item,
-                            cu->class_def_idx, cu->method_idx,
-                            cu->access_flags);
+  DexCompilationUnit m_unit(cu);
   return cu->compiler_driver->ComputeInstanceFieldInfo(field_idx, &m_unit,
            field_offset, is_volatile, is_put);
 }
diff --git a/src/compiler/dex/quick/gen_common.cc b/src/compiler/dex/quick/gen_common.cc
index f14d6cf..a289252 100644
--- a/src/compiler/dex/quick/gen_common.cc
+++ b/src/compiler/dex/quick/gen_common.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "codegen_util.h"
+#include "compiler/dex/quick/codegen_util.h"
 #include "compiler/dex/compiler_ir.h"
 #include "oat/runtime/oat_support_entrypoints.h"
 #include "ralloc_util.h"
@@ -354,8 +354,7 @@
   bool is_volatile;
   bool is_referrers_class;
 
-  DexCompilationUnit m_unit(cu->class_loader, cu->class_linker, *cu->dex_file, cu->code_item,
-                            cu->class_def_idx, cu->method_idx, cu->access_flags);
+  DexCompilationUnit m_unit(cu);
 
   bool fast_path =
       cu->compiler_driver->ComputeStaticFieldInfo(field_idx, &m_unit,
@@ -446,10 +445,7 @@
   bool is_volatile;
   bool is_referrers_class;
 
-  DexCompilationUnit m_unit(cu->class_loader, cu->class_linker,
-                            *cu->dex_file, cu->code_item,
-                            cu->class_def_idx, cu->method_idx,
-                            cu->access_flags);
+  DexCompilationUnit m_unit(cu);
 
   bool fast_path =
       cu->compiler_driver->ComputeStaticFieldInfo(field_idx, &m_unit,
diff --git a/src/compiler/dex/quick/gen_invoke.cc b/src/compiler/dex/quick/gen_invoke.cc
index 2c01c19..1ae29be 100644
--- a/src/compiler/dex/quick/gen_invoke.cc
+++ b/src/compiler/dex/quick/gen_invoke.cc
@@ -16,6 +16,7 @@
 
 #include "codegen_util.h"
 #include "compiler/dex/compiler_ir.h"
+#include "invoke_type.h"
 #include "oat/runtime/oat_support_entrypoints.h"
 #include "ralloc_util.h"
 #include "x86/codegen_x86.h"
@@ -1335,10 +1336,7 @@
   // Explicit register usage
   LockCallTemps(cu);
 
-  DexCompilationUnit m_unit(cu->class_loader, cu->class_linker,
-                            *cu->dex_file, cu->code_item,
-                            cu->class_def_idx, cu->method_idx,
-                            cu->access_flags);
+  DexCompilationUnit m_unit(cu);
 
   uint32_t dex_method_idx = info->index;
   int vtable_idx;
diff --git a/src/compiler/dex/quick/gen_loadstore.cc b/src/compiler/dex/quick/gen_loadstore.cc
index b945e31..a7baea4 100644
--- a/src/compiler/dex/quick/gen_loadstore.cc
+++ b/src/compiler/dex/quick/gen_loadstore.cc
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-#include "codegen_util.h"
+#include "compiler/dex/quick/codegen_util.h"
 #include "compiler/dex/compiler_ir.h"
+#include "invoke_type.h"
 #include "ralloc_util.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/ralloc_util.cc b/src/compiler/dex/quick/ralloc_util.cc
index a782264..5b7de2c 100644
--- a/src/compiler/dex/quick/ralloc_util.cc
+++ b/src/compiler/dex/quick/ralloc_util.cc
@@ -16,10 +16,10 @@
 
 /* This file contains register alloction support. */
 
-#include "codegen_util.h"
 #include "compiler/dex/compiler_ir.h"
 #include "compiler/dex/compiler_utility.h"
 #include "compiler/dex/dataflow.h"
+#include "compiler/dex/quick/codegen_util.h"
 #include "ralloc_util.h"
 
 namespace art {
diff --git a/src/compiler/dex/write_elf.cc b/src/compiler/dex/write_elf.cc
index a78d98e..7e3d512 100644
--- a/src/compiler/dex/write_elf.cc
+++ b/src/compiler/dex/write_elf.cc
@@ -19,12 +19,17 @@
 
 namespace art {
 class CompilerDriver;
+class DexFile;
 }  // namespace art
 
 extern "C" bool WriteElf(art::CompilerDriver& driver,
+                         const std::string* host_prefix,
+                         bool is_host,
+                         const std::vector<const art::DexFile*>& dex_files,
                          std::vector<uint8_t>& oat_contents,
-                         art::File* file) {
-  return art::ElfWriter::Create(file, oat_contents, driver);
+                         art::File* file)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return art::ElfWriter::Create(file, oat_contents, dex_files, host_prefix, is_host, driver);
 }
 extern "C" bool FixupElf(art::File* file, uintptr_t oat_data_begin) {
   return art::ElfWriter::Fixup(file, oat_data_begin);
@@ -34,3 +39,6 @@
                                      size_t& oat_data_offset) {
   art::ElfWriter::GetOatElfInformation(file, oat_loaded_size, oat_data_offset);
 }
+extern "C" bool StripElf(art::File* file) {
+  return art::ElfWriter::Strip(file);
+}
diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc
index a28ba18..8856a00 100644
--- a/src/compiler/driver/compiler_driver.cc
+++ b/src/compiler/driver/compiler_driver.cc
@@ -1678,7 +1678,7 @@
   const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx), &shorty_len);
   bool is_static = (access_flags & kAccStatic) != 0;
   std::string key(MakeInvokeStubKey(is_static, shorty));
-  const CompiledInvokeStub* compiled_invoke_stub = FindInvokeStub(key);
+  CompiledInvokeStub* compiled_invoke_stub = FindInvokeStub(key);
   if (compiled_invoke_stub == NULL) {
     compiled_invoke_stub = (*create_invoke_stub_)(*this, is_static, shorty, shorty_len);
     CHECK(compiled_invoke_stub != NULL);
@@ -1686,7 +1686,7 @@
   }
 
   if ((compiler_backend_ == kPortable) && !is_static) {
-    const CompiledInvokeStub* compiled_proxy_stub = FindProxyStub(shorty);
+    CompiledInvokeStub* compiled_proxy_stub = FindProxyStub(shorty);
     if (compiled_proxy_stub == NULL) {
       compiled_proxy_stub = (*create_proxy_stub_)(*this, shorty, shorty_len);
       CHECK(compiled_proxy_stub != NULL);
@@ -1701,12 +1701,12 @@
   }
 }
 
-const CompiledInvokeStub* CompilerDriver::FindInvokeStub(bool is_static, const char* shorty) const {
+CompiledInvokeStub* CompilerDriver::FindInvokeStub(bool is_static, const char* shorty) const {
   const std::string key(MakeInvokeStubKey(is_static, shorty));
   return FindInvokeStub(key);
 }
 
-const CompiledInvokeStub* CompilerDriver::FindInvokeStub(const std::string& key) const {
+CompiledInvokeStub* CompilerDriver::FindInvokeStub(const std::string& key) const {
   MutexLock mu(Thread::Current(), compiled_invoke_stubs_lock_);
   InvokeStubTable::const_iterator it = compiled_invoke_stubs_.find(key);
   if (it == compiled_invoke_stubs_.end()) {
@@ -1717,8 +1717,7 @@
   }
 }
 
-void CompilerDriver::InsertInvokeStub(const std::string& key,
-                                      const CompiledInvokeStub* compiled_invoke_stub) {
+void CompilerDriver::InsertInvokeStub(const std::string& key, CompiledInvokeStub* compiled_invoke_stub) {
   MutexLock mu(Thread::Current(), compiled_invoke_stubs_lock_);
   InvokeStubTable::iterator it = compiled_invoke_stubs_.find(key);
   if (it != compiled_invoke_stubs_.end()) {
@@ -1729,7 +1728,7 @@
   }
 }
 
-const CompiledInvokeStub* CompilerDriver::FindProxyStub(const char* shorty) const {
+CompiledInvokeStub* CompilerDriver::FindProxyStub(const char* shorty) const {
   MutexLock mu(Thread::Current(), compiled_proxy_stubs_lock_);
   ProxyStubTable::const_iterator it = compiled_proxy_stubs_.find(shorty);
   if (it == compiled_proxy_stubs_.end()) {
@@ -1740,8 +1739,7 @@
   }
 }
 
-void CompilerDriver::InsertProxyStub(const char* shorty,
-                                     const CompiledInvokeStub* compiled_proxy_stub) {
+void CompilerDriver::InsertProxyStub(const char* shorty, CompiledInvokeStub* compiled_proxy_stub) {
   MutexLock mu(Thread::Current(), compiled_proxy_stubs_lock_);
   InvokeStubTable::iterator it = compiled_proxy_stubs_.find(shorty);
   if (it != compiled_proxy_stubs_.end()) {
@@ -1795,11 +1793,21 @@
   return freezing_constructor_classes_.count(ClassReference(dex_file, class_def_index)) != 0;
 }
 
-bool CompilerDriver::WriteElf(std::vector<uint8_t>& oat_contents, File* file) {
-  typedef bool (*WriteElfFn)(CompilerDriver&, std::vector<uint8_t>&, File*);
+bool CompilerDriver::WriteElf(const std::string* host_prefix,
+                              bool is_host,
+                              const std::vector<const DexFile*>& dex_files,
+                              std::vector<uint8_t>& oat_contents,
+                              File* file) {
+  typedef bool (*WriteElfFn)(CompilerDriver&,
+                             const std::string* host_prefix,
+                             bool is_host,
+                             const std::vector<const DexFile*>& dex_files,
+                             std::vector<uint8_t>&,
+                             File*);
   WriteElfFn WriteElf =
     FindFunction<WriteElfFn>(MakeCompilerSoName(compiler_backend_), compiler_library_, "WriteElf");
-  return WriteElf(*this, oat_contents, file);
+  Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
+  return WriteElf(*this, host_prefix, is_host, dex_files, oat_contents, file);
 }
 
 bool CompilerDriver::FixupElf(File* file, uintptr_t oat_data_begin) const {
@@ -1819,11 +1827,18 @@
   GetOatElfInformation(file, oat_loaded_size, oat_data_offset);
 }
 
+bool CompilerDriver::StripElf(File* file) const {
+  typedef bool (*StripElfFn)(File*);
+  StripElfFn StripElf =
+    FindFunction<StripElfFn>(MakeCompilerSoName(compiler_backend_), compiler_library_, "StripElf");
+  return StripElf(file);
+}
+
 void CompilerDriver::InstructionSetToLLVMTarget(InstructionSet instruction_set,
                                                 std::string& target_triple,
                                                 std::string& target_cpu,
                                                 std::string& target_attr) {
-    switch (instruction_set) {
+  switch (instruction_set) {
     case kThumb2:
       target_triple = "thumb-none-linux-gnueabi";
       target_cpu = "cortex-a9";
diff --git a/src/compiler/driver/compiler_driver.h b/src/compiler/driver/compiler_driver.h
index 49bc473..7f67c21 100644
--- a/src/compiler/driver/compiler_driver.h
+++ b/src/compiler/driver/compiler_driver.h
@@ -123,11 +123,11 @@
   CompiledMethod* GetCompiledMethod(MethodReference ref) const
       LOCKS_EXCLUDED(compiled_methods_lock_);
 
-  const CompiledInvokeStub* FindInvokeStub(bool is_static, const char* shorty) const;
-  const CompiledInvokeStub* FindInvokeStub(const std::string& key) const
+  CompiledInvokeStub* FindInvokeStub(bool is_static, const char* shorty) const;
+  CompiledInvokeStub* FindInvokeStub(const std::string& key) const
       LOCKS_EXCLUDED(compiled_invoke_stubs_lock_);
 
-  const CompiledInvokeStub* FindProxyStub(const char* shorty) const;
+  CompiledInvokeStub* FindProxyStub(const char* shorty) const;
 
   void AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file, size_t class_def_index);
   bool RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, size_t class_def_index);
@@ -186,10 +186,15 @@
 
   void SetBitcodeFileName(std::string const& filename);
 
-  // TODO: remove when libart links against LLVM (when separate compiler library is gone)
-  bool WriteElf(std::vector<uint8_t>& oat_contents, File* file);
+  // TODO: remove these Elf wrappers when libart links against LLVM (when separate compiler library is gone)
+  bool WriteElf(const std::string* host_prefix,
+                bool is_host,
+                const std::vector<const DexFile*>& dex_files,
+                std::vector<uint8_t>& oat_contents,
+                File* file);
   bool FixupElf(File* file, uintptr_t oat_data_begin) const;
   void GetOatElfInformation(File* file, size_t& oat_loaded_size, size_t& oat_data_offset) const;
+  bool StripElf(File* file) const;
 
   // TODO: move to a common home for llvm helpers once quick/portable are merged
   static void InstructionSetToLLVMTarget(InstructionSet instruction_set,
@@ -316,10 +321,10 @@
   static void CompileClass(const ParallelCompilationManager* context, size_t class_def_index)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
-  void InsertInvokeStub(const std::string& key, const CompiledInvokeStub* compiled_invoke_stub)
+  void InsertInvokeStub(const std::string& key, CompiledInvokeStub* compiled_invoke_stub)
       LOCKS_EXCLUDED(compiled_invoke_stubs_lock_);
 
-  void InsertProxyStub(const char* shorty, const CompiledInvokeStub* compiled_proxy_stub);
+  void InsertProxyStub(const char* shorty, CompiledInvokeStub* compiled_proxy_stub);
 
   std::vector<const PatchInformation*> code_to_patch_;
   std::vector<const PatchInformation*> methods_to_patch_;
@@ -342,12 +347,12 @@
   mutable Mutex compiled_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   MethodTable compiled_methods_ GUARDED_BY(compiled_methods_lock_);
 
-  typedef SafeMap<std::string, const CompiledInvokeStub*> InvokeStubTable;
+  typedef SafeMap<std::string, CompiledInvokeStub*> InvokeStubTable;
   // Invocation stubs created to allow invocation of the compiled methods.
   mutable Mutex compiled_invoke_stubs_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   InvokeStubTable compiled_invoke_stubs_ GUARDED_BY(compiled_invoke_stubs_lock_);
 
-  typedef SafeMap<std::string, const CompiledInvokeStub*> ProxyStubTable;
+  typedef SafeMap<std::string, CompiledInvokeStub*> ProxyStubTable;
   // Proxy stubs created for proxy invocation delegation
   mutable Mutex compiled_proxy_stubs_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   ProxyStubTable compiled_proxy_stubs_ GUARDED_BY(compiled_proxy_stubs_lock_);
diff --git a/src/compiler/driver/compiler_driver_test.cc b/src/compiler/driver/compiler_driver_test.cc
index 19ccb35..dee448d 100644
--- a/src/compiler/driver/compiler_driver_test.cc
+++ b/src/compiler/driver/compiler_driver_test.cc
@@ -132,6 +132,7 @@
 }
 
 TEST_F(CompilerDriverTest, AbstractMethodErrorStub) {
+  TEST_DISABLED_FOR_PORTABLE();
   jobject class_loader;
   {
     ScopedObjectAccess soa(Thread::Current());
diff --git a/src/compiler/driver/dex_compilation_unit.cc b/src/compiler/driver/dex_compilation_unit.cc
new file mode 100644
index 0000000..67987fa
--- /dev/null
+++ b/src/compiler/driver/dex_compilation_unit.cc
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 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 "dex_compilation_unit.h"
+
+#include "base/stringprintf.h"
+#include "compiler/dex/compiler_ir.h"
+#include "utils.h"
+
+namespace art {
+
+DexCompilationUnit::DexCompilationUnit(CompilationUnit* cu)
+    : cu_(cu),
+      class_loader_(cu->class_loader),
+      class_linker_(cu->class_linker),
+      dex_file_(cu->dex_file),
+      code_item_(cu->code_item),
+      class_def_idx_(cu->class_def_idx),
+      dex_method_idx_(cu->method_idx),
+      access_flags_(cu->access_flags),
+      symbol_(StringPrintf("dex_%s", MangleForJni(PrettyMethod(dex_method_idx_, *dex_file_)).c_str())) {
+}
+
+DexCompilationUnit:: DexCompilationUnit(CompilationUnit* cu,
+                                        jobject class_loader,
+                                        ClassLinker* class_linker,
+                                        const DexFile& dex_file,
+                                        const DexFile::CodeItem* code_item,
+                                        uint32_t class_def_idx,
+                                        uint32_t method_idx,
+                                        uint32_t access_flags)
+    : cu_(cu),
+      class_loader_(class_loader),
+      class_linker_(class_linker),
+      dex_file_(&dex_file),
+      code_item_(code_item),
+      class_def_idx_(class_def_idx),
+      dex_method_idx_(method_idx),
+      access_flags_(access_flags),
+      symbol_(StringPrintf("dex_%s", MangleForJni(PrettyMethod(dex_method_idx_, *dex_file_)).c_str())) {
+}
+
+} // namespace art
diff --git a/src/compiler/driver/dex_compilation_unit.h b/src/compiler/driver/dex_compilation_unit.h
index 6a0218d..0fc1123 100644
--- a/src/compiler/driver/dex_compilation_unit.h
+++ b/src/compiler/driver/dex_compilation_unit.h
@@ -17,26 +17,29 @@
 #ifndef ART_SRC_COMPILER_DEX_DEX_COMPILATION_UNIT_H_
 #define ART_SRC_COMPILER_DEX_DEX_COMPILATION_UNIT_H_
 
-#include "dex_file.h"
-
 #include <stdint.h>
 
+#include "dex_file.h"
+#include "jni.h"
+
 namespace art {
 namespace mirror {
 class ClassLoader;
 class DexCache;
 }  // namespace mirror
 class ClassLinker;
-class DexFile;
+class CompilationUnit;
 
 class DexCompilationUnit {
  public:
-  DexCompilationUnit(jobject class_loader, ClassLinker* class_linker, const DexFile& dex_file,
-                     const DexFile::CodeItem* code_item, uint32_t class_def_idx,
-                     uint32_t method_idx, uint32_t access_flags)
-      : class_loader_(class_loader), class_linker_(class_linker), dex_file_(&dex_file),
-        code_item_(code_item), class_def_idx_(class_def_idx), dex_method_idx_(method_idx),
-        access_flags_(access_flags) {
+  DexCompilationUnit(CompilationUnit* cu);
+
+  DexCompilationUnit(CompilationUnit* cu, jobject class_loader, ClassLinker* class_linker,
+                     const DexFile& dex_file, const DexFile::CodeItem* code_item,
+                     uint32_t class_def_idx, uint32_t method_idx, uint32_t access_flags);
+
+  CompilationUnit* GetCompilationUnit() const {
+    return cu_;
   }
 
   jobject GetClassLoader() const {
@@ -89,8 +92,15 @@
     return ((access_flags_ & kAccSynchronized) != 0);
   }
 
+  const std::string& GetSymbol() const {
+    return symbol_;
+  }
+
  private:
+  CompilationUnit* cu_;
+
   const jobject class_loader_;
+
   ClassLinker* const class_linker_;
 
   const DexFile* const dex_file_;
@@ -99,6 +109,8 @@
   const uint32_t class_def_idx_;
   const uint32_t dex_method_idx_;
   const uint32_t access_flags_;
+
+  const std::string symbol_;
 };
 
 } // namespace art
diff --git a/src/compiler/invoke_stubs/portable/stub_compiler.cc b/src/compiler/invoke_stubs/portable/stub_compiler.cc
index 5c314e6..ec6dc30 100644
--- a/src/compiler/invoke_stubs/portable/stub_compiler.cc
+++ b/src/compiler/invoke_stubs/portable/stub_compiler.cc
@@ -52,7 +52,7 @@
   size_t shorty_size = strlen(shorty);
 
   // Function name
-  std::string func_name(ElfFuncName(cunit_->GetIndex()));
+  std::string func_name(StringPrintf("invoke_stub_%s%s", shorty, is_static ? "_static" : ""));
 
   // Get argument types
   ::llvm::Type* arg_types[] = {
@@ -69,8 +69,8 @@
 
   // Create function
   ::llvm::Function* func =
-    ::llvm::Function::Create(func_type, ::llvm::Function::ExternalLinkage,
-                           func_name, module_);
+    ::llvm::Function::Create(func_type, ::llvm::Function::InternalLinkage,
+                             func_name, module_);
 
 
   // Create basic block for the body of this function
@@ -185,7 +185,8 @@
   cunit_->Materialize();
 
   return new CompiledInvokeStub(cunit_->GetInstructionSet(),
-                                cunit_->GetCompiledCode());
+                                cunit_->GetElfObject(),
+                                func_name);
 }
 
 
@@ -194,7 +195,7 @@
   size_t shorty_size = strlen(shorty);
 
   // Function name
-  std::string func_name(ElfFuncName(cunit_->GetIndex()));
+  std::string func_name(StringPrintf("proxy_stub_%s", shorty));
 
   // Accurate function type
   ::llvm::Type* accurate_ret_type = irb_.getJType(shorty[0]);
@@ -212,7 +213,7 @@
 
   // Create function
   ::llvm::Function* func =
-    ::llvm::Function::Create(accurate_func_type, ::llvm::Function::ExternalLinkage,
+    ::llvm::Function::Create(accurate_func_type, ::llvm::Function::InternalLinkage,
                              func_name, module_);
   switch(shorty[0]) {
     case 'Z':
@@ -271,7 +272,8 @@
   cunit_->Materialize();
 
   return new CompiledInvokeStub(cunit_->GetInstructionSet(),
-                                cunit_->GetCompiledCode());
+                                cunit_->GetElfObject(),
+                                func_name);
 }
 
 
diff --git a/src/compiler/jni/jni_compiler_test.cc b/src/compiler/jni/jni_compiler_test.cc
index 4ed7898..5176752 100644
--- a/src/compiler/jni/jni_compiler_test.cc
+++ b/src/compiler/jni/jni_compiler_test.cc
@@ -130,6 +130,7 @@
 }
 
 TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "foo", "()V",
                reinterpret_cast<void*>(&Java_MyClassNatives_foo));
 
@@ -141,6 +142,7 @@
 }
 
 TEST_F(JniCompilerTest, CompileAndRunIntMethodThroughStub) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "bar", "(I)I",
                NULL /* calling through stub will link with &Java_MyClassNatives_bar */);
 
@@ -155,6 +157,7 @@
 }
 
 TEST_F(JniCompilerTest, CompileAndRunStaticIntMethodThroughStub) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "sbar", "(I)I",
                NULL /* calling through stub will link with &Java_MyClassNatives_sbar */);
 
@@ -181,6 +184,7 @@
 }
 
 TEST_F(JniCompilerTest, CompileAndRunIntMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooI", "(I)I",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooI));
 
@@ -206,6 +210,7 @@
 }
 
 TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooII", "(II)I",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooII));
 
@@ -232,6 +237,7 @@
 }
 
 TEST_F(JniCompilerTest, CompileAndRunLongLongMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooJJ", "(JJ)J",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooJJ));
 
@@ -259,6 +265,7 @@
 }
 
 TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooDD", "(DD)D",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooDD));
 
@@ -287,6 +294,7 @@
 }
 
 TEST_F(JniCompilerTest, CompileAndRun_fooJJ_synchronized) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooJJ_synchronized", "(JJ)J",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooJJ_synchronized));
 
@@ -319,6 +327,7 @@
 }
 
 TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooIOO",
                "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooIOO));
@@ -362,6 +371,7 @@
 }
 
 TEST_F(JniCompilerTest, CompileAndRunStaticIntIntMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "fooSII", "(II)I",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooSII));
 
@@ -384,6 +394,7 @@
 }
 
 TEST_F(JniCompilerTest, CompileAndRunStaticDoubleDoubleMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "fooSDD", "(DD)D",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooSDD));
 
@@ -420,6 +431,7 @@
 
 
 TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "fooSIOO",
                "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooSIOO));
@@ -470,6 +482,7 @@
 }
 
 TEST_F(JniCompilerTest, CompileAndRunStaticSynchronizedIntObjectObjectMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "fooSSIOO",
                "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooSSIOO));
@@ -506,6 +519,7 @@
 }
 
 TEST_F(JniCompilerTest, ExceptionHandling) {
+  TEST_DISABLED_FOR_PORTABLE();
   {
     ASSERT_FALSE(runtime_->IsStarted());
     ScopedObjectAccess soa(Thread::Current());
@@ -585,6 +599,7 @@
 }
 
 TEST_F(JniCompilerTest, NativeStackTraceElement) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooI", "(I)I",
                reinterpret_cast<void*>(&Java_MyClassNatives_nativeUpCall));
   jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 10);
@@ -596,6 +611,7 @@
 }
 
 TEST_F(JniCompilerTest, ReturnGlobalRef) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooO", "(Ljava/lang/Object;)Ljava/lang/Object;",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooO));
   jobject result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, jobj_);
@@ -613,6 +629,7 @@
 }
 
 TEST_F(JniCompilerTest, LocalReferenceTableClearingTest) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooI", "(I)I", reinterpret_cast<void*>(&local_ref_test));
   // 1000 invocations of a method that adds 10 local references
   for (int i = 0; i < 1000; i++) {
@@ -631,6 +648,7 @@
 }
 
 TEST_F(JniCompilerTest, JavaLangSystemArrayCopy) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V",
                reinterpret_cast<void*>(&my_arraycopy));
   env_->CallStaticVoidMethod(jklass_, jmethod_, jobj_, 1234, jklass_, 5678, 9876);
@@ -646,6 +664,7 @@
 }
 
 TEST_F(JniCompilerTest, CompareAndSwapInt) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "compareAndSwapInt", "(Ljava/lang/Object;JII)Z",
                reinterpret_cast<void*>(&my_casi));
   jboolean result = env_->CallBooleanMethod(jobj_, jmethod_, jobj_, 0x12345678ABCDEF88ll, 0xCAFEF00D, 0xEBADF00D);
@@ -662,6 +681,7 @@
 }
 
 TEST_F(JniCompilerTest, GetText) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "getText", "(JLjava/lang/Object;JLjava/lang/Object;)I",
                reinterpret_cast<void*>(&my_gettext));
   jint result = env_->CallStaticIntMethod(jklass_, jmethod_, 0x12345678ABCDEF88ll, jobj_,
@@ -670,6 +690,7 @@
 }
 
 TEST_F(JniCompilerTest, GetSinkPropertiesNative) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "getSinkPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;", NULL);
   // This space intentionally left blank. Just testing compilation succeeds.
 }
@@ -685,6 +706,7 @@
 }
 
 TEST_F(JniCompilerTest, UpcallReturnTypeChecking_Instance) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "instanceMethodThatShouldReturnClass", "()Ljava/lang/Class;",
                reinterpret_cast<void*>(&Java_MyClassNatives_instanceMethodThatShouldReturnClass));
 
@@ -702,6 +724,7 @@
 }
 
 TEST_F(JniCompilerTest, UpcallReturnTypeChecking_Static) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "staticMethodThatShouldReturnClass", "()Ljava/lang/Class;",
                reinterpret_cast<void*>(&Java_MyClassNatives_staticMethodThatShouldReturnClass));
 
@@ -727,6 +750,7 @@
 }
 
 TEST_F(JniCompilerTest, UpcallArgumentTypeChecking_Instance) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "instanceMethodThatShouldTakeClass", "(ILjava/lang/Class;)V",
                reinterpret_cast<void*>(&Java_MyClassNatives_instanceMethodThatShouldTakeClass));
 
@@ -737,6 +761,7 @@
 }
 
 TEST_F(JniCompilerTest, UpcallArgumentTypeChecking_Static) {
+  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "staticMethodThatShouldTakeClass", "(ILjava/lang/Class;)V",
                reinterpret_cast<void*>(&Java_MyClassNatives_staticMethodThatShouldTakeClass));
 
diff --git a/src/compiler/jni/portable/jni_compiler.cc b/src/compiler/jni/portable/jni_compiler.cc
index 1a4ad95..8495150 100644
--- a/src/compiler/jni/portable/jni_compiler.cc
+++ b/src/compiler/jni/portable/jni_compiler.cc
@@ -64,7 +64,10 @@
   char const return_shorty = dex_file->GetMethodShorty(method_id)[0];
   ::llvm::Value* this_object_or_class_object;
 
-  CreateFunction();
+  uint32_t method_idx = dex_compilation_unit_->GetDexMethodIndex();
+  std::string func_name(StringPrintf("jni_%s",
+                                     MangleForJni(PrettyMethod(method_idx, *dex_file)).c_str()));
+  CreateFunction(func_name);
 
   // Set argument name
   ::llvm::Function::arg_iterator arg_begin(func_->arg_begin());
@@ -233,13 +236,13 @@
   cunit_->Materialize();
 
   return new CompiledMethod(cunit_->GetInstructionSet(),
-                            cunit_->GetCompiledCode());
+                            cunit_->GetElfObject(),
+                            func_name);
 }
 
 
-void JniCompiler::CreateFunction() {
-  // LLVM function name
-  std::string func_name(ElfFuncName(cunit_->GetIndex()));
+void JniCompiler::CreateFunction(const std::string& func_name) {
+  CHECK_NE(0U, func_name.size());
 
   const bool is_static = dex_compilation_unit_->IsStatic();
 
@@ -248,8 +251,8 @@
     GetFunctionType(dex_compilation_unit_->GetDexMethodIndex(), is_static, false);
 
   // Create function
-  func_ = ::llvm::Function::Create(func_type, ::llvm::Function::ExternalLinkage,
-                                 func_name, module_);
+  func_ = ::llvm::Function::Create(func_type, ::llvm::Function::InternalLinkage,
+                                   func_name, module_);
 
   // Create basic block
   ::llvm::BasicBlock* basic_block = ::llvm::BasicBlock::Create(*context_, "B0", func_);
diff --git a/src/compiler/jni/portable/jni_compiler.h b/src/compiler/jni/portable/jni_compiler.h
index 3df81a5..a04277c 100644
--- a/src/compiler/jni/portable/jni_compiler.h
+++ b/src/compiler/jni/portable/jni_compiler.h
@@ -19,6 +19,8 @@
 
 #include <stdint.h>
 
+#include <string>
+
 namespace art {
   class ClassLinker;
   class CompiledMethod;
@@ -58,10 +60,10 @@
   CompiledMethod* Compile();
 
  private:
-  void CreateFunction();
+  void CreateFunction(const std::string& symbol);
 
   ::llvm::FunctionType* GetFunctionType(uint32_t method_idx,
-                                      bool is_static, bool is_target_function);
+                                        bool is_static, bool is_target_function);
 
  private:
   LlvmCompilationUnit* cunit_;
diff --git a/src/compiler/llvm/compiler_llvm.cc b/src/compiler/llvm/compiler_llvm.cc
index 1c9a494..be1730f 100644
--- a/src/compiler/llvm/compiler_llvm.cc
+++ b/src/compiler/llvm/compiler_llvm.cc
@@ -16,14 +16,15 @@
 
 #include "compiler_llvm.h"
 
-#include "base/stl_util.h"
 #include "backend_options.h"
+#include "base/stl_util.h"
 #include "class_linker.h"
 #include "compiled_method.h"
 #include "compiler/driver/compiler_driver.h"
 #include "compiler/driver/dex_compilation_unit.h"
 #include "compiler/invoke_stubs/portable/stub_compiler.h"
 #include "compiler/jni/portable/jni_compiler.h"
+#include "globals.h"
 #include "ir_builder.h"
 #include "llvm_compilation_unit.h"
 #include "oat_file.h"
@@ -43,7 +44,7 @@
                       uint32_t access_flags, InvokeType invoke_type,
                       uint32_t class_def_idx, uint32_t method_idx, jobject class_loader,
                       const DexFile& dex_file,
-                      LLVMInfo* llvm_info);
+                      llvm::LlvmCompilationUnit* llvm_info);
 }
 
 namespace llvm {
@@ -65,17 +66,17 @@
   art::llvm::InitialBackendOptions();
 
   // Initialize LLVM target, MC subsystem, asm printer, and asm parser.
-#if defined(ART_TARGET)
-  // Don't initialize all targets on device. Just initialize the device's native target
-  llvm::InitializeNativeTarget();
-  llvm::InitializeNativeTargetAsmPrinter();
-  llvm::InitializeNativeTargetAsmParser();
-#else
-  llvm::InitializeAllTargets();
-  llvm::InitializeAllTargetMCs();
-  llvm::InitializeAllAsmPrinters();
-  llvm::InitializeAllAsmParsers();
-#endif
+  if (art::kIsTargetBuild) {
+    // Don't initialize all targets on device. Just initialize the device's native target
+    llvm::InitializeNativeTarget();
+    llvm::InitializeNativeTargetAsmPrinter();
+    llvm::InitializeNativeTargetAsmParser();
+  } else {
+    llvm::InitializeAllTargets();
+    llvm::InitializeAllTargetMCs();
+    llvm::InitializeAllAsmPrinters();
+    llvm::InitializeAllAsmParsers();
+  }
 
   // Initialize LLVM optimization passes
   llvm::PassRegistry &registry = *llvm::PassRegistry::getPassRegistry();
@@ -110,8 +111,7 @@
 
 CompilerLLVM::CompilerLLVM(CompilerDriver* driver, InstructionSet insn_set)
     : compiler_driver_(driver), insn_set_(insn_set),
-      num_cunits_lock_("compilation unit counter lock"), num_cunits_(0),
-      plt_(insn_set) {
+      next_cunit_id_lock_("compilation unit id lock"), next_cunit_id_(1) {
 
   // Initialize LLVM libraries
   pthread_once(&llvm_initialized, InitializeLLVM);
@@ -123,10 +123,12 @@
 
 
 LlvmCompilationUnit* CompilerLLVM::AllocateCompilationUnit() {
-  MutexLock GUARD(Thread::Current(), num_cunits_lock_);
-  LlvmCompilationUnit* cunit = new LlvmCompilationUnit(this, ++num_cunits_);
+  MutexLock GUARD(Thread::Current(), next_cunit_id_lock_);
+  LlvmCompilationUnit* cunit = new LlvmCompilationUnit(this, next_cunit_id_++);
   if (!bitcode_filename_.empty()) {
-    cunit->SetBitcodeFileName(StringPrintf("%s-%zu", bitcode_filename_.c_str(), cunit->GetIndex()));
+    cunit->SetBitcodeFileName(StringPrintf("%s-%zu",
+                                           bitcode_filename_.c_str(),
+                                           cunit->GetCompilationUnitId()));
   }
   return cunit;
 }
@@ -136,8 +138,8 @@
 CompileDexMethod(DexCompilationUnit* dex_compilation_unit, InvokeType invoke_type) {
   UniquePtr<LlvmCompilationUnit> cunit(AllocateCompilationUnit());
 
-  std::string methodName(PrettyMethod(dex_compilation_unit->GetDexMethodIndex(),
-                                      *dex_compilation_unit->GetDexFile()));
+  cunit->SetDexCompilationUnit(dex_compilation_unit);
+  cunit->SetCompiler(compiler_driver_);
   // TODO: consolidate ArtCompileMethods
   CompileOneMethod(*compiler_driver_,
                    kPortable,
@@ -148,19 +150,16 @@
                    dex_compilation_unit->GetDexMethodIndex(),
                    dex_compilation_unit->GetClassLoader(),
                    *dex_compilation_unit->GetDexFile(),
-                   cunit->GetQuickContext()
-  );
-
-  cunit->SetCompiler(compiler_driver_);
-  cunit->SetDexCompilationUnit(dex_compilation_unit);
+                   cunit.get());
 
   cunit->Materialize();
 
   CompilerDriver::MethodReference mref(dex_compilation_unit->GetDexFile(),
                                        dex_compilation_unit->GetDexMethodIndex());
   return new CompiledMethod(compiler_driver_->GetInstructionSet(),
-                            cunit->GetCompiledCode(),
-                            *verifier::MethodVerifier::GetDexGcMap(mref));
+                            cunit->GetElfObject(),
+                            *verifier::MethodVerifier::GetDexGcMap(mref),
+                            cunit->GetDexCompilationUnit()->GetSymbol());
 }
 
 
@@ -235,7 +234,7 @@
   art::ClassLinker *class_linker = art::Runtime::Current()->GetClassLinker();
 
   art::DexCompilationUnit dex_compilation_unit(
-    class_loader, class_linker, dex_file, code_item,
+    NULL, class_loader, class_linker, dex_file, code_item,
     class_def_idx, method_idx, access_flags);
   art::llvm::CompilerLLVM* compiler_llvm = ContextOf(driver);
   art::CompiledMethod* result = compiler_llvm->CompileDexMethod(&dex_compilation_unit, invoke_type);
@@ -248,7 +247,7 @@
   art::ClassLinker *class_linker = art::Runtime::Current()->GetClassLinker();
 
   art::DexCompilationUnit dex_compilation_unit(
-    NULL, class_linker, dex_file, NULL,
+    NULL, NULL, class_linker, dex_file, NULL,
     0, method_idx, access_flags);
 
   art::llvm::CompilerLLVM* compiler_llvm = ContextOf(driver);
diff --git a/src/compiler/llvm/compiler_llvm.h b/src/compiler/llvm/compiler_llvm.h
index 870a541..cbee115 100644
--- a/src/compiler/llvm/compiler_llvm.h
+++ b/src/compiler/llvm/compiler_llvm.h
@@ -22,7 +22,6 @@
 #include "dex_file.h"
 #include "instruction_set.h"
 #include "mirror/object.h"
-#include "procedure_linkage_table.h"
 
 #include <UniquePtr.h>
 
@@ -87,10 +86,6 @@
 
   CompiledInvokeStub* CreateProxyStub(const char *shorty);
 
-  const ProcedureLinkageTable& GetProcedureLinkageTable() const {
-    return plt_;
-  }
-
  private:
   LlvmCompilationUnit* AllocateCompilationUnit();
 
@@ -98,13 +93,11 @@
 
   InstructionSet insn_set_;
 
-  Mutex num_cunits_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
-  size_t num_cunits_ GUARDED_BY(num_cunits_lock_);
+  Mutex next_cunit_id_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  size_t next_cunit_id_ GUARDED_BY(next_cunit_id_lock_);
 
   std::string bitcode_filename_;
 
-  ProcedureLinkageTable plt_;
-
   DISALLOW_COPY_AND_ASSIGN(CompilerLLVM);
 };
 
diff --git a/src/compiler/llvm/compiler_runtime_func_list.h b/src/compiler/llvm/compiler_runtime_func_list.h
deleted file mode 100644
index ffbae85..0000000
--- a/src/compiler/llvm/compiler_runtime_func_list.h
+++ /dev/null
@@ -1,234 +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_SRC_COMPILER_LLVM_COMPILER_RUNTIME_FUNC_LIST_H_
-#define ART_SRC_COMPILER_LLVM_COMPILER_RUNTIME_FUNC_LIST_H_
-
-// NOTE: COMPILER_RUNTIME_FUNC_LIST_* should be sorted!
-
-#define COMPILER_RUNTIME_FUNC_LIST_X86(V) \
-  V(__ashldi3,          long long, long long, int) \
-  V(__ashrdi3,          long long, long long, int) \
-  V(__divdi3,           long long, long long, long long) \
-  V(__fixdfdi,          long long, double) \
-  V(__fixsfdi,          long long, float) \
-  V(__fixtfdi,          long long, long double) \
-  V(__fixtfsi,          int, long double) \
-  V(__fixunsdfdi,       unsigned long long, double) \
-  V(__fixunsdfsi,       unsigned int, double) \
-  V(__fixunssfdi,       unsigned long long, float) \
-  V(__fixunssfsi,       unsigned int, float) \
-  V(__fixunstfdi,       unsigned long long, long double) \
-  V(__fixunstfsi,       unsigned int, long double) \
-  V(__fixunsxfdi,       unsigned long long, long double) \
-  V(__fixunsxfsi,       unsigned int, long double) \
-  V(__fixxfdi,          long long, long double) \
-  V(__floatdidf,        double, long long) \
-  V(__floatdisf,        float, long long) \
-  V(__floatditf,        long double, long long) \
-  V(__floatdixf,        long double, long long) \
-  V(__floatsitf,        long double, int) \
-  V(__floatundidf,      double, unsigned long long) \
-  V(__floatundisf,      float, unsigned long long) \
-  V(__floatunditf,      long double, unsigned long long) \
-  V(__floatundixf,      long double, unsigned long long) \
-  V(__floatunsitf,      long double, int) \
-  V(__lshrdi3,          long long, long long, int) \
-  V(__moddi3,           long long, long long, long long) \
-  V(__muldi3,           long long, long long, long long) \
-  V(__negdi2,           long long, long long) \
-  V(__powidf2,          double, double, int) \
-  V(__powisf2,          float, float, int) \
-  V(__powitf2,          long double, long double, int) \
-  V(__powixf2,          long double, long double, int) \
-  V(__trunctfdf2,       double, long double) \
-  V(__trunctfsf2,       float, long double) \
-  V(__udivdi3,          unsigned long long, unsigned long long, unsigned long long) \
-  V(__umoddi3,          unsigned long long, unsigned long long, unsigned long long) \
-  V(ceil,               double, double) \
-  V(ceilf,              float, float) \
-  V(ceill,              long double, long double) \
-  V(copysign,           double, double, double) \
-  V(copysignf,          float, float, float) \
-  V(copysignl,          long double, long double, long double) \
-  V(cos,                double, double) \
-  V(cosf,               float, float) \
-  V(exp,                double, double) \
-  V(exp2,               double, double) \
-  V(exp2f,              float, float) \
-  V(expf,               float, float) \
-  V(floor,              double, double) \
-  V(floorf,             float, float) \
-  V(floorl,             long double, long double) \
-  V(fma,                double, double, double, double) \
-  V(fmaf,               float, float, float, float) \
-  V(fmod,               double, double, double) \
-  V(fmodf,              float, float, float) \
-  V(log,                double, double) \
-  V(log10,              double, double) \
-  V(log10f,             float, float) \
-  V(logf,               float, float) \
-  V(memcpy,             void *, void *, const void *, size_t) \
-  V(memmove,            void *, void *, const void *, size_t) \
-  V(memset,             void *, void *, int, size_t) \
-  V(nearbyint,          double, double) \
-  V(nearbyintf,         float, float) \
-  V(pow,                double, double, double) \
-  V(powf,               float, float, float) \
-  V(rint,               double, double) \
-  V(rintf,              float, float) \
-  V(sin,                double, double) \
-  V(sinf,               float, float) \
-  V(sqrt,               double, double) \
-  V(sqrtf,              float, float) \
-  V(trunc,              double, double) \
-  V(truncf,             float, float) \
-  V(truncl,             long double, long double)
-
-#define COMPILER_RUNTIME_FUNC_LIST_MIPS(V) \
-  V(__ashldi3,          long long, long long, int) \
-  V(__ashrdi3,          long long, long long, int) \
-  V(__divdi3,           long long, long long, long long) \
-  V(__fixdfdi,          long long, double) \
-  V(__fixsfdi,          long long, float) \
-  V(__fixunsdfdi,       unsigned long long, double) \
-  V(__fixunsdfsi,       unsigned int, double) \
-  V(__fixunssfdi,       unsigned long long, float) \
-  V(__fixunssfsi,       unsigned int, float) \
-  V(__floatdidf,        double, long long) \
-  V(__floatdisf,        float, long long) \
-  V(__floatundidf,      double, unsigned long long) \
-  V(__floatundisf,      float, unsigned long long) \
-  V(__lshrdi3,          long long, long long, int) \
-  V(__moddi3,           long long, long long, long long) \
-  V(__muldi3,           long long, long long, long long) \
-  V(__negdi2,           long long, long long) \
-  V(__powidf2,          double, double, int) \
-  V(__powisf2,          float, float, int) \
-  V(__udivdi3,          unsigned long long, unsigned long long, unsigned long long) \
-  V(__umoddi3,          unsigned long long, unsigned long long, unsigned long long) \
-  V(ceil,               double, double) \
-  V(ceilf,              float, float) \
-  V(ceill,              long double, long double) \
-  V(copysign,           double, double, double) \
-  V(copysignf,          float, float, float) \
-  V(copysignl,          long double, long double, long double) \
-  V(cos,                double, double) \
-  V(cosf,               float, float) \
-  V(exp,                double, double) \
-  V(exp2,               double, double) \
-  V(exp2f,              float, float) \
-  V(expf,               float, float) \
-  V(floor,              double, double) \
-  V(floorf,             float, float) \
-  V(floorl,             long double, long double) \
-  V(fma,                double, double, double, double) \
-  V(fmaf,               float, float, float, float) \
-  V(fmod,               double, double, double) \
-  V(fmodf,              float, float, float) \
-  V(log,                double, double) \
-  V(log10,              double, double) \
-  V(log10f,             float, float) \
-  V(logf,               float, float) \
-  V(memcpy,             void *, void *, const void *, size_t) \
-  V(memmove,            void *, void *, const void *, size_t) \
-  V(memset,             void *, void *, int, size_t) \
-  V(nearbyint,          double, double) \
-  V(nearbyintf,         float, float) \
-  V(pow,                double, double, double) \
-  V(powf,               float, float, float) \
-  V(rint,               double, double) \
-  V(rintf,              float, float) \
-  V(sin,                double, double) \
-  V(sinf,               float, float) \
-  V(sqrt,               double, double) \
-  V(sqrtf,              float, float) \
-  V(trunc,              double, double) \
-  V(truncf,             float, float) \
-  V(truncl,             long double, long double)
-
-#define COMPILER_RUNTIME_FUNC_LIST_ARM(V) \
-  V(__aeabi_d2f,        float, double) \
-  V(__aeabi_d2iz,       int, double) \
-  V(__aeabi_d2lz,       long long, double) \
-  V(__aeabi_d2uiz,      unsigned, double) \
-  V(__aeabi_d2ulz,      unsigned long long, double) \
-  V(__aeabi_dadd,       double, double, double) \
-  V(__aeabi_dcmpeq,     int, double, double) \
-  V(__aeabi_dcmpge,     int, double, double) \
-  V(__aeabi_dcmpgt,     int, double, double) \
-  V(__aeabi_dcmple,     int, double, double) \
-  V(__aeabi_dcmplt,     int, double, double) \
-  V(__aeabi_dcmpun,     int, double, double) \
-  V(__aeabi_ddiv,       double, double, double) \
-  V(__aeabi_dmul,       double, double, double) \
-  V(__aeabi_dsub,       double, double, double) \
-  V(__aeabi_f2d,        double, float) \
-  V(__aeabi_f2iz,       int, float) \
-  V(__aeabi_f2lz,       long long, float) \
-  V(__aeabi_f2uiz,      unsigned int, float) \
-  V(__aeabi_f2ulz,      unsigned long long, float) \
-  V(__aeabi_fadd,       float, float, float) \
-  V(__aeabi_fcmpeq,     int, float, float) \
-  V(__aeabi_fcmpge,     int, float, float) \
-  V(__aeabi_fcmpgt,     int, float, float) \
-  V(__aeabi_fcmple,     int, float, float) \
-  V(__aeabi_fcmplt,     int, float, float) \
-  V(__aeabi_fcmpun,     int, float, float) \
-  V(__aeabi_fdiv,       float, float, float) \
-  V(__aeabi_fmul,       float, float, float) \
-  V(__aeabi_fsub,       float, float, float) \
-  V(__aeabi_i2d,        double, int) \
-  V(__aeabi_i2f,        float, int) \
-  V(__aeabi_idiv,       int, int, int) \
-  V(__aeabi_l2d,        double, long long) \
-  V(__aeabi_l2f,        float, long long) \
-  V(__aeabi_lasr,       long long, long long, int) \
-  V(__aeabi_ldivmod,    /* value in regs */ void, long long, long long) \
-  V(__aeabi_llsl,       long long, long long, int) \
-  V(__aeabi_llsr,       long long, long long, int) \
-  V(__aeabi_lmul,       long long, long long, long long) \
-  V(__aeabi_memcpy,     void, void *, const void *, size_t) \
-  V(__aeabi_memmove,    void, void *, const void *, size_t) \
-  V(__aeabi_memset,     void, void *, size_t, int) /* different from stdlib */ \
-  V(__aeabi_ui2d,       double, unsigned int) \
-  V(__aeabi_ui2f,       float, unsigned int) \
-  V(__aeabi_uidiv,      unsigned int, unsigned int, unsigned int) \
-  V(__aeabi_ul2d,       double, unsigned long long) \
-  V(__aeabi_ul2f,       float, unsigned long long) \
-  V(__aeabi_uldivmod,   /* value in regs */ void, unsigned long long, unsigned long long) \
-  V(__moddi3,           long long, long long, long long) \
-  V(__modsi3,           int, int, int) \
-  V(__umoddi3,          unsigned long long, unsigned long long, unsigned long long) \
-  V(__umodsi3,          unsigned int, unsigned int, unsigned int) \
-  V(fmod,               double, double, double) \
-  V(fmodf,              float, float, float) \
-  V(memcpy,             void *, void *, const void *, size_t) \
-  V(memmove,            void *, void *, const void *, size_t) \
-  V(memset,             void *, void *, int, size_t)
-
-
-#if defined(__arm__)
-#define COMPILER_RUNTIME_FUNC_LIST_NATIVE(V) COMPILER_RUNTIME_FUNC_LIST_ARM(V)
-#elif defined(__mips__)
-#define COMPILER_RUNTIME_FUNC_LIST_NATIVE(V) COMPILER_RUNTIME_FUNC_LIST_MIPS(V)
-#elif defined(__i386__)
-#define COMPILER_RUNTIME_FUNC_LIST_NATIVE(V) COMPILER_RUNTIME_FUNC_LIST_X86(V)
-#else
-#error "Unknown target platform"
-#endif
-
-#endif // ART_SRC_COMPILER_LLVM_COMPILER_RUNTIME_FUNC_LIST_H_
diff --git a/src/compiler/llvm/gbc_expander.cc b/src/compiler/llvm/gbc_expander.cc
index 4e1a91d..9de2e41 100644
--- a/src/compiler/llvm/gbc_expander.cc
+++ b/src/compiler/llvm/gbc_expander.cc
@@ -326,7 +326,7 @@
   static char ID;
 
   GBCExpanderPass(const IntrinsicHelper& intrinsic_helper, IRBuilder& irb,
-                  art::CompilerDriver* compiler, art::DexCompilationUnit* dex_compilation_unit)
+                  art::CompilerDriver* compiler, const art::DexCompilationUnit* dex_compilation_unit)
       : llvm::FunctionPass(ID), intrinsic_helper_(intrinsic_helper), irb_(irb),
         context_(irb.getContext()), rtb_(irb.Runtime()),
         shadow_frame_(NULL), old_shadow_frame_(NULL),
@@ -350,7 +350,7 @@
   VLOG(compiler) << "GBC expansion on " << func.getName().str();
 
   // Runtime support or stub
-  if (func.getName().startswith("art_") || func.getName().startswith("Art")) {
+  if (dex_compilation_unit_ == NULL) {
     return false;
   }
 
@@ -3634,7 +3634,7 @@
 
 ::llvm::FunctionPass*
 CreateGBCExpanderPass(const IntrinsicHelper& intrinsic_helper, IRBuilder& irb,
-                      CompilerDriver* driver, DexCompilationUnit* dex_compilation_unit) {
+                      CompilerDriver* driver, const DexCompilationUnit* dex_compilation_unit) {
   return new GBCExpanderPass(intrinsic_helper, irb, driver, dex_compilation_unit);
 }
 
diff --git a/src/compiler/llvm/llvm_compilation_unit.cc b/src/compiler/llvm/llvm_compilation_unit.cc
index aad18fb..3783ae9 100644
--- a/src/compiler/llvm/llvm_compilation_unit.cc
+++ b/src/compiler/llvm/llvm_compilation_unit.cc
@@ -16,16 +16,11 @@
 
 #include "llvm_compilation_unit.h"
 
-#include "base/logging.h"
-#include "compiled_method.h"
-#include "compiler_llvm.h"
-#include "instruction_set.h"
-#include "ir_builder.h"
-#include "os.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
 
-#include "runtime_support_builder_arm.h"
-#include "runtime_support_builder_thumb2.h"
-#include "runtime_support_builder_x86.h"
+#include <string>
 
 #include <llvm/ADT/OwningPtr.h>
 #include <llvm/ADT/StringSet.h>
@@ -71,24 +66,30 @@
 #include <llvm/Transforms/IPO/PassManagerBuilder.h>
 #include <llvm/Transforms/Scalar.h>
 
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <string>
+#include "base/logging.h"
+#include "base/unix_file/fd_file.h"
+#include "compiled_method.h"
+#include "compiler_llvm.h"
+#include "instruction_set.h"
+#include "ir_builder.h"
+#include "os.h"
+#include "runtime_support_builder_arm.h"
+#include "runtime_support_builder_thumb2.h"
+#include "runtime_support_builder_x86.h"
+#include "utils_llvm.h"
 
 namespace art {
 namespace llvm {
 
 ::llvm::FunctionPass*
 CreateGBCExpanderPass(const IntrinsicHelper& intrinsic_helper, IRBuilder& irb,
-                      CompilerDriver* compiler, DexCompilationUnit* dex_compilation_unit);
+                      CompilerDriver* compiler, const DexCompilationUnit* dex_compilation_unit);
 
 ::llvm::Module* makeLLVMModuleContents(::llvm::Module* module);
 
 
-LlvmCompilationUnit::LlvmCompilationUnit(const CompilerLLVM* compiler_llvm, size_t cunit_idx)
-    : compiler_llvm_(compiler_llvm), cunit_idx_(cunit_idx) {
+LlvmCompilationUnit::LlvmCompilationUnit(const CompilerLLVM* compiler_llvm, size_t cunit_id)
+    : compiler_llvm_(compiler_llvm), cunit_id_(cunit_id) {
   driver_ = NULL;
   dex_compilation_unit_ = NULL;
   llvm_info_.reset(new LLVMInfo());
@@ -136,27 +137,24 @@
 
 
 bool LlvmCompilationUnit::Materialize() {
-  std::string elf_image;
-
   // Compile and prelink ::llvm::Module
-  if (!MaterializeToString(elf_image)) {
-    LOG(ERROR) << "Failed to materialize compilation unit " << cunit_idx_;
+  if (!MaterializeToString(elf_object_)) {
+    LOG(ERROR) << "Failed to materialize compilation unit " << cunit_id_;
     return false;
   }
 
-#if 0
-  // Dump the ELF image for debugging
-  std::string filename(StringPrintf("%s/Art%zu.elf",
-                                    GetArtCacheOrDie(GetAndroidData()).c_str(),
-                                    cunit_idx_));
-  UniquePtr<File> output(OS::OpenFile(filename.c_str(), true));
-  output->WriteFully(elf_image.data(), elf_image.size());
-#endif
-
-  // Extract the .text section and prelink the code
-  if (!ExtractCodeAndPrelink(elf_image)) {
-    LOG(ERROR) << "Failed to extract code from compilation unit " << cunit_idx_;
-    return false;
+  if (false) {
+    // Dump the ELF image for debugging
+    std::string directory;
+    if (kIsTargetBuild) {
+      directory += GetArtCacheOrDie(GetAndroidData());
+    } else {
+      directory += "/tmp";
+    }
+    std::string filename(StringPrintf("%s/Art%u.o", directory.c_str(), cunit_id_));
+    UniquePtr<File> output(OS::OpenFile(filename.c_str(), true));
+    output->WriteFully(elf_object_.data(), elf_object_.size());
+    LOG(INFO) << ".o file written successfully: " << filename;
   }
 
   return true;
@@ -284,112 +282,6 @@
   return true;
 }
 
-bool LlvmCompilationUnit::ExtractCodeAndPrelink(const std::string& elf_image) {
-  if (GetInstructionSet() == kX86) {
-    compiled_code_.push_back(0xccU);
-    compiled_code_.push_back(0xccU);
-    compiled_code_.push_back(0xccU);
-    compiled_code_.push_back(0xccU);
-    return true;
-  }
-
-  ::llvm::OwningPtr< ::llvm::MemoryBuffer> elf_image_buff(
-    ::llvm::MemoryBuffer::getMemBuffer(::llvm::StringRef(elf_image.data(),
-                                                     elf_image.size())));
-
-  ::llvm::OwningPtr< ::llvm::object::ObjectFile> elf_file(
-    ::llvm::object::ObjectFile::createELFObjectFile(elf_image_buff.take()));
-
-  ::llvm::error_code ec;
-
-  const ProcedureLinkageTable& plt = compiler_llvm_->GetProcedureLinkageTable();
-
-  for (::llvm::object::section_iterator
-       sec_iter = elf_file->begin_sections(),
-       sec_end = elf_file->end_sections();
-       sec_iter != sec_end; sec_iter.increment(ec)) {
-
-    CHECK(ec == 0) << "Failed to read section because " << ec.message();
-
-    // Read the section information
-    ::llvm::StringRef name;
-    uint64_t alignment = 0u;
-    uint64_t size = 0u;
-
-    CHECK(sec_iter->getName(name) == 0);
-    CHECK(sec_iter->getSize(size) == 0);
-    CHECK(sec_iter->getAlignment(alignment) == 0);
-
-    if (name == ".data" || name == ".bss" || name == ".rodata") {
-      if (size > 0) {
-        LOG(FATAL) << "Compilation unit " << cunit_idx_ << " has non-empty "
-                   << name.str() << " section";
-      }
-
-    } else if (name == "" || name == ".rel.text" ||
-               name == ".ARM.attributes" || name == ".symtab" ||
-               name == ".strtab" || name == ".shstrtab") {
-      // We can ignore these sections.  We don't have to copy them into
-      // the result Oat file.
-
-    } else if (name == ".text") {
-      // Ensure the alignment requirement is less than or equal to
-      // kArchAlignment
-      CheckCodeAlign(alignment);
-
-      // Copy the compiled code
-      ::llvm::StringRef contents;
-      CHECK(sec_iter->getContents(contents) == 0);
-
-      copy(contents.data(),
-           contents.data() + contents.size(),
-           back_inserter(compiled_code_));
-
-      // Prelink the compiled code
-      for (::llvm::object::relocation_iterator
-           rel_iter = sec_iter->begin_relocations(),
-           rel_end = sec_iter->end_relocations(); rel_iter != rel_end;
-           rel_iter.increment(ec)) {
-
-        CHECK(ec == 0) << "Failed to read relocation because " << ec.message();
-
-        // Read the relocation information
-        ::llvm::object::SymbolRef sym_ref;
-        uint64_t rel_offset = 0;
-        uint64_t rel_type = 0;
-        int64_t rel_addend = 0;
-
-        CHECK(rel_iter->getSymbol(sym_ref) == 0);
-        CHECK(rel_iter->getOffset(rel_offset) == 0);
-        CHECK(rel_iter->getType(rel_type) == 0);
-        CHECK(rel_iter->getAdditionalInfo(rel_addend) == 0);
-
-        // Read the symbol related to this relocation fixup
-        ::llvm::StringRef sym_name;
-        CHECK(sym_ref.getName(sym_name) == 0);
-
-        // Relocate the fixup.
-        // TODO: Support more relocation type.
-        CHECK(rel_type == ::llvm::ELF::R_ARM_ABS32);
-        CHECK_LE(rel_offset + 4, compiled_code_.size());
-
-        uintptr_t dest_addr = plt.GetEntryAddress(sym_name.str().c_str());
-        uintptr_t final_addr = dest_addr + rel_addend;
-        compiled_code_[rel_offset] = final_addr & 0xff;
-        compiled_code_[rel_offset + 1] = (final_addr >> 8) & 0xff;
-        compiled_code_[rel_offset + 2] = (final_addr >> 16) & 0xff;
-        compiled_code_[rel_offset + 3] = (final_addr >> 24) & 0xff;
-      }
-
-    } else {
-      LOG(WARNING) << "Unexpected section: " << name.str();
-    }
-  }
-
-  return true;
-}
-
-
 // Check whether the align is less than or equal to the code alignment of
 // that architecture.  Since the Oat writer only guarantee that the compiled
 // method being aligned to kArchAlignment, we have no way to align the ELf
diff --git a/src/compiler/llvm/llvm_compilation_unit.h b/src/compiler/llvm/llvm_compilation_unit.h
index 9ca9e3f..96d019c 100644
--- a/src/compiler/llvm/llvm_compilation_unit.h
+++ b/src/compiler/llvm/llvm_compilation_unit.h
@@ -53,8 +53,8 @@
  public:
   ~LlvmCompilationUnit();
 
-  size_t GetIndex() const {
-    return cunit_idx_;
+  uint32_t GetCompilationUnitId() const {
+    return cunit_id_;
   }
 
   InstructionSet GetInstructionSet() const;
@@ -81,27 +81,30 @@
   void SetCompiler(CompilerDriver* driver) {
     driver_ = driver;
   }
-  void SetDexCompilationUnit(DexCompilationUnit* dex_compilation_unit) {
+  const DexCompilationUnit* GetDexCompilationUnit() {
+    return dex_compilation_unit_;
+  }
+  void SetDexCompilationUnit(const DexCompilationUnit* dex_compilation_unit) {
     dex_compilation_unit_ = dex_compilation_unit;
   }
 
   bool Materialize();
 
   bool IsMaterialized() const {
-    return !compiled_code_.empty();
+    return !elf_object_.empty();
   }
 
-  const std::vector<uint8_t>& GetCompiledCode() const {
+  const std::string& GetElfObject() const {
     DCHECK(IsMaterialized());
-    return compiled_code_;
+    return elf_object_;
   }
 
  private:
   LlvmCompilationUnit(const CompilerLLVM* compiler_llvm,
-                      size_t cunit_idx);
+                      uint32_t cunit_id);
 
   const CompilerLLVM* compiler_llvm_;
-  const size_t cunit_idx_;
+  const uint32_t cunit_id_;
 
   UniquePtr< ::llvm::LLVMContext> context_;
   UniquePtr<IRBuilder> irb_;
@@ -110,11 +113,11 @@
   UniquePtr<IntrinsicHelper> intrinsic_helper_;
   UniquePtr<LLVMInfo> llvm_info_;
   CompilerDriver* driver_;
-  DexCompilationUnit* dex_compilation_unit_;
+  const DexCompilationUnit* dex_compilation_unit_;
 
   std::string bitcode_filename_;
 
-  std::vector<uint8_t> compiled_code_;
+  std::string elf_object_;
 
   SafeMap<const ::llvm::Function*, CompiledMethod*> compiled_methods_map_;
 
@@ -123,8 +126,6 @@
   bool MaterializeToString(std::string& str_buffer);
   bool MaterializeToRawOStream(::llvm::raw_ostream& out_stream);
 
-  bool ExtractCodeAndPrelink(const std::string& elf_image);
-
   friend class CompilerLLVM;  // For LlvmCompilationUnit constructor
 };
 
diff --git a/src/compiler/llvm/procedure_linkage_table.cc b/src/compiler/llvm/procedure_linkage_table.cc
deleted file mode 100644
index 47ba9bd..0000000
--- a/src/compiler/llvm/procedure_linkage_table.cc
+++ /dev/null
@@ -1,326 +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 "procedure_linkage_table.h"
-
-#include "base/logging.h"
-#include "compiler_runtime_func_list.h"
-#include "globals.h"
-#include "instruction_set.h"
-#include "runtime_support_func_list.h"
-#include "runtime_support_llvm.h"
-#include "utils_llvm.h"
-
-#include <algorithm>
-
-#include <UniquePtr.h>
-
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-
-namespace {
-  const char* const art_runtime_func_name_list[] = {
-#define DEFINE_ENTRY(ID, NAME) #NAME,
-    RUNTIME_SUPPORT_FUNC_LIST(DEFINE_ENTRY)
-#undef DEFINE_ENTRY
-  };
-
-  const char* const compiler_runtime_func_name_list_arm[] = {
-#define DEFINE_ENTRY(NAME, RETURN_TYPE, ...) #NAME,
-    COMPILER_RUNTIME_FUNC_LIST_ARM(DEFINE_ENTRY)
-#undef DEFINE_ENTRY
-  };
-
-  const char* const compiler_runtime_func_name_list_mips[] = {
-#define DEFINE_ENTRY(NAME, RETURN_TYPE, ...) #NAME,
-    COMPILER_RUNTIME_FUNC_LIST_MIPS(DEFINE_ENTRY)
-#undef DEFINE_ENTRY
-  };
-
-  const char* const compiler_runtime_func_name_list_x86[] = {
-#define DEFINE_ENTRY(NAME, RETURN_TYPE, ...) #NAME,
-    COMPILER_RUNTIME_FUNC_LIST_X86(DEFINE_ENTRY)
-#undef DEFINE_ENTRY
-  };
-
-  const size_t art_runtime_func_count =
-    sizeof(art_runtime_func_name_list) / sizeof(const char*);
-
-  const size_t compiler_runtime_func_count_arm =
-    sizeof(compiler_runtime_func_name_list_arm) / sizeof(const char*);
-
-  const size_t compiler_runtime_func_count_mips =
-    sizeof(compiler_runtime_func_name_list_mips) / sizeof(const char*);
-
-  const size_t compiler_runtime_func_count_x86 =
-    sizeof(compiler_runtime_func_name_list_x86) / sizeof(const char*);
-}
-
-
-namespace art {
-namespace llvm {
-
-
-ProcedureLinkageTable::ProcedureLinkageTable(InstructionSet insn_set)
-    : insn_set_(insn_set) {
-}
-
-
-ProcedureLinkageTable::~ProcedureLinkageTable() {
-}
-
-
-bool ProcedureLinkageTable::AllocateTable() {
-  if (table_mmap_.get()) {
-    return true;
-  }
-
-  // Allocate the PLT
-  byte* suggested_table_addr = reinterpret_cast<byte*>(kTableAddress);
-
-  UniquePtr<MemMap> table_mmap(
-      MemMap::MapAnonymous(".plt", suggested_table_addr,
-                           GetTableSizeInBytes(), PROT_READ | PROT_WRITE));
-
-  if (!table_mmap.get()) {
-    return false;
-  }
-
-  if (table_mmap->Begin() != suggested_table_addr) {
-    // Our PLT should be allocated at the FIXED address
-    return false;
-  }
-
-  // Create the stubs in the PLT
-  byte* stub_ptr = table_mmap->Begin();
-  size_t stub_size = GetStubSizeInBytes();
-
-  for (size_t i = 0; i < art_runtime_func_count; ++i, stub_ptr += stub_size) {
-    const char* name = art_runtime_func_name_list[i];
-    void* func = art_portable_find_runtime_support_func(NULL, name);
-    DCHECK(func != NULL);
-    CreateStub(stub_ptr, func);
-  }
-
-  const char* const* crt_name_list = NULL;
-  size_t crt_count = 0u;
-
-  switch (insn_set_) {
-  case kArm:
-  case kThumb2:
-    crt_name_list = compiler_runtime_func_name_list_arm;
-    crt_count = compiler_runtime_func_count_arm;
-    break;
-
-  case kMips:
-    crt_name_list = compiler_runtime_func_name_list_mips;
-    crt_count = compiler_runtime_func_count_mips;
-    break;
-
-  case kX86:
-    crt_name_list = compiler_runtime_func_name_list_x86;
-    crt_count = compiler_runtime_func_count_x86;
-    break;
-
-  default:
-    LOG(FATAL) << "Unknown instruction set: " << insn_set_;
-    return false;
-  }
-
-  for (size_t i = 0; i < crt_count; ++i, stub_ptr += stub_size) {
-    void* func = art_portable_find_runtime_support_func(NULL, crt_name_list[i]);
-    DCHECK(func != NULL);
-    CreateStub(stub_ptr, func);
-  }
-
-  // Protect the procedure linkage table
-  table_mmap->Protect(PROT_READ | PROT_EXEC);
-
-  // Flush the instruction cache on specific architecture
-#if defined(__arm__) || defined(__mips__)
-  cacheflush(reinterpret_cast<long int>(table_mmap->Begin()),
-             reinterpret_cast<long int>(table_mmap->End()), 0);
-#endif
-
-  // Transfer the ownership
-  table_mmap_.reset(table_mmap.release());
-
-  return true;
-}
-
-
-uintptr_t ProcedureLinkageTable::GetEntryAddress(const char* name) const {
-  int func_idx = IndexOfRuntimeFunc(name);
-  if (func_idx == -1) {
-    return 0u;
-  }
-
-  return (kTableAddress + func_idx * GetStubSizeInBytes());
-}
-
-
-
-int ProcedureLinkageTable::IndexOfRuntimeFunc(const char* name) const {
-  int result = IndexOfCompilerRuntimeFunc(name);
-  if (result != -1) {
-    return art_runtime_func_count + result;
-  }
-
-  return IndexOfArtRuntimeFunc(name);
-}
-
-
-int ProcedureLinkageTable::IndexOfArtRuntimeFunc(const char* name) {
-  for (size_t i = 0; i < art_runtime_func_count; ++i) {
-    if (strcmp(name, art_runtime_func_name_list[i]) == 0) {
-      return static_cast<int>(i);
-    }
-  }
-  return -1;
-}
-
-int ProcedureLinkageTable::IndexOfCompilerRuntimeFunc(InstructionSet insn_set,
-                                                      const char* name) {
-  const char* const* rt_begin = NULL;
-  const char* const* rt_end = NULL;
-
-  switch (insn_set) {
-  case kArm:
-  case kThumb2:
-    rt_begin = compiler_runtime_func_name_list_arm;
-    rt_end = compiler_runtime_func_name_list_arm +
-             compiler_runtime_func_count_arm;
-    break;
-
-  case kMips:
-    rt_begin = compiler_runtime_func_name_list_mips;
-    rt_end = compiler_runtime_func_name_list_mips +
-             compiler_runtime_func_count_mips;
-    break;
-
-  case kX86:
-    rt_begin = compiler_runtime_func_name_list_x86;
-    rt_end = compiler_runtime_func_name_list_x86 +
-             compiler_runtime_func_count_x86;
-    break;
-
-  default:
-    LOG(FATAL) << "Unknown instruction set: " << insn_set;
-    return -1;
-  }
-
-  const char* const* name_lbound_ptr =
-      std::lower_bound(rt_begin, rt_end, name, CStringLessThanComparator());
-
-  if (name_lbound_ptr < rt_end && strcmp(*name_lbound_ptr, name) == 0) {
-    return (name_lbound_ptr - rt_begin);
-  } else {
-    return -1;
-  }
-}
-
-
-size_t ProcedureLinkageTable::GetStubCount(InstructionSet insn_set) {
-  switch (insn_set) {
-  case kArm:
-  case kThumb2:
-    return art_runtime_func_count + compiler_runtime_func_count_arm;
-
-  case kMips:
-    return art_runtime_func_count + compiler_runtime_func_count_mips;
-
-  case kX86:
-    return art_runtime_func_count + compiler_runtime_func_count_x86;
-
-  default:
-    LOG(FATAL) << "Unknown instruction set: " << insn_set;
-    return 0u;
-  }
-}
-
-
-size_t ProcedureLinkageTable::GetStubSizeInBytes(InstructionSet insn_set) {
-  switch (insn_set) {
-  case kArm:
-  case kThumb2:
-    return 8u;
-
-  case kMips:
-    return 16u;
-
-  case kX86:
-    return 8u;
-
-  default:
-    LOG(FATAL) << "Unknown instruction set: " << insn_set;
-    return 0u;
-  }
-}
-
-
-void ProcedureLinkageTable::CreateStub(InstructionSet insn_set,
-                                       byte* stub, void* dest_) {
-  switch (insn_set) {
-  case kArm:
-  case kThumb2:
-    {
-      uint32_t dest = static_cast<uint32_t>(
-                      reinterpret_cast<uintptr_t>(dest_) & 0xfffffffful);
-      uint32_t* stub_w = reinterpret_cast<uint32_t*>(stub);
-
-      stub_w[0] = 0xe51ff004ul; // ldr pc, [pc #-4]
-      stub_w[1] = dest;
-    }
-    break;
-
-  case kMips:
-    {
-      uint32_t dest = static_cast<uint32_t>(
-                      reinterpret_cast<uintptr_t>(dest_) & 0xfffffffful);
-      uint32_t* stub_w = reinterpret_cast<uint32_t*>(stub);
-
-      stub_w[0] = 0x3c190000ul | ((dest >> 16) & 0xfffful); // lui
-      stub_w[1] = 0x37390000ul | (dest & 0xfffful);; // ori
-      stub_w[2] = 0x03200008ul; // jr (jump register)
-      stub_w[3] = 0x00000000ul; // nop
-    }
-    break;
-
-  case kX86:
-    {
-      uint32_t off = static_cast<uint32_t>(
-                     reinterpret_cast<uintptr_t>(dest_) -
-                     reinterpret_cast<uintptr_t>(stub + 1) - 4);
-      // jmp (32-bit offset)
-      stub[0] = 0xe9u;
-      stub[1] = off & 0xffu;
-      stub[2] = (off >> 8) & 0xffu;
-      stub[2] = (off >> 16) & 0xffu;
-      stub[2] = (off >> 24) & 0xffu;
-    }
-    break;
-
-  default:
-    LOG(FATAL) << "Unknown instruction set: " << insn_set;
-  }
-}
-
-
-} // namespace llvm
-} // namespace art
diff --git a/src/compiler/llvm/procedure_linkage_table.h b/src/compiler/llvm/procedure_linkage_table.h
deleted file mode 100644
index 1c89d29..0000000
--- a/src/compiler/llvm/procedure_linkage_table.h
+++ /dev/null
@@ -1,85 +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_SRC_COMPILER_LLVM_PROCEDURE_LINKAGE_TABLE_H_
-#define ART_SRC_COMPILER_LLVM_PROCEDURE_LINKAGE_TABLE_H_
-
-#include "globals.h"
-#include "instruction_set.h"
-#include "mem_map.h"
-
-#include <UniquePtr.h>
-
-#include <stddef.h>
-#include <stdint.h>
-
-namespace art {
-namespace llvm {
-
-
-class ProcedureLinkageTable {
- public:
-  ProcedureLinkageTable(InstructionSet insn_set);
-
-  ~ProcedureLinkageTable();
-
-  bool AllocateTable();
-
-  uintptr_t GetEntryAddress(const char* func_name) const;
-
- private:
-  static size_t GetStubCount(InstructionSet insn_set);
-  static size_t GetStubSizeInBytes(InstructionSet insn_set);
-  static void CreateStub(InstructionSet insn_set,
-                         byte* stub, void* branch_dest);
-
-  int IndexOfRuntimeFunc(const char* name) const;
-  static int IndexOfArtRuntimeFunc(const char* name);
-  static int IndexOfCompilerRuntimeFunc(InstructionSet insn_set,
-                                        const char* name);
-
-  size_t GetStubCount() const {
-    return GetStubCount(insn_set_);
-  }
-
-  size_t GetStubSizeInBytes() const {
-    return GetStubSizeInBytes(insn_set_);
-  }
-
-  size_t GetTableSizeInBytes() const {
-    return GetStubSizeInBytes() * GetStubCount();
-  }
-
-  void CreateStub(byte* stub, void* branch_dest) {
-    return CreateStub(insn_set_, stub, branch_dest);
-  }
-
-  int IndexOfCompilerRuntimeFunc(const char* name) const {
-    return IndexOfCompilerRuntimeFunc(insn_set_, name);
-  }
-
-  InstructionSet insn_set_;
-  UniquePtr<MemMap> table_mmap_;
-
-  static const size_t kTableSizeInBytes = 1024u;
-  static const uintptr_t kTableAddress = 0x5fffc000u;
-};
-
-
-} // namespace llvm
-} // namespace art
-
-#endif // ART_SRC_COMPILER_LLVM_PROCEDURE_LINKAGE_TABLE_H_
diff --git a/src/compiler/llvm/runtime_support_llvm.cc b/src/compiler/llvm/runtime_support_llvm.cc
index ae8bb4a..b18eefe 100644
--- a/src/compiler/llvm/runtime_support_llvm.cc
+++ b/src/compiler/llvm/runtime_support_llvm.cc
@@ -20,7 +20,6 @@
 #include "asm_support.h"
 #include "class_linker.h"
 #include "class_linker-inl.h"
-#include "compiler_runtime_func_list.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
 #include "mirror/abstract_method-inl.h"
@@ -743,46 +742,6 @@
   return o;
 }
 
-//----------------------------------------------------------------------------
-// Runtime Support Function Lookup Callback
-//----------------------------------------------------------------------------
-
-#define EXTERNAL_LINKAGE(NAME, RETURN_TYPE, ...) \
-extern "C" RETURN_TYPE NAME(__VA_ARGS__);
-COMPILER_RUNTIME_FUNC_LIST_NATIVE(EXTERNAL_LINKAGE)
-#undef EXTERNAL_LINKAGE
-
-static void* art_portable_find_compiler_runtime_func(const char* name) {
-// TODO: If target support some math func, use the target's version. (e.g. art_portable_d2i -> __aeabi_d2iz)
-  static const char* const names[] = {
-#define DEFINE_ENTRY(NAME, RETURN_TYPE, ...) #NAME ,
-    COMPILER_RUNTIME_FUNC_LIST_NATIVE(DEFINE_ENTRY)
-#undef DEFINE_ENTRY
-  };
-
-  static void* const funcs[] = {
-#define DEFINE_ENTRY(NAME, RETURN_TYPE, ...) \
-    reinterpret_cast<void*>(static_cast<RETURN_TYPE (*)(__VA_ARGS__)>(NAME)) ,
-    COMPILER_RUNTIME_FUNC_LIST_NATIVE(DEFINE_ENTRY)
-#undef DEFINE_ENTRY
-  };
-
-  static const size_t num_entries = sizeof(names) / sizeof(const char* const);
-
-  const char* const* const names_begin = names;
-  const char* const* const names_end = names + num_entries;
-
-  const char* const* name_lbound_ptr =
-      std::lower_bound(names_begin, names_end, name,
-                       CStringLessThanComparator());
-
-  if (name_lbound_ptr < names_end && strcmp(*name_lbound_ptr, name) == 0) {
-    return funcs[name_lbound_ptr - names_begin];
-  } else {
-    return NULL;
-  }
-}
-
 // Handler for invocation on proxy methods. Create a boxed argument array and invoke the invocation
 // handler which is a field within the proxy object receiver. The var args encode the arguments
 // with the last argument being a pointer to a JValue to store the result in.
@@ -860,43 +819,6 @@
   }
 }
 
-void* art_portable_find_runtime_support_func(void* context, const char* name) {
-  struct func_entry_t {
-    const char* name;
-    size_t name_len;
-    void* addr;
-  };
-
-  static struct func_entry_t const tab[] = {
-#define DEFINE_ENTRY(ID, NAME) \
-    { #NAME, sizeof(#NAME) - 1, reinterpret_cast<void*>(NAME) },
-    RUNTIME_SUPPORT_FUNC_LIST(DEFINE_ENTRY)
-#undef DEFINE_ENTRY
-  };
-
-  static size_t const tab_size = sizeof(tab) / sizeof(struct func_entry_t);
-
-  // Search the compiler runtime (such as __divdi3)
-  void* result = art_portable_find_compiler_runtime_func(name);
-  if (result != NULL) {
-    return result;
-  }
-
-  // Note: Since our table is small, we are using trivial O(n) searching
-  // function.  For bigger table, it will be better to use a binary
-  // search or hash function.
-  size_t i;
-  size_t name_len = strlen(name);
-  for (i = 0; i < tab_size; ++i) {
-    if (name_len == tab[i].name_len && strcmp(name, tab[i].name) == 0) {
-      return tab[i].addr;
-    }
-  }
-
-  LOG(FATAL) << "Error: Can't find symbol " << name;
-  return 0;
-}
-
 //----------------------------------------------------------------------------
 // Memory barrier
 //----------------------------------------------------------------------------
diff --git a/src/compiler/llvm/utils_llvm.h b/src/compiler/llvm/utils_llvm.h
index e06e113..2e273f4 100644
--- a/src/compiler/llvm/utils_llvm.h
+++ b/src/compiler/llvm/utils_llvm.h
@@ -17,13 +17,8 @@
 #ifndef ART_SRC_UTILS_LLVM_H_
 #define ART_SRC_UTILS_LLVM_H_
 
-#include "base/stringprintf.h"
-
 #include <llvm/Analysis/Verifier.h>
 
-#include <stdint.h>
-#include <string>
-
 namespace art {
 
 #ifndef NDEBUG
@@ -32,17 +27,6 @@
 #define VERIFY_LLVM_FUNCTION(func)
 #endif
 
-inline static std::string ElfFuncName(uint32_t idx) {
-  return StringPrintf("Art%u", static_cast<unsigned int>(idx));
-}
-
-class CStringLessThanComparator {
- public:
-  bool operator()(const char* lhs, const char* rhs) const {
-    return (strcmp(lhs, rhs) < 0);
-  }
-};
-
 }  // namespace art
 
 #endif  // ART_SRC_UTILS_LLVM_H_
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 6b94dc0..6892bb3 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -81,13 +81,19 @@
   UsageError("      to the file descriptor specified by --zip-fd.");
   UsageError("      Example: --zip-location=/system/app/Calculator.apk");
   UsageError("");
-  UsageError("  --oat-file=<file.oat>: specifies the required oat filename.");
+  UsageError("  --oat-file=<file.oat>: specifies the oat output destination via a filename.");
+  UsageError("      Example: --oat-file=/system/framework/boot.oat");
+  UsageError("");
+  UsageError("  --oat-fd=<number>: specifies the oat output destination via a file descriptor.");
   UsageError("      Example: --oat-file=/system/framework/boot.oat");
   UsageError("");
   UsageError("  --oat-location=<oat-name>: specifies a symbolic name for the file corresponding");
   UsageError("      to the file descriptor specified by --oat-fd.");
   UsageError("      Example: --oat-location=/data/art-cache/system@app@Calculator.apk.oat");
   UsageError("");
+  UsageError("  --oat-symbols=<file.oat>: specifies the oat output destination with full symbols.");
+  UsageError("      Example: --oat-symbols=/symbols/system/framework/boot.oat");
+  UsageError("");
   UsageError("  --bitcode=<file.bc>: specifies the optional bitcode filename.");
   UsageError("      Example: --bitcode=/system/framework/boot.bc");
   UsageError("");
@@ -104,7 +110,7 @@
   UsageError("      Example: --boot-image=/system/framework/boot.art");
   UsageError("      Default: <host-prefix>/system/framework/boot.art");
   UsageError("");
-  UsageError("  --host-prefix may be used to translate host paths to target paths during");
+  UsageError("  --host-prefix=<path>: used to translate host paths to target paths during");
   UsageError("      cross compilation.");
   UsageError("      Example: --host-prefix=out/target/product/crespo");
   UsageError("      Default: $ANDROID_PRODUCT_OUT");
@@ -118,6 +124,9 @@
   UsageError("      set.");
   UsageError("      Example: --instruction-set=Portable");
   UsageError("      Default: Quick");
+  UsageError("");
+  UsageError("  --host: used with Portable backend to link against host runtime libraries");
+  UsageError("");
   UsageError("  --runtime-arg <argument>: used to specify various arguments for the runtime,");
   UsageError("      such as initial heap size, maximum heap size, and verbose output.");
   UsageError("      Use a separate --runtime-arg switch for each argument.");
@@ -215,6 +224,7 @@
 
   const CompilerDriver* CreateOatFile(const std::string& boot_image_option,
                                 const std::string* host_prefix,
+                                bool is_host,
                                 const std::vector<const DexFile*>& dex_files,
                                 File* oat_file,
                                 const std::string& bitcode_filename,
@@ -285,7 +295,7 @@
       return NULL;
     }
 
-    if (!driver->WriteElf(oat_contents, oat_file)) {
+    if (!driver->WriteElf(host_prefix, is_host, dex_files, oat_contents, oat_file)) {
       LOG(ERROR) << "Failed to write ELF file " << oat_file->GetPath();
       return NULL;
     }
@@ -311,9 +321,7 @@
       oat_data_begin = image_writer.GetOatDataBegin();
     }
 
-    LG << "dex2oat CreateImageFile opening : " << oat_filename;
     UniquePtr<File> oat_file(OS::OpenFile(oat_filename.c_str(), true, false));
-    LG << "dex2oat CreateImageFile opened : " << oat_filename;
     if (oat_file.get() == NULL) {
       PLOG(ERROR) << "Failed to open ELF file: " << oat_filename;
       return false;
@@ -322,7 +330,6 @@
       LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath();
       return false;
     }
-    LOG(ERROR) << "ELF file fixed up successfully: " << oat_file->GetPath();
     return true;
   }
 
@@ -634,6 +641,7 @@
   int zip_fd = -1;
   std::string zip_location;
   std::string oat_filename;
+  std::string oat_symbols;
   std::string oat_location;
   int oat_fd = -1;
   std::string bitcode_filename;
@@ -659,6 +667,7 @@
 #else
 #error "Unsupported architecture"
 #endif
+  bool is_host = false;
   bool dump_stats = kIsDebugBuild;
   bool dump_timings = kIsDebugBuild;
   bool watch_dog_enabled = !kIsTargetBuild;
@@ -682,6 +691,8 @@
       zip_location = option.substr(strlen("--zip-location=")).data();
     } else if (option.starts_with("--oat-file=")) {
       oat_filename = option.substr(strlen("--oat-file=")).data();
+    } else if (option.starts_with("--oat-symbols=")) {
+      oat_symbols = option.substr(strlen("--oat-symbols=")).data();
     } else if (option.starts_with("--oat-fd=")) {
       const char* oat_fd_str = option.substr(strlen("--oat-fd=")).data();
       if (!ParseInt(oat_fd_str, &oat_fd)) {
@@ -735,6 +746,8 @@
       } else if (backend_str == "Portable") {
         compiler_backend = kPortable;
       }
+    } else if (option == "--host") {
+      is_host = true;
     } else if (option == "--runtime-arg") {
       if (++i >= argc) {
         Usage("Missing required argument for --runtime-arg");
@@ -756,8 +769,12 @@
     Usage("--oat-file should not be used with --oat-fd");
   }
 
-  if (!oat_filename.empty() && oat_fd != -1) {
-    Usage("--oat-file should not be used with --oat-fd");
+  if (!oat_symbols.empty() && oat_fd != -1) {
+    Usage("--oat-symbols should not be used with --oat-fd");
+  }
+
+  if (!oat_symbols.empty() && is_host) {
+    Usage("--oat-symbols should not be used with --host");
   }
 
   if (oat_fd != -1 && !image_filename.empty()) {
@@ -825,14 +842,22 @@
     }
   }
 
+  std::string oat_stripped(oat_filename);
+  std::string oat_unstripped;
+  if (!oat_symbols.empty()) {
+    oat_unstripped += oat_symbols;
+  } else {
+    oat_unstripped += oat_filename;
+  }
+
   // Done with usage checks, enable watchdog if requested
   WatchDog watch_dog(watch_dog_enabled);
 
   // Check early that the result of compilation can be written
   UniquePtr<File> oat_file;
-  bool create_file = !oat_filename.empty();  // as opposed to using open file descriptor
+  bool create_file = !oat_unstripped.empty();  // as opposed to using open file descriptor
   if (create_file) {
-    oat_file.reset(OS::OpenFile(oat_filename.c_str(), true));
+    oat_file.reset(OS::OpenFile(oat_unstripped.c_str(), true));
     if (oat_location.empty()) {
       oat_location = oat_filename;
     }
@@ -921,6 +946,7 @@
 
   UniquePtr<const CompilerDriver> compiler(dex2oat->CreateOatFile(boot_image_option,
                                                                   host_prefix.get(),
+                                                                  is_host,
                                                                   dex_files,
                                                                   oat_file.get(),
                                                                   bitcode_filename,
@@ -934,10 +960,7 @@
     return EXIT_FAILURE;
   }
 
-  if (!image) {
-    LOG(INFO) << "Oat file written successfully: " << oat_location;
-    return EXIT_SUCCESS;
-  }
+  LOG(INFO) << "Oat file written successfully (unstripped): " << oat_location;
 
   // Notes on the interleaving of creating the image and oat file to
   // ensure the references between the two are correct.
@@ -989,21 +1012,52 @@
   // load the .so at the desired location at runtime by offsetting the
   // Elf32_Phdr.p_vaddr values by the desired base address.
   //
-  Thread::Current()->TransitionFromRunnableToSuspended(kNative);
-  bool image_creation_success = dex2oat->CreateImageFile(image_filename,
-                                                         image_base,
-                                                         image_classes.get(),
-                                                         oat_filename,
-                                                         oat_location,
-                                                         *compiler.get());
-  Thread::Current()->TransitionFromSuspendedToRunnable();
-  if (!image_creation_success) {
-    return EXIT_FAILURE;
+  if (image) {
+    Thread::Current()->TransitionFromRunnableToSuspended(kNative);
+    bool image_creation_success = dex2oat->CreateImageFile(image_filename,
+                                                           image_base,
+                                                           image_classes.get(),
+                                                           oat_unstripped,
+                                                           oat_location,
+                                                           *compiler.get());
+    Thread::Current()->TransitionFromSuspendedToRunnable();
+    LOG(INFO) << "Image written successfully: " << image_filename;
+    if (!image_creation_success) {
+      return EXIT_FAILURE;
+    }
   }
 
+  if (is_host) {
+    return EXIT_SUCCESS;
+  }
+
+  // If we don't want to strip in place, copy from unstripped location to stripped location.
+  // We need to strip after image creation because FixupElf needs to use .strtab.
+  if (oat_unstripped != oat_stripped) {
+    oat_file.reset();
+    UniquePtr<File> in(OS::OpenFile(oat_unstripped.c_str(), false));
+    UniquePtr<File> out(OS::OpenFile(oat_stripped.c_str(), true));
+    size_t buffer_size = 8192;
+    UniquePtr<uint8_t> buffer(new uint8_t[buffer_size]);
+    while (true) {
+      int bytes_read = TEMP_FAILURE_RETRY(read(in->Fd(), buffer.get(), buffer_size));
+      if (bytes_read <= 0) {
+        break;
+      }
+      bool write_ok = out->WriteFully(buffer.get(), bytes_read);
+      CHECK(write_ok);
+    }
+    oat_file.reset(out.release());
+    LOG(INFO) << "Oat file copied successfully (stripped): " << oat_stripped;
+  }
+
+  // Strip unneeded sections for target
+  off_t seek_actual = lseek(oat_file->Fd(), 0, SEEK_SET);
+  CHECK_EQ(0, seek_actual);
+  compiler->StripElf(oat_file.get());
+
   // We wrote the oat file successfully, and want to keep it.
-  LOG(INFO) << "Oat file written successfully: " << oat_filename;
-  LOG(INFO) << "Image written successfully: " << image_filename;
+  LOG(INFO) << "Oat file written successfully (stripped): " << oat_stripped;
   return EXIT_SUCCESS;
 }
 
diff --git a/src/dex_method_iterator.h b/src/dex_method_iterator.h
new file mode 100644
index 0000000..dc2e712
--- /dev/null
+++ b/src/dex_method_iterator.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2011 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_SRC_DEX_METHOD_ITERATOR_H_
+#define ART_SRC_DEX_METHOD_ITERATOR_H_
+
+#include <vector>
+
+#include "dex_file.h"
+
+namespace art {
+
+class DexMethodIterator {
+ public:
+  DexMethodIterator(const std::vector<const DexFile*>& dex_files)
+      : dex_files_(dex_files),
+        found_next_(false),
+        dex_file_index_(0),
+        class_def_index_(0),
+        class_def_(NULL),
+        class_data_(NULL),
+        direct_method_(false) {
+    CHECK_NE(0U, dex_files_.size());
+  }
+
+  bool HasNext() {
+    if (found_next_) {
+      return true;
+    }
+    while (true) {
+      // End of DexFiles, we are done.
+      if (dex_file_index_ == dex_files_.size()) {
+        return false;
+      }
+      if (class_def_index_ == GetDexFileInternal().NumClassDefs()) {
+        // End of this DexFile, advance and retry.
+        class_def_index_ = 0;
+        dex_file_index_++;
+        continue;
+      }
+      if (class_def_ == NULL) {
+        class_def_ = &GetDexFileInternal().GetClassDef(class_def_index_);
+      }
+      if (class_data_ == NULL) {
+        class_data_ = GetDexFileInternal().GetClassData(*class_def_);
+        if (class_data_ == NULL) {
+          // empty class, such as a marker interface
+          // End of this class, advance and retry.
+          class_def_ = NULL;
+          class_def_index_++;
+          continue;
+        }
+      }
+      if (it_.get() == NULL) {
+        it_.reset(new ClassDataItemIterator(GetDexFileInternal(), class_data_));
+        // Skip fields
+        while (GetIterator().HasNextStaticField()) {
+          GetIterator().Next();
+        }
+        while (GetIterator().HasNextInstanceField()) {
+          GetIterator().Next();
+        }
+        direct_method_ = true;
+      }
+      if (direct_method_ && GetIterator().HasNextDirectMethod()) {
+        // Found method
+        found_next_ = true;
+        return true;
+      }
+      direct_method_ = false;
+      if (GetIterator().HasNextVirtualMethod()) {
+        // Found method
+        found_next_ = true;
+        return true;
+      }
+      // End of this class, advance and retry.
+      DCHECK(!GetIterator().HasNext());
+      it_.reset(NULL);
+      class_data_ = NULL;
+      class_def_ = NULL;
+      class_def_index_++;
+    }
+  }
+
+  void Next() {
+    found_next_ = false;
+    if (it_.get() != NULL) {
+      // Advance to next method if we currently are looking at a class.
+      GetIterator().Next();
+    }
+  }
+
+  const DexFile& GetDexFile() {
+    CHECK(HasNext());
+    return GetDexFileInternal();
+  }
+
+  uint32_t GetMemberIndex() {
+    CHECK(HasNext());
+    return GetIterator().GetMemberIndex();
+  }
+
+  InvokeType GetInvokeType() {
+    CHECK(HasNext());
+    CHECK(class_def_ != NULL);
+    return GetIterator().GetMethodInvokeType(*class_def_);
+  }
+
+ private:
+
+  ClassDataItemIterator& GetIterator() const {
+    CHECK(it_.get() != NULL);
+    return *it_.get();
+  }
+
+  const DexFile& GetDexFileInternal() const {
+    CHECK_LT(dex_file_index_, dex_files_.size());
+    const DexFile* dex_file = dex_files_[dex_file_index_];
+    CHECK(dex_file != NULL);
+    return *dex_file;
+  }
+
+  const std::vector<const DexFile*>& dex_files_;
+
+  bool found_next_;
+
+  uint32_t dex_file_index_;
+  uint32_t class_def_index_;
+  const DexFile::ClassDef* class_def_;
+  const byte* class_data_;
+  UniquePtr<ClassDataItemIterator> it_;
+  bool direct_method_;
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_DEX_METHOD_ITERATOR_H_
diff --git a/src/dex_method_iterator_test.cc b/src/dex_method_iterator_test.cc
new file mode 100644
index 0000000..e4a42db
--- /dev/null
+++ b/src/dex_method_iterator_test.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2011 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 "dex_method_iterator.h"
+
+#include "common_test.h"
+
+namespace art {
+
+class DexMethodIteratorTest : public CommonTest {};
+
+TEST_F(DexMethodIteratorTest, Basic) {
+  ScopedObjectAccess soa(Thread::Current());
+  std::vector<const DexFile*> dex_files;
+  dex_files.push_back(DexFile::Open(GetDexFileName("core"), GetDexFileName("core")));
+  dex_files.push_back(DexFile::Open(GetDexFileName("core-junit"), GetDexFileName("core-junit")));
+  dex_files.push_back(DexFile::Open(GetDexFileName("bouncycastle"), GetDexFileName("bouncycastle")));
+  DexMethodIterator it(dex_files);
+  while (it.HasNext()) {
+    const DexFile& dex_file = it.GetDexFile();
+    InvokeType invoke_type = it.GetInvokeType();
+    uint32_t method_idx = it.GetMemberIndex();
+    if (false) {
+      LG << invoke_type << " " << PrettyMethod(method_idx, dex_file);
+    }
+    it.Next();
+  }
+  STLDeleteElements(&dex_files);
+}
+
+}  // namespace art
diff --git a/src/elf_file.cc b/src/elf_file.cc
index 8d6e630..6f9d53c 100644
--- a/src/elf_file.cc
+++ b/src/elf_file.cc
@@ -36,7 +36,9 @@
   dynsym_section_start_(NULL),
   strtab_section_start_(NULL),
   dynstr_section_start_(NULL),
-  hash_section_start_(NULL) {}
+  hash_section_start_(NULL),
+  symtab_symbol_table_(NULL),
+  dynsym_symbol_table_(NULL) {}
 
 ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only) {
   UniquePtr<ElfFile> elf_file(new ElfFile());
@@ -61,28 +63,34 @@
     prot = PROT_READ;
     flags = MAP_PRIVATE;
   }
-  if (file->GetLength() < sizeof(llvm::ELF::Elf32_Ehdr)) {
-    LOG(WARNING) << "File not large enough to contain ELF header: " << file->GetPath();
+  int64_t file_length = file_->GetLength();
+  if (file_length < 0) {
+    errno = -file_length;
+    PLOG(WARNING) << "Failed to get length of file: " << file_->GetPath() << " fd=" << file_->Fd();
+    return false;
+  }
+  if (file_length < sizeof(llvm::ELF::Elf32_Ehdr)) {
+    LOG(WARNING) << "File not large enough to contain ELF header: " << file_->GetPath();
     return false;
   }
 
   if (program_header_only) {
     // first just map ELF header to get program header size information
     size_t elf_header_size = sizeof(llvm::ELF::Elf32_Ehdr);
-    if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, file->Fd(), 0))) {
-      LOG(WARNING) << "Failed to map ELF header: " << file->GetPath();
+    if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, file_->Fd(), 0))) {
+      LOG(WARNING) << "Failed to map ELF header: " << file_->GetPath();
       return false;
     }
     // then remap to cover program header
     size_t program_header_size = header_->e_phoff + (header_->e_phentsize * header_->e_phnum);
-    if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file->Fd(), 0))) {
-      LOG(WARNING) << "Failed to map ELF program headers: " << file->GetPath();
+    if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file_->Fd(), 0))) {
+      LOG(WARNING) << "Failed to map ELF program headers: " << file_->GetPath();
       return false;
     }
   } else {
     // otherwise map entire file
-    if (!SetMap(MemMap::MapFile(file->GetLength(), prot, flags, file->Fd(), 0))) {
-      LOG(WARNING) << "Failed to map ELF file: " << file->GetPath();
+    if (!SetMap(MemMap::MapFile(file_->GetLength(), prot, flags, file_->Fd(), 0))) {
+      LOG(WARNING) << "Failed to map ELF file: " << file_->GetPath();
       return false;
     }
   }
@@ -97,7 +105,7 @@
     // Find .dynamic section info from program header
     dynamic_program_header_ = FindProgamHeaderByType(llvm::ELF::PT_DYNAMIC);
     if (dynamic_program_header_ == NULL) {
-      LOG(WARNING) << "Failed to find PT_DYNAMIC program header in ELF file: " << file->GetPath();
+      LOG(WARNING) << "Failed to find PT_DYNAMIC program header in ELF file: " << file_->GetPath();
       return false;
     }
 
@@ -129,7 +137,7 @@
         case llvm::ELF::SHT_DYNAMIC: {
           if (reinterpret_cast<byte*>(dynamic_section_start_) != section_addr) {
             LOG(WARNING) << "Failed to find matching SHT_DYNAMIC for PT_DYNAMIC in "
-                         << file->GetPath() << ": " << std::hex
+                         << file_->GetPath() << ": " << std::hex
                          << reinterpret_cast<void*>(dynamic_section_start_)
                          << " != " << reinterpret_cast<void*>(section_addr);
             return false;
@@ -148,6 +156,8 @@
 
 ElfFile::~ElfFile() {
   STLDeleteElements(&segments_);
+  delete symtab_symbol_table_;
+  delete dynsym_symbol_table_;
 }
 
 bool ElfFile::SetMap(MemMap* map) {
@@ -247,9 +257,9 @@
   return symbol_section_start;
 }
 
-char* ElfFile::GetSymbolStringSectionStart(llvm::ELF::Elf32_Word section_type) {
+const char* ElfFile::GetStringSectionStart(llvm::ELF::Elf32_Word section_type) {
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
-  char* string_section_start;
+  const char* string_section_start;
   switch (section_type) {
     case llvm::ELF::SHT_SYMTAB: {
       string_section_start = strtab_section_start_;
@@ -268,6 +278,16 @@
   return string_section_start;
 }
 
+const char* ElfFile::GetString(llvm::ELF::Elf32_Word section_type, llvm::ELF::Elf32_Word i) {
+  CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
+  if (i == 0) {
+    return NULL;
+  }
+  const char* string_section_start = GetStringSectionStart(section_type);
+  const char* string = string_section_start + i;
+  return string;
+}
+
 llvm::ELF::Elf32_Word* ElfFile::GetHashSectionStart() {
   CHECK(hash_section_start_ != NULL);
   return hash_section_start_;
@@ -342,28 +362,30 @@
 }
 
 // from bionic
-static unsigned elfhash(const char *_name)
-{
-    const unsigned char *name = (const unsigned char *) _name;
-    unsigned h = 0, g;
+static unsigned elfhash(const char *_name) {
+  const unsigned char *name = (const unsigned char *) _name;
+  unsigned h = 0, g;
 
-    while(*name) {
-        h = (h << 4) + *name++;
-        g = h & 0xf0000000;
-        h ^= g;
-        h ^= g >> 24;
-    }
-    return h;
+  while(*name) {
+    h = (h << 4) + *name++;
+    g = h & 0xf0000000;
+    h ^= g;
+    h ^= g >> 24;
+  }
+  return h;
+}
+
+llvm::ELF::Elf32_Shdr& ElfFile::GetSectionNameStringSection() {
+  return GetSectionHeader(GetHeader().e_shstrndx);
 }
 
 byte* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) {
   llvm::ELF::Elf32_Word hash = elfhash(symbol_name.c_str());
   llvm::ELF::Elf32_Word bucket_index = hash % GetHashBucketNum();
   llvm::ELF::Elf32_Word symbol_and_chain_index = GetHashBucket(bucket_index);
-  char* symbol_string_section_start = GetSymbolStringSectionStart(llvm::ELF::SHT_DYNSYM);
   while (symbol_and_chain_index != 0 /* STN_UNDEF */) {
     llvm::ELF::Elf32_Sym& symbol = GetSymbol(llvm::ELF::SHT_DYNSYM, symbol_and_chain_index);
-    char* name = symbol_string_section_start + symbol.st_name;
+    const char* name = GetString(llvm::ELF::SHT_DYNSYM, symbol.st_name);
     if (symbol_name == name) {
       return base_address_ + symbol.st_value;
     }
@@ -387,10 +409,66 @@
   return *(GetSymbolSectionStart(section_type) + i);
 }
 
+ElfFile::SymbolTable** ElfFile::GetSymbolTable(llvm::ELF::Elf32_Word section_type) {
+  CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
+  switch (section_type) {
+    case llvm::ELF::SHT_SYMTAB: {
+      return &symtab_symbol_table_;
+    }
+    case llvm::ELF::SHT_DYNSYM: {
+      return &dynsym_symbol_table_;
+    }
+    default: {
+      LOG(FATAL) << section_type;
+      return NULL;
+    }
+  }
+}
+
 llvm::ELF::Elf32_Sym* ElfFile::FindSymbolByName(llvm::ELF::Elf32_Word section_type,
-                                                const std::string& symbol_name) {
+                                                const std::string& symbol_name,
+                                                bool build_map) {
   CHECK(!program_header_only_) << file_->GetPath();
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
+
+  SymbolTable** symbol_table = GetSymbolTable(section_type);
+  if (*symbol_table != NULL || build_map) {
+    if (*symbol_table == NULL) {
+      DCHECK(build_map);
+      *symbol_table = new SymbolTable;
+      llvm::ELF::Elf32_Shdr* symbol_section = FindSectionByType(section_type);
+      CHECK(symbol_section != NULL) << file_->GetPath();
+      llvm::ELF::Elf32_Shdr& string_section = GetSectionHeader(symbol_section->sh_link);
+      for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
+        llvm::ELF::Elf32_Sym& symbol = GetSymbol(section_type, i);
+        unsigned char type = symbol.getType();
+        if (type == llvm::ELF::STT_NOTYPE) {
+          continue;
+        }
+        const char* name = GetString(string_section, symbol.st_name);
+        if (name == NULL) {
+          continue;
+        }
+        std::pair<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.
+          CHECK_EQ(symbol.st_value, result.first->second->st_value);
+          CHECK_EQ(symbol.st_size, result.first->second->st_size);
+          CHECK_EQ(symbol.st_info, result.first->second->st_info);
+          CHECK_EQ(symbol.st_other, result.first->second->st_other);
+          CHECK_EQ(symbol.st_shndx, result.first->second->st_shndx);
+        }
+      }
+    }
+    CHECK(*symbol_table != NULL);
+    SymbolTable::const_iterator it = (*symbol_table)->find(symbol_name);
+    if (it == (*symbol_table)->end()) {
+      return NULL;
+    }
+    return it->second;
+  }
+
+  // Fall back to linear search
   llvm::ELF::Elf32_Shdr* symbol_section = FindSectionByType(section_type);
   CHECK(symbol_section != NULL) << file_->GetPath();
   llvm::ELF::Elf32_Shdr& string_section = GetSectionHeader(symbol_section->sh_link);
@@ -408,15 +486,16 @@
 }
 
 llvm::ELF::Elf32_Addr ElfFile::FindSymbolAddress(llvm::ELF::Elf32_Word section_type,
-                                                 const std::string& symbol_name) {
-  llvm::ELF::Elf32_Sym* symbol = FindSymbolByName(section_type, symbol_name);
+                                                 const std::string& symbol_name,
+                                                 bool build_map) {
+  llvm::ELF::Elf32_Sym* symbol = FindSymbolByName(section_type, symbol_name, build_map);
   if (symbol == NULL) {
     return 0;
   }
   return symbol->st_value;
 }
 
-char* ElfFile::GetString(llvm::ELF::Elf32_Shdr& string_section, llvm::ELF::Elf32_Word i) {
+const char* ElfFile::GetString(llvm::ELF::Elf32_Shdr& string_section, llvm::ELF::Elf32_Word i) {
   CHECK(!program_header_only_) << file_->GetPath();
   // TODO: remove this static_cast from enum when using -std=gnu++0x
   CHECK_EQ(static_cast<llvm::ELF::Elf32_Word>(llvm::ELF::SHT_STRTAB), string_section.sh_type) << file_->GetPath();
@@ -427,7 +506,7 @@
   byte* strings = Begin() + string_section.sh_offset;
   byte* string = strings + i;
   CHECK_LT(string, End()) << file_->GetPath();
-  return reinterpret_cast<char*>(string);
+  return reinterpret_cast<const char*>(string);
 }
 
 llvm::ELF::Elf32_Word ElfFile::GetDynamicNum() {
@@ -439,6 +518,50 @@
   return *(GetDynamicSectionStart() + i);
 }
 
+llvm::ELF::Elf32_Word ElfFile::FindDynamicValueByType(llvm::ELF::Elf32_Sword type) {
+  for (llvm::ELF::Elf32_Word i = 0; i < GetDynamicNum(); i++) {
+    llvm::ELF::Elf32_Dyn& elf_dyn = GetDynamic(i);
+    if (elf_dyn.d_tag == type) {
+      return elf_dyn.d_un.d_val;
+    }
+  }
+  return 0;
+}
+
+llvm::ELF::Elf32_Rel* ElfFile::GetRelSectionStart(llvm::ELF::Elf32_Shdr& section_header) {
+  CHECK(llvm::ELF::SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
+  return reinterpret_cast<llvm::ELF::Elf32_Rel*>(Begin() + section_header.sh_offset);
+}
+
+llvm::ELF::Elf32_Word ElfFile::GetRelNum(llvm::ELF::Elf32_Shdr& section_header) {
+  CHECK(llvm::ELF::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;
+}
+
+llvm::ELF::Elf32_Rel& ElfFile::GetRel(llvm::ELF::Elf32_Shdr& section_header, llvm::ELF::Elf32_Word i) {
+  CHECK(llvm::ELF::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);
+}
+
+llvm::ELF::Elf32_Rela* ElfFile::GetRelaSectionStart(llvm::ELF::Elf32_Shdr& section_header) {
+  CHECK(llvm::ELF::SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
+  return reinterpret_cast<llvm::ELF::Elf32_Rela*>(Begin() + section_header.sh_offset);
+}
+
+llvm::ELF::Elf32_Word ElfFile::GetRelaNum(llvm::ELF::Elf32_Shdr& section_header) {
+  CHECK(llvm::ELF::SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
+  return section_header.sh_size / section_header.sh_entsize;
+}
+
+llvm::ELF::Elf32_Rela& ElfFile::GetRela(llvm::ELF::Elf32_Shdr& section_header,
+                                        llvm::ELF::Elf32_Word i) {
+  CHECK(llvm::ELF::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() {
   llvm::ELF::Elf32_Addr min_vaddr = 0xFFFFFFFFu;
@@ -528,6 +651,7 @@
     CHECK_EQ(segment->Begin(), p_vaddr) << file_->GetPath();
     segments_.push_back(segment.release());
   }
+
   // Now that we are done loading, .dynamic should be in memory to find .dynstr, .dynsym, .hash
   dynamic_section_start_
       = reinterpret_cast<llvm::ELF::Elf32_Dyn*>(base_address_ + GetDynamicProgramHeader().p_vaddr);
@@ -549,6 +673,7 @@
       }
       case llvm::ELF::DT_NULL: {
         CHECK_EQ(GetDynamicNum(), i+1);
+        break;
       }
     }
   }
diff --git a/src/elf_file.h b/src/elf_file.h
index b1d787e..59ce7f5 100644
--- a/src/elf_file.h
+++ b/src/elf_file.h
@@ -17,6 +17,7 @@
 #ifndef ART_SRC_ELF_FILE_H_
 #define ART_SRC_ELF_FILE_H_
 
+#include <map>
 #include <vector>
 
 #include <llvm/Support/ELF.h>
@@ -65,20 +66,49 @@
   ::llvm::ELF::Elf32_Shdr& GetSectionHeader(::llvm::ELF::Elf32_Word);
   ::llvm::ELF::Elf32_Shdr* FindSectionByType(::llvm::ELF::Elf32_Word type);
 
+  ::llvm::ELF::Elf32_Shdr& GetSectionNameStringSection();
+
+  // Find .dynsym using .hash for more efficient lookup than FindSymbolAddress.
   byte* FindDynamicSymbolAddress(const std::string& symbol_name);
 
   static bool IsSymbolSectionType(::llvm::ELF::Elf32_Word section_type);
   ::llvm::ELF::Elf32_Word GetSymbolNum(::llvm::ELF::Elf32_Shdr&);
   ::llvm::ELF::Elf32_Sym& GetSymbol(::llvm::ELF::Elf32_Word section_type, ::llvm::ELF::Elf32_Word i);
-  ::llvm::ELF::Elf32_Sym* FindSymbolByName(::llvm::ELF::Elf32_Word section_type,
-                                         const std::string& symbol_name);
-  ::llvm::ELF::Elf32_Addr FindSymbolAddress(::llvm::ELF::Elf32_Word section_type,
-                                          const std::string& symbol_name);
 
-  char* GetString(::llvm::ELF::Elf32_Shdr&, ::llvm::ELF::Elf32_Word);
+  // Find symbol in specified table, returning NULL 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.
+  ::llvm::ELF::Elf32_Sym* FindSymbolByName(::llvm::ELF::Elf32_Word section_type,
+                                           const std::string& symbol_name,
+                                           bool build_map);
+
+  // Find address of symbol in specified table, returning 0 if it is
+  // not found. See FindSymbolByName for an explanation of build_map.
+  ::llvm::ELF::Elf32_Addr FindSymbolAddress(::llvm::ELF::Elf32_Word section_type,
+                                            const std::string& symbol_name,
+                                            bool build_map);
+
+  // Lookup a string given string section and offset. Returns NULL for
+  // special 0 offset.
+  const char* GetString(::llvm::ELF::Elf32_Shdr&, ::llvm::ELF::Elf32_Word);
+
+  // Lookup a string by section type. Returns NULL for special 0 offset.
+  const char* GetString(::llvm::ELF::Elf32_Word section_type, ::llvm::ELF::Elf32_Word);
 
   ::llvm::ELF::Elf32_Word GetDynamicNum();
   ::llvm::ELF::Elf32_Dyn& GetDynamic(::llvm::ELF::Elf32_Word);
+  ::llvm::ELF::Elf32_Word FindDynamicValueByType(::llvm::ELF::Elf32_Sword type);
+
+  ::llvm::ELF::Elf32_Word GetRelNum(::llvm::ELF::Elf32_Shdr&);
+  ::llvm::ELF::Elf32_Rel& GetRel(::llvm::ELF::Elf32_Shdr&, ::llvm::ELF::Elf32_Word);
+
+  ::llvm::ELF::Elf32_Word GetRelaNum(::llvm::ELF::Elf32_Shdr&);
+  ::llvm::ELF::Elf32_Rela& GetRela(::llvm::ELF::Elf32_Shdr&, ::llvm::ELF::Elf32_Word);
 
   // Returns the expected size when the file is loaded at runtime
   size_t GetLoadedSize();
@@ -98,19 +128,28 @@
   ::llvm::ELF::Elf32_Phdr& GetDynamicProgramHeader();
   ::llvm::ELF::Elf32_Dyn* GetDynamicSectionStart();
   ::llvm::ELF::Elf32_Sym* GetSymbolSectionStart(::llvm::ELF::Elf32_Word section_type);
-  char* GetSymbolStringSectionStart(::llvm::ELF::Elf32_Word section_type);
+  const char* GetStringSectionStart(::llvm::ELF::Elf32_Word section_type);
+  ::llvm::ELF::Elf32_Rel* GetRelSectionStart(::llvm::ELF::Elf32_Shdr&);
+  ::llvm::ELF::Elf32_Rela* GetRelaSectionStart(::llvm::ELF::Elf32_Shdr&);
   ::llvm::ELF::Elf32_Word* GetHashSectionStart();
   ::llvm::ELF::Elf32_Word GetHashBucketNum();
   ::llvm::ELF::Elf32_Word GetHashChainNum();
   ::llvm::ELF::Elf32_Word GetHashBucket(size_t i);
   ::llvm::ELF::Elf32_Word GetHashChain(size_t i);
 
+  typedef std::map<std::string, ::llvm::ELF::Elf32_Sym*> SymbolTable;
+  SymbolTable** GetSymbolTable(::llvm::ELF::Elf32_Word section_type);
+
   File* file_;
   bool writable_;
   bool program_header_only_;
+
+  // ELF header mapping. If program_header_only_ is false, will actually point to the entire elf file.
   UniquePtr<MemMap> map_;
   ::llvm::ELF::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.
@@ -122,10 +161,12 @@
   ::llvm::ELF::Elf32_Dyn* dynamic_section_start_;
   ::llvm::ELF::Elf32_Sym* symtab_section_start_;
   ::llvm::ELF::Elf32_Sym* dynsym_section_start_;
-  char* strtab_section_start_;
-  char* dynstr_section_start_;
+  const char* strtab_section_start_;
+  const char* dynstr_section_start_;
   ::llvm::ELF::Elf32_Word* hash_section_start_;
 
+  SymbolTable* symtab_symbol_table_;
+  SymbolTable* dynsym_symbol_table_;
 };
 
 }  // namespace art
diff --git a/src/elf_writer.cc b/src/elf_writer.cc
index 106ad44..88b3543 100644
--- a/src/elf_writer.cc
+++ b/src/elf_writer.cc
@@ -16,12 +16,6 @@
 
 #include "elf_writer.h"
 
-#include "base/unix_file/fd_file.h"
-#include "compiler/driver/compiler_driver.h"
-#include "elf_file.h"
-#include "oat.h"
-#include "oat_file.h"
-
 #include <llvm/Support/TargetSelect.h>
 
 #include <mcld/Environment.h>
@@ -33,30 +27,66 @@
 #include <mcld/Support/Path.h>
 #include <mcld/Support/TargetSelect.h>
 
+#include "base/unix_file/fd_file.h"
+#include "class_linker.h"
+#include "compiler/driver/compiler_driver.h"
+#include "compiler/llvm/utils_llvm.h"
+#include "dex_method_iterator.h"
+#include "elf_file.h"
+#include "invoke_type.h"
+#include "mirror/abstract_method-inl.h"
+#include "oat.h"
+#include "oat_file.h"
+#include "scoped_thread_state_change.h"
+
 namespace art {
 
-bool ElfWriter::Create(File* file, std::vector<uint8_t>& oat_contents, const CompilerDriver& compiler) {
-  ElfWriter elf_writer(&compiler);
-  return elf_writer.Write(oat_contents, file);
+bool ElfWriter::Create(File* elf_file,
+                       std::vector<uint8_t>& oat_contents,
+                       const std::vector<const DexFile*>& dex_files,
+                       const std::string* host_prefix,
+                       bool is_host,
+                       const CompilerDriver& driver) {
+  ElfWriter elf_writer(driver, elf_file);
+  return elf_writer.Write(oat_contents, dex_files, host_prefix, is_host);
 }
 
-ElfWriter::ElfWriter(const CompilerDriver* driver) : compiler_driver_(driver) {}
+ElfWriter::ElfWriter(const CompilerDriver& driver, File* elf_file)
+  : compiler_driver_(&driver), elf_file_(elf_file), oat_input_(NULL) {}
 
 ElfWriter::~ElfWriter() {}
 
-static void InitializeLLVM() {
-  // TODO: this is lifted from art's compiler_llvm.cc, should be factored out
-#if defined(ART_TARGET)
-  ::llvm::InitializeNativeTarget();
-  // TODO: odd that there is no InitializeNativeTargetMC?
-#else
-  ::llvm::InitializeAllTargets();
-  ::llvm::InitializeAllTargetMCs();
+bool ElfWriter::Write(std::vector<uint8_t>& oat_contents,
+                      const std::vector<const DexFile*>& dex_files,
+                      const std::string* host_prefix,
+                      bool is_host) {
+  Init();
+  AddOatInput(oat_contents);
+#if defined(ART_USE_PORTABLE_COMPILER)
+  AddMethodInputs(dex_files);
+  AddRuntimeInputs(host_prefix, is_host);
 #endif
+  if (!Link()) {
+    return false;
+  }
+#if defined(ART_USE_PORTABLE_COMPILER)
+  FixupOatMethodOffsets(dex_files);
+#endif
+  return true;
 }
 
-bool ElfWriter::Write(std::vector<uint8_t>& oat_contents, File* elf_file) {
+static void InitializeLLVM() {
+  // TODO: this is lifted from art's compiler_llvm.cc, should be factored out
+  if (kIsTargetBuild) {
+    llvm::InitializeNativeTarget();
+    // TODO: odd that there is no InitializeNativeTargetMC?
+  } else {
+    llvm::InitializeAllTargets();
+    llvm::InitializeAllTargetMCs();
+  }
+}
 
+void ElfWriter::Init() {
   std::string target_triple;
   std::string target_cpu;
   std::string target_attr;
@@ -65,154 +95,358 @@
                                        target_cpu,
                                        target_attr);
 
-  {
-    // Based on mclinker's llvm-mcld.cpp main() and LinkerTest
-    //
-    // TODO: LinkerTest uses mcld::Initialize(), but it does an
-    // llvm::InitializeAllTargets, which we don't want. Basically we
-    // want mcld::InitializeNative, but it doesn't exist yet, so we
-    // inline the minimal we need here.
-    InitializeLLVM();
-    mcld::InitializeAllTargets();
-    mcld::InitializeAllLinkers();
-    mcld::InitializeAllEmulations();
-    mcld::InitializeAllDiagnostics();
+  // Based on mclinker's llvm-mcld.cpp main() and LinkerTest
+  //
+  // TODO: LinkerTest uses mcld::Initialize(), but it does an
+  // llvm::InitializeAllTargets, which we don't want. Basically we
+  // want mcld::InitializeNative, but it doesn't exist yet, so we
+  // inline the minimal we need here.
+  InitializeLLVM();
+  mcld::InitializeAllTargets();
+  mcld::InitializeAllLinkers();
+  mcld::InitializeAllEmulations();
+  mcld::InitializeAllDiagnostics();
 
-    UniquePtr<mcld::LinkerConfig> linker_config(new mcld::LinkerConfig(target_triple));
-    CHECK(linker_config.get() != NULL);
-    linker_config->setCodeGenType(mcld::LinkerConfig::DynObj);
-    if (compiler_driver_->GetInstructionSet() == kMips) {
-      // MCLinker defaults MIPS section alignment to 0x10000, not 0x1000
-      mcld::ZOption z_option;
-      z_option.setKind(mcld::ZOption::MaxPageSize);
-      z_option.setPageSize(kPageSize);
-      linker_config->options().addZOption(z_option);
-    }
-    linker_config->options().setSOName(elf_file->GetPath());
-    // TODO: Wire up mcld DiagnosticEngine to LOG?
-    if (false) {
-      // enables some tracing of input file processing
-      linker_config->options().setTrace(true);
-    }
+  linker_config_.reset(new mcld::LinkerConfig(target_triple));
+  CHECK(linker_config_.get() != NULL);
+  linker_config_->setCodeGenType(mcld::LinkerConfig::DynObj);
+  linker_config_->options().setSOName(elf_file_->GetPath());
 
-    // Based on alone::Linker::config
-    UniquePtr<mcld::Module> module(new mcld::Module(linker_config->options().soname()));
-    CHECK(module.get() != NULL);
-    UniquePtr<mcld::IRBuilder> ir_builder(new mcld::IRBuilder(*module.get(), *linker_config.get()));
-    CHECK(ir_builder.get() != NULL);
-    UniquePtr<mcld::Linker> linker(new mcld::Linker());
-    CHECK(linker.get() != NULL);
-    linker->config(*linker_config.get());
+  // error on undefined symbols.
+  // TODO: should this just be set if kIsDebugBuild?
+  linker_config_->options().setNoUndefined(true);
 
-
-    // Add an artificial memory input. Based on LinkerTest.
-    UniquePtr<OatFile> oat_file(OatFile::Open(oat_contents, elf_file->GetPath()));
-    CHECK(oat_file.get() != NULL) << elf_file->GetPath();
-
-    const char* oat_data_start = reinterpret_cast<const char*>(&oat_file->GetOatHeader());
-    const size_t oat_data_length = oat_file->GetOatHeader().GetExecutableOffset();
-    const char* oat_code_start = oat_data_start + oat_data_length;
-    const size_t oat_code_length = oat_file->Size() - oat_data_length;
-
-    // TODO: ownership of input?
-    mcld::Input* input = ir_builder->CreateInput("oat contents",
-                                                 mcld::sys::fs::Path("oat contents path"),
-                                                 mcld::Input::Object);
-    CHECK(input != NULL);
-
-    // TODO: ownership of null_section?
-    mcld::LDSection* null_section = ir_builder->CreateELFHeader(*input,
-                                                                "",
-                                                                mcld::LDFileFormat::Null,
-                                                                ::llvm::ELF::SHT_NULL,
-                                                                0);
-    CHECK(null_section != NULL);
-
-    // TODO: we should split readonly data from readonly executable
-    // code like .oat does.  We need to control section layout with
-    // linker script like functionality to guarantee references
-    // between sections maintain relative position which isn't
-    // possible right now with the mclinker APIs.
-    CHECK(oat_code_start);
-
-    // we need to ensure that oatdata is page aligned so when we
-    // fixup the segment load addresses, they remain page aligned.
-    uint32_t alignment = kPageSize;
-
-    // TODO: ownership of text_section?
-    mcld::LDSection* text_section = ir_builder->CreateELFHeader(*input,
-                                                                ".text",
-                                                                ::llvm::ELF::SHT_PROGBITS,
-                                                                ::llvm::ELF::SHF_EXECINSTR
-                                                                | ::llvm::ELF::SHF_ALLOC,
-                                                                alignment);
-    CHECK(text_section != NULL);
-
-    mcld::SectionData* text_section_data = ir_builder->CreateSectionData(*text_section);
-    CHECK(text_section_data != NULL);
-
-    // TODO: why does IRBuilder::CreateRegion take a non-const pointer?
-    mcld::Fragment* text_fragment = ir_builder->CreateRegion(const_cast<char*>(oat_data_start),
-                                                             oat_file->Size());
-    CHECK(text_fragment != NULL);
-    ir_builder->AppendFragment(*text_fragment, *text_section_data);
-
-    ir_builder->AddSymbol(*input,
-                          "oatdata",
-                          mcld::ResolveInfo::Object,
-                          mcld::ResolveInfo::Define,
-                          mcld::ResolveInfo::Global,
-                          oat_data_length,  // size
-                          0,                // offset
-                          text_section);
-
-    ir_builder->AddSymbol(*input,
-                          "oatexec",
-                          mcld::ResolveInfo::Function,
-                          mcld::ResolveInfo::Define,
-                          mcld::ResolveInfo::Global,
-                          oat_code_length,  // size
-                          oat_data_length,  // offset
-                          text_section);
-
-    ir_builder->AddSymbol(*input,
-                          "oatlastword",
-                          mcld::ResolveInfo::Object,
-                          mcld::ResolveInfo::Define,
-                          mcld::ResolveInfo::Global,
-                          0,                // size
-                          // subtract a word so symbol is within section
-                          (oat_data_length + oat_code_length) - sizeof(uint32_t),  // offset
-                          text_section);
-
-    // link inputs
-    if (!linker->link(*module.get(), *ir_builder.get())) {
-      LOG(ERROR) << "problem linking " << elf_file->GetPath();
-      return false;
-    }
-
-    // emited linked output
-    if (!linker->emit(elf_file->Fd())) {
-      LOG(ERROR) << "problem emitting " << elf_file->GetPath();
-      return false;
-    }
-    // TODO: mcld::Linker::emit closed the file descriptor. It probably shouldn't.
-    // For now, close our File to match.
-    elf_file->Close();
-    mcld::Finalize();
+  // TODO: Wire up mcld DiagnosticEngine to LOG?
+  linker_config_->options().setColor(false);
+  if (false) {
+    // enables some tracing of input file processing
+    linker_config_->options().setTrace(true);
   }
-  LOG(INFO) << "ELF file written successfully: " << elf_file->GetPath();
+
+  // Based on alone::Linker::config
+  module_.reset(new mcld::Module(linker_config_->options().soname()));
+  CHECK(module_.get() != NULL);
+  ir_builder_.reset(new mcld::IRBuilder(*module_.get(), *linker_config_.get()));
+  CHECK(ir_builder_.get() != NULL);
+  linker_.reset(new mcld::Linker());
+  CHECK(linker_.get() != NULL);
+  linker_->config(*linker_config_.get());
+}
+
+void ElfWriter::AddOatInput(std::vector<uint8_t>& oat_contents) {
+  // Add an artificial memory input. Based on LinkerTest.
+  UniquePtr<OatFile> oat_file(OatFile::OpenMemory(oat_contents, elf_file_->GetPath()));
+  CHECK(oat_file.get() != NULL) << elf_file_->GetPath();
+
+  const char* oat_data_start = reinterpret_cast<const char*>(&oat_file->GetOatHeader());
+  const size_t oat_data_length = oat_file->GetOatHeader().GetExecutableOffset();
+  const char* oat_code_start = oat_data_start + oat_data_length;
+  const size_t oat_code_length = oat_file->Size() - oat_data_length;
+
+  // TODO: ownership of oat_input?
+  oat_input_ = ir_builder_->CreateInput("oat contents",
+                                        mcld::sys::fs::Path("oat contents path"),
+                                        mcld::Input::Object);
+  CHECK(oat_input_ != NULL);
+
+  // TODO: ownership of null_section?
+  mcld::LDSection* null_section = ir_builder_->CreateELFHeader(*oat_input_,
+                                                               "",
+                                                               mcld::LDFileFormat::Null,
+                                                               llvm::ELF::SHT_NULL,
+                                                               0);
+  CHECK(null_section != NULL);
+
+  // TODO: we should split readonly data from readonly executable
+  // code like .oat does.  We need to control section layout with
+  // linker script like functionality to guarantee references
+  // between sections maintain relative position which isn't
+  // possible right now with the mclinker APIs.
+  CHECK(oat_code_start != NULL);
+
+  // we need to ensure that oatdata is page aligned so when we
+  // fixup the segment load addresses, they remain page aligned.
+  uint32_t alignment = kPageSize;
+
+  // TODO: ownership of text_section?
+  mcld::LDSection* text_section = ir_builder_->CreateELFHeader(*oat_input_,
+                                                               ".text",
+                                                               llvm::ELF::SHT_PROGBITS,
+                                                               llvm::ELF::SHF_EXECINSTR
+                                                               | llvm::ELF::SHF_ALLOC,
+                                                               alignment);
+  CHECK(text_section != NULL);
+
+  mcld::SectionData* text_sectiondata = ir_builder_->CreateSectionData(*text_section);
+  CHECK(text_sectiondata != NULL);
+
+  // TODO: why does IRBuilder::CreateRegion take a non-const pointer?
+  mcld::Fragment* text_fragment = ir_builder_->CreateRegion(const_cast<char*>(oat_data_start),
+                                                            oat_file->Size());
+  CHECK(text_fragment != NULL);
+  ir_builder_->AppendFragment(*text_fragment, *text_sectiondata);
+
+  ir_builder_->AddSymbol(*oat_input_,
+                         "oatdata",
+                         mcld::ResolveInfo::Object,
+                         mcld::ResolveInfo::Define,
+                         mcld::ResolveInfo::Global,
+                         oat_data_length,  // size
+                         0,                // offset
+                         text_section);
+
+  ir_builder_->AddSymbol(*oat_input_,
+                         "oatexec",
+                         mcld::ResolveInfo::Function,
+                         mcld::ResolveInfo::Define,
+                         mcld::ResolveInfo::Global,
+                         oat_code_length,  // size
+                         oat_data_length,  // offset
+                         text_section);
+
+  ir_builder_->AddSymbol(*oat_input_,
+                         "oatlastword",
+                         mcld::ResolveInfo::Object,
+                         mcld::ResolveInfo::Define,
+                         mcld::ResolveInfo::Global,
+                         0,                // size
+                         // subtract a word so symbol is within section
+                         (oat_data_length + oat_code_length) - sizeof(uint32_t),  // offset
+                         text_section);
+}
+
+#if defined(ART_USE_PORTABLE_COMPILER)
+void ElfWriter::AddMethodInputs(const std::vector<const DexFile*>& dex_files) {
+  DCHECK(oat_input_ != NULL);
+
+  DexMethodIterator it(dex_files);
+  while (it.HasNext()) {
+    const DexFile& dex_file = it.GetDexFile();
+    uint32_t method_idx = it.GetMemberIndex();
+    InvokeType invoke_type = it.GetInvokeType();
+    const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
+    const CompiledMethod* compiled_method =
+      compiler_driver_->GetCompiledMethod(CompilerDriver::MethodReference(&dex_file, method_idx));
+    if (compiled_method != NULL) {
+      AddCompiledCodeInput(*compiled_method);
+    }
+    const CompiledInvokeStub* compiled_invoke_stub = compiler_driver_->FindInvokeStub(invoke_type == kStatic,
+                                                                                      shorty);
+    if (compiled_invoke_stub != NULL) {
+      AddCompiledCodeInput(*compiled_invoke_stub);
+    }
+
+    if (invoke_type != kStatic) {
+      const CompiledInvokeStub* compiled_proxy_stub = compiler_driver_->FindProxyStub(shorty);
+      if (compiled_proxy_stub != NULL) {
+        AddCompiledCodeInput(*compiled_proxy_stub);
+      }
+    }
+    it.Next();
+  }
+  added_symbols_.clear();
+}
+
+void ElfWriter::AddCompiledCodeInput(const CompiledCode& compiled_code) {
+  // Check if we've seen this compiled code before. If so skip
+  // it. This can happen for reused code such as invoke stubs.
+  const std::string& symbol = compiled_code.GetSymbol();
+  SafeMap<const std::string*, const std::string*>::iterator it = added_symbols_.find(&symbol);
+  if (it != added_symbols_.end()) {
+    return;
+  }
+  added_symbols_.Put(&symbol, &symbol);
+
+  // Add input to supply code for symbol
+  const std::vector<uint8_t>& code = compiled_code.GetCode();
+  // TODO: ownership of code_input?
+  // TODO: why does IRBuilder::ReadInput take a non-const pointer?
+  mcld::Input* code_input = ir_builder_->ReadInput(symbol,
+                                                   const_cast<uint8_t*>(&code[0]),
+                                                   code.size());
+  CHECK(code_input != NULL);
+}
+
+void ElfWriter::AddRuntimeInputs(const std::string* host_prefix, bool is_host) {
+  std::string android_root;
+  if (is_host) {
+    const char* android_host_out = getenv("ANDROID_HOST_OUT");
+    CHECK(android_host_out != NULL) << "ANDROID_HOST_OUT environment variable not set";
+    android_root += android_host_out;
+  } else {
+    if (host_prefix != NULL) {
+      android_root += *host_prefix;
+      android_root += "/system";
+    } else {
+      android_root += GetAndroidRoot();
+    }
+  }
+
+  std::string libart_so(android_root);
+  libart_so += kIsDebugBuild ? "/lib/libartd.so" : "/lib/libart.so";
+  // TODO: ownership of libart_so_input?
+  mcld::Input* libart_so_input = ir_builder_->ReadInput(libart_so, libart_so);
+  CHECK(libart_so_input != NULL);
+
+  std::string host_prebuilt_dir("prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6");
+
+  std::string compiler_runtime_lib;
+  if (is_host) {
+    compiler_runtime_lib += host_prebuilt_dir;
+    compiler_runtime_lib += "/lib/gcc/i686-linux/4.6.x-google/libgcc.a";
+  } else {
+    compiler_runtime_lib += android_root;
+    compiler_runtime_lib += "/lib/libcompiler-rt.a";
+  }
+  // TODO: ownership of compiler_runtime_lib_input?
+  mcld::Input* compiler_runtime_lib_input = ir_builder_->ReadInput(compiler_runtime_lib,
+                                                                   compiler_runtime_lib);
+  CHECK(compiler_runtime_lib_input != NULL);
+
+  std::string libc_lib;
+  if (is_host) {
+    libc_lib += host_prebuilt_dir;
+    libc_lib += "/sysroot/usr/lib/libc.so.6";
+  } else {
+    libc_lib += android_root;
+    libc_lib += "/lib/libc.so";
+  }
+  // TODO: ownership of libc_lib_input?
+  mcld::Input* libc_lib_input_input = ir_builder_->ReadInput(libc_lib, libc_lib);
+  CHECK(libc_lib_input_input != NULL);
+
+  std::string libm_lib;
+  if (is_host) {
+    libm_lib += host_prebuilt_dir;
+    libm_lib += "/sysroot/usr/lib/libm.so";
+  } else {
+    libm_lib += android_root;
+    libm_lib += "/lib/libm.so";
+  }
+  // TODO: ownership of libm_lib_input?
+  mcld::Input* libm_lib_input_input = ir_builder_->ReadInput(libm_lib, libm_lib);
+  CHECK(libm_lib_input_input != NULL);
+
+}
+#endif
+
+bool ElfWriter::Link() {
+  // link inputs
+  if (!linker_->link(*module_.get(), *ir_builder_.get())) {
+    LOG(ERROR) << "Failed to link " << elf_file_->GetPath();
+    return false;
+  }
+
+  // emit linked output
+  // TODO: avoid dup of fd by fixing Linker::emit to not close the argument fd.
+  int fd = dup(elf_file_->Fd());
+  if (fd == -1) {
+    PLOG(ERROR) << "Failed to dup file descriptor for " << elf_file_->GetPath();
+    return false;
+  }
+  if (!linker_->emit(fd)) {
+    LOG(ERROR) << "Failed to emit " << elf_file_->GetPath();
+    return false;
+  }
+  mcld::Finalize();
+  LOG(INFO) << "ELF file written successfully: " << elf_file_->GetPath();
   return true;
 }
 
+static llvm::ELF::Elf32_Addr GetOatDataAddress(ElfFile* elf_file) {
+  llvm::ELF::Elf32_Addr oatdata_address = elf_file->FindSymbolAddress(llvm::ELF::SHT_DYNSYM,
+                                                                      "oatdata",
+                                                                      false);
+  CHECK_NE(0U, oatdata_address);
+  return oatdata_address;
+}
+
+#if defined(ART_USE_PORTABLE_COMPILER)
+void ElfWriter::FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files) {
+  UniquePtr<ElfFile> elf_file(ElfFile::Open(elf_file_, true, false));
+  CHECK(elf_file.get() != NULL) << elf_file_->GetPath();
+
+  llvm::ELF::Elf32_Addr oatdata_address = GetOatDataAddress(elf_file.get());
+  DexMethodIterator it(dex_files);
+  while (it.HasNext()) {
+    const DexFile& dex_file = it.GetDexFile();
+    uint32_t method_idx = it.GetMemberIndex();
+    InvokeType invoke_type = it.GetInvokeType();
+    const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
+    mirror::AbstractMethod* method = NULL;
+    if (compiler_driver_->IsImage()) {
+      ClassLinker* linker = Runtime::Current()->GetClassLinker();
+      mirror::DexCache* dex_cache = linker->FindDexCache(dex_file);
+      // Unchecked as we hold mutator_lock_ on entry.
+      ScopedObjectAccessUnchecked soa(Thread::Current());
+      method = linker->ResolveMethod(dex_file, method_idx, dex_cache, NULL, NULL, invoke_type);
+      CHECK(method != NULL);
+    }
+    const CompiledMethod* compiled_method =
+      compiler_driver_->GetCompiledMethod(CompilerDriver::MethodReference(&dex_file, method_idx));
+    if (compiled_method != NULL) {
+      uint32_t offset = FixupCompiledCodeOffset(*elf_file.get(), oatdata_address, *compiled_method);
+      // Don't overwrite static method trampoline
+      if (method != NULL &&
+          (!method->IsStatic() ||
+           method->IsConstructor() ||
+           method->GetDeclaringClass()->IsInitialized())) {
+        method->SetOatCodeOffset(offset);
+      }
+    }
+    const CompiledInvokeStub* compiled_invoke_stub = compiler_driver_->FindInvokeStub(invoke_type == kStatic,
+                                                                                      shorty);
+    if (compiled_invoke_stub != NULL) {
+      uint32_t offset = FixupCompiledCodeOffset(*elf_file.get(), oatdata_address, *compiled_invoke_stub);
+      if (method != NULL) {
+        method->SetOatInvokeStubOffset(offset);
+      }
+    }
+
+    if (invoke_type != kStatic) {
+      const CompiledInvokeStub* compiled_proxy_stub = compiler_driver_->FindProxyStub(shorty);
+      if (compiled_proxy_stub != NULL) {
+        FixupCompiledCodeOffset(*elf_file.get(), oatdata_address, *compiled_proxy_stub);
+      }
+    }
+    it.Next();
+  }
+  symbol_to_compiled_code_offset_.clear();
+}
+
+uint32_t ElfWriter::FixupCompiledCodeOffset(ElfFile& elf_file,
+                                            llvm::ELF::Elf32_Addr oatdata_address,
+                                            const CompiledCode& compiled_code) {
+  const std::string& symbol = compiled_code.GetSymbol();
+  SafeMap<const std::string*, uint32_t>::iterator it = symbol_to_compiled_code_offset_.find(&symbol);
+  if (it != symbol_to_compiled_code_offset_.end()) {
+    return it->second;
+  }
+
+  llvm::ELF::Elf32_Addr compiled_code_address = elf_file.FindSymbolAddress(llvm::ELF::SHT_SYMTAB,
+                                                                           symbol,
+                                                                           true);
+  CHECK_NE(0U, compiled_code_address) << symbol;
+  CHECK_LT(oatdata_address, compiled_code_address) << symbol;
+  uint32_t compiled_code_offset = compiled_code_address - oatdata_address;
+  symbol_to_compiled_code_offset_.Put(&symbol, compiled_code_offset);
+
+  const std::vector<uint32_t>& offsets = compiled_code.GetOatdataOffsetsToCompliledCodeOffset();
+  for (uint32_t i = 0; i < offsets.size(); i++) {
+    uint32_t oatdata_offset = oatdata_address + offsets[i];
+    uint32_t* addr = reinterpret_cast<uint32_t*>(elf_file.Begin() + oatdata_offset);
+    *addr = compiled_code_offset;
+  }
+  return compiled_code_offset;
+}
+#endif
+
 bool ElfWriter::Fixup(File* file, uintptr_t oat_data_begin) {
   UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false));
   CHECK(elf_file.get() != NULL);
 
   // Lookup "oatdata" symbol address.
-  ::llvm::ELF::Elf32_Addr oatdata_address = elf_file->FindSymbolAddress(::llvm::ELF::SHT_DYNSYM,
-                                                                        "oatdata");
-  CHECK_NE(0U, oatdata_address);
+  ::llvm::ELF::Elf32_Addr oatdata_address = GetOatDataAddress(elf_file.get());
   ::llvm::ELF::Elf32_Off base_address = oat_data_begin - oatdata_address;
 
   if (!FixupDynamic(*elf_file.get(), base_address)) {
@@ -235,6 +469,10 @@
       LOG(WARNING) << "Failed fo fixup .symtab in " << file->GetPath();
       return false;
   }
+  if (!FixupRelocations(*elf_file.get(), base_address)) {
+      LOG(WARNING) << "Failed fo fixup .rel.dyn in " << file->GetPath();
+      return false;
+  }
   return true;
 }
 
@@ -314,6 +552,123 @@
   return true;
 }
 
+bool ElfWriter::FixupRelocations(ElfFile& elf_file, uintptr_t base_address) {
+  for (llvm::ELF::Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) {
+    llvm::ELF::Elf32_Shdr& sh = elf_file.GetSectionHeader(i);
+    if (sh.sh_type == llvm::ELF::SHT_REL) {
+      for (uint32_t i = 0; i < elf_file.GetRelNum(sh); i++) {
+        llvm::ELF::Elf32_Rel& rel = elf_file.GetRel(sh, i);
+        rel.r_offset += base_address;
+      }
+    } else if (sh.sh_type == llvm::ELF::SHT_RELA) {
+      for (uint32_t i = 0; i < elf_file.GetRelaNum(sh); i++) {
+        llvm::ELF::Elf32_Rela& rela = elf_file.GetRela(sh, i);
+        rela.r_offset += base_address;
+      }
+    }
+  }
+  return true;
+}
+
+bool ElfWriter::Strip(File* file) {
+  UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false));
+  CHECK(elf_file.get() != NULL);
+
+  // 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<llvm::ELF::Elf32_Shdr> section_headers;
+  std::vector<llvm::ELF::Elf32_Word> section_headers_original_indexes;
+  section_headers.reserve(elf_file->GetSectionHeaderNum());
+
+
+  llvm::ELF::Elf32_Shdr& string_section = elf_file->GetSectionNameStringSection();
+  for (llvm::ELF::Elf32_Word i = 0; i < elf_file->GetSectionHeaderNum(); i++) {
+    llvm::ELF::Elf32_Shdr& sh = elf_file->GetSectionHeader(i);
+    const char* name = elf_file->GetString(string_section, sh.sh_name);
+    if (name == NULL) {
+      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
+  llvm::ELF::Elf32_Off offset = elf_file->GetSectionHeader(1).sh_offset;
+  for (size_t i = 1; i < section_headers.size(); i++) {
+    llvm::ELF::Elf32_Shdr& new_sh = section_headers[i];
+    llvm::ELF::Elf32_Shdr& old_sh = elf_file->GetSectionHeader(section_headers_original_indexes[i]);
+    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;
+  }
+
+  llvm::ELF::Elf32_Off shoff = offset;
+  size_t section_headers_size_in_bytes = section_headers.size() * sizeof(llvm::ELF::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) {
+    PLOG(ERROR) << "Failed to truncate while stripping ELF file: " << file->GetPath();
+    return false;
+  }
+  return true;
+}
+
 void ElfWriter::GetOatElfInformation(File* file,
                                      size_t& oat_loaded_size,
                                      size_t& oat_data_offset) {
@@ -322,7 +677,7 @@
 
   oat_loaded_size = elf_file->GetLoadedSize();
   CHECK_NE(0U, oat_loaded_size);
-  oat_data_offset = elf_file->FindSymbolAddress(::llvm::ELF::SHT_DYNSYM, "oatdata");
+  oat_data_offset = GetOatDataAddress(elf_file.get());
   CHECK_NE(0U, oat_data_offset);
 }
 
diff --git a/src/elf_writer.h b/src/elf_writer.h
index f55003f..6f22db1 100644
--- a/src/elf_writer.h
+++ b/src/elf_writer.h
@@ -17,23 +17,52 @@
 #ifndef ART_SRC_ELF_WRITER_H_
 #define ART_SRC_ELF_WRITER_H_
 
-#include "elf_file.h"
-#include "os.h"
+#include <stdint.h>
 
+#include <cstddef>
 #include <vector>
 
+#include <llvm/Support/ELF.h>
+
+#include "UniquePtr.h"
+#include "dex_file.h"
+#include "os.h"
+
+namespace mcld {
+class IRBuilder;
+class Input;
+class LDSection;
+class LDSymbol;
+class Linker;
+class LinkerConfig;
+class Module;
+} // namespace mcld
+
 namespace art {
+
+class CompiledCode;
 class CompilerDriver;
+class ElfFile;
 
 class ElfWriter {
  public:
   // Write an ELF file. Returns true on success, false on failure.
-  static bool Create(File* file, std::vector<uint8_t>& oat_contents, const CompilerDriver& compiler);
+  static bool Create(File* file,
+                     std::vector<uint8_t>& oat_contents,
+                     const std::vector<const DexFile*>& dex_files,
+                     const std::string* host_prefix,
+                     bool is_host,
+                     const CompilerDriver& driver)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // 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);
 
+  // Strip an ELF file of unneeded debugging information.
+  // Returns true on success, false on failure.
+  static bool Strip(File* file);
+
   // Looks up information about location of oat file in elf file container.
   // Used for ImageWriter to perform memory layout.
   static void GetOatElfInformation(File* file,
@@ -41,10 +70,28 @@
                                    size_t& oat_data_offset);
 
  private:
-  ElfWriter(const CompilerDriver* driver);
+  ElfWriter(const CompilerDriver& driver, File* elf_file);
   ~ElfWriter();
 
-  bool Write(std::vector<uint8_t>& oat_contents, File* elf_file);
+  bool Write(std::vector<uint8_t>& oat_contents,
+             const std::vector<const DexFile*>& dex_files,
+             const std::string* host_prefix,
+             bool is_host)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  void Init();
+  void AddOatInput(std::vector<uint8_t>& oat_contents);
+  void AddMethodInputs(const std::vector<const DexFile*>& dex_files);
+  void AddCompiledCodeInput(const CompiledCode& compiled_code);
+  void AddRuntimeInputs(const std::string* host_prefix, bool is_host);
+  bool Link();
+#if defined(ART_USE_PORTABLE_COMPILER)
+  void FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  uint32_t FixupCompiledCodeOffset(ElfFile& elf_file,
+                                   llvm::ELF::Elf32_Addr oatdata_address,
+                                   const CompiledCode& compiled_code);
+#endif
 
   // Fixup .dynamic d_ptr values for the expected base_address.
   static bool FixupDynamic(ElfFile& elf_file, uintptr_t base_address);
@@ -58,7 +105,31 @@
   // Fixup symbol table
   static bool FixupSymbols(ElfFile& elf_file, uintptr_t base_address, bool dynamic);
 
-  const CompilerDriver* const compiler_driver_;
+  // Fixup dynamic relocations
+  static bool FixupRelocations(ElfFile& elf_file, uintptr_t base_address);
+
+  // Setup by constructor
+  const CompilerDriver* compiler_driver_;
+  File* elf_file_;
+
+  // Setup by Init()
+  UniquePtr<mcld::LinkerConfig> linker_config_;
+  UniquePtr<mcld::Module> module_;
+  UniquePtr<mcld::IRBuilder> ir_builder_;
+  UniquePtr<mcld::Linker> linker_;
+
+  // Setup by AddOatInput()
+  // TODO: ownership of oat_input_?
+  mcld::Input* oat_input_;
+
+  // Setup by AddCompiledCodeInput
+  // set of symbols for already added mcld::Inputs
+  SafeMap<const std::string*, const std::string*> added_symbols_;
+
+  // Setup by FixupCompiledCodeOffset
+  // map of symbol names to oatdata offset
+  SafeMap<const std::string*, uint32_t> symbol_to_compiled_code_offset_;
+
 };
 
 }  // namespace art
diff --git a/src/elf_writer_test.cc b/src/elf_writer_test.cc
index 0be624d..a47bc71 100644
--- a/src/elf_writer_test.cc
+++ b/src/elf_writer_test.cc
@@ -30,9 +30,9 @@
   }
 };
 
-#define EXPECT_ELF_FILE_ADDRESS(ef, value, name) \
-  EXPECT_EQ(value, reinterpret_cast<void*>(ef->FindSymbolAddress(::llvm::ELF::SHT_SYMTAB, name))); \
-  EXPECT_EQ(value, reinterpret_cast<void*>(ef->FindSymbolAddress(::llvm::ELF::SHT_DYNSYM, name))); \
+#define EXPECT_ELF_FILE_ADDRESS(ef, value, name, build_map) \
+  EXPECT_EQ(value, reinterpret_cast<void*>(ef->FindSymbolAddress(::llvm::ELF::SHT_SYMTAB, name, build_map))); \
+  EXPECT_EQ(value, reinterpret_cast<void*>(ef->FindSymbolAddress(::llvm::ELF::SHT_DYNSYM, name, build_map))); \
   EXPECT_EQ(value, ef->FindDynamicSymbolAddress(name)); \
 
 /*
@@ -79,9 +79,16 @@
   {
     UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, false));
     CHECK(ef.get() != NULL);
-    EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata");
-    EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec");
-    EXPECT_ELF_FILE_ADDRESS(ef, dl_oatlastword, "oatlastword");
+    EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", false);
+    EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec", false);
+    EXPECT_ELF_FILE_ADDRESS(ef, dl_oatlastword, "oatlastword", false);
+  }
+  {
+    UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, false));
+    CHECK(ef.get() != NULL);
+    EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", true);
+    EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec", true);
+    EXPECT_ELF_FILE_ADDRESS(ef, dl_oatlastword, "oatlastword", true);
   }
   {
     UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, true));
diff --git a/src/heap.cc b/src/heap.cc
index c8df031..64df6b8 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -104,6 +104,10 @@
   std::string base_option_string(StringPrintf("--base=0x%x", ART_BASE_ADDRESS));
   arg_vector.push_back(strdup(base_option_string.c_str()));
 
+  if (!kIsTargetBuild) {
+    arg_vector.push_back(strdup("--host"));
+  }
+
   std::string command_line(Join(arg_vector, ' '));
   LOG(INFO) << command_line;
 
diff --git a/src/image_test.cc b/src/image_test.cc
index 6d22cad..dc16a6c 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -57,9 +57,13 @@
         mirror::Class* klass = class_linker_->FindSystemClass(descriptor);
         EXPECT_TRUE(klass != NULL) << descriptor;
       }
+      bool success_elf = compiler_driver_->WriteElf(NULL,
+                                                    !kIsTargetBuild,
+                                                    dex_files,
+                                                    oat_contents,
+                                                    tmp_elf.GetFile());
+      ASSERT_TRUE(success_elf);
     }
-    bool success_elf = compiler_driver_->WriteElf(oat_contents, tmp_elf.GetFile());
-    ASSERT_TRUE(success_elf);
   }
   // Workound bug that mcld::Linker::emit closes tmp_elf by reopening as tmp_oat.
   UniquePtr<File> tmp_oat(OS::OpenFile(tmp_elf.GetFilename().c_str(), true, false));
diff --git a/src/image_writer.cc b/src/image_writer.cc
index d9ac61b..ad2c9b7 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -78,7 +78,7 @@
     LOG(ERROR) << "Failed to open oat file " << oat_filename << " for " << oat_location;
     return false;
   }
-  oat_file_ = OatFile::Open(oat_file.get(), oat_location, NULL, true);
+  oat_file_ = OatFile::OpenWritable(oat_file.get(), oat_location);
   class_linker->RegisterOatFile(*oat_file_);
 
   {
diff --git a/src/image_writer.h b/src/image_writer.h
index ee02ec4..46d134f 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -98,7 +98,12 @@
   }
 
   const byte* GetOatAddress(uint32_t offset) const {
+#if !defined(ART_USE_PORTABLE_COMPILER)
+    // With Quick, code is within the OatFile, as there are all in one
+    // .o ELF object. However with Portable, the code is always in
+    // different .o ELF objects.
     DCHECK_LT(offset, oat_file_->Size());
+#endif
     if (offset == 0) {
       return NULL;
     }
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index 801e7c9..deff290 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -1406,6 +1406,7 @@
 }
 
 TEST_F(JniInternalTest, StaticMainMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("Main");
   SirtRef<mirror::ClassLoader>
@@ -1427,121 +1428,145 @@
 }
 
 TEST_F(JniInternalTest, StaticNopMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeNopMethod(true);
 }
 
 TEST_F(JniInternalTest, NonStaticNopMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeNopMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticIdentityByteMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeIdentityByteMethod(true);
 }
 
 TEST_F(JniInternalTest, NonStaticIdentityByteMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeIdentityByteMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticIdentityIntMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeIdentityIntMethod(true);
 }
 
 TEST_F(JniInternalTest, NonStaticIdentityIntMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeIdentityIntMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticIdentityDoubleMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeIdentityDoubleMethod(true);
 }
 
 TEST_F(JniInternalTest, NonStaticIdentityDoubleMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeIdentityDoubleMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticSumIntIntMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumIntIntMethod(true);
 }
 
 TEST_F(JniInternalTest, NonStaticSumIntIntMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumIntIntMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticSumIntIntIntMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumIntIntIntMethod(true);
 }
 
 TEST_F(JniInternalTest, NonStaticSumIntIntIntMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumIntIntIntMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticSumIntIntIntIntMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumIntIntIntIntMethod(true);
 }
 
 TEST_F(JniInternalTest, NonStaticSumIntIntIntIntMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumIntIntIntIntMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticSumIntIntIntIntIntMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumIntIntIntIntIntMethod(true);
 }
 
 TEST_F(JniInternalTest, NonStaticSumIntIntIntIntIntMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumIntIntIntIntIntMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticSumDoubleDoubleMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumDoubleDoubleMethod(true);
 }
 
 TEST_F(JniInternalTest, NonStaticSumDoubleDoubleMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumDoubleDoubleMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumDoubleDoubleDoubleMethod(true);
 }
 
 TEST_F(JniInternalTest, NonStaticSumDoubleDoubleDoubleMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumDoubleDoubleDoubleMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleDoubleMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumDoubleDoubleDoubleDoubleMethod(true);
 }
 
 TEST_F(JniInternalTest, NonStaticSumDoubleDoubleDoubleDoubleMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumDoubleDoubleDoubleDoubleMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleDoubleDoubleMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(true);
 }
 
 TEST_F(JniInternalTest, NonStaticSumDoubleDoubleDoubleDoubleDoubleMethod) {
+  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(false);
 }
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 5fd95be..62fc740 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -44,8 +44,8 @@
   }
 }
 
-OatFile* OatFile::Open(std::vector<uint8_t>& oat_contents,
-                       const std::string& location) {
+OatFile* OatFile::OpenMemory(std::vector<uint8_t>& oat_contents,
+                             const std::string& location) {
   CHECK(!oat_contents.empty()) << location;
   CheckLocation(location);
   UniquePtr<OatFile> oat_file(new OatFile(location));
@@ -69,11 +69,17 @@
    *    Fix MIPS to use standard kPageSize=0x1000 section alignment for ELF sections
    *
    *    Change-Id: I905f0c5f75921a65bd7426a54d6258c780d85d0e
+   */
   OatFile* result = OpenDlopen(filename, location, requested_base);
   if (result != NULL) {
     return result;
   }
-  */
+  // On target, only used dlopen to load.
+  if (kIsTargetBuild) {
+    return NULL;
+  }
+  // On host, dlopen is expected to fail when cross compiling, so fall back to OpenElfFile.
+  // This won't work for portable runtime execution because it doesn't process relocations.
   UniquePtr<File> file(OS::OpenFile(filename.c_str(), false, false));
   if (file.get() == NULL) {
     return NULL;
@@ -81,12 +87,9 @@
   return OpenElfFile(file.get(), location, requested_base, false);
 }
 
-OatFile* OatFile::Open(File* file,
-                       const std::string& location,
-                       byte* requested_base,
-                       bool writable) {
+OatFile* OatFile::OpenWritable(File* file, const std::string& location) {
   CheckLocation(location);
-  return OpenElfFile(file, location, requested_base, writable);
+  return OpenElfFile(file, location, NULL, true);
 }
 
 OatFile* OatFile::OpenDlopen(const std::string& elf_filename,
@@ -396,6 +399,13 @@
 }
 
 uint32_t OatFile::OatMethod::GetCodeSize() const {
+#if defined(ART_USE_PORTABLE_COMPILER)
+  // TODO: With Quick, we store the size before the code. With
+  // Portable, the code is in a .o file we don't manage ourselves. ELF
+  // symbols do have a concept of size, so we could capture that and
+  // store it somewhere, such as the OatMethod.
+  return 0;
+#else
   uintptr_t code = reinterpret_cast<uint32_t>(GetCode());
 
   if (code == 0) {
@@ -404,6 +414,7 @@
   // TODO: make this Thumb2 specific
   code &= ~0x1;
   return reinterpret_cast<uint32_t*>(code)[-1];
+#endif
 }
 
 mirror::AbstractMethod::InvokeStub* OatFile::OatMethod::GetInvokeStub() const {
@@ -412,6 +423,9 @@
 }
 
 uint32_t OatFile::OatMethod::GetInvokeStubSize() const {
+#if defined(ART_USE_PORTABLE_COMPILER)
+  return 0;
+#else
   uintptr_t code = reinterpret_cast<uint32_t>(GetInvokeStub());
   if (code == 0) {
     return 0;
@@ -419,6 +433,7 @@
   // TODO: make this Thumb2 specific
   code &= ~0x1;
   return reinterpret_cast<uint32_t*>(code)[-1];
+#endif
 }
 
 #if defined(ART_USE_PORTABLE_COMPILER)
@@ -427,7 +442,7 @@
 }
 #endif
 
-void OatFile::OatMethod::LinkMethodPointers(mirror::AbstractMethod* method) const {
+void OatFile::OatMethod::LinkMethod(mirror::AbstractMethod* method) const {
   CHECK(method != NULL);
   method->SetCode(GetCode());
   method->SetFrameSizeInBytes(frame_size_in_bytes_);
@@ -439,16 +454,4 @@
   method->SetInvokeStub(GetInvokeStub());
 }
 
-void OatFile::OatMethod::LinkMethodOffsets(mirror::AbstractMethod* method) const {
-  CHECK(method != NULL);
-  method->SetOatCodeOffset(GetCodeOffset());
-  method->SetFrameSizeInBytes(GetFrameSizeInBytes());
-  method->SetCoreSpillMask(GetCoreSpillMask());
-  method->SetFpSpillMask(GetFpSpillMask());
-  method->SetOatMappingTableOffset(GetMappingTableOffset());
-  method->SetOatVmapTableOffset(GetVmapTableOffset());
-  method->SetOatNativeGcMapOffset(GetNativeGcMapOffset());
-  method->SetOatInvokeStubOffset(GetInvokeStubOffset());
-}
-
 }  // namespace art
diff --git a/src/oat_file.h b/src/oat_file.h
index 8efdf9f..4aa18ba 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -46,14 +46,15 @@
                        byte* requested_base);
 
   // Open an oat file from an already opened File.
-  static OatFile* Open(File* file,
-                       const std::string& location,
-                       byte* requested_base,
-                       bool writable);
+  // Does not use dlopen underneath so cannot be used for runtime use
+  // where relocations may be required. Currently used from
+  // ImageWriter which wants to open a writable version from an existing
+  // file descriptor for patching.
+  static OatFile* OpenWritable(File* file, const std::string& location);
 
   // Open an oat file backed by a std::vector with the given location.
-  static OatFile* Open(std::vector<uint8_t>& oat_contents,
-                       const std::string& location);
+  static OatFile* OpenMemory(std::vector<uint8_t>& oat_contents,
+                             const std::string& location);
 
   ~OatFile();
 
@@ -67,11 +68,7 @@
 
   class OatMethod {
    public:
-    // Link Method for execution using the contents of this OatMethod
-    void LinkMethodPointers(mirror::AbstractMethod* method) const;
-
-    // Link Method for image writing using the contents of this OatMethod
-    void LinkMethodOffsets(mirror::AbstractMethod* method) const;
+    void LinkMethod(mirror::AbstractMethod* method) const;
 
     uint32_t GetCodeOffset() const {
       return code_offset_;
diff --git a/src/oat_test.cc b/src/oat_test.cc
index 69ce48b..ace52f4 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -90,7 +90,11 @@
                                        "lue.art",
                                        *compiler_driver_.get());
   ASSERT_TRUE(success_oat);
-  bool success_elf = compiler_driver_->WriteElf(oat_contents, tmp.GetFile());
+  bool success_elf = compiler_driver_->WriteElf(NULL,
+                                                !kIsTargetBuild,
+                                                class_linker->GetBootClassPath(),
+                                                oat_contents,
+                                                tmp.GetFile());
   ASSERT_TRUE(success_elf);
 
   if (compile) {  // OatWriter strips the code, regenerate to compare
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 1a269e9..e299a27 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -93,7 +93,7 @@
   for (size_t i = 0; i != dex_files_->size(); ++i) {
     const DexFile* dex_file = (*dex_files_)[i];
     CHECK(dex_file != NULL);
-    OatDexFile* oat_dex_file = new OatDexFile(*dex_file);
+    OatDexFile* oat_dex_file = new OatDexFile(offset, *dex_file);
     oat_dex_files_.push_back(oat_dex_file);
     offset += oat_dex_file->SizeOf();
   }
@@ -145,7 +145,7 @@
         status = mirror::Class::kStatusNotReady;
       }
 
-      OatClass* oat_class = new OatClass(status, num_methods);
+      OatClass* oat_class = new OatClass(offset, status, num_methods);
       oat_classes_.push_back(oat_class);
       offset += oat_class->SizeOf();
     }
@@ -232,7 +232,7 @@
                                     size_t __attribute__((unused)) class_def_index,
                                     size_t class_def_method_index,
                                     bool __attribute__((unused)) is_native,
-                                    InvokeType type,
+                                    InvokeType invoke_type,
                                     uint32_t method_idx, const DexFile* dex_file) {
   // derived from CompiledMethod if available
   uint32_t code_offset = 0;
@@ -248,12 +248,22 @@
   uint32_t proxy_stub_offset = 0;
 #endif
 
+  OatClass* oat_class = oat_classes_[oat_class_index];
+#if defined(ART_USE_PORTABLE_COMPILER)
+  size_t oat_method_offsets_offset =
+      oat_class->GetOatMethodOffsetsOffsetFromOatHeader(class_def_method_index);
+#endif
+
   CompiledMethod* compiled_method =
       compiler_driver_->GetCompiledMethod(CompilerDriver::MethodReference(dex_file, method_idx));
   if (compiled_method != NULL) {
+#if defined(ART_USE_PORTABLE_COMPILER)
+    compiled_method->AddOatdataOffsetToCompliledCodeOffset(
+        oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, code_offset_));
+#else
+    const std::vector<uint8_t>& code = compiled_method->GetCode();
     offset = compiled_method->AlignCode(offset);
     DCHECK_ALIGNED(offset, kArmAlignment);
-    const std::vector<uint8_t>& code = compiled_method->GetCode();
     uint32_t code_size = code.size() * sizeof(code[0]);
     CHECK_NE(code_size, 0U);
     uint32_t thumb_offset = compiled_method->CodeDelta();
@@ -269,6 +279,7 @@
       offset += code_size;
       oat_header_->UpdateChecksum(&code[0], code_size);
     }
+#endif
     frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
     core_spill_mask = compiled_method->GetCoreSpillMask();
     fp_spill_mask = compiled_method->GetFpSpillMask();
@@ -335,12 +346,16 @@
   }
 
   const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx));
-  const CompiledInvokeStub* compiled_invoke_stub = compiler_driver_->FindInvokeStub(type == kStatic,
-                                                                             shorty);
+  CompiledInvokeStub* compiled_invoke_stub = compiler_driver_->FindInvokeStub(invoke_type == kStatic,
+                                                                              shorty);
   if (compiled_invoke_stub != NULL) {
+#if defined(ART_USE_PORTABLE_COMPILER)
+    compiled_invoke_stub->AddOatdataOffsetToCompliledCodeOffset(
+        oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, invoke_stub_offset_));
+#else
+    const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
     offset = CompiledMethod::AlignCode(offset, compiler_driver_->GetInstructionSet());
     DCHECK_ALIGNED(offset, kArmAlignment);
-    const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
     uint32_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
     CHECK_NE(invoke_stub_size, 0U);
     uint32_t thumb_offset = compiled_invoke_stub->CodeDelta();
@@ -356,35 +371,20 @@
       offset += invoke_stub_size;
       oat_header_->UpdateChecksum(&invoke_stub[0], invoke_stub_size);
     }
+#endif
   }
 
 #if defined(ART_USE_PORTABLE_COMPILER)
-  if (type != kStatic) {
-    const CompiledInvokeStub* compiled_proxy_stub = compiler_driver_->FindProxyStub(shorty);
+  if (invoke_type != kStatic) {
+    CompiledInvokeStub* compiled_proxy_stub = compiler_driver_->FindProxyStub(shorty);
     if (compiled_proxy_stub != NULL) {
-      offset = CompiledMethod::AlignCode(offset, compiler_driver_->GetInstructionSet());
-      DCHECK_ALIGNED(offset, kArmAlignment);
-      const std::vector<uint8_t>& proxy_stub = compiled_proxy_stub->GetCode();
-      uint32_t proxy_stub_size = proxy_stub.size() * sizeof(proxy_stub[0]);
-      CHECK_NE(proxy_stub_size, 0U);
-      uint32_t thumb_offset = compiled_proxy_stub->CodeDelta();
-      proxy_stub_offset = offset + sizeof(proxy_stub_size) + thumb_offset;
-
-      // Deduplicate proxy stubs
-      SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter = code_offsets_.find(&proxy_stub);
-      if (stub_iter != code_offsets_.end()) {
-        proxy_stub_offset = stub_iter->second;
-      } else {
-        code_offsets_.Put(&proxy_stub, proxy_stub_offset);
-        offset += sizeof(proxy_stub_size);  // proxy stub size is prepended before code
-        offset += proxy_stub_size;
-        oat_header_->UpdateChecksum(&proxy_stub[0], proxy_stub_size);
-      }
+      compiled_proxy_stub->AddOatdataOffsetToCompliledCodeOffset(
+          oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, proxy_stub_offset_));
     }
   }
 #endif
 
-  oat_classes_[oat_class_index]->method_offsets_[class_def_method_index]
+  oat_class->method_offsets_[class_def_method_index]
       = OatMethodOffsets(code_offset,
                          frame_size_in_bytes,
                          core_spill_mask,
@@ -404,7 +404,7 @@
     // Unchecked as we hold mutator_lock_ on entry.
     ScopedObjectAccessUnchecked soa(Thread::Current());
     mirror::AbstractMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache,
-                                                           NULL, NULL, type);
+                                                           NULL, NULL, invoke_type);
     CHECK(method != NULL);
     method->SetFrameSizeInBytes(frame_size_in_bytes);
     method->SetCoreSpillMask(core_spill_mask);
@@ -425,8 +425,11 @@
   return offset;
 }
 
-#define DCHECK_CODE_OFFSET() \
-  DCHECK_EQ(static_cast<off_t>(code_offset), out.Seek(0, kSeekCurrent))
+#define DCHECK_OFFSET() \
+  DCHECK_EQ(static_cast<off_t>(offset), out.Seek(0, kSeekCurrent))
+
+#define DCHECK_OFFSET_() \
+  DCHECK_EQ(static_cast<off_t>(offset_), out.Seek(0, kSeekCurrent))
 
 bool OatWriter::Write(OutputStream& out) {
   if (!out.WriteFully(oat_header_, sizeof(*oat_header_))) {
@@ -491,15 +494,15 @@
 }
 
 size_t OatWriter::WriteCode(OutputStream& out) {
-  uint32_t code_offset = oat_header_->GetExecutableOffset();
+  uint32_t offset = oat_header_->GetExecutableOffset();
   off_t new_offset = out.Seek(executable_offset_padding_length_, kSeekCurrent);
-  if (static_cast<uint32_t>(new_offset) != code_offset) {
+  if (static_cast<uint32_t>(new_offset) != offset) {
     PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
-                << " Expected: " << code_offset << " File: " << out.GetLocation();
+                << " Expected: " << offset << " File: " << out.GetLocation();
     return 0;
   }
-  DCHECK_CODE_OFFSET();
-  return code_offset;
+  DCHECK_OFFSET();
+  return offset;
 }
 
 size_t OatWriter::WriteCodeDexFiles(OutputStream& out, size_t code_offset) {
@@ -575,7 +578,7 @@
   return code_offset;
 }
 
-size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t code_offset, size_t oat_class_index,
+size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_class_index,
                                   size_t class_def_method_index, bool is_static,
                                   uint32_t method_idx, const DexFile& dex_file) {
   const CompiledMethod* compiled_method =
@@ -586,43 +589,46 @@
 
 
   if (compiled_method != NULL) {  // ie. not an abstract method
-    uint32_t aligned_code_offset = compiled_method->AlignCode(code_offset);
-    uint32_t aligned_code_delta = aligned_code_offset - code_offset;
+#if !defined(ART_USE_PORTABLE_COMPILER)
+    uint32_t aligned_offset = compiled_method->AlignCode(offset);
+    uint32_t aligned_code_delta = aligned_offset - offset;
     if (aligned_code_delta != 0) {
       off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
-      if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
+      if (static_cast<uint32_t>(new_offset) != aligned_offset) {
         PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
-                    << " Expected: " << aligned_code_offset << " File: " << out.GetLocation();
+                    << " Expected: " << aligned_offset << " File: " << out.GetLocation();
         return 0;
       }
-      code_offset += aligned_code_delta;
-      DCHECK_CODE_OFFSET();
+      offset += aligned_code_delta;
+      DCHECK_OFFSET();
     }
-    DCHECK_ALIGNED(code_offset, kArmAlignment);
+    DCHECK_ALIGNED(offset, kArmAlignment);
     const std::vector<uint8_t>& code = compiled_method->GetCode();
     uint32_t code_size = code.size() * sizeof(code[0]);
     CHECK_NE(code_size, 0U);
 
     // Deduplicate code arrays
-    size_t offset = code_offset + sizeof(code_size) + compiled_method->CodeDelta();
+    size_t code_offset = offset + sizeof(code_size) + compiled_method->CodeDelta();
     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
-    if (code_iter != code_offsets_.end() && offset != method_offsets.code_offset_) {
-      DCHECK(code_iter->second == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
+    if (code_iter != code_offsets_.end() && code_offset != method_offsets.code_offset_) {
+      DCHECK(code_iter->second == method_offsets.code_offset_)
+          << PrettyMethod(method_idx, dex_file);
     } else {
-      DCHECK(offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
+      DCHECK(code_offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
       if (!out.WriteFully(&code_size, sizeof(code_size))) {
         ReportWriteFailure("method code size", method_idx, dex_file, out);
         return 0;
       }
-      code_offset += sizeof(code_size);
-      DCHECK_CODE_OFFSET();
+      offset += sizeof(code_size);
+      DCHECK_OFFSET();
       if (!out.WriteFully(&code[0], code_size)) {
         ReportWriteFailure("method code", method_idx, dex_file, out);
         return 0;
       }
-      code_offset += code_size;
+      offset += code_size;
     }
-    DCHECK_CODE_OFFSET();
+    DCHECK_OFFSET();
+#endif
 
     const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
     size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
@@ -631,21 +637,21 @@
     SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter =
         mapping_table_offsets_.find(&mapping_table);
     if (mapping_iter != mapping_table_offsets_.end() &&
-        code_offset != method_offsets.mapping_table_offset_) {
+        offset != method_offsets.mapping_table_offset_) {
       DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
           || mapping_iter->second == method_offsets.mapping_table_offset_)
           << PrettyMethod(method_idx, dex_file);
     } else {
       DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
-          || code_offset == method_offsets.mapping_table_offset_)
+          || offset == method_offsets.mapping_table_offset_)
           << PrettyMethod(method_idx, dex_file);
       if (!out.WriteFully(&mapping_table[0], mapping_table_size)) {
         ReportWriteFailure("mapping table", method_idx, dex_file, out);
         return 0;
       }
-      code_offset += mapping_table_size;
+      offset += mapping_table_size;
     }
-    DCHECK_CODE_OFFSET();
+    DCHECK_OFFSET();
 
     const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
     size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
@@ -654,21 +660,21 @@
     SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter =
         vmap_table_offsets_.find(&vmap_table);
     if (vmap_iter != vmap_table_offsets_.end() &&
-        code_offset != method_offsets.vmap_table_offset_) {
+        offset != method_offsets.vmap_table_offset_) {
       DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
           || vmap_iter->second == method_offsets.vmap_table_offset_)
           << PrettyMethod(method_idx, dex_file);
     } else {
       DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
-          || code_offset == method_offsets.vmap_table_offset_)
+          || offset == method_offsets.vmap_table_offset_)
           << PrettyMethod(method_idx, dex_file);
       if (!out.WriteFully(&vmap_table[0], vmap_table_size)) {
         ReportWriteFailure("vmap table", method_idx, dex_file, out);
         return 0;
       }
-      code_offset += vmap_table_size;
+      offset += vmap_table_size;
     }
-    DCHECK_CODE_OFFSET();
+    DCHECK_OFFSET();
 
     const std::vector<uint8_t>& gc_map = compiled_method->GetNativeGcMap();
     size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
@@ -677,119 +683,76 @@
     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter =
         gc_map_offsets_.find(&gc_map);
     if (gc_map_iter != gc_map_offsets_.end() &&
-        code_offset != method_offsets.gc_map_offset_) {
+        offset != method_offsets.gc_map_offset_) {
       DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
           || gc_map_iter->second == method_offsets.gc_map_offset_)
           << PrettyMethod(method_idx, dex_file);
     } else {
       DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
-          || code_offset == method_offsets.gc_map_offset_)
+          || offset == method_offsets.gc_map_offset_)
           << PrettyMethod(method_idx, dex_file);
       if (!out.WriteFully(&gc_map[0], gc_map_size)) {
         ReportWriteFailure("GC map", method_idx, dex_file, out);
         return 0;
       }
-      code_offset += gc_map_size;
+      offset += gc_map_size;
     }
-    DCHECK_CODE_OFFSET();
+    DCHECK_OFFSET();
   }
+
+#if !defined(ART_USE_PORTABLE_COMPILER)
   const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
   const CompiledInvokeStub* compiled_invoke_stub = compiler_driver_->FindInvokeStub(is_static, shorty);
   if (compiled_invoke_stub != NULL) {
-    uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset,
-                                                             compiler_driver_->GetInstructionSet());
-    uint32_t aligned_code_delta = aligned_code_offset - code_offset;
+    uint32_t aligned_offset = CompiledMethod::AlignCode(offset,
+                                                        compiler_driver_->GetInstructionSet());
+    uint32_t aligned_code_delta = aligned_offset - offset;
     if (aligned_code_delta != 0) {
       off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
-      if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
+      if (static_cast<uint32_t>(new_offset) != aligned_offset) {
         PLOG(ERROR) << "Failed to seek to align invoke stub code. Actual: " << new_offset
-                    << " Expected: " << aligned_code_offset;
+                    << " Expected: " << aligned_offset;
         return 0;
       }
-      code_offset += aligned_code_delta;
-      DCHECK_CODE_OFFSET();
+      offset += aligned_code_delta;
+      DCHECK_OFFSET();
     }
-    DCHECK_ALIGNED(code_offset, kArmAlignment);
+    DCHECK_ALIGNED(offset, kArmAlignment);
     const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
     uint32_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
     CHECK_NE(invoke_stub_size, 0U);
 
     // Deduplicate invoke stubs
-    size_t offset = code_offset + sizeof(invoke_stub_size) + compiled_invoke_stub->CodeDelta();
+    size_t invoke_stub_offset = offset + sizeof(invoke_stub_size) + compiled_invoke_stub->CodeDelta();
     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter =
         code_offsets_.find(&invoke_stub);
-    if (stub_iter != code_offsets_.end() && offset != method_offsets.invoke_stub_offset_) {
-      DCHECK(stub_iter->second == method_offsets.invoke_stub_offset_) << PrettyMethod(method_idx, dex_file);
+    if (stub_iter != code_offsets_.end()
+        && invoke_stub_offset != method_offsets.invoke_stub_offset_) {
+      DCHECK(stub_iter->second == method_offsets.invoke_stub_offset_)
+          << PrettyMethod(method_idx, dex_file);
     } else {
-      DCHECK(offset == method_offsets.invoke_stub_offset_) << PrettyMethod(method_idx, dex_file);
+      DCHECK(invoke_stub_offset == method_offsets.invoke_stub_offset_) << PrettyMethod(method_idx, dex_file);
       if (!out.WriteFully(&invoke_stub_size, sizeof(invoke_stub_size))) {
         ReportWriteFailure("invoke stub code size", method_idx, dex_file, out);
         return 0;
       }
-      code_offset += sizeof(invoke_stub_size);
-      DCHECK_CODE_OFFSET();
+      offset += sizeof(invoke_stub_size);
+      DCHECK_OFFSET();
       if (!out.WriteFully(&invoke_stub[0], invoke_stub_size)) {
         ReportWriteFailure("invoke stub code", method_idx, dex_file, out);
         return 0;
       }
-      code_offset += invoke_stub_size;
-      DCHECK_CODE_OFFSET();
-    }
-  }
-
-#if defined(ART_USE_PORTABLE_COMPILER)
-  if (!is_static) {
-    const CompiledInvokeStub* compiled_proxy_stub = compiler_driver_->FindProxyStub(shorty);
-    if (compiled_proxy_stub != NULL) {
-      uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset,
-                                                               compiler_driver_->GetInstructionSet());
-      uint32_t aligned_code_delta = aligned_code_offset - code_offset;
-      CHECK(aligned_code_delta < 48u);
-      if (aligned_code_delta != 0) {
-        off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
-        if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
-          PLOG(ERROR) << "Failed to seek to align proxy stub code. Actual: " << new_offset
-                      << " Expected: " << aligned_code_offset;
-          return 0;
-        }
-        code_offset += aligned_code_delta;
-        DCHECK_CODE_OFFSET();
-      }
-      DCHECK_ALIGNED(code_offset, kArmAlignment);
-      const std::vector<uint8_t>& proxy_stub = compiled_proxy_stub->GetCode();
-      uint32_t proxy_stub_size = proxy_stub.size() * sizeof(proxy_stub[0]);
-      CHECK_NE(proxy_stub_size, 0U);
-
-      // Deduplicate proxy stubs
-      size_t offset = code_offset + sizeof(proxy_stub_size) + compiled_proxy_stub->CodeDelta();
-      SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter =
-          code_offsets_.find(&proxy_stub);
-      if (stub_iter != code_offsets_.end() && offset != method_offsets.proxy_stub_offset_) {
-        DCHECK(stub_iter->second == method_offsets.proxy_stub_offset_) << PrettyMethod(method_idx, dex_file);
-      } else {
-        DCHECK(offset == method_offsets.proxy_stub_offset_) << PrettyMethod(method_idx, dex_file);
-        if (!out.WriteFully(&proxy_stub_size, sizeof(proxy_stub_size))) {
-          ReportWriteFailure("proxy stub code size", method_idx, dex_file, out);
-          return 0;
-        }
-        code_offset += sizeof(proxy_stub_size);
-        DCHECK_CODE_OFFSET();
-        if (!out.WriteFully(&proxy_stub[0], proxy_stub_size)) {
-          ReportWriteFailure("proxy stub code", method_idx, dex_file, out);
-          return 0;
-        }
-        code_offset += proxy_stub_size;
-        DCHECK_CODE_OFFSET();
-      }
-      DCHECK_CODE_OFFSET();
+      offset += invoke_stub_size;
+      DCHECK_OFFSET();
     }
   }
 #endif
 
-  return code_offset;
+  return offset;
 }
 
-OatWriter::OatDexFile::OatDexFile(const DexFile& dex_file) {
+OatWriter::OatDexFile::OatDexFile(size_t offset, const DexFile& dex_file) {
+  offset_ = offset;
   const std::string& location(dex_file.GetLocation());
   dex_file_location_size_ = location.size();
   dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
@@ -816,6 +779,7 @@
 }
 
 bool OatWriter::OatDexFile::Write(OutputStream& out) const {
+  DCHECK_OFFSET_();
   if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
     PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation();
     return false;
@@ -840,14 +804,25 @@
   return true;
 }
 
-OatWriter::OatClass::OatClass(mirror::Class::Status status, uint32_t methods_count) {
+OatWriter::OatClass::OatClass(size_t offset, mirror::Class::Status status, uint32_t methods_count) {
+  offset_ = offset;
   status_ = status;
   method_offsets_.resize(methods_count);
 }
 
-size_t OatWriter::OatClass::SizeOf() const {
+size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader(
+    size_t class_def_method_index_) const {
+  return offset_ + GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_);
+}
+
+size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatClass(
+    size_t class_def_method_index_) const {
   return sizeof(status_)
-          + (sizeof(method_offsets_[0]) * method_offsets_.size());
+          + (sizeof(method_offsets_[0]) * class_def_method_index_);
+}
+
+size_t OatWriter::OatClass::SizeOf() const {
+  return GetOatMethodOffsetsOffsetFromOatClass(method_offsets_.size());
 }
 
 void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const {
@@ -857,15 +832,20 @@
 }
 
 bool OatWriter::OatClass::Write(OutputStream& out) const {
+  DCHECK_OFFSET_();
   if (!out.WriteFully(&status_, sizeof(status_))) {
     PLOG(ERROR) << "Failed to write class status to " << out.GetLocation();
     return false;
   }
+  DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(0)),
+            out.Seek(0, kSeekCurrent));
   if (!out.WriteFully(&method_offsets_[0],
                       sizeof(method_offsets_[0]) * method_offsets_.size())) {
     PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation();
     return false;
   }
+  DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())),
+            out.Seek(0, kSeekCurrent));
   return true;
 }
 
diff --git a/src/oat_writer.h b/src/oat_writer.h
index f67a3b0..e1d76f4 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -117,11 +117,15 @@
 
   class OatDexFile {
    public:
-    explicit OatDexFile(const DexFile& dex_file);
+    explicit OatDexFile(size_t offset, const DexFile& dex_file);
     size_t SizeOf() const;
     void UpdateChecksum(OatHeader& oat_header) const;
     bool Write(OutputStream& out) const;
 
+    // Offset of start of OatDexFile from beginning of OatHeader. It is
+    // used to validate file position when writing.
+    size_t offset_;
+
     // data to write
     uint32_t dex_file_location_size_;
     const uint8_t* dex_file_location_data_;
@@ -135,11 +139,20 @@
 
   class OatClass {
    public:
-    explicit OatClass(mirror::Class::Status status, uint32_t methods_count);
+    explicit OatClass(size_t offset, mirror::Class::Status status, uint32_t methods_count);
+    size_t GetOatMethodOffsetsOffsetFromOatHeader(size_t class_def_method_index_) const;
+    size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const;
     size_t SizeOf() const;
     void UpdateChecksum(OatHeader& oat_header) const;
     bool Write(OutputStream& out) const;
 
+    // Offset of start of OatClass from beginning of OatHeader. It is
+    // used to validate file position when writing. For Portable, it
+    // is also used to calculate the position of the OatMethodOffsets
+    // so that code pointers within the OatMethodOffsets can be
+    // patched to point to code in the Portable .o ELF objects.
+    size_t offset_;
+
     // data to write
     mirror::Class::Status status_;
     std::vector<OatMethodOffsets> method_offsets_;
diff --git a/src/runtime.cc b/src/runtime.cc
index c74757f..414bef4 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -57,10 +57,6 @@
 #include "verifier/method_verifier.h"
 #include "well_known_classes.h"
 
-#if defined(ART_USE_PORTABLE_COMPILER)
-#include "compiler/llvm/procedure_linkage_table.h"
-#endif
-
 #include "JniConstants.h" // Last to avoid LOG redefinition in ics-mr1-plus-art.
 
 namespace art {
@@ -99,27 +95,13 @@
       instrumentation_(NULL),
       use_compile_time_class_path_(false),
       main_thread_group_(NULL),
-      system_thread_group_(NULL)
-#if defined(ART_USE_PORTABLE_COMPILER)
-#if defined(__arm__)
-    , plt_(kArm)
-#elif defined(__mips__)
-    , plt_(kMips)
-#elif defined(__i386__)
-    , plt_(kX86)
-#endif
-#endif
-      {
+      system_thread_group_(NULL) {
   for (int i = 0; i < Runtime::kLastTrampolineMethodType; i++) {
     resolution_stub_array_[i] = NULL;
   }
   for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
     callee_save_methods_[i] = NULL;
   }
-
-#if defined(ART_USE_PORTABLE_COMPILER)
-  CHECK(plt_.AllocateTable()) << "Failed to allocate PLT";
-#endif
 }
 
 Runtime::~Runtime() {
diff --git a/src/runtime.h b/src/runtime.h
index 411d618..696f231 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -36,10 +36,6 @@
 #include "runtime_stats.h"
 #include "safe_map.h"
 
-#if defined(ART_USE_PORTABLE_COMPILER)
-#include "compiler/llvm/procedure_linkage_table.h"
-#endif
-
 namespace art {
 
 namespace mirror {
@@ -477,9 +473,6 @@
 
   jobject main_thread_group_;
   jobject system_thread_group_;
-#if defined(ART_USE_PORTABLE_COMPILER)
-  art::llvm::ProcedureLinkageTable plt_;
-#endif
 
   DISALLOW_COPY_AND_ASSIGN(Runtime);
 };
diff --git a/test/etc/host-run-test-jar b/test/etc/host-run-test-jar
index c130521..c0c5e12 100755
--- a/test/etc/host-run-test-jar
+++ b/test/etc/host-run-test-jar
@@ -88,7 +88,7 @@
 
 if [ "$GDB" = "y" ]; then
     gdb=gdb
-    gdbargs="--args $exe"
+    gdbargs="--annotate=3 --args $exe"
 fi
 
 if [ "$INTERPRETER" = "y" ]; then