From ba348e2165668ae0f4af8b349fc4a6d0910950ed Mon Sep 17 00:00:00 2001 From: Apple Date: Tue, 19 Aug 2014 22:19:03 +0000 Subject: [PATCH] ld64-242.tar.gz --- ld64.xcodeproj/project.pbxproj | 15 +-- src/abstraction/MachOFileAbstraction.hpp | 39 +++++- src/create_configure | 2 +- src/ld/InputFiles.cpp | 3 +- src/ld/Options.cpp | 71 +++++++--- src/ld/Options.h | 1 + src/ld/Resolver.cpp | 14 +- src/ld/ld.hpp | 2 +- .../parsers/libunwind/DwarfInstructions.hpp | 31 +++++ src/ld/parsers/lto_file.cpp | 3 +- src/ld/parsers/lto_file.h | 1 + src/ld/parsers/macho_relocatable_file.cpp | 102 ++++++++++++++- src/ld/parsers/macho_relocatable_file.h | 1 + src/ld/passes/compact_unwind.cpp | 70 ++++++++++ src/other/ObjectDump.cpp | 1 + src/other/unwinddump.cpp | 123 ++++++++++++++++++ 16 files changed, 431 insertions(+), 48 deletions(-) diff --git a/ld64.xcodeproj/project.pbxproj b/ld64.xcodeproj/project.pbxproj index 854356e..b4d1749 100644 --- a/ld64.xcodeproj/project.pbxproj +++ b/ld64.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 42; + objectVersion = 46; objects = { /* Begin PBXAggregateTarget section */ @@ -697,10 +697,11 @@ F9023C3006D5A227001BBF46 /* Project object */ = { isa = PBXProject; attributes = { + LastUpgradeCheck = 0600; ORGANIZATIONNAME = "Apple Inc."; }; buildConfigurationList = F933D92309291AC90083EAC8 /* Build configuration list for PBXProject "ld64" */; - compatibilityVersion = "Xcode 2.4"; + compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( @@ -1244,18 +1245,15 @@ F933D92409291AC90083EAC8 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1)"; - ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64; GCC_DYNAMIC_NO_PIC = NO; GCC_TREAT_WARNINGS_AS_ERRORS = NO; + ONLY_ACTIVE_ARCH = YES; }; name = Debug; }; F933D92509291AC90083EAC8 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1)"; - ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64; GCC_DYNAMIC_NO_PIC = NO; GCC_TREAT_WARNINGS_AS_ERRORS = NO; }; @@ -1282,8 +1280,6 @@ F9849FF810B5DE8E009E9878 /* Release-assert */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1)"; - ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64; GCC_DYNAMIC_NO_PIC = NO; GCC_TREAT_WARNINGS_AS_ERRORS = NO; }; @@ -1496,6 +1492,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; GCC_ENABLE_FIX_AND_CONTINUE = NO; @@ -1524,6 +1521,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_MODEL_TUNING = G5; @@ -1544,6 +1542,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; GCC_ENABLE_FIX_AND_CONTINUE = NO; diff --git a/src/abstraction/MachOFileAbstraction.hpp b/src/abstraction/MachOFileAbstraction.hpp index 8b58efd..ae61d7c 100644 --- a/src/abstraction/MachOFileAbstraction.hpp +++ b/src/abstraction/MachOFileAbstraction.hpp @@ -254,9 +254,16 @@ // hack until arm64 headers are worked out -#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) -#define CPU_SUBTYPE_ARM64_ALL 0 -#define CPU_SUBTYPE_ARM64_V8 1 +#ifndef CPU_TYPE_ARM64 + #define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) +#endif +#ifndef CPU_SUBTYPE_ARM64_ALL + #define CPU_SUBTYPE_ARM64_ALL 0 +#endif +#ifndef CPU_SUBTYPE_ARM64_V8 + #define CPU_SUBTYPE_ARM64_V8 1 +#endif + #define ARM64_RELOC_UNSIGNED 0 // for pointers #define ARM64_RELOC_SUBTRACTOR 1 // must be followed by a ARM64_RELOC_UNSIGNED @@ -370,6 +377,8 @@ #define UNWIND_ARM64_DWARF_SECTION_OFFSET 0x00FFFFFF +#define UNW_ARM_D31 287 + #ifndef LC_SOURCE_VERSION #define LC_SOURCE_VERSION 0x2A @@ -442,6 +451,26 @@ #define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t) 8) #endif +#define UNWIND_ARM_MODE_MASK 0x0F000000 +#define UNWIND_ARM_MODE_FRAME 0x01000000 +#define UNWIND_ARM_MODE_FRAME_D 0x02000000 +#define UNWIND_ARM_MODE_DWARF 0x04000000 + +#define UNWIND_ARM_FRAME_STACK_ADJUST_MASK 0x00C00000 + +#define UNWIND_ARM_FRAME_FIRST_PUSH_R4 0x00000001 +#define UNWIND_ARM_FRAME_FIRST_PUSH_R5 0x00000002 +#define UNWIND_ARM_FRAME_FIRST_PUSH_R6 0x00000004 + +#define UNWIND_ARM_FRAME_SECOND_PUSH_R8 0x00000008 +#define UNWIND_ARM_FRAME_SECOND_PUSH_R9 0x00000010 +#define UNWIND_ARM_FRAME_SECOND_PUSH_R10 0x00000020 +#define UNWIND_ARM_FRAME_SECOND_PUSH_R11 0x00000040 +#define UNWIND_ARM_FRAME_SECOND_PUSH_R12 0x00000080 + +#define UNWIND_ARM_FRAME_D_REG_COUNT_MASK 0x00000F00 + +#define UNWIND_ARM_DWARF_SECTION_OFFSET 0x00FFFFFF struct ArchInfo { const char* archName; @@ -508,10 +537,10 @@ static const ArchInfo archInfoArray[] = { #define SUPPORT_ARCH_arm_any 1 #endif #if SUPPORT_ARCH_arm64 - { "arm64", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL, "arm64-", "", false, false }, + { "arm64", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL, "arm64-", "aarch64-", false, false }, #endif #if SUPPORT_ARCH_arm64v8 - { "arm64v8", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_V8, "arm64v8-", "", true, false }, + { "arm64v8", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_V8, "arm64v8-", "aarch64-", true, false }, #endif { NULL, 0, 0, NULL, NULL, false, false } }; diff --git a/src/create_configure b/src/create_configure index 8ca92be..f991231 100755 --- a/src/create_configure +++ b/src/create_configure @@ -11,7 +11,7 @@ else fi if [ -z "${RC_SUPPORTED_ARCHS}" ]; then - RC_SUPPORTED_ARCHS="i386 x86_64 x86_64h armv6 armv7 armv7s armv7m arm64" + RC_SUPPORTED_ARCHS="i386 x86_64 x86_64h armv6 armv7 armv7s armv7m armv7k arm64" fi for ANARCH in ${RC_SUPPORTED_ARCHS} diff --git a/src/ld/InputFiles.cpp b/src/ld/InputFiles.cpp index 595b5d1..30c0875 100644 --- a/src/ld/InputFiles.cpp +++ b/src/ld/InputFiles.cpp @@ -293,6 +293,7 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib objOpts.forceDwarfConversion= (_options.outputKind() == Options::kDyld); objOpts.neverConvertDwarf = !_options.needsUnwindInfoSection(); objOpts.verboseOptimizationHints = _options.verboseOptimizationHints(); + objOpts.armUsesZeroCostExceptions = _options.armUsesZeroCostExceptions(); objOpts.subType = _options.subArchitecture(); ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts); if ( objResult != NULL ) { @@ -586,7 +587,6 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan ld::dylib::File* dylibReader = dynamic_cast(reader); if ( dylibReader != NULL ) { if ( ! dylibReader->installPathVersionSpecific() ) { - dylibReader->forEachAtom(handler); dylibReader->setImplicitlyLinked(); this->addDylib(dylibReader, info); } @@ -613,7 +613,6 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan ld::dylib::File* dylibReader = dynamic_cast(reader); ld::archive::File* archiveReader = dynamic_cast(reader); if ( dylibReader != NULL ) { - dylibReader->forEachAtom(handler); dylibReader->setImplicitlyLinked(); this->addDylib(dylibReader, info); } diff --git a/src/ld/Options.cpp b/src/ld/Options.cpp index aa4f6ee..228a0df 100644 --- a/src/ld/Options.cpp +++ b/src/ld/Options.cpp @@ -601,6 +601,11 @@ void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype) fArchitectureName = "unknown architecture"; } +bool Options::armUsesZeroCostExceptions() const +{ + return ( (fArchitecture == CPU_TYPE_ARM) && (fSubArchitecture == CPU_SUBTYPE_ARM_V7K) ); +} + void Options::parseArch(const char* arch) { if ( arch == NULL ) @@ -3889,8 +3894,26 @@ void Options::reconfigureDefaults() } break; case CPU_TYPE_ARM: - fAddCompactUnwindEncoding = false; - fRemoveDwarfUnwindIfCompactExists = false; + if ( armUsesZeroCostExceptions() ) { + switch ( fOutputKind ) { + case Options::kObjectFile: + case Options::kStaticExecutable: + case Options::kPreload: + case Options::kKextBundle: + fAddCompactUnwindEncoding = false; + break; + case Options::kDyld: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kDynamicExecutable: + fAddCompactUnwindEncoding = true; + break; + } + } + else { + fAddCompactUnwindEncoding = false; + fRemoveDwarfUnwindIfCompactExists = false; + } break; case 0: // if -arch is missing, assume we don't want compact unwind info @@ -4270,25 +4293,32 @@ void Options::reconfigureDefaults() // ARM64 needs 16KB page size for user land code // make armv7[s] use 16KB pages in user land code for iOS 8 or later if ( fSegmentAlignment == 4096 ) { - if ( (fArchitecture == CPU_TYPE_ARM64) - || ((fArchitecture == CPU_TYPE_ARM) && (fIOSVersionMin >= ld::iOS_8_0) && - ((fSubArchitecture == CPU_SUBTYPE_ARM_V7S) || (fSubArchitecture == CPU_SUBTYPE_ARM_V7))) ) { - switch ( fOutputKind ) { - case Options::kDynamicExecutable: - case Options::kDynamicLibrary: - case Options::kDynamicBundle: - case Options::kDyld: + switch ( fOutputKind ) { + case Options::kDynamicExecutable: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kDyld: + if ( (fArchitecture == CPU_TYPE_ARM64) + || ((fArchitecture == CPU_TYPE_ARM) && (fIOSVersionMin >= ld::iOS_8_0) && + ((fSubArchitecture == CPU_SUBTYPE_ARM_V7S) || (fSubArchitecture == CPU_SUBTYPE_ARM_V7))) ) { fSegmentAlignment = 4096*4; - break; - case Options::kStaticExecutable: - case Options::kKextBundle: - case Options::kObjectFile: - case Options::kPreload: - break; - } + } + break; + case Options::kStaticExecutable: + case Options::kKextBundle: + // 16KB segments for arm64 kexts + if ( (fArchitecture == CPU_TYPE_ARM64) && (fIOSVersionMin >= ld::iOS_9_0) ) { + fSegmentAlignment = 4096*4; + } + break; + case Options::kObjectFile: + case Options::kPreload: + break; } } + + // linker should not convert dwarf unwind if .o file has compact unwind section switch ( fOutputKind ) { case Options::kDynamicExecutable: @@ -4316,6 +4346,13 @@ void Options::reconfigureDefaults() break; } + // Make sure -image_base matches alignment + uint64_t alignedBaseAddress = (fBaseAddress+fSegmentAlignment-1) & (-fSegmentAlignment); + if ( alignedBaseAddress != fBaseAddress ) { + warning("base address 0x%llX is not properly aligned. Changing it to 0x%llX", fBaseAddress, alignedBaseAddress); + fBaseAddress = alignedBaseAddress; + } + } void Options::checkIllegalOptionCombinations() diff --git a/src/ld/Options.h b/src/ld/Options.h index 8395fc9..39ee6fe 100644 --- a/src/ld/Options.h +++ b/src/ld/Options.h @@ -390,6 +390,7 @@ public: linkerOptions() const { return fLinkerOptions; } FileInfo findFramework(const char* frameworkName) const; FileInfo findLibrary(const char* rootName, bool dylibsOnly=false) const; + bool armUsesZeroCostExceptions() const; const std::vector& sectionRenames() const { return fSectionRenames; } const std::vector& segmentRenames() const { return fSegmentRenames; } bool moveRoSymbol(const char* symName, const char* filePath, const char*& seg, bool& wildCardMatch) const; diff --git a/src/ld/Resolver.cpp b/src/ld/Resolver.cpp index a5405a9..8a72b67 100644 --- a/src/ld/Resolver.cpp +++ b/src/ld/Resolver.cpp @@ -330,17 +330,14 @@ void Resolver::doLinkerOption(const std::vector& linkerOption, cons } } -static void userReadableSwiftVersion(uint8_t value, char versionString[64]) +static void userReadableSwiftVersion(uint8_t value, char versionString[32]) { switch (value) { case 1: strcpy(versionString, "1.0"); break; - case 2: - strcpy(versionString, "1.1"); - break; default: - sprintf(versionString, "unknown ABI version 0x%02X", value); + sprintf(versionString, "0x%02X", value); } } @@ -403,8 +400,8 @@ void Resolver::doFile(const ld::File& file) _internal.swiftVersion = file.swiftVersion(); } else if ( file.swiftVersion() != _internal.swiftVersion ) { - char fileVersion[64]; - char otherVersion[64]; + char fileVersion[32]; + char otherVersion[32]; userReadableSwiftVersion(file.swiftVersion(), fileVersion); userReadableSwiftVersion(_internal.swiftVersion, otherVersion); if ( file.swiftVersion() > _internal.swiftVersion ) { @@ -513,7 +510,7 @@ void Resolver::doFile(const ld::File& file) if ( (_options.iOSVersionMin() != iOSVersionUnset) && (_options.iOSVersionMin() < iOS_8_0) ) { // only warn about linking against embedded dylib if it is built for iOS 8 or later if ( dylibFile->iOSMinVersion() >= iOS_8_0 ) - throwf("embedded dylibs/frameworks are only supported on iOS 8.0 and later (%s)", depInstallName); + warning("embedded dylibs/frameworks are only supported on iOS 8.0 and later (%s)", depInstallName); } } if ( _options.sharedRegionEligible() ) { @@ -1550,6 +1547,7 @@ void Resolver::linkTimeOptimize() optOpt.needsUnwindInfoSection = _options.needsUnwindInfoSection(); optOpt.keepDwarfUnwind = _options.keepDwarfUnwind(); optOpt.verboseOptimizationHints = _options.verboseOptimizationHints(); + optOpt.armUsesZeroCostExceptions = _options.armUsesZeroCostExceptions(); optOpt.arch = _options.architecture(); optOpt.mcpu = _options.mcpuLTO(); optOpt.llvmOptions = &_options.llvmOptions(); diff --git a/src/ld/ld.hpp b/src/ld/ld.hpp index 8c3de4f..889cf2c 100644 --- a/src/ld/ld.hpp +++ b/src/ld/ld.hpp @@ -168,7 +168,7 @@ enum MacVersionMin { macVersionUnset=0, mac10_4=0x000A0400, mac10_5=0x000A0500, enum IOSVersionMin { iOSVersionUnset=0, iOS_2_0=0x00020000, iOS_3_1=0x00030100, iOS_4_2=0x00040200, iOS_4_3=0x00040300, iOS_5_0=0x00050000, iOS_6_0=0x00060000, iOS_7_0=0x00070000, iOS_8_0=0x00080000, - iOS_Future=0x10000000}; + iOS_9_0=0x00090000, iOS_Future=0x10000000}; namespace relocatable { // diff --git a/src/ld/parsers/libunwind/DwarfInstructions.hpp b/src/ld/parsers/libunwind/DwarfInstructions.hpp index 1835540..c14c38f 100644 --- a/src/ld/parsers/libunwind/DwarfInstructions.hpp +++ b/src/ld/parsers/libunwind/DwarfInstructions.hpp @@ -167,6 +167,14 @@ private: const Registers_arm64&, const typename CFI_Parser::PrologInfo& prolog, char warningBuffer[1024]); + // arm specific variants + static bool isReturnAddressRegister(int regNum, const Registers_arm&); + static pint_t getCFA(A& addressSpace, const typename CFI_Parser::PrologInfo& prolog, const Registers_arm&); + static compact_unwind_encoding_t encodeToUseDwarf(const Registers_arm&); + static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr, + const Registers_arm&, const typename CFI_Parser::PrologInfo& prolog, + char warningBuffer[1024]); + }; @@ -1962,6 +1970,29 @@ compact_unwind_encoding_t DwarfInstructions::createCompactEncodingFromProlo } + + +// +// arm specific functions +// + +template +compact_unwind_encoding_t DwarfInstructions::encodeToUseDwarf(const Registers_arm&) +{ + return UNWIND_ARM_MODE_DWARF; +} + + +template +compact_unwind_encoding_t DwarfInstructions::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr, + const Registers_arm& r, const typename CFI_Parser::PrologInfo& prolog, + char warningBuffer[1024]) +{ + warningBuffer[0] = '\0'; + return UNWIND_ARM_MODE_DWARF; +} + + } // namespace libunwind diff --git a/src/ld/parsers/lto_file.cpp b/src/ld/parsers/lto_file.cpp index f2cb8ca..fbba237 100644 --- a/src/ld/parsers/lto_file.cpp +++ b/src/ld/parsers/lto_file.cpp @@ -302,6 +302,7 @@ ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, cons objOpts.forceDwarfConversion = false; objOpts.neverConvertDwarf = false; objOpts.verboseOptimizationHints = options.verboseOptimizationHints; + objOpts.armUsesZeroCostExceptions = options.armUsesZeroCostExceptions; objOpts.subType = 0; @@ -485,8 +486,6 @@ void Parser::ltoDiagnosticHandler(lto_codegen_diagnostic_severity_t severity, co switch ( severity ) { #if LTO_API_VERSION >= 10 case LTO_DS_REMARK: - fprintf(stderr, "ld: LTO remark: %s\n", message); - break; #endif case LTO_DS_NOTE: case LTO_DS_WARNING: diff --git a/src/ld/parsers/lto_file.h b/src/ld/parsers/lto_file.h index 332215d..dcd6e36 100644 --- a/src/ld/parsers/lto_file.h +++ b/src/ld/parsers/lto_file.h @@ -57,6 +57,7 @@ struct OptimizeOptions { bool needsUnwindInfoSection; bool keepDwarfUnwind; bool verboseOptimizationHints; + bool armUsesZeroCostExceptions; cpu_type_t arch; const char* mcpu; const std::vector* llvmOptions; diff --git a/src/ld/parsers/macho_relocatable_file.cpp b/src/ld/parsers/macho_relocatable_file.cpp index d3990e3..49d333e 100644 --- a/src/ld/parsers/macho_relocatable_file.cpp +++ b/src/ld/parsers/macho_relocatable_file.cpp @@ -435,6 +435,7 @@ protected: virtual unsigned long contentHash(const class Atom* atom, const ld::IndirectBindingTable& ind) const; virtual bool canCoalesceWith(const class Atom* atom, const ld::Atom& rhs, const ld::IndirectBindingTable& ind) const; + virtual bool ignoreLabel(const char* label) const; }; template @@ -454,6 +455,7 @@ protected: virtual unsigned long contentHash(const class Atom* atom, const ld::IndirectBindingTable& ind) const; virtual bool canCoalesceWith(const class Atom* atom, const ld::Atom& rhs, const ld::IndirectBindingTable& ind) const; + virtual bool ignoreLabel(const char* label) const; }; template @@ -473,6 +475,7 @@ protected: virtual unsigned long contentHash(const class Atom* atom, const ld::IndirectBindingTable& ind) const; virtual bool canCoalesceWith(const class Atom* atom, const ld::Atom& rhs, const ld::IndirectBindingTable& ind) const; + virtual bool ignoreLabel(const char* label) const; }; @@ -1054,6 +1057,7 @@ public: bool forceDwarfConversion() { return _forceDwarfConversion; } bool verboseOptimizationHints() { return _verboseOptimizationHints; } bool neverConvertDwarf() { return _neverConvertDwarf; } + bool armUsesZeroCostExceptions() { return _armUsesZeroCostExceptions; } macho_data_in_code_entry

* dataInCodeStart() { return _dataInCodeStart; } macho_data_in_code_entry

* dataInCodeEnd() { return _dataInCodeEnd; } @@ -1204,6 +1208,7 @@ private: bool _forceDwarfConversion; bool _neverConvertDwarf; bool _verboseOptimizationHints; + bool _armUsesZeroCostExceptions; unsigned int _stubsSectionNum; const macho_section

* _stubsMachOSection; std::vector _dtraceProviderInfo; @@ -1632,6 +1637,8 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) // respond to -t option if ( opts.logAllFiles ) printf("%s\n", _path); + + _armUsesZeroCostExceptions = opts.armUsesZeroCostExceptions; // parse start of mach-o file if ( ! parseLoadCommands() ) @@ -4069,6 +4076,12 @@ uint32_t Section::sectionNum(class Parser& parser) const template <> uint32_t CFISection::cfiCount(Parser& parser) { + if ( parser.armUsesZeroCostExceptions() ) { + // create ObjectAddressSpace object for use by libunwind + OAS oas(*this, (uint8_t*)this->file().fileContent()+this->_machOSection->offset()); + return libunwind::CFI_Parser::getCFICount(oas, + this->_machOSection->addr(), this->_machOSection->size()); + } return 0; } @@ -4203,8 +4216,22 @@ void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, libunwind::CFI_Atom_Info::OAS>::CFI_Atom_Info cfiArray[], uint32_t& count, const pint_t cuStarts[], uint32_t cuCount) { - // arm does not use zero cost exceptions - assert(count == 0); + if ( !parser.armUsesZeroCostExceptions() ) { + // most arm do not use zero cost exceptions + assert(count == 0); + return; + } + // create ObjectAddressSpace object for use by libunwind + OAS oas(*this, (uint8_t*)this->file().fileContent()+this->_machOSection->offset()); + + // use libuwind to parse __eh_frame data into array of CFI_Atom_Info + const char* msg; + msg = libunwind::DwarfInstructions::parseCFIs( + oas, this->_machOSection->addr(), this->_machOSection->size(), + cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(), parser.neverConvertDwarf(), + cfiArray, count, (void*)&parser, warnFunc); + if ( msg != NULL ) + throwf("malformed __eh_frame section: %s", msg); } @@ -4385,6 +4412,29 @@ void CFISection::addCiePersonalityFixups(class Parser& parser, con } #endif +template <> +void CFISection::addCiePersonalityFixups(class Parser& parser, const CFI_Atom_Info* cieInfo) +{ + uint8_t personalityEncoding = cieInfo->u.cieInfo.personality.encodingOfTargetAddress; + if ( (personalityEncoding == 0x9B) || (personalityEncoding == 0x90) ) { + uint32_t offsetInCFI = cieInfo->u.cieInfo.personality.offsetInCFI; + uint32_t nlpAddr = cieInfo->u.cieInfo.personality.targetAddress; + Atom* cieAtom = this->findAtomByAddress(cieInfo->address); + Atom* nlpAtom = parser.findAtomByAddress(nlpAddr); + assert(nlpAtom->contentType() == ld::Atom::typeNonLazyPointer); + Parser::SourceLocation src(cieAtom, cieInfo->u.cieInfo.personality.offsetInCFI); + + parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, nlpAtom); + parser.addFixup(src, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, cieAtom); + parser.addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, offsetInCFI); + parser.addFixup(src, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32); + } + else if ( personalityEncoding != 0 ) { + throwf("unsupported address encoding (%02X) of personality function in CIE", personalityEncoding); + } +} + + template void CFISection::addCiePersonalityFixups(class Parser& parser, const CFI_Atom_Info* cieInfo) @@ -4686,6 +4736,35 @@ const char* CUSection::personalityName(class Parser& parser, const } #endif +#if SUPPORT_ARCH_arm_any +template <> +const char* CUSection::personalityName(class Parser& parser, const macho_relocation_info* reloc) +{ + if ( reloc->r_extern() ) { + assert((reloc->r_type() == ARM_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section"); + const macho_nlist

& sym = parser.symbolFromIndex(reloc->r_symbolnum()); + return parser.nameFromSymbol(sym); + } + else { + // support __LD, __compact_unwind personality entries which are pointer to personality non-lazy pointer + const pint_t* content = (pint_t*)(this->file().fileContent() + this->_machOSection->offset() + reloc->r_address()); + pint_t nlPointerAddr = *content; + Section* nlSection = parser.sectionForAddress(nlPointerAddr); + if ( nlSection->type() == ld::Section::typeCode ) { + // personality function is defined in this .o file, so this is a direct reference to it + // atoms may not be constructed yet, so scan symbol table for labels + const char* name = parser.scanSymbolTableForAddress(nlPointerAddr); + return name; + } + else { + uint32_t symIndex = parser.symbolIndexFromIndirectSectionAddress(nlPointerAddr, nlSection->machoSection()); + const macho_nlist

& nlSymbol = parser.symbolFromIndex(symIndex); + return parser.nameFromSymbol(nlSymbol); + } + } +} +#endif + template const char* CUSection::personalityName(class Parser& parser, const macho_relocation_info

* reloc) @@ -4709,7 +4788,7 @@ bool CUSection::encodingMeansUseDwarf(compact_unwind_encoding_t enc) template <> bool CUSection::encodingMeansUseDwarf(compact_unwind_encoding_t enc) { - return false; + return ((enc & UNWIND_ARM_MODE_MASK) == UNWIND_ARM_MODE_DWARF); } #endif @@ -5069,6 +5148,11 @@ uint32_t ImplicitSizeSection::appendAtoms(class Parser& parser, uint8_t* p return count; } +template +bool Literal4Section::ignoreLabel(const char* label) const +{ + return (label[0] == 'L') || (label[0] == 'l'); +} template unsigned long Literal4Section::contentHash(const class Atom* atom, const ld::IndirectBindingTable& ind) const @@ -5094,6 +5178,12 @@ bool Literal4Section::canCoalesceWith(const class Atom* atom, const ld::At } +template +bool Literal8Section::ignoreLabel(const char* label) const +{ + return (label[0] == 'L') || (label[0] == 'l'); +} + template unsigned long Literal8Section::contentHash(const class Atom* atom, const ld::IndirectBindingTable& ind) const { @@ -5128,6 +5218,11 @@ bool Literal8Section::canCoalesceWith(const class Atom* atom, const ld::At return false; } +template +bool Literal16Section::ignoreLabel(const char* label) const +{ + return (label[0] == 'L') || (label[0] == 'l'); +} template unsigned long Literal16Section::contentHash(const class Atom* atom, const ld::IndirectBindingTable& ind) const @@ -5373,7 +5468,6 @@ ld::Atom::Scope NonLazyPointerSection::scopeAtAddress(Parser& parser, pint return ld::Atom::scopeLinkageUnit; } - template const uint8_t* CFStringSection::targetContent(const class Atom* atom, const ld::IndirectBindingTable& ind, ContentType* ct, unsigned int* count) diff --git a/src/ld/parsers/macho_relocatable_file.h b/src/ld/parsers/macho_relocatable_file.h index 6d20847..92e9042 100644 --- a/src/ld/parsers/macho_relocatable_file.h +++ b/src/ld/parsers/macho_relocatable_file.h @@ -40,6 +40,7 @@ struct ParserOptions { bool forceDwarfConversion; bool neverConvertDwarf; bool verboseOptimizationHints; + bool armUsesZeroCostExceptions; uint32_t subType; }; diff --git a/src/ld/passes/compact_unwind.cpp b/src/ld/passes/compact_unwind.cpp index 3ddd9b8..6c1308d 100644 --- a/src/ld/passes/compact_unwind.cpp +++ b/src/ld/passes/compact_unwind.cpp @@ -304,6 +304,13 @@ bool UnwindInfoAtom::encodingMeansUseDwarf(compact_unwind_encoding_t enc) return ((enc & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF); } +template <> +bool UnwindInfoAtom::encodingMeansUseDwarf(compact_unwind_encoding_t enc) +{ + return ((enc & UNWIND_ARM_MODE_MASK) == UNWIND_ARM_MODE_DWARF); +} + + template void UnwindInfoAtom::compressDuplicates(const std::vector& entries, std::vector& uniqueEntries) { @@ -418,6 +425,22 @@ void UnwindInfoAtom::addCompressedAddressOffsetFixup(uint32_t offset, con _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32)); } +template <> +void UnwindInfoAtom::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc) +{ + if ( fromFunc->isThumb() ) { + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, func)); + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, fromFunc)); + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 1)); + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndianLow24of32)); + } + else { + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func)); + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc)); + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32)); + } +} + template <> void UnwindInfoAtom::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde) { @@ -439,6 +462,13 @@ void UnwindInfoAtom::addCompressedEncodingFixup(uint32_t offset, const ld _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32)); } +template <> +void UnwindInfoAtom::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde) +{ + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde)); + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32)); +} + template <> void UnwindInfoAtom::addRegularAddressFixup(uint32_t offset, const ld::Atom* func) { @@ -460,6 +490,13 @@ void UnwindInfoAtom::addRegularAddressFixup(uint32_t offset, const ld::At _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32)); } +template <> +void UnwindInfoAtom::addRegularAddressFixup(uint32_t offset, const ld::Atom* func) +{ + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func)); + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32)); +} + template <> void UnwindInfoAtom::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde) { @@ -481,6 +518,13 @@ void UnwindInfoAtom::addRegularFDEOffsetFixup(uint32_t offset, const ld:: _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32)); } +template <> +void UnwindInfoAtom::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde) +{ + _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde)); + _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32)); +} + template <> void UnwindInfoAtom::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ) { @@ -502,6 +546,13 @@ void UnwindInfoAtom::addImageOffsetFixup(uint32_t offset, const ld::Atom* _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32)); } +template <> +void UnwindInfoAtom::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ) +{ + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ)); + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32)); +} + template <> void UnwindInfoAtom::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend) { @@ -526,6 +577,14 @@ void UnwindInfoAtom::addImageOffsetFixupPlusAddend(uint32_t offset, const _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32)); } +template <> +void UnwindInfoAtom::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend) +{ + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ)); + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend)); + _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32)); +} + @@ -839,6 +898,12 @@ static void makeFinalLinkedImageCompactUnwindSection(const Options& opts, ld::In case CPU_TYPE_ARM64: state.addAtom(*new UnwindInfoAtom(entries, ehFrameSize)); break; +#endif +#if SUPPORT_ARCH_arm_any + case CPU_TYPE_ARM: + if ( opts.armUsesZeroCostExceptions() ) + state.addAtom(*new UnwindInfoAtom(entries, ehFrameSize)); + break; #endif default: assert(0 && "no compact unwind for arch"); @@ -892,6 +957,8 @@ template <> ld::Fixup::Kind CompactUnwindAtom::_s_pointerStoreKind = ld: template <> ld::Fixup::Kind CompactUnwindAtom::_s_pointerKind = ld::Fixup::kindStoreLittleEndian64; template <> ld::Fixup::Kind CompactUnwindAtom::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian64; #endif +template <> ld::Fixup::Kind CompactUnwindAtom::_s_pointerKind = ld::Fixup::kindStoreLittleEndian32; +template <> ld::Fixup::Kind CompactUnwindAtom::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian32; template CompactUnwindAtom::CompactUnwindAtom(ld::Internal& state,const ld::Atom* funcAtom, uint32_t startOffset, @@ -953,6 +1020,9 @@ static void makeCompactUnwindAtom(const Options& opts, ld::Internal& state, cons state.addAtom(*new CompactUnwindAtom(state, atom, startOffset, endOffset-startOffset, cui)); break; #endif + case CPU_TYPE_ARM: + state.addAtom(*new CompactUnwindAtom(state, atom, startOffset, endOffset-startOffset, cui)); + break; } } diff --git a/src/other/ObjectDump.cpp b/src/other/ObjectDump.cpp index e957e2b..ceab63c 100644 --- a/src/other/ObjectDump.cpp +++ b/src/other/ObjectDump.cpp @@ -1242,6 +1242,7 @@ static ld::relocatable::File* createReader(const char* path) objOpts.keepDwarfUnwind = false; objOpts.forceDwarfConversion = false; objOpts.verboseOptimizationHints = true; + objOpts.armUsesZeroCostExceptions = true; objOpts.subType = sPreferredSubArch; #if 1 if ( ! foundFatSlice ) { diff --git a/src/other/unwinddump.cpp b/src/other/unwinddump.cpp index effd09b..f91ece3 100644 --- a/src/other/unwinddump.cpp +++ b/src/other/unwinddump.cpp @@ -163,6 +163,25 @@ bool UnwindPrinter::validFile(const uint8_t* fileContent) } #endif +template <> +bool UnwindPrinter::validFile(const uint8_t* fileContent) +{ + const macho_header

* header = (const macho_header

*)fileContent; + if ( header->magic() != MH_MAGIC ) + return false; + if ( header->cputype() != CPU_TYPE_ARM ) + return false; + switch (header->filetype()) { + case MH_EXECUTE: + case MH_DYLIB: + case MH_BUNDLE: + case MH_DYLINKER: + case MH_OBJECT: + return true; + } + return false; +} + template UnwindPrinter::UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool showFunctionNames) : fHeader(NULL), fLength(fileLength), fUnwindSection(NULL), @@ -737,6 +756,91 @@ void UnwindPrinter::decode(uint32_t encoding, const uint8_t* funcStart, c } #endif +template <> +void UnwindPrinter::decode(uint32_t encoding, const uint8_t* funcStart, char* str) +{ + *str = '\0'; + switch ( encoding & UNWIND_ARM_MODE_MASK ) { + case UNWIND_ARM_MODE_DWARF: + sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_ARM_DWARF_SECTION_OFFSET); + break; + case UNWIND_ARM_MODE_FRAME: + case UNWIND_ARM_MODE_FRAME_D: + switch ( encoding & UNWIND_ARM_FRAME_STACK_ADJUST_MASK ) { + case 0x00000000: + strcpy(str, "std frame: "); + break; + case 0x00400000: + strcat(str, "std frame(sp adj 4): "); + break; + case 0x00800000: + strcat(str, "std frame(sp adj 8): "); + break; + case 0x00C00000: + strcat(str, "std frame(sp adj 12): "); + break; + } + if ( encoding & UNWIND_ARM_FRAME_FIRST_PUSH_R4 ) + strcat(str, "r4 "); + if ( encoding & UNWIND_ARM_FRAME_FIRST_PUSH_R5 ) + strcat(str, "r5 "); + if ( encoding & UNWIND_ARM_FRAME_FIRST_PUSH_R6 ) + strcat(str, "r6 "); + + if ( encoding & 0x000000F8) + strcat(str, " / "); + if ( encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R8 ) + strcat(str, "r8 "); + if ( encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R9 ) + strcat(str, "r9 "); + if ( encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R10 ) + strcat(str, "r10 "); + if ( encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R11 ) + strcat(str, "r11 "); + if ( encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R12 ) + strcat(str, "r12 "); + + if ( (encoding & UNWIND_ARM_MODE_MASK) == UNWIND_ARM_MODE_FRAME_D ) { + switch ( encoding & UNWIND_ARM_FRAME_D_REG_COUNT_MASK ) { + case 0x00000000: + strcat(str, " / d8 "); + break; + case 0x00000100: + strcat(str, " / d8,d10 "); + break; + case 0x00000200: + strcat(str, " / d8,d10,d12 "); + break; + case 0x00000300: + strcat(str, " / d8,d10,d12,d14 "); + break; + case 0x00000400: + strcat(str, " / d12,d14 / d8,d9,d10 "); + break; + case 0x00000500: + strcat(str, " / d14 / d8,d9,d10,d11,d12"); + break; + case 0x00000600: + strcat(str, " / d8,d9,d10,d11,d12,d13,d14 "); + break; + case 0x00000700: + strcat(str, " / d8,d9,d10,d11,d12,d13,d14 "); + break; + default: + strcat(str, " / unknown D register usage "); + break; + } + } + + break; + default: + if ( encoding == 0 ) + strcpy(str, "no unwind information"); + else + strcpy(str, "unsupported compact unwind"); + break; + } +} template <> @@ -768,6 +872,14 @@ const char* UnwindPrinter::personalityName(const macho_relocation_info +const char* UnwindPrinter::personalityName(const macho_relocation_info* reloc) +{ + //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section"); + //assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section"); + const macho_nlist

& sym = fSymbols[reloc->r_symbolnum()]; + return &fStrings[sym.n_strx()]; +} template bool UnwindPrinter::hasExernReloc(uint64_t sectionOffset, const char** personalityStr, pint_t* addr) @@ -1004,6 +1116,12 @@ static void dump(const char* path, const std::set& onlyArchs, bool s throw "in universal file, arm64 slice does not contain arm64 mach-o"; break; #endif + case CPU_TYPE_ARM: + if ( UnwindPrinter::validFile(p + offset) ) + UnwindPrinter::make(p + offset, size, path, showFunctionNames); + else + throw "in universal file, arm slice does not contain arm mach-o"; + break; default: throwf("in universal file, unknown architecture slice 0x%x\n", cputype); } @@ -1021,6 +1139,9 @@ static void dump(const char* path, const std::set& onlyArchs, bool s UnwindPrinter::make(p, length, path, showFunctionNames); } #endif + else if ( UnwindPrinter::validFile(p) && onlyArchs.count(CPU_TYPE_ARM) ) { + UnwindPrinter::make(p, length, path, showFunctionNames); + } else { throw "not a known file type"; } @@ -1051,6 +1172,8 @@ int main(int argc, const char* argv[]) else if ( strcmp(arch, "arm64") == 0 ) onlyArchs.insert(CPU_TYPE_ARM64); #endif + else if ( strcmp(arch, "armv7k") == 0 ) + onlyArchs.insert(CPU_TYPE_ARM); else throwf("unknown architecture %s", arch); } -- 2.45.2