blob: 84b6583a8fc0eb1231e945a0c861ea16ef4ba54a [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
23#include "bcc/Config/Config.h"
24#include "bcc/Script.h"
25#include "bcc/Source.h"
26#include "bcc/Support/CompilerConfig.h"
27#include "bcc/Support/LinkerConfig.h"
28#include "bcc/Support/Log.h"
29#include "bcc/Support/OutputFile.h"
30#include "bcc/Support/TargetLinkerConfigs.h"
31#include "bcc/Support/TargetCompilerConfigs.h"
32
33#include "mcld/Config/Config.h"
34
35namespace bcc {
36
37ABCCompilerDriver::ABCCompilerDriver(const std::string &pTriple,
38 const std::string &pAndroidSysroot)
39 : mContext(), mCompiler(), mLinker(),
40 mCompilerConfig(NULL), mLinkerConfig(NULL),
41 mTriple(pTriple), mAndroidSysroot(pAndroidSysroot) {
42}
43
44ABCCompilerDriver::~ABCCompilerDriver() {
45 delete mCompilerConfig;
46 delete mLinkerConfig;
47}
48
49bool ABCCompilerDriver::configCompiler() {
50 if (mCompilerConfig != NULL) {
51 return true;
52 }
53
54 mCompilerConfig = new (std::nothrow) CompilerConfig(mTriple);
55 if (mCompilerConfig == NULL) {
56 ALOGE("Out of memory when create the compiler configuration!");
57 return false;
58 }
59
60 // Set PIC mode for relocatables.
61 mCompilerConfig->setRelocationModel(llvm::Reloc::PIC_);
62
63 // Set optimization level to -O1.
64 mCompilerConfig->setOptimizationLevel(llvm::CodeGenOpt::Less);
65
66 Compiler::ErrorCode result = mCompiler.config(*mCompilerConfig);
67
68 if (result != Compiler::kSuccess) {
69 ALOGE("Failed to configure the compiler! (detail: %s)",
70 Compiler::GetErrorString(result));
71 return false;
72 }
73
74 return true;
75}
76
77bool ABCCompilerDriver::configLinker() {
78 if (mLinkerConfig != NULL) {
79 return true;
80 }
81
82 mLinkerConfig = new (std::nothrow) LinkerConfig(mTriple);
83 if (mLinkerConfig == NULL) {
84 ALOGE("Out of memory when create the linker configuration!");
85 return false;
86 }
87
88 // FIXME: how can we get the soname if input/output is file descriptor?
89 mLinkerConfig->setSOName("");
90
91 mLinkerConfig->setDyld("/system/bin/linker");
92 mLinkerConfig->setSysRoot(mAndroidSysroot);
93 mLinkerConfig->addSearchDir("=/system/lib");
94
95 // Add non-portable function list. For each function X, linker will rename
96 // it to X_portable. And X_portable" is implemented in libportable to solve
97 // portable issues.
98 mLinkerConfig->addPortable("stat");
99 mLinkerConfig->addPortable("fstat");
100 mLinkerConfig->addPortable("lstat");
101 mLinkerConfig->addPortable("fstatat");
102 mLinkerConfig->addPortable("socket");
103 mLinkerConfig->addPortable("setsockopt");
104 mLinkerConfig->addPortable("getsockopt");
105 mLinkerConfig->addPortable("epoll_event");
106 mLinkerConfig->addPortable("epoll_ctl");
107 mLinkerConfig->addPortable("epoll_wait");
108
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
214bool ABCCompilerDriver::build(int pInputFd, int pOutputFd) {
215 //===--------------------------------------------------------------------===//
216 // Prepare the input.
217 //===--------------------------------------------------------------------===//
218 Script *script = prepareScript(pInputFd);
219 if (script == NULL) {
220 return false;
221 }
222
223 //===--------------------------------------------------------------------===//
224 // Prepare the output.
225 //===--------------------------------------------------------------------===//
226 std::string output_relocatable;
227 llvm::raw_ostream *output =
228 new (std::nothrow) llvm::raw_string_ostream(output_relocatable);
229 if (output == NULL) {
230 ALOGE("Failed to prepare the output for compile the input from %d into "
231 "relocatable object!", pInputFd);
232 delete script;
233 return false;
234 }
235
236 //===--------------------------------------------------------------------===//
237 // Compile.
238 //===--------------------------------------------------------------------===//
239 if (!compile(*script, *output)) {
240 delete output;
241 delete script;
242 return false;
243 }
244
245 //===--------------------------------------------------------------------===//
246 // Close the output.
247 //===--------------------------------------------------------------------===//
248 delete output;
249
250 //===--------------------------------------------------------------------===//
251 // Link.
252 //===--------------------------------------------------------------------===//
253 if (!link(*script, output_relocatable, pOutputFd)) {
254 delete script;
255 return false;
256 }
257
258 //===--------------------------------------------------------------------===//
259 // Clean up.
260 //===--------------------------------------------------------------------===//
261 delete script;
262
263 return true;
264}
265
266} // namespace bcc