1 /* 2 * Copyright 2013, 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 <cassert> 18 #include <cstdlib> 19 #include <fcntl.h> 20 #include <fstream> 21 #include <sstream> 22 #include <stdint.h> 23 #include <unistd.h> 24 #include "Abcc.h" 25 26 #if !defined(_WIN32) 27 #include <sys/mman.h> 28 #else 29 #include "mman.h" 30 #endif 31 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 using namespace abcc; 35 36 TargetAbi::TargetAbi(const std::string &abi) { 37 if (abi == "armeabi-v7a" || abi == "armeabi-v7a-hard") //ToDo: support armeabi-v7a-hard 38 mAbi = ARMEABI_V7A; 39 else if (abi == "armeabi") 40 mAbi = ARMEABI; 41 else if (abi == "x86") 42 mAbi = X86; 43 else if (abi == "mips") 44 mAbi = MIPS; 45 else if (abi == "arm64-v8a") 46 mAbi = ARM64_V8A; 47 else if (abi == "x86_64") 48 mAbi = X86_64; 49 else if (abi == "mips64") 50 mAbi = MIPS64; 51 else { 52 assert (false && "Unknown abi for abcc. Check your --abi flag."); 53 exit (1); 54 } 55 } 56 57 58 BitcodeInfo::BitcodeInfo(const std::string &bc) 59 : mShared(false), mBCPath(bc) { 60 std::string stem = mBCPath.substr(0, mBCPath.rfind(".")); 61 mTargetBCPath = stem + "-target.bc"; 62 mObjPath = stem + ".o"; 63 mOutPath = stem; // If shared, we will add .so after readWrapper 64 mSOName = mBCPath.substr(mBCPath.rfind("/") + 1); 65 } 66 67 int BitcodeInfo::readWrapper(BitcodeCompiler &compiler) { 68 int fd = open(mBCPath.c_str(), O_RDONLY); 69 70 if (fd < 0) { 71 return -1; 72 } 73 74 unsigned char *buf, *p; 75 struct stat st; 76 int bc_offset; 77 78 fstat (fd, &st); 79 buf = (unsigned char *) mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 80 close (fd); 81 82 bc_offset = transferBytesToNumLe (buf+ 8, 4); 83 p = buf + 4 * 7; // Offset to tag fields. 84 85 while (p < buf + bc_offset) { 86 uint16_t tag, length; 87 88 tag = transferBytesToNumLe (p, 2); 89 length = transferBytesToNumLe (p + 2, 2); 90 p += 4; 91 switch (tag) { 92 case 0x4002: // Optimization Level,. e.g., 2 for -O2 93 mOptimizationLevel = transferBytesToNumLe (p, 4); 94 LOGV("Wrapper field: -O%d", mOptimizationLevel); 95 break; 96 97 case 0x5002: // LDFLAGS string 98 LOGV("Wrapper field: %s", p); 99 if (compiler.parseLDFlags (*this, reinterpret_cast<const char *>(p)) != 0) { 100 LOGE("Cannot parse ldflags from wrapper"); 101 close(fd); 102 return -1; 103 } 104 break; 105 106 case 0x4001: // Compiler Version, e.g., 3300 for llvm-3.3. 107 case 0x5001: // Bitcode Type, e.g., rel, shared, or exec. 108 default: 109 // Some field maybe useful, but we use wrapper to encode command line, 110 // this is not necessary for now. 111 break; 112 } 113 114 p += (length + 3) & ~3; // Data are always padding to 4-byte boundary. 115 } 116 117 munmap (buf, st.st_size); 118 return 0; 119 } 120 121 void BitcodeInfo::dropExternalLDLibs(SONameMap &map) { 122 for (SONameMap::iterator i = map.begin(), e = map.end(); i != e; ++i) { 123 BitcodeInfo &info = i->second; 124 for (std::list<std::string>::iterator i_libs = info.mLDLibs.begin(), 125 e_libs = info.mLDLibs.end(); i_libs != e_libs; ) { 126 std::list<std::string>::iterator cur_libs = i_libs++; 127 std::string full_soname = std::string("lib") + *cur_libs + ".so"; 128 if (map.find(full_soname) == map.end()) { 129 LOGV("Drop -l%s from %s for linking order decision", cur_libs->c_str(), info.mSOName.c_str()); 130 info.mLDLibs.erase(cur_libs); 131 } 132 } 133 } 134 } 135 136 // This function reads N bytes from BUFFER in little endian. 137 int BitcodeInfo::transferBytesToNumLe(const unsigned char *buffer, size_t n) { 138 int ret = 0; 139 const unsigned char *p = buffer + n; 140 141 while (--p >= buffer) 142 ret = ret * 0x100 + *p; 143 144 return ret; 145 } 146 147 BitcodeCompiler::BitcodeCompiler(const std::string &abi, const std::string &sysroot, const std::string &working_dir, const bool savetemps) 148 : mAbi(abi), mSysroot(sysroot), mWorkingDir(working_dir), mRet(RET_OK), mSaveTemps(savetemps) { 149 // CFlags 150 mGlobalCFlags = kGlobalTargetAttrs[mAbi].mBaseCFlags; 151 mGlobalCFlags += std::string(" -mtriple=") + kGlobalTargetAttrs[mAbi].mTriple; 152 mGlobalCFlags += " -filetype=obj -mc-relax-all"; 153 mGlobalCFlags += " -relocation-model=pic -code-model=small -use-init-array"; 154 mGlobalCFlags += " -ffunction-sections"; 155 156 // LDFlags 157 mGlobalLDFlags = kGlobalTargetAttrs[mAbi].mBaseLDFlags; 158 mGlobalLDFlags += std::string(" -Bsymbolic -X -m ") + kGlobalTargetAttrs[mAbi].mLinkEmulation; 159 mGlobalLDFlags += std::string(" --sysroot=") + mSysroot; 160 mGlobalLDFlags += " --build-id --eh-frame-hdr"; 161 162 // LDLibs 163 mGlobalLDLibs = " "; 164 } 165 166 BitcodeCompiler::~BitcodeCompiler() { 167 } 168 169 void BitcodeCompiler::translate() { 170 for (std::vector<BitcodeInfo>::const_iterator i = mBitcodeFiles.begin(), 171 e = mBitcodeFiles.end(); i != e; ++i) { 172 const BitcodeInfo &bc = *i; 173 LOGV("Translate bitcode: %s -> %s", bc.mBCPath.c_str(), bc.mTargetBCPath.c_str()); 174 std::string cmd = mExecutableToolsPath[(unsigned)CMD_TRANSLATE]; 175 cmd += std::string(" -arch=") + kGlobalTargetAttrs[mAbi].mArch; 176 cmd += " " + bc.mBCPath + " -o " + bc.mTargetBCPath; 177 runCmd(cmd, /*dump=*/true); 178 if (returnCode() != RET_OK) { 179 mRet = RET_FAIL_TRANSLATE; 180 return; 181 } 182 if (!mSaveTemps) 183 removeIntermediateFile(bc.mBCPath); 184 } 185 } 186 187 void BitcodeCompiler::compile() { 188 for (std::vector<BitcodeInfo>::const_iterator i = mBitcodeFiles.begin(), 189 e = mBitcodeFiles.end(); i != e; ++i) { 190 const BitcodeInfo &bc = *i; 191 LOGV("Compile bitcode: %s -> %s", bc.mTargetBCPath.c_str(), bc.mObjPath.c_str()); 192 std::ostringstream os; 193 194 os << mExecutableToolsPath[(unsigned)CMD_COMPILE] 195 << " " << mGlobalCFlags 196 << " -O" << bc.mOptimizationLevel 197 << " " << bc.mTargetBCPath 198 << " -o " << bc.mObjPath; 199 200 if (bc.mLDFlags.find("-pie") != std::string::npos) 201 os << " -enable-pie"; 202 203 #if ON_DEVICE && VERBOSE 204 Timer t_llc; 205 t_llc.start(); 206 #endif 207 runCmd(os.str(), /*dump=*/true); 208 #if ON_DEVICE && VERBOSE 209 llc_usec += t_llc.stop(); 210 #endif 211 if (returnCode() != RET_OK) { 212 mRet = RET_FAIL_COMPILE; 213 return; 214 } 215 if (!mSaveTemps) 216 removeIntermediateFile(bc.mTargetBCPath); 217 } 218 } 219 220 void BitcodeCompiler::link() { 221 BitcodeInfo::dropExternalLDLibs(mSonameMap); 222 223 while (!mSonameMap.empty()) { 224 SONameMap::iterator i = mSonameMap.begin(), e = mSonameMap.end(); 225 for (; i != e; ++i) { 226 const BitcodeInfo &bc = i->second; 227 228 if (bc.mLDLibs.empty()) { 229 // No internal dependency for this bitcode 230 LOGV("Link: %s -> %s", bc.mObjPath.c_str(), bc.mSOName.c_str()); 231 std::string cmd = mExecutableToolsPath[(unsigned)CMD_LINK]; 232 std::string libdir = (mAbi == TargetAbi::X86_64) ? "lib64" : "lib"; 233 cmd += " " + mGlobalLDFlags; 234 cmd += " " + bc.mLDFlags; 235 if (bc.mShared) { 236 cmd += std::string(" ") + mSysroot + "/usr/" + libdir + "/crtbegin_so.o"; 237 cmd += " -shared " + bc.mObjPath + " -o " + bc.mOutPath; 238 cmd += " -soname " + bc.mSOName; 239 } else { 240 cmd += std::string(" ") + mSysroot + "/usr/" + libdir + "/crtbegin_dynamic.o"; 241 cmd += " " + bc.mObjPath + " -o " + bc.mOutPath; 242 } 243 // Add ldlibs 244 cmd += " " + bc.mLDLocalLibsStr; 245 cmd += " " + mGlobalLDLibs; 246 cmd += " " + bc.mLDLibsStr; 247 cmd += " " + mExecutableToolsPath[(unsigned)CMD_LINK_RUNTIME]; 248 if (bc.mShared) 249 cmd += std::string(" ") + mSysroot + "/usr/" + libdir + "/crtend_so.o"; 250 else 251 cmd += std::string(" ") + mSysroot + "/usr/" + libdir + "/crtend_android.o"; 252 runCmd(cmd, /*dump=*/true); 253 if (returnCode() != RET_OK) 254 return; 255 256 copyRuntime(bc); 257 if (!mSaveTemps) 258 removeIntermediateFile(bc.mObjPath); 259 260 mSonameMap.erase(i); 261 BitcodeInfo::dropExternalLDLibs(mSonameMap); 262 break; // Re-compute 263 } 264 } // for 265 266 if (i == e) { 267 LOGE("Failed to compute linking order: Internal cyclic dependency!"); 268 mRet = RET_FAIL_LINK; 269 return; 270 } 271 } // while 272 } 273 274 void BitcodeCompiler::runCmd(std::string cmd, bool dump) { 275 LOGV("Command: %s", cmd.c_str()); 276 std::string logfilename = mWorkingDir + "/compile_log"; 277 if (dump) { 278 cmd += " > " + logfilename + " 2>&1"; 279 } 280 int ret = system(cmd.c_str()); 281 if (ret != 0) { 282 mRet = RET_FAIL_RUN_CMD; 283 if (dump) { 284 std::ifstream ifs(logfilename.c_str()); 285 std::stringstream sstr; 286 sstr << ifs.rdbuf(); 287 LOGE("Error message: %s", sstr.str().c_str()); 288 std::fstream fout; 289 std::string file = mWorkingDir + "/compile_error"; 290 fout.open(file.c_str(), std::fstream::out | std::fstream::app); 291 fout << "Failed command: " << cmd << "\n"; 292 fout << "Error message: " << sstr.str() << "\n"; 293 fout.close(); 294 } 295 return; 296 } 297 mRet = RET_OK; 298 } 299 300 void BitcodeCompiler::prepareBitcodes() { 301 getBitcodeFiles(); 302 createSONameMapping(); 303 } 304 305 void BitcodeCompiler::createSONameMapping() { 306 for (std::vector<BitcodeInfo>::const_iterator i = mBitcodeFiles.begin(), 307 e = mBitcodeFiles.end(); i != e; ++i) { 308 const BitcodeInfo &info = *i; 309 LOGV("Map soname %s -> %s", info.mSOName.c_str(), info.mBCPath.c_str()); 310 mSonameMap[info.mSOName] = info; 311 } 312 } 313