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