blob: 696cd62e5ae2802a9a55f11a90cc32be6d068e2f [file] [log] [blame]
Shih-wei Liao52aefd82012-07-27 03:12:56 -07001/*
2 * Copyright 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 "bcc/AndroidBitcode/ABCCompilerDriver.h"
18
19#include <llvm/Module.h>
20#include <llvm/Support/MemoryBuffer.h>
21#include <llvm/Support/raw_ostream.h>
22
Shih-wei Liao3928c622012-08-16 00:23:15 -070023#include "ARMABCCompilerDriver.h"
24#include "MipsABCCompilerDriver.h"
25#include "X86ABCCompilerDriver.h"
26
Shih-wei Liao52aefd82012-07-27 03:12:56 -070027#include "bcc/Config/Config.h"
28#include "bcc/Script.h"
29#include "bcc/Source.h"
30#include "bcc/Support/CompilerConfig.h"
31#include "bcc/Support/LinkerConfig.h"
32#include "bcc/Support/Log.h"
33#include "bcc/Support/OutputFile.h"
34#include "bcc/Support/TargetLinkerConfigs.h"
35#include "bcc/Support/TargetCompilerConfigs.h"
36
37#include "mcld/Config/Config.h"
38
39namespace bcc {
40
Shih-wei Liao3928c622012-08-16 00:23:15 -070041ABCCompilerDriver::ABCCompilerDriver(const std::string &pTriple)
Shih-wei Liao52aefd82012-07-27 03:12:56 -070042 : mContext(), mCompiler(), mLinker(),
43 mCompilerConfig(NULL), mLinkerConfig(NULL),
Shih-wei Liao3928c622012-08-16 00:23:15 -070044 mTriple(pTriple), mAndroidSysroot("/") {
Shih-wei Liao52aefd82012-07-27 03:12:56 -070045}
46
47ABCCompilerDriver::~ABCCompilerDriver() {
48 delete mCompilerConfig;
49 delete mLinkerConfig;
50}
51
52bool ABCCompilerDriver::configCompiler() {
53 if (mCompilerConfig != NULL) {
54 return true;
55 }
56
57 mCompilerConfig = new (std::nothrow) CompilerConfig(mTriple);
58 if (mCompilerConfig == NULL) {
59 ALOGE("Out of memory when create the compiler configuration!");
60 return false;
61 }
62
63 // Set PIC mode for relocatables.
64 mCompilerConfig->setRelocationModel(llvm::Reloc::PIC_);
65
66 // Set optimization level to -O1.
67 mCompilerConfig->setOptimizationLevel(llvm::CodeGenOpt::Less);
68
69 Compiler::ErrorCode result = mCompiler.config(*mCompilerConfig);
70
71 if (result != Compiler::kSuccess) {
72 ALOGE("Failed to configure the compiler! (detail: %s)",
73 Compiler::GetErrorString(result));
74 return false;
75 }
76
77 return true;
78}
79
80bool ABCCompilerDriver::configLinker() {
81 if (mLinkerConfig != NULL) {
82 return true;
83 }
84
85 mLinkerConfig = new (std::nothrow) LinkerConfig(mTriple);
86 if (mLinkerConfig == NULL) {
87 ALOGE("Out of memory when create the linker configuration!");
88 return false;
89 }
90
91 // FIXME: how can we get the soname if input/output is file descriptor?
92 mLinkerConfig->setSOName("");
93
94 mLinkerConfig->setDyld("/system/bin/linker");
95 mLinkerConfig->setSysRoot(mAndroidSysroot);
96 mLinkerConfig->addSearchDir("=/system/lib");
97
98 // Add non-portable function list. For each function X, linker will rename
99 // it to X_portable. And X_portable" is implemented in libportable to solve
100 // portable issues.
Shih-wei Liao31b7c562012-08-16 00:56:04 -0700101 const char **non_portable_func = getNonPortableList();
102 if (non_portable_func != NULL) {
103 while (*non_portable_func != NULL) {
104 mLinkerConfig->addPortable(*non_portable_func);
105 non_portable_func++;
106 }
107 }
Shih-wei Liao52aefd82012-07-27 03:12:56 -0700108
109 // -shared
110 mLinkerConfig->setShared(true);
111
112 // -Bsymbolic.
113 mLinkerConfig->setBsymbolic(true);
114
115 // Config the linker.
116 Linker::ErrorCode result = mLinker.config(*mLinkerConfig);
117 if (result != Linker::kSuccess) {
118 ALOGE("Failed to configure the linker! (%s)",
119 Linker::GetErrorString(result));
120 return false;
121 }
122
123 return true;
124}
125
126//------------------------------------------------------------------------------
127
128Script *ABCCompilerDriver::prepareScript(int pInputFd) {
129 Source *source = Source::CreateFromFd(mContext, pInputFd);
130 if (source == NULL) {
131 ALOGE("Failed to load LLVM module from file descriptor `%d'", pInputFd);
132 return NULL;
133 }
134
135 Script *script = new (std::nothrow) Script(*source);
136 if (script == NULL) {
137 ALOGE("Out of memory when create script for file descriptor `%d'!",
138 pInputFd);
139 delete source;
140 return NULL;
141 }
142
143 return script;
144}
145
146bool ABCCompilerDriver::compile(Script &pScript, llvm::raw_ostream &pOutput) {
147 // Config the compiler.
148 if (!configCompiler()) {
149 return false;
150 }
151
152 // Run the compiler.
153 Compiler::ErrorCode result = mCompiler.compile(pScript, pOutput);
154 if (result != Compiler::kSuccess) {
155 ALOGE("Fatal error during compilation (%s)!",
156 Compiler::GetErrorString(result));
157 return false;
158 }
159
160 return true;
161}
162
163bool ABCCompilerDriver::link(const Script &pScript,
164 const std::string &input_relocatable,
165 int pOutputFd) {
166 // Config the linker.
167 if (!configLinker()) {
168 return false;
169 }
170
171 // Prepare output file.
172 Linker::ErrorCode result = mLinker.setOutput(pOutputFd);
173
174 if (result != Linker::kSuccess) {
175 ALOGE("Failed to open the output file! (file descriptor `%d': %s)",
176 pOutputFd, Linker::GetErrorString(result));
177 return false;
178 }
179
180 mLinker.addObject(mAndroidSysroot + "/system/lib/crtbegin_so.o");
181
182 // Prepare the relocatables.
183 //
184 // FIXME: Ugly const_cast here.
185 mLinker.addObject(const_cast<char *>(input_relocatable.data()),
186 input_relocatable.size());
187
188 // Read dependent library list.
189 const Source &source = pScript.getSource();
190 for (llvm::Module::lib_iterator lib_iter = source.getModule().lib_begin(),
191 lib_end = source.getModule().lib_end(); lib_iter != lib_end;
192 ++lib_iter) {
193 mLinker.addNameSpec(*lib_iter);
194 }
195
196 // TODO: Refactor libbcc/runtime/ to libcompilerRT.so and use it.
197 mLinker.addNameSpec("bcc");
198
199 mLinker.addObject(mAndroidSysroot + "/system/lib/crtend_so.o");
200
201 // Perform linking.
202 result = mLinker.link();
203 if (result != Linker::kSuccess) {
204 ALOGE("Failed to link the shared object (detail: %s)",
205 Linker::GetErrorString(result));
206 return false;
207 }
208
209 return true;
210}
211
212//------------------------------------------------------------------------------
213
Shih-wei Liao3928c622012-08-16 00:23:15 -0700214ABCCompilerDriver *ABCCompilerDriver::Create(const std::string &pTriple) {
215 std::string error;
216 const llvm::Target *target =
217 llvm::TargetRegistry::lookupTarget(pTriple, error);
218
219 if (target == NULL) {
220 ALOGE("Unsupported target '%s' (detail: %s)!", pTriple.c_str(),
221 error.c_str());
222 return NULL;
223 }
224
225 switch (llvm::Triple::getArchTypeForLLVMName(target->getName())) {
226 case llvm::Triple::arm:
227 case llvm::Triple::thumb: {
228 return new ARMABCCompilerDriver(pTriple);
229 }
230 case llvm::Triple::mipsel: {
231 return new MipsABCCompilerDriver(pTriple);
232 }
233 case llvm::Triple::x86: {
234 return new X86ABCCompilerDriver(pTriple);
235 }
236 default: {
237 ALOGE("Unknown architecture '%s' supplied in %s!", target->getName(),
238 pTriple.c_str());
239 break;
240 }
241 }
242
243 return NULL;
244}
245
Shih-wei Liao52aefd82012-07-27 03:12:56 -0700246bool ABCCompilerDriver::build(int pInputFd, int pOutputFd) {
247 //===--------------------------------------------------------------------===//
248 // Prepare the input.
249 //===--------------------------------------------------------------------===//
250 Script *script = prepareScript(pInputFd);
251 if (script == NULL) {
252 return false;
253 }
254
255 //===--------------------------------------------------------------------===//
256 // Prepare the output.
257 //===--------------------------------------------------------------------===//
258 std::string output_relocatable;
259 llvm::raw_ostream *output =
260 new (std::nothrow) llvm::raw_string_ostream(output_relocatable);
261 if (output == NULL) {
262 ALOGE("Failed to prepare the output for compile the input from %d into "
263 "relocatable object!", pInputFd);
264 delete script;
265 return false;
266 }
267
268 //===--------------------------------------------------------------------===//
269 // Compile.
270 //===--------------------------------------------------------------------===//
271 if (!compile(*script, *output)) {
272 delete output;
273 delete script;
274 return false;
275 }
276
277 //===--------------------------------------------------------------------===//
278 // Close the output.
279 //===--------------------------------------------------------------------===//
280 delete output;
281
282 //===--------------------------------------------------------------------===//
283 // Link.
284 //===--------------------------------------------------------------------===//
285 if (!link(*script, output_relocatable, pOutputFd)) {
286 delete script;
287 return false;
288 }
289
290 //===--------------------------------------------------------------------===//
291 // Clean up.
292 //===--------------------------------------------------------------------===//
293 delete script;
294
295 return true;
296}
297
298} // namespace bcc