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