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