blob: 7705b9cf8a03785eca151e8a048a10522c80a706 [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
Ian Rogers3d504072014-03-01 09:16:49 -080019#include <llvm/Support/ELF.h>
Brian Carlstrom7940e442013-07-12 13:46:57 -070020#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>
Brian Carlstrom4e3b2842014-01-18 11:26:51 -080026#include <mcld/LinkerScript.h>
Brian Carlstrom7940e442013-07-12 13:46:57 -070027#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"
Nicolas Geoffrayf2b39562014-03-03 15:54:42 +000036#include "elf_file.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070037#include "globals.h"
Brian Carlstromea46f952013-07-30 01:26:50 -070038#include "mirror/art_method.h"
39#include "mirror/art_method-inl.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070040#include "mirror/object-inl.h"
Brian Carlstromc50d8e12013-07-23 22:35:16 -070041#include "oat_writer.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070042#include "scoped_thread_state_change.h"
Brian Carlstromc50d8e12013-07-23 22:35:16 -070043#include "vector_output_stream.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070044
45namespace art {
46
47ElfWriterMclinker::ElfWriterMclinker(const CompilerDriver& driver, File* elf_file)
Ian Rogers3d504072014-03-01 09:16:49 -080048 : ElfWriter(driver, elf_file), oat_input_(nullptr) {
49}
Brian Carlstrom7940e442013-07-12 13:46:57 -070050
Ian Rogers3d504072014-03-01 09:16:49 -080051ElfWriterMclinker::~ElfWriterMclinker() {
52}
Brian Carlstrom7940e442013-07-12 13:46:57 -070053
54bool ElfWriterMclinker::Create(File* elf_file,
Ian Rogers3d504072014-03-01 09:16:49 -080055 OatWriter* oat_writer,
Brian Carlstrom7940e442013-07-12 13:46:57 -070056 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);
Brian Carlstromc50d8e12013-07-23 22:35:16 -070061 return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
Brian Carlstrom7940e442013-07-12 13:46:57 -070062}
63
Ian Rogers3d504072014-03-01 09:16:49 -080064bool ElfWriterMclinker::Write(OatWriter* oat_writer,
Brian Carlstrom7940e442013-07-12 13:46:57 -070065 const std::vector<const DexFile*>& dex_files,
66 const std::string& android_root,
67 bool is_host) {
Brian Carlstromc50d8e12013-07-23 22:35:16 -070068 std::vector<uint8_t> oat_contents;
Ian Rogers3d504072014-03-01 09:16:49 -080069 oat_contents.reserve(oat_writer->GetSize());
Brian Carlstromc50d8e12013-07-23 22:35:16 -070070
Brian Carlstrom7940e442013-07-12 13:46:57 -070071 Init();
Vladimir Markof4da6752014-08-01 19:04:18 +010072 mcld::LDSection* oat_section = AddOatInput(oat_writer, &oat_contents);
Ian Rogers3d504072014-03-01 09:16:49 -080073 if (kUsePortableCompiler) {
74 AddMethodInputs(dex_files);
75 AddRuntimeInputs(android_root, is_host);
76 }
Vladimir Markof4da6752014-08-01 19:04:18 +010077
78 // link inputs
79 if (!linker_->link(*module_.get(), *ir_builder_.get())) {
80 LOG(ERROR) << "Failed to link " << elf_file_->GetPath();
Brian Carlstrom7940e442013-07-12 13:46:57 -070081 return false;
82 }
Vladimir Markof4da6752014-08-01 19:04:18 +010083
84 // Fill oat_contents.
Ian Rogers0279ebb2014-10-08 17:27:48 -070085 VectorOutputStream output_stream("oat contents", &oat_contents);
Vladimir Markof4da6752014-08-01 19:04:18 +010086 oat_writer->SetOatDataOffset(oat_section->offset());
87 CHECK(oat_writer->Write(&output_stream));
88 CHECK_EQ(oat_writer->GetSize(), oat_contents.size());
89
90 // emit linked output
91 // TODO: avoid dup of fd by fixing Linker::emit to not close the argument fd.
92 int fd = dup(elf_file_->Fd());
93 if (fd == -1) {
94 PLOG(ERROR) << "Failed to dup file descriptor for " << elf_file_->GetPath();
95 return false;
96 }
97 if (!linker_->emit(*module_.get(), fd)) {
98 LOG(ERROR) << "Failed to emit " << elf_file_->GetPath();
99 return false;
100 }
101 mcld::Finalize();
102 LOG(INFO) << "ELF file written successfully: " << elf_file_->GetPath();
103
Brian Carlstromc50d8e12013-07-23 22:35:16 -0700104 oat_contents.clear();
Ian Rogers3d504072014-03-01 09:16:49 -0800105 if (kUsePortableCompiler) {
106 FixupOatMethodOffsets(dex_files);
107 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700108 return true;
109}
110
111static void InitializeLLVM() {
112 // TODO: this is lifted from art's compiler_llvm.cc, should be factored out
113 if (kIsTargetBuild) {
114 llvm::InitializeNativeTarget();
115 // TODO: odd that there is no InitializeNativeTargetMC?
116 } else {
117 llvm::InitializeAllTargets();
118 llvm::InitializeAllTargetMCs();
119 }
120}
121
122void ElfWriterMclinker::Init() {
123 std::string target_triple;
124 std::string target_cpu;
125 std::string target_attr;
126 CompilerDriver::InstructionSetToLLVMTarget(compiler_driver_->GetInstructionSet(),
Ian Rogers3d504072014-03-01 09:16:49 -0800127 &target_triple,
128 &target_cpu,
129 &target_attr);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700130
131 // Based on mclinker's llvm-mcld.cpp main() and LinkerTest
132 //
133 // TODO: LinkerTest uses mcld::Initialize(), but it does an
134 // llvm::InitializeAllTargets, which we don't want. Basically we
135 // want mcld::InitializeNative, but it doesn't exist yet, so we
136 // inline the minimal we need here.
137 InitializeLLVM();
138 mcld::InitializeAllTargets();
139 mcld::InitializeAllLinkers();
140 mcld::InitializeAllEmulations();
141 mcld::InitializeAllDiagnostics();
142
143 linker_config_.reset(new mcld::LinkerConfig(target_triple));
144 CHECK(linker_config_.get() != NULL);
145 linker_config_->setCodeGenType(mcld::LinkerConfig::DynObj);
146 linker_config_->options().setSOName(elf_file_->GetPath());
147
148 // error on undefined symbols.
149 // TODO: should this just be set if kIsDebugBuild?
150 linker_config_->options().setNoUndefined(true);
151
152 if (compiler_driver_->GetInstructionSet() == kMips) {
153 // MCLinker defaults MIPS section alignment to 0x10000, not
154 // 0x1000. The ABI says this is because the max page size is
155 // general is 64k but that isn't true on Android.
156 mcld::ZOption z_option;
157 z_option.setKind(mcld::ZOption::MaxPageSize);
158 z_option.setPageSize(kPageSize);
159 linker_config_->options().addZOption(z_option);
160 }
161
162 // TODO: Wire up mcld DiagnosticEngine to LOG?
163 linker_config_->options().setColor(false);
164 if (false) {
165 // enables some tracing of input file processing
166 linker_config_->options().setTrace(true);
167 }
168
169 // Based on alone::Linker::config
Brian Carlstrom4e3b2842014-01-18 11:26:51 -0800170 linker_script_.reset(new mcld::LinkerScript());
171 module_.reset(new mcld::Module(linker_config_->options().soname(), *linker_script_.get()));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700172 CHECK(module_.get() != NULL);
173 ir_builder_.reset(new mcld::IRBuilder(*module_.get(), *linker_config_.get()));
174 CHECK(ir_builder_.get() != NULL);
175 linker_.reset(new mcld::Linker());
176 CHECK(linker_.get() != NULL);
Brian Carlstrom4e3b2842014-01-18 11:26:51 -0800177 linker_->emulate(*linker_script_.get(), *linker_config_.get());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700178}
179
Vladimir Markof4da6752014-08-01 19:04:18 +0100180mcld::LDSection* ElfWriterMclinker::AddOatInput(OatWriter* oat_writer,
181 std::vector<uint8_t>* oat_contents) {
182 // NOTE: oat_contents has sufficient reserved space but it doesn't contain the data yet.
183 const char* oat_data_start = reinterpret_cast<const char*>(&(*oat_contents)[0]);
184 const size_t oat_data_length = oat_writer->GetOatHeader().GetExecutableOffset();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700185 const char* oat_code_start = oat_data_start + oat_data_length;
Vladimir Markof4da6752014-08-01 19:04:18 +0100186 const size_t oat_code_length = oat_writer->GetSize() - oat_data_length;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700187
188 // TODO: ownership of oat_input?
189 oat_input_ = ir_builder_->CreateInput("oat contents",
190 mcld::sys::fs::Path("oat contents path"),
191 mcld::Input::Object);
192 CHECK(oat_input_ != NULL);
193
194 // TODO: ownership of null_section?
195 mcld::LDSection* null_section = ir_builder_->CreateELFHeader(*oat_input_,
196 "",
197 mcld::LDFileFormat::Null,
Nicolas Geoffrayf2b39562014-03-03 15:54:42 +0000198 SHT_NULL,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700199 0);
200 CHECK(null_section != NULL);
201
202 // TODO: we should split readonly data from readonly executable
203 // code like .oat does. We need to control section layout with
204 // linker script like functionality to guarantee references
205 // between sections maintain relative position which isn't
206 // possible right now with the mclinker APIs.
207 CHECK(oat_code_start != NULL);
208
209 // we need to ensure that oatdata is page aligned so when we
210 // fixup the segment load addresses, they remain page aligned.
211 uint32_t alignment = kPageSize;
212
213 // TODO: ownership of text_section?
214 mcld::LDSection* text_section = ir_builder_->CreateELFHeader(*oat_input_,
215 ".text",
Nicolas Geoffrayf2b39562014-03-03 15:54:42 +0000216 SHT_PROGBITS,
217 SHF_EXECINSTR | SHF_ALLOC,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700218 alignment);
219 CHECK(text_section != NULL);
220
221 mcld::SectionData* text_sectiondata = ir_builder_->CreateSectionData(*text_section);
222 CHECK(text_sectiondata != NULL);
223
224 // TODO: why does IRBuilder::CreateRegion take a non-const pointer?
225 mcld::Fragment* text_fragment = ir_builder_->CreateRegion(const_cast<char*>(oat_data_start),
Vladimir Markof4da6752014-08-01 19:04:18 +0100226 oat_writer->GetSize());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700227 CHECK(text_fragment != NULL);
228 ir_builder_->AppendFragment(*text_fragment, *text_sectiondata);
229
230 ir_builder_->AddSymbol(*oat_input_,
231 "oatdata",
232 mcld::ResolveInfo::Object,
233 mcld::ResolveInfo::Define,
234 mcld::ResolveInfo::Global,
235 oat_data_length, // size
236 0, // offset
237 text_section);
238
239 ir_builder_->AddSymbol(*oat_input_,
240 "oatexec",
241 mcld::ResolveInfo::Function,
242 mcld::ResolveInfo::Define,
243 mcld::ResolveInfo::Global,
244 oat_code_length, // size
245 oat_data_length, // offset
246 text_section);
247
248 ir_builder_->AddSymbol(*oat_input_,
249 "oatlastword",
250 mcld::ResolveInfo::Object,
251 mcld::ResolveInfo::Define,
252 mcld::ResolveInfo::Global,
253 0, // size
254 // subtract a word so symbol is within section
255 (oat_data_length + oat_code_length) - sizeof(uint32_t), // offset
256 text_section);
Vladimir Markof4da6752014-08-01 19:04:18 +0100257
258 return text_section;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700259}
260
Brian Carlstrom7940e442013-07-12 13:46:57 -0700261void ElfWriterMclinker::AddMethodInputs(const std::vector<const DexFile*>& dex_files) {
262 DCHECK(oat_input_ != NULL);
263
264 DexMethodIterator it(dex_files);
265 while (it.HasNext()) {
266 const DexFile& dex_file = it.GetDexFile();
267 uint32_t method_idx = it.GetMemberIndex();
268 const CompiledMethod* compiled_method =
269 compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, method_idx));
270 if (compiled_method != NULL) {
271 AddCompiledCodeInput(*compiled_method);
272 }
273 it.Next();
274 }
275 added_symbols_.clear();
276}
277
278void ElfWriterMclinker::AddCompiledCodeInput(const CompiledCode& compiled_code) {
279 // Check if we've seen this compiled code before. If so skip
280 // it. This can happen for reused code such as invoke stubs.
281 const std::string& symbol = compiled_code.GetSymbol();
282 SafeMap<const std::string*, const std::string*>::iterator it = added_symbols_.find(&symbol);
283 if (it != added_symbols_.end()) {
284 return;
285 }
286 added_symbols_.Put(&symbol, &symbol);
287
288 // Add input to supply code for symbol
Brian Carlstrom7dff39e2014-02-09 23:11:47 -0800289 const std::vector<uint8_t>* code = compiled_code.GetPortableCode();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700290 // TODO: ownership of code_input?
291 // TODO: why does IRBuilder::ReadInput take a non-const pointer?
292 mcld::Input* code_input = ir_builder_->ReadInput(symbol,
Brian Carlstrom093713f2014-02-10 09:46:37 -0800293 const_cast<uint8_t*>(&(*code)[0]),
294 code->size());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700295 CHECK(code_input != NULL);
296}
297
298void ElfWriterMclinker::AddRuntimeInputs(const std::string& android_root, bool is_host) {
299 std::string libart_so(android_root);
300 libart_so += kIsDebugBuild ? "/lib/libartd.so" : "/lib/libart.so";
301 // TODO: ownership of libart_so_input?
302 mcld::Input* libart_so_input = ir_builder_->ReadInput(libart_so, libart_so);
303 CHECK(libart_so_input != NULL);
304
305 std::string host_prebuilt_dir("prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6");
306
307 std::string compiler_runtime_lib;
308 if (is_host) {
309 compiler_runtime_lib += host_prebuilt_dir;
310 compiler_runtime_lib += "/lib/gcc/i686-linux/4.6.x-google/libgcc.a";
311 } else {
312 compiler_runtime_lib += android_root;
313 compiler_runtime_lib += "/lib/libcompiler_rt.a";
314 }
315 // TODO: ownership of compiler_runtime_lib_input?
316 mcld::Input* compiler_runtime_lib_input = ir_builder_->ReadInput(compiler_runtime_lib,
317 compiler_runtime_lib);
318 CHECK(compiler_runtime_lib_input != NULL);
319
320 std::string libc_lib;
321 if (is_host) {
322 libc_lib += host_prebuilt_dir;
323 libc_lib += "/sysroot/usr/lib/libc.so.6";
324 } else {
325 libc_lib += android_root;
326 libc_lib += "/lib/libc.so";
327 }
328 // TODO: ownership of libc_lib_input?
329 mcld::Input* libc_lib_input_input = ir_builder_->ReadInput(libc_lib, libc_lib);
330 CHECK(libc_lib_input_input != NULL);
331
332 std::string libm_lib;
333 if (is_host) {
334 libm_lib += host_prebuilt_dir;
335 libm_lib += "/sysroot/usr/lib/libm.so";
336 } else {
337 libm_lib += android_root;
338 libm_lib += "/lib/libm.so";
339 }
340 // TODO: ownership of libm_lib_input?
341 mcld::Input* libm_lib_input_input = ir_builder_->ReadInput(libm_lib, libm_lib);
342 CHECK(libm_lib_input_input != NULL);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700343}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700344
Brian Carlstrom7940e442013-07-12 13:46:57 -0700345void ElfWriterMclinker::FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files) {
Ian Rogers8584a682013-10-24 11:48:02 -0700346 std::string error_msg;
Ian Rogers700a4022014-05-19 16:49:03 -0700347 std::unique_ptr<ElfFile> elf_file(ElfFile::Open(elf_file_, true, false, &error_msg));
Ian Rogers8584a682013-10-24 11:48:02 -0700348 CHECK(elf_file.get() != NULL) << elf_file_->GetPath() << ": " << error_msg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700349
Nicolas Geoffrayf2b39562014-03-03 15:54:42 +0000350 uint32_t oatdata_address = GetOatDataAddress(elf_file.get());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700351 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();
Brian Carlstromea46f952013-07-30 01:26:50 -0700356 mirror::ArtMethod* method = NULL;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700357 if (compiler_driver_->IsImage()) {
358 ClassLinker* linker = Runtime::Current()->GetClassLinker();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700359 // Unchecked as we hold mutator_lock_ on entry.
360 ScopedObjectAccessUnchecked soa(Thread::Current());
Mathieu Chartier0cd81352014-05-22 16:48:55 -0700361 StackHandleScope<1> hs(soa.Self());
Mathieu Chartier421c5372014-05-14 14:11:40 -0700362 Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(dex_file)));
Mathieu Chartier0cd81352014-05-22 16:48:55 -0700363 method = linker->ResolveMethod(dex_file, method_idx, dex_cache,
364 NullHandle<mirror::ClassLoader>(),
365 NullHandle<mirror::ArtMethod>(), invoke_type);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700366 CHECK(method != NULL);
367 }
368 const CompiledMethod* compiled_method =
369 compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, method_idx));
370 if (compiled_method != NULL) {
371 uint32_t offset = FixupCompiledCodeOffset(*elf_file.get(), oatdata_address, *compiled_method);
372 // Don't overwrite static method trampoline
373 if (method != NULL &&
374 (!method->IsStatic() ||
375 method->IsConstructor() ||
376 method->GetDeclaringClass()->IsInitialized())) {
Brian Carlstrom398c9b52014-02-09 21:02:01 -0800377 method->SetPortableOatCodeOffset(offset);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700378 }
379 }
380 it.Next();
381 }
382 symbol_to_compiled_code_offset_.clear();
383}
384
385uint32_t ElfWriterMclinker::FixupCompiledCodeOffset(ElfFile& elf_file,
Nicolas Geoffrayf2b39562014-03-03 15:54:42 +0000386 Elf32_Addr oatdata_address,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700387 const CompiledCode& compiled_code) {
388 const std::string& symbol = compiled_code.GetSymbol();
389 SafeMap<const std::string*, uint32_t>::iterator it = symbol_to_compiled_code_offset_.find(&symbol);
390 if (it != symbol_to_compiled_code_offset_.end()) {
391 return it->second;
392 }
393
Nicolas Geoffrayf2b39562014-03-03 15:54:42 +0000394 Elf32_Addr compiled_code_address = elf_file.FindSymbolAddress(SHT_SYMTAB,
395 symbol,
396 true);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700397 CHECK_NE(0U, compiled_code_address) << symbol;
398 CHECK_LT(oatdata_address, compiled_code_address) << symbol;
399 uint32_t compiled_code_offset = compiled_code_address - oatdata_address;
400 symbol_to_compiled_code_offset_.Put(&symbol, compiled_code_offset);
401
402 const std::vector<uint32_t>& offsets = compiled_code.GetOatdataOffsetsToCompliledCodeOffset();
403 for (uint32_t i = 0; i < offsets.size(); i++) {
404 uint32_t oatdata_offset = oatdata_address + offsets[i];
405 uint32_t* addr = reinterpret_cast<uint32_t*>(elf_file.Begin() + oatdata_offset);
406 *addr = compiled_code_offset;
407 }
408 return compiled_code_offset;
409}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700410
411} // namespace art