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