1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2010 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
33 #include <unordered_map>
35 #include "llvm-c/lto.h"
41 #include "bitcode_bundle.h"
45 #include "Bitcode.hpp"
46 #include "macho_relocatable_file.h"
51 namespace bitcode_bundle
{
53 class BitcodeTempFile
;
55 class BitcodeAtom
: public ld::Atom
{
56 static ld::Section bitcodeBundleSection
;
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
) { }
74 ld::Section
BitcodeAtom::bitcodeBundleSection("__LLVM", "__bundle", ld::Section::typeSectCreate
);
76 class BitcodeTempFile
{
78 BitcodeTempFile(const char* path
, bool deleteAfterRead
);
80 uint8_t* getContent() const { return _content
; }
81 uint64_t getSize() const { return _size
; }
83 friend class BitcodeAtom
;
87 bool _deleteAfterRead
;
90 class BitcodeObfuscator
{
95 void addMustPreserveSymbols(const char* name
);
96 void bitcodeHideSymbols(ld::Bitcode
* bc
, const char* filePath
, const char* outputPath
);
97 void writeSymbolMap(const char* outputPath
);
99 typedef void (*lto_codegen_func_t
) (lto_code_gen_t
);
100 typedef void (*lto_codegen_output_t
) (lto_code_gen_t
, const char*);
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
;
109 // generic handler for files in a bundle
111 virtual void populateMustPreserveSymbols(BitcodeObfuscator
* _obfuscator
) { }
112 virtual void obfuscateAndWriteToPath(BitcodeObfuscator
* _obfuscator
, const char* path
) { };
113 xar_file_t
getXARFile() { return _xar_file
; }
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() { }
124 if (xar_extract_tobuffersz(_parent
, _xar_file
, &_file_buffer
, &_file_size
) != 0)
125 throwf("could not extract files from bitcode bundle");
134 xar_file_t _xar_file
;
139 class BundleHandler
: public FileHandler
{
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
) { }
148 virtual void populateMustPreserveSymbols(BitcodeObfuscator
* obfuscator
) override
;
149 virtual void obfuscateAndWriteToPath(BitcodeObfuscator
* obfuscator
, const char* path
) override
;
153 void copyXARProp(xar_file_t src
, xar_file_t dst
);
157 const Options
& _options
;
158 std::vector
<FileHandler
*> _handlers
;
161 class BitcodeHandler
: public FileHandler
{
163 BitcodeHandler(char* content
, size_t size
) : FileHandler(content
, size
) { }
164 BitcodeHandler(xar_t parent
, xar_file_t xar_file
) : FileHandler(parent
, xar_file
) { }
168 virtual void populateMustPreserveSymbols(BitcodeObfuscator
* obfuscator
) override
{ } // Don't need to preserve symbols
169 virtual void obfuscateAndWriteToPath(BitcodeObfuscator
* obfuscator
, const char* path
) override
;
172 class ObjectHandler
: public FileHandler
{
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
) { }
181 void populateMustPreserveSymbols(BitcodeObfuscator
* obfuscator
) override
;
182 void obfuscateAndWriteToPath(BitcodeObfuscator
* obfuscator
, const char* path
) override
;
187 class BitcodeBundle
{
189 BitcodeBundle(const Options
& opts
, ld::Internal
& internal
) :
190 _options(opts
), _state(internal
) { }
195 const Options
& _options
;
196 ld::Internal
& _state
;
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)),
206 // initialize a marker of 1 byte
207 _content
= (uint8_t*)calloc(1,1);
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
)
217 // Creating the Atom will transfer the ownership of the buffer from Tempfile to Atom
218 tempfile
._content
= NULL
;
221 BitcodeTempFile::BitcodeTempFile(const char* path
, bool deleteAfterRead
= true)
222 : _path(path
), _deleteAfterRead(deleteAfterRead
)
224 int fd
= ::open(path
, O_RDONLY
, 0);
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
);
235 _size
= stat_buf
.st_size
;
238 BitcodeTempFile::~BitcodeTempFile()
241 if ( _deleteAfterRead
) {
242 if ( ::unlink(_path
) != 0 )
243 throwf("could not remove temp file: %s", _path
);
247 BitcodeObfuscator::BitcodeObfuscator()
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);
264 BitcodeObfuscator::~BitcodeObfuscator()
266 ::lto_codegen_dispose(_obfuscator
);
269 void BitcodeObfuscator::addMustPreserveSymbols(const char* name
)
271 ::lto_codegen_add_must_preserve_symbol(_obfuscator
, name
);
274 void BitcodeObfuscator::bitcodeHideSymbols(ld::Bitcode
* bc
, const char* filePath
, const char* outputPath
)
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);
285 ::lto_codegen_write_merged_modules(_obfuscator
, outputPath
);
286 (*_lto_reset_context
)(_obfuscator
);
291 void BitcodeObfuscator::writeSymbolMap(const char *outputPath
)
293 (*_lto_write_reverse_map
)(_obfuscator
, outputPath
);
296 BundleHandler::~BundleHandler()
301 for (auto handler
: _handlers
)
304 // delete temp file if not -save-temps
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());
313 if ( !_options
.saveTempFiles() && ::rmdir(_temp_dir
) != 0 )
314 warning("could not delete temp directory: %s", _temp_dir
);
319 BitcodeHandler::~BitcodeHandler()
324 ObjectHandler::~ObjectHandler()
329 void BundleHandler::init()
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");
342 sprintf(_temp_dir
, "%s.bundle.XXXXXX", finalOutput
);
343 ::mkdtemp(_temp_dir
);
345 // write the bundle to the temp_directory
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
);
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());
356 _xar
= xar_open(oldXARPath
.c_str(), READ
);
358 // Init the vector of handler
359 xar_iter_t iter
= xar_iter_new();
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
));
373 assert(0 && "Unknown file type");
378 void BundleHandler::copyXARProp(xar_file_t src
, xar_file_t dst
)
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.
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
);
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
);
413 void BundleHandler::populateMustPreserveSymbols(BitcodeObfuscator
* obfuscator
)
419 // iterate through the XAR file and add symbols
420 for ( auto handler
: _handlers
)
421 handler
->populateMustPreserveSymbols(obfuscator
);
424 void ObjectHandler::populateMustPreserveSymbols(BitcodeObfuscator
* obfuscator
)
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
);
435 void BundleHandler::obfuscateAndWriteToPath(BitcodeObfuscator
*obfuscator
, const char *path
)
441 // creating the new xar
442 xar_t x
= xar_open(path
, WRITE
);
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");
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
);
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
);
473 void BitcodeHandler::obfuscateAndWriteToPath(BitcodeObfuscator
*obfuscator
, const char *path
)
476 ld::Bitcode
bc((uint8_t*)_file_buffer
, _file_size
);
477 obfuscator
->bitcodeHideSymbols(&bc
, path
, path
);
480 void ObjectHandler::obfuscateAndWriteToPath(BitcodeObfuscator
*obfuscator
, const char *path
)
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
);
489 void BitcodeBundle::doPass()
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.
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
);
507 if ( _state
.filesWithBitcode
.empty() && _state
.ltoBitcodePath
.empty() )
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");
517 sprintf(tempdir
, "%s.bundle.XXXXXX", finalOutput
);
519 // A lookup map to look for BundlerHandler base on filename
520 std::unordered_map
<std::string
, BundleHandler
*> handlerMap
;
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:
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 §
: _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());
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
);
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");
566 char outFile
[PATH_MAX
];
567 sprintf(outFile
, "%s/bundle.xar", tempdir
);
569 // By default, it uses gzip to compress and SHA1 as checksum
570 x
= xar_open(outFile
, WRITE
);
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");
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();
583 // Copy each bitcode file into archive
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());
602 bcFile
= xar_add_frombuffer(x
, NULL
, outFilePath
, (char*)const_cast<uint8_t*>(llvmbc
->getContent()), llvmbc
->getSize());
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");
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());
629 bundleFile
= xar_add_frombuffer(x
, NULL
, outFilePath
,
630 (char*)const_cast<uint8_t*>(bundlebc
->getContent()),
631 bundlebc
->getSize());
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());
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());
646 assert(false && "Unknown bitcode");
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(<oBitcode
, _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());
663 ltoFile
= xar_add_frombuffer(x
, NULL
, "lto.o", (char*)ltoTemp
->getContent(), ltoTemp
->getSize());
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());
672 // Common LinkOptions
673 std::vector
<std::string
> linkCmd
= _options
.writeBitcodeLinkOptions();
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());
685 linkCmd
.push_back("-sectcreate");
686 linkCmd
.push_back(extraSect
->segmentName
);
687 linkCmd
.push_back(extraSect
->sectionName
);
688 linkCmd
.push_back(sectName
);
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();
698 for (std::vector
<const char*>::iterator it
= exports
.begin();
699 it
!= exports
.end(); ++ it
) {
703 // always append an empty line so exps cannot be empty. rdar://problem/22404253
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");
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");
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");
722 if ( xar_prop_create((xar_file_t
)linkXML
, "architecture", _options
.architectureName()) != 0 )
723 throwf("could not add achitecture name to bitcode bundle");
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");
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");
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());
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
);
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");
768 if ( xar_prop_create((xar_file_t
)linkXML
, "dylibs/lib", dylibPath
) != 0)
769 throwf("could not add dylib options to bitcode bundle");
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");
782 // Read the file back
783 BitcodeTempFile
* xarTemp
= new BitcodeTempFile(outFile
, !_options
.saveTempFiles());
785 // Create an Atom and add to the list
786 BitcodeAtom
* bundleAtom
= new BitcodeAtom(*xarTemp
);
787 _state
.addAtom(*bundleAtom
);
789 // write the reverse mapping file if required
790 if ( _options
.hideSymbols() && !_options
.reverseMapTempPath().empty() )
791 obfuscator
->writeSymbolMap(_options
.reverseMapTempPath().c_str());
793 // Clean up local variables
796 for ( auto &entry
: handlerMap
)
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
);
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
);
815 } // namespace bitcode_bundle
816 } // namespace passes