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