]> git.saurik.com Git - apple/ld64.git/blob - src/ld/passes/bitcode_bundle.cpp
9e1da55cf10789850ea7f7bb6a65c3970a1e1d91
[apple/ld64.git] / src / ld / passes / bitcode_bundle.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2010 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <fcntl.h>
28 #include <vector>
29 #include <dlfcn.h>
30 #include <math.h>
31 #include <unistd.h>
32 #include <time.h>
33 #include <unordered_map>
34
35 #include "llvm-c/lto.h"
36 // c header
37 extern "C" {
38 #include <xar/xar.h>
39 }
40
41 #include "bitcode_bundle.h"
42
43 #include "Options.h"
44 #include "ld.hpp"
45 #include "Bitcode.hpp"
46 #include "macho_relocatable_file.h"
47
48
49 namespace ld {
50 namespace passes {
51 namespace bitcode_bundle {
52
53 class BitcodeTempFile;
54
55 class BitcodeAtom : public ld::Atom {
56 static ld::Section bitcodeBundleSection;
57 public:
58 BitcodeAtom();
59 BitcodeAtom(BitcodeTempFile& tempfile);
60 ~BitcodeAtom() { free(_content); }
61 virtual ld::File* file() const { return NULL; }
62 virtual const char* name() const { return "bitcode bundle"; }
63 virtual uint64_t size() const { return _size; }
64 virtual uint64_t objectAddress() const { return 0; }
65 virtual void copyRawContent(uint8_t buffer[]) const
66 { memcpy(buffer, _content, _size); }
67 virtual void setScope(Scope) { }
68
69 private:
70 uint8_t* _content;
71 uint64_t _size;
72 };
73
74 ld::Section BitcodeAtom::bitcodeBundleSection("__LLVM", "__bundle", ld::Section::typeSectCreate);
75
76 class BitcodeTempFile {
77 public:
78 BitcodeTempFile(const char* path, bool deleteAfterRead);
79 ~BitcodeTempFile();
80 uint8_t* getContent() const { return _content; }
81 uint64_t getSize() const { return _size; }
82 private:
83 friend class BitcodeAtom;
84 const char* _path;
85 uint8_t* _content;
86 uint64_t _size;
87 bool _deleteAfterRead;
88 };
89
90 class BitcodeObfuscator {
91 public:
92 BitcodeObfuscator();
93 ~BitcodeObfuscator();
94
95 void addMustPreserveSymbols(const char* name);
96 void bitcodeHideSymbols(ld::Bitcode* bc, const char* filePath, const char* outputPath);
97 void writeSymbolMap(const char* outputPath);
98 private:
99 typedef void (*lto_codegen_func_t) (lto_code_gen_t);
100 typedef void (*lto_codegen_output_t) (lto_code_gen_t, const char*);
101
102 lto_code_gen_t _obfuscator;
103 lto_codegen_func_t _lto_hide_symbols;
104 lto_codegen_func_t _lto_reset_context;
105 lto_codegen_output_t _lto_write_reverse_map;
106 };
107
108 class FileHandler {
109 // generic handler for files in a bundle
110 public:
111 virtual void populateMustPreserveSymbols(BitcodeObfuscator* _obfuscator) { }
112 virtual void obfuscateAndWriteToPath(BitcodeObfuscator* _obfuscator, const char* path) { };
113 xar_file_t getXARFile() { return _xar_file; }
114
115 FileHandler(char* content, size_t size) :
116 _parent(NULL), _xar_file(NULL), _file_buffer(content), _file_size(size) { } // eager construct
117 FileHandler(xar_t parent, xar_file_t xar_file) :
118 _parent(parent), _xar_file(xar_file), _file_buffer(NULL), _file_size(0) { } // lazy construct
119 virtual ~FileHandler() { }
120
121 protected:
122 void initFile() {
123 if (!_file_buffer) {
124 if (xar_extract_tobuffersz(_parent, _xar_file, &_file_buffer, &_file_size) != 0)
125 throwf("could not extract files from bitcode bundle");
126 }
127 }
128 void destroyFile() {
129 if (_parent)
130 free(_file_buffer);
131 }
132
133 xar_t _parent;
134 xar_file_t _xar_file;
135 char* _file_buffer;
136 size_t _file_size;
137 };
138
139 class BundleHandler : public FileHandler {
140 public:
141 BundleHandler(char* bundleContent, size_t bundleSize, const Options& options) :
142 FileHandler(bundleContent, bundleSize), _xar(NULL), _temp_dir(NULL), _options(options) { }
143 BundleHandler(xar_t parent, xar_file_t xar_file, const Options& options) :
144 FileHandler(parent, xar_file), _xar(NULL), _temp_dir(NULL), _options(options) { }
145
146 ~BundleHandler();
147
148 virtual void populateMustPreserveSymbols(BitcodeObfuscator* obfuscator) override;
149 virtual void obfuscateAndWriteToPath(BitcodeObfuscator* obfuscator, const char* path) override;
150
151 private:
152 void init();
153 void copyXARProp(xar_file_t src, xar_file_t dst);
154
155 xar_t _xar;
156 char* _temp_dir;
157 const Options& _options;
158 std::vector<FileHandler*> _handlers;
159 };
160
161 class BitcodeHandler : public FileHandler {
162 public:
163 BitcodeHandler(char* content, size_t size) : FileHandler(content, size) { }
164 BitcodeHandler(xar_t parent, xar_file_t xar_file) : FileHandler(parent, xar_file) { }
165
166 ~BitcodeHandler();
167
168 virtual void populateMustPreserveSymbols(BitcodeObfuscator* obfuscator) override { } // Don't need to preserve symbols
169 virtual void obfuscateAndWriteToPath(BitcodeObfuscator* obfuscator, const char* path) override;
170 };
171
172 class ObjectHandler : public FileHandler {
173 public:
174 ObjectHandler(char* content, size_t size) :
175 FileHandler(content, size) { }
176 ObjectHandler(xar_t parent, xar_file_t xar_file) :
177 FileHandler(parent, xar_file) { }
178
179 ~ObjectHandler();
180
181 void populateMustPreserveSymbols(BitcodeObfuscator* obfuscator) override;
182 void obfuscateAndWriteToPath(BitcodeObfuscator* obfuscator, const char* path) override;
183
184 };
185
186
187 class BitcodeBundle {
188 public:
189 BitcodeBundle(const Options& opts, ld::Internal& internal) :
190 _options(opts), _state(internal) { }
191 ~BitcodeBundle() { }
192 void doPass();
193
194 private:
195 const Options& _options;
196 ld::Internal& _state;
197 };
198
199 BitcodeAtom::BitcodeAtom()
200 : ld::Atom(bitcodeBundleSection,
201 ld::Atom::definitionRegular, ld::Atom::combineNever,
202 ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
203 ld::Atom::symbolTableNotIn, true, false, false, ld::Atom::Alignment(0)),
204 _size(1)
205 {
206 // initialize a marker of 1 byte
207 _content = (uint8_t*)calloc(1,1);
208 }
209
210 BitcodeAtom::BitcodeAtom(BitcodeTempFile& tempfile)
211 : ld::Atom(bitcodeBundleSection,
212 ld::Atom::definitionRegular, ld::Atom::combineNever,
213 ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
214 ld::Atom::symbolTableNotIn, true, false, false, ld::Atom::Alignment(0)),
215 _content(tempfile._content), _size(tempfile._size)
216 {
217 // Creating the Atom will transfer the ownership of the buffer from Tempfile to Atom
218 tempfile._content = NULL;
219 }
220
221 BitcodeTempFile::BitcodeTempFile(const char* path, bool deleteAfterRead = true)
222 : _path(path), _deleteAfterRead(deleteAfterRead)
223 {
224 int fd = ::open(path, O_RDONLY, 0);
225 if ( fd == -1 )
226 throwf("could not open bitcode temp file: %s", path);
227 struct stat stat_buf;
228 ::fstat(fd, &stat_buf);
229 _content = (uint8_t*)malloc(stat_buf.st_size);
230 if ( _content == NULL )
231 throwf("could not process bitcode temp file: %s", path);
232 if ( read(fd, _content, stat_buf.st_size) != stat_buf.st_size )
233 throwf("could not read bitcode temp file: %s", path);
234 ::close(fd);
235 _size = stat_buf.st_size;
236 }
237
238 BitcodeTempFile::~BitcodeTempFile()
239 {
240 free(_content);
241 if ( _deleteAfterRead ) {
242 if ( ::unlink(_path) != 0 )
243 throwf("could not remove temp file: %s", _path);
244 }
245 }
246
247 BitcodeObfuscator::BitcodeObfuscator()
248 {
249 // check if apple internal libLTO is used
250 if ( ::lto_get_version() == NULL )
251 throwf("libLTO is not loaded");
252 _lto_hide_symbols = (lto_codegen_func_t) dlsym(RTLD_DEFAULT, "lto_codegen_hide_symbols");
253 _lto_write_reverse_map = (lto_codegen_output_t) dlsym(RTLD_DEFAULT, "lto_codegen_write_symbol_reverse_map");
254 _lto_reset_context = (lto_codegen_func_t) dlsym(RTLD_DEFAULT, "lto_codegen_reset_context");
255 if ( _lto_hide_symbols == NULL || _lto_write_reverse_map == NULL ||
256 _lto_reset_context == NULL || ::lto_api_version() < 14 )
257 throwf("loaded libLTO doesn't support -bitcode_hide_symbols: %s", ::lto_get_version());
258 _obfuscator = ::lto_codegen_create_in_local_context();
259 #if LTO_API_VERSION >= 14
260 lto_codegen_set_should_internalize(_obfuscator, false);
261 #endif
262 }
263
264 BitcodeObfuscator::~BitcodeObfuscator()
265 {
266 ::lto_codegen_dispose(_obfuscator);
267 }
268
269 void BitcodeObfuscator::addMustPreserveSymbols(const char* name)
270 {
271 ::lto_codegen_add_must_preserve_symbol(_obfuscator, name);
272 }
273
274 void BitcodeObfuscator::bitcodeHideSymbols(ld::Bitcode* bc, const char* filePath, const char* outputPath)
275 {
276 #if LTO_API_VERSION >= 13 && LTO_APPLE_INTERNAL
277 lto_module_t module = ::lto_module_create_in_codegen_context(bc->getContent(), bc->getSize(), filePath, _obfuscator);
278 if ( module == NULL )
279 throwf("object contains invalid bitcode: %s", filePath);
280 ::lto_codegen_set_module(_obfuscator, module);
281 (*_lto_hide_symbols)(_obfuscator);
282 #if LTO_API_VERSION >= 15
283 ::lto_codegen_set_should_embed_uselists(_obfuscator, true);
284 #endif
285 ::lto_codegen_write_merged_modules(_obfuscator, outputPath);
286 (*_lto_reset_context)(_obfuscator);
287 #endif
288 return;
289 }
290
291 void BitcodeObfuscator::writeSymbolMap(const char *outputPath)
292 {
293 (*_lto_write_reverse_map)(_obfuscator, outputPath);
294 }
295
296 BundleHandler::~BundleHandler()
297 {
298 // free buffers
299 destroyFile();
300 // free handlers
301 for (auto handler : _handlers)
302 delete handler;
303
304 // delete temp file if not -save-temps
305 if ( _xar ) {
306 xar_close(_xar);
307 std::string oldXARPath = std::string(_temp_dir) + std::string("/bundle.xar");
308 if ( !_options.saveTempFiles() && ::unlink(oldXARPath.c_str()) != 0)
309 warning("could not delete temp file: %s", oldXARPath.c_str());
310 }
311
312 if ( _temp_dir ) {
313 if ( !_options.saveTempFiles() && ::rmdir(_temp_dir) != 0 )
314 warning("could not delete temp directory: %s", _temp_dir);
315 free(_temp_dir);
316 }
317 }
318
319 BitcodeHandler::~BitcodeHandler()
320 {
321 destroyFile();
322 }
323
324 ObjectHandler::~ObjectHandler()
325 {
326 destroyFile();
327 }
328
329 void BundleHandler::init()
330 {
331 if ( _xar != NULL )
332 return;
333
334 // make temp directory
335 const char* finalOutput = _options.outputFilePath();
336 _temp_dir = (char*)malloc(PATH_MAX * sizeof(char));
337 // Check outputFilePath.bundle-XXXXXX/YYYYYYYYYY.bc will not over flow PATH_MAX
338 // If so, fall back to /tmp
339 if ( strlen(finalOutput) + 30 >= PATH_MAX )
340 sprintf(_temp_dir, "/tmp/ld.bundle.XXXXXX");
341 else
342 sprintf(_temp_dir, "%s.bundle.XXXXXX", finalOutput);
343 ::mkdtemp(_temp_dir);
344
345 // write the bundle to the temp_directory
346 initFile();
347 std::string oldXARPath = std::string(_temp_dir) + std::string("/bundle.xar");
348 int f = ::open(oldXARPath.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
349 if ( f == -1 )
350 throwf("could not write file to temp directory: %s", _temp_dir);
351 if ( ::write(f, _file_buffer, _file_size) != (int)_file_size )
352 throwf("failed to write content to temp file: %s", oldXARPath.c_str());
353 ::close(f);
354
355 // read the xar file
356 _xar = xar_open(oldXARPath.c_str(), READ);
357
358 // Init the vector of handler
359 xar_iter_t iter = xar_iter_new();
360 if ( !iter )
361 throwf("could not aquire iterator for the bitcode bundle");
362 for ( xar_file_t f = xar_file_first(_xar, iter); f; f = xar_file_next(iter) ) {
363 const char* filetype = NULL;
364 if ( xar_prop_get(f, "file-type", &filetype) != 0 )
365 throwf("could not get the file type for the bitcode bundle");
366 if ( strcmp(filetype, "Bundle") == 0 )
367 _handlers.push_back(new BundleHandler(_xar, f, _options));
368 else if ( strcmp(filetype, "Object") == 0 )
369 _handlers.push_back(new ObjectHandler(_xar, f));
370 else if ( strcmp(filetype, "Bitcode") == 0 || strcmp(filetype, "LTO") == 0 )
371 _handlers.push_back(new BitcodeHandler(_xar, f));
372 else
373 assert(0 && "Unknown file type");
374 }
375 xar_iter_free(iter);
376 }
377
378 void BundleHandler::copyXARProp(xar_file_t src, xar_file_t dst)
379 {
380 // copy the property in the XAR.
381 // Since XAR API can only get the first value from the key,
382 // Deleting the value after read.
383 int i = 0;
384 while (1) {
385 xar_iter_t p = xar_iter_new();
386 const char* key = xar_prop_first(src, p);
387 for (int x = 0; x < i; x++)
388 key = xar_prop_next(p);
389 if ( !key )
390 break;
391 const char* val = NULL;
392 xar_prop_get(src, key, &val);
393 if ( // Info from bitcode files
394 strcmp(key, "file-type") == 0 ||
395 strcmp(key, "clang/cmd") == 0 ||
396 strcmp(key, "swift/cmd") == 0 ||
397 // Info from linker subdoc
398 strcmp(key, "version") == 0 ||
399 strcmp(key, "architecture") == 0 ||
400 strcmp(key, "hide-symbols") == 0 ||
401 strcmp(key, "platform") == 0 ||
402 strcmp(key, "sdkversion") == 0 ||
403 strcmp(key, "dylibs/lib") == 0 ||
404 strcmp(key, "link-options/option") == 0 ) {
405 xar_prop_create(dst, key, val);
406 xar_prop_unset(src, key);
407 } else
408 ++ i;
409 xar_iter_free(p);
410 }
411 }
412
413 void BundleHandler::populateMustPreserveSymbols(BitcodeObfuscator* obfuscator)
414 {
415 // init the handler
416 if ( _xar == NULL )
417 init();
418
419 // iterate through the XAR file and add symbols
420 for ( auto handler : _handlers )
421 handler->populateMustPreserveSymbols(obfuscator);
422 }
423
424 void ObjectHandler::populateMustPreserveSymbols(BitcodeObfuscator* obfuscator)
425 {
426 initFile();
427 // Parse the object file and add the symbols
428 std::vector<const char*> symbols;
429 if ( mach_o::relocatable::getNonLocalSymbols((uint8_t*)_file_buffer, symbols) ) {
430 for ( auto sym : symbols )
431 obfuscator->addMustPreserveSymbols(sym);
432 }
433 }
434
435 void BundleHandler::obfuscateAndWriteToPath(BitcodeObfuscator *obfuscator, const char *path)
436 {
437 // init the handler
438 if ( _xar == NULL )
439 init();
440
441 // creating the new xar
442 xar_t x = xar_open(path, WRITE);
443 if (x == NULL)
444 throwf("could not open output bundle to write %s", path);
445 // Disable compression
446 if (xar_opt_set(x, XAR_OPT_COMPRESSION, XAR_OPT_VAL_NONE) != 0)
447 throwf("could not disable compression for bitcode bundle");
448
449 // iterate through the XAR file and obfuscate
450 for ( auto handler : _handlers ) {
451 const char* name = NULL;
452 xar_file_t f = handler->getXARFile();
453 if ( xar_prop_get(f, "name", &name) != 0 )
454 throwf("could not get the name of the file from bitcode bundle");
455 char outputPath[PATH_MAX];
456 sprintf(outputPath, "%s/%s", _temp_dir, name);
457 handler->obfuscateAndWriteToPath(obfuscator, outputPath);
458 BitcodeTempFile* bcOut = new BitcodeTempFile(outputPath, !_options.saveTempFiles());
459 xar_file_t bcEntry = xar_add_frombuffer(x, NULL, name, (char*)bcOut->getContent(), bcOut->getSize());
460 copyXARProp(f, bcEntry);
461 delete bcOut;
462 }
463
464 // copy the subdoc as well
465 for ( xar_subdoc_t sub = xar_subdoc_first(_xar); sub; sub = xar_subdoc_next(sub) ) {
466 const char *name = xar_subdoc_name(sub);
467 xar_subdoc_t newDoc = xar_subdoc_new(x, name);
468 copyXARProp((xar_file_t) sub, (xar_file_t) newDoc);
469 }
470 xar_close(x);
471 }
472
473 void BitcodeHandler::obfuscateAndWriteToPath(BitcodeObfuscator *obfuscator, const char *path)
474 {
475 initFile();
476 ld::Bitcode bc((uint8_t*)_file_buffer, _file_size);
477 obfuscator->bitcodeHideSymbols(&bc, path, path);
478 }
479
480 void ObjectHandler::obfuscateAndWriteToPath(BitcodeObfuscator *obfuscator, const char *path)
481 {
482 initFile();
483 int f = ::open(path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
484 if ( f == -1 || ::write(f, _file_buffer, _file_size) != (int)_file_size )
485 throwf("failed to write content to temp file: %s", path);
486 ::close(f);
487 }
488
489 void BitcodeBundle::doPass()
490 {
491 if ( _options.bitcodeKind() == Options::kBitcodeStrip ||
492 _options.bitcodeKind() == Options::kBitcodeAsData )
493 // if emit no bitcode or emit bitcode segment as data, no need to generate bundle.
494 return;
495 else if ( _state.embedMarkerOnly || _options.bitcodeKind() == Options::kBitcodeMarker ) {
496 // if the bitcode is just a marker,
497 // the executable will be created without bitcode section.
498 // Otherwise, create a marker.
499 if( _options.outputKind() != Options::kDynamicExecutable &&
500 _options.outputKind() != Options::kStaticExecutable ) {
501 BitcodeAtom* marker = new BitcodeAtom();
502 _state.addAtom(*marker);
503 }
504 return;
505 }
506
507 if ( _state.filesWithBitcode.empty() && _state.ltoBitcodePath.empty() )
508 return;
509 // Create tempdir, the temp directory should be OUTPUT/main.exe.bundle-XXXXXX
510 char tempdir[PATH_MAX];
511 const char* finalOutput = _options.outputFilePath();
512 // Check outputFilePath.bundle-XXXXXX/YYYYYYYYYY.bc will not over flow PATH_MAX
513 // If so, fall back to /tmp
514 if ( strlen(finalOutput) + 30 >= PATH_MAX )
515 sprintf(tempdir, "/tmp/ld.bundle.XXXXXX");
516 else
517 sprintf(tempdir, "%s.bundle.XXXXXX", finalOutput);
518 ::mkdtemp(tempdir);
519 // A lookup map to look for BundlerHandler base on filename
520 std::unordered_map<std::string, BundleHandler*> handlerMap;
521
522 BitcodeObfuscator* obfuscator = _options.hideSymbols() ? new BitcodeObfuscator() : NULL;
523 // Build must keep symbols if we need to hide all the symbols
524 if ( _options.hideSymbols() ) {
525 // Go through all the atoms and decide if it should be obfuscated.
526 // The following symbols are kept:
527 // 1. entry point
528 // 2. undefined symbols
529 // 3. symbols must not be stripped
530 // 4. all the globals if the globals are dead_strip root (ex. dylibs)
531 // 5. there is an exported symbol list suggests the symbol should be exported
532 // 6. the special symbols supplied by linker
533 for ( auto &sect : _state.sections ) {
534 for ( auto &atom : sect->atoms ) {
535 if ( atom == _state.entryPoint ||
536 atom->definition() == ld::Atom::definitionProxy ||
537 atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip ||
538 ( _options.allGlobalsAreDeadStripRoots() && atom->scope() == ld::Atom::scopeGlobal ) ||
539 ( _options.hasExportRestrictList() && _options.shouldExport(atom->name())) )
540 obfuscator->addMustPreserveSymbols(atom->name());
541 }
542 }
543 // If there are assembly sources, add globals and undefined symbols from them as well
544 for ( auto &f : _state.filesWithBitcode ) {
545 if ( ld::AsmBitcode* ab = dynamic_cast<ld::AsmBitcode*>(f->getBitcode()) ) {
546 ObjectHandler objHandler((char*)ab->getContent(), ab->getSize());
547 objHandler.populateMustPreserveSymbols(obfuscator);
548 } else if ( ld::BundleBitcode* bb = dynamic_cast<ld::BundleBitcode*>(f->getBitcode()) ) {
549 BundleHandler* bh = new BundleHandler((char*)bb->getContent(), bb->getSize(), _options);
550 bh->populateMustPreserveSymbols(obfuscator);
551 handlerMap.emplace(std::string(f->path()), bh);
552 }
553 }
554 // special symbols supplied by linker
555 obfuscator->addMustPreserveSymbols("___dso_handle");
556 obfuscator->addMustPreserveSymbols("__mh_execute_header");
557 obfuscator->addMustPreserveSymbols("__mh_dylib_header");
558 obfuscator->addMustPreserveSymbols("__mh_bundle_header");
559 obfuscator->addMustPreserveSymbols("__mh_dylinker_header");
560 obfuscator->addMustPreserveSymbols("__mh_object_header");
561 obfuscator->addMustPreserveSymbols("__mh_preload_header");
562 }
563
564 // Open XAR output
565 xar_t x;
566 char outFile[PATH_MAX];
567 sprintf(outFile, "%s/bundle.xar", tempdir);
568
569 // By default, it uses gzip to compress and SHA1 as checksum
570 x = xar_open(outFile, WRITE);
571 if (x == NULL)
572 throwf("could not open output bundle to write %s", outFile);
573 // Disable compression
574 if (xar_opt_set(x, XAR_OPT_COMPRESSION, XAR_OPT_VAL_NONE) != 0)
575 throwf("could not disable compression for bitcode bundle");
576
577 // Sort all the object file according to oridnal order
578 std::sort(_state.filesWithBitcode.begin(), _state.filesWithBitcode.end(),
579 [](const ld::relocatable::File* a, const ld::relocatable::File* b) {
580 return a->ordinal() < b->ordinal();
581 });
582
583 // Copy each bitcode file into archive
584 int index = 1;
585 char formatString[10];
586 sprintf(formatString, "%%0%ud", (unsigned int)log10(_state.filesWithBitcode.size()) + 1);
587 for ( auto &obj : _state.filesWithBitcode ) {
588 assert(obj->getBitcode() != NULL && "File should contain bitcode");
589 char outFilePath[16];
590 sprintf(outFilePath, formatString, index++);
591 if ( ld::LLVMBitcode* llvmbc = dynamic_cast<ld::LLVMBitcode*>(obj->getBitcode()) ) {
592 // Handle clang and swift bitcode
593 xar_file_t bcFile = NULL;
594 if ( _options.hideSymbols() && !llvmbc->isMarker() ) { // dont strip if it is just a marker
595 char tempfile[PATH_MAX];
596 sprintf(tempfile, "%s/%s.bc", tempdir, outFilePath);
597 obfuscator->bitcodeHideSymbols(llvmbc, obj->path(), tempfile);
598 BitcodeTempFile* bcTemp = new BitcodeTempFile(tempfile, !_options.saveTempFiles());
599 bcFile = xar_add_frombuffer(x, NULL, outFilePath, (char*)bcTemp->getContent(), bcTemp->getSize());
600 delete bcTemp;
601 } else {
602 bcFile = xar_add_frombuffer(x, NULL, outFilePath, (char*)const_cast<uint8_t*>(llvmbc->getContent()), llvmbc->getSize());
603 }
604 if ( bcFile == NULL )
605 throwf("could not add bitcode from %s to bitcode bundle", obj->path());
606 if ( xar_prop_set(bcFile, "file-type", "Bitcode") != 0 )
607 throwf("could not set bitcode property for %s in bitcode bundle", obj->path());
608 // Write commandline options
609 std::string tagName = std::string(llvmbc->getBitcodeName()) + std::string("/cmd");
610 for ( uint32_t i = 0; i < llvmbc->getCmdSize(); ++i ) {
611 if ( i == 0 || llvmbc->getCmdline()[i-1] == '\0' ) {
612 if ( xar_prop_create(bcFile, tagName.c_str(), (const char *)llvmbc->getCmdline() + i) )
613 throwf("could not set cmdline to XAR file");
614 }
615 }
616 }
617 else if ( ld::BundleBitcode* bundlebc = dynamic_cast<ld::BundleBitcode*>(obj->getBitcode()) ) {
618 xar_file_t bundleFile = NULL;
619 if ( _options.hideSymbols() && !bundlebc->isMarker() ) { // dont strip if it is just a marker
620 char tempfile[PATH_MAX];
621 sprintf(tempfile, "%s/%s.xar", tempdir, outFilePath);
622 auto search = handlerMap.find(std::string(obj->path()));
623 assert( search != handlerMap.end() && "Cannot find handler");
624 search->second->obfuscateAndWriteToPath(obfuscator, tempfile);
625 BitcodeTempFile* bundleTemp = new BitcodeTempFile(tempfile, !_options.saveTempFiles());
626 bundleFile = xar_add_frombuffer(x, NULL, outFilePath, (char*)bundleTemp->getContent(), bundleTemp->getSize());
627 delete bundleTemp;
628 } else {
629 bundleFile = xar_add_frombuffer(x, NULL, outFilePath,
630 (char*)const_cast<uint8_t*>(bundlebc->getContent()),
631 bundlebc->getSize());
632 }
633 if ( bundleFile == NULL )
634 throwf("could not add bitcode from the bundle %s to bitcode bundle", obj->path());
635 if ( xar_prop_set(bundleFile, "file-type", "Bundle") != 0 )
636 throwf("could not set bundle property for %s in bitcode bundle", obj->path());
637 }
638 else if ( ld::AsmBitcode* asmbc = dynamic_cast<ld::AsmBitcode*>(obj->getBitcode()) ) {
639 xar_file_t objFile = xar_add_frombuffer(x, NULL, outFilePath, (char*)asmbc->getContent(), asmbc->getSize());
640 if ( objFile == NULL )
641 throwf("could not add obj file %s to bitcode bundle", obj->path());
642 if ( xar_prop_set(objFile, "file-type", "Object") != 0 )
643 throwf("could not set object property for %s in bitcode bundle", obj->path());
644 }
645 else {
646 assert(false && "Unknown bitcode");
647 }
648 }
649
650 // Write merged LTO bitcode
651 if ( !_state.ltoBitcodePath.empty() ) {
652 xar_file_t ltoFile = NULL;
653 BitcodeTempFile* ltoTemp = new BitcodeTempFile(_state.ltoBitcodePath.c_str(), !_options.saveTempFiles());
654 if ( _options.hideSymbols() ) {
655 ld::Bitcode ltoBitcode(ltoTemp->getContent(), ltoTemp->getSize());
656 char ltoTempFile[PATH_MAX];
657 sprintf(ltoTempFile, "%s/lto.bc", tempdir);
658 obfuscator->bitcodeHideSymbols(&ltoBitcode, _state.ltoBitcodePath.c_str(), ltoTempFile);
659 BitcodeTempFile* ltoStrip = new BitcodeTempFile(ltoTempFile, !_options.saveTempFiles());
660 ltoFile = xar_add_frombuffer(x, NULL, "lto.o", (char*)ltoStrip->getContent(), ltoStrip->getSize());
661 delete ltoStrip;
662 } else {
663 ltoFile = xar_add_frombuffer(x, NULL, "lto.o", (char*)ltoTemp->getContent(), ltoTemp->getSize());
664 }
665 if ( ltoFile == NULL )
666 throwf("could not add lto file %s to bitcode bundle", _state.ltoBitcodePath.c_str());
667 if ( xar_prop_set(ltoFile, "file-type", "LTO") != 0 )
668 throwf("could not set bitcode property for %s in bitcode bundle", _state.ltoBitcodePath.c_str());
669 delete ltoTemp;
670 }
671
672 // Common LinkOptions
673 std::vector<std::string> linkCmd = _options.writeBitcodeLinkOptions();
674
675 // support -sectcreate option
676 for ( auto extraSect = _options.extraSectionsBegin(); extraSect != _options.extraSectionsEnd(); ++ extraSect ) {
677 std::string sectName = std::string(extraSect->segmentName) + std::string(",") + std::string(extraSect->sectionName);
678 BitcodeTempFile* sectFile = new BitcodeTempFile(extraSect->path, false);
679 xar_file_t sectXar = xar_add_frombuffer(x, NULL, sectName.c_str(), (char*)sectFile->getContent(), sectFile->getSize());
680 if ( sectXar == NULL )
681 throwf("could not encode sectcreate file %s into bitcode bundle", extraSect->path);
682 if ( xar_prop_set(sectXar, "file-type", "Section") != 0 )
683 throwf("could not set bitcode property for %s", sectName.c_str());
684 delete sectFile;
685 linkCmd.push_back("-sectcreate");
686 linkCmd.push_back(extraSect->segmentName);
687 linkCmd.push_back(extraSect->sectionName);
688 linkCmd.push_back(sectName);
689 }
690
691 // Write exports file
692 if ( _options.hasExportMaskList() ) {
693 linkCmd.push_back("-exported_symbols_list");
694 linkCmd.push_back("exports.exp");
695 const char* exportsPath = "exports.exp";
696 std::vector<const char*> exports = _options.exportsData();
697 std::string exps;
698 for (std::vector<const char*>::iterator it = exports.begin();
699 it != exports.end(); ++ it) {
700 exps += *it;
701 exps += "\n";
702 }
703 // always append an empty line so exps cannot be empty. rdar://problem/22404253
704 exps += "\n";
705 xar_file_t exportsFile = xar_add_frombuffer(x, NULL, exportsPath, const_cast<char*>(exps.data()), exps.size());
706 if (exportsFile == NULL)
707 throwf("could not add exports list to bitcode bundle");
708 if (xar_prop_set(exportsFile, "file-type", "Exports") != 0)
709 throwf("could not set exports property in bitcode bundle");
710 }
711
712 // Create subdoc to write link information
713 xar_subdoc_t linkXML = xar_subdoc_new(x, "Ld");
714 if ( linkXML == NULL )
715 throwf("could not create XML in bitcode bundle");
716
717 // Write version number
718 if ( xar_prop_create((xar_file_t)linkXML, "version", BITCODE_XAR_VERSION) != 0 )
719 throwf("could not add version number to bitcode bundle");
720
721 // Arch
722 if ( xar_prop_create((xar_file_t)linkXML, "architecture", _options.architectureName()) != 0 )
723 throwf("could not add achitecture name to bitcode bundle");
724
725 // Opt-out symbols
726 if ( _options.hideSymbols() ) {
727 if ( xar_prop_create((xar_file_t)linkXML, "hide-symbols", "1") != 0 )
728 throwf("could not add property to bitcode bundle");
729 }
730
731 // Write SDK version
732 if ( _options.sdkPaths().size() > 1 )
733 throwf("only one -syslibroot is accepted for bitcode bundle");
734 if ( xar_prop_create((xar_file_t)linkXML, "platform", _options.getPlatformStr().c_str()) != 0 )
735 throwf("could not add platform name to bitcode bundle");
736 if ( xar_prop_create((xar_file_t)linkXML, "sdkversion", _options.getSDKVersionStr().c_str()) != 0 )
737 throwf("could not add SDK version to bitcode bundle");
738
739 // Write dylibs
740 char sdkRoot[PATH_MAX];
741 if ( _options.sdkPaths().empty() || (realpath(_options.sdkPaths().front(), sdkRoot) == NULL) )
742 strcpy(sdkRoot, "/");
743 if ( !_state.dylibs.empty() ) {
744 char dylibPath[PATH_MAX];
745 for ( auto &dylib : _state.dylibs ) {
746 // For every dylib/framework, figure out if it is coming from a SDK.
747 // The dylib/framework from SDK must begin with '/' and user framework must begin with '@'.
748 if (dylib->installPath()[0] == '/') {
749 // Verify the path of the framework is within the SDK.
750 char dylibRealPath[PATH_MAX];
751 if ( realpath(dylib->path(), dylibRealPath) != NULL && strncmp(sdkRoot, dylibRealPath, strlen(sdkRoot)) != 0 )
752 warning("%s has install name beginning with \"/\" but it is not from the specified SDK", dylib->path());
753 // The path start with a string template
754 strcpy(dylibPath, "{SDKPATH}");
755 // append the path of dylib/frameowrk in the SDK
756 strcat(dylibPath, dylib->installPath());
757 } else {
758 // Not in any SDKs, then assume it is a user dylib/framework
759 // strip off all the path in the front
760 const char* dylib_name = strrchr(dylib->path(), '/');
761 dylib_name = (dylib_name == NULL) ? dylib->path() : dylib_name + 1;
762 strcpy(dylibPath, dylib_name);
763 }
764 if ( dylib->forcedWeakLinked() ) {
765 if ( xar_prop_create((xar_file_t)linkXML, "dylibs/weak", dylibPath) != 0)
766 throwf("could not add dylib options to bitcode bundle");
767 } else {
768 if ( xar_prop_create((xar_file_t)linkXML, "dylibs/lib", dylibPath) != 0)
769 throwf("could not add dylib options to bitcode bundle");
770 }
771 }
772 }
773
774 // Write link-line into archive
775 for ( auto &it : linkCmd ) {
776 if (xar_prop_create((xar_file_t)linkXML, "link-options/option", it.c_str()) != 0)
777 throwf("could not add link options to bitcode bundle");
778 }
779 // Finish writing
780 xar_close(x);
781
782 // Read the file back
783 BitcodeTempFile* xarTemp = new BitcodeTempFile(outFile, !_options.saveTempFiles());
784
785 // Create an Atom and add to the list
786 BitcodeAtom* bundleAtom = new BitcodeAtom(*xarTemp);
787 _state.addAtom(*bundleAtom);
788
789 // write the reverse mapping file if required
790 if ( _options.hideSymbols() && !_options.reverseMapTempPath().empty() )
791 obfuscator->writeSymbolMap(_options.reverseMapTempPath().c_str());
792
793 // Clean up local variables
794 delete xarTemp;
795 delete obfuscator;
796 for ( auto &entry: handlerMap )
797 delete entry.second;
798 // delete temp directory if not using -save-temps
799 // only do so after all the BitcodeTempFiles are deleted.
800 if ( !_options.saveTempFiles() ) {
801 if ( ::rmdir(tempdir) != 0 )
802 warning("temp directory cannot be removed: %s", tempdir);
803 }
804 }
805
806
807
808 // called by linker to write bitcode bundle into a mach-o section
809 void doPass(const Options& opts, ld::Internal& internal) {
810 BitcodeBundle BB(opts, internal);
811 BB.doPass();
812 }
813
814
815 } // namespace bitcode_bundle
816 } // namespace passes
817 } // namespace ld