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