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 <string> 18 #include <vector> 19 20 #include <stdlib.h> 21 22 #include <llvm/ADT/STLExtras.h> 23 #include <llvm/ADT/SmallString.h> 24 #include <llvm/Config/config.h> 25 #include <llvm/Support/CommandLine.h> 26 #include <llvm/Support/FileSystem.h> 27 #include <llvm/Support/Path.h> 28 #include <llvm/Support/raw_ostream.h> 29 #include <llvm/Support/system_error.h> 30 31 #include <bcc/BCCContext.h> 32 #include <bcc/Compiler.h> 33 #include <bcc/Config/BuildInfo.h> 34 #include <bcc/Config/Config.h> 35 #include <bcc/ExecutionEngine/CompilerRTSymbolResolver.h> 36 #include <bcc/ExecutionEngine/ObjectLoader.h> 37 #include <bcc/ExecutionEngine/SymbolResolverProxy.h> 38 #include <bcc/ExecutionEngine/SymbolResolvers.h> 39 #include <bcc/Script.h> 40 #include <bcc/Source.h> 41 #include <bcc/Support/CompilerConfig.h> 42 #include <bcc/Support/Initialization.h> 43 #include <bcc/Support/InputFile.h> 44 #include <bcc/Support/OutputFile.h> 45 #include <bcc/Support/TargetCompilerConfigs.h> 46 47 using namespace bcc; 48 49 //===----------------------------------------------------------------------===// 50 // General Options 51 //===----------------------------------------------------------------------===// 52 namespace { 53 54 llvm::cl::list<std::string> 55 OptInputFilenames(llvm::cl::Positional, llvm::cl::OneOrMore, 56 llvm::cl::desc("<input bitcode files>")); 57 58 llvm::cl::opt<std::string> 59 OptOutputFilename("o", llvm::cl::desc("Specify the output filename"), 60 llvm::cl::value_desc("filename")); 61 62 #ifdef TARGET_BUILD 63 const std::string OptTargetTriple(DEFAULT_TARGET_TRIPLE_STRING); 64 #else 65 llvm::cl::opt<std::string> 66 OptTargetTriple("mtriple", 67 llvm::cl::desc("Specify the target triple (default: " 68 DEFAULT_TARGET_TRIPLE_STRING ")"), 69 llvm::cl::init(DEFAULT_TARGET_TRIPLE_STRING), 70 llvm::cl::value_desc("triple")); 71 72 llvm::cl::alias OptTargetTripleC("C", llvm::cl::NotHidden, 73 llvm::cl::desc("Alias for -mtriple"), 74 llvm::cl::aliasopt(OptTargetTriple)); 75 #endif 76 77 //===----------------------------------------------------------------------===// 78 // Compiler Options 79 //===----------------------------------------------------------------------===// 80 llvm::cl::opt<bool> 81 OptPIC("fPIC", llvm::cl::desc("Generate fully relocatable, position independent" 82 " code")); 83 84 llvm::cl::opt<char> 85 OptOptLevel("O", llvm::cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] " 86 "(default: -O2)"), 87 llvm::cl::Prefix, llvm::cl::ZeroOrMore, llvm::cl::init('2')); 88 89 llvm::cl::opt<bool> 90 OptC("c", llvm::cl::desc("Compile and assemble, but do not link.")); 91 92 //===----------------------------------------------------------------------===// 93 // Linker Options 94 //===----------------------------------------------------------------------===// 95 // FIXME: this option will be removed in the future when MCLinker is capable 96 // of generating shared library directly from given bitcode. It only 97 // takes effect when -shared is supplied. 98 llvm::cl::opt<std::string> 99 OptImmObjectOutput("or", llvm::cl::desc("Specify the filename for output the " 100 "intermediate relocatable when linking " 101 "the input bitcode to the shared " 102 "library"), llvm::cl::ValueRequired); 103 104 llvm::cl::opt<bool> 105 OptShared("shared", llvm::cl::desc("Create a shared library from input bitcode " 106 "files")); 107 108 109 //===----------------------------------------------------------------------===// 110 // Loader Options 111 //===----------------------------------------------------------------------===// 112 llvm::cl::opt<bool> 113 OptRunEntry("R", llvm::cl::desc("Run the entry method after successfully load " 114 "and compile.")); 115 116 llvm::cl::opt<std::string> 117 OptEntryFunction("entry-function", llvm::cl::desc("Specify the entry function " 118 "for -R (default: main)"), 119 llvm::cl::value_desc("function"), llvm::cl::init("main")); 120 121 llvm::cl::opt<bool> 122 OptEnableGDB("enable-gdb", llvm::cl::desc("Enable GDB JIT debugging when " 123 "runs the entry method")); 124 125 llvm::cl::list<std::string> 126 OptRuntimeLibs("load", llvm::cl::desc("Specify the shared libraries for " 127 "execution (e.g., -load=c will search " 128 "and load libc.so for execution)"), 129 llvm::cl::ZeroOrMore, llvm::cl::value_desc("namespec")); 130 131 // Override "bcc -version" since the LLVM version information is not correct on 132 // Android build. 133 void BCCVersionPrinter() { 134 llvm::raw_ostream &os = llvm::outs(); 135 os << "libbcc (The Android Open Source Project, http://www.android.com/):\n" 136 << " Build time: " << BuildInfo::GetBuildTime() << "\n" 137 << " Build revision: " << BuildInfo::GetBuildRev() << "\n" 138 << " Build source blob: " << BuildInfo::GetBuildSourceBlob() << "\n" 139 << " Default target: " << DEFAULT_TARGET_TRIPLE_STRING << "\n"; 140 141 os << "\n"; 142 143 os << "LLVM (http://llvm.org/):\n" 144 << " Version: " << PACKAGE_VERSION << "\n"; 145 return; 146 } 147 148 } // end anonymous namespace 149 150 static inline 151 Script *PrepareScript(BCCContext &pContext, 152 const llvm::cl::list<std::string> &pBitcodeFiles) { 153 Script *result = NULL; 154 155 for (unsigned i = 0; i < pBitcodeFiles.size(); i++) { 156 const std::string &input_bitcode = pBitcodeFiles[i]; 157 Source *source = Source::CreateFromFile(pContext, input_bitcode); 158 if (source == NULL) { 159 llvm::errs() << "Failed to load llvm module from file `" << input_bitcode 160 << "'!\n"; 161 return NULL; 162 } 163 164 if (result != NULL) { 165 if (!result->mergeSource(*source, /* pPreserveSource */false)) { 166 llvm::errs() << "Failed to merge the llvm module `" << input_bitcode 167 << "' to compile!\n"; 168 delete source; 169 return NULL; 170 } 171 } else { 172 result = new (std::nothrow) Script(*source); 173 if (result == NULL) { 174 llvm::errs() << "Out of memory when create script for file `" 175 << input_bitcode << "'!\n"; 176 delete source; 177 return NULL; 178 } 179 } 180 } 181 182 return result; 183 } 184 185 static inline 186 bool ConfigCompiler(Compiler &pCompiler) { 187 CompilerConfig *config = NULL; 188 189 #ifdef TARGET_BUILD 190 config = new (std::nothrow) DefaultCompilerConfig(); 191 #else 192 config = new (std::nothrow) CompilerConfig(OptTargetTriple); 193 #endif 194 if (config == NULL) { 195 llvm::errs() << "Out of memory when create the compiler configuration!\n"; 196 return false; 197 } 198 199 // Setup the config according to the valud of command line option. 200 if (OptPIC) { 201 config->setRelocationModel(llvm::Reloc::PIC_); 202 } 203 switch (OptOptLevel) { 204 case '0': config->setOptimizationLevel(llvm::CodeGenOpt::None); break; 205 case '1': config->setOptimizationLevel(llvm::CodeGenOpt::Less); break; 206 case '3': config->setOptimizationLevel(llvm::CodeGenOpt::Aggressive); break; 207 case '2': 208 default: { 209 config->setOptimizationLevel(llvm::CodeGenOpt::Default); 210 break; 211 } 212 } 213 214 Compiler::ErrorCode result = pCompiler.config(*config); 215 216 delete config; 217 218 if (result != Compiler::kSuccess) { 219 llvm::errs() << "Failed to configure the compiler! (detail: " 220 << Compiler::GetErrorString(result) << ")\n"; 221 return false; 222 } 223 224 return true; 225 } 226 227 #define DEFAULT_OUTPUT_PATH "/sdcard/a.out" 228 static inline 229 std::string DetermineOutputFilename(const std::string &pOutputPath) { 230 if (!pOutputPath.empty()) { 231 return pOutputPath; 232 } 233 234 // User doesn't specify the value to -o. 235 if (OptInputFilenames.size() > 1) { 236 llvm::errs() << "Use " DEFAULT_OUTPUT_PATH " for output file!\n"; 237 return DEFAULT_OUTPUT_PATH; 238 } 239 240 // There's only one input bitcode file. 241 const std::string &input_path = OptInputFilenames[0]; 242 llvm::SmallString<200> output_path(input_path); 243 244 llvm::error_code err = llvm::sys::fs::make_absolute(output_path); 245 if (err != llvm::errc::success) { 246 llvm::errs() << "Failed to determine the absolute path of `" << input_path 247 << "'! (detail: " << err.message() << ")\n"; 248 return ""; 249 } 250 251 if (OptC) { 252 // -c was specified. Replace the extension to .o. 253 llvm::sys::path::replace_extension(output_path, "o"); 254 } else { 255 // Use a.out under current working directory when compile executable or 256 // shared library. 257 llvm::sys::path::remove_filename(output_path); 258 llvm::sys::path::append(output_path, "a.out"); 259 } 260 261 return output_path.c_str(); 262 } 263 264 static inline 265 bool CompileScript(Compiler &pCompiler, Script &pScript, 266 const std::string &pOutputPath) { 267 // Open the output file. 268 OutputFile output_file(pOutputPath, FileBase::kTruncate); 269 270 if (output_file.hasError()) { 271 llvm::errs() << "Failed to open the output file `" << pOutputPath 272 << "'! (detail: " << output_file.getErrorMessage() << ")\n"; 273 return false; 274 } 275 276 // Run the compiler. 277 Compiler::ErrorCode result = pCompiler.compile(pScript, output_file); 278 if (result != Compiler::kSuccess) { 279 llvm::errs() << "Fatal error during compilation (detail: " 280 << Compiler::GetErrorString(result) << ".)\n"; 281 return false; 282 } 283 284 return true; 285 } 286 287 static inline 288 bool PrepareRuntimes(std::vector<SymbolResolverInterface *> &pRuntimes) { 289 llvm::SmallVector<const char *, 2> search_paths; 290 291 #ifdef TARGET_BUILD 292 search_paths.push_back("/system/lib/"); 293 #else 294 search_paths.push_back("/lib/"); 295 search_paths.push_back("/usr/lib/"); 296 #endif 297 298 // Most of the following lines comes from llvm/tools/llvm-ld.cpp. 299 for (unsigned i = 0; i < OptRuntimeLibs.size(); i++) { 300 const std::string &lib = OptRuntimeLibs[i]; 301 llvm::sys::Path lib_path; 302 for (llvm::SmallVectorImpl<const char *>::const_iterator 303 search_path_iter = search_paths.begin(), 304 search_path_end = search_paths.end(); 305 search_path_iter != search_path_end; search_path_iter++) { 306 307 lib_path = *search_path_iter; 308 lib_path.appendComponent("lib" + lib); 309 lib_path.appendSuffix(llvm::sys::Path::GetDLLSuffix()); 310 311 if (lib_path.isEmpty()) { 312 if (!lib_path.isDynamicLibrary()) { 313 lib_path = llvm::sys::Path(); 314 } else { 315 break; 316 } 317 } 318 } // for each search_paths 319 if (lib_path.isEmpty()) { 320 // FIXME: llvm::sys::Path::FindLibrary(...) is able to consume 321 // 'const std::string &' instead of 'std::string &'. 322 std::string lib_tmp = lib; 323 lib_path = llvm::sys::Path::FindLibrary(lib_tmp); 324 } 325 if (lib_path.isEmpty()) { 326 llvm::errs() << "Unable to find `lib" << lib << "' for execution!\n"; 327 llvm::DeleteContainerPointers(pRuntimes); 328 return false; 329 } else { 330 DyldSymbolResolver *dyld_resolver = 331 new (std::nothrow) DyldSymbolResolver(lib_path.str().c_str()); 332 333 if (dyld_resolver != NULL) { 334 pRuntimes.push_back(dyld_resolver); 335 } else { 336 llvm::errs() << "Out of memory when load `" << lib_path.str() << "'!\n"; 337 llvm::DeleteContainerPointers(pRuntimes); 338 return false; 339 } 340 } 341 } // for each OptRuntimeLibs 342 343 return true; 344 } 345 346 static inline 347 bool LoadAndRun(const std::string &pOutputExecutable) { 348 SymbolResolverProxy runtime_resolver; 349 350 // Include compiler runtime. 351 CompilerRTSymbolResolver compiler_runtimes; 352 runtime_resolver.chainResolver(compiler_runtimes); 353 354 // Open the output file for execution. 355 InputFile input_exec(pOutputExecutable); 356 if (input_exec.hasError()) { 357 llvm::errs() << "Failed to open the executable `" << pOutputExecutable 358 << "'! (detail: " << input_exec.getErrorMessage() << ")\n"; 359 return false; 360 } 361 362 // Load the runtime libraries given in command line. 363 std::vector<SymbolResolverInterface *> lib_runtimes; 364 if (!PrepareRuntimes(lib_runtimes)) { 365 return false; 366 } 367 368 for (std::vector<SymbolResolverInterface *>::const_iterator 369 librt_iter = lib_runtimes.begin(), librt_end = lib_runtimes.end(); 370 librt_iter != librt_end; librt_iter++) { 371 runtime_resolver.chainResolver(*(*librt_iter)); 372 } 373 374 // Load the output file. 375 ObjectLoader *loader = ObjectLoader::Load(input_exec, runtime_resolver, 376 OptEnableGDB); 377 if (loader == NULL) { 378 llvm::errs() << "Failed to load `" << pOutputExecutable << "'!\n"; 379 llvm::DeleteContainerPointers(lib_runtimes); 380 return false; 381 } 382 383 // Retrieve the address of entry function. 384 void *entry = loader->getSymbolAddress(OptEntryFunction.c_str()); 385 if (entry == NULL) { 386 llvm::errs() << "Couldn't find entry method `" << OptEntryFunction 387 << "' in " << pOutputExecutable << "' for execution!\n"; 388 delete loader; 389 llvm::DeleteContainerPointers(lib_runtimes); 390 return false; 391 } 392 393 // Execute the entry function. 394 int run_result = reinterpret_cast<int (*)()>(entry)(); 395 llvm::errs() << "result: " << run_result << "\n"; 396 397 // Clean up. 398 delete loader; 399 llvm::DeleteContainerPointers(lib_runtimes); 400 401 return true; 402 } 403 404 int main(int argc, char **argv) { 405 llvm::cl::SetVersionPrinter(BCCVersionPrinter); 406 llvm::cl::ParseCommandLineOptions(argc, argv); 407 init::Initialize(); 408 409 BCCContext context; 410 Compiler compiler; 411 412 Script *script = PrepareScript(context, OptInputFilenames); 413 if (script == NULL) { 414 return EXIT_FAILURE; 415 } 416 417 if (!ConfigCompiler(compiler)) { 418 return EXIT_FAILURE; 419 } 420 421 std::string OutputFilename = DetermineOutputFilename(OptOutputFilename); 422 if (OutputFilename.empty()) { 423 return EXIT_FAILURE; 424 } 425 426 if (!CompileScript(compiler, *script, OutputFilename)) { 427 return EXIT_FAILURE; 428 } 429 430 if (OptRunEntry && !LoadAndRun(OutputFilename)) { 431 return EXIT_FAILURE; 432 } 433 434 return EXIT_SUCCESS; 435 } 436