X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/f410558f5d60087e4c310119a1751b437121c3b9..e456bf1059cf7e6b8b71545d1b2f2092b55a9684:/src/ld/parsers/macho_relocatable_file.cpp diff --git a/src/ld/parsers/macho_relocatable_file.cpp b/src/ld/parsers/macho_relocatable_file.cpp index ae3be5f..00d5feb 100644 --- a/src/ld/parsers/macho_relocatable_file.cpp +++ b/src/ld/parsers/macho_relocatable_file.cpp @@ -80,11 +80,10 @@ public: _dwarfTranslationUnitPath(NULL), _dwarfDebugInfoSect(NULL), _dwarfDebugAbbrevSect(NULL), _dwarfDebugLineSect(NULL), _dwarfDebugStringSect(NULL), - _objConstraint(ld::File::objcConstraintNone), + _hasObjC(false), _swiftVersion(0), _cpuSubType(0), _minOSVersion(0), - _platform(Options::kPlatformUnknown), _canScatterAtoms(false), _hasllvmProfiling(false), _objcHasCategoryClassPropertiesField(false), @@ -95,11 +94,10 @@ public: virtual bool forEachAtom(ld::File::AtomHandler&) const; virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const { return false; } - virtual uint32_t minOSVersion() const { return _minOSVersion; } - virtual uint32_t platform() const { return _platform; } + virtual const ld::VersionSet& platforms() const { return _platforms; } // overrides of ld::relocatable::File - virtual ObjcConstraint objCConstraint() const { return _objConstraint; } + virtual bool hasObjC() const { return _hasObjC; } virtual bool objcHasCategoryClassPropertiesField() const { return _objcHasCategoryClassPropertiesField; } virtual uint32_t cpuSubType() const { return _cpuSubType; } @@ -144,11 +142,11 @@ private: const macho_section
* _dwarfDebugAbbrevSect; const macho_section
* _dwarfDebugLineSect; const macho_section
* _dwarfDebugStringSect;
- ld::File::ObjcConstraint _objConstraint;
+ bool _hasObjC;
uint8_t _swiftVersion;
uint32_t _cpuSubType;
uint32_t _minOSVersion;
- Options::Platform _platform;
+ ld::VersionSet _platforms;
bool _canScatterAtoms;
bool _hasllvmProfiling;
bool _objcHasCategoryClassPropertiesField;
@@ -995,7 +993,7 @@ public:
static bool validFile(const uint8_t* fileContent, bool subtypeMustMatch=false,
cpu_subtype_t subtype=0);
static const char* fileKind(const uint8_t* fileContent);
- static Options::Platform findPlatform(const macho_header * _stubsMachOSection;
std::vector ** symbol)
{
+ bool cfiApplicable = (sect.machoSection()->flags() & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS));
// may not be a label on start of section, but need atom demarcation there
if ( newSection ) {
newSection = false;
// advance symIndex until we get to the first label at or past the start of this section
while ( symIndex < sortedSymbolCount ) {
- const macho_nlist & sym = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]);
- if ( ! sect.ignoreLabel(parser.nameFromSymbol(sym)) ) {
- pint_t nextSymbolAddr = sym.n_value();
+ const macho_nlist * sym = &parser.symbolFromIndex(sortedSymbolIndexes[symIndex]);
+ // if compile threw in "ltmp*" symbol at start of section and there is another real label at same location, ignore ltmp one
+ if ( symIndex+1 < sortedSymbolCount ) {
+ const macho_nlist * sym2 = &parser.symbolFromIndex(sortedSymbolIndexes[symIndex+1]);
+ if ( (sym->n_sect() == sym2->n_sect()) && (sym->n_value() == sym2->n_value()) ) {
+ if ( strncmp(parser.nameFromSymbol(*sym), "ltmp", 4) == 0 ) {
+ ++symIndex;
+ sym = sym2;
+ }
+ }
+ }
+ if ( ! sect.ignoreLabel(parser.nameFromSymbol(*sym)) ) {
+ pint_t nextSymbolAddr = sym->n_value();
//fprintf(stderr, "sectNum=%d, nextSymbolAddr=0x%08llX, name=%s\n", sectNum, (uint64_t)nextSymbolAddr, parser.nameFromSymbol(sym));
- if ( (nextSymbolAddr > startAddr) || ((nextSymbolAddr == startAddr) && (sym.n_sect() == sectNum)) )
+ if ( (nextSymbolAddr > startAddr) || ((nextSymbolAddr == startAddr) && (sym->n_sect() == sectNum)) )
break;
}
++symIndex;
@@ -1621,7 +1650,7 @@ bool Parser::LabelAndCFIBreakIterator::next(Parser& parser, const Section<
return true;
}
// no symbols in section, check CFI
- if ( cfiIndex < cfiStartsCount ) {
+ if ( cfiApplicable && (cfiIndex < cfiStartsCount) ) {
pint_t nextCfiAddr = cfiStartsArray[cfiIndex];
if ( nextCfiAddr < endAddr ) {
// use cfi
@@ -1749,6 +1778,10 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts)
_treateBitcodeAsData = opts.treateBitcodeAsData;
_usingBitcode = opts.usingBitcode;
+#if SUPPORT_ARCH_arm64e
+ _supportsAuthenticatedPointers = opts.supportsAuthenticatedPointers;
+#endif
+
// respond to -t option
if ( opts.logAllFiles )
printf("%s\n", _path);
@@ -1757,7 +1790,7 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts)
_maxDefaultCommonAlignment = opts.maxDefaultCommonAlignment;
// parse start of mach-o file
- if ( ! parseLoadCommands(opts.platform, opts.minOSVersion, opts.simulator, opts.ignoreMismatchPlatform) )
+ if ( ! parseLoadCommands(opts.platforms, opts.simulator, opts.ignoreMismatchPlatform) )
return _file;
// make array of
@@ -1999,9 +2032,13 @@ template <> uint8_t Parser * header = (const macho_header *)_fileContent;
@@ -2015,7 +2052,7 @@ bool Parser::parseLoadCommands(Options::Platform platform, uint32_t linkMinOS
// * const cmds = (macho_load_command *)((char*)header + sizeof(macho_header ));
const macho_load_command * const cmdsEnd = (macho_load_command *)((char*)header + sizeof(macho_header ) + header->sizeofcmds());
const macho_load_command * cmd = cmds;
@@ -2097,23 +2134,19 @@ bool Parser::parseLoadCommands(Options::Platform platform, uint32_t linkMinOS
case LC_VERSION_MIN_MACOSX:
case LC_VERSION_MIN_IPHONEOS:
case LC_VERSION_MIN_WATCHOS:
- #if SUPPORT_APPLE_TV
case LC_VERSION_MIN_TVOS:
- #endif
if ( ignoreMismatchPlatform )
break;
- lcPlatform = Options::platformForLoadCommand(cmd->cmd());
- _file->_platform = lcPlatform;
- _file->_minOSVersion = ((macho_version_min_command *)cmd)->version();
+ lcPlatforms.add({Options::platformForLoadCommand(cmd->cmd(), useSimulatorVariant()), ((macho_version_min_command *)cmd)->version()});
+ _file->_platforms.add({Options::platformForLoadCommand(cmd->cmd(), useSimulatorVariant()), ((macho_version_min_command *)cmd)->version()});
break;
case LC_BUILD_VERSION:
{
const macho_build_version_command * buildVersCmd = (macho_build_version_command *)cmd;
if ( ignoreMismatchPlatform )
break;
- lcPlatform = (Options::Platform)buildVersCmd->platform();
- _file->_platform = lcPlatform;
- _file->_minOSVersion = buildVersCmd->minos();
+ lcPlatforms.add({(ld::Platform)buildVersCmd->platform(), buildVersCmd->minos()});
+ _file->_platforms.add({(ld::Platform)buildVersCmd->platform(), buildVersCmd->minos()});
const macho_build_tool_version * entry = (macho_build_tool_version *)((uint8_t*)cmd + sizeof(macho_build_version_command ));
for (uint32_t t=0; t < buildVersCmd->ntools(); ++t) {
_file->_toolVersions.push_back(std::make_pair(entry->tool(), entry->version()));
@@ -2134,80 +2167,63 @@ bool Parser::parseLoadCommands(Options::Platform platform, uint32_t linkMinOS
if ( cmd > cmdsEnd )
throwf("malformed mach-o file, load command #%d is outside size of load commands", i);
}
+
// arm/arm64 objects are default to ios platform if not set.
// rdar://problem/21746314
- if (lcPlatform == Options::kPlatformUnknown &&
+ if (lcPlatforms.empty() &&
(std::is_same::value || std::is_same::value))
- lcPlatform = Options::kPlatformiOS;
+ lcPlatforms.add({ld::kPlatform_iOS,0});
// Check platform cross-linking.
if ( !ignoreMismatchPlatform ) {
- if ( lcPlatform != platform ) {
- switch (platform) {
- case Options::kPlatformOSX:
- case Options::kPlatformiOS:
- 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)
- 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(),
- Options::platformName(lcPlatform));
- break;
- #if SUPPORT_APPLE_TV
- case 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(),
- Options::platformName(lcPlatform));
- break;
- #endif
- case Options::kPlatformUnknown:
- // skip if the target platform is unknown
- break;
+ __block bool warned = false;
+ platforms.forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+ if ( !warned && !lcPlatforms.contains(platform) ) {
+ if (_usingBitcode)
+ throwf("building for %s, but linking in object file built for %s,",
+ platforms.to_str().c_str(), lcPlatforms.to_str().c_str());
+#if 0
+// FIXME: Re-enable once clang supports zippering
+// *)((char*)segment + sizeof(macho_segment_command ));
_machOSectionsCount = segment->nsects();
if ( (sizeof(macho_segment_command ) + _machOSectionsCount * sizeof(macho_section )) > segment->cmdsize() )
throw "too many sections for size of LC_SEGMENT command";
+
return true;
}
template * header)
+ld::Platform Parser::findPlatform(const macho_header * header, uint32_t* minOsVers)
{
const uint32_t cmd_count = header->ncmds();
if ( cmd_count == 0 )
- return Options::kPlatformUnknown;
+ return ld::kPlatform_unknown;
const macho_load_command * const cmds = (macho_load_command *)((char*)header + sizeof(macho_header ));
const macho_load_command * const cmdsEnd = (macho_load_command *)((char*)header + sizeof(macho_header ) + header->sizeofcmds());
const macho_load_command * cmd = cmds;
@@ -2218,25 +2234,37 @@ Options::Platform Parser::findPlatform(const macho_header * header)
const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
if ( endOfCmd > (uint8_t*)cmdsEnd )
throwf("load command #%d extends beyond the end of the load commands", i);
+ const macho_version_min_command * versCmd = (macho_version_min_command *)cmd;
+ const macho_build_version_command * buildVersCmd = (macho_build_version_command *)cmd;
+ *minOsVers = versCmd->version();
switch (cmd->cmd()) {
case LC_VERSION_MIN_MACOSX:
- return Options::kPlatformOSX;
+ return ld::kPlatform_macOS;
case LC_VERSION_MIN_IPHONEOS:
- return Options::kPlatformiOS;
+ if (useSimulatorVariant())
+ return ld::kPlatform_iOSSimulator;
+ else
+ return ld::kPlatform_iOS;
case LC_VERSION_MIN_WATCHOS:
- return Options::kPlatformWatchOS;
- #if SUPPORT_APPLE_TV
+ if (useSimulatorVariant())
+ return ld::kPlatform_watchOSSimulator;
+ else
+ return ld::kPlatform_watchOS;
case LC_VERSION_MIN_TVOS:
- return Options::kPlatform_tvOS;
- #endif
+ if (useSimulatorVariant())
+ return ld::kPlatform_tvOSSimulator;
+ else
+ return ld::kPlatform_tvOS;
case LC_BUILD_VERSION:
- return (Options::Platform)((macho_build_version_command *)cmd)->platform();
+ *minOsVers = buildVersCmd->minos();
+ return (ld::Platform)buildVersCmd->platform();
}
cmd = (const macho_load_command *)(((char*)cmd)+cmd->cmdsize());
if ( cmd > cmdsEnd )
throwf("malformed mach-o file, load command #%d is outside size of load commands", i);
}
- return Options::kPlatformUnknown;
+ *minOsVers = 0;
+ return ld::kPlatform_unknown;
}
@@ -2578,14 +2606,7 @@ void Parser::makeSections()
const uint32_t* contents = (uint32_t*)(_file->fileContent()+sect->offset());
if ( (sect->size() >= 8) && (contents[0] == 0) ) {
uint32_t flags = E::get32(contents[1]);
- if ( (flags & 4) == 4 )
- _file->_objConstraint = ld::File::objcConstraintGC;
- else if ( (flags & 2) == 2 )
- _file->_objConstraint = ld::File::objcConstraintRetainReleaseOrGC;
- else if ( (flags & 32) == 32 )
- _file->_objConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
- else
- _file->_objConstraint = ld::File::objcConstraintRetainRelease;
+ _file->_hasObjC = true;
_file->_swiftVersion = ((flags >> 8) & 0xFF);
_file->_objcHasCategoryClassPropertiesField = (flags & 64);
if ( sect->size() > 8 ) {
@@ -3055,6 +3076,13 @@ void Parser::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co
ld::Fixup::Cluster cl = ld::Fixup::k1of3;
ld::Fixup::Kind firstKind = ld::Fixup::kindSetTargetAddress;
bool combined = false;
+
+#if SUPPORT_ARCH_arm64e
+ bool isAuthenticated = setKind == ld::Fixup::kindStoreLittleEndianAuth64;
+ // Authenticated pointers need an extra fixup for the auth data.
+ if (isAuthenticated)
+ cl = ld::Fixup::k2of4;
+#endif
if ( target.addend == 0 ) {
cl = ld::Fixup::k1of1;
combined = true;
@@ -3114,6 +3142,12 @@ void Parser::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co
case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
firstKind = ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12;
break;
+#endif
+#if SUPPORT_ARCH_arm64e
+ case ld::Fixup::kindStoreLittleEndianAuth64:
+ firstKind = ld::Fixup::kindStoreTargetAddressLittleEndianAuth64;
+ cl = ld::Fixup::k2of2;
+ break;
#endif
default:
combined = false;
@@ -3122,6 +3156,19 @@ void Parser::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co
}
}
+#if SUPPORT_ARCH_arm64e
+ // As the auth data is independent of the addend and target, we can just always
+ // put it first.
+ if (isAuthenticated) {
+ if (cl == ld::Fixup::k2of2) {
+ addFixup(src, ld::Fixup::k1of2, ld::Fixup::kindSetAuthData, target.authData);
+ } else {
+ assert(cl == ld::Fixup::k2of4);
+ addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetAuthData, target.authData);
+ }
+ }
+#endif
+
if ( target.atom != NULL ) {
if ( target.atom->scope() == ld::Atom::scopeTranslationUnit ) {
addFixup(src, cl, firstKind, target.atom);
@@ -3146,12 +3193,24 @@ void Parser::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co
addFixup(src, cl, firstKind, target.weakImport, target.name);
}
if ( target.addend == 0 ) {
+#if SUPPORT_ARCH_arm64e
+ if (isAuthenticated)
+ assert(combined);
+#endif
if ( ! combined )
addFixup(src, ld::Fixup::k2of2, setKind);
}
else {
- addFixup(src, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, target.addend);
- addFixup(src, ld::Fixup::k3of3, setKind);
+#if SUPPORT_ARCH_arm64e
+ if (isAuthenticated) {
+ addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindAddAddend, target.addend);
+ addFixup(src, ld::Fixup::k4of4, setKind);
+ } else
+#endif
+ {
+ addFixup(src, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, target.addend);
+ addFixup(src, ld::Fixup::k3of3, setKind);
+ }
}
}
@@ -5470,7 +5529,7 @@ uint32_t ImplicitSizeSection::appendAtoms(class Parser& parser, uint8_t* p
}
else {
// make named atom for label
- //fprintf(stderr, " 0x%08llX make labeled\n", (uint64_t)foundAddr);
+ //fprintf(stderr, " 0x%08llX make labeled: %s\n", (uint64_t)foundAddr, parser.nameFromSymbol(*foundLabel));
new (allocatedSpace) Atom(*this, parser, *foundLabel, labeledAtomSize);
}
if ( !skip ) {
@@ -6308,6 +6367,8 @@ bool Section