blob: 66a91451f31cee77899f9f4dba7296a663801d92 [file] [log] [blame]
Brian Carlstrom700c8d32012-11-05 10:42:02 -08001/*
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.h"
18
19#include "base/unix_file/fd_file.h"
20#include "elf_file.h"
21#include "oat.h"
22#include "oat_file.h"
23
24#include <llvm/Support/TargetSelect.h>
25
26#include <mcld/Environment.h>
27#include <mcld/IRBuilder.h>
28#include <mcld/Linker.h>
29#include <mcld/LinkerConfig.h>
30#include <mcld/Module.h>
31#include <mcld/Support/Path.h>
32#include <mcld/Support/TargetSelect.h>
33
34namespace art {
35
36bool ElfWriter::Create(File* file, std::vector<uint8_t>& oat_contents, const Compiler& compiler) {
37 ElfWriter elf_writer(compiler);
38 return elf_writer.Write(oat_contents, file);
39}
40
41ElfWriter::ElfWriter(const Compiler& compiler) : compiler_(&compiler) {}
42
43ElfWriter::~ElfWriter() {}
44
45static void InitializeLLVM() {
46 // TODO: this is lifted from art's compiler_llvm.cc, should be factored out
47#if defined(ART_TARGET)
48 llvm::InitializeNativeTarget();
49 // TODO: odd that there is no InitializeNativeTargetMC?
50#else
51 llvm::InitializeAllTargets();
52 llvm::InitializeAllTargetMCs();
53#endif
54}
55
56bool ElfWriter::Write(std::vector<uint8_t>& oat_contents, File* elf_file) {
57
58 std::string target_triple;
59 std::string target_cpu;
60 std::string target_attr;
61 Compiler::InstructionSetToLLVMTarget(compiler_->GetInstructionSet(),
62 target_triple,
63 target_cpu,
64 target_attr);
65
66 {
67 // Based on mclinker's llvm-mcld.cpp main() and LinkerTest
68 //
69 // TODO: LinkerTest uses mcld::Initialize(), but it does an
70 // llvm::InitializeAllTargets, which we don't want. Basically we
71 // want mcld::InitializeNative, but it doesn't exist yet, so we
72 // inline the minimal we need here.
73 InitializeLLVM();
74 mcld::InitializeAllTargets();
75 mcld::InitializeAllLinkers();
76 mcld::InitializeAllEmulations();
77 mcld::InitializeAllDiagnostics();
78
79 UniquePtr<mcld::LinkerConfig> linker_config(new mcld::LinkerConfig(target_triple));
80 CHECK(linker_config.get() != NULL);
81 linker_config->setCodeGenType(mcld::LinkerConfig::DynObj);
82 linker_config->options().setSOName(elf_file->GetPath());
83 // TODO: Wire up mcld DiagnosticEngine to LOG?
84 if (false) {
85 // enables some tracing of input file processing
86 linker_config->options().setTrace(true);
87 }
88
89 // Based on alone::Linker::config
90 UniquePtr<mcld::Module> module(new mcld::Module(linker_config->options().soname()));
91 CHECK(module.get() != NULL);
92 UniquePtr<mcld::IRBuilder> ir_builder(new mcld::IRBuilder(*module.get(), *linker_config.get()));
93 CHECK(ir_builder.get() != NULL);
94 UniquePtr<mcld::Linker> linker(new mcld::Linker());
95 CHECK(linker.get() != NULL);
96 linker->config(*linker_config.get());
97
98
99 // Add an artificial memory input. Based on LinkerTest.
100 UniquePtr<OatFile> oat_file(OatFile::Open(oat_contents, elf_file->GetPath()));
101 CHECK(oat_file.get() != NULL) << elf_file->GetPath();
102
103 const char* oat_data_start = reinterpret_cast<const char*>(&oat_file->GetOatHeader());
104 const size_t oat_data_length = oat_file->GetOatHeader().GetExecutableOffset();
105 const char* oat_code_start = oat_data_start + oat_data_length;
106 const size_t oat_code_length = oat_file->Size() - oat_data_length;
107
108 // TODO: ownership of input?
109 mcld::Input* input = ir_builder->CreateInput("oat contents",
110 mcld::sys::fs::Path("oat contents path"),
111 mcld::Input::Object);
112 CHECK(input != NULL);
113
114 // TODO: ownership of null_section?
115 mcld::LDSection* null_section = ir_builder->CreateELFHeader(*input,
116 "",
117 mcld::LDFileFormat::Null,
118 llvm::ELF::SHT_NULL,
119 0);
120 CHECK(null_section != NULL);
121
122 // TODO: we should split readonly data from readonly executable
123 // code like .oat does. We need to control section layout with
124 // linker script like functionality to guarantee references
125 // between sections maintain relative position which isn't
126 // possible right now with the mclinker APIs.
127 CHECK(oat_code_start);
128
129 // TODO: ownership of text_section?
130 // we need to ensure that oatdata is page aligned so when we
131 // fixup the segment load addresses, they remain page aligned.
132 mcld::LDSection* text_section = ir_builder->CreateELFHeader(*input,
133 ".text",
134 llvm::ELF::SHT_PROGBITS,
135 llvm::ELF::SHF_EXECINSTR
136 | llvm::ELF::SHF_ALLOC,
137 kPageSize);
138 CHECK(text_section != NULL);
139
140 mcld::SectionData* text_section_data = ir_builder->CreateSectionData(*text_section);
141 CHECK(text_section_data != NULL);
142
143 // TODO: why does IRBuilder::CreateRegion take a non-const pointer?
144 mcld::Fragment* text_fragment = ir_builder->CreateRegion(const_cast<char*>(oat_data_start),
145 oat_file->Size());
146 CHECK(text_fragment != NULL);
147 ir_builder->AppendFragment(*text_fragment, *text_section_data);
148
149 ir_builder->AddSymbol(*input,
150 "oatdata",
151 mcld::ResolveInfo::Object,
152 mcld::ResolveInfo::Define,
153 mcld::ResolveInfo::Global,
154 oat_data_length, // size
155 0, // offset
156 text_section);
157
158 ir_builder->AddSymbol(*input,
159 "oatexec",
Ian Rogerse9de2dd2013-01-31 11:11:16 -0800160 mcld::ResolveInfo::Function,
Brian Carlstrom700c8d32012-11-05 10:42:02 -0800161 mcld::ResolveInfo::Define,
162 mcld::ResolveInfo::Global,
163 oat_code_length, // size
164 oat_data_length, // offset
165 text_section);
166
167 ir_builder->AddSymbol(*input,
168 "oatlastword",
169 mcld::ResolveInfo::Object,
170 mcld::ResolveInfo::Define,
171 mcld::ResolveInfo::Global,
172 0, // size
173 // subtract a word so symbol is within section
174 (oat_data_length + oat_code_length) - sizeof(uint32_t), // offset
175 text_section);
176
177 // link inputs
178 if (!linker->link(*module.get(), *ir_builder.get())) {
179 LOG(ERROR) << "problem linking " << elf_file->GetPath();
180 return false;
181 }
182
183 // emited linked output
184 if (!linker->emit(elf_file->Fd())) {
185 LOG(ERROR) << "problem emitting " << elf_file->GetPath();
186 return false;
187 }
188 // TODO: mcld::Linker::emit closed the file descriptor. It probably shouldn't.
189 // For now, close our File to match.
190 elf_file->Close();
191 mcld::Finalize();
192 }
193 LOG(INFO) << "ELF file written successfully: " << elf_file->GetPath();
194 return true;
195}
196
197bool ElfWriter::Fixup(File* file, uintptr_t oat_data_begin) {
198 UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false));
199 CHECK(elf_file.get() != NULL);
200
201 // Lookup "oatdata" symbol address.
202 llvm::ELF::Elf32_Addr oatdata_address = elf_file->FindSymbolAddress(llvm::ELF::SHT_DYNSYM,
203 "oatdata");
204 CHECK_NE(0U, oatdata_address);
205 llvm::ELF::Elf32_Off base_address = oat_data_begin - oatdata_address;
206
207 if (!FixupDynamic(*elf_file.get(), base_address)) {
208 LOG(WARNING) << "Failed fo fixup .dynamic in " << file->GetPath();
209 return false;
210 }
211 if (!FixupSectionHeaders(*elf_file.get(), base_address)) {
212 LOG(WARNING) << "Failed fo fixup section headers in " << file->GetPath();
213 return false;
214 }
215 if (!FixupProgramHeaders(*elf_file.get(), base_address)) {
216 LOG(WARNING) << "Failed fo fixup program headers in " << file->GetPath();
217 return false;
218 }
219 if (!FixupSymbols(*elf_file.get(), base_address, true)) {
220 LOG(WARNING) << "Failed fo fixup .dynsym in " << file->GetPath();
221 return false;
222 }
223 if (!FixupSymbols(*elf_file.get(), base_address, false)) {
224 LOG(WARNING) << "Failed fo fixup .symtab in " << file->GetPath();
225 return false;
226 }
227 return true;
228}
229
230bool ElfWriter::FixupDynamic(ElfFile& elf_file, uintptr_t base_address) {
231 // TODO: C++0x auto.
232 for (llvm::ELF::Elf32_Word i = 0; i < elf_file.GetDynamicNum(); i++) {
233 llvm::ELF::Elf32_Dyn& elf_dyn = elf_file.GetDynamic(i);
234 bool elf_dyn_needs_fixup = false;
235 // case 1: if Elf32_Dyn.d_tag implies Elf32_Dyn.d_un contains an address in d_ptr
236 switch (elf_dyn.d_tag) {
237 case llvm::ELF::DT_PLTGOT:
238 case llvm::ELF::DT_HASH:
239 case llvm::ELF::DT_STRTAB:
240 case llvm::ELF::DT_SYMTAB:
241 case llvm::ELF::DT_RELA:
242 case llvm::ELF::DT_INIT:
243 case llvm::ELF::DT_FINI:
244 case llvm::ELF::DT_REL:
245 case llvm::ELF::DT_DEBUG:
246 case llvm::ELF::DT_JMPREL: {
247 elf_dyn_needs_fixup = true;
248 break;
249 }
250 default: {
251 // case 2: if d_tag is even and greater than > DT_ENCODING
252 if ((elf_dyn.d_tag > llvm::ELF::DT_ENCODING) && ((elf_dyn.d_tag % 2) == 0)) {
253 elf_dyn_needs_fixup = true;
254 }
255 break;
256 }
257 }
258 if (elf_dyn_needs_fixup) {
259 uint32_t d_ptr = elf_dyn.d_un.d_ptr;
260 d_ptr += base_address;
261 elf_dyn.d_un.d_ptr = d_ptr;
262 }
263 }
264 return true;
265}
266
267bool ElfWriter::FixupSectionHeaders(ElfFile& elf_file, uintptr_t base_address) {
268 for (llvm::ELF::Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) {
269 llvm::ELF::Elf32_Shdr& sh = elf_file.GetSectionHeader(i);
270 // 0 implies that the section will not exist in the memory of the process
271 if (sh.sh_addr == 0) {
272 continue;
273 }
274 sh.sh_addr += base_address;
275 }
276 return true;
277}
278
279bool ElfWriter::FixupProgramHeaders(ElfFile& elf_file, uintptr_t base_address) {
280 // TODO: ELFObjectFile doesn't have give to Elf32_Phdr, so we do that ourselves for now.
281 for (llvm::ELF::Elf32_Word i = 0; i < elf_file.GetProgramHeaderNum(); i++) {
282 llvm::ELF::Elf32_Phdr& ph = elf_file.GetProgramHeader(i);
283 CHECK_EQ(ph.p_vaddr, ph.p_paddr) << elf_file.GetFile().GetPath() << " i=" << i;
284 CHECK((ph.p_align == 0) || (0 == ((ph.p_vaddr - ph.p_offset) & (ph.p_align - 1))));
285 ph.p_vaddr += base_address;
286 ph.p_paddr += base_address;
287 CHECK((ph.p_align == 0) || (0 == ((ph.p_vaddr - ph.p_offset) & (ph.p_align - 1))));
288 }
289 return true;
290}
291
292bool ElfWriter::FixupSymbols(ElfFile& elf_file, uintptr_t base_address, bool dynamic) {
293 llvm::ELF::Elf32_Word section_type = dynamic ? llvm::ELF::SHT_DYNSYM : llvm::ELF::SHT_SYMTAB;
294 // TODO: Unfortunate ELFObjectFile has protected symbol access, so use ElfFile
295 llvm::ELF::Elf32_Shdr* symbol_section = elf_file.FindSectionByType(section_type);
296 CHECK(symbol_section != NULL) << elf_file.GetFile().GetPath();
297 for (uint32_t i = 0; i < elf_file.GetSymbolNum(*symbol_section); i++) {
298 llvm::ELF::Elf32_Sym& symbol = elf_file.GetSymbol(section_type, i);
299 if (symbol.st_value != 0) {
300 symbol.st_value += base_address;
301 }
302 }
303 return true;
304}
305
306void ElfWriter::GetOatElfInformation(File* file,
307 size_t& oat_loaded_size,
308 size_t& oat_data_offset) {
309 UniquePtr<ElfFile> elf_file(ElfFile::Open(file, false, false));
310 CHECK(elf_file.get() != NULL);
311
312 oat_loaded_size = elf_file->GetLoadedSize();
313 CHECK_NE(0U, oat_loaded_size);
314 oat_data_offset = elf_file->FindSymbolAddress(llvm::ELF::SHT_DYNSYM, "oatdata");
315 CHECK_NE(0U, oat_data_offset);
316}
317
318} // namespace art