+-------- tagged ld64-128.1
+
+2011-09-13 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/10111122> Enable dyld to be put into the dyld shared cache
+
+2011-09-13 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/10100056> Fix "using ld_classic" warning for i386 kexts
+
+2011-09-13 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/10052396> LTO many have eliminated need for some undefines
+
+-------- tagged ld64-128
+
+2011-09-08 Nick Kledzik <kledzik@apple.com>
+
+ Rework 8924157 fix to sort all sections
+
+2011-09-07 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/10089743> ER: -current_version should allow 64-bit a.b.c.d.e tuple
+
+2011-09-06 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/10038370> -mdynamic-no-pic broke with movw of weak thumb symbol
+
+2011-09-01 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/10057157> 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 <kledzik@apple.com>
+
+ <rdar://problem/6780050> Add -fatal_warnings
+
+2011-08-30 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/8482298> Support .weak_def_can_be_hidden via LTO interface
+
+2011-08-29 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/10043807> improve performance of zerofill->data ordering
+
+2011-08-29 Nick Kledzik <kledzik@apple.com>
+
+ Implement -print_statistics
+
+2011-08-25 Nick Kledzik <kledzik@apple.com>
+
+ check for overlaps between pinned segments and regular segments
+
+2011-08-23 Nick Kledzik <kledzik@apple.com>
+
+ do got elimination more aggressively in static and preload mode
+
+2011-08-22 Nick Kledzik <kledzik@apple.com>
+
+ enable __dso_handle in -preload
+
+2011-08-22 Nick Kledzik <kledzik@apple.com>
+
+ fix section$end to sort to end of __mod_init_func section
+
+2011-08-18 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/9737570> __constructor section removed with -dead_strip
+
+2011-08-11 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/8828975> remove ld support for PowerPC
+
+2011-08-11 Nick Kledzik <kledzik@apple.com>
+
+ Fix spurious -segaddr alignment warning
+
+-------- tagged ld64-127.3
+
+2011-08-31 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/8924157> [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 <kledzik@apple.com>
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
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
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 */; };
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 = "<group>"; };
F97F5028070D0BB200B9FCD7 /* ld.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = ld.1; path = doc/man/man1/ld.1; sourceTree = "<group>"; };
- F984963310AB9318009E9878 /* stub_ppc_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_ppc_classic.hpp; sourceTree = "<group>"; };
- F9849E3410B38EF5009E9878 /* order_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = order_file.cpp; sourceTree = "<group>"; };
- F9849E3510B38EF5009E9878 /* order_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = order_file.h; sourceTree = "<group>"; };
+ F9849E3410B38EF5009E9878 /* order.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = order.cpp; sourceTree = "<group>"; };
+ F9849E3510B38EF5009E9878 /* order.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = order.h; sourceTree = "<group>"; };
F984A13B10B614CF009E9878 /* stub_arm_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_arm_classic.hpp; sourceTree = "<group>"; };
F984A38010BB4B0D009E9878 /* branch_island.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = branch_island.cpp; sourceTree = "<group>"; };
F984A38110BB4B0D009E9878 /* branch_island.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = branch_island.h; sourceTree = "<group>"; };
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 */,
F9BA8A7E1096150F0097A440 /* stub_x86_classic.hpp */,
F989D0391062E6350014B60C /* stub_x86_64.hpp */,
F92D9C2710657AAB00FF369B /* stub_x86_64_classic.hpp */,
- F984963310AB9318009E9878 /* stub_ppc_classic.hpp */,
);
path = stubs;
sourceTree = "<group>";
);
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 */ = {
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 */,
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;
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;
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;
#include <mach-o/fat.h>
#include <mach-o/stab.h>
#include <mach-o/reloc.h>
-#include <mach-o/ppc/reloc.h>
#include <mach-o/x86_64/reloc.h>
#include <mach-o/arm/reloc.h>
#include <mach-o/compact_unwind_encoding.h>
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:
return bits;
}
-template <> uint32_t HeaderAndLoadCommandsAtom<ppc>::magic() const { return MH_MAGIC; }
-template <> uint32_t HeaderAndLoadCommandsAtom<ppc64>::magic() const { return MH_MAGIC_64; }
template <> uint32_t HeaderAndLoadCommandsAtom<x86>::magic() const { return MH_MAGIC; }
template <> uint32_t HeaderAndLoadCommandsAtom<x86_64>::magic() const { return MH_MAGIC_64; }
template <> uint32_t HeaderAndLoadCommandsAtom<arm>::magic() const { return MH_MAGIC; }
-template <> uint32_t HeaderAndLoadCommandsAtom<ppc>::cpuType() const { return CPU_TYPE_POWERPC; }
-template <> uint32_t HeaderAndLoadCommandsAtom<ppc64>::cpuType() const { return CPU_TYPE_POWERPC64; }
template <> uint32_t HeaderAndLoadCommandsAtom<x86>::cpuType() const { return CPU_TYPE_I386; }
template <> uint32_t HeaderAndLoadCommandsAtom<x86_64>::cpuType() const { return CPU_TYPE_X86_64; }
template <> uint32_t HeaderAndLoadCommandsAtom<arm>::cpuType() const { return CPU_TYPE_ARM; }
-template <>
-uint32_t HeaderAndLoadCommandsAtom<ppc>::cpuSubType() const
-{
- return _state.cpuSubType;
-}
-
-template <>
-uint32_t HeaderAndLoadCommandsAtom<ppc64>::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<x86>::cpuSubType() 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<P>)], _options.installPath());
return p + sz;
cmd->set_cmd(LC_VERSION_MIN_MACOSX);
cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
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<P>));
cmd->set_version((uint32_t)iOSVersion);
- cmd->set_reserved(0);
+ cmd->set_sdk(0);
}
return p + sizeof(macho_version_min_command<P>);
}
-template <>
-uint32_t HeaderAndLoadCommandsAtom<ppc>::threadLoadCommandSize() const
-{
- return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
-}
-
-
-template <>
-uint8_t* HeaderAndLoadCommandsAtom<ppc>::copyThreadsLoadCommand(uint8_t* p) const
-{
- assert(_state.entryPoint != NULL);
- pint_t start = _state.entryPoint->finalAddress();
- macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)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<ppc64>::threadLoadCommandSize() const
-{
- return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
-}
-
-template <>
-uint8_t* HeaderAndLoadCommandsAtom<ppc64>::copyThreadsLoadCommand(uint8_t* p) const
-{
- assert(_state.entryPoint != NULL);
- pint_t start = _state.entryPoint->finalAddress();
- macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)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<x86>::threadLoadCommandSize() const
// 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__
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);
mutable std::vector<uint64_t> _32bitPointerLocations;
mutable std::vector<uint64_t> _64bitPointerLocations;
- mutable std::vector<uint64_t> _ppcHi16Locations;
mutable std::vector<uint64_t> _thumbLo16Locations;
mutable std::vector<uint64_t> _thumbHi16Locations[16];
mutable std::vector<uint64_t> _armLo16Locations;
}
-template <>
-void SplitSegInfoAtom<ppc>::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<ppc64>::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 <typename A>
void SplitSegInfoAtom<A>::uleb128EncodeAddresses(const std::vector<uint64_t>& locations) 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");
// clean up temporaries
_32bitPointerLocations.clear();
_64bitPointerLocations.clear();
- _ppcHi16Locations.clear();
}
template <typename A>
void LocalRelocationsAtom<A>::addTextReloc(uint64_t addr, ld::Fixup::Kind kind, uint64_t targetAddr, uint32_t symNum)
{
- macho_relocation_info<P> reloc1;
- macho_relocation_info<P> 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;
- }
}
template <> uint32_t ExternalRelocationsAtom<arm>::pointerReloc() { return ARM_RELOC_VANILLA; }
template <> uint32_t ExternalRelocationsAtom<x86>::pointerReloc() { return GENERIC_RELOC_VANILLA; }
-template <> uint32_t ExternalRelocationsAtom<ppc>::pointerReloc() { return PPC_RELOC_VANILLA; }
template <> uint32_t ExternalRelocationsAtom<x86_64>::pointerReloc() { return X86_64_RELOC_UNSIGNED; }
-template <> uint32_t ExternalRelocationsAtom<ppc64>::pointerReloc() { return PPC_RELOC_VANILLA; }
template <> uint32_t ExternalRelocationsAtom<x86_64>::callReloc() { return X86_64_RELOC_BRANCH; }
}
-template <>
-void SectionRelocationsAtom<ppc>::encodeSectionReloc(ld::Internal::FinalSection* sect,
- const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
-{
- macho_relocation_info<P> reloc1;
- macho_relocation_info<P> reloc2;
- macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
- macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&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<ppc64>::encodeSectionReloc(ld::Internal::FinalSection* sect,
- const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
-{
- macho_relocation_info<P> reloc1;
- macho_relocation_info<P> reloc2;
- macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
- macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&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 <typename A>
void SectionRelocationsAtom<A>::addSectionReloc(ld::Internal::FinalSection* sect, ld::Fixup::Kind kind,
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 ) {
}
+bool Options::errorBecauseOfWarnings() const
+{
+ return (sFatalWarnings && (sWarningsCount > 0));
+}
const char* Options::installPath() const
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) ) {
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;
}
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 ) {
}
+//
+// 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 == '.' ) {
}
}
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;
}
*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 )
const char* vers = argv[++i];
if ( vers == NULL )
throw "-dylib_compatibility_version missing <version>";
- 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 <version>";
- 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) )
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.
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;
}
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();
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);
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");
break;
}
// else use object file
- case CPU_TYPE_POWERPC:
case CPU_TYPE_I386:
// use .o files
fOutputKind = kObjectFile;
// 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;
// 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:
// 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
}
}
break;
- case CPU_TYPE_POWERPC64:
case CPU_TYPE_X86_64:
fPrebind = false;
break;
|| (strncmp(this->installPath(), "/System/Library/", 16) == 0) )
fSharedRegionEligible = true;
}
-
+ else if ( fOutputKind == Options::kDyld ) {
+ // <rdar://problem/10111122> 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
break;
}
break;
- case CPU_TYPE_POWERPC:
- case CPU_TYPE_POWERPC64:
case CPU_TYPE_ARM:
fAddCompactUnwindEncoding = false;
fRemoveDwarfUnwindIfCompactExists = false;
if ( !minOS(ld::mac10_6, ld::iOS_3_1) )
fMakeCompressedDyldInfo = false;
break;
- case CPU_TYPE_POWERPC:
- case CPU_TYPE_POWERPC64:
default:
fMakeCompressedDyldInfo = false;
}
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;
}
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 ) {
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;
if ( fObjCABIVersion2Override )
alterObjC1ClassNamesToObjC2 = true;
break;
- case CPU_TYPE_POWERPC64:
case CPU_TYPE_X86_64:
case CPU_TYPE_ARM:
alterObjC1ClassNamesToObjC2 = true;
// 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;
// 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 ) {
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 ) {
}
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) {
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();
bool forceNotWeak(const char* symbolName) const;
bool forceWeakNonWildCard(const char* symbolName) const;
bool forceNotWeakNonWildcard(const char* symbolName) const;
+ bool errorBecauseOfWarnings() const;
private:
class CStringEquals
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);
bool fDeadStrip;
NameSpace fNameSpace;
uint32_t fDylibCompatVersion;
- uint32_t fDylibCurrentVersion;
+ uint64_t fDylibCurrentVersion;
const char* fDylibInstallName;
const char* fFinalName;
const char* fEntryName;
// 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<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
ld::Internal::FinalSection* sect = *it;
&& (_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<ld::Internal::FinalSection*>::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,
if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace )
address += sect->size;
}
+ if ( overlappingFixedSection != NULL ) {
+ fprintf(stderr, "Section layout:\n");
+ for (std::vector<ld::Internal::FinalSection*>::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
}
}
-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));
- }
-}
int64_t delta;
uint32_t instruction;
uint32_t newInstruction;
- uint16_t instructionLowHalf;
bool is_bl;
bool is_blx;
bool is_b;
}
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:
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
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;
}
}
}
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)
return addPreloadLinkEdit(state);
switch ( _options.architecture() ) {
- case CPU_TYPE_POWERPC:
- if ( _hasSectionRelocations ) {
- _sectionsRelocationsAtom = new SectionRelocationsAtom<ppc>(_options, state, *this);
- sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
- }
- if ( _hasDyldInfo ) {
- _rebasingInfoAtom = new RebaseInfoAtom<ppc>(_options, state, *this);
- rebaseSection = state.addAtom(*_rebasingInfoAtom);
-
- _bindingInfoAtom = new BindingInfoAtom<ppc>(_options, state, *this);
- bindingSection = state.addAtom(*_bindingInfoAtom);
-
- _weakBindingInfoAtom = new WeakBindingInfoAtom<ppc>(_options, state, *this);
- weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
-
- _lazyBindingInfoAtom = new LazyBindingInfoAtom<ppc>(_options, state, *this);
- lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
-
- _exportInfoAtom = new ExportInfoAtom<ppc>(_options, state, *this);
- exportSection = state.addAtom(*_exportInfoAtom);
- }
- if ( _hasLocalRelocations ) {
- _localRelocsAtom = new LocalRelocationsAtom<ppc>(_options, state, *this);
- localRelocationsSection = state.addAtom(*_localRelocsAtom);
- }
- if ( _hasSplitSegInfo ) {
- _splitSegInfoAtom = new SplitSegInfoAtom<ppc>(_options, state, *this);
- splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
- }
- if ( _hasFunctionStartsInfo ) {
- _functionStartsAtom = new FunctionStartsAtom<ppc>(_options, state, *this);
- functionStartsSection = state.addAtom(*_functionStartsAtom);
- }
- if ( _hasSymbolTable ) {
- _symbolTableAtom = new SymbolTableAtom<ppc>(_options, state, *this);
- symbolTableSection = state.addAtom(*_symbolTableAtom);
- }
- if ( _hasExternalRelocations ) {
- _externalRelocsAtom = new ExternalRelocationsAtom<ppc>(_options, state, *this);
- externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
- }
- if ( _hasSymbolTable ) {
- _indirectSymbolTableAtom = new IndirectSymbolTableAtom<ppc>(_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<x86>(_options, state, *this);
stringPoolSection = state.addAtom(*_stringPoolAtom);
}
break;
- case CPU_TYPE_POWERPC64:
- if ( _hasSectionRelocations ) {
- _sectionsRelocationsAtom = new SectionRelocationsAtom<ppc64>(_options, state, *this);
- sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
- }
- if ( _hasDyldInfo ) {
- _rebasingInfoAtom = new RebaseInfoAtom<ppc64>(_options, state, *this);
- rebaseSection = state.addAtom(*_rebasingInfoAtom);
-
- _bindingInfoAtom = new BindingInfoAtom<ppc64>(_options, state, *this);
- bindingSection = state.addAtom(*_bindingInfoAtom);
-
- _weakBindingInfoAtom = new WeakBindingInfoAtom<ppc64>(_options, state, *this);
- weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
-
- _lazyBindingInfoAtom = new LazyBindingInfoAtom<ppc64>(_options, state, *this);
- lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
-
- _exportInfoAtom = new ExportInfoAtom<ppc64>(_options, state, *this);
- exportSection = state.addAtom(*_exportInfoAtom);
- }
- if ( _hasLocalRelocations ) {
- _localRelocsAtom = new LocalRelocationsAtom<ppc64>(_options, state, *this);
- localRelocationsSection = state.addAtom(*_localRelocsAtom);
- }
- if ( _hasSplitSegInfo ) {
- _splitSegInfoAtom = new SplitSegInfoAtom<ppc64>(_options, state, *this);
- splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
- }
- if ( _hasFunctionStartsInfo ) {
- _functionStartsAtom = new FunctionStartsAtom<ppc64>(_options, state, *this);
- functionStartsSection = state.addAtom(*_functionStartsAtom);
- }
- if ( _hasSymbolTable ) {
- _symbolTableAtom = new SymbolTableAtom<ppc64>(_options, state, *this);
- symbolTableSection = state.addAtom(*_symbolTableAtom);
- }
- if ( _hasExternalRelocations ) {
- _externalRelocsAtom = new ExternalRelocationsAtom<ppc64>(_options, state, *this);
- externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
- }
- if ( _hasSymbolTable ) {
- _indirectSymbolTableAtom = new IndirectSymbolTableAtom<ppc64>(_options, state, *this);
- indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
- _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
- stringPoolSection = state.addAtom(*_stringPoolAtom);
- }
- break;
default:
throw "unknown architecture";
}
_headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86>(_options, state, *this);
headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
break;
- case CPU_TYPE_POWERPC:
- _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<ppc>(_options, state, *this);
- headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
- break;
- case CPU_TYPE_POWERPC64:
- _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<ppc64>(_options, state, *this);
- headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
- break;
default:
throw "unknown architecture";
}
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);
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:
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;
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);
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:
uint32_t encryptedTextStartOffset() { return _encryptedTEXTstartOffset; }
uint32_t encryptedTextEndOffset() { return _encryptedTEXTendOffset; }
int compressedOrdinalForAtom(const ld::Atom* target);
-
+ uint64_t fileSize() const { return _fileSize; }
bool hasWeakExternalSymbols;
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);
//_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)
{
// 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() ) {
}
break;
- case CPU_TYPE_POWERPC64:
- break;
-
case CPU_TYPE_I386:
_internal.cpuSubType = CPU_SUBTYPE_I386_ALL;
break;
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:
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
break;
}
std::vector<const char*> unresolvableUndefines;
- if ( _options.deadCodeStrip() )
+ // <rdar://problem/10052396> LTO many have eliminated need for some undefines
+ if ( _options.deadCodeStrip() || _haveLLVMObjs )
this->liveUndefines(unresolvableUndefines);
else
_symbolTable.undefines(unresolvableUndefines);
void markLive(const ld::Atom& atom, WhyLiveBackChain* previous);
bool isDtraceProbe(ld::Fixup::Kind kind);
void liveUndefines(std::vector<const char*>&);
- static unsigned int ppcSubTypeIndex(uint32_t subtype);
bool printReferencedBy(const char* name, SymbolTable::IndirectBindingSlot slot);
}
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());
+ }
}
}
}
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:
/* -*- 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@
*
#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"
#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:
SectionInToOut _sectionInToFinalMap;
const Options& _options;
+ bool _atomsOrderedInSections;
};
ld::Section InternalState::FinalSection::_s_DATA_data( "__DATA", "__data", ld::Section::typeUnclassified);
ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
{
ld::Internal::FinalSection* fs = this->getFinalSection(atom.section());
-
- // <rdar://problem/8612550> 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;
}
}
+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);
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();
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));
+ }
+ // <rdar://problem/6780050> 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) {
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
kindStoreTargetAddressARMBranch24, // kindSetTargetAddress + kindStoreARMBranch24
kindStoreTargetAddressThumbBranch22, // kindSetTargetAddress + kindStoreThumbBranch22
kindStoreTargetAddressARMLoad12, // kindSetTargetAddress + kindStoreARMLoad12
- // PowerPC value calculation and store combinations
- kindStoreTargetAddressPPCBranch24, // kindSetTargetAddress + kindStorePPCBranch24
};
union {
}
-template <> cpu_type_t File<ppc>::architecture() { return CPU_TYPE_POWERPC; }
-template <> cpu_type_t File<ppc64>::architecture() { return CPU_TYPE_POWERPC64; }
template <> cpu_type_t File<x86>::architecture() { return CPU_TYPE_I386; }
template <> cpu_type_t File<x86_64>::architecture() { return CPU_TYPE_X86_64; }
template <> cpu_type_t File<arm>::architecture() { return CPU_TYPE_ARM; }
}
}
-template <>
-bool File<ppc>::memberHasObjCCategories(const Entry* member) const
-{
- // ppc uses ObjC1 ABI which has .objc_category* global symbols
- return false;
-}
template <typename A>
if ( archive::Parser<arm>::validFile(fileContent, fileLength, opts.objOpts) )
return archive::Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
break;
- case CPU_TYPE_POWERPC:
- if ( archive::Parser<ppc>::validFile(fileContent, fileLength, opts.objOpts) )
- return archive::Parser<ppc>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
- break;
- case CPU_TYPE_POWERPC64:
- if ( archive::Parser<ppc64>::validFile(fileContent, fileLength, opts.objOpts) )
- return archive::Parser<ppc64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
- break;
}
return NULL;
}
{
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; }
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;
}
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:
// 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;
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);
}
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);
{
}
-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)
-template <>
-bool Parser<ppc>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
-{
- const macho_header<P>* header = (const macho_header<P>*)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<ppc64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
-{
- const macho_header<P>* header = (const macho_header<P>*)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<x86>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
{
if ( Parser<arm>::validFile(fileContent, bundleLoader) )
return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
break;
- case CPU_TYPE_POWERPC:
- if ( Parser<ppc>::validFile(fileContent, bundleLoader) )
- return Parser<ppc>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
- break;
- case CPU_TYPE_POWERPC64:
- if ( Parser<ppc64>::validFile(fileContent, bundleLoader) )
- return Parser<ppc64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
- break;
}
return NULL;
}
_beginAtoms(NULL), _endAtoms(NULL), _hasAliases(false) { }
- bool addRelocFixup_powerpc(class Parser<A>& parser,const macho_relocation_info<typename A::P>* reloc);
Atom<A>* findContentAtomByAddress(pint_t addr, class Atom<A>* start, class Atom<A>* end);
uint32_t x86_64PcRelOffset(uint8_t r_type);
static const char* makeSegmentName(const macho_section<typename A::P>* s);
{
}
-template <>
-bool Parser<ppc>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
-{
- const macho_header<P>* header = (const macho_header<P>*)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<ppc64>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
-{
- const macho_header<P>* header = (const macho_header<P>*)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<x86>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
}
-template <>
-const char* Parser<ppc>::fileKind(const uint8_t* fileContent)
-{
- const macho_header<P>* header = (const macho_header<P>*)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<ppc64>::fileKind(const uint8_t* fileContent)
-{
- const macho_header<P>* header = (const macho_header<P>*)fileContent;
- if ( header->magic() != MH_MAGIC )
- return NULL;
- if ( header->cputype() != CPU_TYPE_POWERPC64 )
- return NULL;
- return "ppc64";
-}
template <>
const char* Parser<x86>::fileKind(const uint8_t* fileContent)
-template <> uint8_t Parser<ppc>::loadCommandSizeMask() { return 0x03; }
-template <> uint8_t Parser<ppc64>::loadCommandSizeMask() { return 0x07; }
template <> uint8_t Parser<x86>::loadCommandSizeMask() { return 0x03; }
template <> uint8_t Parser<x86_64>::loadCommandSizeMask() { return 0x07; }
template <> uint8_t Parser<arm>::loadCommandSizeMask() { return 0x03; }
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;
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 )
return 1 + (this->_machOSection - parser.firstMachOSection());
}
-// libunwind does not support ppc64
-template <> uint32_t CFISection<ppc64>::cfiCount() { return 0; }
// arm does not have zero cost exceptions
template <> uint32_t CFISection<arm>::cfiCount() { return 0; }
}
-// need to change libunwind parseCFIs() to work for ppc
-template <>
-void CFISection<ppc>::cfiParse(class Parser<ppc>& parser, uint8_t* buffer,
- libunwind::CFI_Atom_Info<CFISection<ppc>::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<OAS, libunwind::Registers_ppc>::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<ppc64>::cfiParse(class Parser<ppc64>& parser, uint8_t* buffer,
- libunwind::CFI_Atom_Info<CFISection<ppc64>::OAS>::CFI_Atom_Info cfiArray[],
- uint32_t count)
-{
- // libunwind does not support ppc64
- assert(count == 0);
-}
template <>
void CFISection<arm>::cfiParse(class Parser<arm>& parser, uint8_t* buffer,
template <> bool CFISection<x86_64>::bigEndian() { return false; }
template <> bool CFISection<x86>::bigEndian() { return false; }
template <> bool CFISection<arm>::bigEndian() { return false; }
-template <> bool CFISection<ppc>::bigEndian() { return true; }
-template <> bool CFISection<ppc64>::bigEndian() { return true; }
template <>
}
-template <>
-void CFISection<ppc>::addCiePersonalityFixups(class Parser<ppc>& 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<ppc>* cieAtom = this->findAtomByAddress(cieInfo->address);
- Atom<ppc>* nlpAtom = parser.findAtomByAddress(nlpAddr);
- assert(nlpAtom->contentType() == ld::Atom::typeNonLazyPointer);
- Parser<ppc>::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 <typename A>
void CFISection<A>::addCiePersonalityFixups(class Parser<A>& parser, const CFI_Atom_Info* cieInfo)
{
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;
}
}
return ld::Fixup::kindStoreLittleEndian32;
}
-template <>
-ld::Fixup::Kind NonLazyPointerSection<ppc>::fixupKind()
-{
- return ld::Fixup::kindStoreBigEndian32;
-}
-
-template <>
-ld::Fixup::Kind NonLazyPointerSection<ppc64>::fixupKind()
-{
- return ld::Fixup::kindStoreBigEndian64;
-}
template <>
void NonLazyPointerSection<x86_64>::makeFixups(class Parser<x86_64>& parser, const struct Parser<x86_64>::CFI_CU_InfoArrays&)
-//
-// ppc and ppc64 both use the same relocations, so process them in one common routine
-//
-template <typename A>
-bool Section<A>::addRelocFixup_powerpc(class Parser<A>& parser,
- const macho_relocation_info<typename A::P>* reloc)
-{
- const macho_section<P>* 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<A>::SourceLocation src;
- typename Parser<A>::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<P>* 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<P>& 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<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
- // file format allows pair to be scattered or not
- const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
- const macho_relocation_info<P>* 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<A>::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<A>* fromAtom = parser.findAtomByAddress(nextRelocValue);
- Atom<A>* 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<ppc>::addRelocFixup(class Parser<ppc>& parser, const macho_relocation_info<P>* reloc)
-{
- return addRelocFixup_powerpc(parser, reloc);
-}
-
-
-template <>
-bool Section<ppc64>::addRelocFixup(class Parser<ppc64>& parser, const macho_relocation_info<P>* reloc)
-{
- return addRelocFixup_powerpc(parser, reloc);
-}
-
template <>
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() )
dstAddr = (other16 << 16) | instruction16;
if ( reloc->r_extern() ) {
target.addend = dstAddr;
+ if ( externSymbolIsThumbDef )
+ target.addend &= -2; // remove thumb bit
}
else {
parser.findTargetFromAddress(dstAddr, target);
return FixedSizeSection<x86>::addRelocFixup(parser, reloc);
}
-template <>
-bool ObjC1ClassSection<ppc>::addRelocFixup(class Parser<ppc>& parser, const macho_relocation_info<ppc::P>* 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<P>* sect = this->machoSection();
- Parser<ppc>::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<ppc>::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<ppc>::addRelocFixup(parser, reloc);
-}
-
-
template <typename A>
}
-template <>
-bool Objc1ClassReferences<ppc>::addRelocFixup(class Parser<ppc>& parser, const macho_relocation_info<ppc::P>* 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<P>* sect = this->machoSection();
- Parser<ppc>::SourceLocation src;
- uint32_t srcAddr = sect->addr() + reloc->r_address();
- src.atom = this->findAtomByAddress(srcAddr);
- src.offsetInAtom = srcAddr - src.atom->objectAddress();
- Parser<ppc>::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<ppc>::addRelocFixup(parser, reloc);
-}
-
template <>
bool Objc1ClassReferences<x86>::addRelocFixup(class Parser<x86>& parser, const macho_relocation_info<x86::P>* reloc)
if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) )
return mach_o::relocatable::Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
break;
- case CPU_TYPE_POWERPC:
- if ( mach_o::relocatable::Parser<ppc>::validFile(fileContent) )
- return mach_o::relocatable::Parser<ppc>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
- break;
- case CPU_TYPE_POWERPC64:
- if ( mach_o::relocatable::Parser<ppc64>::validFile(fileContent) )
- return mach_o::relocatable::Parser<ppc64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
- break;
}
return NULL;
}
return ( mach_o::relocatable::Parser<x86>::validFile(fileContent) );
case CPU_TYPE_ARM:
return ( mach_o::relocatable::Parser<arm>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) );
- case CPU_TYPE_POWERPC:
- return ( mach_o::relocatable::Parser<ppc>::validFile(fileContent) );
- case CPU_TYPE_POWERPC64:
- return ( mach_o::relocatable::Parser<ppc64>::validFile(fileContent) );
}
return false;
}
*subResult = header->cpusubtype();
return true;
}
- if ( mach_o::relocatable::Parser<ppc>::validFile(fileContent) ) {
- *result = CPU_TYPE_POWERPC;
- const macho_header<Pointer32<BigEndian> >* header = (const macho_header<Pointer32<BigEndian> >*)fileContent;
- *subResult = header->cpusubtype();
- return true;
- }
- if ( mach_o::relocatable::Parser<ppc64>::validFile(fileContent) ) {
- *result = CPU_TYPE_POWERPC64;
- *subResult = CPU_SUBTYPE_POWERPC_ALL;
- return true;
- }
return false;
}
if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, false, 0) ) {
return mach_o::relocatable::Parser<arm>::fileKind(fileContent);
}
- if ( mach_o::relocatable::Parser<ppc>::validFile(fileContent) ) {
- return mach_o::relocatable::Parser<ppc>::fileKind(fileContent);
- }
- if ( mach_o::relocatable::Parser<ppc64>::validFile(fileContent) ) {
- return mach_o::relocatable::Parser<ppc64>::fileKind(fileContent);
- }
return NULL;
}
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 {
}
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:
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
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
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:
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:
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));
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:
}
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;
state.addAtom(*new ObjCImageInfoAtom<x86>(state.objcObjectConstraint, compaction,
state.hasObjcReplacementClasses, opts.objCABIVersion2POverride() ? true : false));
break;
- case CPU_TYPE_POWERPC:
- state.addAtom(*new ObjCImageInfoAtom<ppc>(state.objcObjectConstraint, compaction,
- state.hasObjcReplacementClasses, false));
- break;
case CPU_TYPE_ARM:
state.addAtom(*new ObjCImageInfoAtom<arm>(state.objcObjectConstraint, compaction,
state.hasObjcReplacementClasses, true));
break;
- case CPU_TYPE_POWERPC64:
- state.addAtom(*new ObjCImageInfoAtom<ppc64>(state.objcObjectConstraint, compaction,
- state.hasObjcReplacementClasses, true));
- break;
default:
assert(0 && "unknown objc arch");
}
// disable optimization until fully tested
//OptimizeCategories<arm>::doit(opts, state);
break;
- case CPU_TYPE_POWERPC64:
- case CPU_TYPE_POWERPC:
- break;
default:
assert(0 && "unknown objc arch");
}
--- /dev/null
+/* -*- 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 <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <mach/machine.h>
+
+#include <vector>
+#include <map>
+
+#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<const char*, const ld::Atom*, __gnu_cxx::hash<const char*>, CStringEquals> NameToAtom;
+
+ typedef std::map<const ld::Atom*, const ld::Atom*> AtomToAtom;
+
+ typedef std::map<const ld::Atom*, uint32_t> 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<const ld::Atom*> _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 ld::Atom*>::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<ld::Internal::FinalSection*>::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<const ld::Atom*>::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<const ld::Atom*>::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<const ld::Atom*>::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<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( !possibleToOrder(sect) )
+ continue;
+ for (std::vector<const ld::Atom*>::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<const ld::Atom*>& theSet) : _set(theSet) {}
+
+ bool operator()(const ld::Atom* atom) const {
+ return ( _set.count(atom) != 0 );
+ }
+private:
+ const std::set<const ld::Atom*>& _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<const ld::Atom*> moveToData;
+ for(Options::OrderedSymbolsIterator it = _options.orderedSymbolsBegin(); it != _options.orderedSymbolsEnd(); ++it) {
+ const ld::Atom* atom = this->findAtom(*it);
+ if ( atom != NULL ) {
+ // <rdar://problem/8612550> 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() );
+ }
+
+
+ // <rdar://problem/8612550> When order file used on data, turn ordered zero fill symbols into zeroed data
+ if ( ! moveToData.empty() ) {
+ for (std::vector<ld::Internal::FinalSection*>::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<ld::Internal::FinalSection*>::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<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
+ // ld::Internal::FinalSection* sect = *sit;
+ // for (std::vector<const ld::Atom*>::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
--- /dev/null
+/* -*- 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__
+++ /dev/null
-/* -*- 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 <stdint.h>
-#include <math.h>
-#include <unistd.h>
-#include <dlfcn.h>
-#include <mach/machine.h>
-
-#include <vector>
-#include <map>
-
-#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<const char*, const ld::Atom*, __gnu_cxx::hash<const char*>, CStringEquals> NameToAtom;
-
- typedef std::map<const ld::Atom*, const ld::Atom*> AtomToAtom;
-
- typedef std::map<const ld::Atom*, uint32_t> 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<const ld::Atom*> _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 ld::Atom*>::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<ld::Internal::FinalSection*>::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<const ld::Atom*>::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<const ld::Atom*>::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<const ld::Atom*>::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<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
- ld::Internal::FinalSection* sect = *sit;
- if ( !orderableSection(sect) )
- continue;
- for (std::vector<const ld::Atom*>::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<ld::Internal::FinalSection*>::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<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
- // ld::Internal::FinalSection* sect = *sit;
- // for (std::vector<const ld::Atom*>::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
+++ /dev/null
-/* -*- 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__
+++ /dev/null
-/* -*- 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
-
#include "stub_x86_classic.hpp"
#include "stub_arm.hpp"
#include "stub_arm_classic.hpp"
-#include "stub_ppc_classic.hpp"
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:
}
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);
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());
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;
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;
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:
}
else if ( strcmp(arg, "-arch") == 0 ) {
const char* arch = ++i<argc? argv[i]: "";
- if ( strcmp(arch, "ppc64") == 0 )
- sPreferredArch = CPU_TYPE_POWERPC64;
- else if ( strcmp(arch, "ppc") == 0 )
- sPreferredArch = CPU_TYPE_POWERPC;
- else if ( strcmp(arch, "i386") == 0 )
+ if ( strcmp(arch, "i386") == 0 )
sPreferredArch = CPU_TYPE_I386;
else if ( strcmp(arch, "x86_64") == 0 )
sPreferredArch = CPU_TYPE_X86_64;
{
if ( r_type == GENERIC_RELOC_VANILLA )
return "pointer";
- else if ( r_type == PPC_RELOC_PB_LA_PTR )
- return "pb pointer";
else
return "??";
}
}
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());
}
}
else {
- macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)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";
}
}
};
-template <> const char* UnwindPrinter<ppc>::archName() { return "ppc"; }
-template <> const char* UnwindPrinter<ppc64>::archName() { return "ppc64"; }
template <> const char* UnwindPrinter<x86>::archName() { return "i386"; }
template <> const char* UnwindPrinter<x86_64>::archName() { return "x86_64"; }
template <> const char* UnwindPrinter<arm>::archName() { return "arm"; }
--- /dev/null
+##
+# 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
--- /dev/null
+int bar() { return 0; }
+
+__attribute__((constructor))
+void bar_init() { }
--- /dev/null
+int bar2() { return 0; }
+
+__attribute__((constructor))
+void bar2_init() { }
--- /dev/null
+int bar3() { return 0; }
+
+__attribute__((constructor))
+void bar3_init() { }
--- /dev/null
+int foo() { return 1; }
+
+__attribute__((constructor))
+void foo_init() { }
--- /dev/null
+int foo2() { return 1; }
+
+__attribute__((constructor))
+void foo2_init() { }
--- /dev/null
+int foo3() { return 1; }
+
+__attribute__((constructor))
+void foo3_init() { }
--- /dev/null
+/* -*- 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
--- /dev/null
+##
+# 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
--- /dev/null
+
+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
+
--- /dev/null
+
+extern "C" int ctr();
+extern "C" void dtr();
+
+class Foo
+{
+public:
+ Foo() : field(ctr()) { }
+ ~Foo() { dtr(); }
+private:
+ int field;
+};
+
+
+Foo f1;
+Foo f2;
+
+
--- /dev/null
+
+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
--- /dev/null
+#include <stdio.h>
+
+#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;
+}
+
--- /dev/null
+##
+# 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
--- /dev/null
+
+int main()
+{
+ return 0;
+}
##
-# Copyright (c) 2010 Apple Inc. All rights reserved.
+# Copyright (c) 2010-2011 Apple Inc. All rights reserved.
#
# @APPLE_LICENSE_HEADER_START@
#
TESTROOT = ../..
include ${TESTROOT}/include/common.makefile
+
#
# <rdar://problem/7438246> LTO with 'dead code strip' can't ignore unused functions with undefined references
+# <rdar://problem/10052396> LTO many have eliminated need for some undefines
#
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:
--- /dev/null
+
+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
--- /dev/null
+
+int xyz_f2;
+int xyz_f4;
+int other;
--- /dev/null
+/* -*- 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 <stdio.h>
+
+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;
+}
--- /dev/null
+_xyz_f4
+_xyz_mi4
+_xyz_f2
+_xyz_m3
+_xyz_m1
+_xyz_ms1
+_xyz_mi3
--- /dev/null
+_xyz_f4
+_xyz_mi4
+_xyz_f2
+_xyz_m3
+_xyz_m1
+_xyz_ms1
+
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: