mirror of
https://github.com/darlinghq/cctools-port.git
synced 2025-02-16 23:28:02 +00:00
Merge branch 'master' into 877.8-ld64-253.9-ppc
Conflicts: README.md
This commit is contained in:
commit
13ee0a2fcb
105
.merge.log
105
.merge.log
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -1,4 +1,4 @@
|
||||
const char ldVersionString[] = "253.3\n";
|
||||
const char ldVersionString[] = "253.9\n";
|
||||
|
||||
#ifndef __APPLE__
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) ) {
|
||||
|
@ -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;
|
||||
|
@ -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() ) {
|
||||
|
@ -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;
|
||||
|
@ -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";
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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 )
|
||||
|
@ -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 § : _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 § : _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
|
||||
|
@ -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;
|
||||
|
@ -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__
|
||||
|
@ -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)){
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user