diff options
Diffstat (limited to 'compiler/elf_writer_mclinker.cc')
-rw-r--r-- | compiler/elf_writer_mclinker.cc | 411 |
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 |