Merge branch 'master' into 877.8-ld64-253.9-ppc

Conflicts:
	README.md
This commit is contained in:
Thomas Pöchtrager 2016-05-09 21:32:06 +02:00
commit 13ee0a2fcb
25 changed files with 1022 additions and 234 deletions

View File

@ -1,3 +1,34 @@
## cctools 877.5 -> 877.8 ##
patching file include/mach-o/loader.h
patching file libstuff/execute.c
patching file libstuff/ofile.c
patching file libstuff/swap_headers.c
patching file misc/bitcode_strip.c
Hunk #11 NOT MERGED at 364-373, merged at 377, merged at 382-385.
Hunk #20 merged at 547-557.
patching file otool/main.c
patching file otool/ofile_print.c
## ld64 253.3 -> ld64 253.9 ##
patching file src/ld/InputFiles.cpp
patching file src/ld/ld.hpp
patching file src/ld/Options.cpp
Hunk #1 NOT MERGED at 194-205.
patching file src/ld/Options.h
patching file src/ld/parsers/lto_file.cpp
Hunk #1 merged at 324-325.
patching file src/ld/parsers/macho_dylib_file.cpp
patching file src/ld/parsers/macho_relocatable_file.cpp
patching file src/ld/parsers/macho_relocatable_file.h
patching file src/ld/parsers/textstub_dylib_file.cpp
patching file src/ld/passes/bitcode_bundle.cpp
patching file src/ld/Resolver.cpp
patching file src/other/ObjectDump.cpp
--------------------------------------------------------------------------------------------------------------------------------------------------------------
## cctools 870 -> 877.5 ##
can't find file to patch at input line 4
@ -8,8 +39,8 @@ The text leading up to this was:
|--- ../cctools-870/Makefile 2015-08-26 07:49:15.000000000 +0200
|+++ ./Makefile 2015-09-15 03:35:14.000000000 +0200
--------------------------
File to patch:
Skip this patch? [y]
File to patch:
Skip this patch? [y]
Skipping patch.
3 out of 3 hunks ignored
patching file ./as/driver.c
@ -45,8 +76,8 @@ The text leading up to this was:
|--- ../cctools-870/misc/Makefile 2013-12-10 20:28:11.000000000 +0100
|+++ ./misc/Makefile 2015-03-10 01:33:19.000000000 +0100
--------------------------
File to patch:
Skip this patch? [y]
File to patch:
Skip this patch? [y]
Skipping patch.
7 out of 7 hunks ignored
patching file ./misc/bitcode_strip.c
@ -71,8 +102,8 @@ The text leading up to this was:
|--- ../cctools-870/otool/Makefile 2014-01-14 01:21:55.000000000 +0100
|+++ ./otool/Makefile 2015-03-10 01:33:19.000000000 +0100
--------------------------
File to patch:
Skip this patch? [y]
File to patch:
Skip this patch? [y]
Skipping patch.
1 out of 1 hunk ignored
patching file ./otool/main.c
@ -109,8 +140,8 @@ The text leading up to this was:
|--- ../ld64-242.2/ld64.xcodeproj/project.pbxproj 2014-08-20 00:19:03.000000000 +0200
|+++ ./ld64.xcodeproj/project.pbxproj 2015-05-20 08:11:58.000000000 +0200
--------------------------
File to patch:
Skip this patch? [y]
File to patch:
Skip this patch? [y]
Skipping patch.
22 out of 22 hunks ignored
patching file ./src/abstraction/MachOFileAbstraction.hpp
@ -139,8 +170,8 @@ patching file ./src/ld/ld.cpp
patching file ./src/ld/ld.hpp
Hunk #1 merged at 35-36,38,45-47.
The next patch would delete the file ./src/ld/lto_file.hpp,
which does not exist! Assume -R? [n]
Apply anyway? [n]
which does not exist! Assume -R? [n]
Apply anyway? [n]
Skipping patch.
1 out of 1 hunk ignored
patching file ./src/ld/parsers/lto_file.cpp
@ -187,8 +218,8 @@ The text leading up to this was:
|--- ../ld64-242/unit-tests/test-cases/branch-islands/space.s 2013-10-19 03:10:28.000000000 +0200
|+++ ./unit-tests/test-cases/branch-islands/space.s 2015-05-05 21:42:23.000000000 +0200
--------------------------
File to patch:
Skip this patch? [y]
File to patch:
Skip this patch? [y]
Skipping patch.
1 out of 1 hunk ignored
@ -288,7 +319,7 @@ patching file ./src/ld/parsers/lto_file.cpp
Hunk #2 NOT MERGED at 499-507. # Resolved.
patching file ./src/ld/parsers/lto_file.h
patching file ./src/ld/parsers/macho_relocatable_file.cpp
Hunk #8 merged at 4219-4234.
Hunk #8 merged at 4219-4234.
patching file ./src/ld/parsers/macho_relocatable_file.h
patching file ./src/ld/passes/compact_unwind.cpp
patching file ./src/other/ObjectDump.cpp
@ -299,28 +330,28 @@ patching file ./src/other/unwinddump.cpp
## cctools 855 -> 862 ##
patching file efitools/mtoc.c
Reversed (or previously applied) patch detected! Assume -R? [n]
Apply anyway? [n]
Reversed (or previously applied) patch detected! Assume -R? [n]
Apply anyway? [n]
Skipping patch.
2 out of 2 hunks ignored -- saving rejects to file efitools/mtoc.c.rej
patching file include/llvm-c/Disassembler.h
Reversed (or previously applied) patch detected! Assume -R? [n]
Apply anyway? [n]
Reversed (or previously applied) patch detected! Assume -R? [n]
Apply anyway? [n]
Skipping patch.
1 out of 1 hunk ignored -- saving rejects to file include/llvm-c/Disassembler.h.rej
patching file include/mach-o/loader.h
Reversed (or previously applied) patch detected! Assume -R? [n]
Apply anyway? [n]
Reversed (or previously applied) patch detected! Assume -R? [n]
Apply anyway? [n]
Skipping patch.
1 out of 1 hunk ignored -- saving rejects to file include/mach-o/loader.h.rej
patching file include/mach-o/nlist.h
Reversed (or previously applied) patch detected! Assume -R? [n]
Apply anyway? [n]
Reversed (or previously applied) patch detected! Assume -R? [n]
Apply anyway? [n]
Skipping patch.
1 out of 1 hunk ignored -- saving rejects to file include/mach-o/nlist.h.rej
patching file include/stuff/llvm.h
Reversed (or previously applied) patch detected! Assume -R? [n]
Apply anyway? [n]
Reversed (or previously applied) patch detected! Assume -R? [n]
Apply anyway? [n]
Skipping patch.
1 out of 1 hunk ignored -- saving rejects to file include/stuff/llvm.h.rej
can't find file to patch at input line 103
@ -331,8 +362,8 @@ The text leading up to this was:
|--- ../cctools-855/libmacho/arch.c 2014-04-05 00:42:22.000000000 +0200
|+++ ./libmacho/arch.c 2014-11-02 06:48:07.000000000 +0100
--------------------------
File to patch:
Skip this patch? [y]
File to patch:
Skip this patch? [y]
Skipping patch.
1 out of 1 hunk ignored
patching file libstuff/checkout.c
@ -380,8 +411,8 @@ The text leading up to this was:
|--- ../ld64-236.3/ld64.xcodeproj/project.pbxproj 2014-04-05 00:42:29.000000000 +0200
|+++ ./ld64.xcodeproj/project.pbxproj 2014-11-04 00:58:03.000000000 +0100
--------------------------
File to patch:
Skip this patch? [y]
File to patch:
Skip this patch? [y]
Skipping patch.
3 out of 3 hunks ignored
patching file src/abstraction/MachOFileAbstraction.hpp
@ -506,8 +537,8 @@ The text leading up to this was:
|--- ../ld64-236.3/unit-tests/include/common.makefile 2014-04-05 00:42:29.000000000 +0200
|+++ ./unit-tests/include/common.makefile 2014-09-11 00:24:46.000000000 +0200
--------------------------
File to patch:
Skip this patch? [y]
File to patch:
Skip this patch? [y]
Skipping patch.
2 out of 2 hunks ignored
patching file unit-tests/test-cases/alias-basic/aliases.s
@ -521,8 +552,8 @@ The text leading up to this was:
|--- ../ld64-236.3/unit-tests/test-cases/alias-objects/aliases.s 2014-04-05 00:42:29.000000000 +0200
|+++ ./unit-tests/test-cases/alias-objects/aliases.s 2014-09-11 00:24:46.000000000 +0200
--------------------------
File to patch:
Skip this patch? [y]
File to patch:
Skip this patch? [y]
Skipping patch.
1 out of 1 hunk ignored
can't find file to patch at input line 3668
@ -533,8 +564,8 @@ The text leading up to this was:
|--- ../ld64-236.3/unit-tests/test-cases/alias-objects/Makefile 2014-04-05 00:42:29.000000000 +0200
|+++ ./unit-tests/test-cases/alias-objects/Makefile 2014-09-11 00:24:46.000000000 +0200
--------------------------
File to patch:
Skip this patch? [y]
File to patch:
Skip this patch? [y]
Skipping patch.
2 out of 2 hunks ignored
patching file unit-tests/test-cases/alt-entry/foo.c
@ -577,8 +608,8 @@ The text leading up to this was:
|--- ../ld64-236.3/unit-tests/test-cases/section-labels/main.c 2014-04-05 00:42:29.000000000 +0200
|+++ ./unit-tests/test-cases/section-labels/main.c 2014-09-11 00:24:46.000000000 +0200
--------------------------
File to patch:
Skip this patch? [y]
File to patch:
Skip this patch? [y]
Skipping patch.
1 out of 1 hunk ignored
patching file unit-tests/test-cases/symbol-section-move/main.c
@ -594,7 +625,7 @@ The text leading up to this was:
|--- ../ld64-236.3/unit-tests/test-cases/weak_import-undefined/Makefile 2014-04-05 00:42:29.000000000 +0200
|+++ ./unit-tests/test-cases/weak_import-undefined/Makefile 2014-09-11 00:24:46.000000000 +0200
--------------------------
File to patch:
Skip this patch? [y]
File to patch:
Skip this patch? [y]
Skipping patch.
1 out of 1 hunk ignored

View File

@ -1,6 +1,6 @@
# Apple cctools port for Linux, *BSD and Windows (Cygwin) #
Current Version: 877.5 + ld64-253.3.
Current Version: 877.8 + ld64-253.9.
## CREDITS ##
@ -60,4 +60,4 @@ If you get compile errors because of `unistd.h`, then please run
## TRAVIS CI ##
[![Build Status](https://travis-ci.org/tpoechtrager/cctools-port.svg?branch=870-ld64-253.3-ppc)](https://travis-ci.org/tpoechtrager/cctools-port)
[![Build Status](https://travis-ci.org/tpoechtrager/cctools-port.svg?branch=877.8-ld64-253.9-ppc)](https://travis-ci.org/tpoechtrager/cctools-port)

View File

@ -1,4 +1,4 @@
AC_INIT([cctools], [877.5], [t.poechtrager@gmail.com])
AC_INIT([cctools], [877.8], [t.poechtrager@gmail.com])
AC_CANONICAL_BUILD
AC_CANONICAL_HOST

View File

@ -300,6 +300,7 @@ struct load_command {
#define LC_ENCRYPTION_INFO_64 0x2C /* 64-bit encrypted segment information */
#define LC_LINKER_OPTION 0x2D /* linker options in MH_OBJECT files */
#define LC_LINKER_OPTIMIZATION_HINT 0x2E /* optimization hints in MH_OBJECT files */
#define LC_VERSION_MIN_TVOS 0x2F /* build for AppleTV min OS version */
#define LC_VERSION_MIN_WATCHOS 0x30 /* build for Watch min OS version */
/*
@ -1202,8 +1203,9 @@ struct encryption_info_command_64 {
*/
struct version_min_command {
uint32_t cmd; /* LC_VERSION_MIN_MACOSX or
LC_VERSION_MIN_IPHONEOS
LC_VERSION_MIN_WATCHOS */
LC_VERSION_MIN_IPHONEOS or
LC_VERSION_MIN_WATCHOS or
LC_VERSION_MIN_TVOS */
uint32_t cmdsize; /* sizeof(struct min_version_command) */
uint32_t version; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */

View File

@ -1,4 +1,4 @@
const char ldVersionString[] = "253.3\n";
const char ldVersionString[] = "253.9\n";
#ifndef __APPLE__

View File

@ -317,12 +317,10 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
objOpts.subType = _options.subArchitecture();
objOpts.platform = _options.platform();
objOpts.minOSVersion = _options.minOSversion();
// workaround for strip -S
// when ld -r has single input file, set the srcKind to kSourceSingle so __LLVM segment will be kept
if (_options.outputKind() == Options::kObjectFile && _options.getInputFiles().size() == 1)
objOpts.srcKind = ld::relocatable::File::kSourceSingle;
else
objOpts.srcKind = ld::relocatable::File::kSourceObj;
objOpts.srcKind = ld::relocatable::File::kSourceObj;
objOpts.treateBitcodeAsData = _options.bitcodeKind() == Options::kBitcodeAsData;
objOpts.usingBitcode = _options.bundleBitcode();
ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts);
if ( objResult != NULL ) {
OSAtomicAdd64(len, &_totalObjectSize);
@ -380,6 +378,9 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
archOpts.objOpts.srcKind = ld::relocatable::File::kSourceCompilerArchive;
else
archOpts.objOpts.srcKind = ld::relocatable::File::kSourceArchive;
archOpts.objOpts.treateBitcodeAsData = _options.bitcodeKind() == Options::kBitcodeAsData;
archOpts.objOpts.usingBitcode = _options.bundleBitcode();
ld::archive::File* archiveResult = ::archive::parse(p, len, info.path, info.modTime, info.ordinal, archOpts);
if ( archiveResult != NULL ) {
OSAtomicAdd64(len, &_totalArchiveSize);

View File

@ -191,9 +191,10 @@ Options::Options(int argc, const char* argv[])
fMarkAppExtensionSafe(false), fCheckAppExtensionSafe(false), fForceLoadSwiftLibs(false),
fSharedRegionEncodingV2(false), fUseDataConstSegment(false),
fUseDataConstSegmentForceOn(false), fUseDataConstSegmentForceOff(false),
fBundleBitcode(false), fHideSymbols(false), fReverseMapUUIDRename(false), fReverseMapPath(NULL), fLTOCodegenOnly(false),
fIgnoreAutoLink(false), fPlatform(kPlatformUnknown),
fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
fBundleBitcode(false), fHideSymbols(false), fVerifyBitcode(false),
fReverseMapUUIDRename(false), fReverseMapPath(NULL), fLTOCodegenOnly(false),
fIgnoreAutoLink(false), fAllowDeadDups(false), fBitcodeKind(kBitcodeProcess),
fPlatform(kPlatformUnknown), fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), fWatchOSVersionMin(ld::wOSVersionUnset), // ld64-port: added fWatchOSVersionMin(ld::wOSVersionUnset) - https://gist.github.com/tpoechtrager/6537a058dfb4d587fff4
fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL),
fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1)
@ -1815,6 +1816,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:");
@ -2398,7 +2405,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;
@ -2490,7 +2496,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 )
@ -2503,7 +2508,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;
@ -3103,8 +3107,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;
}
else if ( strcmp(arg, "-bitcode_symbol_map") == 0) {
fReverseMapPath = argv[++i];
@ -3130,6 +3135,24 @@ void Options::parse(int argc, const char* argv[])
else if ( strcmp(argv[i], "-ignore_auto_link") == 0) {
fIgnoreAutoLink = true;
}
else if ( strcmp(argv[i], "-allow_dead_duplicates") == 0) {
fAllowDeadDups = true;
}
else if ( strcmp(argv[i], "-bitcode_process_mode") == 0 ) {
const char* bitcode_type = argv[++i];
if ( bitcode_type == NULL )
throw "missing argument to -bitcode_process_mode";
else if ( strcmp(bitcode_type, "strip") == 0 )
fBitcodeKind = kBitcodeStrip;
else if ( strcmp(bitcode_type, "marker") == 0 )
fBitcodeKind = kBitcodeMarker;
else if ( strcmp(bitcode_type, "data") == 0 )
fBitcodeKind = kBitcodeAsData;
else if ( strcmp(bitcode_type, "bitcode") == 0 )
fBitcodeKind = kBitcodeProcess;
else
throw "unknown argument to -bitcode_process_mode {strip,marker,data,bitcode}";
}
else if ( strcmp(arg, "-rpath") == 0 ) {
const char* path = argv[++i];
if ( path == NULL )
@ -5401,6 +5424,26 @@ void Options::checkIllegalOptionCombinations()
if ( !fSegmentOrder.empty() && (fOutputKind != Options::kPreload) )
throw "-segment_order can only used used with -preload output";
if ( fBitcodeKind != kBitcodeProcess &&
fOutputKind != Options::kObjectFile ) {
throw "-bitcode_process_mode can only be used together with -r";
}
// auto fix up the process type for strip -S.
// when there is only one input and output type is object file, downgrade kBitcodeProcess to kBitcodeAsData.
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";
}
// <rdar://problem/17598404> warn if building an embedded iOS dylib for pre-iOS 8
// <rdar://problem/18935714> 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) ) {

View File

@ -86,6 +86,7 @@ public:
enum CommonsMode { kCommonsIgnoreDylibs, kCommonsOverriddenByDylibs, kCommonsConflictsDylibsError };
enum UUIDMode { kUUIDNone, kUUIDRandom, kUUIDContent };
enum LocalSymbolHandling { kLocalSymbolsAll, kLocalSymbolsNone, kLocalSymbolsSelectiveInclude, kLocalSymbolsSelectiveExclude };
enum BitcodeMode { kBitcodeProcess, kBitcodeAsData, kBitcodeMarker, kBitcodeStrip };
enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull };
#if SUPPORT_APPLE_TV
enum Platform { kPlatformUnknown, kPlatformOSX, kPlatformiOS, kPlatformWatchOS, kPlatform_tvOS };
@ -412,11 +413,14 @@ public:
bool forceLoadSwiftLibs() const { return fForceLoadSwiftLibs; }
bool bundleBitcode() const { return fBundleBitcode; }
bool hideSymbols() const { return fHideSymbols; }
bool verifyBitcode() const { return fVerifyBitcode; }
bool renameReverseSymbolMap() const { return fReverseMapUUIDRename; }
const char* reverseSymbolMapPath() const { return fReverseMapPath; }
std::string reverseMapTempPath() const { return fReverseMapTempPath; }
bool ltoCodegenOnly() const { return fLTOCodegenOnly; }
bool ignoreAutoLink() const { return fIgnoreAutoLink; }
bool allowDeadDuplicates() const { return fAllowDeadDups; }
BitcodeMode bitcodeKind() const { return fBitcodeKind; }
bool sharedRegionEncodingV2() const { return fSharedRegionEncodingV2; }
bool useDataConstSegment() const { return fUseDataConstSegment; }
bool hasWeakBitTweaks() const;
@ -709,11 +713,14 @@ private:
bool fUseDataConstSegmentForceOff;
bool fBundleBitcode;
bool fHideSymbols;
bool fVerifyBitcode;
bool fReverseMapUUIDRename;
const char* fReverseMapPath;
std::string fReverseMapTempPath;
bool fLTOCodegenOnly;
bool fIgnoreAutoLink;
bool fAllowDeadDups;
BitcodeMode fBitcodeKind;
Platform fPlatform;
DebugInfoStripping fDebugInfoStripping;
const char* fTraceOutputFile;

View File

@ -383,7 +383,6 @@ void Resolver::doFile(const ld::File& file)
this->doLinkerOption(*it, file.path());
}
}
// Resolve bitcode section in the object file
if ( _options.bundleBitcode() ) {
if ( objFile->getBitcode() == NULL ) {
@ -403,35 +402,25 @@ void Resolver::doFile(const ld::File& file)
"You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.", file.path());
break;
case Options::kPlatformWatchOS:
#if SUPPORT_APPLE_TV
case Options::kPlatform_tvOS:
#endif
throwf("'%s' does not contain bitcode. "
"You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor", file.path());
break;
#if SUPPORT_APPLE_TV
case Options::kPlatform_tvOS:
warning("URGENT: all bitcode will be dropped because '%s' was built without bitcode. "
"You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor. "
"Note: This will be an error in the future.", file.path());
_internal.filesWithBitcode.clear();
_internal.dropAllBitcode = true;
break;
#endif
}
}
} else {
// contains bitcode, check if it is just a marker
if ( objFile->getBitcode()->isMarker() ) {
// if the bitcode is just a marker,
// the executable will be created without bitcode section.
// Otherwise, create a marker.
if ( _options.outputKind() != Options::kDynamicExecutable &&
_options.outputKind() != Options::kStaticExecutable )
_internal.embedMarkerOnly = true;
// Issue a warning if the marker is in the static library and filesWithBitcode is not empty.
// That means there are object files actually compiled with full bitcode but the archive only has marker.
// Don't warn on normal object files because it can be a debug build using archives with full bitcode.
if ( !_internal.filesWithBitcode.empty() && objFile->sourceKind() == ld::relocatable::File::kSourceArchive )
warning("full bitcode bundle could not be generated because '%s' was built only with bitcode marker. "
"The library must be generated from Xcode archive build with bitcode enabled (Xcode setting ENABLE_BITCODE)", objFile->path());
// if -bitcode_verify_bundle is used, check if all the object files participate in the linking have full bitcode embedded.
// error on any marker encountered.
if ( _options.verifyBitcode() )
throwf("bitcode bundle could not be generated because '%s' was built without full bitcode. "
"All object files and libraries for bitcode must be generated from Xcode Archive or Install build",
objFile->path());
// update the internal state that marker is encountered.
_internal.embedMarkerOnly = true;
_internal.filesWithBitcode.clear();
_internal.dropAllBitcode = true;
} else if ( !_internal.dropAllBitcode )
@ -588,8 +577,8 @@ void Resolver::doFile(const ld::File& file)
if ( dylibFile != NULL ) {
// Check dylib for bitcode, if the library install path is relative path or @rpath, it has to contain bitcode
if ( _options.bundleBitcode() ) {
if ( dylibFile->getBitcode() == NULL &&
dylibFile->installPath()[0] != '/' ) {
bool isSystemFramework = ( dylibFile->installPath() != NULL ) && ( dylibFile->installPath()[0] == '/' );
if ( dylibFile->getBitcode() == NULL && !isSystemFramework ) {
// Check if the dylib is from toolchain by checking the path
char tcLibPath[PATH_MAX];
char ldPath[PATH_MAX];
@ -620,21 +609,21 @@ void Resolver::doFile(const ld::File& file)
"You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.", file.path());
break;
case Options::kPlatformWatchOS:
#if SUPPORT_APPLE_TV
case Options::kPlatform_tvOS:
#endif
throwf("'%s' does not contain bitcode. "
"You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor", file.path());
break;
#if SUPPORT_APPLE_TV
case Options::kPlatform_tvOS:
warning("URGENT: all bitcode will be dropped because '%s' was built without bitcode. "
"You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor. "
"Note: This will be an error in the future.", file.path());
_internal.filesWithBitcode.clear();
_internal.dropAllBitcode = true;
break;
#endif
}
}
}
// Error on bitcode marker in non-system frameworks if -bitcode_verify is used
if ( _options.verifyBitcode() && !isSystemFramework &&
dylibFile->getBitcode() != NULL && dylibFile->getBitcode()->isMarker() )
throwf("bitcode bundle could not be generated because '%s' was built without full bitcode. "
"All frameworks and dylibs for bitcode must be generated from Xcode Archive or Install build",
dylibFile->path());
}
// update which form of ObjC dylibs are being linked
@ -775,7 +764,7 @@ void Resolver::doAtom(const ld::Atom& atom)
// tell symbol table about non-static atoms
if ( atom.scope() != ld::Atom::scopeTranslationUnit ) {
_symbolTable.add(atom, _options.deadCodeStrip() && _completedInitialObjectFiles);
_symbolTable.add(atom, _options.deadCodeStrip() && (_completedInitialObjectFiles || _options.allowDeadDuplicates()));
// add symbol aliases defined on the command line
if ( _options.haveCmdLineAliases() ) {

View File

@ -203,7 +203,7 @@ namespace relocatable {
{
public:
enum DebugInfoKind { kDebugInfoNone=0, kDebugInfoStabs=1, kDebugInfoDwarf=2, kDebugInfoStabsUUID=3 };
enum SourceKind { kSourceUnknown=0, kSourceObj, kSourceLTO, kSourceArchive, kSourceCompilerArchive, kSourceSingle };
enum SourceKind { kSourceUnknown=0, kSourceObj, kSourceLTO, kSourceArchive, kSourceCompilerArchive };
struct Stab {
const class Atom* atom;
uint8_t type;

View File

@ -321,6 +321,8 @@ ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, cons
objOpts.subType = 0;
objOpts.minOSVersion = 0; // ld64-port: https://gist.github.com/tpoechtrager/2efafec8ac996509b9d6
objOpts.srcKind = ld::relocatable::File::kSourceLTO;
objOpts.treateBitcodeAsData = false;
objOpts.usingBitcode = options.bitcodeBundle;
// mach-o parsing is done in-memory, but need path for debug notes
const char* path = "/tmp/lto.o";

View File

@ -148,7 +148,7 @@ public:
Options::Platform platform, uint32_t linkMinOSVersion, bool allowSimToMacOSX,
bool addVers, bool buildingForSimulator,
bool logAllFiles, const char* installPath,
bool indirectDylib, bool ignoreMismatchPlatform);
bool indirectDylib, bool ignoreMismatchPlatform, bool usingBitcode);
virtual ~File() {}
// overrides of ld::File
@ -239,6 +239,7 @@ private:
bool _installPathOverride;
bool _indirectDylibsProcessed;
bool _appExtensionSafe;
bool _usingBitcode;
uint32_t _minVersionInDylib;
uint32_t _platformInDylib;
std::unique_ptr<ld::Bitcode> _bitcode;
@ -261,7 +262,7 @@ template <typename A>
File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth, time_t mTime, ld::File::Ordinal ord,
bool linkingFlatNamespace, bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
Options::Platform platform, uint32_t linkMinOSVersion, bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
bool logAllFiles, const char* targetInstallPath, bool indirectDylib, bool ignoreMismatchPlatform)
bool logAllFiles, const char* targetInstallPath, bool indirectDylib, bool ignoreMismatchPlatform, bool usingBitcode)
: ld::dylib::File(strdup(pth), mTime, ord),
_platform(platform), _linkMinOSVersion(linkMinOSVersion), _allowSimToMacOSXLinking(allowSimToMacOSX), _addVersionLoadCommand(addVers),
_linkingFlat(linkingFlatNamespace), _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs),
@ -272,7 +273,7 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
_noRexports(false), _hasWeakExports(false),
_deadStrippable(false), _hasPublicInstallName(false),
_providedAtom(false), _explictReExportFound(false), _wrongOS(false), _installPathOverride(false),
_indirectDylibsProcessed(false), _appExtensionSafe(false),
_indirectDylibsProcessed(false), _appExtensionSafe(false), _usingBitcode(usingBitcode),
_minVersionInDylib(0), _platformInDylib(Options::kPlatformUnknown)
{
const macho_header<P>* header = (const macho_header<P>*)fileContent;
@ -438,7 +439,11 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
#if SUPPORT_APPLE_TV
case Options::kPlatform_tvOS:
// tvOS is a warning temporarily. rdar://problem/21746965
if (platform == Options::kPlatform_tvOS)
if ( usingBitcode )
throwf("building for %s simulator, but linking against dylib built for %s,",
Options::platformName(platform),
Options::platformName(lcPlatform));
else
warning("URGENT: building for %s simulator, but linking against dylib (%s) built for %s. "
"Note: This will be an error in the future.",
Options::platformName(platform), path(),
@ -467,7 +472,11 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
#if SUPPORT_APPLE_TV
case Options::kPlatform_tvOS:
// tvOS is a warning temporarily. rdar://problem/21746965
if (platform == Options::kPlatform_tvOS)
if ( _usingBitcode )
throwf("building for %s, but linking against dylib built for %s,",
Options::platformName(platform),
Options::platformName(lcPlatform));
else
warning("URGENT: building for %s, but linking against dylib (%s) built for %s. "
"Note: This will be an error in the future.",
Options::platformName(platform), path(),
@ -1001,7 +1010,8 @@ public:
opts.logAllFiles(),
opts.installPath(),
indirectDylib,
opts.outputKind() == Options::kPreload);
opts.outputKind() == Options::kPreload,
opts.bundleBitcode());
}
};

View File

@ -108,7 +108,6 @@ public:
virtual uint8_t swiftVersion() const { return _swiftVersion; }
virtual ld::Bitcode* getBitcode() const { return _bitcode.get(); }
virtual SourceKind sourceKind() const { return _srcKind; }
virtual void setSourceKind(SourceKind src) { _srcKind = src; }
const uint8_t* fileContent() { return _fileContent; }
private:
@ -1257,6 +1256,8 @@ private:
bool _verboseOptimizationHints;
bool _armUsesZeroCostExceptions;
bool _ignoreMismatchPlatform;
bool _treateBitcodeAsData;
bool _usingBitcode;
unsigned int _stubsSectionNum;
const macho_section<P>* _stubsMachOSection;
std::vector<const char*> _dtraceProviderInfo;
@ -1774,8 +1775,11 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
// create file object
_file = new File<A>(_path, _modTime, _fileContent, _ordinal);
// set input source
_file->setSourceKind(opts.srcKind);
// set sourceKind
_file->_srcKind = opts.srcKind;
// set treatBitcodeAsData
_treateBitcodeAsData = opts.treateBitcodeAsData;
_usingBitcode = opts.usingBitcode;
// respond to -t option
if ( opts.logAllFiles )
@ -2170,8 +2174,12 @@ bool Parser<A>::parseLoadCommands(Options::Platform platform, uint32_t linkMinOS
break;
#if SUPPORT_APPLE_TV
case Options::kPlatform_tvOS:
// tvOS is a warning temporarily. rdar://problem/21746965
if (platform == Options::kPlatform_tvOS)
// Error when using bitcocde, warning otherwise.
if (_usingBitcode)
throwf("building for %s%s, but linking in object file built for %s,",
Options::platformName(platform), (simulator ? " simulator" : ""),
Options::platformName(lcPlatform));
else
warning("URGENT: building for %s%s, but linking in object file (%s) built for %s. "
"Note: This will be an error in the future.",
Options::platformName(platform), (simulator ? " simulator" : ""), path(),
@ -2533,6 +2541,7 @@ void Parser<A>::makeSections()
}
}
if ( strcmp(sect->segname(), "__LLVM") == 0 ) {
// Process bitcode segement
if ( strncmp(sect->sectname(), "__bitcode", 9) == 0 ) {
bitcodeSect = sect;
} else if ( strncmp(sect->sectname(), "__cmdline", 9) == 0 ) {
@ -2544,9 +2553,8 @@ void Parser<A>::makeSections()
} else if ( strncmp(sect->sectname(), "__asm", 5) == 0 ) {
bitcodeAsm = true;
}
// If it is not single input for ld -r, don't count the section
// otherwise, fall through and add it to the sections.
if (_file->sourceKind() != ld::relocatable::File::kSourceSingle)
// If treat the bitcode as data, continue to parse as a normal section.
if ( !_treateBitcodeAsData )
continue;
}
// ignore empty __OBJC sections

View File

@ -47,6 +47,8 @@ struct ParserOptions {
Options::Platform platform;
uint32_t minOSVersion;
ld::relocatable::File::SourceKind srcKind;
bool treateBitcodeAsData;
bool usingBitcode;
};
extern ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength,

View File

@ -315,6 +315,10 @@ class TBDFile {
bool parseArchFlowSequence(Token archName) {
expectToken("archs");
// <rdar://problem/22268737> 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 )

View File

@ -33,6 +33,7 @@
#include <unistd.h>
#include <time.h>
#include <unordered_map>
#include <sstream>
#include "llvm-c/lto.h"
// c header
@ -109,23 +110,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) :
@ -181,7 +191,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;
};
@ -194,11 +204,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:
@ -268,8 +290,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
@ -309,6 +335,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
@ -342,6 +380,11 @@ ObjectHandler::~ObjectHandler()
destroyFile();
}
SymbolListHandler::~SymbolListHandler()
{
destroyFile();
}
void BundleHandler::init()
{
if ( _xar != NULL )
@ -385,8 +428,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);
}
@ -437,6 +482,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();
@ -472,7 +528,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;
}
@ -493,7 +555,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);
@ -504,12 +592,19 @@ void ObjectHandler::obfuscateAndWriteToPath(BitcodeObfuscator *obfuscator, const
void BitcodeBundle::doPass()
{
if ( _state.embedMarkerOnly ) {
assert( _options.outputKind() != Options::kDynamicExecutable &&
_options.outputKind() != Options::kStaticExecutable &&
"Don't emit marker for executables");
BitcodeAtom* marker = new BitcodeAtom();
_state.addAtom(*marker);
if ( _options.bitcodeKind() == Options::kBitcodeStrip ||
_options.bitcodeKind() == Options::kBitcodeAsData )
// if emit no bitcode or emit bitcode segment as data, no need to generate bundle.
return;
else if ( _state.embedMarkerOnly || _options.bitcodeKind() == Options::kBitcodeMarker ) {
// if the bitcode is just a marker,
// the executable will be created without bitcode section.
// Otherwise, create a marker.
if( _options.outputKind() != Options::kDynamicExecutable &&
_options.outputKind() != Options::kStaticExecutable ) {
BitcodeAtom* marker = new BitcodeAtom();
_state.addAtom(*marker);
}
return;
}
@ -545,7 +640,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());
}
}
@ -558,6 +653,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<ld::LLVMBitcode*>(f->getBitcode()) ) {
BitcodeHandler* bitcodeHandler = new BitcodeHandler((char*)bitcode->getContent(), bitcode->getSize());
bitcodeHandler->populateMustPreserveSymbols(obfuscator);
}
}
// special symbols supplied by linker
@ -698,24 +796,120 @@ void BitcodeBundle::doPass()
}
// Write exports file
// A vector of all the exported symbols.
if ( _options.hasExportMaskList() ) {
std::vector<const char*> exportedSymbols;
for ( auto &sect : _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<const char*> exports = _options.exportsData();
std::string exps;
for (std::vector<const char*>::iterator it = exports.begin();
it != exports.end(); ++ it) {
for (std::vector<const char*>::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<char*>(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<const char*> unexportedSymbols;
for ( auto &sect : _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<const char*>::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<char*>(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<char*>(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
@ -746,22 +940,23 @@ void BitcodeBundle::doPass()
throwf("could not add SDK version to bitcode bundle");
// Write dylibs
const char* sdkRoot = NULL;
if ( !_options.sdkPaths().empty() )
sdkRoot = _options.sdkPaths().front();
char sdkRoot[PATH_MAX];
if ( _options.sdkPaths().empty() || (realpath(_options.sdkPaths().front(), sdkRoot) == NULL) )
strcpy(sdkRoot, "/");
if ( !_state.dylibs.empty() ) {
std::vector<const char*> SDKPaths = _options.sdkPaths();
char dylibPath[PATH_MAX];
for ( auto &dylib : _state.dylibs ) {
// For every dylib/framework, figure out if it is coming from a SDK
// if it is coming from some SDK, we parse the path to figure out which SDK
// If -syslibroot is pointing to a SDK, it should end with PlatformX.Y.sdk/
if (sdkRoot && strncmp(dylib->path(), sdkRoot, strlen(sdkRoot)) == 0) {
// dylib/framework from one of the -syslibroot
// For every dylib/framework, figure out if it is coming from a SDK.
// The dylib/framework from SDK must begin with '/' and user framework must begin with '@'.
if (dylib->installPath()[0] == '/') {
// Verify the path of the framework is within the SDK.
char dylibRealPath[PATH_MAX];
if ( realpath(dylib->path(), dylibRealPath) != NULL && strncmp(sdkRoot, dylibRealPath, strlen(sdkRoot)) != 0 )
warning("%s has install name beginning with \"/\" but it is not from the specified SDK", dylib->path());
// The path start with a string template
strcpy(dylibPath, "{SDKPATH}/");
strcpy(dylibPath, "{SDKPATH}");
// append the path of dylib/frameowrk in the SDK
strcat(dylibPath, dylib->path() + strlen(sdkRoot));
strcat(dylibPath, dylib->installPath());
} else {
// Not in any SDKs, then assume it is a user dylib/framework
// strip off all the path in the front

View File

@ -1284,7 +1284,8 @@ static ld::relocatable::File* createReader(const char* path)
objOpts.verboseOptimizationHints = true;
objOpts.armUsesZeroCostExceptions = true;
objOpts.subType = sPreferredSubArch;
objOpts.srcKind = ld::relocatable::File::kSourceObj;
objOpts.treateBitcodeAsData = false;
objOpts.usingBitcode = true;
#if 1
if ( ! foundFatSlice ) {
cpu_type_t archOfObj;

View File

@ -27,6 +27,7 @@
#include <signal.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <errno.h>
#include "stuff/errors.h"
#include "stuff/allocate.h"
#include "stuff/execute.h"
@ -71,7 +72,10 @@ int verbose)
return(1); /* can't get here, removes a warning from the compiler */
}
else{
waitpid = wait(&waitstatus);
waitpid = -1;
do{
waitpid = wait(&waitstatus);
} while (waitpid == -1 && errno == EINTR);
if(waitpid == -1)
system_fatal("wait on forked process %d failed", forkpid);
#ifndef __OPENSTEP__

View File

@ -4204,6 +4204,26 @@ check_linkedit_data_command:
}
break;
case LC_VERSION_MIN_TVOS:
if(l.cmdsize < sizeof(struct version_min_command)){
Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
" cmdsize too small) in command %u",i);
goto return_bad;
}
if(vers != NULL){
Mach_O_error(ofile, "malformed object (more than one "
"LC_VERSION_MIN_ command)");
goto return_bad;
}
vers = (struct version_min_command *)lc;
if(swapped)
swap_version_min_command(vers, host_byte_sex);
if(vers->cmdsize < sizeof(struct version_min_command)){
Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
" command %u has too small cmdsize field)", i);
goto return_bad;
}
break;
case LC_VERSION_MIN_WATCHOS:
if(l.cmdsize < sizeof(struct version_min_command)){

View File

@ -1171,6 +1171,15 @@ check_dylinker_command:
}
break;
case LC_VERSION_MIN_TVOS:
vc = (struct version_min_command *)lc;
if(vc->cmdsize != sizeof(struct version_min_command)){
error("in swap_object_headers(): malformed load commands "
"(LC_VERSION_MIN_ command %lu has incorrect "
"cmdsize", i);
return(FALSE);
}
break;
case LC_VERSION_MIN_WATCHOS:
vc = (struct version_min_command *)lc;
@ -1760,6 +1769,7 @@ check_dylinker_command:
case LC_VERSION_MIN_MACOSX:
case LC_VERSION_MIN_IPHONEOS:
case LC_VERSION_MIN_WATCHOS:
case LC_VERSION_MIN_TVOS:
vc = (struct version_min_command *)lc;
swap_version_min_command(vc, target_byte_sex);
break;

View File

@ -23,11 +23,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libc.h>
#include "stuff/bool.h"
#include "stuff/errors.h"
#include "stuff/breakout.h"
#include "stuff/allocate.h"
#include "stuff/rnd.h"
#include "stuff/execute.h"
/* used by error routines as the name of the program */
char *progname = NULL;
@ -35,6 +37,7 @@ char *progname = NULL;
static enum bool rflag = FALSE; /* remove bitcode segment */
static enum bool mflag = FALSE; /* remove bitcode but leave a marker segment */
static enum bool lflag = FALSE; /* leave only bitcode segment */
static enum bool vflag = FALSE; /* to print internal commands that are run */
/*
* We shortcut bitcode_strip(1) to do nothing with the -r option when there is
@ -53,14 +56,17 @@ static void process(
static enum bool check_object(
struct arch *arch,
struct member *member,
struct object *object);
static void strip_bitcode_segment(
struct arch *arch,
struct member *member,
struct object *object);
static void leave_just_bitcode_segment(
struct arch *arch,
struct member *member,
struct object *object);
static void strip_bitcode_from_load_commands(
@ -75,6 +81,20 @@ static void reset_pointers_for_object_load_commands(
struct arch *arch,
struct object *object);
static void make_ld_process_mh_object(
struct arch *arch,
struct member *member,
struct object *object);
static void make_ld_r_object(
struct arch *arch,
struct object *object);
static void setup_symbolic_info_for_mh_object(
struct arch *arch,
struct member *member,
struct object *object);
/*
* The bitcode_strip(1) program takes one of two options:
* -r remove the bitcode segment
@ -132,6 +152,9 @@ char **envp)
}
mflag = TRUE;
}
else if(strcmp(argv[i], "-v") == 0){
vflag = TRUE;
}
else{
if(input != NULL){
error("more than one input file specified (%s and %s)",
@ -157,13 +180,26 @@ char **envp)
process(archs, narchs);
/*
* We shortcut bitcode_strip(1) to do nothing with the -r option when
* there is no bitcode and the input file is the same as the output
* file.
* We shortcut bitcode_strip(1) with the -r option when there is no
* bitcode.
*/
if(rflag && some_slice_has_bitcode == FALSE &&
strcmp(input, output) == 0)
if(rflag && some_slice_has_bitcode == FALSE){
/* If the input file is the same as the output file do nothing. */
if(strcmp(input, output) == 0)
return(EXIT_SUCCESS);
/*
* Otherwise cp(1) the input to the output to not mess up the
* code signature
*/
reset_execute_list();
add_execute_list("/bin/cp");
add_execute_list(input);
add_execute_list(output);
if(execute_list(vflag) == 0)
fatal("internal /bin/cp command failed");
return(EXIT_SUCCESS);
}
writeout(archs, narchs, output, 0777, TRUE, FALSE, FALSE, NULL);
@ -197,28 +233,25 @@ struct arch *archs,
uint32_t narchs)
{
uint32_t i;
#ifdef ALLOW_ARCHIVES
uint32_t j, offset, size;
#endif
struct object *object;
for(i = 0; i < narchs; i++){
if(archs[i].type == OFILE_ARCHIVE){
#ifndef ALLOW_ARCHIVES
error_arch(archs + i, NULL, "input file must be a linked "
"Mach-O file not an archive: ");
return;
#else /* defined(ALLOW_ARCHIVES) */
for(j = 0; j < archs[i].nmembers; j++){
if(archs[i].members[j].type == OFILE_Mach_O){
object = archs[i].members[j].object;
if(check_object(archs + i, object) == FALSE)
if(check_object(archs + i, archs[i].members + j,
object) == FALSE)
return;
if(rflag || (object->seg_bitcode == NULL &&
object->seg_bitcode64 == NULL))
strip_bitcode_segment(archs + i, object);
if(rflag || mflag)
strip_bitcode_segment(archs + i,
archs[i].members + j, object);
else
leave_just_bitcode_segment(archs + i, object);
leave_just_bitcode_segment(archs + i,
archs[i].members + j,
object);
}
}
/*
@ -230,13 +263,18 @@ uint32_t narchs)
size = 0;
if(archs[i].members[j].member_long_name == TRUE){
size = rnd(archs[i].members[j].member_name_size,
sizeof(int32_t));
sizeof(int64_t));
size = rnd(archs[i].members[j].member_name_size, 8) +
(rnd(sizeof(struct ar_hdr), 8) -
sizeof(struct ar_hdr));
archs[i].toc_long_name = TRUE;
}
if(archs[i].members[j].object != NULL){
size += archs[i].members[j].object->object_size
- archs[i].members[j].object->input_sym_info_size
+ archs[i].members[j].object->output_sym_info_size;
size +=
rnd(archs[i].members[j].object->object_size -
archs[i].members[j].object->input_sym_info_size +
archs[i].members[j].object->output_sym_info_size,
8);
sprintf(archs[i].members[j].ar_hdr->ar_size, "%-*ld",
(int)sizeof(archs[i].members[j].ar_hdr->ar_size),
(long)(size));
@ -253,17 +291,15 @@ uint32_t narchs)
offset += sizeof(struct ar_hdr) + size;
}
archs[i].library_size = offset;
#endif /* defined(ALLOW_ARCHIVES) */
}
else if(archs[i].type == OFILE_Mach_O){
object = archs[i].object;
if(check_object(archs +i, object) == FALSE)
if(check_object(archs + i, NULL, object) == FALSE)
return;
if(rflag || mflag || (object->seg_bitcode == NULL &&
object->seg_bitcode64 == NULL))
strip_bitcode_segment(archs + i, object);
if(rflag || mflag)
strip_bitcode_segment(archs + i, NULL, object);
else
leave_just_bitcode_segment(archs + i, object);
leave_just_bitcode_segment(archs + i, NULL, object);
}
}
}
@ -271,15 +307,16 @@ uint32_t narchs)
/*
* check_object() checks to make sure the object is one that can processed for
* stripping the bitcode segment or just leaving only the bitcode segment.
* This must be a fully linked Mach-O file for use with the dynamic linker.
* And if built for the Watch OS it must have a bitcode segment.
* And the bitcode segment must not have any relocation entries or symbols
* defined it its sections. And its sections must be of type S_REGULAR.
* If not a .o file this must be a fully linked Mach-O file for use with the
* dynamic linker. And the bitcode segment must not have any relocation
* entries or symbols defined it its sections. And its sections must be of
* type S_REGULAR.
*/
static
enum bool
check_object(
struct arch *arch,
struct member *member,
struct object *object)
{
uint32_t i, mh_ncmds, mh_flags;
@ -295,19 +332,19 @@ struct object *object)
sg64 = NULL; /* cctools-port */
if(arch->object->mh != NULL){
mh_ncmds = arch->object->mh->ncmds;
if(object->mh != NULL){
mh_ncmds = object->mh->ncmds;
mh_flags = object->mh->flags;
}
else{
mh_ncmds = arch->object->mh64->ncmds;
mh_ncmds = object->mh64->ncmds;
mh_flags = object->mh64->flags;
}
if((mh_flags & MH_DYLDLINK) != MH_DYLDLINK)
fatal_arch(arch, NULL, "can't be used on a file not built for use "
"with the dynamic linker: ");
if(object->mh_filetype != MH_OBJECT &&
(mh_flags & MH_DYLDLINK) != MH_DYLDLINK)
fatal_arch(arch, member, "can't be used on a file not built for "
"use with the dynamic linker: ");
/*
* If it has a bitcode segment it can't have any relocation entries.
@ -329,7 +366,7 @@ struct object *object)
if(object->seg_bitcode != NULL || object->seg_bitcode64 != NULL){
section_ordinal = 1;
first_bitcode_section_ordinal = 0;
lc = arch->object->load_commands;
lc = object->load_commands;
for(i = 0; i < mh_ncmds && first_bitcode_section_ordinal == 0; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
@ -338,7 +375,7 @@ struct object *object)
last_bitcode_section_ordinal = section_ordinal +
sg->nsects;
}
section_ordinal += sg64->nsects;
section_ordinal += sg->nsects;
}
else if(lc->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc;
@ -359,8 +396,8 @@ struct object *object)
if((symbols[i].n_type & N_TYPE) == N_SECT &&
symbols[i].n_sect >= first_bitcode_section_ordinal &&
symbols[i].n_sect < last_bitcode_section_ordinal){
fatal_arch(arch, NULL, "bitcode segment can't have "
"symbols defined it its sections in: ");
fatal_arch(arch, member, "bitcode segment can't "
"have symbols defined it its sections in: ");
}
}
}
@ -372,8 +409,8 @@ struct object *object)
symbols64[i].n_sect >=
first_bitcode_section_ordinal &&
symbols64[i].n_sect < last_bitcode_section_ordinal){
fatal_arch(arch, NULL, "bitcode segment can't have "
"symbols defined it its sections in: ");
fatal_arch(arch, member, "bitcode segment can't "
"have symbols defined it its sections in: ");
}
}
}
@ -389,7 +426,7 @@ struct object *object)
sizeof(struct segment_command));
for(i = 0; i < object->seg_bitcode->nsects; i++){
if((s->flags & SECTION_TYPE) != S_REGULAR)
fatal_arch(arch, NULL, "bitcode segment can't have "
fatal_arch(arch, member, "bitcode segment can't have "
"sections that are not of type S_REGULAR in: ");
s++;
}
@ -399,7 +436,7 @@ struct object *object)
sizeof(struct segment_command_64));
for(i = 0; i < object->seg_bitcode64->nsects; i++){
if((s64->flags & SECTION_TYPE) != S_REGULAR)
fatal_arch(arch, NULL, "bitcode segment can't have "
fatal_arch(arch, member, "bitcode segment can't have "
"sections that are not of type S_REGULAR in: ");
s64++;
}
@ -414,8 +451,8 @@ struct object *object)
#if 0
if(lflag == TRUE &&
object->seg_bitcode == NULL && object->seg_bitcode64 == NULL)
fatal_arch(arch, NULL, "-l to leave only bitcode segment can't be "
"used on a file without a __LLVM segment: ");
fatal_arch(arch, member, "-l to leave only bitcode segment can't "
"be used on a file without a __LLVM segment: ");
#endif
return(TRUE);
@ -440,6 +477,7 @@ static
void
strip_bitcode_segment(
struct arch *arch,
struct member *member,
struct object *object)
{
uint32_t start_offset, offset, end_of_string_table, alignment_padding;
@ -454,6 +492,17 @@ struct object *object)
segalign = 0; /* cctools-port */
/*
* For MH_OBJECT files, .o files, the bitcode info is in two sections
* and requires a static link editor operation to remove or change to
* a marker. So to do this an ld(1) -r is run with an option to
* process the object file as needed.
*/
if(object->mh_filetype == MH_OBJECT){
make_ld_process_mh_object(arch, member, object);
return;
}
/*
* If we are removing the bitcode segment and leaving just a marker
* calculate a minimum sized segment contents with all zeros which
@ -911,6 +960,7 @@ static
void
leave_just_bitcode_segment(
struct arch *arch,
struct member *member,
struct object *object)
{
uint32_t i, start_offset, offset, sect_offset;
@ -920,6 +970,16 @@ struct object *object)
struct section *s;
struct section_64 *s64;
/*
* For MH_OBJECT files, .o files there is no static link editor
* operation to just leave the bitcode. So this is a hard error.
*/
if(object->mh_filetype == MH_OBJECT) {
fatal_arch(arch, member, "Can't use the -l option on .o files "
"(filetypes of MH_OBJECT) for: ");
return;
}
/*
* To get the right amount of the start of the file copied out by
* writeout() before the symbolic information for this case when we
@ -942,8 +1002,8 @@ struct object *object)
*/
if(object->mh != NULL){
start_offset = 0;
lc = arch->object->load_commands;
for(i = 0; i < arch->object->mh->ncmds && start_offset == 0; i++){
lc = object->load_commands;
for(i = 0; i < object->mh->ncmds && start_offset == 0; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
if(sg->filesize != 0 && sg->fileoff == 0){
@ -982,8 +1042,8 @@ struct object *object)
}
else{
start_offset = 0;
lc = arch->object->load_commands;
for(i = 0; i < arch->object->mh64->ncmds && start_offset == 0; i++){
lc = object->load_commands;
for(i = 0; i < object->mh64->ncmds && start_offset == 0; i++){
if(lc->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc;
if(sg64->filesize != 0 && sg64->fileoff == 0){
@ -1194,13 +1254,13 @@ struct object *object)
* Allocate space for the new load commands and zero it out so any holes
* will be zero bytes.
*/
if(arch->object->mh != NULL){
mh_ncmds = arch->object->mh->ncmds;
mh_sizeofcmds = arch->object->mh->sizeofcmds;
if(object->mh != NULL){
mh_ncmds = object->mh->ncmds;
mh_sizeofcmds = object->mh->sizeofcmds;
}
else{
mh_ncmds = arch->object->mh64->ncmds;
mh_sizeofcmds = arch->object->mh64->sizeofcmds;
mh_ncmds = object->mh64->ncmds;
mh_sizeofcmds = object->mh64->sizeofcmds;
}
new_load_commands = allocate(mh_sizeofcmds);
memset(new_load_commands, '\0', mh_sizeofcmds);
@ -1211,7 +1271,7 @@ struct object *object)
* Unless the -m flag is specified then do copy the bitcode segment
* load command.
*/
lc1 = arch->object->load_commands;
lc1 = object->load_commands;
lc2 = new_load_commands;
new_ncmds = 0;
new_sizeofcmds = 0;
@ -1248,16 +1308,16 @@ struct object *object)
* Finally copy the updated load commands over the existing load
* commands.
*/
memcpy(arch->object->load_commands, new_load_commands, new_sizeofcmds);
memcpy(object->load_commands, new_load_commands, new_sizeofcmds);
if(mh_sizeofcmds > new_sizeofcmds)
memset((char *)arch->object->load_commands + new_sizeofcmds,
memset((char *)object->load_commands + new_sizeofcmds,
'\0', (mh_sizeofcmds - new_sizeofcmds));
if(arch->object->mh != NULL) {
arch->object->mh->sizeofcmds = new_sizeofcmds;
arch->object->mh->ncmds = new_ncmds;
if(object->mh != NULL) {
object->mh->sizeofcmds = new_sizeofcmds;
object->mh->ncmds = new_ncmds;
} else {
arch->object->mh64->sizeofcmds = new_sizeofcmds;
arch->object->mh64->ncmds = new_ncmds;
object->mh64->sizeofcmds = new_sizeofcmds;
object->mh64->ncmds = new_ncmds;
}
free(new_load_commands);
@ -1297,13 +1357,13 @@ struct object *object)
* Allocate space for the new load commands and zero it out so any holes
* will be zero bytes.
*/
if(arch->object->mh != NULL){
mh_ncmds = arch->object->mh->ncmds;
mh_sizeofcmds = arch->object->mh->sizeofcmds;
if(object->mh != NULL){
mh_ncmds = object->mh->ncmds;
mh_sizeofcmds = object->mh->sizeofcmds;
}
else{
mh_ncmds = arch->object->mh64->ncmds;
mh_sizeofcmds = arch->object->mh64->sizeofcmds;
mh_ncmds = object->mh64->ncmds;
mh_sizeofcmds = object->mh64->sizeofcmds;
}
new_load_commands = allocate(mh_sizeofcmds);
memset(new_load_commands, '\0', mh_sizeofcmds);
@ -1313,7 +1373,7 @@ struct object *object)
* LC_DYLIB_CODE_SIGN_DRS. For the segment commands other than the
* bitcode segment and linkedit segment zero out the fields.
*/
lc1 = arch->object->load_commands;
lc1 = object->load_commands;
lc2 = new_load_commands;
new_ncmds = 0;
new_sizeofcmds = 0;
@ -1386,16 +1446,16 @@ struct object *object)
* Finally copy the updated load commands over the existing load
* commands.
*/
memcpy(arch->object->load_commands, new_load_commands, new_sizeofcmds);
memcpy(object->load_commands, new_load_commands, new_sizeofcmds);
if(mh_sizeofcmds > new_sizeofcmds)
memset((char *)arch->object->load_commands + new_sizeofcmds,
memset((char *)object->load_commands + new_sizeofcmds,
'\0', (mh_sizeofcmds - new_sizeofcmds));
if(arch->object->mh != NULL) {
arch->object->mh->sizeofcmds = new_sizeofcmds;
arch->object->mh->ncmds = new_ncmds;
if(object->mh != NULL) {
object->mh->sizeofcmds = new_sizeofcmds;
object->mh->ncmds = new_ncmds;
} else {
arch->object->mh64->sizeofcmds = new_sizeofcmds;
arch->object->mh64->ncmds = new_ncmds;
object->mh64->sizeofcmds = new_sizeofcmds;
object->mh64->ncmds = new_ncmds;
}
free(new_load_commands);
@ -1426,40 +1486,40 @@ struct object *object)
struct segment_command *sg;
struct segment_command_64 *sg64;
if(arch->object->mh != NULL)
mh_ncmds = arch->object->mh->ncmds;
if(object->mh != NULL)
mh_ncmds = object->mh->ncmds;
else
mh_ncmds = arch->object->mh64->ncmds;
mh_ncmds = object->mh64->ncmds;
/* reset the pointers into the load commands */
lc = arch->object->load_commands;
lc = object->load_commands;
for(i = 0; i < mh_ncmds; i++){
switch(lc->cmd){
case LC_SYMTAB:
arch->object->st = (struct symtab_command *)lc;
object->st = (struct symtab_command *)lc;
break;
case LC_DYSYMTAB:
arch->object->dyst = (struct dysymtab_command *)lc;
object->dyst = (struct dysymtab_command *)lc;
break;
case LC_TWOLEVEL_HINTS:
arch->object->hints_cmd = (struct twolevel_hints_command *)lc;
object->hints_cmd = (struct twolevel_hints_command *)lc;
break;
case LC_PREBIND_CKSUM:
arch->object->cs = (struct prebind_cksum_command *)lc;
object->cs = (struct prebind_cksum_command *)lc;
break;
case LC_SEGMENT:
sg = (struct segment_command *)lc;
if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
arch->object->seg_linkedit = sg;
object->seg_linkedit = sg;
else if(strcmp(sg->segname, "__LLVM") == 0)
arch->object->seg_bitcode = sg;
object->seg_bitcode = sg;
break;
case LC_SEGMENT_64:
sg64 = (struct segment_command_64 *)lc;
if(strcmp(sg64->segname, SEG_LINKEDIT) == 0)
arch->object->seg_linkedit64 = sg64;
object->seg_linkedit64 = sg64;
else if(strcmp(sg64->segname, "__LLVM") == 0)
arch->object->seg_bitcode64 = sg64;
object->seg_bitcode64 = sg64;
break;
case LC_SEGMENT_SPLIT_INFO:
object->split_info_cmd = (struct linkedit_data_command *)lc;
@ -1489,3 +1549,385 @@ struct object *object)
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
/*
* For MH_OBJECT files, .o files, the bitcode info is in two sections and
* requires a static link editor operation to remove or change to a marker.
* So to do this an ld(1) -r is run with an option to process the object file
* as needed.
*/
static
void
make_ld_process_mh_object(
struct arch *arch,
struct member *member,
struct object *object)
{
/*
* We set this so the optimizations of doing nothing or of copying over
* the input to the output does not happen. See the code at the end
* of main() above.
*/
if(rflag)
some_slice_has_bitcode = TRUE;
make_ld_r_object(arch, object);
setup_symbolic_info_for_mh_object(arch, member, object);
}
/*
* make_ld_r_object() takes the object file contents referenced by the passed
* data structures, writes that to a temporary file. Then runs "ld -r" plus an
* option to get the bitcode removed or replaced with a marker creating a second
* temporary file. This is then read in and replaces the object file contents
* with that.
*/
static
void
make_ld_r_object(
struct arch *arch,
struct object *object)
{
enum byte_sex host_byte_sex;
char *input_file, *output_file;
int fd;
struct ofile *ld_r_ofile;
struct arch *ld_r_archs;
uint32_t ld_r_narchs, save_errors;
host_byte_sex = get_host_byte_sex();
/*
* Swap the object file back into its bytesex before writing it to the
* temporary file if needed.
*/
if(object->object_byte_sex != host_byte_sex){
if(object->mh != NULL){
if(swap_object_headers(object->mh, object->load_commands) ==
FALSE)
fatal("internal error: swap_object_headers() failed");
}
else{
if(swap_object_headers(object->mh64, object->load_commands) ==
FALSE)
fatal("internal error: swap_object_headers() failed");
}
}
/*
* Create an input object file for the ld -r command from the bytes
* of this arch's object file.
*/
input_file = makestr("/tmp/bitcode_strip.XXXXXX", NULL);
input_file = mktemp(input_file);
if((fd = open(input_file, O_WRONLY|O_CREAT, 0600)) < 0)
system_fatal("can't open temporary file: %s", input_file);
if(write(fd, object->object_addr, object->object_size) !=
object->object_size)
system_fatal("can't write temporary file: %s", input_file);
if(close(fd) == -1)
system_fatal("can't close temporary file: %s", input_file);
/*
* Create a temporary name for the output file of the ld -r
*/
output_file = makestr("/tmp/bitcode_strip.XXXXXX", NULL);
output_file = mktemp(output_file);
/*
* Create the ld -r command line and execute it.
*/
reset_execute_list();
add_execute_list_with_prefix("ld");
add_execute_list("-keep_private_externs");
add_execute_list("-r");
if(rflag){
add_execute_list("-bitcode_process_mode");
add_execute_list("strip");
}
else if(mflag){
add_execute_list("-bitcode_process_mode");
add_execute_list("marker");
}
add_execute_list(input_file);
add_execute_list("-o");
add_execute_list(output_file);
if(execute_list(vflag) == 0)
fatal("internal link edit command failed");
save_errors = errors;
errors = 0;
/* breakout the output file of the ld -f for processing */
ld_r_ofile = breakout(output_file, &ld_r_archs, &ld_r_narchs, FALSE);
if(errors)
goto make_ld_r_object_cleanup;
/* checkout the file for processing */
checkout(ld_r_archs, ld_r_narchs);
/*
* Make sure the output of the ld -r is an object file with one arch.
*/
if(ld_r_narchs != 1 ||
ld_r_archs->type != OFILE_Mach_O ||
ld_r_archs->object == NULL ||
ld_r_archs->object->mh_filetype != MH_OBJECT)
fatal("internal link edit command failed to produce a thin Mach-O "
"object file");
/*
* Copy over the object struct from the ld -r object file onto the
* input object file.
*/
*object = *ld_r_archs->object;
/*
* Save the ofile struct for the ld -r output so it can be umapped when
* we are done. And free up the ld_r_archs now that we are done with
* them.
*/
object->ld_r_ofile = ld_r_ofile;
free_archs(ld_r_archs, ld_r_narchs);
make_ld_r_object_cleanup:
errors += save_errors;
/*
* Remove the input and output files and clean up.
*/
if(unlink(input_file) == -1)
system_fatal("can't remove temporary file: %s", input_file);
if(unlink(output_file) == -1)
system_fatal("can't remove temporary file: %s", output_file);
free(input_file);
free(output_file);
}
/*
* setup_symbolic_info_for_mh_object() is called after a .o file has been
* modified as needed by an "ld -r" execution. Here the symbolic info and
* sizes are set into the object struct. So it can be later written out by
* the writeout() call. No processing is done here just setting up the object
* struct's input_sym_info_size and output_sym_info_size value and all the
* output_* fields and offsets to the symbolic info so it is written out
* correctly.
*/
static
void
setup_symbolic_info_for_mh_object(
struct arch *arch,
struct member *member,
struct object *object)
{
uint32_t offset, start_offset;
/*
* Determine the starting offset of the symbolic info in the .o file
* which can be determined because of the order symbolic info has
* already been confirmed when the by previous call to checkout().
* This this routine only deals with MH_OBJECT filetypes so some info
* should not be present in .o files which is consider an error here.
*/
offset = UINT_MAX;
/* There should be no link edit segment in a .o file. */
if(object->seg_linkedit != NULL || object->seg_linkedit64 != NULL)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain a "
"link edit segment");
if(object->dyst != NULL && object->dyst->nlocrel != 0)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain "
"local relocation entries in the dynamic symbol table");
if(object->func_starts_info_cmd != NULL &&
object->func_starts_info_cmd->datasize != 0 &&
object->func_starts_info_cmd->dataoff < offset)
offset = object->func_starts_info_cmd->dataoff;
if(object->data_in_code_cmd != NULL &&
object->data_in_code_cmd->datasize != 0 &&
object->data_in_code_cmd->dataoff < offset)
offset = object->data_in_code_cmd->dataoff;
if(object->link_opt_hint_cmd != NULL &&
object->link_opt_hint_cmd->datasize != 0 &&
object->link_opt_hint_cmd->dataoff < offset)
offset = object->link_opt_hint_cmd->dataoff;
if(object->st->nsyms != 0 &&
object->st->symoff < offset)
offset = object->st->symoff;
if(object->dyst != NULL && object->dyst->nextrel != 0)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain "
"external relocation entries in the dynamic symbol "
"table");
if(object->dyst != NULL &&
object->dyst->nindirectsyms != 0 &&
object->dyst->indirectsymoff < offset)
offset = object->dyst->indirectsymoff;
if(object->dyst != NULL && object->dyst->ntoc)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain "
"toc entries in the dynamic symbol table");
if(object->dyst != NULL && object->dyst->nmodtab != 0)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain "
"module entries in the dynamic symbol table");
if(object->dyst != NULL && object->dyst->nextrefsyms != 0)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain "
"external reference entries in the dynamic symbol "
"table");
if(object->st->strsize != 0 &&
object->st->stroff < offset)
offset = object->st->stroff;
start_offset = offset;
/*
* Size the input symbolic info and set up all the input symbolic info
* to be the output symbolic info except any code signature data which
* will be removed if the input file contains bitcode of we are leaving
* just bitcode.
*
* Assign the offsets to the symbolic data in the proper order and
* increment the local variable offset by the size of each part if the
* the symbolic data. The output_sym_info_size is then determined at
* the end as the difference of the local variable offset from the
* local variable start_offset.
*/
object->input_sym_info_size = 0;
object->output_sym_info_size = 0;
/* There should be no dyld info in a .o file. */
if(object->dyld_info != NULL)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain a "
"dyld info");
/* Local relocation entries off the dynamic symbol table would next in
the output, but there are not in .o files */
/* There should be no split info in a .o file. */
if(object->split_info_cmd != NULL)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain a "
"split info load command");
if(object->func_starts_info_cmd != NULL){
object->input_sym_info_size +=
object->func_starts_info_cmd->datasize;
object->output_func_start_info_data = object->object_addr +
object->func_starts_info_cmd->dataoff;
object->output_func_start_info_data_size =
object->func_starts_info_cmd->datasize;
object->func_starts_info_cmd->dataoff = offset;
offset += object->func_starts_info_cmd->datasize;
}
if(object->data_in_code_cmd != NULL){
object->input_sym_info_size +=
object->data_in_code_cmd->datasize;
object->output_data_in_code_info_data = object->object_addr +
object->data_in_code_cmd->dataoff;
object->output_data_in_code_info_data_size =
object->data_in_code_cmd->datasize;
object->data_in_code_cmd->dataoff = offset;
offset += object->data_in_code_cmd->datasize;
}
if(object->code_sign_drs_cmd != NULL)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain a "
"code signature load command");
if(object->link_opt_hint_cmd != NULL){
object->input_sym_info_size +=
object->link_opt_hint_cmd->datasize;
object->output_link_opt_hint_info_data = object->object_addr +
object->link_opt_hint_cmd->dataoff;
object->output_link_opt_hint_info_data_size =
object->link_opt_hint_cmd->datasize;
object->link_opt_hint_cmd->dataoff = offset;
offset += object->link_opt_hint_cmd->datasize;
}
if(object->st != NULL && object->st->nsyms != 0){
if(object->mh != NULL){
object->input_sym_info_size +=
object->st->nsyms * sizeof(struct nlist);
object->output_symbols = (struct nlist *)
(object->object_addr + object->st->symoff);
if(object->object_byte_sex != get_host_byte_sex())
swap_nlist(object->output_symbols,
object->st->nsyms,
get_host_byte_sex());
object->output_symbols64 = NULL;
}
else{
object->input_sym_info_size +=
object->st->nsyms * sizeof(struct nlist_64);
object->output_symbols64 = (struct nlist_64 *)
(object->object_addr + object->st->symoff);
if(object->object_byte_sex != get_host_byte_sex())
swap_nlist_64(object->output_symbols64,
object->st->nsyms,
get_host_byte_sex());
object->output_symbols = NULL;
}
object->output_nsymbols = object->st->nsyms;
object->st->symoff = offset;
if(object->mh != NULL)
offset += object->st->nsyms * sizeof(struct nlist);
else
offset += object->st->nsyms * sizeof(struct nlist_64);
}
else if(object->st != NULL && object->st->nsyms == 0)
object->st->symoff = 0;
if(object->hints_cmd != NULL)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain a "
"two level hints load command");
// Note that this should always be true in objects this program
// operates on as it does not need to work on staticly linked images.
if(object->dyst != NULL){
object->output_ilocalsym = object->dyst->ilocalsym;
object->output_nlocalsym = object->dyst->nlocalsym;
object->output_iextdefsym = object->dyst->iextdefsym;
object->output_nextdefsym = object->dyst->nextdefsym;
object->output_iundefsym = object->dyst->iundefsym;
object->output_nundefsym = object->dyst->nundefsym;
/* External relocation entries off the dynamic symbol table would
next in the output, but there are not in .o files */
if(object->dyst->nindirectsyms != 0){
object->input_sym_info_size +=
object->dyst->nindirectsyms * sizeof(uint32_t) +
object->input_indirectsym_pad;
object->output_indirect_symtab = (uint32_t *)
(object->object_addr + object->dyst->indirectsymoff);
object->dyst->indirectsymoff = offset;
offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
object->input_indirectsym_pad;
}
else
object->dyst->indirectsymoff = 0;
/* Toc entries off the dynamic symbol table would
next in the output, but there are not in .o files */
/* Module entries off the dynamic symbol table would
next in the output, but there are not in .o files */
/* External references off the dynamic symbol table would
next in the output, but there are not in .o files */
}
if(object->st != NULL && object->st->strsize != 0){
object->input_sym_info_size += object->st->strsize;
object->output_strings = object->object_addr + object->st->stroff;
object->output_strings_size = object->st->strsize;
object->st->stroff = offset;
offset += object->st->strsize;
}
else{
object->st->stroff = 0;
}
/* The code signature would next in the output, but that is is not in
.o files */
object->output_sym_info_size = offset - start_offset;
}

View File

@ -767,6 +767,7 @@ void *cookie) /* cookie is not used */
uint32_t nloh;
struct dyld_bind_info *dbi;
uint64_t ndbi;
uint64_t big_size;
sorted_symbols = NULL;
nsorted_symbols = 0;
@ -1038,11 +1039,24 @@ void *cookie) /* cookie is not used */
/*
* Load commands.
*/
if(mh_sizeofcmds + sizeof_mach_header > size){
big_size = mh_sizeofcmds;
big_size += sizeof_mach_header;
if(big_size > size){
/*
* For malformed binaries trim the mh_sizeofcmds to be no bigger
* than the size of the file after the mach_header. This will
* limit the printing of the unknown load commands so it does not
* appear to be in an infinite loop printing the zero's we created
* with the memset().
*/
if(size > sizeof_mach_header)
mh_sizeofcmds = size - sizeof_mach_header;
else
mh_sizeofcmds = sizeof(struct load_command);
load_commands = allocate(mh_sizeofcmds);
memset(load_commands, '\0', mh_sizeofcmds);
memcpy(load_commands, ofile->load_commands,
size - sizeof_mach_header);
if(size > sizeof_mach_header)
memcpy(load_commands, ofile->load_commands, mh_sizeofcmds);
ofile->load_commands = load_commands;
}
if(lflag)

View File

@ -2293,6 +2293,7 @@ enum bool very_verbose)
case LC_VERSION_MIN_MACOSX:
case LC_VERSION_MIN_IPHONEOS:
case LC_VERSION_MIN_WATCHOS:
case LC_VERSION_MIN_TVOS:
memset((char *)&vd, '\0', sizeof(struct version_min_command));
size = left < sizeof(struct version_min_command) ?
left : sizeof(struct version_min_command);
@ -3504,6 +3505,8 @@ struct version_min_command *vd)
printf(" cmd LC_VERSION_MIN_IPHONEOS\n");
else if(vd->cmd == LC_VERSION_MIN_WATCHOS)
printf(" cmd LC_VERSION_MIN_WATCHOS\n");
else if(vd->cmd == LC_VERSION_MIN_TVOS)
printf(" cmd LC_VERSION_MIN_TVOS\n");
else
printf(" cmd %u (?)\n", vd->cmd);
printf(" cmdsize %u", vd->cmdsize);
@ -6043,7 +6046,7 @@ enum bool swapped)
uint32_t left, *state, i, j;
left = end - begin;
if(left * sizeof(uint32_t) >= count){
if(left / sizeof(uint32_t) >= count){
state = allocate(count * sizeof(uint32_t));
memcpy((char *)state, begin, count * sizeof(uint32_t));
begin += count * sizeof(uint32_t);

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
BASE_VERSION=870
NEW_VERSION=877.5
BASE_VERSION=877.5
NEW_VERSION=877.8
set -e

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
BASE_VERSION=242
NEW_VERSION=242.2
BASE_VERSION=253.3
NEW_VERSION=253.9
set -e