summaryrefslogtreecommitdiff
path: root/compiler/elf_writer_mclinker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/elf_writer_mclinker.cc')
-rw-r--r--compiler/elf_writer_mclinker.cc411
1 files changed, 0 insertions, 411 deletions
diff --git a/compiler/elf_writer_mclinker.cc b/compiler/elf_writer_mclinker.cc
deleted file mode 100644
index 7705b9cf8a..0000000000
--- a/compiler/elf_writer_mclinker.cc
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "elf_writer_mclinker.h"
-
-#include <llvm/Support/ELF.h>
-#include <llvm/Support/TargetSelect.h>
-
-#include <mcld/Environment.h>
-#include <mcld/IRBuilder.h>
-#include <mcld/Linker.h>
-#include <mcld/LinkerConfig.h>
-#include <mcld/LinkerScript.h>
-#include <mcld/MC/ZOption.h>
-#include <mcld/Module.h>
-#include <mcld/Support/Path.h>
-#include <mcld/Support/TargetSelect.h>
-
-#include "base/unix_file/fd_file.h"
-#include "class_linker.h"
-#include "dex_method_iterator.h"
-#include "driver/compiler_driver.h"
-#include "elf_file.h"
-#include "globals.h"
-#include "mirror/art_method.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/object-inl.h"
-#include "oat_writer.h"
-#include "scoped_thread_state_change.h"
-#include "vector_output_stream.h"
-
-namespace art {
-
-ElfWriterMclinker::ElfWriterMclinker(const CompilerDriver& driver, File* elf_file)
- : ElfWriter(driver, elf_file), oat_input_(nullptr) {
-}
-
-ElfWriterMclinker::~ElfWriterMclinker() {
-}
-
-bool ElfWriterMclinker::Create(File* elf_file,
- OatWriter* oat_writer,
- const std::vector<const DexFile*>& dex_files,
- const std::string& android_root,
- bool is_host,
- const CompilerDriver& driver) {
- ElfWriterMclinker elf_writer(driver, elf_file);
- return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
-}
-
-bool ElfWriterMclinker::Write(OatWriter* oat_writer,
- const std::vector<const DexFile*>& dex_files,
- const std::string& android_root,
- bool is_host) {
- std::vector<uint8_t> oat_contents;
- oat_contents.reserve(oat_writer->GetSize());
-
- Init();
- mcld::LDSection* oat_section = AddOatInput(oat_writer, &oat_contents);
- if (kUsePortableCompiler) {
- AddMethodInputs(dex_files);
- AddRuntimeInputs(android_root, is_host);
- }
-
- // link inputs
- if (!linker_->link(*module_.get(), *ir_builder_.get())) {
- LOG(ERROR) << "Failed to link " << elf_file_->GetPath();
- return false;
- }
-
- // Fill oat_contents.
- VectorOutputStream output_stream("oat contents", &oat_contents);
- oat_writer->SetOatDataOffset(oat_section->offset());
- CHECK(oat_writer->Write(&output_stream));
- CHECK_EQ(oat_writer->GetSize(), oat_contents.size());
-
- // 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(*module_.get(), fd)) {
- LOG(ERROR) << "Failed to emit " << elf_file_->GetPath();
- return false;
- }
- mcld::Finalize();
- LOG(INFO) << "ELF file written successfully: " << elf_file_->GetPath();
-
- oat_contents.clear();
- if (kUsePortableCompiler) {
- FixupOatMethodOffsets(dex_files);
- }
- return true;
-}
-
-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 ElfWriterMclinker::Init() {
- std::string target_triple;
- std::string target_cpu;
- std::string target_attr;
- CompilerDriver::InstructionSetToLLVMTarget(compiler_driver_->GetInstructionSet(),
- &target_triple,
- &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();
-
- 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());
-
- // error on undefined symbols.
- // TODO: should this just be set if kIsDebugBuild?
- linker_config_->options().setNoUndefined(true);
-
- if (compiler_driver_->GetInstructionSet() == kMips) {
- // MCLinker defaults MIPS section alignment to 0x10000, not
- // 0x1000. The ABI says this is because the max page size is
- // general is 64k but that isn't true on Android.
- mcld::ZOption z_option;
- z_option.setKind(mcld::ZOption::MaxPageSize);
- z_option.setPageSize(kPageSize);
- linker_config_->options().addZOption(z_option);
- }
-
- // 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);
- }
-
- // Based on alone::Linker::config
- linker_script_.reset(new mcld::LinkerScript());
- module_.reset(new mcld::Module(linker_config_->options().soname(), *linker_script_.get()));
- 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_->emulate(*linker_script_.get(), *linker_config_.get());
-}
-
-mcld::LDSection* ElfWriterMclinker::AddOatInput(OatWriter* oat_writer,
- std::vector<uint8_t>* oat_contents) {
- // NOTE: oat_contents has sufficient reserved space but it doesn't contain the data yet.
- const char* oat_data_start = reinterpret_cast<const char*>(&(*oat_contents)[0]);
- const size_t oat_data_length = oat_writer->GetOatHeader().GetExecutableOffset();
- const char* oat_code_start = oat_data_start + oat_data_length;
- const size_t oat_code_length = oat_writer->GetSize() - 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,
- 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",
- SHT_PROGBITS,
- SHF_EXECINSTR | 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_writer->GetSize());
- 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);
-
- return text_section;
-}
-
-void ElfWriterMclinker::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();
- const CompiledMethod* compiled_method =
- compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, method_idx));
- if (compiled_method != NULL) {
- AddCompiledCodeInput(*compiled_method);
- }
- it.Next();
- }
- added_symbols_.clear();
-}
-
-void ElfWriterMclinker::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.GetPortableCode();
- // 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 ElfWriterMclinker::AddRuntimeInputs(const std::string& android_root, bool is_host) {
- 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);
-}
-
-void ElfWriterMclinker::FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files) {
- std::string error_msg;
- std::unique_ptr<ElfFile> elf_file(ElfFile::Open(elf_file_, true, false, &error_msg));
- CHECK(elf_file.get() != NULL) << elf_file_->GetPath() << ": " << error_msg;
-
- uint32_t 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();
- mirror::ArtMethod* method = NULL;
- if (compiler_driver_->IsImage()) {
- ClassLinker* linker = Runtime::Current()->GetClassLinker();
- // Unchecked as we hold mutator_lock_ on entry.
- ScopedObjectAccessUnchecked soa(Thread::Current());
- StackHandleScope<1> hs(soa.Self());
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(dex_file)));
- method = linker->ResolveMethod(dex_file, method_idx, dex_cache,
- NullHandle<mirror::ClassLoader>(),
- NullHandle<mirror::ArtMethod>(), invoke_type);
- CHECK(method != NULL);
- }
- const CompiledMethod* compiled_method =
- compiler_driver_->GetCompiledMethod(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->SetPortableOatCodeOffset(offset);
- }
- }
- it.Next();
- }
- symbol_to_compiled_code_offset_.clear();
-}
-
-uint32_t ElfWriterMclinker::FixupCompiledCodeOffset(ElfFile& elf_file,
- 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;
- }
-
- Elf32_Addr compiled_code_address = elf_file.FindSymbolAddress(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;
-}
-
-} // namespace art