F984A13B10B614CF009E9878 /* stub_arm_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_arm_classic.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F984A38010BB4B0D009E9878 /* branch_island.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = branch_island.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F984A38110BB4B0D009E9878 /* branch_island.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = branch_island.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F98565241E98090F00528B1C /* dwarf2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2.h; path = src/ld/dwarf2.h; sourceTree = "<group>"; };
F989D0391062E6350014B60C /* stub_x86_64.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_64.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F989D30B106826020014B60C /* OutputFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OutputFile.cpp; path = src/ld/OutputFile.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F989D30C106826020014B60C /* OutputFile.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = OutputFile.h; path = src/ld/OutputFile.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
B091FB641ABA3AFB00CC8193 /* Bitcode.hpp */,
F9EA7582097882F3008B4F1D /* debugline.c */,
F9EA7583097882F3008B4F1D /* debugline.h */,
+ F98565241E98090F00528B1C /* dwarf2.h */,
B3B672411406D42800A376BB /* Snapshot.cpp */,
B3B672441406D44300A376BB /* Snapshot.h */,
);
F9023C3006D5A227001BBF46 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0600;
+ LastUpgradeCheck = 0900;
ORGANIZATIONNAME = "Apple Inc.";
};
buildConfigurationList = F933D92309291AC90083EAC8 /* Build configuration list for PBXProject "ld64" */;
83046A801C8FF23E00024A7E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
COPY_PHASE_STRIP = NO;
83046A811C8FF23E00024A7E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
COPY_PHASE_STRIP = YES;
83046A821C8FF23E00024A7E /* Release-assert */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
COPY_PHASE_STRIP = YES;
F933D91C09291AC90083EAC8 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_CXX_LIBRARY = "libc++";
COPY_PHASE_STRIP = NO;
F933D91D09291AC90083EAC8 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_CXX_LIBRARY = "libc++";
COPY_PHASE_STRIP = NO;
F933D92009291AC90083EAC8 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_CXX_LIBRARY = "libc++";
COPY_PHASE_STRIP = NO;
F933D92109291AC90083EAC8 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_CXX_LIBRARY = "libc++";
COPY_PHASE_STRIP = YES;
F933D92409291AC90083EAC8 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ EXCLUDED_INSTALLSRC_SUBDIRECTORY_PATTERNS = "$(inherited) build DerivedData";
GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx.internal;
};
F933D92509291AC90083EAC8 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ EXCLUDED_INSTALLSRC_SUBDIRECTORY_PATTERNS = "$(inherited) build DerivedData";
GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
SDKROOT = macosx.internal;
};
name = Release;
F9849FF810B5DE8E009E9878 /* Release-assert */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ EXCLUDED_INSTALLSRC_SUBDIRECTORY_PATTERNS = "$(inherited) build DerivedData";
GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
SDKROOT = macosx.internal;
};
name = "Release-assert";
F9849FFA10B5DE8E009E9878 /* Release-assert */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_CXX_LIBRARY = "libc++";
COPY_PHASE_STRIP = NO;
F9849FFD10B5DE8E009E9878 /* Release-assert */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_CXX_LIBRARY = "libc++";
COPY_PHASE_STRIP = YES;
#define DYLD_CACHE_ADJ_V2_IMAGE_OFF_32 0x0C
+#ifndef LC_BUILD_VERSION
+ #define LC_BUILD_VERSION 0x32 /* build for platform min OS version */
+
+ /*
+ * The build_version_command contains the min OS version on which this
+ * binary was built to run for its platform. The list of known platforms and
+ * tool values following it.
+ */
+ struct build_version_command {
+ uint32_t cmd; /* LC_BUILD_VERSION */
+ uint32_t cmdsize; /* sizeof(struct build_version_command) plus */
+ /* ntools * sizeof(struct build_tool_version) */
+ uint32_t platform; /* platform */
+ uint32_t minos; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
+ uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
+ uint32_t ntools; /* number of tool entries following this */
+ };
+
+ struct build_tool_version {
+ uint32_t tool; /* enum for the tool */
+ uint32_t version; /* version number of the tool */
+ };
+
+ /* Known values for the platform field above. */
+ #define PLATFORM_MACOS 1
+ #define PLATFORM_IOS 2
+ #define PLATFORM_TVOS 3
+ #define PLATFORM_WATCHOS 4
+ #define PLATFORM_BRIDGEOS 5
+
+ /* Known values for the tool field above. */
+ #define TOOL_CLANG 1
+ #define TOOL_SWIFT 2
+ #define TOOL_LD 3
+#endif
+
+#ifndef LC_NOTE
+ #define LC_NOTE 0x31
+ struct note_command {
+ uint32_t cmd; /* LC_NOTE */
+ uint32_t cmdsize; /* sizeof(struct note_command) */
+ char data_owner[16]; /* owner name for this LC_NOTE */
+ uint64_t offset; /* file offset of this data */
+ uint64_t size; /* length of data region */
+ };
+#endif
+
// kind target-address fixup-addr [adj]
#define SUPPORT_ARCH_arm_any 1
#endif
#if SUPPORT_ARCH_arm64
- { "arm64", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL, "arm64-", "aarch64-", false, false },
+ { "arm64", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL, "arm64-", "aarch64-", true, false },
#endif
#if SUPPORT_ARCH_arm64v8
{ "arm64v8", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_V8, "arm64v8-", "aarch64-", true, false },
};
+
+//
+// mach-o build version load command
+//
+template <typename P>
+class macho_build_version_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t platform() const INLINE { return fields.platform; }
+ void set_platform(uint32_t value) INLINE { E::set32(fields.platform, value); }
+
+ uint32_t minos() const INLINE { return fields.minos; }
+ void set_minos(uint32_t value) INLINE { E::set32(fields.minos, value); }
+
+ uint32_t sdk() const INLINE { return fields.sdk; }
+ void set_sdk(uint32_t value) INLINE { E::set32(fields.sdk, value); }
+
+ uint32_t ntools() const INLINE { return fields.ntools; }
+ void set_ntools(uint32_t value) INLINE { E::set32(fields.ntools, value); }
+
+
+ typedef typename P::E E;
+private:
+ build_version_command fields;
+};
+
+
+//
+// mach-o build version load command
+//
+template <typename P>
+class macho_build_tool_version {
+public:
+ uint32_t tool() const INLINE { return E::get32(fields.tool); }
+ void set_tool(uint32_t value) INLINE { E::set32(fields.tool, value); }
+
+ uint32_t version() const INLINE { return E::get32(fields.version); }
+ void set_version(uint32_t value) INLINE { E::set32(fields.version, value); }
+
+ typedef typename P::E E;
+private:
+ build_tool_version fields;
+};
+
+
+
+
//
// mach-o __LD, __compact_unwind section in object files
//
fi
echo "#define BITCODE_XAR_VERSION \"1.0\"" >> ${DERIVED_FILE_DIR}/configure.h
+
+if [ -n "${RC_ProjectSourceVersion}" ]; then
+ echo "#define LD64_VERSION_NUM ${RC_ProjectSourceVersion}" >> ${DERIVED_FILE_DIR}/configure.h
+else
+ echo "#define LD64_VERSION_NUM 0" >> ${DERIVED_FILE_DIR}/configure.h
+fi
uint8_t* copyRoutinesLoadCommand(uint8_t* p) const;
uint8_t* copyUUIDLoadCommand(uint8_t* p) const;
uint8_t* copyVersionLoadCommand(uint8_t* p) const;
+ uint8_t* copyBuildVersionLoadCommand(uint8_t* p) const;
uint8_t* copySourceVersionLoadCommand(uint8_t* p) const;
uint8_t* copyThreadsLoadCommand(uint8_t* p) const;
uint8_t* copyEntryPointLoadCommand(uint8_t* p) const;
bool _hasRPathLoadCommands;
bool _hasSubFrameworkLoadCommand;
bool _hasVersionLoadCommand;
+ bool _hasBuildVersionLoadCommand;
bool _hasFunctionStartsLoadCommand;
bool _hasDataInCodeLoadCommand;
bool _hasSourceVersionLoadCommand;
bool _hasOptimizationHints;
+ Options::Platform _platform;
uint32_t _dylibLoadCommmandsCount;
uint32_t _allowableClientLoadCommmandsCount;
uint32_t _dyldEnvironExrasCount;
mutable uint32_t _linkeditCmdOffset;
mutable uint32_t _symboltableCmdOffset;
std::vector< std::vector<const char*> > _linkerOptions;
+ std::unordered_set<uint64_t>& _toolsVersions;
static ld::Section _s_section;
static ld::Section _s_preload_section;
ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
ld::Atom::symbolTableNotIn, false, false, false,
(opts.outputKind() == Options::kPreload) ? ld::Atom::Alignment(0) : ld::Atom::Alignment(log2(opts.segmentAlignment())) ),
- _options(opts), _state(state), _writer(writer), _address(0), _uuidCmdInOutputBuffer(NULL), _linkeditCmdOffset(0), _symboltableCmdOffset(0)
+ _options(opts), _state(state), _writer(writer), _address(0), _uuidCmdInOutputBuffer(NULL), _linkeditCmdOffset(0), _symboltableCmdOffset(0),
+ _toolsVersions(state.toolsVersions)
{
bzero(_uuid, 16);
_hasDyldInfoLoadCommand = opts.makeCompressedDyldInfo();
}
_hasRPathLoadCommands = (_options.rpaths().size() != 0);
_hasSubFrameworkLoadCommand = (_options.umbrellaName() != NULL);
- _hasVersionLoadCommand = _options.addVersionLoadCommand() ||
- (!state.objectFileFoundWithNoVersion && (_options.outputKind() == Options::kObjectFile)
- && ((_options.platform() != Options::kPlatformUnknown) || (state.derivedPlatformLoadCommand != 0)) );
+ _platform = _options.platform();
+ if ( (_platform == Options::kPlatformUnknown) && (_state.derivedPlatform != 0) )
+ _platform = (Options::Platform)_state.derivedPlatform;
+ if ( _options.addVersionLoadCommand() ) {
+ _hasBuildVersionLoadCommand = _options.addBuildVersionLoadCommand();
+ _hasVersionLoadCommand = !_hasBuildVersionLoadCommand;
+ }
+ else if (((_options.outputKind() == Options::kObjectFile) && (_platform != Options::kPlatformUnknown) && !state.objectFileFoundWithNoVersion) ) {
+ _hasBuildVersionLoadCommand = (_platform == Options::kPlatform_bridgeOS);
+ _hasVersionLoadCommand = !_hasBuildVersionLoadCommand;
+ }
+ else {
+ _hasVersionLoadCommand = false;
+ _hasBuildVersionLoadCommand = false;
+ }
_hasFunctionStartsLoadCommand = _options.addFunctionStarts();
_hasDataInCodeLoadCommand = _options.addDataInCodeInfo();
_hasSourceVersionLoadCommand = _options.needsSourceVersionLoadCommand();
if ( _hasVersionLoadCommand )
sz += sizeof(macho_version_min_command<P>);
+ if ( _hasBuildVersionLoadCommand )
+ sz += alignedSize(sizeof(macho_build_version_command<P>) + sizeof(macho_build_tool_version<P>)*_toolsVersions.size());
+
if ( _hasSourceVersionLoadCommand )
sz += sizeof(macho_source_version_command<P>);
if ( _hasVersionLoadCommand )
++count;
+ if ( _hasBuildVersionLoadCommand )
+ ++count;
+
if ( _hasSourceVersionLoadCommand )
++count;
template <>
uint32_t HeaderAndLoadCommandsAtom<arm64>::cpuSubType() const
{
- return CPU_SUBTYPE_ARM64_ALL;
+ return _state.cpuSubType;
}
uint8_t* HeaderAndLoadCommandsAtom<A>::copyVersionLoadCommand(uint8_t* p) const
{
macho_version_min_command<P>* cmd = (macho_version_min_command<P>*)p;
- switch (_options.platform()) {
- case Options::kPlatformUnknown:
- assert(_state.derivedPlatformLoadCommand != 0 && "unknown platform");
- cmd->set_cmd(_state.derivedPlatformLoadCommand);
- cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
- cmd->set_version(_state.minOSVersion);
- cmd->set_sdk(0);
- break;
+ switch (_platform) {
case Options::kPlatformOSX:
cmd->set_cmd(LC_VERSION_MIN_MACOSX);
cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
cmd->set_sdk(_options.sdkVersion());
break;
#endif
+ case Options::kPlatformUnknown:
+ assert(0 && "unknown platform");
+ break;
+ case Options::kPlatform_bridgeOS:
+ assert(0 && "bridgeOS uses LC_BUILD_VERSION");
+ break;
}
return p + sizeof(macho_version_min_command<P>);
}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyBuildVersionLoadCommand(uint8_t* p) const
+{
+ macho_build_version_command<P>* cmd = (macho_build_version_command<P>*)p;
+
+ cmd->set_cmd(LC_BUILD_VERSION);
+ cmd->set_cmdsize(alignedSize(sizeof(macho_build_version_command<P>) + sizeof(macho_build_tool_version<P>)*_toolsVersions.size()));
+ cmd->set_platform(_options.platform());
+ cmd->set_minos(_state.minOSVersion);
+ cmd->set_sdk(_options.sdkVersion());
+ cmd->set_ntools(_toolsVersions.size());
+ macho_build_tool_version<P>* tools = (macho_build_tool_version<P>*)(p + sizeof(macho_build_version_command<P>));
+ for (uint64_t tool : _toolsVersions) {
+ tools->set_tool((uint64_t)tool >> 32);
+ tools->set_version(tool & 0xFFFFFFFF);
+ ++tools;
+ }
+
+ return p + cmd->cmdsize();
+}
+
+
template <typename A>
uint8_t* HeaderAndLoadCommandsAtom<A>::copySourceVersionLoadCommand(uint8_t* p) const
{
if ( _hasVersionLoadCommand )
p = this->copyVersionLoadCommand(p);
+ if ( _hasBuildVersionLoadCommand )
+ p = this->copyBuildVersionLoadCommand(p);
+
if ( _hasSourceVersionLoadCommand )
p = this->copySourceVersionLoadCommand(p);
}
break;
}
- file->forEachAtom(handler);
+ try {
+ file->forEachAtom(handler);
+ }
+ catch (const char* msg) {
+ asprintf((char**)&_exception, "%s file '%s'", msg, file->path());
+ }
}
+ if (_exception)
+ throw _exception;
markExplicitlyLinkedDylibs();
addLinkerOptionLibraries(state, handler);
// upward dependency on lto::version()
namespace lto {
extern const char* version();
+ extern unsigned static_api_version();
+ extern unsigned runtime_api_version();
}
// magic to place command line in crash reports
fObjcGcCompaction(false), fObjCGc(false), fObjCGcOnly(false),
fDemangle(false), fTLVSupport(false),
fVersionLoadCommand(false), fVersionLoadCommandForcedOn(false),
- fVersionLoadCommandForcedOff(false), fFunctionStartsLoadCommand(false),
+ fVersionLoadCommandForcedOff(false), fBuildVersionLoadCommand(false), fFunctionStartsLoadCommand(false),
fFunctionStartsForcedOn(false), fFunctionStartsForcedOff(false),
fDataInCodeInfoLoadCommand(false), fDataInCodeInfoLoadCommandForcedOn(false), fDataInCodeInfoLoadCommandForcedOff(false),
fCanReExportSymbols(false), fObjcCategoryMerging(true), fPageAlignDataAtoms(false),
fBundleBitcode(false), fHideSymbols(false), fVerifyBitcode(false),
fReverseMapUUIDRename(false), fDeDupe(true), fVerboseDeDupe(false),
fReverseMapPath(NULL), fLTOCodegenOnly(false),
- fIgnoreAutoLink(false), fAllowDeadDups(false), fAllowWeakImports(true), fBitcodeKind(kBitcodeProcess),
+ fIgnoreAutoLink(false), fAllowDeadDups(false), fAllowWeakImports(true), fNoInitializers(false), fBitcodeKind(kBitcodeProcess),
fPlatform(kPlatformUnknown), fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), fWatchOSVersionMin(ld::wOSVersionUnset),
fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL),
- fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1), fTraceFileDescriptor(-1), fMaxDefaultCommonAlign(0)
+ fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1), fTraceFileDescriptor(-1), fMaxDefaultCommonAlign(0),
+ fUnalignedPointerTreatment(kUnalignedPointerIgnore)
{
this->checkForClassic(argc, argv);
this->parsePreCommandLineEnvironmentSettings();
case Options::kPlatform_tvOS:
return iOSVersionMin();
#endif
- default:
- break;
+ case kPlatform_bridgeOS:
+ return iOSVersionMin();
+ case kPlatformUnknown:
+ return 0;
}
return 0;
}
fArchitectureName = t->archName;
fHasPreferredSubType = t->isSubType;
fArchSupportsThumb2 = t->supportsThumb2;
- fPlatform = platform;
+ if ( fPlatform == kPlatformUnknown)
+ fPlatform = platform;
switch ( type ) {
case CPU_TYPE_I386:
case CPU_TYPE_X86_64:
if ( fMacVersionMin != ld::macVersionUnset ) {
return ( fMacVersionMin >= requiredMacMin );
}
- else if ( fWatchOSVersionMin != ld::wOSVersionUnset ) {
- // Hack until we fully track watch and ios versions seperately
- return ( (fWatchOSVersionMin + 0x00070000) >= requirediPhoneOSMin);
- }
else {
- return ( fIOSVersionMin >= requirediPhoneOSMin );
+ return min_iOS(requirediPhoneOSMin);
}
}
// Hack until we fully track watch and ios versions seperately
return ( (fWatchOSVersionMin + 0x00070000) >= requirediOSMin);
}
+ else if ( fPlatform == Options::kPlatform_bridgeOS ) {
+ // Hack until we fully track bridge and ios versions seperately
+ return ( (fIOSVersionMin + 0x00090000) >= requirediOSMin);
+ }
else {
return ( fIOSVersionMin >= requirediOSMin );
}
return "AppleTVOS";
break;
#endif
+ case Options::kPlatform_bridgeOS:
+ return "bridgeOS";
case Options::kPlatformUnknown:
return "Unknown";
}
linkCommand.push_back(getVersionString32((unsigned)fIOSVersionMin));
break;
#endif
+ case Options::kPlatform_bridgeOS:
+ linkCommand.push_back("-bridgeos_version_min");
+ linkCommand.push_back(getVersionString32((unsigned)fIOSVersionMin));
+ break;
case Options::kPlatformUnknown:
if ( fOutputKind != Options::kObjectFile ) {
throwf("platform is unknown for final bitcode bundle,"
fTargetIOSSimulator = true;
}
#endif
+ else if ( strcmp(arg, "-bridgeos_version_min") == 0 ) {
+ const char* vers = argv[++i];
+ if ( vers == NULL )
+ throw "-bridgeos_version_min missing version argument";
+ setIOSVersionMin(vers);
+ fPlatform = kPlatform_bridgeOS;
+ }
else if ( strcmp(arg, "-multiply_defined") == 0 ) {
//warnObsolete(arg);
++i;
if ( fReverseMapPath == NULL )
throw "missing argument to -bitcode_symbol_map";
struct stat statbuf;
- ::stat(fReverseMapPath, &statbuf);
- if (S_ISDIR(statbuf.st_mode)) {
+ int ret = ::stat(fReverseMapPath, &statbuf);
+ if ( ret == 0 && S_ISDIR(statbuf.st_mode)) {
char tempPath[PATH_MAX];
sprintf(tempPath, "%s/XXXXXX", fReverseMapPath);
int tempFile = ::mkstemp(tempPath);
else if ( strcmp(argv[i], "-no_weak_imports") == 0 ) {
fAllowWeakImports = false;
}
+ else if ( strcmp(argv[i], "-no_inits") == 0 ) {
+ fNoInitializers = true;
+ }
// put this last so that it does not interfer with other options starting with 'i'
else if ( strncmp(arg, "-i", 2) == 0 ) {
const char* colon = strchr(arg, ':');
if ( argc == 2 ) {
const char* ltoVers = lto::version();
if ( ltoVers != NULL )
- fprintf(stderr, "LTO support using: %s\n", ltoVers);
+ fprintf(stderr, "LTO support using: %s (static support for %d, runtime is %d)\n",
+ ltoVers, lto::static_api_version(), lto::runtime_api_version());
fprintf(stderr, "TAPI support using: %s\n", tapi::Version::getFullVersionAsString().c_str());
exit(0);
}
}
+
+static bool sharedCacheEligiblePath(const char* path)
+{
+ return ( (strncmp(path, "/usr/lib/", 9) == 0) || (strncmp(path, "/System/Library/", 16) == 0) );
+}
+
void Options::reconfigureDefaults()
{
// sync reader options
// determine if info for shared region should be added
if ( fOutputKind == Options::kDynamicLibrary ) {
- if ( minOS(ld::mac10_5, ld::iOS_3_1) && !fTargetIOSSimulator )
+ if ( minOS(ld::mac10_5, ld::iOS_3_1) )
if ( !fPrebind && !fSharedRegionEligibleForceOff )
- if ( (strncmp(this->installPath(), "/usr/lib/", 9) == 0)
- || (strncmp(this->installPath(), "/System/Library/", 16) == 0) )
+ if ( sharedCacheEligiblePath(this->installPath()) )
fSharedRegionEligible = true;
}
else if ( fOutputKind == Options::kDyld ) {
fSharedRegionEligible = true;
}
- // <rdar://problem/18719327> warn if -rpath is used with OS dylibs
- if ( fSharedRegionEligible && !fRPaths.empty() )
- warning("-rpath cannot be used with dylibs that will be in the dyld shared cache");
-
// automatically use __DATA_CONST in iOS dylibs
- if ( fSharedRegionEligible && minOS(ld::mac10_Future, ld::iOS_9_0) && !fUseDataConstSegmentForceOff ) {
+ if ( fSharedRegionEligible && minOS(ld::mac10_Future, ld::iOS_9_0) && !fUseDataConstSegmentForceOff && !fTargetIOSSimulator) {
fUseDataConstSegment = true;
}
if ( fUseDataConstSegmentForceOn ) {
// Use V2 shared cache info when targetting newer OSs
if ( fSharedRegionEligible && minOS(ld::mac10_12, ld::iOS_9_0)) {
fSharedRegionEncodingV2 = true;
- // <rdar://problem/24772435> only use v2 for Swift dylibs on Mac OS X
- if ( (fPlatform == kPlatformOSX) && (strncmp(this->installPath(), "/System/Library/PrivateFrameworks/Swift/", 40) != 0) )
+ if ( fPlatform == kPlatformOSX ) {
fSharedRegionEncodingV2 = false;
+ // <rdar://problem/24772435> only use v2 for Swift dylibs on Mac OS X
+ if ( strncmp(this->installPath(), "/System/Library/PrivateFrameworks/Swift/", 40) == 0 )
+ fSharedRegionEncodingV2 = true;
+ // <rdar://problem/31428120> an other OS frameworks that use swift need v2
+ for (const char* searchPath : fLibrarySearchPaths ) {
+ if ( strstr(searchPath, "xctoolchain/usr/lib/swift/macos") != NULL ) {
+ fSharedRegionEncodingV2 = true;
+ break;
+ }
+ }
+ }
fIgnoreOptimizationHints = true;
}
}
}
+
+ // <rdar://problem/32138080> Automatically use OrderFiles found in the AppleInternal SDK
+ if ( (fFinalName != NULL) && fOrderedSymbols.empty() && !fSDKPaths.empty() ) {
+ char path[PATH_MAX];
+ strlcpy(path , fSDKPaths.front(), sizeof(path));
+ strlcat(path , "/AppleInternal/OrderFiles/", sizeof(path));
+ strlcat(path , fFinalName, sizeof(path));
+ strlcat(path , ".order", sizeof(path));
+ FileInfo info;
+ if ( info.checkFileExists(*this, path) )
+ parseOrderFile(path, false);
+ }
+
// <rdar://problem/20503811> Reduce the default alignment of structures/arrays to save memory in embedded systems
if ( fMaxDefaultCommonAlign == 0 ) {
if ( fOutputKind == Options::kPreload )
else
fMaxDefaultCommonAlign = 15;
}
+
+ // Add warnings for issues likely to cause OS verification issues
+ if ( fSharedRegionEligible && !fRPaths.empty() ) {
+ // <rdar://problem/18719327> warn if -rpath is used with OS dylibs
+ warning("OS dylibs should not add rpaths (linker option: -rpath) (Xcode build setting: LD_RUNPATH_SEARCH_PATHS)");
+ }
+ if ( (fOutputKind == Options::kDynamicLibrary) && (fDylibInstallName != NULL) && (fFinalName != NULL) && sharedCacheEligiblePath(fFinalName) ) {
+ if ( strncmp(fDylibInstallName, "@rpath", 6) == 0 )
+ warning("OS dylibs should not use @rpath for -install_name. Use absolute path instead");
+ if ( strcmp(fDylibInstallName, fFinalName) != 0 ) {
+ bool different = true;
+ // some projects end up with double slash in -final_output path
+ if ( strstr(fFinalName, "//") != NULL ) {
+ char fixedPath[strlen(fFinalName)+1];
+ char* t = fixedPath;
+ bool lastWasSlash = false;
+ for (const char* s=fFinalName; *s != '\0'; ++s) {
+ if ( *s == '/' ) {
+ if ( !lastWasSlash )
+ *t++ = *s;
+ lastWasSlash = true;
+ }
+ else {
+ *t++ = *s;
+ lastWasSlash = false;
+ }
+ }
+ *t = '\0';
+ different = (strcmp(fDylibInstallName, fixedPath) != 0);
+ }
+ if ( different )
+ warning("OS dylibs -install_name should match its real absolute path");
+ }
+ }
+
+ // set if unaligned pointers are warnings or errors
+ if ( fMacVersionMin >= ld::mac10_12 ) {
+ // ignore unaligned pointers when targeting older macOS versions
+ if ( fSharedRegionEligible )
+ fUnalignedPointerTreatment = Options::kUnalignedPointerWarning;
+ else
+ fUnalignedPointerTreatment = Options::kUnalignedPointerIgnore;
+ }
+ else if ( min_iOS(ld::iOS_10_0) ) {
+ fUnalignedPointerTreatment = Options::kUnalignedPointerWarning;
+ }
+ else {
+ fUnalignedPointerTreatment = Options::kUnalignedPointerIgnore;
+ }
+
}
void Options::checkIllegalOptionCombinations()
break;
case kPlatformiOS:
case kPlatformWatchOS:
+ case kPlatform_bridgeOS:
#if SUPPORT_APPLE_TV
case kPlatform_tvOS:
#endif
break;
case kPlatformiOS:
case kPlatformWatchOS:
+ case kPlatform_bridgeOS:
#if SUPPORT_APPLE_TV
case Options::kPlatform_tvOS:
#endif
warning("embedded dylibs/frameworks only run on iOS 8 or later");
}
+ // bridgeOS always generates new load command
+ if ( fVersionLoadCommand && (fPlatform == kPlatform_bridgeOS) ) {
+ fBuildVersionLoadCommand = true;
+ }
// produce nicer error when no input
if ( fInputFiles.empty() ) {
enum LocalSymbolHandling { kLocalSymbolsAll, kLocalSymbolsNone, kLocalSymbolsSelectiveInclude, kLocalSymbolsSelectiveExclude };
enum BitcodeMode { kBitcodeProcess, kBitcodeAsData, kBitcodeMarker, kBitcodeStrip };
enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull };
+ enum UnalignedPointerTreatment { kUnalignedPointerError, kUnalignedPointerWarning, kUnalignedPointerIgnore };
#if SUPPORT_APPLE_TV
- enum Platform { kPlatformUnknown, kPlatformOSX, kPlatformiOS, kPlatformWatchOS, kPlatform_tvOS };
+ enum Platform { kPlatformUnknown, kPlatformOSX=1, kPlatformiOS=2, kPlatformWatchOS=3, kPlatform_tvOS=4, kPlatform_bridgeOS=5 };
#else
enum Platform { kPlatformUnknown, kPlatformOSX, kPlatformiOS, kPlatformWatchOS };
#endif
case kPlatform_tvOS:
return "tvOS";
#endif
+ case kPlatform_bridgeOS:
+ return "bridgeOS";
case kPlatformUnknown:
default:
return "(unknown)";
case 4:
strcpy(versionString, "3.0");
break;
+ case 5:
+ strcpy(versionString, "4.0");
+ break;
default:
sprintf(versionString, "unknown ABI version 0x%02X", value);
}
bool objcGcOnly() const { return fObjCGcOnly; }
bool canUseThreadLocalVariables() const { return fTLVSupport; }
bool addVersionLoadCommand() const { return fVersionLoadCommand && (fPlatform != kPlatformUnknown); }
+ bool addBuildVersionLoadCommand() const { return fBuildVersionLoadCommand; }
bool addFunctionStarts() const { return fFunctionStartsLoadCommand; }
bool addDataInCodeInfo() const { return fDataInCodeInfoLoadCommand; }
bool canReExportSymbols() const { return fCanReExportSymbols; }
bool ignoreAutoLink() const { return fIgnoreAutoLink; }
bool allowDeadDuplicates() const { return fAllowDeadDups; }
bool allowWeakImports() const { return fAllowWeakImports; }
+ bool noInitializers() const { return fNoInitializers; }
BitcodeMode bitcodeKind() const { return fBitcodeKind; }
bool sharedRegionEncodingV2() const { return fSharedRegionEncodingV2; }
bool useDataConstSegment() const { return fUseDataConstSegment; }
bool hasDataSymbolMoves() const { return !fSymbolsMovesData.empty(); }
bool hasCodeSymbolMoves() const { return !fSymbolsMovesCode.empty(); }
void writeToTraceFile(const char* buffer, size_t len) const;
+ UnalignedPointerTreatment unalignedPointerTreatment() const { return fUnalignedPointerTreatment; }
static uint32_t parseVersionNumber32(const char*);
bool fVersionLoadCommand;
bool fVersionLoadCommandForcedOn;
bool fVersionLoadCommandForcedOff;
+ bool fBuildVersionLoadCommand;
bool fFunctionStartsLoadCommand;
bool fFunctionStartsForcedOn;
bool fFunctionStartsForcedOff;
bool fIgnoreAutoLink;
bool fAllowDeadDups;
bool fAllowWeakImports;
+ bool fNoInitializers;
BitcodeMode fBitcodeKind;
Platform fPlatform;
DebugInfoStripping fDebugInfoStripping;
mutable int fDependencyFileDescriptor;
mutable int fTraceFileDescriptor;
uint8_t fMaxDefaultCommonAlign;
+ UnalignedPointerTreatment fUnalignedPointerTreatment;
};
printSectionLayout(state);
const ld::Atom* target;
- throwf("32-bit RIP relative reference out of range (%lld max is +/-4GB): from %s (0x%08llX) to %s (0x%08llX)",
+ throwf("32-bit RIP relative reference out of range (%lld max is +/-2GB): from %s (0x%08llX) to %s (0x%08llX)",
displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),
addressOf(state, fixup, &target));
}
++machoSectionIndex;
for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
const ld::Atom* atom = *ait;
- if ( setMachoSectionIndex )
+ if ( setMachoSectionIndex )
(const_cast<ld::Atom*>(atom))->setMachoSection(machoSectionIndex);
else if ( sect->type() == ld::Section::typeMachHeader )
(const_cast<ld::Atom*>(atom))->setMachoSection(1); // __mh_execute_header is not in any section by needs n_sect==1
}
}
if ( ((address & (pointerSize-1)) != 0) && (rebaseType == REBASE_TYPE_POINTER) ) {
- if ( (pointerSize == 8) && ((address & 7) == 4) ) {
- // for now, don't warning about 8-byte pointers only 4-byte aligned
- }
- else {
- warning("pointer not aligned at address 0x%llX (%s + %lld from %s)",
- address, atom->name(), (address - atom->finalAddress()), atom->safeFilePath());
+ switch ( _options.unalignedPointerTreatment() ) {
+ case Options::kUnalignedPointerError:
+ throwf("pointer not aligned at address 0x%llX (%s + %lld from %s)",
+ address, atom->name(), (address - atom->finalAddress()), atom->safeFilePath());
+ break;
+ case Options::kUnalignedPointerWarning:
+ warning("pointer not aligned at address 0x%llX (%s + %lld from %s)",
+ address, atom->name(), (address - atom->finalAddress()), atom->safeFilePath());
+ break;
+ case Options::kUnalignedPointerIgnore:
+ // do nothing
+ break;
}
}
_rebaseInfo.push_back(RebaseInfo(rebaseType, address));
sect->hasExternalRelocs = true; // so dyld knows to change permissions on __TEXT segment
}
if ( ((address & (pointerSize-1)) != 0) && (type == BIND_TYPE_POINTER) ) {
- if ( (pointerSize == 8) && ((address & 7) == 4) ) {
- // for now, don't warning about 8-byte pointers only 4-byte aligned
- }
- else {
- warning("pointer not aligned at address 0x%llX (%s + %lld from %s)",
- address, atom->name(), (address - atom->finalAddress()), atom->safeFilePath());
+ switch ( _options.unalignedPointerTreatment() ) {
+ case Options::kUnalignedPointerError:
+ throwf("pointer not aligned at address 0x%llX (%s + %lld from %s)",
+ address, atom->name(), (address - atom->finalAddress()), atom->safeFilePath());
+ break;
+ case Options::kUnalignedPointerWarning:
+ warning("pointer not aligned at address 0x%llX (%s + %lld from %s)",
+ address, atom->name(), (address - atom->finalAddress()), atom->safeFilePath());
+ break;
+ case Options::kUnalignedPointerIgnore:
+ // do nothing
+ break;
}
}
_bindingInfo.push_back(BindingInfo(type, this->compressedOrdinalForAtom(target), target->name(), weak_import, address, addend));
// make a vector of atoms that come from files compiled with dwarf debug info
std::vector<const ld::Atom*> atomsNeedingDebugNotes;
std::set<const ld::Atom*> atomsWithStabs;
+ std::set<const ld::relocatable::File*> filesSeenWithStabs;
atomsNeedingDebugNotes.reserve(1024);
const ld::relocatable::File* objFile = NULL;
bool objFileHasDwarf = false;
}
if ( objFileHasDwarf )
atomsNeedingDebugNotes.push_back(atom);
- if ( objFileHasStabs )
+ if ( objFileHasStabs ) {
atomsWithStabs.insert(atom);
+ if ( objFile != NULL )
+ filesSeenWithStabs.insert(objFile);
+ }
}
}
}
endFileStab.string = "";
state.stabs.push_back(endFileStab);
}
-
- // copy any stabs from .o file
- std::set<const ld::File*> filesSeenWithStabs;
- for (std::set<const ld::Atom*>::iterator it=atomsWithStabs.begin(); it != atomsWithStabs.end(); it++) {
- const ld::Atom* atom = *it;
- objFile = dynamic_cast<const ld::relocatable::File*>(atom->file());
- if ( objFile != NULL ) {
- if ( filesSeenWithStabs.count(objFile) == 0 ) {
- filesSeenWithStabs.insert(objFile);
- const std::vector<ld::relocatable::File::Stab>* stabs = objFile->stabs();
- if ( stabs != NULL ) {
- for(std::vector<ld::relocatable::File::Stab>::const_iterator sit = stabs->begin(); sit != stabs->end(); ++sit) {
- ld::relocatable::File::Stab stab = *sit;
- // ignore stabs associated with atoms that were dead stripped or coalesced away
- if ( (sit->atom != NULL) && (atomsWithStabs.count(sit->atom) == 0) )
+
+ // copy any stabs from .o files
+ bool deadStripping = _options.deadCodeStrip();
+ for (const ld::relocatable::File* obj : filesSeenWithStabs) {
+ const std::vector<ld::relocatable::File::Stab>* filesStabs = obj->stabs();
+ if ( filesStabs != NULL ) {
+ for (const ld::relocatable::File::Stab& stab : *filesStabs ) {
+ // ignore stabs associated with atoms that were dead stripped or coalesced away
+ if ( (stab.atom != NULL) && (atomsWithStabs.count(stab.atom) == 0) )
+ continue;
+ // <rdar://problem/8284718> Value of N_SO stabs should be address of first atom from translation unit
+ if ( (stab.type == N_SO) && (stab.string != NULL) && (stab.string[0] != '\0') ) {
+ uint64_t lowestAtomAddress = 0;
+ const ld::Atom* lowestAddressAtom = NULL;
+ for (const ld::relocatable::File::Stab& stab2 : *filesStabs ) {
+ if ( stab2.atom == NULL )
continue;
- // <rdar://problem/8284718> Value of N_SO stabs should be address of first atom from translation unit
- if ( (stab.type == N_SO) && (stab.string != NULL) && (stab.string[0] != '\0') ) {
- stab.atom = atom;
+ // skip over atoms that were dead stripped
+ if ( deadStripping && !stab2.atom->live() )
+ continue;
+ if ( stab2.atom->coalescedAway() )
+ continue;
+ uint64_t atomAddr = stab2.atom->objectAddress();
+ if ( (lowestAddressAtom == NULL) || (atomAddr < lowestAtomAddress) ) {
+ lowestAddressAtom = stab2.atom;
+ lowestAtomAddress = atomAddr;
}
- state.stabs.push_back(stab);
}
+ ld::relocatable::File::Stab altStab = stab;
+ altStab.atom = lowestAddressAtom;
+ state.stabs.push_back(altStab);
+ }
+ else {
+ state.stabs.push_back(stab);
}
}
}
}
-
}
#include <AvailabilityMacros.h>
#include "Options.h"
-
#include "ld.hpp"
#include "Bitcode.hpp"
#include "InputFiles.h"
#include "Resolver.h"
#include "parsers/lto_file.h"
+#include "configure.h"
+
+#define VAL(x) #x
+#define STRINGIFY(x) VAL(x)
namespace ld {
namespace tool {
_internal.cpuSubType = _options.subArchitecture();
_internal.minOSVersion = _options.minOSversion();
- _internal.derivedPlatformLoadCommand = 0;
+ _internal.derivedPlatform = 0;
// In -r mode, look for -linker_option additions
if ( _options.outputKind() == Options::kObjectFile ) {
doLinkerOption(*it, "command line");
}
}
+#ifdef LD64_VERSION_NUM
+ uint32_t packedNum = Options::parseVersionNumber32(STRINGIFY(LD64_VERSION_NUM));
+ uint64_t combined = (uint64_t)TOOL_LD << 32 | packedNum;
+ _internal.toolsVersions.insert(combined);
+#endif
}
void Resolver::buildAtomList()
// No bitcode section, figure out if the object file comes from LTO/compiler static library
switch ( _options.platform() ) {
case Options::kPlatformOSX:
+ case Options::kPlatform_bridgeOS:
case Options::kPlatformUnknown:
warning("all bitcode will be dropped because '%s' was built without bitcode. "
"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());
uint32_t objMinOS = objFile->minOSVersion();
if ( !objMinOS )
_internal.objectFileFoundWithNoVersion = true;
-
- uint32_t objPlatformLC = objFile->platformLoadCommand();
- if ( (objPlatformLC != 0) && (_internal.derivedPlatformLoadCommand == 0) && (_options.outputKind() == Options::kObjectFile) )
- _internal.derivedPlatformLoadCommand = objPlatformLC;
-
if ( (_options.outputKind() == Options::kObjectFile) && (objMinOS > _internal.minOSVersion) )
_internal.minOSVersion = objMinOS;
+ uint32_t objPlatform = objFile->platform();
+ if ( (objPlatform != 0) && (_options.outputKind() == Options::kObjectFile) && (_internal.derivedPlatform == 0) )
+ _internal.derivedPlatform = objPlatform;
+
+ // update set of known tools used
+ for (const std::pair<uint32_t,uint32_t>& entry : objFile->toolVersions()) {
+ uint64_t combined = (uint64_t)entry.first << 32 | entry.second;
+ _internal.toolsVersions.insert(combined);
+ }
+
// update cpu-sub-type
cpu_subtype_t nextObjectSubType = file.cpuSubType();
switch ( _options.architecture() ) {
}
break;
+ case CPU_TYPE_ARM64:
+ if ( _options.subArchitecture() != nextObjectSubType ) {
+ if ( _options.allowSubArchitectureMismatches() ) {
+ warning("object file %s was built for different arm64 sub-type (%d) than link command line (%d)",
+ file.path(), nextObjectSubType, _options.subArchitecture());
+ }
+ else {
+ throwf("object file %s was built for different arm64 sub-type (%d) than link command line (%d)",
+ file.path(), nextObjectSubType, _options.subArchitecture());
+ }
+ }
+ break;
+
case CPU_TYPE_I386:
_internal.cpuSubType = CPU_SUBTYPE_I386_ALL;
break;
strncmp(tcLibPath, tempPath, strlen(tcLibPath)) != 0 ) {
switch ( _options.platform() ) {
case Options::kPlatformOSX:
+ case Options::kPlatform_bridgeOS:
case Options::kPlatformUnknown:
warning("all bitcode will be dropped because '%s' was built without bitcode. "
"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());
if ( atom.section().type() == ld::Section::typeTempAlias )
_haveAliases = true;
+ // prevent initializers if -no_inits used
+ if ( (atom.section().type() == ld::Section::typeInitializerPointers) && _options.noInitializers() ) {
+ throw "-no_inits specified, but initializer found";
+ }
+
if ( _options.deadCodeStrip() ) {
// add to set of dead-strip-roots, all symbols that the compiler marks as don't strip
if ( atom.dontDeadStrip() )
virtual uint32_t cpuSubType() const { return 0; }
virtual uint32_t subFileCount() const { return 1; }
virtual uint32_t minOSVersion() const { return 0; }
- virtual uint32_t platformLoadCommand() const { return 0; }
+ virtual uint32_t platform() const { return 0; }
bool fileExists() const { return _modTime != 0; }
Type type() const { return _type; }
virtual Bitcode* getBitcode() const { return NULL; }
const char* string;
};
typedef const std::vector< std::vector<const char*> > LinkerOptionsList;
+ typedef std::vector<std::pair<uint32_t,uint32_t>> ToolVersionList;
File(const char* pth, time_t modTime, Ordinal ord)
: ld::File(pth, modTime, ord, Reloc) { }
virtual bool canScatterAtoms() const = 0;
virtual bool hasLongBranchStubs() { return false; }
virtual LinkerOptionsList* linkerOptions() const = 0;
+ virtual const ToolVersionList& toolVersions() const = 0;
virtual SourceKind sourceKind() const { return kSourceUnknown; }
virtual const uint8_t* fileContent() const { return nullptr; }
};
std::vector<const ld::relocatable::File*> filesFromCompilerRT;
std::vector<const ld::Atom*> deadAtoms;
std::unordered_set<const char*> allUndefProxies;
+ std::unordered_set<uint64_t> toolsVersions;
const ld::dylib::File* bundleLoader;
const Atom* entryPoint;
const Atom* classicBindingHelper;
uint8_t swiftVersion;
uint32_t cpuSubType;
uint32_t minOSVersion;
- uint32_t derivedPlatformLoadCommand;
+ uint32_t derivedPlatform;
bool objectFileFoundWithNoVersion;
bool allObjectFilesScatterable;
bool someObjectFileHasDwarf;
virtual ld::File::ObjcConstraint objCConstraint() const override final { return _objcConstraint; }
virtual uint8_t swiftVersion() const override final { return _swiftVersion; }
virtual uint32_t minOSVersion() const override final { return _minVersionInDylib; }
- virtual uint32_t platformLoadCommand() const override final { return _platformInDylib; }
+ virtual uint32_t platform() const override final { return _platformInDylib; }
virtual ld::Bitcode* getBitcode() const override final { return _bitcode.get(); }
#include "macho_relocatable_file.h"
#include "lto_file.h"
-// #defines are a work around for <rdar://problem/8760268>
-#define __STDC_LIMIT_MACROS 1
-#define __STDC_CONSTANT_MACROS 1
#include "llvm-c/lto.h"
namespace lto {
const std::vector<ld::relocatable::File::Stab>* stabs() const override { return NULL; }
bool canScatterAtoms() const override { return true; }
LinkerOptionsList* linkerOptions() const override { return NULL; }
+ const ToolVersionList& toolVersions() const override { return _toolVersions; }
bool isThinLTO() const { return _isThinLTO; }
void setIsThinLTO(bool ThinLTO) { _isThinLTO = ThinLTO; }
// fixme rdar://24734472 objCConstraint() and objcHasCategoryClassProperties()
ld::Fixup _fixupToInternal;
ld::relocatable::File::DebugInfoKind _debugInfo;
uint32_t _cpuSubType;
+ ToolVersionList _toolVersions; // unused, may some day contain version of clang the created bitcode
};
//
assert(!_module && "Expected module to be disposed");
std::string pathWithID = _path;
pathWithID += std::to_string(id);
- ::thinlto_codegen_add_module(generator, pathWithID.c_str(), (const char *)_content, _contentLength);
+ ::thinlto_codegen_add_module(generator, strdup(pathWithID.c_str()), (const char *)_content, _contentLength);
}
#endif
const char* name = llvmAtom->name();
if ( deadllvmAtoms.find(name) == deadllvmAtoms.end() ) {
if ( logMustPreserve )
- fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name);
+ fprintf(stderr, "thinlto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name);
::thinlto_codegen_add_must_preserve_symbol(thingenerator, name, strlen(name));
deadllvmAtoms[name] = (Atom*)llvmAtom;
}
// 2 - included in nonLLVMRefs set.
// If a symbol is not listed in exportList then LTO is free to optimize it away.
if ( (atom->scope() == ld::Atom::scopeGlobal) && options.preserveAllGlobals ) {
- if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because global symbol\n", name);
+ if ( logMustPreserve ) fprintf(stderr, "thinlto_codegen_add_must_preserve_symbol(%s) because global symbol\n", name);
::thinlto_codegen_add_must_preserve_symbol(thingenerator, name, strlen(name));
}
else if ( nonLLVMRefs.find(name) != nonLLVMRefs.end() ) {
- if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because referenced from outside of ThinLTO\n", name);
+ if ( logMustPreserve ) fprintf(stderr, "thinlto_codegen_add_must_preserve_symbol(%s) because referenced from outside of ThinLTO\n", name);
::thinlto_codegen_add_must_preserve_symbol(thingenerator, name, strlen(name));
}
else if ( LLVMRefs.find(name) != LLVMRefs.end() ) {
- if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because referenced from another file\n", name);
+ if ( logMustPreserve ) fprintf(stderr, "thinlto_codegen_add_cross_referenced_symbol(%s) because referenced from another file\n", name);
::thinlto_codegen_add_cross_referenced_symbol(thingenerator, name, strlen(name));
} else {
if ( logMustPreserve ) fprintf(stderr, "NOT preserving(%s)\n", name);
}
// Add the optimized bitcode to the codegen generator now.
- ::thinlto_codegen_add_module(thingenerator, tempMachoPath.c_str(), (const char *)machOFile.Buffer, machOFile.Size);
+ ::thinlto_codegen_add_module(thingenerator, strdup(tempMachoPath.c_str()), (const char *)machOFile.Buffer, machOFile.Size);
}
}
if ( numObjects == 0 )
throwf("could not do ThinLTO codegen (thinlto_codegen_process didn't produce any object): '%s', using libLTO version '%s'", ::lto_get_error_message(), ::lto_get_version());
+ auto get_thinlto_buffer_or_load_file = [&] (unsigned ID) {
+#if LTO_API_VERSION >= 21
+ if ( useFileBasedAPI ) {
+ const char* path = thinlto_module_get_object_file(thingenerator, ID);
+ // map in whole file
+ struct stat stat_buf;
+ int fd = ::open(path, O_RDONLY, 0);
+ if ( fd == -1 )
+ throwf("can't open thinlto file '%s', errno=%d", path, errno);
+ if ( ::fstat(fd, &stat_buf) != 0 )
+ throwf("fstat thinlto file '%s' failed, errno=%d\n", path, errno);
+ size_t len = stat_buf.st_size;
+ if ( len < 20 )
+ throwf("ThinLTO file '%s' too small (length=%zu)", path, len);
+ const char* p = (const char*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+ if ( p == (const char*)(-1) )
+ throwf("can't map file, errno=%d", errno);
+ ::close(fd);
+ return LTOObjectBuffer{ p, len };
+ }
+#endif
+ return thinlto_module_get_object(thingenerator, ID);
+ };
+
// if requested, save off objects files
if ( options.saveTemps ) {
for (unsigned bufID = 0; bufID < numObjects; ++bufID) {
- auto machOFile = thinlto_module_get_object(thingenerator, bufID);
+ auto machOFile = get_thinlto_buffer_or_load_file(bufID);
std::string tempMachoPath = options.outputFilePath;
tempMachoPath += ".";
tempMachoPath += std::to_string(bufID);
}
}
- auto get_thinlto_buffer_or_load_file = [&] (unsigned ID) {
-#if LTO_API_VERSION >= 21
- if ( useFileBasedAPI ) {
- const char* path = thinlto_module_get_object_file(thingenerator, ID);
- // map in whole file
- struct stat stat_buf;
- int fd = ::open(path, O_RDONLY, 0);
- if ( fd == -1 )
- throwf("can't open thinlto file '%s', errno=%d", path, errno);
- if ( ::fstat(fd, &stat_buf) != 0 )
- throwf("fstat thinlto file '%s' failed, errno=%d\n", path, errno);
- size_t len = stat_buf.st_size;
- if ( len < 20 )
- throwf("ThinLTO file '%s' too small (length=%zu)", path, len);
- const char* p = (const char*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
- if ( p == (const char*)(-1) )
- throwf("can't map file, errno=%d", errno);
- ::close(fd);
- return LTOObjectBuffer{ p, len };
- }
-#endif
- return thinlto_module_get_object(thingenerator, ID);
- };
-
auto ordinal = ld::File::Ordinal::LTOOrdinal().nextFileListOrdinal();
for (unsigned bufID = 0; bufID < numObjects; ++bufID) {
auto machOFile = get_thinlto_buffer_or_load_file(bufID);
return ::lto_get_version();
}
+//
+// used by "ld -v" to report static version of libLTO.dylib API being compiled
+//
+unsigned int static_api_version()
+{
+ return LTO_API_VERSION;
+}
+
+//
+// used by "ld -v" to report version of libLTO.dylib being used
+//
+unsigned int runtime_api_version()
+{
+ return ::lto_api_version();
+}
+
//
// used by ld for error reporting
extern const char* version();
+extern unsigned int runtime_api_version();
+
+extern unsigned int static_api_version();
+
extern bool libLTOisLoaded();
extern const char* archName(const uint8_t* fileContent, uint64_t fileLength);
this->_platformInDylib = cmd->cmd();
lcPlatform = Options::platformForLoadCommand(this->_platformInDylib);
break;
+ case LC_BUILD_VERSION:
+ {
+ const macho_build_version_command<P>* buildVersCmd = (macho_build_version_command<P>*)cmd;
+ this->_platformInDylib = buildVersCmd->platform();
+ this->_minVersionInDylib = buildVersCmd->minos();
+ lcPlatform = (Options::Platform)this->_platformInDylib;
+ }
+ break;
case LC_CODE_SIGNATURE:
break;
case macho_segment_command<P>::CMD:
if ( !this->_allowSimToMacOSXLinking ) {
switch (platform) {
case Options::kPlatformOSX:
+ case Options::kPlatform_bridgeOS:
case Options::kPlatformiOS:
if ( lcPlatform == Options::kPlatformUnknown )
break;
else {
switch (platform) {
case Options::kPlatformOSX:
+ case Options::kPlatform_bridgeOS:
case Options::kPlatformiOS:
if ( lcPlatform == Options::kPlatformUnknown )
break;
this->_ignoreExports.insert(strdup(symName));
}
else if ( strncmp(symAction, "install_name$", 13) == 0 ) {
- this->_dylibInstallPath = symName;
+ this->_dylibInstallPath = strdup(symName);
this->_installPathOverride = true;
// <rdar://problem/14448206> CoreGraphics redirects to ApplicationServices, but with wrong compat version
if ( strcmp(this->_dylibInstallPath, "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices") == 0 )
}
if ( Parser<arm64>::validFile(fileContent, false) ) {
*result = CPU_TYPE_ARM64;
- *subResult = CPU_SUBTYPE_ARM64_ALL;
+ const auto* header = reinterpret_cast<const macho_header<Pointer32<LittleEndian>>*>(fileContent);
+ *subResult = header->cpusubtype();
return true;
}
return false;
_swiftVersion(0),
_cpuSubType(0),
_minOSVersion(0),
- _platform(0),
+ _platform(Options::kPlatformUnknown),
_canScatterAtoms(false),
_objcHasCategoryClassPropertiesField(false),
_srcKind(kSourceUnknown) { }
virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const
{ return false; }
virtual uint32_t minOSVersion() const { return _minOSVersion; }
- virtual uint32_t platformLoadCommand() const { return _platform; }
+ virtual uint32_t platform() const { return _platform; }
// overrides of ld::relocatable::File
virtual ObjcConstraint objCConstraint() const { return _objConstraint; }
virtual bool canScatterAtoms() const { return _canScatterAtoms; }
virtual const char* translationUnitSource() const;
virtual LinkerOptionsList* linkerOptions() const { return &_linkerOptions; }
+ virtual const ToolVersionList& toolVersions() const { return _toolVersions; }
virtual uint8_t swiftVersion() const { return _swiftVersion; }
virtual ld::Bitcode* getBitcode() const { return _bitcode.get(); }
virtual SourceKind sourceKind() const { return _srcKind; }
uint8_t _swiftVersion;
uint32_t _cpuSubType;
uint32_t _minOSVersion;
- uint32_t _platform;
+ Options::Platform _platform;
bool _canScatterAtoms;
bool _objcHasCategoryClassPropertiesField;
std::vector<std::vector<const char*> > _linkerOptions;
std::unique_ptr<ld::Bitcode> _bitcode;
SourceKind _srcKind;
+ ToolVersionList _toolVersions;
};
#endif
if ( ignoreMismatchPlatform )
break;
- _file->_platform = cmd->cmd();
lcPlatform = Options::platformForLoadCommand(cmd->cmd());
+ _file->_platform = lcPlatform;
_file->_minOSVersion = ((macho_version_min_command<P>*)cmd)->version();
break;
+ case LC_BUILD_VERSION:
+ {
+ const macho_build_version_command<P>* buildVersCmd = (macho_build_version_command<P>*)cmd;
+ if ( ignoreMismatchPlatform )
+ break;
+ lcPlatform = (Options::Platform)buildVersCmd->platform();
+ _file->_platform = lcPlatform;
+ _file->_minOSVersion = buildVersCmd->minos();
+ const macho_build_tool_version<P>* entry = (macho_build_tool_version<P>*)((uint8_t*)cmd + sizeof(macho_build_version_command<P>));
+ for (uint32_t t=0; t < buildVersCmd->ntools(); ++t) {
+ _file->_toolVersions.push_back(std::make_pair(entry->tool(), entry->version()));
+ ++entry;
+ }
+ }
+ break;
case macho_segment_command<P>::CMD:
if ( segment != NULL )
throw "more than one LC_SEGMENT found in object file";
if ( lcPlatform == Options::kPlatformUnknown )
break;
// fall through if the Platform is not Unknown
+ case Options::kPlatform_bridgeOS:
case Options::kPlatformWatchOS:
// Error when using bitcocde, warning otherwise.
if (_usingBitcode)
return Options::kPlatformOSX;
case LC_VERSION_MIN_IPHONEOS:
return Options::kPlatformiOS;
+ case LC_VERSION_MIN_WATCHOS:
+ return Options::kPlatformWatchOS;
+ #if SUPPORT_APPLE_TV
+ case LC_VERSION_MIN_TVOS:
+ return Options::kPlatform_tvOS;
+ #endif
+ case LC_BUILD_VERSION:
+ return (Options::Platform)((macho_build_version_command<P>*)cmd)->platform();
}
cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
if ( cmd > cmdsEnd )
if ( mach_o::relocatable::Parser<arm64>::validFile(fileContent, false, 0) ) {
const macho_header<Pointer64<LittleEndian> >* header = (const macho_header<Pointer64<LittleEndian> >*)fileContent;
*result = CPU_TYPE_ARM64;
- *subResult = CPU_SUBTYPE_ARM64_ALL;
+ *subResult = header->cpusubtype();
*platform = Parser<arm64>::findPlatform(header);
return true;
}
return Options::kPlatformWatchOS;
case tapi::Platform::tvOS:
return Options::kPlatform_tvOS;
+ #if ((TAPI_API_VERSION_MAJOR == 1 && TAPI_API_VERSION_MINOR >= 2) || (TAPI_API_VERSION_MAJOR > 1))
+ case tapi::Platform::bridgeOS:
+ return Options::kPlatform_bridgeOS;
+ #endif
}
return Options::kPlatformUnknown;
textAtoms.insert(pos, aliasAtom);
state.atomToSection[aliasAtom] = textSection;
replacementMap[dupAtom] = aliasAtom;
+ (const_cast<ld::Atom*>(dupAtom))->setCoalescedAway();
}
}
}
case LC_DATA_IN_CODE:
case LC_DYLIB_CODE_SIGN_DRS:
case LC_SOURCE_VERSION:
+ case LC_NOTE:
+ case LC_BUILD_VERSION:
break;
case LC_RPATH:
fHasLC_RPATH = true;
if ( fIndirectTableCount != 0 ) {
if ( fDynamicSymbolTable->indirectsymoff() < linkEditSegment->fileoff() )
throw "indirect symbol table not in __LINKEDIT";
- if ( (fDynamicSymbolTable->indirectsymoff()+fIndirectTableCount*8) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+ if ( (fDynamicSymbolTable->indirectsymoff()+fIndirectTableCount*4) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
throw "indirect symbol table not in __LINKEDIT";
if ( (fDynamicSymbolTable->indirectsymoff() % sizeof(pint_t)) != 0 )
throw "indirect symbol table not pointer aligned";
uint64_t segOffset = 0;
uint32_t count;
uint32_t skip;
- uint8_t flags;
const char* symbolName = NULL;
int libraryOrdinal = 0;
int segIndex;
int64_t addend = 0;
pint_t segStartAddr = 0;
- pint_t addr;
bool done = false;
while ( !done && (p < end) ) {
uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
const macho_load_command<P>* cmd = cmds;
for (uint32_t i = 0; i < cmd_count; ++i) {
- uint32_t size = cmd->cmdsize();
const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
if ( endOfCmd > endOfLoadCommands )
throwf("load command #%d extends beyond the end of the load commands", i);
const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
const macho_load_command<P>* cmd = cmds;
for (uint32_t i = 0; i < cmd_count; ++i) {
- uint32_t size = cmd->cmdsize();
const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
if ( endOfCmd > endOfLoadCommands )
throwf("load command #%d extends beyond the end of the load commands", i);