From fb9a160cc46cd88a41dda5ab61012c5572e56f33 Mon Sep 17 00:00:00 2001 From: Apple Date: Sat, 24 Oct 2015 00:37:11 +0000 Subject: [PATCH] ld64-253.9.tar.gz --- src/ld/Options.cpp | 24 ++- src/ld/parsers/textstub_dylib_file.cpp | 4 + src/ld/passes/bitcode_bundle.cpp | 209 +++++++++++++++++++++++-- 3 files changed, 219 insertions(+), 18 deletions(-) diff --git a/src/ld/Options.cpp b/src/ld/Options.cpp index 8106e93..c915f5e 100644 --- a/src/ld/Options.cpp +++ b/src/ld/Options.cpp @@ -1779,6 +1779,12 @@ void Options::parseOrderFile(const char* path, bool cstring) else symbolStart = NULL; } + else if ( strncmp(symbolStart, "arm64:", 6) == 0 ) { + if ( fArchitecture == CPU_TYPE_ARM64 ) + symbolStart = &symbolStart[6]; + else + symbolStart = NULL; + } if ( symbolStart != NULL ) { char* objFileName = NULL; char* colon = strstr(symbolStart, ".o:"); @@ -2360,7 +2366,6 @@ void Options::parse(int argc, const char* argv[]) else if ( strcmp(arg, "-order_file") == 0 ) { snapshotFileArgIndex = 1; parseOrderFile(argv[++i], false); - cannotBeUsedWithBitcode(arg); } else if ( strcmp(arg, "-order_file_statistics") == 0 ) { fPrintOrderFileStatistics = true; @@ -2452,7 +2457,6 @@ void Options::parse(int argc, const char* argv[]) throw "can't use -unexported_symbols_list and -exported_symbols_list"; fExportMode = kDontExportSome; loadExportFile(argv[++i], "-unexported_symbols_list", fDontExportSymbols); - cannotBeUsedWithBitcode(arg); } else if ( strcmp(arg, "-exported_symbol") == 0 ) { if ( fExportMode == kDontExportSome ) @@ -2465,7 +2469,6 @@ void Options::parse(int argc, const char* argv[]) throw "can't use -unexported_symbol and -exported_symbol"; fExportMode = kDontExportSome; fDontExportSymbols.insert(argv[++i]); - cannotBeUsedWithBitcode(arg); } else if ( strcmp(arg, "-non_global_symbols_no_strip_list") == 0 ) { snapshotFileArgIndex = 1; @@ -3061,13 +3064,9 @@ void Options::parse(int argc, const char* argv[]) } else if ( strcmp(arg, "-bitcode_hide_symbols") == 0 ) { fHideSymbols = true; - if ( !fBundleBitcode ) - warning("-bitcode_hide_symbols is ignored without -bitcode_bundle"); } else if ( strcmp(arg, "-bitcode_verify") == 0 ) { fVerifyBitcode = true; - if ( !fBundleBitcode ) - warning("-bitcode_verify is ignored without -bitcode_bundle"); } else if ( strcmp(arg, "-bitcode_symbol_map") == 0) { fReverseMapPath = argv[++i]; @@ -5323,6 +5322,17 @@ void Options::checkIllegalOptionCombinations() if ( fOutputKind == Options::kObjectFile && fInputFiles.size() == 1 && fBitcodeKind == Options::kBitcodeProcess ) fBitcodeKind = Options::kBitcodeAsData; + // warn about bitcode option combinations + if ( !fBundleBitcode ) { + if ( fVerifyBitcode ) + warning("-bitcode_verify is ignored without -bitcode_bundle"); + else if ( fHideSymbols ) + warning("-bitcode_hide_symbols is ignored without -bitcode_bundle"); + } + if ( fReverseMapPath != NULL && !fHideSymbols ) { + throw "-bitcode_symbol_map can only be used with -bitcode_hide_symbols"; + } + // warn if building an embedded iOS dylib for pre-iOS 8 // How can we suppress "ld: warning: embedded dylibs/frameworks only run on iOS 8 or laterĂ“ when building XCTest? if ( (fOutputKind == Options::kDynamicLibrary) && (fIOSVersionMin != ld::iOSVersionUnset) && (fDylibInstallName != NULL) ) { diff --git a/src/ld/parsers/textstub_dylib_file.cpp b/src/ld/parsers/textstub_dylib_file.cpp index cde3344..825cb05 100644 --- a/src/ld/parsers/textstub_dylib_file.cpp +++ b/src/ld/parsers/textstub_dylib_file.cpp @@ -313,6 +313,10 @@ class TBDFile { bool parseArchFlowSequence(Token archName) { expectToken("archs"); + // x86_64h fails to link against text based stubs + if ( archName == "x86_64h" ) + archName = "x86_64"; + bool foundArch = false; parseFlowSequence([&](Token name) { if ( name == archName ) diff --git a/src/ld/passes/bitcode_bundle.cpp b/src/ld/passes/bitcode_bundle.cpp index 9e1da55..2ad5a3e 100644 --- a/src/ld/passes/bitcode_bundle.cpp +++ b/src/ld/passes/bitcode_bundle.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "llvm-c/lto.h" // c header @@ -93,23 +94,32 @@ public: ~BitcodeObfuscator(); void addMustPreserveSymbols(const char* name); + void addAsmSymbolsToMustPreserve(lto_module_t module); void bitcodeHideSymbols(ld::Bitcode* bc, const char* filePath, const char* outputPath); void writeSymbolMap(const char* outputPath); + const char* lookupHiddenName(const char* symbol); private: typedef void (*lto_codegen_func_t) (lto_code_gen_t); typedef void (*lto_codegen_output_t) (lto_code_gen_t, const char*); + typedef const char* (*lto_codegen_lookup_t) (lto_code_gen_t, const char*); + typedef unsigned int (*lto_module_num_symbols) (lto_module_t); + typedef const char* (*lto_module_symbol_name) (lto_module_t, unsigned int); lto_code_gen_t _obfuscator; lto_codegen_func_t _lto_hide_symbols; lto_codegen_func_t _lto_reset_context; lto_codegen_output_t _lto_write_reverse_map; + lto_codegen_lookup_t _lto_lookup_hidden_name; + lto_module_num_symbols _lto_get_asm_symbol_num; + lto_module_symbol_name _lto_get_asm_symbol_name; }; class FileHandler { // generic handler for files in a bundle public: virtual void populateMustPreserveSymbols(BitcodeObfuscator* _obfuscator) { } - virtual void obfuscateAndWriteToPath(BitcodeObfuscator* _obfuscator, const char* path) { }; + virtual void obfuscateAndWriteToPath(BitcodeObfuscator* _obfuscator, const char* path); + virtual const char* compressionMethod() { return XAR_OPT_VAL_NONE; } // no compression by default xar_file_t getXARFile() { return _xar_file; } FileHandler(char* content, size_t size) : @@ -165,7 +175,7 @@ public: ~BitcodeHandler(); - virtual void populateMustPreserveSymbols(BitcodeObfuscator* obfuscator) override { } // Don't need to preserve symbols + virtual void populateMustPreserveSymbols(BitcodeObfuscator* obfuscator) override; virtual void obfuscateAndWriteToPath(BitcodeObfuscator* obfuscator, const char* path) override; }; @@ -178,11 +188,23 @@ public: ~ObjectHandler(); - void populateMustPreserveSymbols(BitcodeObfuscator* obfuscator) override; - void obfuscateAndWriteToPath(BitcodeObfuscator* obfuscator, const char* path) override; + virtual void populateMustPreserveSymbols(BitcodeObfuscator* obfuscator) override; }; +class SymbolListHandler : public FileHandler { +public: + SymbolListHandler(char* content, size_t size) : + FileHandler(content, size) { } + SymbolListHandler(xar_t parent, xar_file_t xar_file) : + FileHandler(parent, xar_file) { } + + ~SymbolListHandler(); + + virtual void obfuscateAndWriteToPath(BitcodeObfuscator* obfuscator, const char* path) override; + virtual const char* compressionMethod() override { return XAR_OPT_VAL_GZIP; } +}; + class BitcodeBundle { public: @@ -252,8 +274,12 @@ BitcodeObfuscator::BitcodeObfuscator() _lto_hide_symbols = (lto_codegen_func_t) dlsym(RTLD_DEFAULT, "lto_codegen_hide_symbols"); _lto_write_reverse_map = (lto_codegen_output_t) dlsym(RTLD_DEFAULT, "lto_codegen_write_symbol_reverse_map"); _lto_reset_context = (lto_codegen_func_t) dlsym(RTLD_DEFAULT, "lto_codegen_reset_context"); + _lto_lookup_hidden_name = (lto_codegen_lookup_t) dlsym(RTLD_DEFAULT, "lto_codegen_lookup_hidden_name"); + _lto_get_asm_symbol_num = (lto_module_num_symbols) dlsym(RTLD_DEFAULT, "lto_module_get_num_asm_symbols"); + _lto_get_asm_symbol_name = (lto_module_symbol_name) dlsym(RTLD_DEFAULT, "lto_module_get_asm_symbol_name"); if ( _lto_hide_symbols == NULL || _lto_write_reverse_map == NULL || - _lto_reset_context == NULL || ::lto_api_version() < 14 ) + _lto_reset_context == NULL || _lto_lookup_hidden_name == NULL || + _lto_get_asm_symbol_num == NULL || _lto_get_asm_symbol_name == NULL || ::lto_api_version() < 14 ) throwf("loaded libLTO doesn't support -bitcode_hide_symbols: %s", ::lto_get_version()); _obfuscator = ::lto_codegen_create_in_local_context(); #if LTO_API_VERSION >= 14 @@ -293,6 +319,18 @@ void BitcodeObfuscator::writeSymbolMap(const char *outputPath) (*_lto_write_reverse_map)(_obfuscator, outputPath); } +const char* BitcodeObfuscator::lookupHiddenName(const char *symbol) +{ + return (*_lto_lookup_hidden_name)(_obfuscator, symbol); +} + +void BitcodeObfuscator::addAsmSymbolsToMustPreserve(lto_module_t module) +{ + for (unsigned int i = 0; i < _lto_get_asm_symbol_num(module); ++ i) { + addMustPreserveSymbols(_lto_get_asm_symbol_name(module, i)); + } +} + BundleHandler::~BundleHandler() { // free buffers @@ -326,6 +364,11 @@ ObjectHandler::~ObjectHandler() destroyFile(); } +SymbolListHandler::~SymbolListHandler() +{ + destroyFile(); +} + void BundleHandler::init() { if ( _xar != NULL ) @@ -369,8 +412,10 @@ void BundleHandler::init() _handlers.push_back(new ObjectHandler(_xar, f)); else if ( strcmp(filetype, "Bitcode") == 0 || strcmp(filetype, "LTO") == 0 ) _handlers.push_back(new BitcodeHandler(_xar, f)); + else if ( strcmp(filetype, "Exports") == 0 || strcmp(filetype, "OrderFile") == 0) + _handlers.push_back(new SymbolListHandler(_xar, f)); else - assert(0 && "Unknown file type"); + _handlers.push_back(new FileHandler(_xar, f)); } xar_iter_free(iter); } @@ -421,6 +466,17 @@ void BundleHandler::populateMustPreserveSymbols(BitcodeObfuscator* obfuscator) handler->populateMustPreserveSymbols(obfuscator); } +void BitcodeHandler::populateMustPreserveSymbols(BitcodeObfuscator* obfuscator) +{ + initFile(); + + // init LTOModule and add asm labels + lto_module_t module = lto_module_create_from_memory(_file_buffer, _file_size); + obfuscator->addAsmSymbolsToMustPreserve(module); + lto_module_dispose(module); +} + + void ObjectHandler::populateMustPreserveSymbols(BitcodeObfuscator* obfuscator) { initFile(); @@ -456,7 +512,13 @@ void BundleHandler::obfuscateAndWriteToPath(BitcodeObfuscator *obfuscator, const sprintf(outputPath, "%s/%s", _temp_dir, name); handler->obfuscateAndWriteToPath(obfuscator, outputPath); BitcodeTempFile* bcOut = new BitcodeTempFile(outputPath, !_options.saveTempFiles()); + if ( xar_opt_set(x, XAR_OPT_COMPRESSION, handler->compressionMethod()) != 0 ) + throwf("could not set compression type for exports list"); xar_file_t bcEntry = xar_add_frombuffer(x, NULL, name, (char*)bcOut->getContent(), bcOut->getSize()); + if ( bcEntry == NULL ) + throwf("could not add file to the bundle"); + if ( xar_opt_set(x, XAR_OPT_COMPRESSION, XAR_OPT_VAL_NONE) != 0 ) + throwf("could not reset compression type for exports list"); copyXARProp(f, bcEntry); delete bcOut; } @@ -477,7 +539,33 @@ void BitcodeHandler::obfuscateAndWriteToPath(BitcodeObfuscator *obfuscator, cons obfuscator->bitcodeHideSymbols(&bc, path, path); } -void ObjectHandler::obfuscateAndWriteToPath(BitcodeObfuscator *obfuscator, const char *path) +void SymbolListHandler::obfuscateAndWriteToPath(BitcodeObfuscator* obfuscator, const char* path) +{ + initFile(); + // Obfuscate exported symbol list. + std::string exports_list; + for (size_t i = 0, start = 0; i < _file_size; ++i) { + if ( _file_buffer[i] == '\n' ) { + _file_buffer[i] = '\0'; + const char* hiddenName = obfuscator->lookupHiddenName(_file_buffer + start); + if ( hiddenName == NULL ) + exports_list += _file_buffer + start; + else + exports_list += hiddenName; + exports_list += "\n"; + start = i + 1; + } else if ( _file_buffer[i] == '*' ) { + throwf("illegal export list found. Please rebuild your static library using -exported_symbol[s_list] with the newest Xcode"); + } + } + exports_list += "\n"; + int f = ::open(path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + if ( f == -1 || ::write(f, exports_list.data(), exports_list.size()) != (int)exports_list.size() ) + throwf("failed to write content to temp file: %s", path); + ::close(f); +} + +void FileHandler::obfuscateAndWriteToPath(BitcodeObfuscator *obfuscator, const char *path) { initFile(); int f = ::open(path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); @@ -536,7 +624,7 @@ void BitcodeBundle::doPass() atom->definition() == ld::Atom::definitionProxy || atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip || ( _options.allGlobalsAreDeadStripRoots() && atom->scope() == ld::Atom::scopeGlobal ) || - ( _options.hasExportRestrictList() && _options.shouldExport(atom->name())) ) + ( _options.hasExportRestrictList() && _options.shouldExport(atom->name()) ) ) obfuscator->addMustPreserveSymbols(atom->name()); } } @@ -549,6 +637,9 @@ void BitcodeBundle::doPass() BundleHandler* bh = new BundleHandler((char*)bb->getContent(), bb->getSize(), _options); bh->populateMustPreserveSymbols(obfuscator); handlerMap.emplace(std::string(f->path()), bh); + } else if ( ld::LLVMBitcode* bitcode = dynamic_cast(f->getBitcode()) ) { + BitcodeHandler* bitcodeHandler = new BitcodeHandler((char*)bitcode->getContent(), bitcode->getSize()); + bitcodeHandler->populateMustPreserveSymbols(obfuscator); } } // special symbols supplied by linker @@ -689,24 +780,120 @@ void BitcodeBundle::doPass() } // Write exports file + // A vector of all the exported symbols. if ( _options.hasExportMaskList() ) { + std::vector exportedSymbols; + for ( auto § : _state.sections ) { + for ( auto &atom : sect->atoms ) { + // The symbols should be added to the export list is the ones that are: + // globalScope, in SymbolTable and should be exported suggested by export file. + if ( atom->scope() == ld::Atom::scopeGlobal && + atom->symbolTableInclusion() == ld::Atom::symbolTableIn && + _options.shouldExport(atom->name()) ) + exportedSymbols.push_back(atom->name()); + } + } linkCmd.push_back("-exported_symbols_list"); linkCmd.push_back("exports.exp"); const char* exportsPath = "exports.exp"; - std::vector exports = _options.exportsData(); std::string exps; - for (std::vector::iterator it = exports.begin(); - it != exports.end(); ++ it) { + for (std::vector::iterator it = exportedSymbols.begin(); + it != exportedSymbols.end(); ++ it) { exps += *it; exps += "\n"; } // always append an empty line so exps cannot be empty. rdar://problem/22404253 exps += "\n"; + if (xar_opt_set(x, XAR_OPT_COMPRESSION, XAR_OPT_VAL_GZIP) != 0) + throwf("could not set compression type for exports list"); xar_file_t exportsFile = xar_add_frombuffer(x, NULL, exportsPath, const_cast(exps.data()), exps.size()); if (exportsFile == NULL) throwf("could not add exports list to bitcode bundle"); if (xar_prop_set(exportsFile, "file-type", "Exports") != 0) throwf("could not set exports property in bitcode bundle"); + if (xar_opt_set(x, XAR_OPT_COMPRESSION, XAR_OPT_VAL_NONE) != 0) + throwf("could not reset compression type for exports list"); + } else if ( _options.hasExportRestrictList() ) { + // handle unexported list here + std::vector unexportedSymbols; + for ( auto § : _state.sections ) { + for ( auto &atom : sect->atoms ) { + // The unexported symbols should not include anything that is in TranslationUnit scope (static) or + // that cannot be in the SymbolTable + if ( atom->scope() != ld::Atom::scopeTranslationUnit && + atom->symbolTableInclusion() == ld::Atom::symbolTableIn && + !_options.shouldExport(atom->name()) ) + unexportedSymbols.push_back(atom->name()); + } + } + linkCmd.push_back("-unexported_symbols_list"); + linkCmd.push_back("unexports.exp"); + const char* unexportsPath = "unexports.exp"; + std::string unexps; + for (std::vector::iterator it = unexportedSymbols.begin(); + it != unexportedSymbols.end(); ++ it) { + // try obfuscate the name for symbols in unexported symbols list. They are likely to be obfsucated. + const char* sym_name = NULL; + if ( _options.hideSymbols() ) + sym_name = obfuscator->lookupHiddenName(*it); + if ( sym_name ) + unexps += sym_name; + else + unexps += *it; + unexps += "\n"; + } + unexps += "\n"; + if (xar_opt_set(x, XAR_OPT_COMPRESSION, XAR_OPT_VAL_GZIP) != 0) + throwf("could not set compression type for exports list"); + xar_file_t unexportsFile = xar_add_frombuffer(x, NULL, unexportsPath, const_cast(unexps.data()), unexps.size()); + if (unexportsFile == NULL) + throwf("could not add unexports list to bitcode bundle"); + if (xar_prop_set(unexportsFile, "file-type", "Exports") != 0) + throwf("could not set exports property in bitcode bundle"); + if (xar_opt_set(x, XAR_OPT_COMPRESSION, XAR_OPT_VAL_NONE) != 0) + throwf("could not reset compression type for exports list"); + } + + // Handle order file. We need to obfuscate all the entries in the order file + if ( _options.orderedSymbolsCount() > 0 ) { + std::string orderFile; + for ( auto entry = _options.orderedSymbolsBegin(); entry != _options.orderedSymbolsEnd(); ++ entry ) { + std::stringstream line; + if ( entry->objectFileName != NULL ) { + unsigned index = 0; + for ( auto &f : _state.filesWithBitcode ) { + const char* atomFullPath = f->path(); + const char* lastSlash = strrchr(atomFullPath, '/'); + if ( (lastSlash != NULL && strcmp(&lastSlash[1], entry->objectFileName) == 0) || + strcmp(atomFullPath, entry->objectFileName) == 0 ) + break; + ++ index; + } + if ( index >= _state.filesWithBitcode.size() ) + continue; + line << index << ".o:"; + } + const char* sym_name = NULL; + if ( _options.hideSymbols() ) + sym_name = obfuscator->lookupHiddenName(entry->symbolName); + if ( sym_name ) + line << sym_name; + else + line << entry->symbolName; + line << "\n"; + orderFile += line.str(); + } + if (xar_opt_set(x, XAR_OPT_COMPRESSION, XAR_OPT_VAL_GZIP) != 0) + throwf("could not set compression type for order file"); + xar_file_t ordersFile = xar_add_frombuffer(x, NULL, "file.order", const_cast(orderFile.data()), orderFile.size()); + if (ordersFile == NULL) + throwf("could not add order file to bitcode bundle"); + if (xar_prop_set(ordersFile, "file-type", "OrderFile") != 0) + throwf("could not set order file property in bitcode bundle"); + if (xar_opt_set(x, XAR_OPT_COMPRESSION, XAR_OPT_VAL_NONE) != 0) + throwf("could not reset compression type for order file"); + linkCmd.push_back("-order_file"); + linkCmd.push_back("file.order"); } // Create subdoc to write link information -- 2.45.2