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