blob: 8e19ef6195008c3ab26a8fbbb284e237a9148de0 [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"
Brian Carlstromea46f952013-07-30 01:26:50 -070036#include "mirror/art_method.h"
37#include "mirror/art_method-inl.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070038#include "mirror/object-inl.h"
Brian Carlstromc50d8e12013-07-23 22:35:16 -070039#include "oat_writer.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070040#include "scoped_thread_state_change.h"
Brian Carlstromc50d8e12013-07-23 22:35:16 -070041#include "vector_output_stream.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070042
43namespace art {
44
45ElfWriterMclinker::ElfWriterMclinker(const CompilerDriver& driver, File* elf_file)
46 : ElfWriter(driver, elf_file), oat_input_(NULL) {}
47
48ElfWriterMclinker::~ElfWriterMclinker() {}
49
50bool ElfWriterMclinker::Create(File* elf_file,
Brian Carlstromc50d8e12013-07-23 22:35:16 -070051 OatWriter& oat_writer,
Brian Carlstrom7940e442013-07-12 13:46:57 -070052 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);
Brian Carlstromc50d8e12013-07-23 22:35:16 -070057 return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
Brian Carlstrom7940e442013-07-12 13:46:57 -070058}
59
Brian Carlstromc50d8e12013-07-23 22:35:16 -070060bool ElfWriterMclinker::Write(OatWriter& oat_writer,
Brian Carlstrom7940e442013-07-12 13:46:57 -070061 const std::vector<const DexFile*>& dex_files,
62 const std::string& android_root,
63 bool is_host) {
Brian Carlstromc50d8e12013-07-23 22:35:16 -070064 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
Brian Carlstrom7940e442013-07-12 13:46:57 -070070 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 }
Brian Carlstromc50d8e12013-07-23 22:35:16 -070079 oat_contents.clear();
Brian Carlstrom7940e442013-07-12 13:46:57 -070080#if defined(ART_USE_PORTABLE_COMPILER)
81 FixupOatMethodOffsets(dex_files);
82#endif
83 return true;
84}
85
86static 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
97void 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
154void ElfWriterMclinker::AddOatInput(std::vector<uint8_t>& oat_contents) {
155 // Add an artificial memory input. Based on LinkerTest.
Ian Rogers8584a682013-10-24 11:48:02 -0700156 std::string error_msg;
157 UniquePtr<OatFile> oat_file(OatFile::OpenMemory(oat_contents, elf_file_->GetPath(), &error_msg));
158 CHECK(oat_file.get() != NULL) << elf_file_->GetPath() << ": " << error_msg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700159
160 const char* oat_data_start = reinterpret_cast<const char*>(&oat_file->GetOatHeader());
161 const size_t oat_data_length = oat_file->GetOatHeader().GetExecutableOffset();
162 const char* oat_code_start = oat_data_start + oat_data_length;
163 const size_t oat_code_length = oat_file->Size() - oat_data_length;
164
165 // TODO: ownership of oat_input?
166 oat_input_ = ir_builder_->CreateInput("oat contents",
167 mcld::sys::fs::Path("oat contents path"),
168 mcld::Input::Object);
169 CHECK(oat_input_ != NULL);
170
171 // TODO: ownership of null_section?
172 mcld::LDSection* null_section = ir_builder_->CreateELFHeader(*oat_input_,
173 "",
174 mcld::LDFileFormat::Null,
175 llvm::ELF::SHT_NULL,
176 0);
177 CHECK(null_section != NULL);
178
179 // TODO: we should split readonly data from readonly executable
180 // code like .oat does. We need to control section layout with
181 // linker script like functionality to guarantee references
182 // between sections maintain relative position which isn't
183 // possible right now with the mclinker APIs.
184 CHECK(oat_code_start != NULL);
185
186 // we need to ensure that oatdata is page aligned so when we
187 // fixup the segment load addresses, they remain page aligned.
188 uint32_t alignment = kPageSize;
189
190 // TODO: ownership of text_section?
191 mcld::LDSection* text_section = ir_builder_->CreateELFHeader(*oat_input_,
192 ".text",
193 llvm::ELF::SHT_PROGBITS,
194 llvm::ELF::SHF_EXECINSTR
195 | llvm::ELF::SHF_ALLOC,
196 alignment);
197 CHECK(text_section != NULL);
198
199 mcld::SectionData* text_sectiondata = ir_builder_->CreateSectionData(*text_section);
200 CHECK(text_sectiondata != NULL);
201
202 // TODO: why does IRBuilder::CreateRegion take a non-const pointer?
203 mcld::Fragment* text_fragment = ir_builder_->CreateRegion(const_cast<char*>(oat_data_start),
204 oat_file->Size());
205 CHECK(text_fragment != NULL);
206 ir_builder_->AppendFragment(*text_fragment, *text_sectiondata);
207
208 ir_builder_->AddSymbol(*oat_input_,
209 "oatdata",
210 mcld::ResolveInfo::Object,
211 mcld::ResolveInfo::Define,
212 mcld::ResolveInfo::Global,
213 oat_data_length, // size
214 0, // offset
215 text_section);
216
217 ir_builder_->AddSymbol(*oat_input_,
218 "oatexec",
219 mcld::ResolveInfo::Function,
220 mcld::ResolveInfo::Define,
221 mcld::ResolveInfo::Global,
222 oat_code_length, // size
223 oat_data_length, // offset
224 text_section);
225
226 ir_builder_->AddSymbol(*oat_input_,
227 "oatlastword",
228 mcld::ResolveInfo::Object,
229 mcld::ResolveInfo::Define,
230 mcld::ResolveInfo::Global,
231 0, // size
232 // subtract a word so symbol is within section
233 (oat_data_length + oat_code_length) - sizeof(uint32_t), // offset
234 text_section);
235}
236
237#if defined(ART_USE_PORTABLE_COMPILER)
238void ElfWriterMclinker::AddMethodInputs(const std::vector<const DexFile*>& dex_files) {
239 DCHECK(oat_input_ != NULL);
240
241 DexMethodIterator it(dex_files);
242 while (it.HasNext()) {
243 const DexFile& dex_file = it.GetDexFile();
244 uint32_t method_idx = it.GetMemberIndex();
245 const CompiledMethod* compiled_method =
246 compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, method_idx));
247 if (compiled_method != NULL) {
248 AddCompiledCodeInput(*compiled_method);
249 }
250 it.Next();
251 }
252 added_symbols_.clear();
253}
254
255void ElfWriterMclinker::AddCompiledCodeInput(const CompiledCode& compiled_code) {
256 // Check if we've seen this compiled code before. If so skip
257 // it. This can happen for reused code such as invoke stubs.
258 const std::string& symbol = compiled_code.GetSymbol();
259 SafeMap<const std::string*, const std::string*>::iterator it = added_symbols_.find(&symbol);
260 if (it != added_symbols_.end()) {
261 return;
262 }
263 added_symbols_.Put(&symbol, &symbol);
264
265 // Add input to supply code for symbol
266 const std::vector<uint8_t>& code = compiled_code.GetCode();
267 // TODO: ownership of code_input?
268 // TODO: why does IRBuilder::ReadInput take a non-const pointer?
269 mcld::Input* code_input = ir_builder_->ReadInput(symbol,
270 const_cast<uint8_t*>(&code[0]),
271 code.size());
272 CHECK(code_input != NULL);
273}
274
275void ElfWriterMclinker::AddRuntimeInputs(const std::string& android_root, bool is_host) {
276 std::string libart_so(android_root);
277 libart_so += kIsDebugBuild ? "/lib/libartd.so" : "/lib/libart.so";
278 // TODO: ownership of libart_so_input?
279 mcld::Input* libart_so_input = ir_builder_->ReadInput(libart_so, libart_so);
280 CHECK(libart_so_input != NULL);
281
282 std::string host_prebuilt_dir("prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6");
283
284 std::string compiler_runtime_lib;
285 if (is_host) {
286 compiler_runtime_lib += host_prebuilt_dir;
287 compiler_runtime_lib += "/lib/gcc/i686-linux/4.6.x-google/libgcc.a";
288 } else {
289 compiler_runtime_lib += android_root;
290 compiler_runtime_lib += "/lib/libcompiler_rt.a";
291 }
292 // TODO: ownership of compiler_runtime_lib_input?
293 mcld::Input* compiler_runtime_lib_input = ir_builder_->ReadInput(compiler_runtime_lib,
294 compiler_runtime_lib);
295 CHECK(compiler_runtime_lib_input != NULL);
296
297 std::string libc_lib;
298 if (is_host) {
299 libc_lib += host_prebuilt_dir;
300 libc_lib += "/sysroot/usr/lib/libc.so.6";
301 } else {
302 libc_lib += android_root;
303 libc_lib += "/lib/libc.so";
304 }
305 // TODO: ownership of libc_lib_input?
306 mcld::Input* libc_lib_input_input = ir_builder_->ReadInput(libc_lib, libc_lib);
307 CHECK(libc_lib_input_input != NULL);
308
309 std::string libm_lib;
310 if (is_host) {
311 libm_lib += host_prebuilt_dir;
312 libm_lib += "/sysroot/usr/lib/libm.so";
313 } else {
314 libm_lib += android_root;
315 libm_lib += "/lib/libm.so";
316 }
317 // TODO: ownership of libm_lib_input?
318 mcld::Input* libm_lib_input_input = ir_builder_->ReadInput(libm_lib, libm_lib);
319 CHECK(libm_lib_input_input != NULL);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700320}
321#endif
322
323bool ElfWriterMclinker::Link() {
324 // link inputs
325 if (!linker_->link(*module_.get(), *ir_builder_.get())) {
326 LOG(ERROR) << "Failed to link " << elf_file_->GetPath();
327 return false;
328 }
329
330 // emit linked output
331 // TODO: avoid dup of fd by fixing Linker::emit to not close the argument fd.
332 int fd = dup(elf_file_->Fd());
333 if (fd == -1) {
334 PLOG(ERROR) << "Failed to dup file descriptor for " << elf_file_->GetPath();
335 return false;
336 }
337 if (!linker_->emit(fd)) {
338 LOG(ERROR) << "Failed to emit " << elf_file_->GetPath();
339 return false;
340 }
341 mcld::Finalize();
342 LOG(INFO) << "ELF file written successfully: " << elf_file_->GetPath();
343 return true;
344}
345
346#if defined(ART_USE_PORTABLE_COMPILER)
347void ElfWriterMclinker::FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files) {
Ian Rogers8584a682013-10-24 11:48:02 -0700348 std::string error_msg;
349 UniquePtr<ElfFile> elf_file(ElfFile::Open(elf_file_, true, false, &error_msg));
350 CHECK(elf_file.get() != NULL) << elf_file_->GetPath() << ": " << error_msg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700351
352 llvm::ELF::Elf32_Addr oatdata_address = GetOatDataAddress(elf_file.get());
353 DexMethodIterator it(dex_files);
354 while (it.HasNext()) {
355 const DexFile& dex_file = it.GetDexFile();
356 uint32_t method_idx = it.GetMemberIndex();
357 InvokeType invoke_type = it.GetInvokeType();
Brian Carlstromea46f952013-07-30 01:26:50 -0700358 mirror::ArtMethod* method = NULL;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700359 if (compiler_driver_->IsImage()) {
360 ClassLinker* linker = Runtime::Current()->GetClassLinker();
361 mirror::DexCache* dex_cache = linker->FindDexCache(dex_file);
362 // Unchecked as we hold mutator_lock_ on entry.
363 ScopedObjectAccessUnchecked soa(Thread::Current());
364 method = linker->ResolveMethod(dex_file, method_idx, dex_cache, NULL, NULL, invoke_type);
365 CHECK(method != NULL);
366 }
367 const CompiledMethod* compiled_method =
368 compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, method_idx));
369 if (compiled_method != NULL) {
370 uint32_t offset = FixupCompiledCodeOffset(*elf_file.get(), oatdata_address, *compiled_method);
371 // Don't overwrite static method trampoline
372 if (method != NULL &&
373 (!method->IsStatic() ||
374 method->IsConstructor() ||
375 method->GetDeclaringClass()->IsInitialized())) {
376 method->SetOatCodeOffset(offset);
377 }
378 }
379 it.Next();
380 }
381 symbol_to_compiled_code_offset_.clear();
382}
383
384uint32_t ElfWriterMclinker::FixupCompiledCodeOffset(ElfFile& elf_file,
385 llvm::ELF::Elf32_Addr oatdata_address,
386 const CompiledCode& compiled_code) {
387 const std::string& symbol = compiled_code.GetSymbol();
388 SafeMap<const std::string*, uint32_t>::iterator it = symbol_to_compiled_code_offset_.find(&symbol);
389 if (it != symbol_to_compiled_code_offset_.end()) {
390 return it->second;
391 }
392
393 llvm::ELF::Elf32_Addr compiled_code_address = elf_file.FindSymbolAddress(llvm::ELF::SHT_SYMTAB,
394 symbol,
395 true);
396 CHECK_NE(0U, compiled_code_address) << symbol;
397 CHECK_LT(oatdata_address, compiled_code_address) << symbol;
398 uint32_t compiled_code_offset = compiled_code_address - oatdata_address;
399 symbol_to_compiled_code_offset_.Put(&symbol, compiled_code_offset);
400
401 const std::vector<uint32_t>& offsets = compiled_code.GetOatdataOffsetsToCompliledCodeOffset();
402 for (uint32_t i = 0; i < offsets.size(); i++) {
403 uint32_t oatdata_offset = oatdata_address + offsets[i];
404 uint32_t* addr = reinterpret_cast<uint32_t*>(elf_file.Begin() + oatdata_offset);
405 *addr = compiled_code_offset;
406 }
407 return compiled_code_offset;
408}
409#endif
410
411} // namespace art