From: Apple Date: Tue, 3 Jan 2012 22:27:18 +0000 (+0000) Subject: ld64-128.2.tar.gz X-Git-Tag: developer-tools-43^0 X-Git-Url: https://git.saurik.com/apple/ld64.git/commitdiff_plain/b2fa67a80bc53211e4d1ea81f23e9f953ee1dd6c?ds=sidebyside;hp=afe874b1634377ecb27057ee76deb04915bb34d7 ld64-128.2.tar.gz --- diff --git a/ChangeLog b/ChangeLog index fd449c8..0514d7f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,88 @@ +-------- tagged ld64-128.1 + +2011-09-13 Nick Kledzik + + Enable dyld to be put into the dyld shared cache + +2011-09-13 Nick Kledzik + + Fix "using ld_classic" warning for i386 kexts + +2011-09-13 Nick Kledzik + + LTO many have eliminated need for some undefines + +-------- tagged ld64-128 + +2011-09-08 Nick Kledzik + + Rework 8924157 fix to sort all sections + +2011-09-07 Nick Kledzik + + ER: -current_version should allow 64-bit a.b.c.d.e tuple + +2011-09-06 Nick Kledzik + + -mdynamic-no-pic broke with movw of weak thumb symbol + +2011-09-01 Nick Kledzik + + Turn crash into a warning if __dso_handle is defined in user code + Added test case: unit-tests/test-cases/dso_handle + +2011-08-31 Nick Kledzik + + Add -fatal_warnings + +2011-08-30 Nick Kledzik + + Support .weak_def_can_be_hidden via LTO interface + +2011-08-29 Nick Kledzik + + improve performance of zerofill->data ordering + +2011-08-29 Nick Kledzik + + Implement -print_statistics + +2011-08-25 Nick Kledzik + + check for overlaps between pinned segments and regular segments + +2011-08-23 Nick Kledzik + + do got elimination more aggressively in static and preload mode + +2011-08-22 Nick Kledzik + + enable __dso_handle in -preload + +2011-08-22 Nick Kledzik + + fix section$end to sort to end of __mod_init_func section + +2011-08-18 Nick Kledzik + + __constructor section removed with -dead_strip + +2011-08-11 Nick Kledzik + + remove ld support for PowerPC + +2011-08-11 Nick Kledzik + + Fix spurious -segaddr alignment warning + +-------- tagged ld64-127.3 + +2011-08-31 Nick Kledzik + + [regression] C++ Initializers from archives not sorted + Added test case: unit-tests/test-cases/archive-init-order + -------- tagged ld64-127.2 2011-08-15 Nick Kledzik diff --git a/doc/man/man1/ld.1 b/doc/man/man1/ld.1 index 03f257a..dc2a501 100644 --- a/doc/man/man1/ld.1 +++ b/doc/man/man1/ld.1 @@ -515,6 +515,8 @@ Prints the version of the linker. Normally i386 main executables will be marked so that the Mac OS X 10.7 and later kernel will only allow pages with the x-bit to execute instructions. This option overrides that behavior and allows instructions on any page to be executed. +.It Fl fatal_warnings +Causes the linker to exit with a non-zero value if any warnings were emitted. .It Fl no_eh_labels Normally in -r mode, the linker produces .eh labels on all FDEs in the __eh_frame section. This option suppresses those labels. Those labels are not needed by the Mac OS X 10.6 @@ -576,7 +578,7 @@ Specifies the minimum space for future expansion of the load commands. Only use install_name_tool to alter the load commands later. Size is a hexadecimal number. .It Fl headerpad_max_install_names Automatically adds space for future expansion of load commands such that all paths could expand to MAXPATHLEN. -Only useful if intend to run install_name_tool to alter the load commands later. Size is a hexadecimal number. +Only useful if intend to run install_name_tool to alter the load commands later. .It Fl bind_at_load Sets a bit in the mach header of the resulting binary which tells dyld to bind all symbols when the binary is loaded, rather than lazily. .It Fl force_flat_namespace diff --git a/ld64.xcodeproj/project.pbxproj b/ld64.xcodeproj/project.pbxproj index ad73394..65f20a7 100644 --- a/ld64.xcodeproj/project.pbxproj +++ b/ld64.xcodeproj/project.pbxproj @@ -49,7 +49,7 @@ F97F5029070D0BB200B9FCD7 /* ld.1 in copy man page */ = {isa = PBXBuildFile; fileRef = F97F5028070D0BB200B9FCD7 /* ld.1 */; }; F98498A310AE2159009E9878 /* compact_unwind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9BA963310A2545C0097A440 /* compact_unwind.cpp */; }; F98498A410AE2159009E9878 /* got.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AB1063107D380700E54C9E /* got.cpp */; }; - F9849E3610B38EF5009E9878 /* order_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9849E3410B38EF5009E9878 /* order_file.cpp */; }; + F9849E3610B38EF5009E9878 /* order.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9849E3410B38EF5009E9878 /* order.cpp */; }; F984A38210BB4B0D009E9878 /* branch_island.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F984A38010BB4B0D009E9878 /* branch_island.cpp */; }; F989D30D106826020014B60C /* OutputFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F989D30B106826020014B60C /* OutputFile.cpp */; }; F9A3DDD30ED762E400C590B9 /* PruneTrie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9A3DDD20ED762E400C590B9 /* PruneTrie.cpp */; }; @@ -251,9 +251,8 @@ F971EED306D5ACF60041D381 /* ObjectDump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ObjectDump; sourceTree = BUILT_PRODUCTS_DIR; }; F971EED706D5AD240041D381 /* ObjectDump.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ObjectDump.cpp; path = src/other/ObjectDump.cpp; sourceTree = ""; }; F97F5028070D0BB200B9FCD7 /* ld.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = ld.1; path = doc/man/man1/ld.1; sourceTree = ""; }; - F984963310AB9318009E9878 /* stub_ppc_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_ppc_classic.hpp; sourceTree = ""; }; - F9849E3410B38EF5009E9878 /* order_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = order_file.cpp; sourceTree = ""; }; - F9849E3510B38EF5009E9878 /* order_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = order_file.h; sourceTree = ""; }; + F9849E3410B38EF5009E9878 /* order.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = order.cpp; sourceTree = ""; }; + F9849E3510B38EF5009E9878 /* order.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = order.h; sourceTree = ""; }; F984A13B10B614CF009E9878 /* stub_arm_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_arm_classic.hpp; sourceTree = ""; }; F984A38010BB4B0D009E9878 /* branch_island.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = branch_island.cpp; sourceTree = ""; }; F984A38110BB4B0D009E9878 /* branch_island.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = branch_island.h; sourceTree = ""; }; @@ -399,8 +398,8 @@ F984A38110BB4B0D009E9878 /* branch_island.h */, F9AA44DA1294885F00CB8390 /* branch_shim.cpp */, F9AA44DB1294885F00CB8390 /* branch_shim.h */, - F9849E3410B38EF5009E9878 /* order_file.cpp */, - F9849E3510B38EF5009E9878 /* order_file.h */, + F9849E3410B38EF5009E9878 /* order.cpp */, + F9849E3510B38EF5009E9878 /* order.h */, F9BA963310A2545C0097A440 /* compact_unwind.cpp */, F9BA963410A2545C0097A440 /* compact_unwind.h */, F9AA67B410570C41003E3539 /* dtrace_dof.h */, @@ -432,7 +431,6 @@ F9BA8A7E1096150F0097A440 /* stub_x86_classic.hpp */, F989D0391062E6350014B60C /* stub_x86_64.hpp */, F92D9C2710657AAB00FF369B /* stub_x86_64_classic.hpp */, - F984963310AB9318009E9878 /* stub_ppc_classic.hpp */, ); path = stubs; sourceTree = ""; @@ -702,7 +700,7 @@ ); runOnlyForDeploymentPostprocessing = 1; shellPath = /bin/sh; - shellScript = "\nif [ -n \"${RC_PURPLE}\" ]; then\n\techo \"here\"\n\tmkdir -p ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer/\n\tmv ${DSTROOT}/usr ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer\nfi\n"; + shellScript = "\nif [ -n \"${DT_TOOLCHAIN_DIR}\" ]\nthen\n\tmkdir -p \"${DSTROOT}/${DT_TOOLCHAIN_DIR}\"\n\tmv ${DSTROOT}/usr \"${DSTROOT}/${DT_TOOLCHAIN_DIR}\"\nelse\n\tif [ -n \"${RC_PURPLE}\" ]\n\tthen\n\t\tmkdir -p ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer/\n\t\tmv ${DSTROOT}/usr ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer\n\tfi\nfi\n\n"; showEnvVarsInLog = 0; }; F9E8DB4D11921594007B4D6A /* make config.h */ = { @@ -745,7 +743,7 @@ F98498A310AE2159009E9878 /* compact_unwind.cpp in Sources */, F98498A410AE2159009E9878 /* got.cpp in Sources */, F9BA955E10A233000097A440 /* huge.cpp in Sources */, - F9849E3610B38EF5009E9878 /* order_file.cpp in Sources */, + F9849E3610B38EF5009E9878 /* order.cpp in Sources */, F984A38210BB4B0D009E9878 /* branch_island.cpp in Sources */, F9A4DB9110F816FF00BD8423 /* objc.cpp in Sources */, F9AE20FF1107D1440007ED5D /* dylibs.cpp in Sources */, @@ -873,7 +871,7 @@ ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)"; - DEAD_CODE_STRIPPING = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; GCC_DYNAMIC_NO_PIC = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; @@ -928,6 +926,7 @@ ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)"; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_DYNAMIC_NO_PIC = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; @@ -1106,6 +1105,7 @@ ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)"; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_DYNAMIC_NO_PIC = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; diff --git a/src/abstraction/MachOFileAbstraction.hpp b/src/abstraction/MachOFileAbstraction.hpp index f5f073b..f4d136f 100644 --- a/src/abstraction/MachOFileAbstraction.hpp +++ b/src/abstraction/MachOFileAbstraction.hpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -1279,8 +1278,13 @@ public: uint32_t version() const INLINE { return fields.version; } void set_version(uint32_t value) INLINE { E::set32(fields.version, value); } - uint32_t reserved() const INLINE { return fields.reserved; } - void set_reserved(uint32_t value) INLINE { E::set32(fields.reserved, value); } +#ifdef LC_SOURCE_VERSION + uint32_t sdk() const INLINE { return fields.sdk; } + void set_sdk(uint32_t value) INLINE { E::set32(fields.sdk, value); } +#else + uint32_t sdk() const INLINE { return fields.reserved; } + void set_sdk(uint32_t value) INLINE { E::set32(fields.reserved, value); } +#endif typedef typename P::E E; private: diff --git a/src/ld/HeaderAndLoadCommands.hpp b/src/ld/HeaderAndLoadCommands.hpp index 395fc99..903a2bf 100644 --- a/src/ld/HeaderAndLoadCommands.hpp +++ b/src/ld/HeaderAndLoadCommands.hpp @@ -519,33 +519,15 @@ uint32_t HeaderAndLoadCommandsAtom::flags() const return bits; } -template <> uint32_t HeaderAndLoadCommandsAtom::magic() const { return MH_MAGIC; } -template <> uint32_t HeaderAndLoadCommandsAtom::magic() const { return MH_MAGIC_64; } template <> uint32_t HeaderAndLoadCommandsAtom::magic() const { return MH_MAGIC; } template <> uint32_t HeaderAndLoadCommandsAtom::magic() const { return MH_MAGIC_64; } template <> uint32_t HeaderAndLoadCommandsAtom::magic() const { return MH_MAGIC; } -template <> uint32_t HeaderAndLoadCommandsAtom::cpuType() const { return CPU_TYPE_POWERPC; } -template <> uint32_t HeaderAndLoadCommandsAtom::cpuType() const { return CPU_TYPE_POWERPC64; } template <> uint32_t HeaderAndLoadCommandsAtom::cpuType() const { return CPU_TYPE_I386; } template <> uint32_t HeaderAndLoadCommandsAtom::cpuType() const { return CPU_TYPE_X86_64; } template <> uint32_t HeaderAndLoadCommandsAtom::cpuType() const { return CPU_TYPE_ARM; } -template <> -uint32_t HeaderAndLoadCommandsAtom::cpuSubType() const -{ - return _state.cpuSubType; -} - -template <> -uint32_t HeaderAndLoadCommandsAtom::cpuSubType() const -{ - if ( (_options.outputKind() == Options::kDynamicExecutable) && (_options.macosxVersionMin() >= ld::mac10_5) ) - return (CPU_SUBTYPE_POWERPC_ALL | 0x80000000); - else - return CPU_SUBTYPE_POWERPC_ALL; -} template <> uint32_t HeaderAndLoadCommandsAtom::cpuSubType() const @@ -973,7 +955,7 @@ uint8_t* HeaderAndLoadCommandsAtom::copyDylibIDLoadCommand(uint8_t* p) const cmd->set_cmdsize(sz); cmd->set_name_offset(); cmd->set_timestamp(1); // needs to be some constant value that is different than DylibLoadCommandsAtom uses - cmd->set_current_version(_options.currentVersion()); + cmd->set_current_version(_options.currentVersion32()); cmd->set_compatibility_version(_options.compatibilityVersion()); strcpy((char*)&p[sizeof(macho_dylib_command

)], _options.installPath()); return p + sz; @@ -1024,62 +1006,18 @@ uint8_t* HeaderAndLoadCommandsAtom::copyVersionLoadCommand(uint8_t* p) const cmd->set_cmd(LC_VERSION_MIN_MACOSX); cmd->set_cmdsize(sizeof(macho_version_min_command

)); cmd->set_version((uint32_t)macVersion); - cmd->set_reserved(0); + cmd->set_sdk(0); } else { cmd->set_cmd(LC_VERSION_MIN_IPHONEOS); cmd->set_cmdsize(sizeof(macho_version_min_command

)); cmd->set_version((uint32_t)iOSVersion); - cmd->set_reserved(0); + cmd->set_sdk(0); } return p + sizeof(macho_version_min_command

); } -template <> -uint32_t HeaderAndLoadCommandsAtom::threadLoadCommandSize() const -{ - return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4 -} - - -template <> -uint8_t* HeaderAndLoadCommandsAtom::copyThreadsLoadCommand(uint8_t* p) const -{ - assert(_state.entryPoint != NULL); - pint_t start = _state.entryPoint->finalAddress(); - macho_thread_command* cmd = (macho_thread_command*)p; - cmd->set_cmd(LC_UNIXTHREAD); - cmd->set_cmdsize(threadLoadCommandSize()); - cmd->set_flavor(1); // PPC_THREAD_STATE - cmd->set_count(40); // PPC_THREAD_STATE_COUNT; - cmd->set_thread_register(0, start); - if ( _options.hasCustomStack() ) - cmd->set_thread_register(3, _options.customStackAddr()); // r1 - return p + threadLoadCommandSize(); -} - -template <> -uint32_t HeaderAndLoadCommandsAtom::threadLoadCommandSize() const -{ - return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4 -} - -template <> -uint8_t* HeaderAndLoadCommandsAtom::copyThreadsLoadCommand(uint8_t* p) const -{ - assert(_state.entryPoint != NULL); - pint_t start = _state.entryPoint->finalAddress(); - macho_thread_command* cmd = (macho_thread_command*)p; - cmd->set_cmd(LC_UNIXTHREAD); - cmd->set_cmdsize(threadLoadCommandSize()); - cmd->set_flavor(5); // PPC_THREAD_STATE64 - cmd->set_count(76); // PPC_THREAD_STATE64_COUNT; - cmd->set_thread_register(0, start); - if ( _options.hasCustomStack() ) - cmd->set_thread_register(3, _options.customStackAddr()); // r1 - return p + threadLoadCommandSize(); -} template <> uint32_t HeaderAndLoadCommandsAtom::threadLoadCommandSize() const diff --git a/src/ld/InputFiles.cpp b/src/ld/InputFiles.cpp index 84a2297..7b05a96 100644 --- a/src/ld/InputFiles.cpp +++ b/src/ld/InputFiles.cpp @@ -627,12 +627,8 @@ void InputFiles::inferArchitecture(Options& opts, const char** archName) // no thin .o files found, so default to same architecture this tool was built as warning("-arch not specified"); -#if __ppc__ - opts.setArchitecture(CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL); -#elif __i386__ +#if __i386__ opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL); -#elif __ppc64__ - opts.setArchitecture(CPU_TYPE_POWERPC64, CPU_SUBTYPE_POWERPC_ALL); #elif __x86_64__ opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL); #elif __arm__ @@ -811,6 +807,7 @@ bool InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) const case Options::kPreload: // add implicit __mh_preload_header label handler.doAtom(DSOHandleAtom::_s_atomPreload); + handler.doAtom(DSOHandleAtom::_s_atomAll); break; case Options::kObjectFile: handler.doAtom(DSOHandleAtom::_s_atomObjectFile); diff --git a/src/ld/LinkEdit.hpp b/src/ld/LinkEdit.hpp index bf9026b..7bca2e3 100644 --- a/src/ld/LinkEdit.hpp +++ b/src/ld/LinkEdit.hpp @@ -1063,7 +1063,6 @@ private: mutable std::vector _32bitPointerLocations; mutable std::vector _64bitPointerLocations; - mutable std::vector _ppcHi16Locations; mutable std::vector _thumbLo16Locations; mutable std::vector _thumbHi16Locations[16]; mutable std::vector _armLo16Locations; @@ -1146,36 +1145,6 @@ void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind ki } -template <> -void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const -{ - switch (kind) { - case ld::Fixup::kindStorePPCPicHigh16AddLow: - _ppcHi16Locations.push_back(address); - break; - case ld::Fixup::kindStoreBigEndian32: - _32bitPointerLocations.push_back(address); - break; - default: - warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address); - break; - } -} - - -template <> -void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const -{ - switch (kind) { - case ld::Fixup::kindStorePPCPicHigh16AddLow: - _ppcHi16Locations.push_back(address); - break; - default: - warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address); - break; - } -} - template void SplitSegInfoAtom::uleb128EncodeAddresses(const std::vector& locations) const @@ -1231,14 +1200,6 @@ void SplitSegInfoAtom::encode() const this->_encodedData.append_byte(0); // terminator } - if ( _ppcHi16Locations.size() != 0 ) { - this->_encodedData.append_byte(3); - //fprintf(stderr, "type 3:\n"); - std::sort(_ppcHi16Locations.begin(), _ppcHi16Locations.end()); - this->uleb128EncodeAddresses(_ppcHi16Locations); - this->_encodedData.append_byte(0); // terminator - } - if ( _thumbLo16Locations.size() != 0 ) { this->_encodedData.append_byte(5); //fprintf(stderr, "type 5:\n"); @@ -1286,7 +1247,6 @@ void SplitSegInfoAtom::encode() const // clean up temporaries _32bitPointerLocations.clear(); _64bitPointerLocations.clear(); - _ppcHi16Locations.clear(); } diff --git a/src/ld/LinkEditClassic.hpp b/src/ld/LinkEditClassic.hpp index 1429d95..7fbc755 100644 --- a/src/ld/LinkEditClassic.hpp +++ b/src/ld/LinkEditClassic.hpp @@ -798,52 +798,6 @@ void LocalRelocationsAtom::addPointerReloc(uint64_t addr, uint32_t symNum) template void LocalRelocationsAtom::addTextReloc(uint64_t addr, ld::Fixup::Kind kind, uint64_t targetAddr, uint32_t symNum) { - macho_relocation_info

reloc1; - macho_relocation_info

reloc2; - switch ( kind ) { - case ld::Fixup::kindStorePPCAbsLow14: - case ld::Fixup::kindStorePPCAbsLow16: - // a reference to the absolute address of something in this same linkage unit can be - // encoded as a local text reloc in a dylib or bundle - if ( _options.outputSlidable() ) { - reloc1.set_r_address(addr); - reloc1.set_r_symbolnum(symNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(2); - reloc1.set_r_extern(false); - reloc1.set_r_type(kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14); - reloc2.set_r_address(targetAddr >> 16); - reloc2.set_r_symbolnum(0); - reloc2.set_r_pcrel(false); - reloc2.set_r_length(2); - reloc2.set_r_extern(false); - reloc2.set_r_type(PPC_RELOC_PAIR); - _relocs.push_back(reloc1); - _relocs.push_back(reloc2); - } - break; - case ld::Fixup::kindStorePPCAbsHigh16AddLow: - case ld::Fixup::kindStorePPCAbsHigh16: - if ( _options.outputSlidable() ) { - reloc1.set_r_address(addr); - reloc1.set_r_symbolnum(symNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(2); - reloc1.set_r_extern(false); - reloc1.set_r_type(kind==ld::Fixup::kindStorePPCAbsHigh16AddLow ? PPC_RELOC_HA16 : PPC_RELOC_HI16); - reloc2.set_r_address(targetAddr & 0xFFFF); - reloc2.set_r_symbolnum(0); - reloc2.set_r_pcrel(false); - reloc2.set_r_length(2); - reloc2.set_r_extern(false); - reloc2.set_r_type(PPC_RELOC_PAIR); - _relocs.push_back(reloc1); - _relocs.push_back(reloc2); - } - break; - default: - break; - } } @@ -967,9 +921,7 @@ uint64_t ExternalRelocationsAtom::size() const template <> uint32_t ExternalRelocationsAtom::pointerReloc() { return ARM_RELOC_VANILLA; } template <> uint32_t ExternalRelocationsAtom::pointerReloc() { return GENERIC_RELOC_VANILLA; } -template <> uint32_t ExternalRelocationsAtom::pointerReloc() { return PPC_RELOC_VANILLA; } template <> uint32_t ExternalRelocationsAtom::pointerReloc() { return X86_64_RELOC_UNSIGNED; } -template <> uint32_t ExternalRelocationsAtom::pointerReloc() { return PPC_RELOC_VANILLA; } template <> uint32_t ExternalRelocationsAtom::callReloc() { return X86_64_RELOC_BRANCH; } @@ -1664,582 +1616,6 @@ void SectionRelocationsAtom::encodeSectionReloc(ld::Internal::FinalSection* } -template <> -void SectionRelocationsAtom::encodeSectionReloc(ld::Internal::FinalSection* sect, - const Entry& entry, std::vector >& relocs) -{ - macho_relocation_info

reloc1; - macho_relocation_info

reloc2; - macho_scattered_relocation_info

* sreloc1 = (macho_scattered_relocation_info

*)&reloc1; - macho_scattered_relocation_info

* sreloc2 = (macho_scattered_relocation_info

*)&reloc2; - uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address; - bool external = entry.toTargetUsesExternalReloc; - uint32_t symbolNum = sectSymNum(external, entry.toTarget); - bool fromExternal = false; - uint32_t fromSymbolNum = 0; - if ( entry.fromTarget != NULL ) { - fromExternal = entry.fromTargetUsesExternalReloc; - fromSymbolNum= sectSymNum(fromExternal, entry.fromTarget); - } - uint32_t toAddr; - uint32_t fromAddr; - - switch ( entry.kind ) { - - case ld::Fixup::kindStorePPCBranch24: - case ld::Fixup::kindStoreTargetAddressPPCBranch24: - case ld::Fixup::kindStorePPCDtraceCallSiteNop: - case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear: - if ( !external && (entry.toAddend != 0) ) { - // use scattered reloc if target offset is non-zero - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(true); - sreloc1->set_r_length(2); - sreloc1->set_r_type(PPC_RELOC_BR24); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - } - else { - reloc1.set_r_address(address); - reloc1.set_r_symbolnum(symbolNum); - reloc1.set_r_pcrel(true); - reloc1.set_r_length(2); - reloc1.set_r_extern(external); - reloc1.set_r_type(PPC_RELOC_BR24); - } - relocs.push_back(reloc1); - break; - - case ld::Fixup::kindStorePPCBranch14: - if ( !external && (entry.toAddend != 0) ) { - // use scattered reloc if target offset is non-zero - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(true); - sreloc1->set_r_length(2); - sreloc1->set_r_type(PPC_RELOC_BR14); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - } - else { - reloc1.set_r_address(address); - reloc1.set_r_symbolnum(symbolNum); - reloc1.set_r_pcrel(true); - reloc1.set_r_length(2); - reloc1.set_r_extern(external); - reloc1.set_r_type(PPC_RELOC_BR14); - } - relocs.push_back(reloc1); - break; - - case ld::Fixup::kindStoreBigEndian32: - case ld::Fixup::kindStoreTargetAddressBigEndian32: - if ( entry.fromTarget != NULL ) { - // this is a pointer-diff - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit ) - sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF); - else - sreloc1->set_r_type(PPC_RELOC_SECTDIFF); - sreloc1->set_r_address(address); - if ( entry.toTarget == entry.inAtom ) - sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend); - else - sreloc1->set_r_value(entry.toTarget->finalAddress()); - sreloc2->set_r_scattered(true); - sreloc2->set_r_pcrel(false); - sreloc2->set_r_length(2); - sreloc2->set_r_type(PPC_RELOC_PAIR); - sreloc2->set_r_address(0); - if ( entry.fromTarget == entry.inAtom ) { - if ( entry.fromAddend > entry.fromTarget->size() ) - sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom); - else - sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend); - } - else - sreloc2->set_r_value(entry.fromTarget->finalAddress()); - relocs.push_back(reloc1); - relocs.push_back(reloc2); - } - else { - // regular pointer - if ( !external && (entry.toAddend != 0) ) { - // use scattered reloc is target offset is non-zero - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - sreloc1->set_r_type(GENERIC_RELOC_VANILLA); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - } - else { - reloc1.set_r_address(address); - reloc1.set_r_symbolnum(symbolNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(2); - reloc1.set_r_extern(external); - reloc1.set_r_type(GENERIC_RELOC_VANILLA); - } - relocs.push_back(reloc1); - } - break; - - case ld::Fixup::kindStorePPCAbsLow14: - case ld::Fixup::kindStorePPCAbsLow16: - if ( !external && (entry.toAddend != 0) ) { - // use scattered reloc if target offset is non-zero - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - sreloc1->set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - } - else { - reloc1.set_r_address(address); - reloc1.set_r_symbolnum(symbolNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(2); - reloc1.set_r_extern(external); - reloc1.set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14); - } - if ( external ) - reloc2.set_r_address(entry.toAddend >> 16); - else - reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) >> 16); - reloc2.set_r_symbolnum(0); - reloc2.set_r_pcrel(false); - reloc2.set_r_length(2); - reloc2.set_r_extern(false); - reloc2.set_r_type(PPC_RELOC_PAIR); - relocs.push_back(reloc1); - relocs.push_back(reloc2); - break; - - case ld::Fixup::kindStorePPCAbsHigh16: - if ( !external && (entry.toAddend != 0) ) { - // use scattered reloc if target offset is non-zero - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - sreloc1->set_r_type(PPC_RELOC_HI16); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - } - else { - reloc1.set_r_address(address); - reloc1.set_r_symbolnum(symbolNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(2); - reloc1.set_r_extern(external); - reloc1.set_r_type(PPC_RELOC_HI16); - } - if ( external ) - reloc2.set_r_address(entry.toAddend & 0x0000FFFF); - else - reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF); - reloc2.set_r_symbolnum(0); - reloc2.set_r_pcrel(false); - reloc2.set_r_length(2); - reloc2.set_r_extern(false); - reloc2.set_r_type(PPC_RELOC_PAIR); - relocs.push_back(reloc1); - relocs.push_back(reloc2); - break; - - case ld::Fixup::kindStorePPCAbsHigh16AddLow: - if ( !external && (entry.toAddend != 0) ) { - // use scattered reloc if target offset is non-zero - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - sreloc1->set_r_type(PPC_RELOC_HA16); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - } - else { - reloc1.set_r_address(address); - reloc1.set_r_symbolnum(symbolNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(2); - reloc1.set_r_extern(external); - reloc1.set_r_type(PPC_RELOC_HA16); - } - if ( external ) - reloc2.set_r_address(entry.toAddend & 0x0000FFFF); - else - reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF); - reloc2.set_r_symbolnum(0); - reloc2.set_r_pcrel(false); - reloc2.set_r_length(2); - reloc2.set_r_extern(false); - reloc2.set_r_type(PPC_RELOC_PAIR); - relocs.push_back(reloc1); - relocs.push_back(reloc2); - break; - - case ld::Fixup::kindStorePPCPicLow14: - case ld::Fixup::kindStorePPCPicLow16: - fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend; - toAddr = entry.toTarget->finalAddress() + entry.toAddend; - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - sreloc1->set_r_type(entry.kind == ld::Fixup::kindStorePPCPicLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - sreloc2->set_r_scattered(true); - sreloc2->set_r_pcrel(false); - sreloc2->set_r_length(2); - sreloc2->set_r_type(PPC_RELOC_PAIR); - sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF); - sreloc2->set_r_value(fromAddr); - relocs.push_back(reloc1); - relocs.push_back(reloc2); - break; - - case ld::Fixup::kindStorePPCPicHigh16AddLow: - fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend; - toAddr = entry.toTarget->finalAddress() + entry.toAddend; - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - sreloc2->set_r_scattered(true); - sreloc2->set_r_pcrel(false); - sreloc2->set_r_length(2); - sreloc2->set_r_type(PPC_RELOC_PAIR); - sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF); - sreloc2->set_r_value(fromAddr); - relocs.push_back(reloc1); - relocs.push_back(reloc2); - break; - - default: - assert(0 && "need to handle -r reloc"); - - } -} - -template <> -void SectionRelocationsAtom::encodeSectionReloc(ld::Internal::FinalSection* sect, - const Entry& entry, std::vector >& relocs) -{ - macho_relocation_info

reloc1; - macho_relocation_info

reloc2; - macho_scattered_relocation_info

* sreloc1 = (macho_scattered_relocation_info

*)&reloc1; - macho_scattered_relocation_info

* sreloc2 = (macho_scattered_relocation_info

*)&reloc2; - uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address; - bool external = entry.toTargetUsesExternalReloc; - uint32_t symbolNum = sectSymNum(external, entry.toTarget); - bool fromExternal = false; - uint32_t fromSymbolNum = 0; - if ( entry.fromTarget != NULL ) { - fromExternal = entry.fromTargetUsesExternalReloc; - fromSymbolNum= sectSymNum(fromExternal, entry.fromTarget); - } - uint32_t toAddr; - uint32_t fromAddr; - - switch ( entry.kind ) { - - case ld::Fixup::kindStorePPCBranch24: - case ld::Fixup::kindStoreTargetAddressPPCBranch24: - case ld::Fixup::kindStorePPCDtraceCallSiteNop: - case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear: - if ( !external && (entry.toAddend != 0) ) { - // use scattered reloc if target offset is non-zero - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(true); - sreloc1->set_r_length(2); - sreloc1->set_r_type(PPC_RELOC_BR24); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - } - else { - reloc1.set_r_address(address); - reloc1.set_r_symbolnum(symbolNum); - reloc1.set_r_pcrel(true); - reloc1.set_r_length(2); - reloc1.set_r_extern(external); - reloc1.set_r_type(PPC_RELOC_BR24); - } - relocs.push_back(reloc1); - break; - - case ld::Fixup::kindStorePPCBranch14: - if ( !external && (entry.toAddend != 0) ) { - // use scattered reloc if target offset is non-zero - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(true); - sreloc1->set_r_length(2); - sreloc1->set_r_type(PPC_RELOC_BR14); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - } - else { - reloc1.set_r_address(address); - reloc1.set_r_symbolnum(symbolNum); - reloc1.set_r_pcrel(true); - reloc1.set_r_length(2); - reloc1.set_r_extern(external); - reloc1.set_r_type(PPC_RELOC_BR14); - } - relocs.push_back(reloc1); - break; - - case ld::Fixup::kindStoreBigEndian32: - case ld::Fixup::kindStoreTargetAddressBigEndian32: - if ( entry.fromTarget != NULL ) { - // this is a pointer-diff - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit ) - sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF); - else - sreloc1->set_r_type(PPC_RELOC_SECTDIFF); - sreloc1->set_r_address(address); - if ( entry.toTarget == entry.inAtom ) - sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend); - else - sreloc1->set_r_value(entry.toTarget->finalAddress()); - sreloc2->set_r_scattered(true); - sreloc2->set_r_pcrel(false); - sreloc2->set_r_length(2); - sreloc2->set_r_type(PPC_RELOC_PAIR); - sreloc2->set_r_address(0); - if ( entry.fromTarget == entry.inAtom ) { - if ( entry.fromAddend > entry.fromTarget->size() ) - sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom); - else - sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend); - } - else - sreloc2->set_r_value(entry.fromTarget->finalAddress()); - relocs.push_back(reloc1); - relocs.push_back(reloc2); - } - else { - // regular pointer - if ( !external && (entry.toAddend != 0) ) { - // use scattered reloc is target offset is non-zero - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - sreloc1->set_r_type(GENERIC_RELOC_VANILLA); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - } - else { - reloc1.set_r_address(address); - reloc1.set_r_symbolnum(symbolNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(2); - reloc1.set_r_extern(external); - reloc1.set_r_type(GENERIC_RELOC_VANILLA); - } - relocs.push_back(reloc1); - } - break; - - case ld::Fixup::kindStoreBigEndian64: - case ld::Fixup::kindStoreTargetAddressBigEndian64: - if ( entry.fromTarget != NULL ) { - // this is a pointer-diff - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(3); - if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit ) - sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF); - else - sreloc1->set_r_type(PPC_RELOC_SECTDIFF); - sreloc1->set_r_address(address); - if ( entry.toTarget == entry.inAtom ) - sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend); - else - sreloc1->set_r_value(entry.toTarget->finalAddress()); - sreloc2->set_r_scattered(true); - sreloc2->set_r_pcrel(false); - sreloc2->set_r_length(3); - sreloc2->set_r_type(PPC_RELOC_PAIR); - sreloc2->set_r_address(0); - if ( entry.fromTarget == entry.inAtom ) { - if ( entry.fromAddend > entry.fromTarget->size() ) - sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom); - else - sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend); - } - else - sreloc2->set_r_value(entry.fromTarget->finalAddress()); - relocs.push_back(reloc1); - relocs.push_back(reloc2); - } - else { - // regular pointer - if ( !external && (entry.toAddend != 0) ) { - // use scattered reloc is target offset is non-zero - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(3); - sreloc1->set_r_type(GENERIC_RELOC_VANILLA); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - } - else { - reloc1.set_r_address(address); - reloc1.set_r_symbolnum(symbolNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(3); - reloc1.set_r_extern(external); - reloc1.set_r_type(GENERIC_RELOC_VANILLA); - } - relocs.push_back(reloc1); - } - break; - - case ld::Fixup::kindStorePPCAbsLow14: - case ld::Fixup::kindStorePPCAbsLow16: - if ( !external && (entry.toAddend != 0) ) { - // use scattered reloc if target offset is non-zero - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - sreloc1->set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - } - else { - reloc1.set_r_address(address); - reloc1.set_r_symbolnum(symbolNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(2); - reloc1.set_r_extern(external); - reloc1.set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14); - } - if ( external ) - reloc2.set_r_address(entry.toAddend >> 16); - else - reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) >> 16); - reloc2.set_r_symbolnum(0); - reloc2.set_r_pcrel(false); - reloc2.set_r_length(2); - reloc2.set_r_extern(false); - reloc2.set_r_type(PPC_RELOC_PAIR); - relocs.push_back(reloc1); - relocs.push_back(reloc2); - break; - - case ld::Fixup::kindStorePPCAbsHigh16: - if ( !external && (entry.toAddend != 0) ) { - // use scattered reloc if target offset is non-zero - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - sreloc1->set_r_type(PPC_RELOC_HI16); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - } - else { - reloc1.set_r_address(address); - reloc1.set_r_symbolnum(symbolNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(2); - reloc1.set_r_extern(external); - reloc1.set_r_type(PPC_RELOC_HI16); - } - if ( external ) - reloc2.set_r_address(entry.toAddend & 0x0000FFFF); - else - reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF); - reloc2.set_r_symbolnum(0); - reloc2.set_r_pcrel(false); - reloc2.set_r_length(2); - reloc2.set_r_extern(false); - reloc2.set_r_type(PPC_RELOC_PAIR); - relocs.push_back(reloc1); - relocs.push_back(reloc2); - break; - - case ld::Fixup::kindStorePPCAbsHigh16AddLow: - if ( !external && (entry.toAddend != 0) ) { - // use scattered reloc if target offset is non-zero - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - sreloc1->set_r_type(PPC_RELOC_HA16); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - } - else { - reloc1.set_r_address(address); - reloc1.set_r_symbolnum(symbolNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(2); - reloc1.set_r_extern(external); - reloc1.set_r_type(PPC_RELOC_HA16); - } - if ( external ) - reloc2.set_r_address(entry.toAddend & 0x0000FFFF); - else - reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF); - reloc2.set_r_symbolnum(0); - reloc2.set_r_pcrel(false); - reloc2.set_r_length(2); - reloc2.set_r_extern(false); - reloc2.set_r_type(PPC_RELOC_PAIR); - relocs.push_back(reloc1); - relocs.push_back(reloc2); - break; - - case ld::Fixup::kindStorePPCPicLow14: - case ld::Fixup::kindStorePPCPicLow16: - fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend; - toAddr = entry.toTarget->finalAddress() + entry.toAddend; - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - sreloc1->set_r_type(entry.kind == ld::Fixup::kindStorePPCPicLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - sreloc2->set_r_scattered(true); - sreloc2->set_r_pcrel(false); - sreloc2->set_r_length(2); - sreloc2->set_r_type(PPC_RELOC_PAIR); - sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF); - sreloc2->set_r_value(fromAddr); - relocs.push_back(reloc1); - relocs.push_back(reloc2); - break; - - case ld::Fixup::kindStorePPCPicHigh16AddLow: - fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend; - toAddr = entry.toTarget->finalAddress() + entry.toAddend; - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF); - sreloc1->set_r_address(address); - sreloc1->set_r_value(entry.toTarget->finalAddress()); - sreloc2->set_r_scattered(true); - sreloc2->set_r_pcrel(false); - sreloc2->set_r_length(2); - sreloc2->set_r_type(PPC_RELOC_PAIR); - sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF); - sreloc2->set_r_value(fromAddr); - relocs.push_back(reloc1); - relocs.push_back(reloc2); - break; - - default: - assert(0 && "need to handle -r reloc"); - - } -} template void SectionRelocationsAtom::addSectionReloc(ld::Internal::FinalSection* sect, ld::Fixup::Kind kind, diff --git a/src/ld/Options.cpp b/src/ld/Options.cpp index 3f5b054..629903f 100644 --- a/src/ld/Options.cpp +++ b/src/ld/Options.cpp @@ -48,11 +48,14 @@ static char crashreporterBuffer[crashreporterBufferSize]; char* __crashreporter_info__ = crashreporterBuffer; static bool sEmitWarnings = true; +static bool sFatalWarnings = false; static const char* sWarningsSideFilePath = NULL; static FILE* sWarningsSideFile = NULL; +static int sWarningsCount = 0; void warning(const char* format, ...) { + ++sWarningsCount; if ( sEmitWarnings ) { va_list list; if ( sWarningsSideFilePath != NULL ) { @@ -146,6 +149,10 @@ Options::~Options() } +bool Options::errorBecauseOfWarnings() const +{ + return (sFatalWarnings && (sWarningsCount > 0)); +} const char* Options::installPath() const @@ -475,50 +482,6 @@ void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype) fArchitecture = type; fSubArchitecture = subtype; switch ( type ) { - case CPU_TYPE_POWERPC: - switch ( subtype ) { - case CPU_SUBTYPE_POWERPC_750: - fArchitectureName = "ppc750"; - fHasPreferredSubType = true; - break; - case CPU_SUBTYPE_POWERPC_7400: - fArchitectureName = "ppc7400"; - fHasPreferredSubType = true; - break; - case CPU_SUBTYPE_POWERPC_7450: - fArchitectureName = "ppc7450"; - fHasPreferredSubType = true; - break; - case CPU_SUBTYPE_POWERPC_970: - fArchitectureName = "ppc970"; - fHasPreferredSubType = true; - break; - case CPU_SUBTYPE_POWERPC_ALL: - fArchitectureName = "ppc"; - fHasPreferredSubType = false; - break; - default: - assert(0 && "unknown ppc subtype"); - fArchitectureName = "ppc"; - break; - } - if ( (fMacVersionMin == ld::macVersionUnset) && (fOutputKind != Options::kObjectFile) ) { - #ifdef DEFAULT_MACOSX_MIN_VERSION - warning("-macosx_version_min not specificed, assuming " DEFAULT_MACOSX_MIN_VERSION); - setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION); - #else - warning("-macosx_version_min not specificed, assuming 10.6"); - fMacVersionMin = ld::mac10_6; - #endif - } - break; - case CPU_TYPE_POWERPC64: - fArchitectureName = "ppc64"; - if ( (fMacVersionMin == ld::macVersionUnset) && (fOutputKind != Options::kObjectFile) ) { - warning("-macosx_version_min not specificed, assuming 10.5"); - fMacVersionMin = ld::mac10_5; - } - break; case CPU_TYPE_I386: fArchitectureName = "i386"; if ( (fMacVersionMin == ld::macVersionUnset) && (fOutputKind != Options::kObjectFile) ) { @@ -583,15 +546,7 @@ void Options::parseArch(const char* arch) if ( arch == NULL ) throw "-arch must be followed by an architecture string"; fArchitectureName = arch; - if ( strcmp(arch, "ppc") == 0 ) { - fArchitecture = CPU_TYPE_POWERPC; - fSubArchitecture = CPU_SUBTYPE_POWERPC_ALL; - } - else if ( strcmp(arch, "ppc64") == 0 ) { - fArchitecture = CPU_TYPE_POWERPC64; - fSubArchitecture = CPU_SUBTYPE_POWERPC_ALL; - } - else if ( strcmp(arch, "i386") == 0 ) { + if ( strcmp(arch, "i386") == 0 ) { fArchitecture = CPU_TYPE_I386; fSubArchitecture = CPU_SUBTYPE_I386_ALL; } @@ -603,27 +558,6 @@ void Options::parseArch(const char* arch) fArchitecture = CPU_TYPE_ARM; fSubArchitecture = CPU_SUBTYPE_ARM_ALL; } - // compatibility support for cpu-sub-types - else if ( strcmp(arch, "ppc750") == 0 ) { - fArchitecture = CPU_TYPE_POWERPC; - fSubArchitecture = CPU_SUBTYPE_POWERPC_750; - fHasPreferredSubType = true; - } - else if ( strcmp(arch, "ppc7400") == 0 ) { - fArchitecture = CPU_TYPE_POWERPC; - fSubArchitecture = CPU_SUBTYPE_POWERPC_7400; - fHasPreferredSubType = true; - } - else if ( strcmp(arch, "ppc7450") == 0 ) { - fArchitecture = CPU_TYPE_POWERPC; - fSubArchitecture = CPU_SUBTYPE_POWERPC_7450; - fHasPreferredSubType = true; - } - else if ( strcmp(arch, "ppc970") == 0 ) { - fArchitecture = CPU_TYPE_POWERPC; - fSubArchitecture = CPU_SUBTYPE_POWERPC_970; - fHasPreferredSubType = true; - } else { for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) { if ( strcmp(t->subTypeName,arch) == 0 ) { @@ -1418,16 +1352,67 @@ uint32_t Options::parseProtection(const char* prot) } +// +// Parses number of form A[.B[.B[.D[.E]]]] into a uint64_t where the bits are a24.b10.c10.d10.e10 +// +uint64_t Options::parseVersionNumber64(const char* versionString) +{ + uint64_t a = 0; + uint64_t b = 0; + uint64_t c = 0; + uint64_t d = 0; + uint64_t e = 0; + char* end; + a = strtoul(versionString, &end, 10); + if ( *end == '.' ) { + b = strtoul(&end[1], &end, 10); + if ( *end == '.' ) { + c = strtoul(&end[1], &end, 10); + if ( *end == '.' ) { + d = strtoul(&end[1], &end, 10); + if ( *end == '.' ) { + e = strtoul(&end[1], &end, 10); + } + } + } + } + if ( (*end != '\0') || (a > 0xFFFFFF) || (b > 0x3FF) || (c > 0x3FF) || (d > 0x3FF) || (e > 0x3FF) ) + throwf("malformed 64-bit a.b.c.d.e version number: %s", versionString); + + return (a << 40) | ( b << 30 ) | ( c << 20 ) | ( d << 10 ) | e; +} + + +uint32_t Options::currentVersion32() const +{ + // warn if it does not fit into 32 bit vers number + uint32_t a = (fDylibCurrentVersion >> 40) & 0xFFFF; + uint32_t b = (fDylibCurrentVersion >> 30) & 0xFF; + uint32_t c = (fDylibCurrentVersion >> 20) & 0xFF; + uint64_t rep32 = ((uint64_t)a << 40) | ((uint64_t)b << 30) | ((uint64_t)c << 20); + if ( rep32 != fDylibCurrentVersion ) { + warning("truncating -current_version to fit in 32-bit space used by old mach-o format"); + a = (fDylibCurrentVersion >> 40) & 0xFFFFFF; + if ( a > 0xFFFF ) + a = 0xFFFF; + b = (fDylibCurrentVersion >> 30) & 0x3FF; + if ( b > 0xFF ) + b = 0xFF; + c = (fDylibCurrentVersion >> 20) & 0x3FF; + if ( c > 0xFF ) + c = 0xFF; + } + return (a << 16) | ( b << 8 ) | c; +} // // Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz // -// -uint32_t Options::parseVersionNumber(const char* versionString) +uint32_t Options::parseVersionNumber32(const char* versionString) { - unsigned long x = 0; - unsigned long y = 0; - unsigned long z = 0; + uint32_t x = 0; + uint32_t y = 0; + uint32_t z = 0; char* end; x = strtoul(versionString, &end, 10); if ( *end == '.' ) { @@ -1437,7 +1422,7 @@ uint32_t Options::parseVersionNumber(const char* versionString) } } if ( (*end != '\0') || (x > 0xffff) || (y > 0xff) || (z > 0xff) ) - throwf("malformed version number: %s", versionString); + throwf("malformed 32-bit x.y.z version number: %s", versionString); return (x << 16) | ( y << 8 ) | z; } @@ -1565,18 +1550,12 @@ void Options::parseOrderFile(const char* path, bool cstring) *last = '\0'; --last; } + // if there is an architecture prefix, only use this symbol it if matches current arch if ( strncmp(symbolStart, "ppc:", 4) == 0 ) { - if ( fArchitecture == CPU_TYPE_POWERPC ) - symbolStart = &symbolStart[4]; - else - symbolStart = NULL; + symbolStart = NULL; } - // if there is an architecture prefix, only use this symbol it if matches current arch else if ( strncmp(symbolStart, "ppc64:", 6) == 0 ) { - if ( fArchitecture == CPU_TYPE_POWERPC64 ) - symbolStart = &symbolStart[6]; - else - symbolStart = NULL; + symbolStart = NULL; } else if ( strncmp(symbolStart, "i386:", 5) == 0 ) { if ( fArchitecture == CPU_TYPE_I386 ) @@ -1860,14 +1839,14 @@ void Options::parse(int argc, const char* argv[]) const char* vers = argv[++i]; if ( vers == NULL ) throw "-dylib_compatibility_version missing "; - fDylibCompatVersion = parseVersionNumber(vers); + fDylibCompatVersion = parseVersionNumber32(vers); } else if ( (strcmp(arg, "-dylib_current_version") == 0) || (strcmp(arg, "-current_version") == 0)) { const char* vers = argv[++i]; if ( vers == NULL ) throw "-dylib_current_version missing "; - fDylibCurrentVersion = parseVersionNumber(vers); + fDylibCurrentVersion = parseVersionNumber64(vers); } else if ( strcmp(arg, "-sectorder") == 0 ) { if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) ) @@ -2127,9 +2106,9 @@ void Options::parse(int argc, const char* argv[]) if ( (seg.name == NULL) || (argv[i+1] == NULL) ) throw "-segaddr missing segName Adddress"; seg.address = parseAddress(argv[++i]); - uint64_t temp = seg.address & (-4096); // page align - if ( (seg.address != temp) ) - warning("-segaddr %s not page aligned, rounding down", seg.name); + uint64_t temp = ((seg.address+fSegmentAlignment-1) & (-fSegmentAlignment)); + if ( seg.address != temp ) + warning("-segaddr %s not %lld byte aligned", seg.name, fSegmentAlignment); fCustomSegmentAddresses.push_back(seg); } // ??? Deprecate when we deprecate split-seg. @@ -2313,6 +2292,9 @@ void Options::parse(int argc, const char* argv[]) else if ( strcmp(arg, "-w") == 0 ) { // previously handled by buildSearchPaths() } + else if ( strcmp(arg, "-fatal_warnings") == 0 ) { + // previously handled by buildSearchPaths() + } else if ( strcmp(arg, "-arch_errors_fatal") == 0 ) { fErrorOnOtherArchFiles = true; } @@ -2787,6 +2769,9 @@ void Options::buildSearchPaths(int argc, const char* argv[]) else if ( strcmp(argv[i], "-w") == 0 ) { sEmitWarnings = false; } + else if ( strcmp(argv[i], "-fatal_warnings") == 0 ) { + sFatalWarnings = true; + } } int standardLibraryPathsStartIndex = libraryPaths.size(); int standardFrameworkPathsStartIndex = frameworkPaths.size(); @@ -3032,7 +3017,6 @@ void Options::reconfigureDefaults() switch ( fArchitecture ) { case CPU_TYPE_I386: case CPU_TYPE_X86_64: - case CPU_TYPE_POWERPC: if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) { #ifdef DEFAULT_MACOSX_MIN_VERSION warning("-macosx_version_min not specificed, assuming " DEFAULT_MACOSX_MIN_VERSION); @@ -3073,12 +3057,6 @@ void Options::reconfigureDefaults() fMacVersionMin = ld::mac10_4; } break; - case CPU_TYPE_POWERPC64: - if ( fMacVersionMin < ld::mac10_4 ) { - //warning("-macosx_version_min should be 10.4 or later for ppc64"); - fMacVersionMin = ld::mac10_4; - } - break; case CPU_TYPE_X86_64: if ( fMacVersionMin < ld::mac10_4 ) { //warning("-macosx_version_min should be 10.4 or later for x86_64"); @@ -3107,7 +3085,6 @@ void Options::reconfigureDefaults() break; } // else use object file - case CPU_TYPE_POWERPC: case CPU_TYPE_I386: // use .o files fOutputKind = kObjectFile; @@ -3150,9 +3127,8 @@ void Options::reconfigureDefaults() // split segs only allowed for dylibs if ( fSplitSegs ) { - // split seg only supported for ppc, i386, and arm. + // split seg only supported for i386, and arm. switch ( fArchitecture ) { - case CPU_TYPE_POWERPC: case CPU_TYPE_I386: if ( fOutputKind != Options::kDynamicLibrary ) fSplitSegs = false; @@ -3179,11 +3155,9 @@ void Options::reconfigureDefaults() // set too-large size switch ( fArchitecture ) { - case CPU_TYPE_POWERPC: case CPU_TYPE_I386: fMaxAddress = 0xFFFFFFFF; break; - case CPU_TYPE_POWERPC64: case CPU_TYPE_X86_64: break; case CPU_TYPE_ARM: @@ -3217,7 +3191,6 @@ void Options::reconfigureDefaults() // disable prebinding depending on arch and min OS version if ( fPrebind ) { switch ( fArchitecture ) { - case CPU_TYPE_POWERPC: case CPU_TYPE_I386: if ( fMacVersionMin == ld::mac10_4 ) { // in 10.4 only split seg dylibs are prebound @@ -3251,7 +3224,6 @@ void Options::reconfigureDefaults() } } break; - case CPU_TYPE_POWERPC64: case CPU_TYPE_X86_64: fPrebind = false; break; @@ -3287,17 +3259,17 @@ void Options::reconfigureDefaults() || (strncmp(this->installPath(), "/System/Library/", 16) == 0) ) fSharedRegionEligible = true; } - + else if ( fOutputKind == Options::kDyld ) { + // Enable dyld to be put into the dyld shared cache + fSharedRegionEligible = true; + } + // figure out if module table is needed for compatibility with old ld/dyld if ( fOutputKind == Options::kDynamicLibrary ) { switch ( fArchitecture ) { case CPU_TYPE_I386: if ( fIOSVersionMin != ld::iOSVersionUnset ) // simulator never needs modules break; - case CPU_TYPE_POWERPC: // 10.3 and earlier dyld requires a module table - if ( fMacVersionMin <= ld::mac10_5 ) - fNeedsModuleTable = true; - break; case CPU_TYPE_ARM: if ( fPrebind ) fNeedsModuleTable = true; // redo_prebinding requires a module table @@ -3329,8 +3301,6 @@ void Options::reconfigureDefaults() break; } break; - case CPU_TYPE_POWERPC: - case CPU_TYPE_POWERPC64: case CPU_TYPE_ARM: fAddCompactUnwindEncoding = false; fRemoveDwarfUnwindIfCompactExists = false; @@ -3402,8 +3372,6 @@ void Options::reconfigureDefaults() if ( !minOS(ld::mac10_6, ld::iOS_3_1) ) fMakeCompressedDyldInfo = false; break; - case CPU_TYPE_POWERPC: - case CPU_TYPE_POWERPC64: default: fMakeCompressedDyldInfo = false; } @@ -3629,12 +3597,10 @@ void Options::checkIllegalOptionCombinations() if ( fStackAddr != 0 ) { switch (fArchitecture) { case CPU_TYPE_I386: - case CPU_TYPE_POWERPC: case CPU_TYPE_ARM: if ( fStackAddr > 0xFFFFFFFF ) throw "-stack_addr must be < 4G for 32-bit processes"; break; - case CPU_TYPE_POWERPC64: case CPU_TYPE_X86_64: break; } @@ -3648,7 +3614,6 @@ void Options::checkIllegalOptionCombinations() if ( fStackSize != 0 ) { switch (fArchitecture) { case CPU_TYPE_I386: - case CPU_TYPE_POWERPC: if ( fStackSize > 0xFFFFFFFF ) throw "-stack_size must be < 4G for 32-bit processes"; if ( fStackAddr == 0 ) { @@ -3664,7 +3629,6 @@ void Options::checkIllegalOptionCombinations() fStackAddr = 0x2F000000; if ( fStackAddr > 0x30000000) throw "-stack_addr must be < 0x30000000 for arm"; - case CPU_TYPE_POWERPC64: case CPU_TYPE_X86_64: if ( fStackAddr == 0 ) { fStackAddr = 0x00007FFF5C000000LL; @@ -3774,7 +3738,6 @@ void Options::checkIllegalOptionCombinations() if ( fObjCABIVersion2Override ) alterObjC1ClassNamesToObjC2 = true; break; - case CPU_TYPE_POWERPC64: case CPU_TYPE_X86_64: case CPU_TYPE_ARM: alterObjC1ClassNamesToObjC2 = true; @@ -3868,18 +3831,10 @@ void Options::checkIllegalOptionCombinations() // zero page size not specified on command line, set default switch (fArchitecture) { case CPU_TYPE_I386: - case CPU_TYPE_POWERPC: case CPU_TYPE_ARM: // first 4KB for 32-bit architectures fZeroPageSize = 0x1000; break; - case CPU_TYPE_POWERPC64: - // first 4GB for ppc64 on 10.5 - if ( fMacVersionMin >= ld::mac10_5 ) - fZeroPageSize = 0x100000000ULL; - else - fZeroPageSize = 0x1000; // 10.4 dyld may not be able to handle >4GB zero page - break; case CPU_TYPE_X86_64: // first 4GB for x86_64 on all OS's fZeroPageSize = 0x100000000ULL; @@ -4053,6 +4008,7 @@ void Options::checkForClassic(int argc, const char* argv[]) // ld_classic does not understand this option, so remove it for(int j=i; j < argc; ++j) argv[j] = argv[j+1]; + warning("using ld_classic"); this->gotoClassicLinker(argc-1, argv); } else if ( strcmp(arg, "-o") == 0 ) { @@ -4070,7 +4026,6 @@ void Options::checkForClassic(int argc, const char* argv[]) if( archFound ) { switch ( fArchitecture ) { case CPU_TYPE_I386: - case CPU_TYPE_POWERPC: if ( (staticFound || kextFound) && !newLinker ) { // this environment variable will disable use of ld_classic for -static links if ( getenv("LD_NO_CLASSIC_LINKER_STATIC") == NULL ) { @@ -4082,15 +4037,16 @@ void Options::checkForClassic(int argc, const char* argv[]) } else { // work around for VSPTool - if ( staticFound ) + if ( staticFound ) { + warning("using ld_classic"); this->gotoClassicLinker(argc, argv); + } } } void Options::gotoClassicLinker(int argc, const char* argv[]) { - warning("using ld_classic"); argv[0] = "ld_classic"; // ld_classic does not support -iphoneos_version_min, so change for(int j=0; j < argc; ++j) { diff --git a/src/ld/Options.h b/src/ld/Options.h index d9becf3..5a8a7e0 100644 --- a/src/ld/Options.h +++ b/src/ld/Options.h @@ -156,7 +156,8 @@ public: bool bindAtLoad() const { return fBindAtLoad; } NameSpace nameSpace() const { return fNameSpace; } const char* installPath() const; // only for kDynamicLibrary - uint32_t currentVersion() const { return fDylibCurrentVersion; } // only for kDynamicLibrary + uint64_t currentVersion() const { return fDylibCurrentVersion; } // only for kDynamicLibrary + uint32_t currentVersion32() const; // only for kDynamicLibrary uint32_t compatibilityVersion() const { return fDylibCompatVersion; } // only for kDynamicLibrary const char* entryName() const { return fEntryName; } // only for kDynamicExecutable or kStaticExecutable const char* executablePath(); @@ -293,6 +294,7 @@ public: bool forceNotWeak(const char* symbolName) const; bool forceWeakNonWildCard(const char* symbolName) const; bool forceNotWeakNonWildcard(const char* symbolName) const; + bool errorBecauseOfWarnings() const; private: class CStringEquals @@ -335,7 +337,8 @@ private: FileInfo findFramework(const char* rootName, const char* suffix); bool checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result) const; - uint32_t parseVersionNumber(const char*); + uint64_t parseVersionNumber64(const char*); + uint32_t parseVersionNumber32(const char*); void parseSectionOrderFile(const char* segment, const char* section, const char* path); void parseOrderFile(const char* path, bool cstring); void addSection(const char* segment, const char* section, const char* path); @@ -384,7 +387,7 @@ private: bool fDeadStrip; NameSpace fNameSpace; uint32_t fDylibCompatVersion; - uint32_t fDylibCurrentVersion; + uint64_t fDylibCurrentVersion; const char* fDylibInstallName; const char* fFinalName; const char* fEntryName; diff --git a/src/ld/OutputFile.cpp b/src/ld/OutputFile.cpp index 65e8b8c..f217eb0 100644 --- a/src/ld/OutputFile.cpp +++ b/src/ld/OutputFile.cpp @@ -516,6 +516,8 @@ void OutputFile::assignFileOffsets(ld::Internal& state) // second pass, assign section address to sections in segments that are contiguous with previous segment address = floatingAddressStart; lastSegName = ""; + ld::Internal::FinalSection* overlappingFixedSection = NULL; + ld::Internal::FinalSection* overlappingFlowSection = NULL; if ( log ) fprintf(stderr, "Regular layout segments:\n"); for (std::vector::iterator it = state.sections.begin(); it != state.sections.end(); ++it) { ld::Internal::FinalSection* sect = *it; @@ -550,6 +552,25 @@ void OutputFile::assignFileOffsets(ld::Internal& state) && (_options.outputKind() != Options::kStaticExecutable) ) throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range", sect->sectionName(), address, sect->size); + + // sanity check it does not overlap a fixed address segment + for (std::vector::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) { + ld::Internal::FinalSection* otherSect = *sit; + if ( ! _options.hasCustomSegmentAddress(otherSect->segmentName()) ) + continue; + if ( sect->address > otherSect->address ) { + if ( (otherSect->address+otherSect->size) > sect->address ) { + overlappingFixedSection = otherSect; + overlappingFlowSection = sect; + } + } + else { + if ( (sect->address+sect->size) > otherSect->address ) { + overlappingFixedSection = otherSect; + overlappingFlowSection = sect; + } + } + } if ( log ) fprintf(stderr, " address=0x%08llX, hidden=%d, alignment=%02d, padBytes=%d, section=%s,%s\n", sect->address, sect->isSectionHidden(), sect->alignment, sect->alignmentPaddingBytes, @@ -558,6 +579,21 @@ void OutputFile::assignFileOffsets(ld::Internal& state) if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace ) address += sect->size; } + if ( overlappingFixedSection != NULL ) { + fprintf(stderr, "Section layout:\n"); + for (std::vector::iterator it = state.sections.begin(); it != state.sections.end(); ++it) { + ld::Internal::FinalSection* sect = *it; + if ( sect->isSectionHidden() ) + continue; + fprintf(stderr, " address:0x%08llX, alignment:2^%d, size:0x%08llX, padBytes:%d, section:%s/%s\n", + sect->address, sect->alignment, sect->size, sect->alignmentPaddingBytes, + sect->segmentName(), sect->sectionName()); + + } + throwf("Section (%s/%s) overlaps fixed address section (%s/%s)", + overlappingFlowSection->segmentName(), overlappingFlowSection->sectionName(), + overlappingFixedSection->segmentName(), overlappingFixedSection->sectionName()); + } // third pass, assign section file offsets @@ -898,33 +934,6 @@ void OutputFile::rangeCheckThumbBranch22(int64_t displacement, ld::Internal& sta } } -void OutputFile::rangeCheckPPCBranch24(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup) -{ - const int64_t bl_eightMegLimit = 0x00FFFFFF; - if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) { - // show layout of final image - printSectionLayout(state); - - const ld::Atom* target; - throwf("bl PPC branch out of range (%lld max is +/-16MB): from %s (0x%08llX) to %s (0x%08llX)", - displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), - addressOf(state, fixup, &target)); - } -} - -void OutputFile::rangeCheckPPCBranch14(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup) -{ - const int64_t b_sixtyFourKiloLimit = 0x0000FFFF; - if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) { - // show layout of final image - printSectionLayout(state); - - const ld::Atom* target; - throwf("bcc PPC branch out of range (%lld max is +/-64KB): from %s (0x%08llX) to %s (0x%08llX)", - displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), - addressOf(state, fixup, &target)); - } -} @@ -956,7 +965,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld:: int64_t delta; uint32_t instruction; uint32_t newInstruction; - uint16_t instructionLowHalf; bool is_bl; bool is_blx; bool is_b; @@ -1145,41 +1153,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld:: } set32LE(fixUpLocation, newInstruction); break; - case ld::Fixup::kindStorePPCBranch14: - delta = accumulator - (atom->finalAddress() + fit->offsetInAtom); - rangeCheckPPCBranch14(delta, state, atom, fit); - instruction = get32BE(fixUpLocation); - newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)delta & 0x0000FFFC); - set32BE(fixUpLocation, newInstruction); - break; - case ld::Fixup::kindStorePPCPicLow14: - case ld::Fixup::kindStorePPCAbsLow14: - instruction = get32BE(fixUpLocation); - if ( (accumulator & 0x3) != 0 ) - throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)accumulator); - newInstruction = (instruction & 0xFFFF0003) | (accumulator & 0xFFFC); - set32BE(fixUpLocation, newInstruction); - break; - case ld::Fixup::kindStorePPCAbsLow16: - case ld::Fixup::kindStorePPCPicLow16: - instruction = get32BE(fixUpLocation); - newInstruction = (instruction & 0xFFFF0000) | (accumulator & 0xFFFF); - set32BE(fixUpLocation, newInstruction); - break; - case ld::Fixup::kindStorePPCAbsHigh16AddLow: - case ld::Fixup::kindStorePPCPicHigh16AddLow: - instructionLowHalf = (accumulator >> 16) & 0xFFFF; - if ( accumulator & 0x00008000 ) - ++instructionLowHalf; - instruction = get32BE(fixUpLocation); - newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf; - set32BE(fixUpLocation, newInstruction); - break; - case ld::Fixup::kindStorePPCAbsHigh16: - instruction = get32BE(fixUpLocation); - newInstruction = (instruction & 0xFFFF0000) | ((accumulator >> 16) & 0xFFFF); - set32BE(fixUpLocation, newInstruction); - break; case ld::Fixup::kindDtraceExtra: break; case ld::Fixup::kindStoreX86DtraceCallSiteNop: @@ -1202,18 +1175,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld:: fixUpLocation[3] = 0x90; // 1-byte nop } break; - case ld::Fixup::kindStorePPCDtraceCallSiteNop: - if ( _options.outputKind() != Options::kObjectFile ) { - // change call site to a NOP - set32BE(fixUpLocation, 0x60000000); - } - break; - case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear: - if ( _options.outputKind() != Options::kObjectFile ) { - // change call site to a li r3,0 - set32BE(fixUpLocation, 0x38600000); - } - break; case ld::Fixup::kindStoreARMDtraceCallSiteNop: if ( _options.outputKind() != Options::kObjectFile ) { // change call site to a NOP @@ -1506,18 +1467,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld:: set32LE(fixUpLocation, newInstruction); } break; - case ld::Fixup::kindStoreTargetAddressPPCBranch24: - accumulator = addressOf(state, fit, &toTarget); - if ( fit->contentDetlaToAddendOnly ) - accumulator = 0; - // fall into kindStorePPCBranch24 case - case ld::Fixup::kindStorePPCBranch24: - delta = accumulator - (atom->finalAddress() + fit->offsetInAtom); - rangeCheckPPCBranch24(delta, state, atom, fit); - instruction = get32BE(fixUpLocation); - newInstruction = (instruction & 0xFC000003) | ((uint32_t)delta & 0x03FFFFFC); - set32BE(fixUpLocation, newInstruction); - break; } } } @@ -1525,10 +1474,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld:: void OutputFile::copyNoOps(uint8_t* from, uint8_t* to, bool thumb) { switch ( _options.architecture() ) { - case CPU_TYPE_POWERPC: - for (uint8_t* p=from; p < to; p += 4) - OSWriteBigInt32((uint32_t*)p, 0, 0x60000000); - break; case CPU_TYPE_I386: case CPU_TYPE_X86_64: for (uint8_t* p=from; p < to; ++p) @@ -2002,54 +1947,6 @@ void OutputFile::addLinkEdit(ld::Internal& state) return addPreloadLinkEdit(state); switch ( _options.architecture() ) { - case CPU_TYPE_POWERPC: - if ( _hasSectionRelocations ) { - _sectionsRelocationsAtom = new SectionRelocationsAtom(_options, state, *this); - sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom); - } - if ( _hasDyldInfo ) { - _rebasingInfoAtom = new RebaseInfoAtom(_options, state, *this); - rebaseSection = state.addAtom(*_rebasingInfoAtom); - - _bindingInfoAtom = new BindingInfoAtom(_options, state, *this); - bindingSection = state.addAtom(*_bindingInfoAtom); - - _weakBindingInfoAtom = new WeakBindingInfoAtom(_options, state, *this); - weakBindingSection = state.addAtom(*_weakBindingInfoAtom); - - _lazyBindingInfoAtom = new LazyBindingInfoAtom(_options, state, *this); - lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom); - - _exportInfoAtom = new ExportInfoAtom(_options, state, *this); - exportSection = state.addAtom(*_exportInfoAtom); - } - if ( _hasLocalRelocations ) { - _localRelocsAtom = new LocalRelocationsAtom(_options, state, *this); - localRelocationsSection = state.addAtom(*_localRelocsAtom); - } - if ( _hasSplitSegInfo ) { - _splitSegInfoAtom = new SplitSegInfoAtom(_options, state, *this); - splitSegInfoSection = state.addAtom(*_splitSegInfoAtom); - } - if ( _hasFunctionStartsInfo ) { - _functionStartsAtom = new FunctionStartsAtom(_options, state, *this); - functionStartsSection = state.addAtom(*_functionStartsAtom); - } - if ( _hasSymbolTable ) { - _symbolTableAtom = new SymbolTableAtom(_options, state, *this); - symbolTableSection = state.addAtom(*_symbolTableAtom); - } - if ( _hasExternalRelocations ) { - _externalRelocsAtom = new ExternalRelocationsAtom(_options, state, *this); - externalRelocationsSection = state.addAtom(*_externalRelocsAtom); - } - if ( _hasSymbolTable ) { - _indirectSymbolTableAtom = new IndirectSymbolTableAtom(_options, state, *this); - indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom); - _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4); - stringPoolSection = state.addAtom(*_stringPoolAtom); - } - break; case CPU_TYPE_I386: if ( _hasSectionRelocations ) { _sectionsRelocationsAtom = new SectionRelocationsAtom(_options, state, *this); @@ -2194,54 +2091,6 @@ void OutputFile::addLinkEdit(ld::Internal& state) stringPoolSection = state.addAtom(*_stringPoolAtom); } break; - case CPU_TYPE_POWERPC64: - if ( _hasSectionRelocations ) { - _sectionsRelocationsAtom = new SectionRelocationsAtom(_options, state, *this); - sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom); - } - if ( _hasDyldInfo ) { - _rebasingInfoAtom = new RebaseInfoAtom(_options, state, *this); - rebaseSection = state.addAtom(*_rebasingInfoAtom); - - _bindingInfoAtom = new BindingInfoAtom(_options, state, *this); - bindingSection = state.addAtom(*_bindingInfoAtom); - - _weakBindingInfoAtom = new WeakBindingInfoAtom(_options, state, *this); - weakBindingSection = state.addAtom(*_weakBindingInfoAtom); - - _lazyBindingInfoAtom = new LazyBindingInfoAtom(_options, state, *this); - lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom); - - _exportInfoAtom = new ExportInfoAtom(_options, state, *this); - exportSection = state.addAtom(*_exportInfoAtom); - } - if ( _hasLocalRelocations ) { - _localRelocsAtom = new LocalRelocationsAtom(_options, state, *this); - localRelocationsSection = state.addAtom(*_localRelocsAtom); - } - if ( _hasSplitSegInfo ) { - _splitSegInfoAtom = new SplitSegInfoAtom(_options, state, *this); - splitSegInfoSection = state.addAtom(*_splitSegInfoAtom); - } - if ( _hasFunctionStartsInfo ) { - _functionStartsAtom = new FunctionStartsAtom(_options, state, *this); - functionStartsSection = state.addAtom(*_functionStartsAtom); - } - if ( _hasSymbolTable ) { - _symbolTableAtom = new SymbolTableAtom(_options, state, *this); - symbolTableSection = state.addAtom(*_symbolTableAtom); - } - if ( _hasExternalRelocations ) { - _externalRelocsAtom = new ExternalRelocationsAtom(_options, state, *this); - externalRelocationsSection = state.addAtom(*_externalRelocsAtom); - } - if ( _hasSymbolTable ) { - _indirectSymbolTableAtom = new IndirectSymbolTableAtom(_options, state, *this); - indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom); - _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4); - stringPoolSection = state.addAtom(*_stringPoolAtom); - } - break; default: throw "unknown architecture"; } @@ -2262,14 +2111,6 @@ void OutputFile::addLoadCommands(ld::Internal& state) _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom(_options, state, *this); headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom); break; - case CPU_TYPE_POWERPC: - _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom(_options, state, *this); - headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom); - break; - case CPU_TYPE_POWERPC64: - _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom(_options, state, *this); - headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom); - break; default: throw "unknown architecture"; } @@ -2425,18 +2266,12 @@ bool OutputFile::isPcRelStore(ld::Fixup::Kind kind) case ld::Fixup::kindStoreARMBranch24: case ld::Fixup::kindStoreThumbBranch22: case ld::Fixup::kindStoreARMLoad12: - case ld::Fixup::kindStorePPCBranch24: - case ld::Fixup::kindStorePPCBranch14: - case ld::Fixup::kindStorePPCPicLow14: - case ld::Fixup::kindStorePPCPicLow16: - case ld::Fixup::kindStorePPCPicHigh16AddLow: case ld::Fixup::kindStoreTargetAddressX86PCRel32: case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad: case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA: case ld::Fixup::kindStoreTargetAddressARMBranch24: case ld::Fixup::kindStoreTargetAddressThumbBranch22: case ld::Fixup::kindStoreTargetAddressARMLoad12: - case ld::Fixup::kindStoreTargetAddressPPCBranch24: return true; case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32: return (_options.outputKind() != Options::kKextBundle); @@ -2485,7 +2320,6 @@ bool OutputFile::setsTarget(ld::Fixup::Kind kind) case ld::Fixup::kindStoreTargetAddressARMBranch24: case ld::Fixup::kindStoreTargetAddressThumbBranch22: case ld::Fixup::kindStoreTargetAddressARMLoad12: - case ld::Fixup::kindStoreTargetAddressPPCBranch24: return true; case ld::Fixup::kindStoreX86DtraceCallSiteNop: case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear: @@ -2493,8 +2327,6 @@ bool OutputFile::setsTarget(ld::Fixup::Kind kind) case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear: case ld::Fixup::kindStoreThumbDtraceCallSiteNop: case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear: - case ld::Fixup::kindStorePPCDtraceCallSiteNop: - case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear: return (_options.outputKind() == Options::kObjectFile); default: break; @@ -3026,25 +2858,6 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio sect->hasLocalRelocs = true; } break; - case ld::Fixup::kindStorePPCAbsLow14: - case ld::Fixup::kindStorePPCAbsLow16: - case ld::Fixup::kindStorePPCAbsHigh16AddLow: - case ld::Fixup::kindStorePPCAbsHigh16: - { - assert(target != NULL); - if ( target->definition() == ld::Atom::definitionProxy ) - throwf("half word text relocs not supported in %s", atom->name()); - if ( _options.outputSlidable() ) { - if ( inReadOnlySeg ) - noteTextReloc(atom, target); - uint32_t machoSectionIndex = (target->definition() == ld::Atom::definitionAbsolute) - ? R_ABS : target->machoSection(); - _localRelocsAtom->addTextReloc(relocAddress, fixupWithTarget->kind, - target->finalAddress(), machoSectionIndex); - sect->hasLocalRelocs = true; - } - } - break; case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32: if ( _options.outputKind() == Options::kKextBundle ) { assert(target != NULL); @@ -3228,7 +3041,6 @@ void OutputFile::makeSplitSegInfo(ld::Internal& state) case ld::Fixup::kindStoreX86PCRel32GOTLoad: case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA: case ld::Fixup::kindStoreX86PCRel32GOT: - case ld::Fixup::kindStorePPCPicHigh16AddLow: case ld::Fixup::kindStoreTargetAddressX86PCRel32: case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad: case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA: diff --git a/src/ld/OutputFile.h b/src/ld/OutputFile.h index 415d24b..8401716 100644 --- a/src/ld/OutputFile.h +++ b/src/ld/OutputFile.h @@ -65,7 +65,7 @@ public: uint32_t encryptedTextStartOffset() { return _encryptedTEXTstartOffset; } uint32_t encryptedTextEndOffset() { return _encryptedTEXTendOffset; } int compressedOrdinalForAtom(const ld::Atom* target); - + uint64_t fileSize() const { return _fileSize; } bool hasWeakExternalSymbols; @@ -210,10 +210,6 @@ private: const ld::Fixup* fixup); void rangeCheckThumbBranch22(int64_t delta, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup); - void rangeCheckPPCBranch24(int64_t delta, ld::Internal& state, const ld::Atom* atom, - const ld::Fixup* fixup); - void rangeCheckPPCBranch14(int64_t delta, ld::Internal& state, const ld::Atom* atom, - const ld::Fixup* fixup); uint64_t sectionOffsetOf(const ld::Internal& state, const ld::Fixup* fixup); uint64_t tlvTemplateOffsetOf(const ld::Internal& state, const ld::Fixup* fixup); void dumpAtomsBySection(ld::Internal& state, bool); diff --git a/src/ld/Resolver.cpp b/src/ld/Resolver.cpp index a56cefe..2502820 100644 --- a/src/ld/Resolver.cpp +++ b/src/ld/Resolver.cpp @@ -297,26 +297,6 @@ void Resolver::buildAtomList() //_symbolTable.printStatistics(); } -unsigned int Resolver::ppcSubTypeIndex(uint32_t subtype) -{ - switch ( subtype ) { - case CPU_SUBTYPE_POWERPC_ALL: - return 0; - case CPU_SUBTYPE_POWERPC_750: - // G3 - return 1; - case CPU_SUBTYPE_POWERPC_7400: - case CPU_SUBTYPE_POWERPC_7450: - // G4 - return 2; - case CPU_SUBTYPE_POWERPC_970: - // G5 can run everything - return 3; - default: - throw "Unhandled PPC cpu subtype!"; - break; - } -} void Resolver::doFile(const ld::File& file) { @@ -363,29 +343,6 @@ void Resolver::doFile(const ld::File& file) // update cpu-sub-type cpu_subtype_t nextObjectSubType = file.cpuSubType(); switch ( _options.architecture() ) { - case CPU_TYPE_POWERPC: - // no checking when -force_cpusubtype_ALL is used - if ( _options.forceCpuSubtypeAll() ) - return; - if ( _options.preferSubArchitecture() ) { - // warn if some .o file is not compatible with desired output sub-type - if ( _options.subArchitecture() != nextObjectSubType ) { - if ( ppcSubTypeIndex(nextObjectSubType) > ppcSubTypeIndex(_options.subArchitecture()) ) { - if ( !_inputFiles.inferredArch() ) - warning("cpu-sub-type of %s is not compatible with command line cpu-sub-type", file.path()); - _internal.cpuSubType = nextObjectSubType; - } - } - } - else { - // command line to linker just had -arch ppc - // figure out final sub-type based on sub-type of all .o files - if ( ppcSubTypeIndex(nextObjectSubType) > ppcSubTypeIndex(_internal.cpuSubType) ) { - _internal.cpuSubType = nextObjectSubType; - } - } - break; - case CPU_TYPE_ARM: if ( _options.subArchitecture() != nextObjectSubType ) { if ( (_options.subArchitecture() == CPU_SUBTYPE_ARM_ALL) && _options.forceCpuSubtypeAll() ) { @@ -405,9 +362,6 @@ void Resolver::doFile(const ld::File& file) } break; - case CPU_TYPE_POWERPC64: - break; - case CPU_TYPE_I386: _internal.cpuSubType = CPU_SUBTYPE_I386_ALL; break; @@ -567,8 +521,6 @@ bool Resolver::isDtraceProbe(ld::Fixup::Kind kind) case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear: case ld::Fixup::kindStoreThumbDtraceCallSiteNop: case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear: - case ld::Fixup::kindStorePPCDtraceCallSiteNop: - case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear: case ld::Fixup::kindDtraceExtra: return true; default: @@ -770,7 +722,6 @@ void Resolver::markLive(const ld::Atom& atom, WhyLiveBackChain* previous) case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA: case ld::Fixup::kindStoreTargetAddressARMBranch24: case ld::Fixup::kindStoreTargetAddressThumbBranch22: - case ld::Fixup::kindStoreTargetAddressPPCBranch24: if ( fit->binding == ld::Fixup::bindingByContentBound ) { // normally this was done in convertReferencesToIndirect() // but a archive loaded .o file may have a forward reference @@ -1078,7 +1029,8 @@ void Resolver::checkUndefines(bool force) break; } std::vector unresolvableUndefines; - if ( _options.deadCodeStrip() ) + // LTO many have eliminated need for some undefines + if ( _options.deadCodeStrip() || _haveLLVMObjs ) this->liveUndefines(unresolvableUndefines); else _symbolTable.undefines(unresolvableUndefines); diff --git a/src/ld/Resolver.h b/src/ld/Resolver.h index 1202fc7..65e2006 100644 --- a/src/ld/Resolver.h +++ b/src/ld/Resolver.h @@ -94,7 +94,6 @@ private: void markLive(const ld::Atom& atom, WhyLiveBackChain* previous); bool isDtraceProbe(ld::Fixup::Kind kind); void liveUndefines(std::vector&); - static unsigned int ppcSubTypeIndex(uint32_t subtype); bool printReferencedBy(const char* name, SymbolTable::IndirectBindingSlot slot); diff --git a/src/ld/SymbolTable.cpp b/src/ld/SymbolTable.cpp index 2716ccf..66ff358 100644 --- a/src/ld/SymbolTable.cpp +++ b/src/ld/SymbolTable.cpp @@ -179,22 +179,32 @@ bool SymbolTable::addByName(const ld::Atom& newAtom, bool ignoreDuplicates) } else { // existing not-weak, new is not-weak - if ( ignoreDuplicates ) { + if ( newAtom.section().type() == ld::Section::typeMachHeader ) { + warning("ignoring override of built-in symbol %s from %s", newAtom.name(), existingAtom->file()->path()); + useNew = true; + } + else if ( existingAtom->section().type() == ld::Section::typeMachHeader ) { + warning("ignoring override of built-in symbol %s from %s", newAtom.name(), newAtom.file()->path()); useNew = false; - static bool fullWarning = false; - if ( ! fullWarning ) { - warning("-dead_strip with lazy loaded static (library) archives " - "has resulted in a duplicate symbol. You can change your " - "source code to rename symbols to avoid the collision. " - "This will be an error in a future linker."); - fullWarning = true; - } - warning("duplicate symbol %s originally in %s now lazily loaded from %s", - SymbolTable::demangle(name), existingAtom->file()->path(), newAtom.file()->path()); - } + } else { - throwf("duplicate symbol %s in %s and %s", - SymbolTable::demangle(name), newAtom.file()->path(), existingAtom->file()->path()); + if ( ignoreDuplicates ) { + useNew = false; + static bool fullWarning = false; + if ( ! fullWarning ) { + warning("-dead_strip with lazy loaded static (library) archives " + "has resulted in a duplicate symbol. You can change your " + "source code to rename symbols to avoid the collision. " + "This will be an error in a future linker."); + fullWarning = true; + } + warning("duplicate symbol %s originally in %s now lazily loaded from %s", + SymbolTable::demangle(name), existingAtom->file()->path(), newAtom.file()->path()); + } + else { + throwf("duplicate symbol %s in %s and %s", + SymbolTable::demangle(name), newAtom.file()->path(), existingAtom->file()->path()); + } } } } @@ -222,17 +232,27 @@ bool SymbolTable::addByName(const ld::Atom& newAtom, bool ignoreDuplicates) switch ( newAtom.definition() ) { case ld::Atom::definitionRegular: // replace existing tentative atom with regular one - checkVisibilityMismatch = true; - if ( newAtom.size() < existingAtom->size() ) { - warning("for symbol %s tentative definition of size %llu from %s is " - "being replaced by a real definition of size %llu from %s", - newAtom.name(), existingAtom->size(), existingAtom->file()->path(), - newAtom.size(), newAtom.file()->path()); + if ( newAtom.section().type() == ld::Section::typeMachHeader ) { + // silently replace tentative __dso_handle with real linker created symbol + useNew = true; + } + else if ( existingAtom->section().type() == ld::Section::typeMachHeader ) { + // silently replace tentative __dso_handle with real linker created symbol + useNew = false; } - if ( newAtom.section().type() == ld::Section::typeCode ) { - warning("for symbol %s tentative (data) defintion from %s is " - "being replaced by code from %s", newAtom.name(), existingAtom->file()->path(), - newAtom.file()->path()); + else { + checkVisibilityMismatch = true; + if ( newAtom.size() < existingAtom->size() ) { + warning("for symbol %s tentative definition of size %llu from %s is " + "being replaced by a real definition of size %llu from %s", + newAtom.name(), existingAtom->size(), existingAtom->file()->path(), + newAtom.size(), newAtom.file()->path()); + } + if ( newAtom.section().type() == ld::Section::typeCode ) { + warning("for symbol %s tentative (data) defintion from %s is " + "being replaced by code from %s", newAtom.name(), existingAtom->file()->path(), + newAtom.file()->path()); + } } break; case ld::Atom::definitionTentative: diff --git a/src/ld/ld.cpp b/src/ld/ld.cpp index 5b21c63..ce49e73 100644 --- a/src/ld/ld.cpp +++ b/src/ld/ld.cpp @@ -1,6 +1,6 @@ /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-* * - * Copyright (c) 2005-2010 Apple Inc. All rights reserved. + * Copyright (c) 2005-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -74,7 +74,7 @@ extern "C" double log2 ( double ); #include "passes/tlvp.h" #include "passes/huge.h" #include "passes/compact_unwind.h" -#include "passes/order_file.h" +#include "passes/order.h" #include "passes/branch_island.h" #include "passes/branch_shim.h" #include "passes/objc.h" @@ -87,14 +87,31 @@ extern "C" double log2 ( double ); #include "parsers/opaque_section_file.h" +struct PerformanceStatistics { + uint64_t startTool; + uint64_t startInputFileProcessing; + uint64_t startResolver; + uint64_t startDylibs; + uint64_t startPasses; + uint64_t startOutput; + uint64_t startDone; + vm_statistics_data_t vmStart; + vm_statistics_data_t vmEnd; +}; + + + + + class InternalState : public ld::Internal { public: - InternalState(const Options& opts) : _options(opts) { } + InternalState(const Options& opts) : _options(opts), _atomsOrderedInSections(false) { } virtual ld::Internal::FinalSection* addAtom(const ld::Atom& atom); virtual ld::Internal::FinalSection* getFinalSection(const ld::Section&); void sortSections(); + void markAtomsOrdered() { _atomsOrderedInSections = true; } virtual ~InternalState() {} private: @@ -134,6 +151,7 @@ private: SectionInToOut _sectionInToFinalMap; const Options& _options; + bool _atomsOrderedInSections; }; ld::Section InternalState::FinalSection::_s_DATA_data( "__DATA", "__data", ld::Section::typeUnclassified); @@ -440,32 +458,28 @@ static void validateFixups(const ld::Atom& atom) ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom) { ld::Internal::FinalSection* fs = this->getFinalSection(atom.section()); - - // When order file used on data, turn ordered zero fill symbols into zero data - switch ( atom.section().type() ) { - case ld::Section::typeZeroFill: - case ld::Section::typeTentativeDefs: - if ( (atom.symbolTableInclusion() == ld::Atom::symbolTableIn) - && (atom.size() <= 512) && (_options.orderedSymbolsCount() != 0) ) { - for(Options::OrderedSymbolsIterator it = _options.orderedSymbolsBegin(); it != _options.orderedSymbolsEnd(); ++it) { - if ( (it->objectFileName == NULL) && (strcmp(it->symbolName, atom.name()) == 0) ) { - // found in order file, move to __data section - fs = getFinalSection(InternalState::FinalSection::_s_DATA_data);\ - //fprintf(stderr, "moved %s to __data section\n", atom.name()); - break; - } - } - } - break; - default: - break; - } - //fprintf(stderr, "InternalState::doAtom(%p), name=%s, sect=%s, finalsect=%p\n", &atom, atom.name(), atom.section().sectionName(), fs); #ifndef NDEBUG validateFixups(atom); #endif - fs->atoms.push_back(&atom); + if ( _atomsOrderedInSections ) { + // make sure this atom is placed before any trailing section$end$ atom + if ( (fs->atoms.size() > 1) && (fs->atoms.back()->contentType() == ld::Atom::typeSectionEnd) ) { + // last atom in section$end$ atom, insert before it + const ld::Atom* endAtom = fs->atoms.back(); + fs->atoms.pop_back(); + fs->atoms.push_back(&atom); + fs->atoms.push_back(endAtom); + } + else { + // not end atom, just append new atom + fs->atoms.push_back(&atom); + } + } + else { + // normal case + fs->atoms.push_back(&atom); + } return fs; } @@ -552,6 +566,49 @@ void InternalState::sortSections() } +static char* commatize(uint64_t in, char* out) +{ + char* result = out; + char rawNum[30]; + sprintf(rawNum, "%llu", in); + const int rawNumLen = strlen(rawNum); + for(int i=0; i < rawNumLen-1; ++i) { + *out++ = rawNum[i]; + if ( ((rawNumLen-i) % 3) == 1 ) + *out++ = ','; + } + *out++ = rawNum[rawNumLen-1]; + *out = '\0'; + return result; +} + +static void printTime(const char* msg, uint64_t partTime, uint64_t totalTime) +{ + static uint64_t sUnitsPerSecond = 0; + if ( sUnitsPerSecond == 0 ) { + struct mach_timebase_info timeBaseInfo; + if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) { + sUnitsPerSecond = 1000000000ULL * timeBaseInfo.denom / timeBaseInfo.numer; + //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond); + } + } + if ( partTime < sUnitsPerSecond ) { + uint32_t milliSecondsTimeTen = (partTime*10000)/sUnitsPerSecond; + uint32_t milliSeconds = milliSecondsTimeTen/10; + uint32_t percentTimesTen = (partTime*1000)/totalTime; + uint32_t percent = percentTimesTen/10; + fprintf(stderr, "%24s: % 4d.%d milliseconds (% 4d.%d%%)\n", msg, milliSeconds, milliSecondsTimeTen-milliSeconds*10, percent, percentTimesTen-percent*10); + } + else { + uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond; + uint32_t seconds = secondsTimeTen/10; + uint32_t percentTimesTen = (partTime*1000)/totalTime; + uint32_t percent = percentTimesTen/10; + fprintf(stderr, "%24s: % 4d.%d seconds (% 4d.%d%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10); + } +} + + static void getVMInfo(vm_statistics_data_t& info) { mach_msg_type_number_t count = sizeof(vm_statistics_data_t) / sizeof(natural_t); @@ -564,23 +621,20 @@ static void getVMInfo(vm_statistics_data_t& info) int main(int argc, const char* argv[]) { -#if DEBUG - usleep(1000000); -#endif const char* archName = NULL; bool showArch = false; bool archInferred = false; try { - vm_statistics_data_t vmStart; - vm_statistics_data_t vmEnd; - getVMInfo(vmStart); - + PerformanceStatistics statistics; + statistics.startTool = mach_absolute_time(); + // create object to track command line arguments Options options(argc, argv); + InternalState state(options); - // gather stats + // gather vm stats if ( options.printStatistics() ) - getVMInfo(vmStart); + getVMInfo(statistics.vmStart); // update strings for error messages showArch = options.printArchPrefix(); @@ -588,46 +642,71 @@ int main(int argc, const char* argv[]) archInferred = (options.architecture() == 0); // open and parse input files + statistics.startInputFileProcessing = mach_absolute_time(); ld::tool::InputFiles inputFiles(options, &archName); // load and resolve all references - InternalState state(options); + statistics.startResolver = mach_absolute_time(); ld::tool::Resolver resolver(options, inputFiles, state); resolver.resolve(); // add dylibs used + statistics.startDylibs = mach_absolute_time(); inputFiles.dylibs(state); // do initial section sorting so passes have rough idea of the layout state.sortSections(); // run passes + statistics.startPasses = mach_absolute_time(); ld::passes::objc::doPass(options, state); ld::passes::stubs::doPass(options, state); ld::passes::huge::doPass(options, state); ld::passes::got::doPass(options, state); ld::passes::tlvp::doPass(options, state); ld::passes::dylibs::doPass(options, state); // must be after stubs and GOT passes - ld::passes::order_file::doPass(options, state); + ld::passes::order::doPass(options, state); + state.markAtomsOrdered(); ld::passes::branch_shim::doPass(options, state); // must be after stubs - ld::passes::branch_island::doPass(options, state); // must be after stubs and order_file pass + ld::passes::branch_island::doPass(options, state); // must be after stubs and order pass ld::passes::dtrace::doPass(options, state); - ld::passes::compact_unwind::doPass(options, state); // must be after order-file pass + ld::passes::compact_unwind::doPass(options, state); // must be after order pass // sort final sections state.sortSections(); // write output file + statistics.startOutput = mach_absolute_time(); ld::tool::OutputFile out(options); out.write(state); + statistics.startDone = mach_absolute_time(); // print statistics //mach_o::relocatable::printCounts(); if ( options.printStatistics() ) { - getVMInfo(vmEnd); - fprintf(stderr, "pageins=%u, pageouts=%u, faults=%u\n", vmEnd.pageins-vmStart.pageins, - vmEnd.pageouts-vmStart.pageouts, vmEnd.faults-vmStart.faults); - + getVMInfo(statistics.vmEnd); + uint64_t totalTime = statistics.startDone - statistics.startTool; + printTime("ld total time", totalTime, totalTime); + printTime(" option parsing time", statistics.startInputFileProcessing - statistics.startTool, totalTime); + printTime(" object file processing", statistics.startResolver - statistics.startInputFileProcessing,totalTime); + printTime(" resolve symbols", statistics.startDylibs - statistics.startResolver, totalTime); + printTime(" build atom list", statistics.startPasses - statistics.startDylibs, totalTime); + printTime(" passess", statistics.startOutput - statistics.startPasses, totalTime); + printTime(" write output", statistics.startDone - statistics.startOutput, totalTime); + fprintf(stderr, "pageins=%u, pageouts=%u, faults=%u\n", + statistics.vmEnd.pageins-statistics.vmStart.pageins, + statistics.vmEnd.pageouts-statistics.vmStart.pageouts, + statistics.vmEnd.faults-statistics.vmStart.faults); + char temp[40]; + fprintf(stderr, "processed %3u object files, totaling %15s bytes\n", inputFiles._totalObjectLoaded, commatize(inputFiles._totalObjectSize, temp)); + fprintf(stderr, "processed %3u archive files, totaling %15s bytes\n", inputFiles._totalArchivesLoaded, commatize(inputFiles._totalArchiveSize, temp)); + fprintf(stderr, "processed %3u dylib files\n", inputFiles._totalDylibsLoaded); + fprintf(stderr, "wrote output file totaling %15s bytes\n", commatize(out.fileSize(), temp)); + } + // Would like linker warning to be build error. + if ( options.errorBecauseOfWarnings() ) { + fprintf(stderr, "ld: fatal warning(s) induced error (-fatal_warnings)\n"); + return 1; } } catch (const char* msg) { diff --git a/src/ld/ld.hpp b/src/ld/ld.hpp index 96075a7..b615046 100644 --- a/src/ld/ld.hpp +++ b/src/ld/ld.hpp @@ -318,16 +318,11 @@ struct Fixup kindStoreARMLoad12, kindStoreARMLow16, kindStoreARMHigh16, kindStoreThumbLow16, kindStoreThumbHigh16, - // PowerPC specific store kinds - kindStorePPCBranch24, kindStorePPCBranch14, - kindStorePPCPicLow14, kindStorePPCPicLow16, kindStorePPCPicHigh16AddLow, - kindStorePPCAbsLow14, kindStorePPCAbsLow16, kindStorePPCAbsHigh16AddLow, kindStorePPCAbsHigh16, // dtrace probes kindDtraceExtra, kindStoreX86DtraceCallSiteNop, kindStoreX86DtraceIsEnableSiteClear, kindStoreARMDtraceCallSiteNop, kindStoreARMDtraceIsEnableSiteClear, kindStoreThumbDtraceCallSiteNop, kindStoreThumbDtraceIsEnableSiteClear, - kindStorePPCDtraceCallSiteNop, kindStorePPCDtraceIsEnableSiteClear, // lazy binding kindLazyTarget, kindSetLazyOffset, // pointer store combinations @@ -350,8 +345,6 @@ struct Fixup kindStoreTargetAddressARMBranch24, // kindSetTargetAddress + kindStoreARMBranch24 kindStoreTargetAddressThumbBranch22, // kindSetTargetAddress + kindStoreThumbBranch22 kindStoreTargetAddressARMLoad12, // kindSetTargetAddress + kindStoreARMLoad12 - // PowerPC value calculation and store combinations - kindStoreTargetAddressPPCBranch24, // kindSetTargetAddress + kindStorePPCBranch24 }; union { diff --git a/src/ld/parsers/archive_file.cpp b/src/ld/parsers/archive_file.cpp index 66f9432..cf0a058 100644 --- a/src/ld/parsers/archive_file.cpp +++ b/src/ld/parsers/archive_file.cpp @@ -226,8 +226,6 @@ const class File::Entry* File::Entry::next() const } -template <> cpu_type_t File::architecture() { return CPU_TYPE_POWERPC; } -template <> cpu_type_t File::architecture() { return CPU_TYPE_POWERPC64; } template <> cpu_type_t File::architecture() { return CPU_TYPE_I386; } template <> cpu_type_t File::architecture() { return CPU_TYPE_X86_64; } template <> cpu_type_t File::architecture() { return CPU_TYPE_ARM; } @@ -314,12 +312,6 @@ bool File::memberHasObjCCategories(const Entry* member) const } } -template <> -bool File::memberHasObjCCategories(const Entry* member) const -{ - // ppc uses ObjC1 ABI which has .objc_category* global symbols - return false; -} template @@ -581,14 +573,6 @@ ld::archive::File* parse(const uint8_t* fileContent, uint64_t fileLength, if ( archive::Parser::validFile(fileContent, fileLength, opts.objOpts) ) return archive::Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts); break; - case CPU_TYPE_POWERPC: - if ( archive::Parser::validFile(fileContent, fileLength, opts.objOpts) ) - return archive::Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts); - break; - case CPU_TYPE_POWERPC64: - if ( archive::Parser::validFile(fileContent, fileLength, opts.objOpts) ) - return archive::Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts); - break; } return NULL; } diff --git a/src/ld/parsers/lto_file.cpp b/src/ld/parsers/lto_file.cpp index 46d350d..3a11c18 100644 --- a/src/ld/parsers/lto_file.cpp +++ b/src/ld/parsers/lto_file.cpp @@ -147,7 +147,7 @@ class Atom : public ld::Atom { public: Atom(File& f, const char* name, ld::Atom::Scope s, - ld::Atom::Definition d, ld::Atom::Combine c, ld::Atom::Alignment a); + ld::Atom::Definition d, ld::Atom::Combine c, ld::Atom::Alignment a, bool ah); // overrides of ld::Atom virtual ld::File* file() const { return &_file; } @@ -257,8 +257,6 @@ bool Parser::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, t->llvmTriplePrefix); } break; - case CPU_TYPE_POWERPC: - return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, "powerpc-"); } return false; } @@ -268,8 +266,6 @@ const char* Parser::fileKind(const uint8_t* p, uint64_t fileLength) if ( (p[0] == 0xDE) && (p[1] == 0xC0) && (p[2] == 0x17) && (p[3] == 0x0B) ) { uint32_t arch = LittleEndian::get32(*((uint32_t*)(&p[16]))); switch (arch) { - case CPU_TYPE_POWERPC: - return "ppc"; case CPU_TYPE_I386: return "i386"; case CPU_TYPE_X86_64: @@ -377,6 +373,7 @@ File::File(const char* pth, time_t mTime, const uint8_t* content, uint32_t conte // make LLVM atoms for definitions and a reference for undefines if ( def != ld::Atom::definitionProxy ) { ld::Atom::Scope scope; + bool autohide = false; switch ( attr & LTO_SYMBOL_SCOPE_MASK) { case LTO_SYMBOL_SCOPE_INTERNAL: scope = ld::Atom::scopeTranslationUnit; @@ -387,6 +384,12 @@ File::File(const char* pth, time_t mTime, const uint8_t* content, uint32_t conte case LTO_SYMBOL_SCOPE_DEFAULT: scope = ld::Atom::scopeGlobal; break; +#if LTO_API_VERSION >= 4 + case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN: + scope = ld::Atom::scopeGlobal; + autohide = true; + break; +#endif default: throwf("unknown scope for symbol %s in bitcode file %s", name, pth); } @@ -395,7 +398,7 @@ File::File(const char* pth, time_t mTime, const uint8_t* content, uint32_t conte continue; uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK); // make Atom using placement new operator - new (&_atomArray[_atomArrayCount++]) Atom(*this, name, scope, def, combine, alignment); + new (&_atomArray[_atomArrayCount++]) Atom(*this, name, scope, def, combine, alignment, autohide); if ( scope == ld::Atom::scopeLinkageUnit ) _internalAtom.addReference(name); if ( log ) fprintf(stderr, "\t0x%08X %s\n", attr, name); @@ -430,11 +433,14 @@ InternalAtom::InternalAtom(File& f) { } -Atom::Atom(File& f, const char* nm, ld::Atom::Scope s, ld::Atom::Definition d, ld::Atom::Combine c, ld::Atom::Alignment a) +Atom::Atom(File& f, const char* nm, ld::Atom::Scope s, ld::Atom::Definition d, ld::Atom::Combine c, + ld::Atom::Alignment a, bool ah) : ld::Atom(f._section, d, c, s, ld::Atom::typeLTOtemporary, ld::Atom::symbolTableIn, false, false, false, a), _file(f), _name(nm), _compiledAtom(NULL) { + if ( ah ) + this->setAutoHide(); } void Atom::setCompiledAtom(const ld::Atom& atom) diff --git a/src/ld/parsers/macho_dylib_file.cpp b/src/ld/parsers/macho_dylib_file.cpp index 436f3e6..39cebfb 100644 --- a/src/ld/parsers/macho_dylib_file.cpp +++ b/src/ld/parsers/macho_dylib_file.cpp @@ -855,60 +855,6 @@ public: -template <> -bool Parser::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC ) - return false; - if ( header->cputype() != CPU_TYPE_POWERPC ) - return false; - switch ( header->filetype() ) { - case MH_DYLIB: - case MH_DYLIB_STUB: - return true; - case MH_BUNDLE: - if ( executableOrDyliborBundle ) - return true; - else - throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)"; - case MH_EXECUTE: - if ( executableOrDyliborBundle ) - return true; - else - throw "can't link with a main executable"; - default: - return false; - } -} - -template <> -bool Parser::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC_64 ) - return false; - if ( header->cputype() != CPU_TYPE_POWERPC64 ) - return false; - switch ( header->filetype() ) { - case MH_DYLIB: - case MH_DYLIB_STUB: - return true; - case MH_BUNDLE: - if ( executableOrDyliborBundle ) - return true; - else - throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)"; - case MH_EXECUTE: - if ( executableOrDyliborBundle ) - return true; - else - throw "can't link with a main executable"; - default: - return false; - } -} - template <> bool Parser::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle) { @@ -1012,14 +958,6 @@ ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, if ( Parser::validFile(fileContent, bundleLoader) ) return Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); break; - case CPU_TYPE_POWERPC: - if ( Parser::validFile(fileContent, bundleLoader) ) - return Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); - break; - case CPU_TYPE_POWERPC64: - if ( Parser::validFile(fileContent, bundleLoader) ) - return Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); - break; } return NULL; } diff --git a/src/ld/parsers/macho_relocatable_file.cpp b/src/ld/parsers/macho_relocatable_file.cpp index abd44fa..e79d261 100644 --- a/src/ld/parsers/macho_relocatable_file.cpp +++ b/src/ld/parsers/macho_relocatable_file.cpp @@ -168,7 +168,6 @@ protected: _beginAtoms(NULL), _endAtoms(NULL), _hasAliases(false) { } - bool addRelocFixup_powerpc(class Parser& parser,const macho_relocation_info* reloc); Atom* findContentAtomByAddress(pint_t addr, class Atom* start, class Atom* end); uint32_t x86_64PcRelOffset(uint8_t r_type); static const char* makeSegmentName(const macho_section* s); @@ -1128,31 +1127,6 @@ Parser::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* p { } -template <> -bool Parser::validFile(const uint8_t* fileContent, bool, cpu_subtype_t) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC ) - return false; - if ( header->cputype() != CPU_TYPE_POWERPC ) - return false; - if ( header->filetype() != MH_OBJECT ) - return false; - return true; -} - -template <> -bool Parser::validFile(const uint8_t* fileContent, bool, cpu_subtype_t) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC_64 ) - return false; - if ( header->cputype() != CPU_TYPE_POWERPC64 ) - return false; - if ( header->filetype() != MH_OBJECT ) - return false; - return true; -} template <> bool Parser::validFile(const uint8_t* fileContent, bool, cpu_subtype_t) @@ -1202,39 +1176,6 @@ bool Parser::validFile(const uint8_t* fileContent, bool subtypeMustMatch, c } -template <> -const char* Parser::fileKind(const uint8_t* fileContent) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC ) - return NULL; - if ( header->cputype() != CPU_TYPE_POWERPC ) - return NULL; - switch ( header->cpusubtype() ) { - case CPU_SUBTYPE_POWERPC_750: - return "ppc750"; - case CPU_SUBTYPE_POWERPC_7400: - return "ppc7400"; - case CPU_SUBTYPE_POWERPC_7450: - return "ppc7450"; - case CPU_SUBTYPE_POWERPC_970: - return "ppc970"; - case CPU_SUBTYPE_POWERPC_ALL: - return "ppc"; - } - return "ppc???"; -} - -template <> -const char* Parser::fileKind(const uint8_t* fileContent) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC ) - return NULL; - if ( header->cputype() != CPU_TYPE_POWERPC64 ) - return NULL; - return "ppc64"; -} template <> const char* Parser::fileKind(const uint8_t* fileContent) @@ -1688,8 +1629,6 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) -template <> uint8_t Parser::loadCommandSizeMask() { return 0x03; } -template <> uint8_t Parser::loadCommandSizeMask() { return 0x07; } template <> uint8_t Parser::loadCommandSizeMask() { return 0x03; } template <> uint8_t Parser::loadCommandSizeMask() { return 0x07; } template <> uint8_t Parser::loadCommandSizeMask() { return 0x03; } @@ -2524,9 +2463,6 @@ void Parser::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co case ld::Fixup::kindStoreThumbBranch22: firstKind = ld::Fixup::kindStoreTargetAddressThumbBranch22; break; - case ld::Fixup::kindStorePPCBranch24: - firstKind = ld::Fixup::kindStoreTargetAddressPPCBranch24; - break; default: combined = false; cl = ld::Fixup::k1of2; @@ -3626,6 +3562,8 @@ ld::Section::Type Section::sectionType(const macho_section* se return ld::Section::typeCode; else if ( strcmp(sect->sectname(), "__StaticInit") == 0 ) return ld::Section::typeCode; + else if ( strcmp(sect->sectname(), "__constructor") == 0 ) + return ld::Section::typeInitializerPointers; } else if ( strcmp(sect->segname(), "__DATA") == 0 ) { if ( strcmp(sect->sectname(), "__cfstring") == 0 ) @@ -3705,8 +3643,6 @@ uint32_t Section::sectionNum(class Parser& parser) const return 1 + (this->_machOSection - parser.firstMachOSection()); } -// libunwind does not support ppc64 -template <> uint32_t CFISection::cfiCount() { return 0; } // arm does not have zero cost exceptions template <> uint32_t CFISection::cfiCount() { return 0; } @@ -3827,32 +3763,7 @@ void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, } -// need to change libunwind parseCFIs() to work for ppc -template <> -void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, - libunwind::CFI_Atom_Info::OAS>::CFI_Atom_Info cfiArray[], - uint32_t count) -{ - // 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(), - cfiArray, count, (void*)&parser, warnFunc); - if ( msg != NULL ) - throwf("malformed __eh_frame section: %s", msg); -} -template <> -void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, - libunwind::CFI_Atom_Info::OAS>::CFI_Atom_Info cfiArray[], - uint32_t count) -{ - // libunwind does not support ppc64 - assert(count == 0); -} template <> void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, @@ -3900,8 +3811,6 @@ uint32_t CFISection::appendAtoms(class Parser& parser, uint8_t* p, template <> bool CFISection::bigEndian() { return false; } template <> bool CFISection::bigEndian() { return false; } template <> bool CFISection::bigEndian() { return false; } -template <> bool CFISection::bigEndian() { return true; } -template <> bool CFISection::bigEndian() { return true; } template <> @@ -3951,30 +3860,6 @@ void CFISection::addCiePersonalityFixups(class Parser& parser, const C } -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::kindStoreBigEndian32); - } - 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) { @@ -4369,6 +4254,8 @@ SymboledSection::SymboledSection(Parser& parser, File& f, const macho_s case S_REGULAR: if ( strncmp(s->sectname(), "__gcc_except_tab", 16) == 0 ) _type = ld::Atom::typeLSDA; + else if ( this->type() == ld::Section::typeInitializerPointers ) + _type = ld::Atom::typeInitializerPointers; break; } } @@ -4714,17 +4601,6 @@ ld::Fixup::Kind NonLazyPointerSection::fixupKind() return ld::Fixup::kindStoreLittleEndian32; } -template <> -ld::Fixup::Kind NonLazyPointerSection::fixupKind() -{ - return ld::Fixup::kindStoreBigEndian32; -} - -template <> -ld::Fixup::Kind NonLazyPointerSection::fixupKind() -{ - return ld::Fixup::kindStoreBigEndian64; -} template <> void NonLazyPointerSection::makeFixups(class Parser& parser, const struct Parser::CFI_CU_InfoArrays&) @@ -5654,406 +5530,6 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati -// -// ppc and ppc64 both use the same relocations, so process them in one common routine -// -template -bool Section::addRelocFixup_powerpc(class Parser& parser, - const macho_relocation_info* reloc) -{ - const macho_section

* sect = this->machoSection(); - bool result = false; - uint32_t srcAddr; - uint32_t dstAddr; - uint32_t* fixUpPtr; - int32_t displacement = 0; - uint32_t instruction = 0; - int16_t lowBits; - pint_t contentValue = 0; - typename Parser::SourceLocation src; - typename Parser::TargetDesc target; - - if ( (reloc->r_address() & R_SCATTERED) == 0 ) { - srcAddr = sect->addr() + reloc->r_address(); - src.atom = this->findAtomByAddress(srcAddr); - src.offsetInAtom = srcAddr - src.atom->_objAddress; - const macho_relocation_info

* nextReloc = &reloc[1]; - fixUpPtr = (uint32_t*)(file().fileContent() + sect->offset() + reloc->r_address()); - if ( reloc->r_type() != PPC_RELOC_PAIR ) - instruction = BigEndian::get32(*fixUpPtr); - if ( reloc->r_extern() ) { - target.atom = NULL; - const macho_nlist

& targetSymbol = parser.symbolFromIndex(reloc->r_symbolnum()); - target.name = parser.nameFromSymbol(targetSymbol); - target.weakImport = parser.weakImportFromSymbol(targetSymbol); - } - switch ( reloc->r_type() ) { - case PPC_RELOC_BR24: - assert((instruction & 0x4C000000) == 0x48000000); - displacement = (instruction & 0x03FFFFFC); - if ( (displacement & 0x02000000) != 0 ) - displacement |= 0xFC000000; - if ( reloc->r_extern() ) { - target.addend = srcAddr + displacement; - } - else { - dstAddr = srcAddr + displacement; - parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target); - } - // special case "calls" for dtrace - if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_probe$", 16) == 0) ) { - parser.addFixup(src, ld::Fixup::k1of1, - ld::Fixup::kindStorePPCDtraceCallSiteNop, false, target.name); - parser.addDtraceExtraInfos(src, &target.name[16]); - } - else if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_isenabled$", 20) == 0) ) { - parser.addFixup(src, ld::Fixup::k1of1, - ld::Fixup::kindStorePPCDtraceIsEnableSiteClear, false, target.name); - parser.addDtraceExtraInfos(src, &target.name[20]); - } - else { - parser.addFixups(src, ld::Fixup::kindStorePPCBranch24, target); - } - break; - case PPC_RELOC_BR14: - displacement = (instruction & 0x0000FFFC); - if ( (displacement & 0x00008000) != 0 ) - displacement |= 0xFFFF0000; - if ( reloc->r_extern() ) { - target.addend = srcAddr + displacement; - } - else { - dstAddr = srcAddr + displacement; - parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target); - } - parser.addFixups(src, ld::Fixup::kindStorePPCBranch14, target); - break; - case PPC_RELOC_PAIR: - // skip, processed by a previous look ahead - break; - case PPC_RELOC_LO16: - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) - throw "PPC_RELOC_LO16 missing following pair"; - result = true; - lowBits = (instruction & 0x0000FFFF); - dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF); - if ( reloc->r_extern() ) { - target.addend = dstAddr; - } - else { - parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target); - } - parser.addFixups(src, ld::Fixup::kindStorePPCAbsLow16, target); - break; - case PPC_RELOC_LO14: - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) - throw "PPC_RELOC_LO14 missing following pair"; - result = true; - lowBits = (instruction & 0xFFFC); - dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF); - if ( reloc->r_extern() ) { - target.addend = dstAddr; - } - else { - parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target); - } - parser.addFixups(src, ld::Fixup::kindStorePPCAbsLow14, target); - break; - case PPC_RELOC_HI16: - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) - throw "PPC_RELOC_HI16 missing following pair"; - result = true; - lowBits = (nextReloc->r_address() & 0xFFFF); - dstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF); - if ( reloc->r_extern() ) { - target.addend = dstAddr; - } - else { - parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target); - } - parser.addFixups(src, ld::Fixup::kindStorePPCAbsHigh16, target); - break; - case PPC_RELOC_HA16: - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) - throw "PPC_RELOC_HA16 missing following pair"; - result = true; - lowBits = (nextReloc->r_address() & 0x0000FFFF); - dstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits; - if ( reloc->r_extern() ) { - target.addend = dstAddr; - } - else { - parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target); - } - parser.addFixups(src, ld::Fixup::kindStorePPCAbsHigh16AddLow, target); - break; - case PPC_RELOC_VANILLA: - contentValue = P::getP(*((pint_t*)fixUpPtr)); - if ( reloc->r_extern() ) { - target.addend = contentValue; - } - else { - parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), target); - } - switch ( reloc->r_length() ) { - case 0: - case 1: - throw "bad r_length in PPC_RELOC_VANILLA"; - case 2: - parser.addFixups(src, ld::Fixup::kindStoreBigEndian32, target); - break; - case 3: - parser.addFixups(src, ld::Fixup::kindStoreBigEndian64, target); - break; - } - break; - case PPC_RELOC_JBSR: - // this is from -mlong-branch codegen. We ignore the jump island and make reference to the real target - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) - throw "PPC_RELOC_JBSR missing following pair"; - if ( !parser._hasLongBranchStubs ) - warning("object file compiled with -mlong-branch which is no longer needed. " - "To remove this warning, recompile without -mlong-branch: %s", parser._path); - parser._hasLongBranchStubs = true; - result = true; - if ( reloc->r_extern() ) { - throw "PPC_RELOC_JBSR should not be using an external relocation"; - } - parser.findTargetFromAddressAndSectionNum(nextReloc->r_address(), reloc->r_symbolnum(), target); - parser.addFixups(src, ld::Fixup::kindStorePPCBranch24, target); - break; - default: - warning("unknown relocation type %d", reloc->r_type()); - } - } - else { - const macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; - // file format allows pair to be scattered or not - const macho_scattered_relocation_info

* nextSReloc = &sreloc[1]; - const macho_relocation_info

* nextReloc = &reloc[1]; - srcAddr = sect->addr() + sreloc->r_address(); - dstAddr = sreloc->r_value(); - fixUpPtr = (uint32_t*)(file().fileContent() + sect->offset() + sreloc->r_address()); - instruction = BigEndian::get32(*fixUpPtr); - src.atom = this->findAtomByAddress(srcAddr); - src.offsetInAtom = srcAddr - src.atom->_objAddress; - typename Parser::TargetDesc picBase; - bool nextRelocIsPair = false; - uint32_t nextRelocAddress = 0; - uint32_t nextRelocValue = 0; - if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) { - if ( nextReloc->r_type() == PPC_RELOC_PAIR ) { - nextRelocIsPair = true; - nextRelocAddress = nextReloc->r_address(); - result = true; - } - } - else { - if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) { - nextRelocIsPair = true; - nextRelocAddress = nextSReloc->r_address(); - nextRelocValue = nextSReloc->r_value(); - result = true; - } - } - switch ( sreloc->r_type() ) { - case PPC_RELOC_VANILLA: - // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr) - target.atom = parser.findAtomByAddress(sreloc->r_value()); - switch ( sreloc->r_length() ) { - case 0: - case 1: - throw "unsuppored r_length < 2 for scattered PPC_RELOC_VANILLA"; - case 2: - contentValue = BigEndian::get32(*(uint32_t*)fixUpPtr); - target.addend = contentValue - target.atom->_objAddress; - parser.addFixups(src, ld::Fixup::kindStoreBigEndian32, target); - break; - case 3: - contentValue = BigEndian::get64(*(uint64_t*)fixUpPtr); - target.addend = contentValue - target.atom->_objAddress; - parser.addFixups(src, ld::Fixup::kindStoreBigEndian64, target); - break; - } - break; - case PPC_RELOC_BR14: - displacement = (instruction & 0x0000FFFC); - if ( (displacement & 0x00008000) != 0 ) - displacement |= 0xFFFF0000; - target.atom = parser.findAtomByAddress(sreloc->r_value()); - target.addend = (srcAddr + displacement) - target.atom->_objAddress; - parser.addFixups(src, ld::Fixup::kindStorePPCBranch14, target); - break; - case PPC_RELOC_BR24: - assert((instruction & 0x4C000000) == 0x48000000); - displacement = (instruction & 0x03FFFFFC); - if ( (displacement & 0x02000000) != 0 ) - displacement |= 0xFC000000; - target.atom = parser.findAtomByAddress(sreloc->r_value()); - target.addend = (srcAddr + displacement) - target.atom->_objAddress; - parser.addFixups(src, ld::Fixup::kindStorePPCBranch24, target); - break; - case PPC_RELOC_LO16_SECTDIFF: - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_LO16_SECTDIFF missing following pair"; - lowBits = (instruction & 0xFFFF); - dstAddr = nextRelocValue + ((nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF)); - parser.findTargetFromAddress(sreloc->r_value(), target); - if ( target.atom != NULL ) - target.addend = dstAddr - target.atom->_objAddress; - picBase.atom = parser.findAtomByAddress(nextRelocValue); - picBase.addend = nextRelocValue - picBase.atom->_objAddress; - picBase.weakImport = false; - picBase.name = NULL; - parser.addFixups(src, ld::Fixup::kindStorePPCPicLow16, target, picBase); - break; - case PPC_RELOC_LO14_SECTDIFF: - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_LO14_SECTDIFF missing following pair"; - lowBits = (instruction & 0xFFFC); - dstAddr = nextRelocValue + ((nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF)); - parser.findTargetFromAddress(sreloc->r_value(), target); - if ( target.atom != NULL ) - target.addend = dstAddr - target.atom->_objAddress; - picBase.atom = parser.findAtomByAddress(nextRelocValue); - picBase.addend = nextRelocValue - picBase.atom->_objAddress; - picBase.weakImport = false; - picBase.name = NULL; - parser.addFixups(src, ld::Fixup::kindStorePPCPicLow14, target, picBase); - break; - case PPC_RELOC_HA16_SECTDIFF: - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_HA16_SECTDIFF missing following pair"; - lowBits = (nextRelocAddress & 0x0000FFFF); - dstAddr = nextRelocValue + (((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits); - parser.findTargetFromAddress(sreloc->r_value(), target); - if ( target.atom != NULL ) - target.addend = dstAddr - target.atom->_objAddress; - picBase.atom = parser.findAtomByAddress(nextRelocValue); - picBase.addend = nextRelocValue - picBase.atom->_objAddress; - picBase.weakImport = false; - picBase.name = NULL; - parser.addFixups(src, ld::Fixup::kindStorePPCPicHigh16AddLow, target, picBase); - break; - case PPC_RELOC_LO14: - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_LO14 missing following pair"; - lowBits = (instruction & 0xFFFC); - dstAddr = ((nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF)); - parser.findTargetFromAddress(sreloc->r_value(), dstAddr, target); - parser.addFixups(src, ld::Fixup::kindStorePPCAbsLow14, target); - break; - case PPC_RELOC_LO16: - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_LO16 missing following pair"; - lowBits = (instruction & 0xFFFF); - dstAddr = ((nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF)); - parser.findTargetFromAddress(sreloc->r_value(), dstAddr, target); - parser.addFixups(src, ld::Fixup::kindStorePPCAbsLow16, target); - break; - case PPC_RELOC_HA16: - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_HA16 missing following pair"; - lowBits = (nextRelocAddress & 0xFFFF); - dstAddr = (((instruction & 0xFFFF) << 16) + (int32_t)lowBits); - parser.findTargetFromAddress(sreloc->r_value(), dstAddr, target); - parser.addFixups(src, ld::Fixup::kindStorePPCAbsHigh16AddLow, target); - break; - case PPC_RELOC_HI16: - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_HI16 missing following pair"; - lowBits = (nextRelocAddress & 0xFFFF); - dstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF); - parser.findTargetFromAddress(sreloc->r_value(), dstAddr, target); - parser.addFixups(src, ld::Fixup::kindStorePPCAbsHigh16, target); - break; - case PPC_RELOC_SECTDIFF: - case PPC_RELOC_LOCAL_SECTDIFF: - { - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_SECTDIFF missing following pair"; - ld::Fixup::Kind kind = ld::Fixup::kindNone; - switch ( sreloc->r_length() ) { - case 0: - throw "bad length for PPC_RELOC_SECTDIFF"; - case 1: - contentValue = (int32_t)(int16_t)BigEndian::get16(*((uint16_t*)fixUpPtr)); - kind = ld::Fixup::kindStoreBigEndian16; - break; - case 2: - contentValue = BigEndian::get32(*((uint32_t*)fixUpPtr)); - kind = ld::Fixup::kindStoreBigEndian32; - break; - case 3: - contentValue = BigEndian::get64(*((uint64_t*)fixUpPtr)); - kind = ld::Fixup::kindStoreBigEndian64; - break; - break; - } - Atom* fromAtom = parser.findAtomByAddress(nextRelocValue); - Atom* targetAtom = parser.findAtomByAddress(sreloc->r_value()); - uint32_t offsetInFrom = nextRelocValue - fromAtom->_objAddress; - uint32_t offsetInTarget = sreloc->r_value() - targetAtom->_objAddress; - // check for addend encoded in the section content - int32_t addend = contentValue - (sreloc->r_value() - nextRelocValue); - if ( addend < 0 ) { - if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) { - parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom); - } - else if ( (targetAtom->combine() == ld::Atom::combineByNameAndContent) || (targetAtom->combine() == ld::Atom::combineByNameAndReferences) ) { - parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, targetAtom); - } - else { - parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, targetAtom->name()); - } - parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, offsetInTarget); - parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom); - parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom-addend); - parser.addFixup(src, ld::Fixup::k5of5, kind); - } - else { - if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) { - parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom); - } - else if ( (targetAtom->combine() == ld::Atom::combineByNameAndContent) || (targetAtom->combine() == ld::Atom::combineByNameAndReferences) ) { - parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, targetAtom); - } - else { - parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, targetAtom->name()); - } - parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, offsetInTarget+addend); - parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom); - parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom); - parser.addFixup(src, ld::Fixup::k5of5, kind); - } - } - break; - case PPC_RELOC_PAIR: - break; - case PPC_RELOC_HI16_SECTDIFF: - warning("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF"); - break; - default: - warning("unknown scattered relocation type %d", sreloc->r_type()); - } - } - return result; -} - - -template <> -bool Section::addRelocFixup(class Parser& parser, const macho_relocation_info

* reloc) -{ - return addRelocFixup_powerpc(parser, reloc); -} - - -template <> -bool Section::addRelocFixup(class Parser& parser, const macho_relocation_info

* reloc) -{ - return addRelocFixup_powerpc(parser, reloc); -} - template <> @@ -6226,7 +5702,9 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati dstAddr = ((instruction16 << 16) | other16); if ( reloc->r_extern() ) { target.addend = dstAddr; - } + if ( externSymbolIsThumbDef ) + target.addend &= -2; // remove thumb bit + } else { parser.findTargetFromAddress(dstAddr, target); if ( target.atom->isThumb() ) @@ -6239,6 +5717,8 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati dstAddr = (other16 << 16) | instruction16; if ( reloc->r_extern() ) { target.addend = dstAddr; + if ( externSymbolIsThumbDef ) + target.addend &= -2; // remove thumb bit } else { parser.findTargetFromAddress(dstAddr, target); @@ -6552,41 +6032,6 @@ bool ObjC1ClassSection::addRelocFixup(class Parser& parser, const mach return FixedSizeSection::addRelocFixup(parser, reloc); } -template <> -bool ObjC1ClassSection::addRelocFixup(class Parser& parser, const macho_relocation_info* reloc) -{ - // if this is the reloc for the super class name string, add implicit reference to super class - if ( ((reloc->r_address() & R_SCATTERED) == 0) && (reloc->r_type() == PPC_RELOC_VANILLA) ) { - assert( reloc->r_length() == 2 ); - assert( ! reloc->r_pcrel() ); - - const macho_section

* sect = this->machoSection(); - Parser::SourceLocation src; - uint32_t srcAddr = sect->addr() + reloc->r_address(); - src.atom = this->findAtomByAddress(srcAddr); - src.offsetInAtom = srcAddr - src.atom->objectAddress(); - if ( src.offsetInAtom == 4 ) { - Parser::TargetDesc stringTarget; - const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address(); - uint32_t contentValue = BigEndian::get32(*((uint32_t*)fixUpPtr)); - parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), stringTarget); - - assert(stringTarget.atom != NULL); - assert(stringTarget.atom->contentType() == ld::Atom::typeCString); - const char* superClassBaseName = (char*)stringTarget.atom->rawContentPointer(); - char* superClassName = new char[strlen(superClassBaseName) + 20]; - strcpy(superClassName, ".objc_class_name_"); - strcat(superClassName, superClassBaseName); - - parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindSetTargetAddress, false, superClassName); - } - } - - // inherited - return FixedSizeSection::addRelocFixup(parser, reloc); -} - - template @@ -6600,38 +6045,6 @@ bool Objc1ClassReferences::addRelocFixup(class Parser& parser, const macho } -template <> -bool Objc1ClassReferences::addRelocFixup(class Parser& parser, const macho_relocation_info* reloc) -{ - // add implict class refs, fixups not usable yet, so look at relocations - assert( (reloc->r_address() & R_SCATTERED) == 0 ); - assert( reloc->r_type() == PPC_RELOC_VANILLA ); - assert( reloc->r_length() == 2 ); - assert( ! reloc->r_pcrel() ); - - const macho_section

* sect = this->machoSection(); - Parser::SourceLocation src; - uint32_t srcAddr = sect->addr() + reloc->r_address(); - src.atom = this->findAtomByAddress(srcAddr); - src.offsetInAtom = srcAddr - src.atom->objectAddress(); - Parser::TargetDesc stringTarget; - const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address(); - uint32_t contentValue = BigEndian::get32(*((uint32_t*)fixUpPtr)); - parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), stringTarget); - - assert(stringTarget.atom != NULL); - assert(stringTarget.atom->contentType() == ld::Atom::typeCString); - const char* baseClassName = (char*)stringTarget.atom->rawContentPointer(); - char* objcClassName = new char[strlen(baseClassName) + 20]; - strcpy(objcClassName, ".objc_class_name_"); - strcat(objcClassName, baseClassName); - - parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindSetTargetAddress, false, objcClassName); - - // inherited - return PointerToCStringSection::addRelocFixup(parser, reloc); -} - template <> bool Objc1ClassReferences::addRelocFixup(class Parser& parser, const macho_relocation_info* reloc) @@ -6738,14 +6151,6 @@ ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, if ( mach_o::relocatable::Parser::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) ) return mach_o::relocatable::Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts); break; - case CPU_TYPE_POWERPC: - if ( mach_o::relocatable::Parser::validFile(fileContent) ) - return mach_o::relocatable::Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts); - break; - case CPU_TYPE_POWERPC64: - if ( mach_o::relocatable::Parser::validFile(fileContent) ) - return mach_o::relocatable::Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts); - break; } return NULL; } @@ -6762,10 +6167,6 @@ bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, const ParserO return ( mach_o::relocatable::Parser::validFile(fileContent) ); case CPU_TYPE_ARM: return ( mach_o::relocatable::Parser::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) ); - case CPU_TYPE_POWERPC: - return ( mach_o::relocatable::Parser::validFile(fileContent) ); - case CPU_TYPE_POWERPC64: - return ( mach_o::relocatable::Parser::validFile(fileContent) ); } return false; } @@ -6791,17 +6192,6 @@ bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* *subResult = header->cpusubtype(); return true; } - if ( mach_o::relocatable::Parser::validFile(fileContent) ) { - *result = CPU_TYPE_POWERPC; - const macho_header >* header = (const macho_header >*)fileContent; - *subResult = header->cpusubtype(); - return true; - } - if ( mach_o::relocatable::Parser::validFile(fileContent) ) { - *result = CPU_TYPE_POWERPC64; - *subResult = CPU_SUBTYPE_POWERPC_ALL; - return true; - } return false; } @@ -6819,12 +6209,6 @@ const char* archName(const uint8_t* fileContent) if ( mach_o::relocatable::Parser::validFile(fileContent, false, 0) ) { return mach_o::relocatable::Parser::fileKind(fileContent); } - if ( mach_o::relocatable::Parser::validFile(fileContent) ) { - return mach_o::relocatable::Parser::fileKind(fileContent); - } - if ( mach_o::relocatable::Parser::validFile(fileContent) ) { - return mach_o::relocatable::Parser::fileKind(fileContent); - } return NULL; } diff --git a/src/ld/passes/branch_island.cpp b/src/ld/passes/branch_island.cpp index 99b3eb8..773031e 100644 --- a/src/ld/passes/branch_island.cpp +++ b/src/ld/passes/branch_island.cpp @@ -59,42 +59,6 @@ public: static bool _s_log = false; static ld::Section _s_text_section("__TEXT", "__text", ld::Section::typeCode); -class PPCBranchIslandAtom : public ld::Atom { -public: - PPCBranchIslandAtom(const char* nm, const ld::Atom* target, TargetAndOffset finalTarget) - : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever, - ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland, - ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)), - _name(nm), - _target(target), - _finalTarget(finalTarget) { } - - virtual const ld::File* file() const { return NULL; } - virtual bool translationUnitSource(const char** dir, const char**) const - { return false; } - virtual const char* name() const { return _name; } - virtual uint64_t size() const { return 4; } - virtual uint64_t objectAddress() const { return 0; } - virtual void copyRawContent(uint8_t buffer[]) const { - int64_t displacement = _target->finalAddress() - this->finalAddress(); - const int64_t bl_sixteenMegLimit = 0x00FFFFFF; - if ( _target->contentType() == ld::Atom::typeBranchIsland ) { - // try optimizing away intermediate islands - int64_t skipToFinalDisplacement = _finalTarget.atom->finalAddress() + _finalTarget.offset - this->finalAddress(); - if ( (skipToFinalDisplacement > bl_sixteenMegLimit) && (skipToFinalDisplacement < (-bl_sixteenMegLimit)) ) { - displacement = skipToFinalDisplacement; - } - } - int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC); - OSWriteBigInt32(buffer, 0, branchInstruction); - } - virtual void setScope(Scope) { } - -private: - const char* _name; - const ld::Atom* _target; - TargetAndOffset _finalTarget; -}; class ARMtoARMBranchIslandAtom : public ld::Atom { @@ -303,10 +267,6 @@ static ld::Atom* makeBranchIsland(const Options& opts, ld::Fixup::Kind kind, int } switch ( kind ) { - case ld::Fixup::kindStorePPCBranch24: - case ld::Fixup::kindStoreTargetAddressPPCBranch24: - return new PPCBranchIslandAtom(name, nextTarget, finalTarget); - break; case ld::Fixup::kindStoreARMBranch24: case ld::Fixup::kindStoreThumbBranch22: case ld::Fixup::kindStoreTargetAddressARMBranch24: @@ -337,10 +297,6 @@ static ld::Atom* makeBranchIsland(const Options& opts, ld::Fixup::Kind kind, int static uint64_t textSizeWhenMightNeedBranchIslands(const Options& opts, bool seenThumbBranch) { switch ( opts.architecture() ) { - case CPU_TYPE_POWERPC: - case CPU_TYPE_POWERPC64: - return 16000000; - break; case CPU_TYPE_ARM: if ( ! seenThumbBranch ) return 32000000; // ARM can branch +/- 32MB @@ -358,10 +314,6 @@ static uint64_t textSizeWhenMightNeedBranchIslands(const Options& opts, bool see static uint64_t maxDistanceBetweenIslands(const Options& opts, bool seenThumbBranch) { switch ( opts.architecture() ) { - case CPU_TYPE_POWERPC: - case CPU_TYPE_POWERPC64: - return 14*1024*1024; - break; case CPU_TYPE_ARM: if ( ! seenThumbBranch ) return 30*1024*1024; // 2MB of branch islands per 32MB @@ -405,10 +357,8 @@ void doPass(const Options& opts, ld::Internal& state) if ( opts.outputKind() == Options::kObjectFile ) return; - // only PowerPC and ARM need branch islands + // only ARM needs branch islands switch ( opts.architecture() ) { - case CPU_TYPE_POWERPC: - case CPU_TYPE_POWERPC64: case CPU_TYPE_ARM: break; default: @@ -506,8 +456,6 @@ void doPass(const Options& opts, ld::Internal& state) case ld::Fixup::kindAddAddend: addend = fit->u.addend; break; - case ld::Fixup::kindStorePPCBranch24: - case ld::Fixup::kindStoreTargetAddressPPCBranch24: case ld::Fixup::kindStoreARMBranch24: case ld::Fixup::kindStoreThumbBranch22: case ld::Fixup::kindStoreTargetAddressARMBranch24: diff --git a/src/ld/passes/dtrace_dof.cpp b/src/ld/passes/dtrace_dof.cpp index f847cc0..665e3ae 100644 --- a/src/ld/passes/dtrace_dof.cpp +++ b/src/ld/passes/dtrace_dof.cpp @@ -143,13 +143,11 @@ void doPass(const Options& opts, ld::Internal& internal) for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) { switch ( fit->kind ) { case ld::Fixup::kindStoreX86DtraceCallSiteNop: - case ld::Fixup::kindStorePPCDtraceCallSiteNop: case ld::Fixup::kindStoreARMDtraceCallSiteNop: case ld::Fixup::kindStoreThumbDtraceCallSiteNop: probeSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name)); break; case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear: - case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear: case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear: case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear: isEnabledSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name)); @@ -170,10 +168,6 @@ void doPass(const Options& opts, ld::Internal& internal) ld::Fixup::Kind storeKind = ld::Fixup::kindNone; switch ( opts.architecture() ) { - case CPU_TYPE_POWERPC: - case CPU_TYPE_POWERPC64: - storeKind = ld::Fixup::kindStoreBigEndian32; - break; case CPU_TYPE_I386: case CPU_TYPE_X86_64: case CPU_TYPE_ARM: diff --git a/src/ld/passes/got.cpp b/src/ld/passes/got.cpp index bb94ddf..08eeb73 100644 --- a/src/ld/passes/got.cpp +++ b/src/ld/passes/got.cpp @@ -89,8 +89,21 @@ static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom } if ( targetOfGOT->scope() == ld::Atom::scopeGlobal ) { // cannot do LEA optimization if target is weak exported symbol - if ( (targetOfGOT->definition() == ld::Atom::definitionRegular) && (targetOfGOT->combine() == ld::Atom::combineByName) ) - *optimizable = false; + if ( (targetOfGOT->definition() == ld::Atom::definitionRegular) && (targetOfGOT->combine() == ld::Atom::combineByName) ) { + switch ( opts.outputKind() ) { + case Options::kDynamicExecutable: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kKextBundle: + *optimizable = false; + break; + case Options::kStaticExecutable: + case Options::kDyld: + case Options::kPreload: + case Options::kObjectFile: + break; + } + } // cannot do LEA optimization if target is interposable if ( opts.interposable(targetOfGOT->name()) ) *optimizable = false; diff --git a/src/ld/passes/objc.cpp b/src/ld/passes/objc.cpp index ed59193..b209b1d 100644 --- a/src/ld/passes/objc.cpp +++ b/src/ld/passes/objc.cpp @@ -1153,18 +1153,10 @@ void doPass(const Options& opts, ld::Internal& state) state.addAtom(*new ObjCImageInfoAtom(state.objcObjectConstraint, compaction, state.hasObjcReplacementClasses, opts.objCABIVersion2POverride() ? true : false)); break; - case CPU_TYPE_POWERPC: - state.addAtom(*new ObjCImageInfoAtom(state.objcObjectConstraint, compaction, - state.hasObjcReplacementClasses, false)); - break; case CPU_TYPE_ARM: state.addAtom(*new ObjCImageInfoAtom(state.objcObjectConstraint, compaction, state.hasObjcReplacementClasses, true)); break; - case CPU_TYPE_POWERPC64: - state.addAtom(*new ObjCImageInfoAtom(state.objcObjectConstraint, compaction, - state.hasObjcReplacementClasses, true)); - break; default: assert(0 && "unknown objc arch"); } @@ -1185,9 +1177,6 @@ void doPass(const Options& opts, ld::Internal& state) // disable optimization until fully tested //OptimizeCategories::doit(opts, state); break; - case CPU_TYPE_POWERPC64: - case CPU_TYPE_POWERPC: - break; default: assert(0 && "unknown objc arch"); } diff --git a/src/ld/passes/order.cpp b/src/ld/passes/order.cpp new file mode 100644 index 0000000..ce17a35 --- /dev/null +++ b/src/ld/passes/order.cpp @@ -0,0 +1,568 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2009-2011 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include +#include +#include +#include +#include + +#include +#include + +#include "ld.hpp" +#include "order.h" + +namespace ld { +namespace passes { +namespace order { + +// +// The purpose of this pass is to take the graph of all Atoms and produce an ordered +// sequence of atoms. The constraints are that: 1) all Atoms of the same Segment must +// be contiguous, 2) all Atoms of the same Section must be contigous, 3) Atoms specified +// in an order are sequenced as in the order file and before Atoms not specified, +// 4) Atoms in the same section from the same .o file should be contiguous and sequenced +// in the same order they were in the .o file, 5) Atoms in the same Section but which came +// from different .o files should be sequenced in the same order that the .o files +// were passed to the linker (i.e. command line order). +// +// The way this is implemented is that the linker passes a "base ordinal" to each File +// as it is constructed. Add each atom has an objectAddress() method. Then +// sorting is just sorting by section, then by file ordinal, then by object address. +// +// If an -order_file is specified, it gets more complicated. First, an override-ordinal map +// is created. It causes the sort routine to ignore the value returned by ordinal() and objectAddress() +// and use the override value instead. Next some Atoms must be laid out consecutively +// (e.g. hand written assembly that does not end with return, but rather falls into +// the next label). This is modeled in via a kindNoneFollowOn fixup. The use of +// kindNoneFollowOn fixups produces "clusters" of atoms that must stay together. +// If an order_file tries to move one atom, it may need to move a whole cluster. The +// algorithm to do this models clusters using two maps. The "starts" maps maps any +// atom in a cluster to the first Atom in the cluster. The "nexts" maps an Atom in a +// cluster to the next Atom in the cluster. With this in place, while processing an +// order_file, if any entry is in a cluster (in "starts" map), then the entire cluster is +// given ordinal overrides. +// + +class Layout +{ +public: + Layout(const Options& opts, ld::Internal& state); + void doPass(); +private: + + class Comparer { + public: + Comparer(const Layout& l) : _layout(l) {} + bool operator()(const ld::Atom* left, const ld::Atom* right); + private: + const Layout& _layout; + }; + + class CStringEquals { + public: + bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } + }; + typedef __gnu_cxx::hash_map, CStringEquals> NameToAtom; + + typedef std::map AtomToAtom; + + typedef std::map AtomToOrdinal; + + const ld::Atom* findAtom(const Options::OrderedSymbol& orderedSymbol); + void buildNameTable(); + void buildFollowOnTables(); + void buildOrdinalOverrideMap(); + const ld::Atom* follower(const ld::Atom* atom); + static bool matchesObjectFile(const ld::Atom* atom, const char* objectFileLeafName); + bool possibleToOrder(const ld::Internal::FinalSection*); + + const Options& _options; + ld::Internal& _state; + AtomToAtom _followOnStarts; + AtomToAtom _followOnNexts; + NameToAtom _nameTable; + std::vector _nameCollisionAtoms; + AtomToOrdinal _ordinalOverrideMap; + Comparer _comparer; + bool _haveOrderFile; + + static bool _s_log; +}; + +bool Layout::_s_log = false; + +Layout::Layout(const Options& opts, ld::Internal& state) + : _options(opts), _state(state), _comparer(*this), _haveOrderFile(opts.orderedSymbolsCount() != 0) +{ +} + + +bool Layout::Comparer::operator()(const ld::Atom* left, const ld::Atom* right) +{ + if ( left == right ) + return false; + + // magic section$start symbol always sorts to the start of its section + if ( left->contentType() == ld::Atom::typeSectionStart ) + return true; + if ( right->contentType() == ld::Atom::typeSectionStart ) + return false; + + // if an -order_file is specified, then sorting is altered to sort those symbols first + if ( _layout._haveOrderFile ) { + AtomToOrdinal::const_iterator leftPos = _layout._ordinalOverrideMap.find(left); + AtomToOrdinal::const_iterator rightPos = _layout._ordinalOverrideMap.find(right); + AtomToOrdinal::const_iterator end = _layout._ordinalOverrideMap.end(); + if ( leftPos != end ) { + if ( rightPos != end ) { + // both left and right are overridden, so compare overridden ordinals + return leftPos->second < rightPos->second; + } + else { + // left is overridden and right is not, so left < right + return true; + } + } + else { + if ( rightPos != end ) { + // right is overridden and left is not, so right < left + return false; + } + else { + // neither are overridden, + // fall into default sorting below + } + } + } + + // magic section$end symbol always sorts to the end of its section + if ( left->contentType() == ld::Atom::typeSectionEnd ) + return false; + if ( right->contentType() == ld::Atom::typeSectionEnd ) + return true; + + // the __common section can have real or tentative definitions + // we want the real ones to sort before tentative ones + bool leftIsTent = (left->definition() == ld::Atom::definitionTentative); + bool rightIsTent = (right->definition() == ld::Atom::definitionTentative); + if ( leftIsTent != rightIsTent ) + return rightIsTent; + +#if 0 + // initializers are auto sorted to start of section + if ( !fInitializerSet.empty() ) { + bool leftFirst = (fInitializerSet.count(left) != 0); + bool rightFirst = (fInitializerSet.count(right) != 0); + if ( leftFirst != rightFirst ) + return leftFirst; + } + + // terminators are auto sorted to end of section + if ( !fTerminatorSet.empty() ) { + bool leftLast = (fTerminatorSet.count(left) != 0); + bool rightLast = (fTerminatorSet.count(right) != 0); + if ( leftLast != rightLast ) + return rightLast; + } +#endif + + // sort by .o order + const ld::File* leftFile = left->file(); + const ld::File* rightFile = right->file(); + uint32_t leftFileOrdinal = (leftFile != NULL) ? leftFile->ordinal() : 0; + uint32_t rightFileOrdinal = (rightFile != NULL) ? rightFile->ordinal() : 0; + if ( leftFileOrdinal != rightFileOrdinal ) + return leftFileOrdinal< rightFileOrdinal; + + // tentative defintions have no address in .o file, they are traditionally laid out by name + if ( leftIsTent && rightIsTent ) + return (strcmp(left->name(), right->name()) < 0); + + // lastly sort by atom address + int64_t addrDiff = left->objectAddress() - right->objectAddress(); + if ( addrDiff == 0 ) { + // have same address so one might be an alias, and aliases need to sort before target + bool leftIsAlias = left->isAlias(); + bool rightIsAlias = right->isAlias(); + if ( leftIsAlias != rightIsAlias ) + return leftIsAlias; + + // both at same address, sort by name + return (strcmp(left->name(), right->name()) < 0); + } + return (addrDiff < 0); +} + +bool Layout::matchesObjectFile(const ld::Atom* atom, const char* objectFileLeafName) +{ + if ( objectFileLeafName == NULL ) + return true; + const char* atomFullPath = atom->file()->path(); + const char* lastSlash = strrchr(atomFullPath, '/'); + if ( lastSlash != NULL ) { + if ( strcmp(&lastSlash[1], objectFileLeafName) == 0 ) + return true; + } + else { + if ( strcmp(atomFullPath, objectFileLeafName) == 0 ) + return true; + } + return false; +} + + +bool Layout::possibleToOrder(const ld::Internal::FinalSection* sect) +{ + // atoms in only some sections can have order_file applied + switch ( sect->type() ) { + case ld::Section::typeUnclassified: + case ld::Section::typeCode: + case ld::Section::typeZeroFill: + return true; + case ld::Section::typeImportProxies: + return false; + default: + // if section has command line aliases, then we must apply ordering so aliases layout before targets + if ( _options.haveCmdLineAliases() ) { + for (std::vector::const_iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) { + const ld::Atom* atom = *ait; + if ( atom->isAlias() ) + return true; + } + } + break; + } + return false; +} + +void Layout::buildNameTable() +{ + for (std::vector::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) { + ld::Internal::FinalSection* sect = *sit; + // some sections are not worth scanning for names + if ( ! possibleToOrder(sect) ) + continue; + for (std::vector::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) { + const ld::Atom* atom = *ait; + if ( atom->symbolTableInclusion() == ld::Atom::symbolTableIn ) { + const char* name = atom->name(); + if ( name != NULL) { + // static function or data + NameToAtom::iterator pos = _nameTable.find(name); + if ( pos == _nameTable.end() ) + _nameTable[name] = atom; + else { + const ld::Atom* existing = _nameTable[name]; + if ( existing != NULL ) { + _nameCollisionAtoms.push_back(existing); + _nameTable[name] = NULL; // collision, denote with NULL + } + _nameCollisionAtoms.push_back(atom); + } + } + } + } + } + if ( _s_log ) { + fprintf(stderr, "buildNameTable() _nameTable:\n"); + for(NameToAtom::iterator it=_nameTable.begin(); it != _nameTable.end(); ++it) + fprintf(stderr, " %p <- %s\n", it->second, it->first); + fprintf(stderr, "buildNameTable() _nameCollisionAtoms:\n"); + for(std::vector::iterator it=_nameCollisionAtoms.begin(); it != _nameCollisionAtoms.end(); ++it) + fprintf(stderr, " %p, %s\n", *it, (*it)->name()); + } +} + + +const ld::Atom* Layout::findAtom(const Options::OrderedSymbol& orderedSymbol) +{ + // look for name in _nameTable + NameToAtom::iterator pos = _nameTable.find(orderedSymbol.symbolName); + if ( pos != _nameTable.end() ) { + if ( (pos->second != NULL) && matchesObjectFile(pos->second, orderedSymbol.objectFileName) ) { + //fprintf(stderr, "found %s in hash table\n", orderedSymbol.symbolName); + return pos->second; + } + if ( pos->second == NULL ) { + // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way + if ( ( orderedSymbol.objectFileName == NULL) && _options.printOrderFileStatistics() ) { + warning("%s specified in order_file but it exists in multiple .o files. " + "Prefix symbol with .o filename in order_file to disambiguate", orderedSymbol.symbolName); + } + for (std::vector::iterator it=_nameCollisionAtoms.begin(); it != _nameCollisionAtoms.end(); it++) { + const ld::Atom* atom = *it; + if ( strcmp(atom->name(), orderedSymbol.symbolName) == 0 ) { + if ( matchesObjectFile(atom, orderedSymbol.objectFileName) ) { + return atom; + } + } + } + } + } + + return NULL; +} + +const ld::Atom* Layout::follower(const ld::Atom* atom) +{ + for (const ld::Atom* a = _followOnStarts[atom]; a != NULL; a = _followOnNexts[a]) { + assert(a != NULL); + if ( _followOnNexts[a] == atom ) { + return a; + } + } + // no follower, first in chain + return NULL; +} + +void Layout::buildFollowOnTables() +{ + // if no -order_file, then skip building follow on table + if ( ! _haveOrderFile ) + return; + + // first make a pass to find all follow-on references and build start/next maps + // which are a way to represent clusters of atoms that must layout together + for (std::vector::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) { + ld::Internal::FinalSection* sect = *sit; + if ( !possibleToOrder(sect) ) + continue; + for (std::vector::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) { + const ld::Atom* atom = *ait; + for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) { + if ( fit->kind == ld::Fixup::kindNoneFollowOn ) { + assert(fit->binding == ld::Fixup::bindingDirectlyBound); + const ld::Atom* followOnAtom = fit->u.target; + if ( _s_log ) fprintf(stderr, "ref %p %s -> %p %s\n", atom, atom->name(), followOnAtom, followOnAtom->name()); + assert(_followOnNexts.count(atom) == 0); + _followOnNexts[atom] = followOnAtom; + if ( _followOnStarts.count(atom) == 0 ) { + // first time atom has been seen, make it start of chain + _followOnStarts[atom] = atom; + if ( _s_log ) fprintf(stderr, " start %s -> %s\n", atom->name(), atom->name()); + } + if ( _followOnStarts.count(followOnAtom) == 0 ) { + // first time followOnAtom has been seen, make atom start of chain + _followOnStarts[followOnAtom] = _followOnStarts[atom]; + if ( _s_log ) fprintf(stderr, " start %s -> %s\n", followOnAtom->name(), _followOnStarts[atom]->name()); + } + else { + if ( _followOnStarts[followOnAtom] == followOnAtom ) { + // followOnAtom atom already start of another chain, hook together + // and change all to use atom as start + const ld::Atom* a = followOnAtom; + while ( true ) { + assert(_followOnStarts[a] == followOnAtom); + _followOnStarts[a] = _followOnStarts[atom]; + if ( _s_log ) fprintf(stderr, " adjust start for %s -> %s\n", a->name(), _followOnStarts[atom]->name()); + AtomToAtom::iterator pos = _followOnNexts.find(a); + if ( pos != _followOnNexts.end() ) + a = pos->second; + else + break; + } + } + else { + // attempt to insert atom into existing followOn chain + const ld::Atom* curPrevToFollowOnAtom = this->follower(followOnAtom); + assert(curPrevToFollowOnAtom != NULL); + assert((atom->size() == 0) || (curPrevToFollowOnAtom->size() == 0)); + if ( atom->size() == 0 ) { + // insert alias into existing chain right before followOnAtom + _followOnNexts[curPrevToFollowOnAtom] = atom; + _followOnNexts[atom] = followOnAtom; + _followOnStarts[atom] = _followOnStarts[followOnAtom]; + } + else { + // insert real atom into existing chain right before alias of followOnAtom + const ld::Atom* curPrevPrevToFollowOn = this->follower(curPrevToFollowOnAtom); + if ( curPrevPrevToFollowOn == NULL ) { + // nothing previous, so make this a start of a new chain + _followOnNexts[atom] = curPrevToFollowOnAtom; + for (const ld::Atom* a = atom; a != NULL; a = _followOnNexts[a]) { + if ( _s_log ) fprintf(stderr, " adjust start for %s -> %s\n", a->name(), atom->name()); + _followOnStarts[a] = atom; + } + } + else { + // is previous, insert into existing chain before previous + _followOnNexts[curPrevPrevToFollowOn] = atom; + _followOnNexts[atom] = curPrevToFollowOnAtom; + _followOnStarts[atom] = _followOnStarts[curPrevToFollowOnAtom]; + } + } + } + } + } + } + } + } + + if ( _s_log ) { + for(AtomToAtom::iterator it = _followOnStarts.begin(); it != _followOnStarts.end(); ++it) + fprintf(stderr, "start %s -> %s\n", it->first->name(), it->second->name()); + + for(AtomToAtom::iterator it = _followOnNexts.begin(); it != _followOnNexts.end(); ++it) + fprintf(stderr, "next %s -> %s\n", it->first->name(), (it->second != NULL) ? it->second->name() : "null"); + } +} + + +class InSet +{ +public: + InSet(const std::set& theSet) : _set(theSet) {} + + bool operator()(const ld::Atom* atom) const { + return ( _set.count(atom) != 0 ); + } +private: + const std::set& _set; +}; + + +void Layout::buildOrdinalOverrideMap() +{ + // if no -order_file, then skip building override map + if ( ! _haveOrderFile ) + return; + + // build fast name->atom table + this->buildNameTable(); + + // handle .o files that cannot have their atoms rearranged + // with the start/next maps of follow-on atoms we can process the order file and produce override ordinals + uint32_t index = 0; + uint32_t matchCount = 0; + std::set moveToData; + for(Options::OrderedSymbolsIterator it = _options.orderedSymbolsBegin(); it != _options.orderedSymbolsEnd(); ++it) { + const ld::Atom* atom = this->findAtom(*it); + if ( atom != NULL ) { + // When order file used on data, turn ordered zero fill symbols into zero data + switch ( atom->section().type() ) { + case ld::Section::typeZeroFill: + case ld::Section::typeTentativeDefs: + if ( atom->size() <= 512 ) + moveToData.insert(atom); + break; + default: + break; + } + + AtomToAtom::iterator start = _followOnStarts.find(atom); + if ( start != _followOnStarts.end() ) { + // this symbol for the order file corresponds to an atom that is in a cluster that must lay out together + for(const ld::Atom* nextAtom = start->second; nextAtom != NULL; nextAtom = _followOnNexts[nextAtom]) { + AtomToOrdinal::iterator pos = _ordinalOverrideMap.find(nextAtom); + if ( pos == _ordinalOverrideMap.end() ) { + _ordinalOverrideMap[nextAtom] = index++; + if (_s_log ) fprintf(stderr, "override ordinal %u assigned to %s in cluster from %s\n", index, nextAtom->name(), nextAtom->file()->path()); + } + else { + if (_s_log ) fprintf(stderr, "could not order %s as %u because it was already laid out earlier by %s as %u\n", + atom->name(), index, _followOnStarts[atom]->name(), _ordinalOverrideMap[atom] ); + } + } + } + else { + _ordinalOverrideMap[atom] = index; + if (_s_log ) fprintf(stderr, "override ordinal %u assigned to %s from %s\n", index, atom->name(), atom->file()->path()); + } + ++matchCount; + } + else { + if ( _options.printOrderFileStatistics() ) { + if ( it->objectFileName == NULL ) + warning("can't find match for order_file entry: %s", it->symbolName); + else + warning("can't find match for order_file entry: %s/%s", it->objectFileName, it->symbolName); + } + } + ++index; + } + if ( _options.printOrderFileStatistics() && (_options.orderedSymbolsCount() != matchCount) ) { + warning("only %u out of %lu order_file symbols were applicable", matchCount, _options.orderedSymbolsCount() ); + } + + + // When order file used on data, turn ordered zero fill symbols into zeroed data + if ( ! moveToData.empty() ) { + for (std::vector::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) { + ld::Internal::FinalSection* sect = *sit; + switch ( sect->type() ) { + case ld::Section::typeZeroFill: + case ld::Section::typeTentativeDefs: + sect->atoms.erase(std::remove_if(sect->atoms.begin(), sect->atoms.end(), InSet(moveToData)), sect->atoms.end()); + break; + case ld::Section::typeUnclassified: + if ( (strcmp(sect->sectionName(), "__data") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) ) + sect->atoms.insert(sect->atoms.end(), moveToData.begin(), moveToData.end()); + break; + default: + break; + } + } + } + +} + +void Layout::doPass() +{ + // handle .o files that cannot have their atoms rearranged + this->buildFollowOnTables(); + + // assign new ordinal value to all ordered atoms + this->buildOrdinalOverrideMap(); + + // sort atoms in each section + for (std::vector::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) { + ld::Internal::FinalSection* sect = *sit; + std::sort(sect->atoms.begin(), sect->atoms.end(), _comparer); + } + + //fprintf(stderr, "Sorted atoms:\n"); + //for (std::vector::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) { + // ld::Internal::FinalSection* sect = *sit; + // for (std::vector::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) { + // const ld::Atom* atom = *ait; + // fprintf(stderr, "\t%s\t%s\n", sect->sectionName(), atom->name()); + // } + //} + +} + + +void doPass(const Options& opts, ld::Internal& state) +{ + Layout layout(opts, state); + layout.doPass(); +} + + +} // namespace order_file +} // namespace passes +} // namespace ld diff --git a/src/ld/passes/order.h b/src/ld/passes/order.h new file mode 100644 index 0000000..a3608e1 --- /dev/null +++ b/src/ld/passes/order.h @@ -0,0 +1,45 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2009-2011 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#ifndef __ORDER_H__ +#define __ORDER_H__ + +#include "Options.h" +#include "ld.hpp" + + +namespace ld { +namespace passes { +namespace order { + +// called by linker to re-arrange atoms to improve locality and performance +extern void doPass(const Options& opts, ld::Internal& internal); + + +} // namespace order +} // namespace passes +} // namespace ld + +#endif // __ORDER_H__ diff --git a/src/ld/passes/order_file.cpp b/src/ld/passes/order_file.cpp deleted file mode 100644 index 5e814bd..0000000 --- a/src/ld/passes/order_file.cpp +++ /dev/null @@ -1,544 +0,0 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2009 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include -#include -#include -#include -#include - -#include -#include - -#include "ld.hpp" -#include "order_file.h" - -namespace ld { -namespace passes { -namespace order_file { - -// -// The purpose of this pass is to take the graph of all Atoms and produce an ordered -// sequence of atoms. The constraints are that: 1) all Atoms of the same Segment must -// be contiguous, 2) all Atoms of the same Section must be contigous, 3) Atoms specified -// in an order_file are sequenced as in the order_file and before Atoms not specified, -// 4) Atoms in the same section from the same .o file should be contiguous and sequenced -// in the same order they were in the .o file, 5) Atoms in the same Section but which came -// from different .o files should be sequenced in the same order that the .o files -// were passed to the linker (i.e. command line order). -// -// The way this is implemented is that the linker passes a "base ordinal" to each File -// as it is constructed. Add each atom has an objectAddress() method. Then -// sorting is just sorting by section, then by file ordinal, then by object address. -// -// If an order_file is specified, it gets more complicated. First, an override-ordinal map -// is created. It causes the sort routine to ignore the value returned by ordinal() and objectAddress() -// and use the override value instead. Next some Atoms must be layed out consecutively -// (e.g. hand written assembly that does not end with return, but rather falls into -// the next label). This is modeled in via a kindNoneFollowOn fixup. The use of -// kindNoneFollowOn fixups produces "clusters" of atoms that must stay together. -// If an order_file tries to move one atom, it may need to move a whole cluster. The -// algorithm to do this models clusters using two maps. The "starts" maps maps any -// atom in a cluster to the first Atom in the cluster. The "nexts" maps an Atom in a -// cluster to the next Atom in the cluster. With this in place, while processing an -// order_file, if any entry is in a cluster (in "starts" map), then the entire cluster is -// given ordinal overrides. -// - -class Layout -{ -public: - Layout(const Options& opts, ld::Internal& state); - void doPass(); -private: - - class Comparer { - public: - Comparer(const Layout& l) : _layout(l) {} - bool operator()(const ld::Atom* left, const ld::Atom* right); - private: - const Layout& _layout; - }; - - class CStringEquals { - public: - bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } - }; - typedef __gnu_cxx::hash_map, CStringEquals> NameToAtom; - - typedef std::map AtomToAtom; - - typedef std::map AtomToOrdinal; - - const ld::Atom* findAtom(const Options::OrderedSymbol& orderedSymbol); - void buildNameTable(); - void buildFollowOnTables(); - void buildOrdinalOverrideMap(); - const ld::Atom* follower(const ld::Atom* atom); - static bool matchesObjectFile(const ld::Atom* atom, const char* objectFileLeafName); - bool orderableSection(const ld::Internal::FinalSection*); - - const Options& _options; - ld::Internal& _state; - AtomToAtom _followOnStarts; - AtomToAtom _followOnNexts; - NameToAtom _nameTable; - std::vector _nameCollisionAtoms; - AtomToOrdinal _ordinalOverrideMap; - Comparer _comparer; - bool _haveOrderFile; - - static bool _s_log; -}; - -bool Layout::_s_log = false; - -Layout::Layout(const Options& opts, ld::Internal& state) - : _options(opts), _state(state), _comparer(*this), _haveOrderFile(opts.orderedSymbolsCount() != 0) -{ -} - - -bool Layout::Comparer::operator()(const ld::Atom* left, const ld::Atom* right) -{ - if ( left == right ) - return false; - - // magic section$start symbol always sorts to the start of its section - if ( left->contentType() == ld::Atom::typeSectionStart ) - return true; - if ( right->contentType() == ld::Atom::typeSectionStart ) - return false; - - // if a -order_file is specified, then sorting is altered to sort those symbols first - if ( _layout._haveOrderFile ) { - AtomToOrdinal::const_iterator leftPos = _layout._ordinalOverrideMap.find(left); - AtomToOrdinal::const_iterator rightPos = _layout._ordinalOverrideMap.find(right); - AtomToOrdinal::const_iterator end = _layout._ordinalOverrideMap.end(); - if ( leftPos != end ) { - if ( rightPos != end ) { - // both left and right are overridden, so compare overridden ordinals - return leftPos->second < rightPos->second; - } - else { - // left is overridden and right is not, so left < right - return true; - } - } - else { - if ( rightPos != end ) { - // right is overridden and left is not, so right < left - return false; - } - else { - // neither are overridden, - // fall into default sorting below - } - } - } - - // magic section$end symbol always sorts to the end of its section - if ( left->contentType() == ld::Atom::typeSectionEnd ) - return false; - if ( right->contentType() == ld::Atom::typeSectionEnd ) - return true; - - // the __common section can have real or tentative definitions - // we want the real ones to sort before tentative ones - bool leftIsTent = (left->definition() == ld::Atom::definitionTentative); - bool rightIsTent = (right->definition() == ld::Atom::definitionTentative); - if ( leftIsTent != rightIsTent ) - return rightIsTent; - -#if 0 - // initializers are auto sorted to start of section - if ( !fInitializerSet.empty() ) { - bool leftFirst = (fInitializerSet.count(left) != 0); - bool rightFirst = (fInitializerSet.count(right) != 0); - if ( leftFirst != rightFirst ) - return leftFirst; - } - - // terminators are auto sorted to end of section - if ( !fTerminatorSet.empty() ) { - bool leftLast = (fTerminatorSet.count(left) != 0); - bool rightLast = (fTerminatorSet.count(right) != 0); - if ( leftLast != rightLast ) - return rightLast; - } -#endif - - // sort by .o order - uint32_t leftFileOrdinal = left->file()->ordinal(); - uint32_t rightFileOrdinal = right->file()->ordinal(); - if ( leftFileOrdinal != rightFileOrdinal ) - return leftFileOrdinal< rightFileOrdinal; - - // tentative defintions have no address in .o file, they are traditionally laid out by name - if ( leftIsTent && rightIsTent ) - return (strcmp(left->name(), right->name()) < 0); - - // lastly sort by atom address - int64_t addrDiff = left->objectAddress() - right->objectAddress(); - if ( addrDiff == 0 ) { - // have same address so one might be an alias, and aliases need to sort before target - bool leftIsAlias = left->isAlias(); - bool rightIsAlias = right->isAlias(); - if ( leftIsAlias != rightIsAlias ) - return leftIsAlias; - - // both at same address, sort by name - return (strcmp(left->name(), right->name()) < 0); - } - return (addrDiff < 0); -} - -bool Layout::matchesObjectFile(const ld::Atom* atom, const char* objectFileLeafName) -{ - if ( objectFileLeafName == NULL ) - return true; - const char* atomFullPath = atom->file()->path(); - const char* lastSlash = strrchr(atomFullPath, '/'); - if ( lastSlash != NULL ) { - if ( strcmp(&lastSlash[1], objectFileLeafName) == 0 ) - return true; - } - else { - if ( strcmp(atomFullPath, objectFileLeafName) == 0 ) - return true; - } - return false; -} - - -bool Layout::orderableSection(const ld::Internal::FinalSection* sect) -{ - // atoms in only some sections are ordered - switch ( sect->type() ) { - case ld::Section::typeUnclassified: - case ld::Section::typeCode: - case ld::Section::typeZeroFill: - return true; - case ld::Section::typeImportProxies: - return false; - default: - // if section has command line aliases, then we must apply ordering so aliases layout before targets - if ( _options.haveCmdLineAliases() ) { - for (std::vector::const_iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) { - const ld::Atom* atom = *ait; - if ( atom->isAlias() ) - return true; - } - } - break; - } - return false; -} - -void Layout::buildNameTable() -{ - for (std::vector::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) { - ld::Internal::FinalSection* sect = *sit; - // atoms in some special sections are never ordered - if ( ! orderableSection(sect) ) - continue; - for (std::vector::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) { - const ld::Atom* atom = *ait; - if ( atom->symbolTableInclusion() == ld::Atom::symbolTableIn ) { - const char* name = atom->name(); - if ( name != NULL) { - // static function or data - NameToAtom::iterator pos = _nameTable.find(name); - if ( pos == _nameTable.end() ) - _nameTable[name] = atom; - else { - const ld::Atom* existing = _nameTable[name]; - if ( existing != NULL ) { - _nameCollisionAtoms.push_back(existing); - _nameTable[name] = NULL; // collision, denote with NULL - } - _nameCollisionAtoms.push_back(atom); - } - } - } - } - } - if ( _s_log ) { - fprintf(stderr, "buildNameTable() _nameTable:\n"); - for(NameToAtom::iterator it=_nameTable.begin(); it != _nameTable.end(); ++it) - fprintf(stderr, " %p <- %s\n", it->second, it->first); - fprintf(stderr, "buildNameTable() _nameCollisionAtoms:\n"); - for(std::vector::iterator it=_nameCollisionAtoms.begin(); it != _nameCollisionAtoms.end(); ++it) - fprintf(stderr, " %p, %s\n", *it, (*it)->name()); - } -} - - -const ld::Atom* Layout::findAtom(const Options::OrderedSymbol& orderedSymbol) -{ - // look for name in _nameTable - NameToAtom::iterator pos = _nameTable.find(orderedSymbol.symbolName); - if ( pos != _nameTable.end() ) { - if ( (pos->second != NULL) && matchesObjectFile(pos->second, orderedSymbol.objectFileName) ) { - //fprintf(stderr, "found %s in hash table\n", orderedSymbol.symbolName); - return pos->second; - } - if ( pos->second == NULL ) { - // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way - if ( ( orderedSymbol.objectFileName == NULL) && _options.printOrderFileStatistics() ) { - warning("%s specified in order_file but it exists in multiple .o files. " - "Prefix symbol with .o filename in order_file to disambiguate", orderedSymbol.symbolName); - } - for (std::vector::iterator it=_nameCollisionAtoms.begin(); it != _nameCollisionAtoms.end(); it++) { - const ld::Atom* atom = *it; - if ( strcmp(atom->name(), orderedSymbol.symbolName) == 0 ) { - if ( matchesObjectFile(atom, orderedSymbol.objectFileName) ) { - return atom; - } - } - } - } - } - - return NULL; -} - -const ld::Atom* Layout::follower(const ld::Atom* atom) -{ - for (const ld::Atom* a = _followOnStarts[atom]; a != NULL; a = _followOnNexts[a]) { - assert(a != NULL); - if ( _followOnNexts[a] == atom ) { - return a; - } - } - // no follower, first in chain - return NULL; -} - -void Layout::buildFollowOnTables() -{ - // first make a pass to find all follow-on references and build start/next maps - // which are a way to represent clusters of atoms that must layout together - for (std::vector::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) { - ld::Internal::FinalSection* sect = *sit; - if ( !orderableSection(sect) ) - continue; - for (std::vector::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) { - const ld::Atom* atom = *ait; - for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) { - if ( fit->kind == ld::Fixup::kindNoneFollowOn ) { - assert(fit->binding == ld::Fixup::bindingDirectlyBound); - const ld::Atom* followOnAtom = fit->u.target; - if ( _s_log ) fprintf(stderr, "ref %p %s -> %p %s\n", atom, atom->name(), followOnAtom, followOnAtom->name()); - assert(_followOnNexts.count(atom) == 0); - _followOnNexts[atom] = followOnAtom; - if ( _followOnStarts.count(atom) == 0 ) { - // first time atom has been seen, make it start of chain - _followOnStarts[atom] = atom; - if ( _s_log ) fprintf(stderr, " start %s -> %s\n", atom->name(), atom->name()); - } - if ( _followOnStarts.count(followOnAtom) == 0 ) { - // first time followOnAtom has been seen, make atom start of chain - _followOnStarts[followOnAtom] = _followOnStarts[atom]; - if ( _s_log ) fprintf(stderr, " start %s -> %s\n", followOnAtom->name(), _followOnStarts[atom]->name()); - } - else { - if ( _followOnStarts[followOnAtom] == followOnAtom ) { - // followOnAtom atom already start of another chain, hook together - // and change all to use atom as start - const ld::Atom* a = followOnAtom; - while ( true ) { - assert(_followOnStarts[a] == followOnAtom); - _followOnStarts[a] = _followOnStarts[atom]; - if ( _s_log ) fprintf(stderr, " adjust start for %s -> %s\n", a->name(), _followOnStarts[atom]->name()); - AtomToAtom::iterator pos = _followOnNexts.find(a); - if ( pos != _followOnNexts.end() ) - a = pos->second; - else - break; - } - } - else { - // attempt to insert atom into existing followOn chain - const ld::Atom* curPrevToFollowOnAtom = this->follower(followOnAtom); - assert(curPrevToFollowOnAtom != NULL); - assert((atom->size() == 0) || (curPrevToFollowOnAtom->size() == 0)); - if ( atom->size() == 0 ) { - // insert alias into existing chain right before followOnAtom - _followOnNexts[curPrevToFollowOnAtom] = atom; - _followOnNexts[atom] = followOnAtom; - _followOnStarts[atom] = _followOnStarts[followOnAtom]; - } - else { - // insert real atom into existing chain right before alias of followOnAtom - const ld::Atom* curPrevPrevToFollowOn = this->follower(curPrevToFollowOnAtom); - if ( curPrevPrevToFollowOn == NULL ) { - // nothing previous, so make this a start of a new chain - _followOnNexts[atom] = curPrevToFollowOnAtom; - for (const ld::Atom* a = atom; a != NULL; a = _followOnNexts[a]) { - if ( _s_log ) fprintf(stderr, " adjust start for %s -> %s\n", a->name(), atom->name()); - _followOnStarts[a] = atom; - } - } - else { - // is previous, insert into existing chain before previous - _followOnNexts[curPrevPrevToFollowOn] = atom; - _followOnNexts[atom] = curPrevToFollowOnAtom; - _followOnStarts[atom] = _followOnStarts[curPrevToFollowOnAtom]; - } - } - } - } - } - } - } - } - - if ( _s_log ) { - for(AtomToAtom::iterator it = _followOnStarts.begin(); it != _followOnStarts.end(); ++it) - fprintf(stderr, "start %s -> %s\n", it->first->name(), it->second->name()); - - for(AtomToAtom::iterator it = _followOnNexts.begin(); it != _followOnNexts.end(); ++it) - fprintf(stderr, "next %s -> %s\n", it->first->name(), (it->second != NULL) ? it->second->name() : "null"); - } -} - -void Layout::buildOrdinalOverrideMap() -{ - // if no -order_file, then skip building override map - if ( ! _haveOrderFile ) - return; - - // build fast name->atom table - this->buildNameTable(); - - // handle .o files that cannot have their atoms rearranged - // with the start/next maps of follow-on atoms we can process the order file and produce override ordinals - uint32_t index = 0; - uint32_t matchCount = 0; - for(Options::OrderedSymbolsIterator it = _options.orderedSymbolsBegin(); it != _options.orderedSymbolsEnd(); ++it) { - const ld::Atom* atom = this->findAtom(*it); - if ( atom != NULL ) { - AtomToAtom::iterator start = _followOnStarts.find(atom); - if ( start != _followOnStarts.end() ) { - // this symbol for the order file corresponds to an atom that is in a cluster that must lay out together - for(const ld::Atom* nextAtom = start->second; nextAtom != NULL; nextAtom = _followOnNexts[nextAtom]) { - AtomToOrdinal::iterator pos = _ordinalOverrideMap.find(nextAtom); - if ( pos == _ordinalOverrideMap.end() ) { - _ordinalOverrideMap[nextAtom] = index++; - if (_s_log ) fprintf(stderr, "override ordinal %u assigned to %s in cluster from %s\n", index, nextAtom->name(), nextAtom->file()->path()); - } - else { - if (_s_log ) fprintf(stderr, "could not order %s as %u because it was already laid out earlier by %s as %u\n", - atom->name(), index, _followOnStarts[atom]->name(), _ordinalOverrideMap[atom] ); - } - } - } - else { - _ordinalOverrideMap[atom] = index; - if (_s_log ) fprintf(stderr, "override ordinal %u assigned to %s from %s\n", index, atom->name(), atom->file()->path()); - } - ++matchCount; - } - else { - if ( _options.printOrderFileStatistics() ) { - if ( it->objectFileName == NULL ) - warning("can't find match for order_file entry: %s", it->symbolName); - else - warning("can't find match for order_file entry: %s/%s", it->objectFileName, it->symbolName); - } - } - ++index; - } - if ( _options.printOrderFileStatistics() && (_options.orderedSymbolsCount() != matchCount) ) { - warning("only %u out of %lu order_file symbols were applicable", matchCount, _options.orderedSymbolsCount() ); - } - - -} - -void Layout::doPass() -{ - // handle .o files that cannot have their atoms rearranged - this->buildFollowOnTables(); - - // - this->buildOrdinalOverrideMap(); - - - // sort atoms in each section - for (std::vector::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) { - ld::Internal::FinalSection* sect = *sit; - if ( orderableSection(sect) ) { - std::sort(sect->atoms.begin(), sect->atoms.end(), _comparer); - } - else { - // bubble sort any typeSectionStart atom to the beginning - bool moving = false; - for (int i=sect->atoms.size()-1; i >= 0; --i) { - if ( moving ) { - const ld::Atom* temp = sect->atoms[i]; - sect->atoms[i] = sect->atoms[i+1]; - sect->atoms[i+1] = temp; - } - if ( sect->atoms[i]->contentType() == ld::Atom::typeSectionStart ) - moving = true; - } - // bubble sort any typeSectionEnd atom to the end - moving = false; - for (unsigned int i=sect->atoms.size(); i < sect->atoms.size(); ++i) { - if ( moving ) { - const ld::Atom* temp = sect->atoms[i]; - sect->atoms[i] = sect->atoms[i-1]; - sect->atoms[i-1] = temp; - } - if ( sect->atoms[i]->contentType() == ld::Atom::typeSectionEnd ) - moving = true; - } - } - } - - //fprintf(stderr, "Sorted atoms:\n"); - //for (std::vector::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) { - // ld::Internal::FinalSection* sect = *sit; - // for (std::vector::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) { - // const ld::Atom* atom = *ait; - // fprintf(stderr, "\t%s\t%s\n", sect->sectionName(), atom->name()); - // } - //} - -} - - -void doPass(const Options& opts, ld::Internal& state) -{ - Layout layout(opts, state); - layout.doPass(); -} - - -} // namespace order_file -} // namespace passes -} // namespace ld diff --git a/src/ld/passes/order_file.h b/src/ld/passes/order_file.h deleted file mode 100644 index 7a2aa87..0000000 --- a/src/ld/passes/order_file.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2009 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#ifndef __ORDER_FILE_H__ -#define __ORDER_FILE_H__ - -#include "Options.h" -#include "ld.hpp" - - -namespace ld { -namespace passes { -namespace order_file { - -// called by linker to re-arrange atoms to improve locality and performance -extern void doPass(const Options& opts, ld::Internal& internal); - - -} // namespace order_file -} // namespace passes -} // namespace ld - -#endif // __ORDER_FILE_H__ diff --git a/src/ld/passes/stubs/stub_ppc_classic.hpp b/src/ld/passes/stubs/stub_ppc_classic.hpp deleted file mode 100644 index 6862b60..0000000 --- a/src/ld/passes/stubs/stub_ppc_classic.hpp +++ /dev/null @@ -1,190 +0,0 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2009 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -// already in ld::passes::stubs namespace -namespace ppc { -namespace classic { - - - -class LazyPointerAtom : public ld::Atom { -public: - LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo, - bool forLazyDylib, bool for64, bool weakImport) - : ld::Atom( forLazyDylib ? _s_sectionLazy : _s_section, - ld::Atom::definitionRegular, ld::Atom::combineNever, - ld::Atom::scopeTranslationUnit, - forLazyDylib ? ld::Atom::typeLazyDylibPointer : ld::Atom::typeLazyPointer, - symbolTableNotIn, false, false, false, for64 ? ld::Atom::Alignment(3) : ld::Atom::Alignment(2)), - _stubTo(stubTo), - _fixup1(0, ld::Fixup::k1of1, - for64 ? ld::Fixup::kindStoreTargetAddressBigEndian64 : ld::Fixup::kindStoreTargetAddressBigEndian32, - forLazyDylib ? pass.internal()->lazyBindingHelper : pass.internal()->classicBindingHelper), - _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo), - _for64(for64) - { _fixup2.weakImport = weakImport; pass.addAtom(*this); } - - virtual const ld::File* file() const { return _stubTo.file(); } - virtual bool translationUnitSource(const char** dir, const char** ) const - { return false; } - virtual const char* name() const { return _stubTo.name(); } - virtual uint64_t size() const { return _for64 ? 8 : 4; } - virtual uint64_t objectAddress() const { return 0; } - virtual void copyRawContent(uint8_t buffer[]) const { } - virtual void setScope(Scope) { } - virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; } - virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; } - -private: - const ld::Atom& _stubTo; - mutable ld::Fixup _fixup1; - mutable ld::Fixup _fixup2; - const bool _for64; - - static ld::Section _s_section; - static ld::Section _s_sectionLazy; -}; - -ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer); -ld::Section LazyPointerAtom::_s_sectionLazy("__DATA", "__ld_symbol_ptr", ld::Section::typeLazyDylibPointer); - - - -class StubPICAtom : public ld::Atom { -public: - StubPICAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo, - bool forLazyDylib, bool for64, bool weakImport) - : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever, - ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, - symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), - _stubTo(stubTo), - _lazyPointer(pass, stubTo, forLazyDylib, for64, weakImport), - _fixup1(12, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_lazyPointer), - _fixup2(12, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this), - _fixup3(12, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 8), - _fixup4(12, ld::Fixup::k4of4, ld::Fixup::kindStorePPCPicHigh16AddLow), - _fixup5(20, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_lazyPointer), - _fixup6(20, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this), - _fixup7(20, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 8), - _fixup8(20, ld::Fixup::k4of4, for64 ? ld::Fixup::kindStorePPCPicLow14 : ld::Fixup::kindStorePPCPicLow16), - _for64(for64) - { pass.addAtom(*this); } - - virtual const ld::File* file() const { return _stubTo.file(); } - virtual bool translationUnitSource(const char** dir, const char** ) const - { return false; } - virtual const char* name() const { return _stubTo.name(); } - virtual uint64_t size() const { return 32; } - virtual uint64_t objectAddress() const { return 0; } - virtual void copyRawContent(uint8_t buffer[]) const { - OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6); // mflr r0 - OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase - OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11 - OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase) - OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0 - if ( _for64 ) - OSWriteBigInt32(&buffer[20], 0, 0xe98b0001);// ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11) - else - OSWriteBigInt32(&buffer[20], 0, 0x858b0000);// lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11) - OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12 - OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr - } - virtual void setScope(Scope) { } - virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; } - virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup8)[1]; } - -private: - const ld::Atom& _stubTo; - LazyPointerAtom _lazyPointer; - mutable ld::Fixup _fixup1; - mutable ld::Fixup _fixup2; - mutable ld::Fixup _fixup3; - mutable ld::Fixup _fixup4; - mutable ld::Fixup _fixup5; - mutable ld::Fixup _fixup6; - mutable ld::Fixup _fixup7; - mutable ld::Fixup _fixup8; - const bool _for64; - - static ld::Section _s_section; -}; - -ld::Section StubPICAtom::_s_section("__TEXT", "__picsymbolstub1", ld::Section::typeStub); - - - -class StubNoPICAtom : public ld::Atom { -public: - StubNoPICAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo, - bool forLazyDylib, bool for64, bool weakImport) - : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever, - ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, - symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), - _stubTo(stubTo), - _lazyPointer(pass, stubTo, forLazyDylib, for64, weakImport), - _fixup1(0, ld::Fixup::k1of2, ld::Fixup::kindSetTargetAddress, &_lazyPointer), - _fixup2(0, ld::Fixup::k2of2, ld::Fixup::kindStorePPCAbsHigh16AddLow), - _fixup3(4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetAddress, &_lazyPointer), - _fixup4(4, ld::Fixup::k2of2, for64 ? ld::Fixup::kindStorePPCAbsLow14 : ld::Fixup::kindStorePPCAbsLow16), - _for64(for64) - { pass.addAtom(*this); } - - virtual const ld::File* file() const { return _stubTo.file(); } - virtual bool translationUnitSource(const char** dir, const char** ) const - { return false; } - virtual const char* name() const { return _stubTo.name(); } - virtual uint64_t size() const { return 16; } - virtual uint64_t objectAddress() const { return 0; } - virtual void copyRawContent(uint8_t buffer[]) const { - OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_foo$lazy_ptr) - if ( _for64 ) - OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001);// ldu r12,lo16(L_foo$lazy_ptr)(r11) - else - OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000);// lwzu r12,lo16(L_foo$lazy_ptr)(r11) - OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12 - OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr - } - virtual void setScope(Scope) { } - virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; } - virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup4)[1]; } - -private: - const ld::Atom& _stubTo; - LazyPointerAtom _lazyPointer; - mutable ld::Fixup _fixup1; - mutable ld::Fixup _fixup2; - mutable ld::Fixup _fixup3; - mutable ld::Fixup _fixup4; - const bool _for64; - - static ld::Section _s_section; -}; - -ld::Section StubNoPICAtom::_s_section("__TEXT", "__symbol_stub1", ld::Section::typeStub); - - -} // namespace classic -} // namespace ppc - diff --git a/src/ld/passes/stubs/stubs.cpp b/src/ld/passes/stubs/stubs.cpp index 274878b..aa4aaf1 100644 --- a/src/ld/passes/stubs/stubs.cpp +++ b/src/ld/passes/stubs/stubs.cpp @@ -89,7 +89,6 @@ private: #include "stub_x86_classic.hpp" #include "stub_arm.hpp" #include "stub_arm_classic.hpp" -#include "stub_ppc_classic.hpp" @@ -116,7 +115,6 @@ const ld::Atom* Pass::stubableFixup(const ld::Fixup* fixup, ld::Internal& state) if ( fixup->binding == ld::Fixup::bindingsIndirectlyBound ) { const ld::Atom* target = state.indirectBindingTable[fixup->u.bindingIndex]; switch ( fixup->kind ) { - case ld::Fixup::kindStoreTargetAddressPPCBranch24: case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32: case ld::Fixup::kindStoreTargetAddressARMBranch24: case ld::Fixup::kindStoreTargetAddressThumbBranch22: @@ -177,15 +175,6 @@ ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport) } switch ( _architecture ) { - case CPU_TYPE_POWERPC: - if ( _pic ) - return new ld::passes::stubs::ppc::classic::StubPICAtom(*this, target, forLazyDylib, false, weakImport); - else - return new ld::passes::stubs::ppc::classic::StubNoPICAtom(*this, target, forLazyDylib, false, weakImport); - break; - case CPU_TYPE_POWERPC64: - return new ld::passes::stubs::ppc::classic::StubPICAtom(*this, target, forLazyDylib, true, weakImport); - break; case CPU_TYPE_I386: if ( usingCompressedLINKEDIT() && !forLazyDylib ) return new ld::passes::stubs::x86::StubAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport); @@ -304,9 +293,7 @@ void Pass::process(ld::Internal& state) if ( _options.outputKind() != Options::kDynamicLibrary ) throwf("resolver functions (%s) can only be used in dylibs", atom->name()); if ( !_options.makeCompressedDyldInfo() ) { - if ( _options.architecture() == CPU_TYPE_POWERPC ) - throwf("resolver functions (%s) not supported for PowerPC", atom->name()); - else if ( _options.architecture() == CPU_TYPE_ARM ) + if ( _options.architecture() == CPU_TYPE_ARM ) throwf("resolver functions (%s) can only be used when targeting iOS 4.2 or later", atom->name()); else throwf("resolver functions (%s) can only be used when targeting Mac OS X 10.6 or later", atom->name()); diff --git a/src/other/ObjectDump.cpp b/src/other/ObjectDump.cpp index 3d7ac5e..44d8f53 100644 --- a/src/other/ObjectDump.cpp +++ b/src/other/ObjectDump.cpp @@ -738,33 +738,6 @@ void dumper::dumpFixup(const ld::Fixup* ref) case ld::Fixup::kindStoreBigEndian64: printf(", then store 64-bit big endian"); break; - case ld::Fixup::kindStorePPCBranch24: - printf(", then store as PPC branch24"); - break; - case ld::Fixup::kindStorePPCBranch14: - printf(", then store as PPC branch14"); - break; - case ld::Fixup::kindStorePPCPicLow14: - printf(", then store as PPC low14 pic"); - break; - case ld::Fixup::kindStorePPCPicLow16: - printf(", then store as PPC low14 pic"); - break; - case ld::Fixup::kindStorePPCPicHigh16AddLow: - printf(", then store as PPC high16 pic"); - break; - case ld::Fixup::kindStorePPCAbsLow14: - printf(", then store as PPC low14 abs"); - break; - case ld::Fixup::kindStorePPCAbsLow16: - printf(", then store as PPC low14 abs"); - break; - case ld::Fixup::kindStorePPCAbsHigh16AddLow: - printf(", then store as PPC high16 abs"); - break; - case ld::Fixup::kindStorePPCAbsHigh16: - printf(", then store as PPC high16 abs, no carry"); - break; case ld::Fixup::kindStoreX86BranchPCRel8: printf(", then store as x86 8-bit pcrel branch"); break; @@ -840,12 +813,6 @@ void dumper::dumpFixup(const ld::Fixup* ref) case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear: printf("x86 dtrace static is-enabled site"); break; - case ld::Fixup::kindStorePPCDtraceCallSiteNop: - printf("ppc dtrace static probe site"); - break; - case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear: - printf("ppc dtrace static is-enabled site"); - break; case ld::Fixup::kindStoreARMDtraceCallSiteNop: printf("ARM dtrace static probe site"); break; @@ -909,9 +876,6 @@ void dumper::dumpFixup(const ld::Fixup* ref) case ld::Fixup::kindStoreTargetAddressARMLoad12: printf("ARM store 12-bit pc-rel branch to %s", referenceTargetAtomName(ref)); break; - case ld::Fixup::kindStoreTargetAddressPPCBranch24: - printf("PowerPC store 24-bit pc-rel load of %s", referenceTargetAtomName(ref)); - break; case ld::Fixup::kindSetTargetTLVTemplateOffset: case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32: case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64: @@ -1220,11 +1184,7 @@ int main(int argc, const char* argv[]) } else if ( strcmp(arg, "-arch") == 0 ) { const char* arch = ++i::relocTypeName(uint8_t r_type) { if ( r_type == GENERIC_RELOC_VANILLA ) return "pointer"; - else if ( r_type == PPC_RELOC_PB_LA_PTR ) - return "pb pointer"; else return "??"; } diff --git a/src/other/machochecker.cpp b/src/other/machochecker.cpp index 4841c7c..54dc560 100644 --- a/src/other/machochecker.cpp +++ b/src/other/machochecker.cpp @@ -1066,9 +1066,6 @@ void MachOChecker::checkLocalReloation(const macho_relocation_info

* relo } else { - // ignore pair relocs - if ( reloc->r_type() == PPC_RELOC_PAIR ) - return; // FIX if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) ) throwf("local relocation address 0x%08X not in writable segment", reloc->r_address()); diff --git a/src/other/rebase.cpp b/src/other/rebase.cpp index d69fc3c..2255789 100644 --- a/src/other/rebase.cpp +++ b/src/other/rebase.cpp @@ -650,13 +650,7 @@ void Rebaser::doLocalRelocation(const macho_relocation_info

* reloc) } } else { - macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; - if ( sreloc->r_type() == PPC_RELOC_PB_LA_PTR ) { - sreloc->set_r_value( sreloc->r_value() + fSlide ); - } - else { - throw "cannot rebase final linked image with scattered relocations"; - } + throw "cannot rebase final linked image with scattered relocations"; } } diff --git a/src/other/unwinddump.cpp b/src/other/unwinddump.cpp index d24e62c..9060557 100644 --- a/src/other/unwinddump.cpp +++ b/src/other/unwinddump.cpp @@ -104,8 +104,6 @@ private: }; -template <> const char* UnwindPrinter::archName() { return "ppc"; } -template <> const char* UnwindPrinter::archName() { return "ppc64"; } template <> const char* UnwindPrinter::archName() { return "i386"; } template <> const char* UnwindPrinter::archName() { return "x86_64"; } template <> const char* UnwindPrinter::archName() { return "arm"; } diff --git a/unit-tests/test-cases/archive-init-order/Makefile b/unit-tests/test-cases/archive-init-order/Makefile new file mode 100644 index 0000000..83364e8 --- /dev/null +++ b/unit-tests/test-cases/archive-init-order/Makefile @@ -0,0 +1,48 @@ +## +# Copyright (c) 2011 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Check the order of functions from archives. +# + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -c -o foo.o + ${CC} ${CCFLAGS} foo2.c -c -o foo2.o + ${CC} ${CCFLAGS} foo3.c -c -o foo3.o + ${CC} ${CCFLAGS} bar.c -c -o bar.o + ${CC} ${CCFLAGS} bar2.c -c -o bar2.o + ${CC} ${CCFLAGS} bar3.c -c -o bar3.o + libtool -static foo.o foo2.o foo3.o -o libfoo.a + libtool -static bar3.o bar2.o bar.o -o libbar.a + ${CC} ${CCFLAGS} main.c -lbar -lfoo -L. -o main -Wl,-map,main.map + grep anon main.map | awk '{ print $$4}' > main-actual.txt + sort main-actual.txt > main-should.txt + diff main-actual.txt main-should.txt + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf *.o *.a main main.map main*.txt diff --git a/unit-tests/test-cases/archive-init-order/bar.c b/unit-tests/test-cases/archive-init-order/bar.c new file mode 100644 index 0000000..850c211 --- /dev/null +++ b/unit-tests/test-cases/archive-init-order/bar.c @@ -0,0 +1,4 @@ +int bar() { return 0; } + +__attribute__((constructor)) +void bar_init() { } diff --git a/unit-tests/test-cases/archive-init-order/bar2.c b/unit-tests/test-cases/archive-init-order/bar2.c new file mode 100644 index 0000000..4c268ba --- /dev/null +++ b/unit-tests/test-cases/archive-init-order/bar2.c @@ -0,0 +1,4 @@ +int bar2() { return 0; } + +__attribute__((constructor)) +void bar2_init() { } diff --git a/unit-tests/test-cases/archive-init-order/bar3.c b/unit-tests/test-cases/archive-init-order/bar3.c new file mode 100644 index 0000000..a55167f --- /dev/null +++ b/unit-tests/test-cases/archive-init-order/bar3.c @@ -0,0 +1,4 @@ +int bar3() { return 0; } + +__attribute__((constructor)) +void bar3_init() { } diff --git a/unit-tests/test-cases/archive-init-order/foo.c b/unit-tests/test-cases/archive-init-order/foo.c new file mode 100644 index 0000000..6149aa1 --- /dev/null +++ b/unit-tests/test-cases/archive-init-order/foo.c @@ -0,0 +1,4 @@ +int foo() { return 1; } + +__attribute__((constructor)) +void foo_init() { } diff --git a/unit-tests/test-cases/archive-init-order/foo2.c b/unit-tests/test-cases/archive-init-order/foo2.c new file mode 100644 index 0000000..a429fe5 --- /dev/null +++ b/unit-tests/test-cases/archive-init-order/foo2.c @@ -0,0 +1,4 @@ +int foo2() { return 1; } + +__attribute__((constructor)) +void foo2_init() { } diff --git a/unit-tests/test-cases/archive-init-order/foo3.c b/unit-tests/test-cases/archive-init-order/foo3.c new file mode 100644 index 0000000..b097ebf --- /dev/null +++ b/unit-tests/test-cases/archive-init-order/foo3.c @@ -0,0 +1,4 @@ +int foo3() { return 1; } + +__attribute__((constructor)) +void foo3_init() { } diff --git a/unit-tests/test-cases/archive-init-order/main.c b/unit-tests/test-cases/archive-init-order/main.c new file mode 100644 index 0000000..242b32a --- /dev/null +++ b/unit-tests/test-cases/archive-init-order/main.c @@ -0,0 +1,41 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +extern int foo(); +extern int foo2(); +extern int foo3(); +extern int bar(); +extern int bar2(); +extern int bar3(); + +int main() +{ + foo(); + bar(); + foo2(); + bar2(); + foo3(); + bar3(); + return 0; +} \ No newline at end of file diff --git a/unit-tests/test-cases/dead_strip-initializers/Makefile b/unit-tests/test-cases/dead_strip-initializers/Makefile new file mode 100644 index 0000000..4292550 --- /dev/null +++ b/unit-tests/test-cases/dead_strip-initializers/Makefile @@ -0,0 +1,47 @@ +## +# Copyright (c) 2011 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Sanity check -dead_strip does not remove initializers and terminators +# + + +run: all + +all: + ${CXX} ${CCFLAGS} main.cxx other.cxx -dead_strip -o main + ${FAIL_IF_BAD_MACHO} main + nm main | grep dead_door_knob | ${FAIL_IF_STDIN} + nm main | grep ctr | ${FAIL_IF_EMPTY} + nm main | grep dtr | ${FAIL_IF_EMPTY} + ${CXX} ${CCFLAGS} -static main.cxx other.cxx -dead_strip -nostdlib -e _main -o main-static -Wl,-new_linker + ${FAIL_IF_BAD_MACHO} main-static + nm main-static | grep dead_door_knob | ${FAIL_IF_STDIN} + nm main-static | grep ctr | ${FAIL_IF_EMPTY} + nm main-static | grep dtr | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main-static + +clean: + rm -rf main main-static diff --git a/unit-tests/test-cases/dead_strip-initializers/main.cxx b/unit-tests/test-cases/dead_strip-initializers/main.cxx new file mode 100644 index 0000000..59af7c2 --- /dev/null +++ b/unit-tests/test-cases/dead_strip-initializers/main.cxx @@ -0,0 +1,24 @@ + +int main() +{ + return 0; +} + + + +void dead_door_knob() { } + + +extern "C" int ctr(); +extern "C" void dtr(); + + +int ctr() { return 10; } +void dtr() { } + + +#if __STATIC__ +extern "C" void __cxa_atexit(); +void __cxa_atexit() {} +#endif + diff --git a/unit-tests/test-cases/dead_strip-initializers/other.cxx b/unit-tests/test-cases/dead_strip-initializers/other.cxx new file mode 100644 index 0000000..1c6534c --- /dev/null +++ b/unit-tests/test-cases/dead_strip-initializers/other.cxx @@ -0,0 +1,18 @@ + +extern "C" int ctr(); +extern "C" void dtr(); + +class Foo +{ +public: + Foo() : field(ctr()) { } + ~Foo() { dtr(); } +private: + int field; +}; + + +Foo f1; +Foo f2; + + diff --git a/unit-tests/test-cases/dso_handle/Makefile b/unit-tests/test-cases/dso_handle/Makefile new file mode 100644 index 0000000..f6c40e4 --- /dev/null +++ b/unit-tests/test-cases/dso_handle/Makefile @@ -0,0 +1,23 @@ + +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +SHELL = bash # use bash shell so we can redirect just stderr + +# +# Verify the linker errors out nicely when __dso_handle is defined in source. +# + +run: all + +all: + ${CC} ${CCFLAGS} test.c -o test + ${FAIL_IF_BAD_MACHO} test + ${CC} ${CCFLAGS} test.c -DDSO_DEF=1 -o test-def 2>warnings.txt + ${FAIL_IF_BAD_MACHO} test-def + ${CC} ${CCFLAGS} test.c -DDSO_TENT=1 -o test-tent + ${PASS_IFF_GOOD_MACHO} test-tent + + +clean: + rm -f test test-def test-tent warnings.txt diff --git a/unit-tests/test-cases/dso_handle/test.c b/unit-tests/test-cases/dso_handle/test.c new file mode 100644 index 0000000..0b984b0 --- /dev/null +++ b/unit-tests/test-cases/dso_handle/test.c @@ -0,0 +1,16 @@ +#include + +#if DSO_DEF + void* __dso_handle = NULL; +#elif DSO_TENT + void* __dso_handle; +#else + extern void* __dso_handle; +#endif + +int main() +{ + printf("dso_handle=%p\n", __dso_handle); + return 0; +} + diff --git a/unit-tests/test-cases/fatal_warning/Makefile b/unit-tests/test-cases/fatal_warning/Makefile new file mode 100644 index 0000000..6758bc0 --- /dev/null +++ b/unit-tests/test-cases/fatal_warning/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2011 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +SHELL = bash # use bash shell so we can redirect just stderr + + +# +# Check that warning under -fatal_warnings causes error +# + +run: all + +all: + ${PASS_IFF_ERROR} ${CC} ${CCFLAGS} main.c -o main -pagezero_size 123 -Wl,-fatal_warnings 2>msgs.txt + + +clean: + rm -f main msgs.txt diff --git a/unit-tests/test-cases/fatal_warning/main.c b/unit-tests/test-cases/fatal_warning/main.c new file mode 100644 index 0000000..fc047f7 --- /dev/null +++ b/unit-tests/test-cases/fatal_warning/main.c @@ -0,0 +1,5 @@ + +int main() +{ + return 0; +} diff --git a/unit-tests/test-cases/lto-dead_strip-unused/Makefile b/unit-tests/test-cases/lto-dead_strip-unused/Makefile index b27291a..82192f8 100644 --- a/unit-tests/test-cases/lto-dead_strip-unused/Makefile +++ b/unit-tests/test-cases/lto-dead_strip-unused/Makefile @@ -1,5 +1,5 @@ ## -# Copyright (c) 2010 Apple Inc. All rights reserved. +# Copyright (c) 2010-2011 Apple Inc. All rights reserved. # # @APPLE_LICENSE_HEADER_START@ # @@ -23,8 +23,10 @@ TESTROOT = ../.. include ${TESTROOT}/include/common.makefile + # # LTO with 'dead code strip' can't ignore unused functions with undefined references +# LTO many have eliminated need for some undefines # run: all @@ -32,7 +34,8 @@ run: all all: ${CC} ${CCFLAGS} -flto bar.c -c -o bar.o ${CC} ${CCFLAGS} -flto main.c -c -o main.o - ${CC} ${CCFLAGS} -dead_strip main.o bar.o -o main + ${CC} ${CCFLAGS} main.o bar.o -o main + ${CC} ${CCFLAGS} main.o bar.o -o main -dead_strip ${PASS_IFF_GOOD_MACHO} main clean: diff --git a/unit-tests/test-cases/order_file-zero-fill/Makefile b/unit-tests/test-cases/order_file-zero-fill/Makefile new file mode 100644 index 0000000..de2283e --- /dev/null +++ b/unit-tests/test-cases/order_file-zero-fill/Makefile @@ -0,0 +1,21 @@ + +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Check that -order_file will transform zero-fill (tentative def) +# symbols to __data symbols to achieve ordering. +# + +run: all + +all: + ${CC} ${CCFLAGS} main.c foo.c -Wl,-order_file,main.order -o main + nm -nj main | grep _xyz_ > main.actual + diff main.expected main.actual + nm -nm main | grep _xyz_f4 | grep __data | ${FAIL_IF_EMPTY} + nm -nm main | grep _other | grep __common | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -f main main.actual diff --git a/unit-tests/test-cases/order_file-zero-fill/foo.c b/unit-tests/test-cases/order_file-zero-fill/foo.c new file mode 100644 index 0000000..8bfc7d2 --- /dev/null +++ b/unit-tests/test-cases/order_file-zero-fill/foo.c @@ -0,0 +1,4 @@ + +int xyz_f2; +int xyz_f4; +int other; diff --git a/unit-tests/test-cases/order_file-zero-fill/main.c b/unit-tests/test-cases/order_file-zero-fill/main.c new file mode 100644 index 0000000..6c37d8e --- /dev/null +++ b/unit-tests/test-cases/order_file-zero-fill/main.c @@ -0,0 +1,38 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include + +int xyz_m1; +int xyz_m3; +static int xyz_ms1; +int xyz_mi3 = 4; +int xyz_mi4 = 4; +int main_common; + + +int main() +{ + fprintf(stdout, "hello %p\n", &xyz_ms1); + return 0; +} diff --git a/unit-tests/test-cases/order_file-zero-fill/main.expected b/unit-tests/test-cases/order_file-zero-fill/main.expected new file mode 100644 index 0000000..8b9edb4 --- /dev/null +++ b/unit-tests/test-cases/order_file-zero-fill/main.expected @@ -0,0 +1,7 @@ +_xyz_f4 +_xyz_mi4 +_xyz_f2 +_xyz_m3 +_xyz_m1 +_xyz_ms1 +_xyz_mi3 diff --git a/unit-tests/test-cases/order_file-zero-fill/main.order b/unit-tests/test-cases/order_file-zero-fill/main.order new file mode 100644 index 0000000..fa6c623 --- /dev/null +++ b/unit-tests/test-cases/order_file-zero-fill/main.order @@ -0,0 +1,7 @@ +_xyz_f4 +_xyz_mi4 +_xyz_f2 +_xyz_m3 +_xyz_m1 +_xyz_ms1 + diff --git a/unit-tests/test-cases/tlv-dead_strip/Makefile b/unit-tests/test-cases/tlv-dead_strip/Makefile index 46e695c..568ebc6 100644 --- a/unit-tests/test-cases/tlv-dead_strip/Makefile +++ b/unit-tests/test-cases/tlv-dead_strip/Makefile @@ -32,7 +32,7 @@ run: all all: clang ${CCFLAGS} main.c -o main -dead_strip -mmacosx-version-min=10.7 otool -lv main | grep S_THREAD_LOCAL_VARIABLES | ${FAIL_IF_EMPTY} - otool -lv main | grep S_THREAD_LOCAL_REGULAR | ${FAIL_IF_EMPTY} + otool -lv main | egrep 'S_THREAD_LOCAL_REGULAR|S_THREAD_LOCAL_ZEROFILL' | ${FAIL_IF_EMPTY} ${PASS_IFF_GOOD_MACHO} main clean: