Home | History | Annotate | Download | only in jni
      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