Home | History | Annotate | Download | only in compiler
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "elf_writer_mclinker.h"
     18 
     19 #include <llvm/Support/TargetSelect.h>
     20 
     21 #include <mcld/Environment.h>
     22 #include <mcld/IRBuilder.h>
     23 #include <mcld/Linker.h>
     24 #include <mcld/LinkerConfig.h>
     25 #include <mcld/MC/ZOption.h>
     26 #include <mcld/Module.h>
     27 #include <mcld/Support/Path.h>
     28 #include <mcld/Support/TargetSelect.h>
     29 
     30 #include "base/unix_file/fd_file.h"
     31 #include "class_linker.h"
     32 #include "dex_method_iterator.h"
     33 #include "driver/compiler_driver.h"
     34 #include "elf_file.h"
     35 #include "globals.h"
     36 #include "mirror/art_method.h"
     37 #include "mirror/art_method-inl.h"
     38 #include "mirror/object-inl.h"
     39 #include "oat_writer.h"
     40 #include "scoped_thread_state_change.h"
     41 #include "vector_output_stream.h"
     42 
     43 namespace art {
     44 
     45 ElfWriterMclinker::ElfWriterMclinker(const CompilerDriver& driver, File* elf_file)
     46   : ElfWriter(driver, elf_file), oat_input_(NULL) {}
     47 
     48 ElfWriterMclinker::~ElfWriterMclinker() {}
     49 
     50 bool ElfWriterMclinker::Create(File* elf_file,
     51                                OatWriter& oat_writer,
     52                                const std::vector<const DexFile*>& dex_files,
     53                                const std::string& android_root,
     54                                bool is_host,
     55                                const CompilerDriver& driver) {
     56   ElfWriterMclinker elf_writer(driver, elf_file);
     57   return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
     58 }
     59 
     60 bool ElfWriterMclinker::Write(OatWriter& oat_writer,
     61                               const std::vector<const DexFile*>& dex_files,
     62                               const std::string& android_root,
     63                               bool is_host) {
     64   std::vector<uint8_t> oat_contents;
     65   oat_contents.reserve(oat_writer.GetSize());
     66   VectorOutputStream output_stream("oat contents", oat_contents);
     67   CHECK(oat_writer.Write(output_stream));
     68   CHECK_EQ(oat_writer.GetSize(), oat_contents.size());
     69 
     70   Init();
     71   AddOatInput(oat_contents);
     72 #if defined(ART_USE_PORTABLE_COMPILER)
     73   AddMethodInputs(dex_files);
     74   AddRuntimeInputs(android_root, is_host);
     75 #endif
     76   if (!Link()) {
     77     return false;
     78   }
     79   oat_contents.clear();
     80 #if defined(ART_USE_PORTABLE_COMPILER)
     81   FixupOatMethodOffsets(dex_files);
     82 #endif
     83   return true;
     84 }
     85 
     86 static void InitializeLLVM() {
     87   // TODO: this is lifted from art's compiler_llvm.cc, should be factored out
     88   if (kIsTargetBuild) {
     89     llvm::InitializeNativeTarget();
     90     // TODO: odd that there is no InitializeNativeTargetMC?
     91   } else {
     92     llvm::InitializeAllTargets();
     93     llvm::InitializeAllTargetMCs();
     94   }
     95 }
     96 
     97 void ElfWriterMclinker::Init() {
     98   std::string target_triple;
     99   std::string target_cpu;
    100   std::string target_attr;
    101   CompilerDriver::InstructionSetToLLVMTarget(compiler_driver_->GetInstructionSet(),
    102                                              target_triple,
    103                                              target_cpu,
    104                                              target_attr);
    105 
    106   // Based on mclinker's llvm-mcld.cpp main() and LinkerTest
    107   //
    108   // TODO: LinkerTest uses mcld::Initialize(), but it does an
    109   // llvm::InitializeAllTargets, which we don't want. Basically we
    110   // want mcld::InitializeNative, but it doesn't exist yet, so we
    111   // inline the minimal we need here.
    112   InitializeLLVM();
    113   mcld::InitializeAllTargets();
    114   mcld::InitializeAllLinkers();
    115   mcld::InitializeAllEmulations();
    116   mcld::InitializeAllDiagnostics();
    117 
    118   linker_config_.reset(new mcld::LinkerConfig(target_triple));
    119   CHECK(linker_config_.get() != NULL);
    120   linker_config_->setCodeGenType(mcld::LinkerConfig::DynObj);
    121   linker_config_->options().setSOName(elf_file_->GetPath());
    122 
    123   // error on undefined symbols.
    124   // TODO: should this just be set if kIsDebugBuild?
    125   linker_config_->options().setNoUndefined(true);
    126 
    127   if (compiler_driver_->GetInstructionSet() == kMips) {
    128      // MCLinker defaults MIPS section alignment to 0x10000, not
    129      // 0x1000.  The ABI says this is because the max page size is
    130      // general is 64k but that isn't true on Android.
    131      mcld::ZOption z_option;
    132      z_option.setKind(mcld::ZOption::MaxPageSize);
    133      z_option.setPageSize(kPageSize);
    134      linker_config_->options().addZOption(z_option);
    135   }
    136 
    137   // TODO: Wire up mcld DiagnosticEngine to LOG?
    138   linker_config_->options().setColor(false);
    139   if (false) {
    140     // enables some tracing of input file processing
    141     linker_config_->options().setTrace(true);
    142   }
    143 
    144   // Based on alone::Linker::config
    145   module_.reset(new mcld::Module(linker_config_->options().soname()));
    146   CHECK(module_.get() != NULL);
    147   ir_builder_.reset(new mcld::IRBuilder(*module_.get(), *linker_config_.get()));
    148   CHECK(ir_builder_.get() != NULL);
    149   linker_.reset(new mcld::Linker());
    150   CHECK(linker_.get() != NULL);
    151   linker_->config(*linker_config_.get());
    152 }
    153 
    154 void ElfWriterMclinker::AddOatInput(std::vector<uint8_t>& oat_contents) {
    155   // Add an artificial memory input. Based on LinkerTest.
    156   UniquePtr<OatFile> oat_file(OatFile::OpenMemory(oat_contents, elf_file_->GetPath()));
    157   CHECK(oat_file.get() != NULL) << elf_file_->GetPath();
    158 
    159   const char* oat_data_start = reinterpret_cast<const char*>(&oat_file->GetOatHeader());
    160   const size_t oat_data_length = oat_file->GetOatHeader().GetExecutableOffset();
    161   const char* oat_code_start = oat_data_start + oat_data_length;
    162   const size_t oat_code_length = oat_file->Size() - oat_data_length;
    163 
    164   // TODO: ownership of oat_input?
    165   oat_input_ = ir_builder_->CreateInput("oat contents",
    166                                         mcld::sys::fs::Path("oat contents path"),
    167                                         mcld::Input::Object);
    168   CHECK(oat_input_ != NULL);
    169 
    170   // TODO: ownership of null_section?
    171   mcld::LDSection* null_section = ir_builder_->CreateELFHeader(*oat_input_,
    172                                                                "",
    173                                                                mcld::LDFileFormat::Null,
    174                                                                llvm::ELF::SHT_NULL,
    175                                                                0);
    176   CHECK(null_section != NULL);
    177 
    178   // TODO: we should split readonly data from readonly executable
    179   // code like .oat does.  We need to control section layout with
    180   // linker script like functionality to guarantee references
    181   // between sections maintain relative position which isn't
    182   // possible right now with the mclinker APIs.
    183   CHECK(oat_code_start != NULL);
    184 
    185   // we need to ensure that oatdata is page aligned so when we
    186   // fixup the segment load addresses, they remain page aligned.
    187   uint32_t alignment = kPageSize;
    188 
    189   // TODO: ownership of text_section?
    190   mcld::LDSection* text_section = ir_builder_->CreateELFHeader(*oat_input_,
    191                                                                ".text",
    192                                                                llvm::ELF::SHT_PROGBITS,
    193                                                                llvm::ELF::SHF_EXECINSTR
    194                                                                | llvm::ELF::SHF_ALLOC,
    195                                                                alignment);
    196   CHECK(text_section != NULL);
    197 
    198   mcld::SectionData* text_sectiondata = ir_builder_->CreateSectionData(*text_section);
    199   CHECK(text_sectiondata != NULL);
    200 
    201   // TODO: why does IRBuilder::CreateRegion take a non-const pointer?
    202   mcld::Fragment* text_fragment = ir_builder_->CreateRegion(const_cast<char*>(oat_data_start),
    203                                                             oat_file->Size());
    204   CHECK(text_fragment != NULL);
    205   ir_builder_->AppendFragment(*text_fragment, *text_sectiondata);
    206 
    207   ir_builder_->AddSymbol(*oat_input_,
    208                          "oatdata",
    209                          mcld::ResolveInfo::Object,
    210                          mcld::ResolveInfo::Define,
    211                          mcld::ResolveInfo::Global,
    212                          oat_data_length,  // size
    213                          0,                // offset
    214                          text_section);
    215 
    216   ir_builder_->AddSymbol(*oat_input_,
    217                          "oatexec",
    218                          mcld::ResolveInfo::Function,
    219                          mcld::ResolveInfo::Define,
    220                          mcld::ResolveInfo::Global,
    221                          oat_code_length,  // size
    222                          oat_data_length,  // offset
    223                          text_section);
    224 
    225   ir_builder_->AddSymbol(*oat_input_,
    226                          "oatlastword",
    227                          mcld::ResolveInfo::Object,
    228                          mcld::ResolveInfo::Define,
    229                          mcld::ResolveInfo::Global,
    230                          0,                // size
    231                          // subtract a word so symbol is within section
    232                          (oat_data_length + oat_code_length) - sizeof(uint32_t),  // offset
    233                          text_section);
    234 }
    235 
    236 #if defined(ART_USE_PORTABLE_COMPILER)
    237 void ElfWriterMclinker::AddMethodInputs(const std::vector<const DexFile*>& dex_files) {
    238   DCHECK(oat_input_ != NULL);
    239 
    240   DexMethodIterator it(dex_files);
    241   while (it.HasNext()) {
    242     const DexFile& dex_file = it.GetDexFile();
    243     uint32_t method_idx = it.GetMemberIndex();
    244     const CompiledMethod* compiled_method =
    245       compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, method_idx));
    246     if (compiled_method != NULL) {
    247       AddCompiledCodeInput(*compiled_method);
    248     }
    249     it.Next();
    250   }
    251   added_symbols_.clear();
    252 }
    253 
    254 void ElfWriterMclinker::AddCompiledCodeInput(const CompiledCode& compiled_code) {
    255   // Check if we've seen this compiled code before. If so skip
    256   // it. This can happen for reused code such as invoke stubs.
    257   const std::string& symbol = compiled_code.GetSymbol();
    258   SafeMap<const std::string*, const std::string*>::iterator it = added_symbols_.find(&symbol);
    259   if (it != added_symbols_.end()) {
    260     return;
    261   }
    262   added_symbols_.Put(&symbol, &symbol);
    263 
    264   // Add input to supply code for symbol
    265   const std::vector<uint8_t>& code = compiled_code.GetCode();
    266   // TODO: ownership of code_input?
    267   // TODO: why does IRBuilder::ReadInput take a non-const pointer?
    268   mcld::Input* code_input = ir_builder_->ReadInput(symbol,
    269                                                    const_cast<uint8_t*>(&code[0]),
    270                                                    code.size());
    271   CHECK(code_input != NULL);
    272 }
    273 
    274 void ElfWriterMclinker::AddRuntimeInputs(const std::string& android_root, bool is_host) {
    275   std::string libart_so(android_root);
    276   libart_so += kIsDebugBuild ? "/lib/libartd.so" : "/lib/libart.so";
    277   // TODO: ownership of libart_so_input?
    278   mcld::Input* libart_so_input = ir_builder_->ReadInput(libart_so, libart_so);
    279   CHECK(libart_so_input != NULL);
    280 
    281   std::string host_prebuilt_dir("prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6");
    282 
    283   std::string compiler_runtime_lib;
    284   if (is_host) {
    285     compiler_runtime_lib += host_prebuilt_dir;
    286     compiler_runtime_lib += "/lib/gcc/i686-linux/4.6.x-google/libgcc.a";
    287   } else {
    288     compiler_runtime_lib += android_root;
    289     compiler_runtime_lib += "/lib/libcompiler_rt.a";
    290   }
    291   // TODO: ownership of compiler_runtime_lib_input?
    292   mcld::Input* compiler_runtime_lib_input = ir_builder_->ReadInput(compiler_runtime_lib,
    293                                                                    compiler_runtime_lib);
    294   CHECK(compiler_runtime_lib_input != NULL);
    295 
    296   std::string libc_lib;
    297   if (is_host) {
    298     libc_lib += host_prebuilt_dir;
    299     libc_lib += "/sysroot/usr/lib/libc.so.6";
    300   } else {
    301     libc_lib += android_root;
    302     libc_lib += "/lib/libc.so";
    303   }
    304   // TODO: ownership of libc_lib_input?
    305   mcld::Input* libc_lib_input_input = ir_builder_->ReadInput(libc_lib, libc_lib);
    306   CHECK(libc_lib_input_input != NULL);
    307 
    308   std::string libm_lib;
    309   if (is_host) {
    310     libm_lib += host_prebuilt_dir;
    311     libm_lib += "/sysroot/usr/lib/libm.so";
    312   } else {
    313     libm_lib += android_root;
    314     libm_lib += "/lib/libm.so";
    315   }
    316   // TODO: ownership of libm_lib_input?
    317   mcld::Input* libm_lib_input_input = ir_builder_->ReadInput(libm_lib, libm_lib);
    318   CHECK(libm_lib_input_input != NULL);
    319 }
    320 #endif
    321 
    322 bool ElfWriterMclinker::Link() {
    323   // link inputs
    324   if (!linker_->link(*module_.get(), *ir_builder_.get())) {
    325     LOG(ERROR) << "Failed to link " << elf_file_->GetPath();
    326     return false;
    327   }
    328 
    329   // emit linked output
    330   // TODO: avoid dup of fd by fixing Linker::emit to not close the argument fd.
    331   int fd = dup(elf_file_->Fd());
    332   if (fd == -1) {
    333     PLOG(ERROR) << "Failed to dup file descriptor for " << elf_file_->GetPath();
    334     return false;
    335   }
    336   if (!linker_->emit(fd)) {
    337     LOG(ERROR) << "Failed to emit " << elf_file_->GetPath();
    338     return false;
    339   }
    340   mcld::Finalize();
    341   LOG(INFO) << "ELF file written successfully: " << elf_file_->GetPath();
    342   return true;
    343 }
    344 
    345 #if defined(ART_USE_PORTABLE_COMPILER)
    346 void ElfWriterMclinker::FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files) {
    347   UniquePtr<ElfFile> elf_file(ElfFile::Open(elf_file_, true, false));
    348   CHECK(elf_file.get() != NULL) << elf_file_->GetPath();
    349 
    350   llvm::ELF::Elf32_Addr oatdata_address = GetOatDataAddress(elf_file.get());
    351   DexMethodIterator it(dex_files);
    352   while (it.HasNext()) {
    353     const DexFile& dex_file = it.GetDexFile();
    354     uint32_t method_idx = it.GetMemberIndex();
    355     InvokeType invoke_type = it.GetInvokeType();
    356     mirror::ArtMethod* method = NULL;
    357     if (compiler_driver_->IsImage()) {
    358       ClassLinker* linker = Runtime::Current()->GetClassLinker();
    359       mirror::DexCache* dex_cache = linker->FindDexCache(dex_file);
    360       // Unchecked as we hold mutator_lock_ on entry.
    361       ScopedObjectAccessUnchecked soa(Thread::Current());
    362       method = linker->ResolveMethod(dex_file, method_idx, dex_cache, NULL, NULL, invoke_type);
    363       CHECK(method != NULL);
    364     }
    365     const CompiledMethod* compiled_method =
    366       compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, method_idx));
    367     if (compiled_method != NULL) {
    368       uint32_t offset = FixupCompiledCodeOffset(*elf_file.get(), oatdata_address, *compiled_method);
    369       // Don't overwrite static method trampoline
    370       if (method != NULL &&
    371           (!method->IsStatic() ||
    372            method->IsConstructor() ||
    373            method->GetDeclaringClass()->IsInitialized())) {
    374         method->SetOatCodeOffset(offset);
    375       }
    376     }
    377     it.Next();
    378   }
    379   symbol_to_compiled_code_offset_.clear();
    380 }
    381 
    382 uint32_t ElfWriterMclinker::FixupCompiledCodeOffset(ElfFile& elf_file,
    383                                                     llvm::ELF::Elf32_Addr oatdata_address,
    384                                                     const CompiledCode& compiled_code) {
    385   const std::string& symbol = compiled_code.GetSymbol();
    386   SafeMap<const std::string*, uint32_t>::iterator it = symbol_to_compiled_code_offset_.find(&symbol);
    387   if (it != symbol_to_compiled_code_offset_.end()) {
    388     return it->second;
    389   }
    390 
    391   llvm::ELF::Elf32_Addr compiled_code_address = elf_file.FindSymbolAddress(llvm::ELF::SHT_SYMTAB,
    392                                                                            symbol,
    393                                                                            true);
    394   CHECK_NE(0U, compiled_code_address) << symbol;
    395   CHECK_LT(oatdata_address, compiled_code_address) << symbol;
    396   uint32_t compiled_code_offset = compiled_code_address - oatdata_address;
    397   symbol_to_compiled_code_offset_.Put(&symbol, compiled_code_offset);
    398 
    399   const std::vector<uint32_t>& offsets = compiled_code.GetOatdataOffsetsToCompliledCodeOffset();
    400   for (uint32_t i = 0; i < offsets.size(); i++) {
    401     uint32_t oatdata_offset = oatdata_address + offsets[i];
    402     uint32_t* addr = reinterpret_cast<uint32_t*>(elf_file.Begin() + oatdata_offset);
    403     *addr = compiled_code_offset;
    404   }
    405   return compiled_code_offset;
    406 }
    407 #endif
    408 
    409 }  // namespace art
    410