bool LTOCodeGenerator::assemble(const std::string& asmPath, const std::string& objPath, std::string& errMsg) { // find compiler driver const sys::Path gcc = sys::Program::FindProgramByName("gcc"); if ( gcc.isEmpty() ) { errMsg = "can't locate gcc"; return true; } // build argument list std::vector<const char*> args; std::string targetTriple = _linker.getModule()->getTargetTriple(); args.push_back(gcc.c_str()); if ( targetTriple.find("darwin") != targetTriple.size() ) { if (strncmp(targetTriple.c_str(), "i686-apple-", 11) == 0) { args.push_back("-arch"); args.push_back("i386"); } else if (strncmp(targetTriple.c_str(), "x86_64-apple-", 13) == 0) { args.push_back("-arch"); args.push_back("x86_64"); } else if (strncmp(targetTriple.c_str(), "powerpc-apple-", 14) == 0) { args.push_back("-arch"); args.push_back("ppc"); } else if (strncmp(targetTriple.c_str(), "powerpc64-apple-", 16) == 0) { args.push_back("-arch"); args.push_back("ppc64"); } } args.push_back("-c"); args.push_back("-x"); args.push_back("assembler"); args.push_back("-o"); args.push_back(objPath.c_str()); args.push_back(asmPath.c_str()); args.push_back(0); // invoke assembler if ( sys::Program::ExecuteAndWait(gcc, &args[0], 0, 0, 0, 0, &errMsg) ) { errMsg = "error in assembly"; return true; } return false; // success }
///Link all modules together and optimize them using IPO. Generate /// native object file using OutputFilename /// Return appropriate LTOStatus. enum LTOStatus LTO::optimizeModules(const std::string &OutputFilename, std::vector<const char *> &exportList, std::string &targetTriple, bool saveTemps, const char *FinalOutputFilename) { if (modules.empty()) return LTO_NO_WORK; std::ios::openmode io_mode = std::ios::out | std::ios::trunc | std::ios::binary; std::string *errMsg = NULL; Module *bigOne = modules[0]; Linker theLinker("LinkTimeOptimizer", bigOne, false); for (unsigned i = 1, e = modules.size(); i != e; ++i) if (theLinker.LinkModules(bigOne, modules[i], errMsg)) return LTO_MODULE_MERGE_FAILURE; // all modules have been handed off to the linker. modules.clear(); sys::Path FinalOutputPath(FinalOutputFilename); FinalOutputPath.eraseSuffix(); switch(CGModel) { case LTO_CGM_Dynamic: Target->setRelocationModel(Reloc::PIC_); break; case LTO_CGM_DynamicNoPIC: Target->setRelocationModel(Reloc::DynamicNoPIC); break; case LTO_CGM_Static: Target->setRelocationModel(Reloc::Static); break; } if (saveTemps) { std::string tempFileName(FinalOutputPath.c_str()); tempFileName += "0.bc"; std::ofstream Out(tempFileName.c_str(), io_mode); WriteBitcodeToFile(bigOne, Out); } // Strip leading underscore because it was added to match names // seen by linker. for (unsigned i = 0, e = exportList.size(); i != e; ++i) { const char *name = exportList[i]; NameToSymbolMap::iterator itr = allSymbols.find(name); if (itr != allSymbols.end()) exportList[i] = allSymbols[name]->getName(); } std::string ErrMsg; sys::Path TempDir = sys::Path::GetTemporaryDirectory(&ErrMsg); if (TempDir.isEmpty()) { cerr << "lto: " << ErrMsg << "\n"; return LTO_WRITE_FAILURE; } sys::Path tmpAsmFilePath(TempDir); if (!tmpAsmFilePath.appendComponent("lto")) { cerr << "lto: " << ErrMsg << "\n"; TempDir.eraseFromDisk(true); return LTO_WRITE_FAILURE; } if (tmpAsmFilePath.createTemporaryFileOnDisk(true, &ErrMsg)) { cerr << "lto: " << ErrMsg << "\n"; TempDir.eraseFromDisk(true); return LTO_WRITE_FAILURE; } sys::RemoveFileOnSignal(tmpAsmFilePath); std::ofstream asmFile(tmpAsmFilePath.c_str(), io_mode); if (!asmFile.is_open() || asmFile.bad()) { if (tmpAsmFilePath.exists()) { tmpAsmFilePath.eraseFromDisk(); TempDir.eraseFromDisk(true); } return LTO_WRITE_FAILURE; } enum LTOStatus status = optimize(bigOne, asmFile, exportList); asmFile.close(); if (status != LTO_OPT_SUCCESS) { tmpAsmFilePath.eraseFromDisk(); TempDir.eraseFromDisk(true); return status; } if (saveTemps) { std::string tempFileName(FinalOutputPath.c_str()); tempFileName += "1.bc"; std::ofstream Out(tempFileName.c_str(), io_mode); WriteBitcodeToFile(bigOne, Out); } targetTriple = bigOne->getTargetTriple(); // Run GCC to assemble and link the program into native code. // // Note: // We can't just assemble and link the file with the system assembler // and linker because we don't know where to put the _start symbol. // GCC mysteriously knows how to do it. const sys::Path gcc = sys::Program::FindProgramByName("gcc"); if (gcc.isEmpty()) { tmpAsmFilePath.eraseFromDisk(); TempDir.eraseFromDisk(true); return LTO_ASM_FAILURE; } std::vector<const char*> args; args.push_back(gcc.c_str()); if (strncmp(targetTriple.c_str(), "i686-apple-", 11) == 0) { args.push_back("-arch"); args.push_back("i386"); } if (strncmp(targetTriple.c_str(), "x86_64-apple-", 13) == 0) { args.push_back("-arch"); args.push_back("x86_64"); } if (strncmp(targetTriple.c_str(), "powerpc-apple-", 14) == 0) { args.push_back("-arch"); args.push_back("ppc"); } if (strncmp(targetTriple.c_str(), "powerpc64-apple-", 16) == 0) { args.push_back("-arch"); args.push_back("ppc64"); } args.push_back("-c"); args.push_back("-x"); args.push_back("assembler"); args.push_back("-o"); args.push_back(OutputFilename.c_str()); args.push_back(tmpAsmFilePath.c_str()); args.push_back(0); if (sys::Program::ExecuteAndWait(gcc, &args[0], 0, 0, 0, 0, &ErrMsg)) { cerr << "lto: " << ErrMsg << "\n"; return LTO_ASM_FAILURE; } tmpAsmFilePath.eraseFromDisk(); TempDir.eraseFromDisk(true); return LTO_OPT_SUCCESS; }