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