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