• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TargetAbi(const std::string & abi)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 
BitcodeInfo(const std::string & bc)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 
readWrapper(BitcodeCompiler & compiler)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 
dropExternalLDLibs(SONameMap & map)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.
transferBytesToNumLe(const unsigned char * buffer,size_t n)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 
BitcodeCompiler(const std::string & abi,const std::string & sysroot,const std::string & working_dir,const bool savetemps)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 
~BitcodeCompiler()166 BitcodeCompiler::~BitcodeCompiler() {
167 }
168 
translate()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 
compile()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 
link()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 
runCmd(std::string cmd,bool dump)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 
prepareBitcodes()300 void BitcodeCompiler::prepareBitcodes() {
301   getBitcodeFiles();
302   createSONameMapping();
303 }
304 
createSONameMapping()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