From: Apple Date: Wed, 9 Sep 2009 21:47:10 +0000 (+0000) Subject: ld64-96.5.tar.gz X-Git-Tag: iphone-31^0 X-Git-Url: https://git.saurik.com/apple/ld64.git/commitdiff_plain/fb24a05017baddaa8cdc205852b134120bcc54ad ld64-96.5.tar.gz --- diff --git a/ChangeLog b/ChangeLog index ab1e984..77b9256 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,13 +1,155 @@ ------ Tagged ld64-95.9 -2009-02-13 Nick Kledzik +----- Tagged ld64-96.5 - Back out Linker changes for H2 hang - * src/ld/Options.cpp: remove fPreventPageCrossingBranches - * src/ld/MachOWriterExecutable.hpp: remove layout of __text so there are not page crossing branches - * src/ld/MachOReaderRelocatable.hpp: parse but ignore ARM_THUMB_32BIT_BRANCH reloc +2009-07-28 Nick Kledzik + Thumb mode compilation isn't working on 3.1 beta 2 + * Fix instructions used in kBranchIslandToThumb1 case + + +----- Tagged ld64-96.4 + +2009-06-22 Nick Kledzik + + platform linker should use platform ld_classic + * Fix Options::gotoClassicLinker() to use realpath()s + + +2009-06-22 Nick Kledzik + + * Fix Options::setIPhoneVersionMin() to handle 2.x through 9.x + + +----- Tagged ld64-96.3 + +2009-06-17 Nick Kledzik + + * Change section sorting so that arm and ppc stub section is immediately after __text section + + +2009-06-17 Nick Kledzik + + don't use no-PIC stubs in any dylibs - it might conflict with codesigning + * In StubAtom::StubAtom() don't use kStubNoPIC for OS dylibs + + +----- Tagged ld64-96.2 + +2009-06-09 Nick Kledzik + + * Back out page-cross branch work around + + +----- Tagged ld64-96.1 + +2009-06-05 Nick Kledzik + + * Fix "duplicate symbol cache-line-crossing-stub" error by giving placeholders unique names + * Fix -pie by allowing relocs in x86 stubs and stub helpers + + +----- Tagged ld64-96 + +2009-06-04 Nick Kledzik + + * Darwin x86_64 static codegen is really dynamic code gen, so use LTO_CODEGEN_PIC_MODEL_DYNAMIC + + +2009-06-03 Nick Kledzik + + use lto_codegen_set_assembler_path() + + +2009-06-03 Nick Kledzik + + * In src/ld/LTOReader.hpp, move where -save-temps .bc file is saved to be after code model set + + +2009-06-01 Nick Kledzik + + Link Time Optimization error with 'dead code strip' + hidden symbol + * scan newAtoms returned from optimize() looking for ones already in the symbol table + * add test case unit-tests/test-cases/lto-dead_strip-all-hidden + + +2009-05-19 Nick Kledzik + + make dyld stubs smaller/faster + * Add new addSynthesizedAtoms() method to Writer, called before atoms are sorted + * Fix throwf() and warning() to check printf types + * Add arm::kPointerDiff12 to support fast arm stubs + * Add new ContentType values for stubs and (non)lazy pointers + * Add new variant of arm stub this is one instruction + + +2009-05-13 Nick Kledzik + + * ld64.xcodeproj/project.pbxproj: add warnings to dyldinfo target + * src/other/dyldinfo.cpp: support classic LINKEDIT format + + +2009-05-12 Nick Kledzik + + * src/ld/MachOWriterExecutable.hpp: fix optimization to skip branch islands with ARM bl instructions + + +2009-05-12 Nick Kledzik + + creation of __unwind_info section can fail if hundreds of functions cannot be compact encoded + * src/ld/MachOWriterExecutable.hpp: fix when to make regular vs compressed pages + + +2009-05-08 Nick Kledzik + + * src/ld/ld.cpp: enhance -save-temps to also write out optimized bitcode file + + +2009-05-08 Nick Kledzik + + * src/ld/ld.cpp: fix -order_file_statistics to print each symbol not found and correct total + + +2009-05-08 Nick Kledzik + + linker should be able to coalesce UTF16 strings + * src/ld/MachOReaderRelocatable.hpp: parse __ustring section by labels but synthesize an + atom name based on the content. Leverage for __cfstring section + * unit-tests/test-cases/cfstring-utf16: update test case + + +2009-05-07 Nick Kledzik + + * src/ld/MachOWriterExecutable.hpp: put branch islands further apart if there is no thumb code + + +2009-05-07 Nick Kledzik + + LINKEDIT optimizations for iPhone + * src/ld/ObjectFile.h: Recognize iPhoneOS 3.1 + * src/ld/Options.cpp: iPhoneOS 3.1 => use compressed LINKEDIT + * src/ld/MachOWriterExecutable.hpp: support generating compressed LINKEDIT for arm + + +2009-05-04 Nick Kledzik + + Add linker support for ARM branch islands + Add labels to linker synthesized jump islands + * src/ld/MachOWriterExecutable.hpp: reworked BranchIslandAtom and createBranchIslands to support arm/thumb + * src/ld/ObjectFile.h: added kBranchIsland + * unit-tests/test-cases/branch-islands: updated test case to check arm/thumb + + +2009-04-30 Nick Kledzik + + * src/ld/Options.cpp: fix custom stack base address for arm + + +2009-04-30 Nick Kledzik + + likely incorrect warning about common symbols + * src/ld/Options.cpp: ignore LD_WARN_COMMONS in -r mode + ----- Tagged ld64-95.8.3 @@ -111,8 +253,4659 @@ * src/ld/MachOReaderRelocatable.hpp: support new ARM_THUMB_32BIT_BRANCH reloce +----- Tagged ld64-95.2.10 + +2009-04-02 Nick Kledzik + + corrupt metaclass entry in dynamic library + * src/ld/ld.cpp: change Section constructor to copy segment and section names + + +----- Tagged ld64-95.2.9 + +2009-04-02 Nick Kledzik + + Update ld64 for new triples introduced in 6654669 to support ARM LLVM + * src/ld/LTOReader.hpp: change "arm-" to "arm" so matching works for new triples + + +----- Tagged ld64-95.2.8 + +2009-03-24 Nick Kledzik + + anonymous functions have the compact unwind info computed wrong + * ld/MachOReaderRelocatable.hpp: use new compact unwind function in AnonymousAtom + + +----- Tagged ld64-95.2.7 + +2009-03-11 Nick Kledzik + + AddressBook incorrectly gets _objc_msgSend from WebKit + * src/ld/MachOReaderDylib.hpp: fix processIndirectLibraries() to not force a private re-export of a dylib + that is already explictly or implicitly linked. + * unit-tests/test-cases/re-export-optimizations-indirect: add test case + + +2009-03-10 Nick Kledzik + + dyld weak linking optimization leaves some symbols unbound + * src/ld/MachOWriterExecutable.hpp: be sure to create bind entry for a reference + to a symbol in a dylib that is a weak definition + * unit-tests/test-cases/coalesce_weak_def_in_dylib: add test case + + +2009-03-10 Nick Kledzik + + many OS i386 OS dylibs still have __IMPORT segment + * ld/MachOReaderRelocatable.hpp: moved where __IMPORT/__pointer is changed to __DATA/__nl_symbol_ptr + * unit-tests/test-cases/stripped-indirect-symbol-table: updated to test for this problem + + +----- Tagged ld64-95.2.6 + +2009-02-27 Nick Kledzik + + ld might set MH_WEAK_DEFINES when it should not + * src/ld/MachOWriterExecutable.hpp: only consider atoms in fRegularDefAtomsThatOverrideADylibsWeakDef + that will be exported when computing MH_WEAK_DEFINES + * unit-tests/test-cases/operator-new: updated to reproduce issue + + +----- Tagged ld64-95.2.5 + +2009-02-24 Nick Kledzik + + x86_64 obj-c runtime confused when static lib is stripped + * src/ld/MachOWriterExecutable.hpp: in setLocalNlist() don't use 'l' labels for x86_64 strings + * unit-tests/test-cases/objc-literal-pointers-strip: added test case + + +----- Tagged ld64-95.2.4 + +2009-02-23 Nick Kledzik + + * src/ld/MachOReaderRelocatable.hpp: ignore ARM_THUMB_32BIT_BRANCH relocs + + +2009-02-18 Nick Kledzik + + Writer::symbolIndex() uses a linear search and does not scale + * src/ld/MachOWriterExecutable.hpp: build a std::map so symbolIndex() scales better + + +2009-02-18 Nick Kledzik + + Use new compact encodings that handle all register permutations + * src/ld/Architectures.hpp: add kSectionOffset24 + * src/ld/ObjectFile.h: add getFDE() + * src/ld/MachOReaderRelocatable.hpp: use new libunwind functions to get new compact encoding + * src/ld/MachOWriterExecutable.hpp: use new compact encoding which includes offset in dwarf if needed + * src/other/unwinddump.cpp: update unwinddump output to display register save set + + +2009-02-16 Nick Kledzik + + runtime error with bundle for 10.5 that has weak external symols + * src/ld/ld.cpp: fix hybrid (10.5) compressed linkedit info for data pointing to weak definitions + + +2009-02-15 Nick Kledzik + + i386 relocation error with negative offsets from local labels + * src/ld/MachOReaderRelocatable.hpp: handle when base addr of scattered relocation does not point to a label + * unit-tests/test-cases/relocs-neg-from-local: add test case + + +2009-02-12 Nick Kledzik + + -dead_strip inhibits weak coalescing in no_dead_strip section + * src/ld/ld.cpp: remove atoms coalesced away from fLiveRootAtoms + * unit-tests/test-cases/dead_strip-weak-coalesce: added test case + + +2009-02-12 Nick Kledzik + + x86_64 weak_import broken for initialized data + * src/ld/MachOReaderRelocatable.hpp: use isWeakImportSymbol() in Reader::addRelocReference() + * src/other/dyldinfo.cpp: update to display weak_import attribute + * unit-tests/test-cases/weak_import: updated test case + + +2009-02-06 Nick Kledzik + + ld parsing of __eh_frame unwind information is slow + * src/ld/MachOReaderRelocatable.hpp: build a std::map of all __eh_frame relocations for x86_64 + + +----- Tagged ld64-95.2.3 + +2009-02-04 Nick Kledzik + + ld: warning: can't add line info to anonymous symbol + * src/ld/MachOReaderRelocatable.hpp: don't warn about line info in dyld stubs + + +----- Tagged ld64-95.2.2 + +2009-02-02 Nick Kledzik + + ld -r does not preserve the N_NO_DEAD_STRIP bit + * src/ld/MachOWriterExecutable.hpp: set N_NO_DEAD_STRIP based on dontDeadStrip() + * unit-tests/test-cases/dead_strip-r_symbol_desc: added test case + + +----- Tagged ld64-95.2.1 + +----- Tagged ld64-95.2.10 + +2009-04-02 Nick Kledzik + + corrupt metaclass entry in dynamic library + * src/ld/ld.cpp: change Section constructor to copy segment and section names + + +----- Tagged ld64-95.2.9 + +2009-04-02 Nick Kledzik + + Update ld64 for new triples introduced in 6654669 to support ARM LLVM + * src/ld/LTOReader.hpp: change "arm-" to "arm" so matching works for new triples + + +----- Tagged ld64-95.2.8 + +2009-03-24 Nick Kledzik + + anonymous functions have the compact unwind info computed wrong + * ld/MachOReaderRelocatable.hpp: use new compact unwind function in AnonymousAtom + + +----- Tagged ld64-95.2.7 + +2009-03-11 Nick Kledzik + + AddressBook incorrectly gets _objc_msgSend from WebKit + * src/ld/MachOReaderDylib.hpp: fix processIndirectLibraries() to not force a private re-export of a dylib + that is already explictly or implicitly linked. + * unit-tests/test-cases/re-export-optimizations-indirect: add test case + + +2009-03-10 Nick Kledzik + + dyld weak linking optimization leaves some symbols unbound + * src/ld/MachOWriterExecutable.hpp: be sure to create bind entry for a reference + to a symbol in a dylib that is a weak definition + * unit-tests/test-cases/coalesce_weak_def_in_dylib: add test case + + +2009-03-10 Nick Kledzik + + many OS i386 OS dylibs still have __IMPORT segment + * ld/MachOReaderRelocatable.hpp: moved where __IMPORT/__pointer is changed to __DATA/__nl_symbol_ptr + * unit-tests/test-cases/stripped-indirect-symbol-table: updated to test for this problem + + +----- Tagged ld64-95.2.6 + +2009-02-27 Nick Kledzik + + ld might set MH_WEAK_DEFINES when it should not + * src/ld/MachOWriterExecutable.hpp: only consider atoms in fRegularDefAtomsThatOverrideADylibsWeakDef + that will be exported when computing MH_WEAK_DEFINES + * unit-tests/test-cases/operator-new: updated to reproduce issue + + +----- Tagged ld64-95.2.5 + +2009-02-24 Nick Kledzik + + x86_64 obj-c runtime confused when static lib is stripped + * src/ld/MachOWriterExecutable.hpp: in setLocalNlist() don't use 'l' labels for x86_64 strings + * unit-tests/test-cases/objc-literal-pointers-strip: added test case + + +----- Tagged ld64-95.2.4 + +2009-02-23 Nick Kledzik + + * src/ld/MachOReaderRelocatable.hpp: ignore ARM_THUMB_32BIT_BRANCH relocs + + +2009-02-18 Nick Kledzik + + Writer::symbolIndex() uses a linear search and does not scale + * src/ld/MachOWriterExecutable.hpp: build a std::map so symbolIndex() scales better + + +2009-02-18 Nick Kledzik + + Use new compact encodings that handle all register permutations + * src/ld/Architectures.hpp: add kSectionOffset24 + * src/ld/ObjectFile.h: add getFDE() + * src/ld/MachOReaderRelocatable.hpp: use new libunwind functions to get new compact encoding + * src/ld/MachOWriterExecutable.hpp: use new compact encoding which includes offset in dwarf if needed + * src/other/unwinddump.cpp: update unwinddump output to display register save set + + +2009-02-16 Nick Kledzik + + runtime error with bundle for 10.5 that has weak external symols + * src/ld/ld.cpp: fix hybrid (10.5) compressed linkedit info for data pointing to weak definitions + + +2009-02-15 Nick Kledzik + + i386 relocation error with negative offsets from local labels + * src/ld/MachOReaderRelocatable.hpp: handle when base addr of scattered relocation does not point to a label + * unit-tests/test-cases/relocs-neg-from-local: add test case + + +2009-02-12 Nick Kledzik + + -dead_strip inhibits weak coalescing in no_dead_strip section + * src/ld/ld.cpp: remove atoms coalesced away from fLiveRootAtoms + * unit-tests/test-cases/dead_strip-weak-coalesce: added test case + + +2009-02-12 Nick Kledzik + + x86_64 weak_import broken for initialized data + * src/ld/MachOReaderRelocatable.hpp: use isWeakImportSymbol() in Reader::addRelocReference() + * src/other/dyldinfo.cpp: update to display weak_import attribute + * unit-tests/test-cases/weak_import: updated test case + + +2009-02-06 Nick Kledzik + + ld parsing of __eh_frame unwind information is slow + * src/ld/MachOReaderRelocatable.hpp: build a std::map of all __eh_frame relocations for x86_64 + + +----- Tagged ld64-95.2.3 + +2009-02-04 Nick Kledzik + + ld: warning: can't add line info to anonymous symbol + * src/ld/MachOReaderRelocatable.hpp: don't warn about line info in dyld stubs + + +----- Tagged ld64-95.2.2 + +2009-02-02 Nick Kledzik + + ld -r does not preserve the N_NO_DEAD_STRIP bit + * src/ld/MachOWriterExecutable.hpp: set N_NO_DEAD_STRIP based on dontDeadStrip() + * unit-tests/test-cases/dead_strip-r_symbol_desc: added test case + + +----- Tagged ld64-95.2.1 + +2009-01-29 Nick Kledzik + + gcc DejaGnu failure: building longcall/dylib library + * src/ld/MachOWriterExecutable.hpp: if no __DATA sections insert non-lazy pointers at end of __TEXT segment + * unit-tests/test-cases/no-data-bundle: added test case + + ----- Tagged ld64-95.2 2009-01-06 Nick Kledzik strip -S fails with "new trie is larger than original" + * src/other/PruneTrie.cpp: don't align trie more than original trie was aligned + + +----- Tagged ld64-95.1 + +2008-12-21 Nick Kledzik + + * src/ld/MachOWriterExecutable.hpp: in new linkedit format, make sure only exported symbols + make it into weak binding info + + +----- Tagged ld64-95 + +2008-12-18 Nick Kledzik + + * src/ld/Options.cpp: move check for fSharedRegionEligible until fPrebind has stabilized + + +2008-12-18 Nick Kledzik + + Generate new compressed LINKEDIT when targeting 10.6 + * src/ld/Options.cpp: turn on compressed LINKEDIT by default + + +----- Tagged ld64-94.1 + +2008-12-16 Nick Kledzik + + * src/ld/Options.cpp: Fix -F handling in buildSearchPaths() + + +----- Tagged ld64-94 + +2008-12-15 Nick Kledzik + + * doc/man/man1/ld.1: document new options + + +2008-12-15 Nick Kledzik + + linker should enforce all .o files have same sub-type, and ignore sub-type of dylibs + * doc/man/man1/ld.1: update man page about -allow_sub_type_mismatches + * src/ld/ld.cpp: call validFile() with new arguments + * src/ld/MachOReaderRelocatable.hpp: add new arguments to validFile() + * src/ld/Options.cpp: Support LD_ALLOW_CPU_SUBTYPE_MISMATCHES and -allow_sub_type_mismatches + + +2008-12-15 Nick Kledzik + + -syslibroot should skip standard search paths not in the SDK + * src/ld/Options.cpp: in buildSearchPaths() if an SDK is specified don't add + standard search paths not in the SDK. + + +2008-12-15 Nick Kledzik + + ld: remove "can't make compact unwind encoding" warning + * src/ld/ObjectFile.h: add fWarnCompactUnwind + * src/ld/Options.cpp: -warn_compact_unwind --> fWarnCompactUnwind + * src/ld/MachOReaderRelocatable.hpp: test fWarnCompactUnwind before warning + + +2008-12-15 Nick Kledzik + + Add dtrace usdt support for arm to ld64 + * src/ld/MachOWriterExecutable.hpp: handle arm::kDtraceIsEnabledSite + * unit-tests/test-cases/dtrace-static-probes: use is-enabled in test case + + +----- Tagged ld64-93 + +2008-12-11 Nick Kledzik + + * src/ld/ObjectFile.h: add fIPhoneVersionMin to track min iPhoneOS version + * src/ld/Options.cpp: use fIPhoneVersionMin + + +2008-12-11 Nick Kledzik + + non-lazy pointer to non-global tentative definition encoded wrong + * src/ld/MachOWriterExecutable.hpp: don't use INDIRECT_SYMBOL_LOCAL for tentative definitions + * unit-tests/test-cases/non-lazy-r: updated test case + + +2008-12-11 Nick Kledzik + + kernel fails to boot when ld64 used for intermediate ld -r step + * src/ld/MachOWriterExecutable.hpp: in -r mode when generating a scattered sect-diff reloc for + i386/arm, special case when from target is not the atom + the relocation is in. + * unit-tests/test-cases/relocs-asm: update test case + + +2008-12-11 Nick Kledzik + + * src/ld/ld.cpp: handle new __program_vars section + * src/ld/MachOWriterExecutable.hpp: handle inserting synthesized sections when there is no __dyld section + + +2008-12-11 Nick Kledzik + + * src/ld/MachOReaderRelocatable.hpp: Fix getDescription() to work when direct reference is to anonymous atom + + +2008-12-10 Nick Kledzik + + * src/ld/Options.cpp: enable LD_FORCE_NO_PREBIND to be used with arm + + +2008-12-10 Nick Kledzik + + Developer tool to print the new compressed LINKEDIT information + * src/other/dyldinfo.cpp: fix typo in usage() + + +2008-12-05 Nick Kledzik + + SnowLeopard kernel should compile warning free + * src/ld/MachOReaderRelocatable.hpp: correct parse two global labels at end of section and make one an alias + * unit-tests/test-cases/end-label: update test case + + +2008-12-04 Nick Kledzik + + Better warning than "PPC_RELOC_JBSR should not be using an external relocation" + * src/ld/MachOReaderRelocatable.hpp: issue warning with .o path if it was compiled with -mlong-branch + + +2008-12-04 Nick Kledzik + + linker should not map __pointers -> __nl_symbol_ptr unless actually making new LINKEDIT + * src/ld/ObjectFile.h: add fMakeCompressedDyldInfo for readers to see + * src/ld/Options.cpp: set fMakeCompressedDyldInfo for readers to see + * src/ld/MachOReaderRelocatable.hpp: check fMakeCompressedDyldInfo + + +2008-12-02 Nick Kledzik + + * src/ld/debugline.c: fix error handling in line_open() + + +2008-11-26 Nick Kledzik + + vtable with thumb entries broke after ld -r + * src/ld/MachOReaderRelocatable.hpp: if target of reloc is thumb, mask thumb bit off addend + * unit-tests/test-cases/thumb-pointer: added test case + + +2008-11-26 Nick Kledzik + + * src/ld/Option.cpp: Fix how crashreporterBuffer is created to not miss some arguments + + +2008-11-24 Nick Kledzik + + Security.framework has some duplicate FDEs for some functions + * src/ld/ld.cpp: remove fDeadAtoms from fLiveAtoms when there are weak atoms overriden by late loads + * unit-tests/test-cases/dead_strip-archive-eh: added test case + + +----- Tagged ld64-92 + +2008-11-21 Nick Kledzik + + * src/ld/MachOReaderDylib.hpp: if export_size is zero, no need to parse trie + * src/abstraction/MachOTrie.hpp: gracefully handle empty trie + + +2008-11-21 Nick Kledzik + + strip(1) support for new compressed LINKEDIT information + * ld64.xcodeproj/project.pbxproj: build and install new libprunetrie.a + * src/other/prune_trie.h: added + * src/other/PruneTrie.cpp: implements prune_trie() + + +2008-11-21 Nick Kledzik + + * src/ld/ld.cpp: if an export file is used and all weak symbols are masked, don't set WEAK_DEFINES + * unit-tests/test-cases/weak-def-flag: added test case + + +2008-11-20 Nick Kledzik + + Generate new compressed LINKEDIT when targeting 10.6 + * src/ld/MachOWriterExecutable.hpp: support generating new compressed format + * src/ld/MachOReaderRelocatable.hpp: new compress format implies non-lazy pointers in __DATA for i386 + * src/ld/MachOReaderDylib.hpp: support linking aginst new format + * src/ld/Options.cpp: suppport -exported_symbols_order and -no_compact_linkedit + * src/ld/ld.cpp: track which atoms have weak counter parts in dylibs + * src/other/dyldinfo.cpp: added tool to display new LINKEDIT format + * ld64.xcodeproj/project.pbxproj: add dyldinfo tool + * unit-tests/*: lots of fixes to work with new format + + +2008-11-20 Nick Kledzik + + ld64 should preserve N_WEAK_REF when linking MH_KEXT_BUNDLEs + * src/ld/MachOWriterExecutable.hpp: set up fWeakImportMap in synthesizeKextGOT() + + +2008-11-19 Nick Kledzik + + VideoToolbox.framework has bad __TEXT.__eh_frame info + * src/ld/Options.cpp: add -no_eh_labels option for use with -r + * src/ld/MachOWriterExecutable.hpp: generate correct x86_64 labeless relocs in -r mode + * src/ld/MachOReaderRelocatable.hpp: now ignore all labels and relocations in + __TEXT/__eh_frame section and rely on getCFIs() from libunwind + * unit-tests/test-cases/eh-coalescing-no-labels: add test case + + +2008-11-19 Nick Kledzik + + LTO doesn't like dtrace symbols + * src/ld/LTOReader.hpp: ignore __dtrace_probe undefines in bitcode files + + +2008-11-14 Nick Kledzik + + * src/abstraction/MachOFileAbstraction.hpp: fix to work with 10.5 headers + + +----- Tagged ld64-91 + +2008-11-07 Nick Kledzik + + Remove COMPACT_UNWIND_SUPPORT conditionalizing + + +2008-11-06 Nick Kledzik + + Reorganize source layout. ld sources are now in "ld", + and other tools are in "other". + + +2008-11-05 Nick Kledzik + + * ld64.xcodeproj/project.pbxproj: start installing unwinddump tool + * src/UnwindDump.cpp: support -arch option + * doc/man/man1/unwinddump.1: create man page + + +2008-11-05 Nick Kledzik + + linker should put cpusubtype in n_sect field of nlist entry for N_OSO debug note entries + * src/ld.cpp: in synthesizeDebugNotes() set other field of OSO to be subtype + + +2008-11-05 Nick Kledzik + + Need a linker option to load all objects from one library + * src/Options.cpp: support -force_load option + * src/ArchiveReader.hpp: Add fForceLoad ivar + * doc/man/man1/ld.1: update man page with -force_load option + * unit-tests/test-cases/archive-force-load: add test case + + +2008-11-05 Nick Kledzik + + Dtrace Probe Warnings: SnowLeopard kernel should compile warning free + * src/ld.cpp: don't generate GSYM stabs for old style __dtrace_probe + * src/MachOReaderRelocatable.hpp: fix test for deciding if a symbol is an alias + + +2008-11-04 Nick Kledzik + + ADOBE: XCODE: ld: duplicate typeinfo in executable + * src/ld.cpp: in dead-strip mode, record overriden symbols and later rebind all uses + * unit-tests/test-cases/dead_strip-archive-weak: add test case + + +2008-11-03 Nick Kledzik + + support increased branch range in Thumb-2 + * src/MachOReaderRelocatable.hpp: handle full branch range in addRelocReference() + * unit-tests/test-cases/branch-distance: added test case + +2008-10-31 Devang Patel + + Sqlite 3.5.4 built with lvm-gcc-4.2 -O4 fails regression test + * src/LTOReader.hpp: Use real atom scope when real atom is available. + Preserve globals while optimizing an executable. + +2008-10-30 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: support all encodings in getEncodedP() + + +----- Tagged ld64-90 + +2008-10-30 Nick Kledzik + + icc has dwarf unwind info that is different than gcc + * src/MachOReaderRelocatable.hpp: support more encodings in getEncodedP() + + +2008-10-23 Nick Kledzik + + build ld64 for x86_64 + * ld64.xcodeproj/project.pbxproj: add X86_64 to valid archs + + +2008-10-23 Nick Kledzik + + * ld64.xcodeproj/project.pbxproj: use generated @$(DERIVED_FILE_DIR)/linker_opts for extra + linker options. This allows linker to be built if LTO headers and libs are missing. + + +2008-10-23 Nick Kledzik + + Linker warning not shown in the Xcode build log + * src/Options.cpp: add colon to format string in warning() + + +----- Tagged ld64-89.3 + +2008-10-24 Nick Kledzik + + ld64-89 broke TOT OpenGL libProgrammability x86_64 build + * src/MachOReaderRelocatable.hpp: add cast in getEncodedP() + + +----- Tagged ld64-89.2 + +2008-10-23 Nick Kledzik + + SnowLeopard: Libsystem built with ld64-89.1 causes crashes + * src/MachOReaderRelocatable.hpp: when FDE information causes __text atom to be split, make the + atoms follow-on pairs. + + +----- Tagged ld64-89.1 + +2008-10-22 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: for x86_64 __eh_frame force direct references + + +2008-10-21 Nick Kledzik + + * src/ObjectDump.cpp: Use getContentType() to see if content type is a cstring + + +----- Tagged ld64-89 + +2008-10-21 Nick Kledzik + + 10A180 with QT-1119 roots: iTunes and QuickTime cannot play back purchased videos + linker should not need .eh labels + * src/MachOWriterExecutable.hpp: use kCFIType to set section attributes + * src/MachOReaderRelocatable.hpp: use libunwind's CFITuple to parse __eh_frame content + * src/ld.cpp: Add adjustScope() phase instead of demoting scope within symboltable.add() + * unit-tests/test-cases/eh-stripped-symbols: added test case + + +----- Tagged ld64-88.1 + +2008-10-16 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: Fix uses of COMPACT_UNWIND_SUPPORT + * src/MachOWriterExecutable.hpp: Fix uses of COMPACT_UNWIND_SUPPORT + + +2008-09-30 Nick Kledzik + + OBJC2: Reorder __DATA,__objc_* sections by writedness + * src/ld.cpp: change sorting order of Sections + + +2008-09-29 Nick Kledzik + + Executable produced by XCode 3.2 on 10.6 crashes on 10.3.9 + * src/MachOWriterExecutable.hpp: set objc_module_info_addr field of module table + + +----- Tagged ld64-88 + +2008-09-25 Nick Kledzik + + kexts need to be built as MH_BUNDLE mach-o files + * src/ld.cpp: use getUndefinedProxyAtom() with kKextBundle + * src/MachOFileAbstraction.hpp: add MH_KEXT_BUNDLE + * src/Options.cpp: support -kext for all architectures + * src/MachOWriterExecutable.hpp: support kKextBundle to make a bundle like kext + * unit-tests/test-cases/kext-basic: added test case + + +2008-09-25 Nick Kledzik + + ld invoking wrong ld_classic + * src/Options.cpp: first look for ld_classic relative to ld itself + + +2008-09-25 Nick Kledzik + + ld fails to link references from 32 bit code into 64 bit code + Desired 32-bit absolute relocation + * src/Architectures.hpp: add x86_64::kPointer32 + * src/MachOReaderRelocatable.hpp: support X86_64_RELOC_UNSIGNED with length=2 + * src/MachOWriterExecutable.hpp: support x86_64::kPointer32 + * unit-tests/test-cases/relocs-asm/relocs-asm.s: added 32-bit pointer tests + + +2008-09-25 Nick Kledzik + + Should be able to mark dylibs as auto-dead-dylib-strip + * src/Options.h: add fMarkDeadStrippableDylib + * src/MachOReaderDylib.hpp: check MH_DEAD_STRIPPABLE_DYLIB + * src/ObjectFile.h: add deadStrippable() + * src/MachOFileAbstraction.hpp: add MH_DEAD_STRIPPABLE_DYLIB + * src/Options.cpp: support -mark_dead_strippable_dylib + * src/MachOWriterExecutable.hpp: test reader->deadStrippable(), set MH_DEAD_STRIPPABLE_DYLIB + * doc/man/man1/ld.1: update man page + * unit-tests/test-cases/dead_strippable_dylib: added test case + + +2008-09-25 Nick Kledzik + + ER: Add -seg_page_size option + * src/Options.cpp: add -seg_page_size option + * src/MachOWriterExecutable.hpp: use new page size info when laying out segments + * doc/man/man1/ld.1: update man page + + +2008-09-24 Nick Kledzik + + -arch_errors_fatal not working + * src/ld.cpp: check fOptions.errorOnOtherArchFiles() + * src/Options.cpp: turn -arch_errors_fatal into fOptions.errorOnOtherArchFiles() + + +2008-09-24 Nick Kledzik + + CrashTracer: [USER] 1 crash in ld at ld: 0x5ce02 + * src/ld.cpp: abort if resolve() finds an unresolved reference, rather than allow a future crash + + +2008-09-24 Nick Kledzik + + linker crashes linking X86-64 with -fwritable-strings + * src/MachOReaderRelocatable.hpp: handle unbound cfstring references + * unit-tests/test-cases/cfstring-coalesce: update test case + + +2008-09-24 Nick Kledzik + + ld64: bl out of range (-17147704 max is +/-16M) on ppc + * src/MachOWriterExecutable.hpp: tweak branch island regions to be every 14MB instead of 15MB + + +2008-09-24 Nick Kledzik + + -filelist fails with comma in path + * src/Options.cpp: in loadFileList() first try without special comma meaning + * unit-tests/test-cases/filelist/Makefile: update test case + + +2008-09-23 Nick Kledzik + + nop not used when aligning functions in -r mode + * src/MachOWriterExecutable.hpp: change check for when to pad with nops to not test segment's name + + +2008-09-23 Nick Kledzik + + "-pie can only be used when linking a main executable" should be a warning, not an error + * src/Options.cpp: make -pie on a dylib or bundle be a warning instead of an error + + +2008-09-23 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: add warning if dwarf cannot be encoded as compact unwind + + +2008-09-18 Nick Kledzik + + * src/LTOReader.hpp: re-enable use of lto_codegen_debug_options() + + +2008-09-16 Nick Kledzik + + ld does not always set S_CSTRING_LITERALS on __TEXT,__cstring + * src/MachOReaderRelocatable.hpp: add getContentType() to SymbolAtom + * src/MachOWriterExecutable.hpp: for x86_64 don't override named cstrings with LC* name + + +2008-09-10 Nick Kledzik + + * Options.cpp: add __crashreporter_info__ to communicate command line to crash reporter + * ld64.xcodeproj/project.pbxproj: leave local symbols in ld to provide better crash reports + + +2008-09-08 Nick Kledzik + + 161569 GCC 4.2 - breakpoints no longer work for a large number of functions + * src/MachOReaderRelocatable.hpp: support DW_FORM_strp out-of-line strings when parsing line table + + +2008-09-02 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: fix compact unwind personality for dyld and -slow_stubs + + +2008-08-29 Nick Kledzik + + -weak_library no longer forces uses to be weak_import + * src/MachOWriterExecutable.hpp: use fWeakImport on dylib to force proxy atoms into fWeakImportMap + * unit-tests/test-cases/weak_import-force: added test case + + +2008-08-29 Nick Kledzik + + linker should order __DATA segment to reduce dyld dirtied pages + * src/Options.cpp: add fOrderData and support -no_data_order + * src/ld.cpp: modify tweakLayout() to sort atoms with relocations to start of __data section + + +2008-08-27 Nick Kledzik + + * src/Options.cpp: back out + + +----- Tagged ld64-87.5 + +2008-08-26 Nick Kledzik + + some projects show _Unwind_Resume coming from libSystem.B.dylib + * src/Options.cpp: swap any early symlinks to libSystem with libgcc_s + + +----- Tagged ld64-87.4 + +2008-08-25 Nick Kledzik + + some projects show _Unwind_Resume coming from libSystem.B.dylib + * src/Options.cpp: swap any early libSystem with libgcc_s + + +2008-08-15 Nick Kledzik + + Unable to build ppc debug builds (linker out of range error) + * src/MachOWriterExecutable.hpp: in addPPCBranchIslands() look ahead so large atoms don't push out branch islands + + +----- Tagged ld64-87.3.1 + +2008-09-08 Nick Kledzik + + i386 dylibs have incorrect personality pointers when put in dyld shared cache + * src/MachOWriterExecutable.hpp: in addCrossSegmentRef() handle kImageOffset32 to __IMPORT segment + + +----- Tagged ld64-87.3 + +2008-08-09 Nick Kledzik + + work around compiler gcc_except_table alignment + * src/ObjectFile.h: change getLSDA() to return a reference instead of an atom + * src/MachOReaderRelocatable.hpp: special case __eh_frame 64-bit pointer diff relocations + * src/MachOWriterExecutable.hpp: track lsda offset when creating __unwind_info section + * src/UnwindDump.cpp: log when LDSA content does not start with 0xFF + +----- Tagged ld64-87.2 + +2008-08-07 Nick Kledzik + + 10A141: libuwind falls back to dwarf and makes whole system super slow + * src/MachOWriterExecutable.hpp: Fix sign extension bug with x86_64::kPointerDiff24 + * src/UnwindDump.cpp: warn about mangled LSDA entries when dumping unwind section + + +----- Tagged ld64-87.1 + +2008-08-03 Nick Kledzik + + * src/LTOReader.hpp: Don't use lto_codegen_debug_options until newer libLTO.dylib is available + + +----- Tagged ld64-87 + +2008-07-21 Nick Kledzik + + * src/Options.cpp: Always set fAutoOrderInitializers=false for dyld + + +2008-07-21 Nick Kledzik + + * src/MachOWriterExecutable.hpp: fix when regular vs compressed __unwind_info pages are generated + * src/UnwindDump.cpp: fix function name decoding in regular pages + + +2008-07-21 Nick Kledzik + + * ld64.xcodeproj/project.pbxproj: don't allow ld to build for x86_64 until libdtrace.dylib is available + + +2008-07-18 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: don't crash if debug_line section has no line table + + +2008-07-18 Nick Kledzik + + Duplicate probe firings in Security.framework + * src/LTOReader.hpp: optimize() now returns atoms optimized away + * src/ObjectFile.h: optimize() should return if it did anything + * src/ArchiveReader.hpp: pass through optimize() result + * src/ld.cpp: rework dtrace probe processing as a new pass to prevent double counting + + +2008-07-15 Nick Kledzik + + automatically order initializers to start of __TEXT + * src/Options.cpp: add -no_order_inits option + * src/MachOReaderRelocatable.hpp: merge __StaticInit into __text + * src/ObjectFile.h: add fAutoOrderInitializers + * src/ld.cpp: sort initializer to start of __text and terminators to end + * doc/man/man1/ld.1: add doc about -no_order_inits + * unit-tests/test-cases/init-order: add test case + +2008-07-15 Nick Kledzik + + Only add LC_SEGMENT_SPLIT_INFO to dylibs that might be in the shared cache + * src/MachOWriterExecutable.hpp: re-layout load commands after split-seg data computed + * src/Options.cpp: non-public install name will disable split-seg load command + + +2008-07-14 Nick Kledzik + + ld -r for x86_64 is changing visibility of cstring constants + * src/MachOWriterExecutable.hpp: force x86_64 cstring labels to be local in -r mode + * unit-tests/test-cases/cstring-label: added test case + + +2008-07-11 Nick Kledzik + + ld not adding updating LC_SEGMENT_SPLIT_INFO with __unwind_info section + * src/MachOWriterExecutable.hpp: run createSplitSegContent() after __unwind_info section is created + +2008-07-10 Nick Kledzik + + * src/LTOReader.hpp: improve missing symbol error message + + +2008-07-09 Nick Kledzik + + linker should order __DATA segment to reduce dyld dirtied pages + * src/ld.cpp: first phase, order sections + + +2008-07-08 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: remove "coal" sections when creating a final linked image + + +2008-07-08 Nick Kledzik + + ld: add support for mllvm LTO options + * src/Options.cpp: support -mllvm option + * src/LTOReader.hpp: call lto_codegen_debug_options() with -mllvm options + * src/ld.cpp: pass llvmOptions to optimize() + * src/Options.h: add fLLVMOptions + * src/ArchiveReader.hpp: add llvmOptions parameter to optimize() + * src/ObjectFile.h: add llvmOptions parameter to optimize() + * unit-tests/test-cases/lto-llvm-options: add test case + + +2008-07-07 Nick Kledzik + + Linker fails with: 24-bit pointer diff out of range in unwind info in unwind info from... + * src/MachOWriterExecutable.hpp: fix when to fallback to uncompressed unwind info + + +2008-07-03 Nick Kledzik + + ld crash with gcc-4.0 code that uses a zero sized array + * src/MachOReaderRelocatable.hpp: handle zero size atom in a zero sized section + + +2008-07-03 Nick Kledzik + + ld crashes when bad ppc relocs are found + * src/MachOReaderRelocatable.hpp: change all missing PAIR warnings to errors + + +2008-07-02 Nick Kledzik + + when linking a kext the static linker should leave a pad in the headers to allow code signing + * src/MachOWriterExecutable.hpp: add padding for load commands in object files + * unit-tests/test-cases/code-signed-object-file: added test case + + +2008-07-02 Nick Kledzik + + LC_SEGMENT_64 filesize incorrect for MH_OBJECT filetype + * src/MachOWriterExecutable.hpp: correctly set segment size info in object files + * unit-tests/test-cases/no-object-symbols: add test case + + +2008-06-26 Nick Kledzik + + * ld64.xcodeproj/project.pbxproj: enable ld and rebase targets to build for x86_64 + * src/rebase.cpp: remove unused fRelocBase field that was not 64-bit clean + * src/MachOReaderRelocatable.hpp: fix getEncodedP() to be 64-bit clean + + +----- Tagged ld64-86.3 + +2008-06-17 Nick Kledzik + + * src/ld.cpp: fix loadUndefines() to double check undefine symbol was not already loaded + + +----- Tagged ld64-86.2 + +2008-06-14 Nick Kledzik + + * srd/ld.cpp: Add NULL check in getTentativesNames() + + +----- Tagged ld64-86.1 + +2008-06-06 Nick Kledzik + + * src/MachOWriterExecutable.hpp: fix header padding calculation for dyld + + +----- Tagged ld64-86 + +2008-06-04 Nick Kledzik + + * src/LTOReader.hpp: if lto_codegen_add_module() fails, add explanation to error message + + +2008-06-04 Nick Kledzik + + * src/ObjectFile.h: add deadAtoms parameter to optimize() + * src/ld.cpp: ditto + * src/ArchiveReader.hpp: ditto + * src/MachOReaderRelocatable.hpp: handle llvm use of 0x1B pointer encodings in CIEs + * src/LTOReader.hpp: make sure libLTO.dylib knows about any llvm symbol coalesced away + * unit-tests/test-cases/lto-weak-native-override: add test case + + +2008-06-04 Nick Kledzik + + LTO : 176.gcc and 177.mesa build failure at -O4 + * src/LTOReader.hpp: make sure internal is returned by getAtoms() + * unit-tests/test-cases/lto-archive-dylib: update test case + + +2008-06-03 Nick Kledzik + + fix for 5613343 need to search for definitions for common symbols is broken + * src/ld.cpp: modify loadUndefines() to check for undefines in all files and tentative definitions but only in archives + * src/machochecker.cpp: check for undefine symbols and external symbols with same name + * unit-tests/test-cases/tentative-and-archive: update test case + + +2008-06-03 Nick Kledzik + + linker produces wrong result for 16-bit call relocations + * src/MachOReaderRelocatable.hpp: properly parse i386 scattered relocs for word sized pc-rel vanilla + * src/MachOWriterExecutable.hpp: propery compute displacement for x86::kPCRel16 + * unit-tests/test-cases/relocs-asm: update test case with callw instructions + + +2008-06-03 Nick Kledzik + + Building kext x86_64 with unexported symbols file causes linking problems + * src/MachOWriterExecutable.hpp: better check when creating undefined proxy atoms + * unit-tests/test-cases/unexported_symbols_list-r: added test case + + +2008-06-02 Nick Kledzik + + S_CSTRING_LITERALS section type not preserved in executable + * src/ObjectFile.h: added ContentType + * src/MachOReaderRelocatable.hpp: set ContentType for anonymous string literals + * src/MachOWriterExecutable.hpp: set S_CSTRING_LITERALS if ContentType is kCStringType + * unit-tests/test-cases/cstring-custom-section: added test case + + +2008-06-02 Nick Kledzik + + linker should produce __unwind_info section in final linked images + * src/ld.cpp: sort __unwind_info then __eh_frame section to end of __TEXT + * src/Architectures.hpp: add kImageOffset32 and kPointerDiff24 + * src/ObjectFile.h: add compact unwind info support + * src/MachOReaderRelocatable.hpp: add compact unwind info support + * src/MachOFileAbstraction.hpp: add C++ wrappers for unwind section layout + * src/UnwindDump.cpp: new tool for dumping __unwind_info section + * src/MachOWriterExecutable.hpp: create __unwind_info section when needed + * src/ObjectDump.cpp: print unwind info + + +2008-06-02 Nick Kledzik + + * unit-tests/test-cases/llvm-integration: split out some test cases + * unit-tests/test-cases/lto-preload-pie: added + * unit-tests/test-cases/lto-archive-dylib: added + + +2008-05-30 Nick Kledzik + + * unit-tests: fixes to build all tests with with gcc-4.2 on SnowLeopard + + +2008-05-30 Nick Kledzik + + support -preload option to generate MH_PRELOAD binaries compatible with mtoc(1) and EFI + * src/ld.cpp: add entryPoint parameter to optimize() + * src/ArchiveReader.hpp: ditto + * src/ObjectFile.h: ditto + * src/LTOReader.hpp: use entryPoint parameter to optimize() + * src/Options.h: add kPreload and segment alignment + * src/Options.cpp: support -preload and -segalign + * src/MachOWriterExecutable.hpp: support kPreload and non-page aligned segments + + +2008-05-30 Nick Kledzik + + ld should warn if passed -r and also dylibs + * src/ld.cpp: check for spurious dylibs in Linker::addDylib() + + +----- Tagged ld64-85.6 + +2008-11-01 Nick Kledzik + + support increased branch range in Thumb-2 + * src/MachOWriterExecutable.hpp: in fixUpReferenceFinal() support new longer branch range + + +2008-11-01 Nick Kledzik + + ld warning: unknown option to -iphoneos_version_min, not 1.x or 2.x + * src/Options.cpp: In setIPhoneVersionMin() support 3.x + + +----- Tagged ld64-85.5 + +2008-09-17 Nick Kledzik + + vtable pointers can be missing thumb bit + * src/MachOWriterExecutable.hpp: Writer::fixUpReferenceFinal() OR in the 1 bit if the target + of a arm::kReadOnlyPointer is thumb. + + +----- Tagged ld64-85.4 + +2008-08-11 Nick Kledzik + + ld should ignore LD_PREBIND when processing a static archive + * src/MachOWriterExecutable.hpp: in setImportNlist() never use N_PBUD for object files + +----- Tagged ld64-85.3 + +2008-07-14 Nick Kledzik + + Prebinding busted in DTSB + * src/Options.cpp: check for libstdc++.6.0.[49] in seg_addr_table + + +----- Tagged ld64-85.2 + +2008-05-06 Nick Kledzik + + ARM ld should take W bit off of maxprot for __TEXT segment + * src/MachOWriterExecutable.hpp: for iPhone always set maxprot to be initprot in all segments + + +2008-05-06 Nick Kledzik + + encryptable images may not be signable + * src/MachOWriterExecutable.hpp: use minimum header padding when aligning __text section + + +----- Tagged ld64-85 (Xcode 3.1) + +2008-04-29 Nick Kledzik + + * ld64.xcodeproj/project.pbxproj: is moving from /usr/local/include to /Developer/usr/local/include + + +2008-04-29 Nick Kledzik + + ld doesn't honor "rightmost" -syslibroot argument + * src/Options.cpp: if last -syslibroot is /, then ignore all syslibroots + + +2008-04-29 Nick Kledzik + + GLRendererFloat has bad __eh_frame section caused by mixing llvm-gcc and gcc object files + * src/MachOReaderRelocatable.hpp: make all atoms in __eh_frame section have 1-byte alignment + * src/MachOWriterExecutable.hpp: make __eh_frame section have pointer sized alignment + + +2008-04-17 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: better cpu subtype support + + +2008-04-14 Nick Kledzik + + ld64 has bad ARM branch island check + * src/MachOWriterExecutable.hpp: in addBranchIslands() don't force large arm programs to fail + + +2008-04-10 Nick Kledzik + + * src/MachOWriterExecutable.hpp: fix stubs used with lazy dylibs + + +----- Tagged ld64-84.4 + +2008-04-10 Nick Kledzik + + SPEC2000/eon built with -mdynamic-no-pic won't run + * src/Architectures.hpp: added arm::kReadOnlyPointer + * src/MachOReaderRelocatable.hpp: generate arm::kReadOnlyPointer + * src/MachOWriterExecutable.hpp: use arm::kReadOnlyPointer + * src/machochecker.cpp: allow MH_PIE bit + * unit-tests/test-cases/switch-jump-table: added test cases + + +----- Tagged ld64-84.3 + +2008-04-09 Nick Kledzik + + -undefined dynamic_lookup busted + * src/ld.cpp: don't create proxy atom when scanning for dylib duplicates + * unit-tests/test-cases/tentative-and-archive: use -undefined dynamic_lookup + + +----- Tagged ld64-84.2 + +2008-04-04 Nick Kledzik + + * src/ld.cpp: don't add .eh symbols to symbol table in -r mode + * unit-tests/test-cases/eh-coalescing-r: update to test out of order coalescing + + +----- Tagged ld64-84.1 + +2008-03-28 Nick Kledzik + + ld should prefer architecture-specific variant over generic in fat object file + * src/Options.cpp: fully process -arch arguments into fArchitecture and fSubArchitecture + * src/ld.cpp: when -arch with a subtype is used, try to find the exact subtype from fat files + * unit-tests/test-cases/cpu-sub-types-preference: added test cases for arm and ppc + + +----- Tagged ld64-84 + +2008-03-28 Nick Kledzik + + * src/LTOReader.hpp: don't print lto version, if lto is unavailable + + +2008-03-26 Nick Kledzik + + Add LD_WARN_COMMONS to BigBear builds + * src/Options.cpp: Add support for LD_WARN_FILE which copies all warnings to a side file + + +2008-03-26 Nick Kledzik + + Need encryption tag in mach-o file + linker should adjust arm final linked images so __text is never on the same page as the load commands + * src/MachOFileAbstraction.hpp: add support for encryption_info_command + * src/Options.cpp: add support for LD_NO_ENCRYPT and -no_encryption + * src/MachOWriterExecutable.hpp: add EncryptionLoadCommandsAtom + * src/machochecker.cpp: validate LC_ENCRYPTION_INFO + + +2008-03-25 Nick Kledzik + + ld64 does not recognize LLVM bitcode archive files + * src/MachOReaderArchive.hpp: renamed to src/ArchiveReader.hpp + * src/ArchiveReader.hpp: sniff each member and instantiate correct reader + * src/ld.cpp: rename mach_o::archive::Reader to archive::Reader + * ld64.xcodeproj/project.pbxproj: rename MachOReaderArchive.hpp to ArchiveReader.hpp + * unit-tests/test-cases/llvm-integration: added test case + + +2008-03-25 Nick Kledzik + + ld64 should switch to new libLTO.dylib interface + Produce llvm bc file in 'ld -r' mode if all .o files are llvm bc + * src/LTOReader.hpp: rewrite from LLVMReader.hpp to use new lto_* C interface + * unit-tests/test-cases/llvm-integration: update and comment + * ld64.xcodeproj/project.pbxproj: update to lazy load libLTO.dylib + * src/ld.cpp: rework and simplify Linker::optimize() + * src/ObjectDump.cpp: Add -nm option + + +2008-03-25 Nick Kledzik + + * src/MachOReaderRelocatable.cpp: Fix some .objc_class_name_ off by one problem + * src/MachOWriterExecutable.cpp: Fix some .objc_class_name_ off by one problem + + +2008-03-24 Nick Kledzik + + Xcode 3.1 breaks linkage of libgcj.9.dylib from gcc 4.3.0 + * src/MachOWriterExecutable.cpp: Make sure all ivars in Writer are initialized. + + +2008-03-21 Nick Kledzik + + * src/Options.cpp: warn if -seg1addr value is not page aligned + + +2008-03-21 Nick Kledzik + + Move ARM support outside of __OPEN_SOURCE__ + * src/ld.cpp: remove __OPEN_SOURCE__ around arm support + * src/LLVMReader.hpp: remove __OPEN_SOURCE__ around arm support + * src/MachOReaderDylib.hpp: remove __OPEN_SOURCE__ around arm support + * src/ObjectFile.h: remove __OPEN_SOURCE__ around arm support + * src/MachOReaderRelocatable.hpp: remove __OPEN_SOURCE__ around arm support + * src/OpaqueSection.hpp: Cover arm support inside __OPEN_SOURCE__ macro check + * src/MachOWriterExecutable.hpp: remove __OPEN_SOURCE__ around arm support + * src/ObjectDump.cpp: remove __OPEN_SOURCE__ around arm support + * ld64.xcodeproj/project.pbxproj: remove ARM_SUPPORT from config.h + + +----- Tagged ld64-83.2 + +2008-03-15 Nick Kledzik + + ld64-83 removes OBJC_CLASS_$ symbols from projects, causes catastrophic results + * src/Options.cpp: restore "case CPU_TYPE_ARM" in switch statement for .objc_class symbols in .exp files + * unit-tests/test-cases/objc-exported_symbols_list: added test case + + +----- Tagged ld64-83.1 + +2008-03-14 Nick Kledzik + + -iphone_version_min ==> -iphoneos_version_min + * src/Options.cpp: support -iphoneos_version_min as well + + +----- Tagged ld64-83 + +2008-03-10 Nick Kledzik + + ld needs to strip iphone_version_min option if invoking ld_classic + * src/Options.cpp: suppress -iphone_version_min from being passed to ld_classic + + +2008-03-04 Nick Kledzik + + ADOBE XCODE: Linker option to lazy load frameworks (cause dyld is too slow) + * src/MachOWriterExecutable.hpp: create lazy stubs and LC_LAZY_LOAD_DYLIB for lazy load dylibs + * src/Options.cpp: support -lazy-l, -lazy_library, and -lazy_framework + * src/MachOFileAbstraction.hpp: add LC_LAZY_LOAD_DYLIB and S_LAZY_DYLIB_SYMBOL_POINTERS until in cctools + * src/MachOReaderDylib.hpp: add isLazyLoadedDylib() + * src/ld.cpp: pass lazy helper atom to writer + * doc/man/man1/ld.1: document new options + * unit-tests/test-cases/lazy-dylib-objc: add test case + * unit-tests/test-cases/lazy-dylib: add test case + + +----- Tagged ld64-82.7 + +2008-03-07 Nick Kledzik + + duplicate symbol literal-pointer@__OBJC@__message_refs@... + * src/MachOReaderRelocatable.hpp: AnonymousAtom from S_LITERAL_POINTERS section should be weak + * unit-tests/test-cases/objc-selector-coalescing: added test case + + +----- Tagged ld64-82.6 + +2008-03-04 Nick Kledzik + + ld crashes building XsanFS for Snow Leopard Builds + * src/ld.cpp: add bool dylibsOnly parameter to addJustInTimeAtoms() + * unit-tests/test-cases/tentative-and-archive: added test case + +2008-03-04 Nick Kledzik + + ld64 should not force building with gcc 4.0 + * ld64.xcodeproj/project.pbxproj: change rules to use "system" compiler instead of 4.0 + + +2008-02-29 Nick Kledzik + + Simulator frameworks are being build split-seg and not prebound + * src/Options.cpp: only splitseg if prebound + + +2008-02-29 Nick Kledzik + + Linker should not make GSYM debug note for .objc_category_* symbols + * src/ld.cpp: suppress GSYM debug notes for absolute symbols + * unit-tests/test-cases/objc-category-debug-notes: added test case + + +2008-02-29 Nick Kledzik + + non-ASCII CFString support is broken + * src/MachOReaderRelocatable.hpp: only name and coalesce cfstring constants if they use a __cstring + * unit-tests/test-cases/cfstring-utf16: add test case + + +2008-02-25 Nick Kledzik + + ld -r -x + * doc/man/man1/ld.1: update man page to explain -r -x produces auto-stripped labels + + +----- Tagged ld64-82.5 + +2008-02-12 Nick Kledzik + + x86_64: -stack_size failure when large __bss is used + * src/ld.cpp: only move section already in __DATA segment to new __huge section + * unit-tests/test-cases/stack_size_no_addr: updated test case to add large bss section + + +----- Tagged ld64-82.4 + +2008-02-06 Nick Kledzik + + comdat warnings with ld -r of C++ .o files + * unit-tests/test-cases/eh-coalescing-r: added test case + * src/ld.cpp: in ld -r mode don't warn about if .eh symbols are not static + + +2008-02-06 Devang Patel + + LTO of Bom framework with -dead_strip causes ld(1) crash + * src/LLVMReader.hpp: Check fAtom while determining LLVMReference target binding. + * unit-tests/test-cases/llvm-integration/Makefile: Add new test case. + * unit-tests/test-cases/llvm-integration/a15.c: New. + * unit-tests/test-cases/llvm-integration/b15.c: New. + * unit-tests/test-cases/llvm-integration/c15.c: New. + +2008-02-05 Nick Kledzik + + * src/ld.cpp: fix for -arch ppc -mdynamic-no-pic -pie so PPC_RELOC_HA16 reloc is used + +----- Tagged ld64-82.3 + +2008-02-04 Nick Kledzik + + ld doesn't seem to understand $ld$add$os... and $ld$hide$os... for 10.6 moves + * src/ObjectFile.h: add 10.6 + * src/Options.cpp: add 10.6 support + * src/MachOReaderDylib.hpp: recognize $os10.6$ + + +----- Tagged ld64-82.2 + +2008-01-30 Devang Patel + + Can't build 64-bit Intel binaries with LTO + ld64 fails to build with llvm-gcc-4.2 + * src/LLVMReader.hpp: Fix character count typo in strncmp call. + Use const char * to initialize temp. string. + * ld64.xcodeproj/project.pbxproj: use $(DEVELOPER_DIR) in header search construction + instead of hard coding /Developer. + +----- Tagged ld64-82.1 + +2008-01-23 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: don't bus error if S_LITERAL_POINTERS is missing relocs + + +2008-01-22 Nick Kledzik + + ld uses 32-bits in some places to hold addresses when parsing 64-bit mach-o files + * src/MachOReaderRelocatable.hpp: use AddrToAtomMap type that switch address to 64-bits for 64-bit archs + * src/MachOWriterExecutable.hpp: verify BR14 does not overflow for external relocs + * unit-tests/test-cases/relocs-c: update test case to slide addresses to verify x86_64 .o files + + +----- Tagged ld64-82 + +2008-01-18 Nick Kledzik + + Bad grammar used in ld warning: cannot exported hidden symbol + * src/ld.cpp: fix typo in warning string + + +2008-01-16 Nick Kledzik + + Bundle Loader does not work anymore when loader is a bundle + ld warns of incorrect architecture when linking a bundle to a bundle + * src/MachOReaderDylib.hpp: support linking against bundles via -bundle_loader. Clean up error messages + * unit-tests/test-cases/bundle_loader: update test case + + +2008-01-16 Nick Kledzik + + ld -r -x creates debug notes (stabs) when it should not with -x (keep only global symbols) + * src/Options.cpp: in reconfigureDefaults() if -r and -x then -S + + +2008-01-16 Nick Kledzik + + if ld crashes while writing output file, it should delete the half written file + * src/MachOWriterExecutable.hpp: wrap open/write/close in try block and add signal handlers all to delete + output file on failure. + + +2008-01-16 Devang Patel + + * src/LLVMReader.hpp: Use __gnu_cxx::hash_map instead of hash supported by LLVM. + + +2008-01-16 Nick Kledzik + + GC-supported library can't be linked into GC-required executable + * src/ld.cpp: loosen constraint that all objc code must be compiled with same GC settings and + allow gc-compatible code to be linked into anything. + * unit-tests/test-cases/objc-gc-checks: update test case + + +2008-01-15 Nick Kledzik + + no debug notes for custom named data + * src/ld.cpp: in synthesizeDebugNotes() check getSymbolTableInclusion() instead of for leading underscore + * unit-tests/test-cases/dwarf-debug-notes: update test case + +----- Tagged ld64-81.5 + +2008-01-14 Devang Patel + + llvm-gcc-4.2 fails to build Sqlite 3.5.4 with -O4 + * src/LLVMReader.hpp: Resolve proxy references. Collect new unbounded references + after optimization. + * src/ld.cpp: Resolve additional unbounded references after optimization. + + +2008-01-14 Nick Kledzik + + PPC Leopard (Xcode 3.0) linker ld gets "Bus error" sometimes + * src/MachOReaderRelocatable.hpp: use same code as x86 to parse ppc and arm sect-diff relocs + * src/MachOWriterExecutable.hpp: use same code as x86 to write ppc and arm sect-diff relocs + + +2008-01-11 Nick Kledzik + + PPC Leopard (Xcode 3.0) linker ld reports "unknown scattered relocation type 4" + * src/MachOReaderRelocatable.hpp: add PPC_RELOC_HI16 to scattered reloc parsing + * unit-tests/test-cases/relocs-asm/relocs-asm.s: added tests for scattered hi/lo instructions + + +2008-01-11 Nick Kledzik + + * doc/man/man1/ld.1: add doc for -no_implicit_dylibs, -read_only_stubs, -slow_stubs, -interposable_list + + +2008-01-11 Nick Kledzik + + ld64(1) man page uses ambiguous term "suffix" + * doc/man/man1/ld.1: make meaning of "suffix" more explicit + + +2008-01-11 Nick Kledzik + + Obj-C Symbols in Leopard Can't Be Weak Linked + * src/MachOWriterExecutable.hpp: set weak and lazy attributes on dummy .objc_class_name undefines + to dylibs to support Mac OS X 10.3.x dyld + + +2008-01-11 Nick Kledzik + + Unknown error with linker (dyld: unknown external relocation type) + * src/ld.cpp: fix crash when SO stabs are not balanced + + +2008-01-11 Devang Patel + + LTO does not work if expected output is a dynamic library + * src/LLVMReader.hpp: Supply arguments describing output kind to optimizer. Communicate + visibility info. + +2000-01-10 Nick Kledzik + + __cls_refs section is losing S_LITERAL_POINTERS section type + * src/MachOWriterExecutable.hpp: special case __cls_refs section + * unit-tests/test-cases/objc-literal-pointers: add test case + + +2008-01-03 Nick Kledzik + + wrong EH information might be used + Created new kGroupSubordinate reference kind to model group comdat. The "signature" atom + has kGroupSubordinate references to the other atoms in the group. If the signature atom + is coalesced away, the linker follows kGroupSubordinate references and throws away the + other members of the group. + * unit-tests/test-cases/eh-coalescing: added test case + * src/ld.cpp: added markDead() and use propagate to subordinates + * src/Architectures.hpp: added kGroupSubordinate + * src/MachOReaderRelocatable.hpp: add kGroupSubordinate reference from a function to its .eh atom + and if used, from .eh atom to its LSDA atom. + * src/MachOWriterExecutable.hpp: handle kGroupSubordinate like kNoFixUp + +----- Tagged ld64-81.4.1 + +2007-12-19 Devang Patel + + * src/LLVMReader.hpp: Add LLVM_LTO_VERSION #ifdef check. + +2007-12-19 Devang Patel + + * src/LLVMReader.hpp: Add fOptimizer NULL check before calling printVersion(). + +2007-12-19 Devang Patel + + print LLVM LTO version number in verbose mode + * src/LLVMReader.hpp: Add printLLVMVersion() to print llvm version string in verbose mode. + * src/Options.cpp: Use printLLVMVersion() in verbose mode. + +2007-12-19 Devang Patel + + print LLVM LTO version number in verbose mode + * src/Options.h: Add verbose() method to check fVerbose flag. + * src/LLVMReader.hpp: Print LLVM version string in verbose mode. + +----- Tagged ld64-81.4 + +2007-12-18 Devang Patel + + * src/LLVMReader.hpp: Invalidate input architecture when optimizer is not available. + +----- Tagged ld64-81.3 + +2007-12-17 Nick Kledzik + + * ld64.xcodeproj/project.pbxproj: remove extraneous header search paths + + +2007-12-17 Devang Patel + + * src/LLVMReader.hpp: Do not throw exception if LLVMReader is not able to + dlopen LTO library. Instead just flag input file as an invalid LLVM bitcode file. + + +2007-12-14 Nick Kledzik + + gcc DejaGnu failure: gcc.dg/20020312-2.c (test for excess errors) (-fstack-protector-all) + * src/MachOWriterExecutable.hpp: fix Writer::generatesExternalTextReloc() to allow text relocs + * unit-tests/test-cases/read-only-relocs: updated test case to link a dynamic main executable compiled with -static + + +2007-12-14 Devang Patel + + Enable Link Time Optimization in Opal + * src/LLVMReader.hpp: Locate LLVMlto.dylib relative to ld location in Developer folder. + * ld64.xcodeproj/project.pbxproj: Add {DEVELOPER_DIR}/usr/include in header search path. + * unit-tests/run-all-unit-tests: Set DYLD_FALLBACK_LIBRARY_PATH to find LLVMlto.dylib during unit testing. + * unit-tests/testcases/llvm-integration/Makefile: Point LLVMGCC and LLVMGXX to llvm-gcc-4.2 in Developer folder during unit testing. + + +2007-12-13 Nick Kledzik + + SWB: failures due to ld: pointer in read-only segment not allowed in slidable image, used in ... + * src/MachOReaderRelocatable.hpp: in Reader::addRelocReference() handle weak pc-rel 32-bit vanilla relocs properly + +----- Tagged ld64-81.2 + + + +2007-12-07 Nick Kledzik + + support 8-bit relocations for i386 + * src/Architectures.hpp: add kPCRel8 + * src/MachOReaderRelocatable.hpp: support 8-bit pc-rel relocations for intel + * src/MachOWriterExecutable.hpp: support 8-bit pc-rel relocations for intel + * unit-tests/test-cases/relocs-asm: add test cases + + +----- Tagged ld64-81.1 + +2007-12-06 Nick Kledzik + + * src/MachOReaderDylib.hpp: rework cycle detection to remove some false positives + + +2007-12-05 Nick Kledzik + + Duplicate probe firings in Security.framework + * src/ld.cpp: check dtrace probe sites are not in fDeadAtoms before using + * unit-tests/test-cases/dtrace-static-probes-coalescing: add test case + + +2007-12-05 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: fix CFString coalescing to work with -fwritable-strings + * unit-tests/test-cases/cfstring-coalesce: add -fwritable-strings to test case + + +----- Tagged ld64-81 + +2007-11-15 Nick Kledzik + + ld64 should support runtime text relocations + * src/MachOWriterExecutable.hpp: add generatesLocalTextReloc() and generatesExternalTextReloc() + * src/Options.cpp: process -read_only_relocs option + * src/Options.h: add allowTextRelocs() and warnAboutTextRelocs() + * src/MachOReaderRelocatable.hpp: add hasLongBranchStubs() + * src/machochecker.cpp: allow relocs in read only segments, if section flags are set + * unit-tests/test-cases/read-only-relocs: update test case + + +2007-11-08 Devang Patel + + * ld64.xcodeproj/project.pbxproj: add new build phase "build configure.h" for + ld target. + * src/ld.cpp: Include "configure.h" + + +----- Tagged ld64-80.11 + +2008-02-12 Nick Kledzik + + Wrong section name for objc info for ARM when OBJC2 is used + * src/MachOWriterExecutable.hpp: switch segment/section name for ARM objc2 image info + +----- Tagged ld64-80.10 + +2008-02-11 Nick Kledzik + + ld64 does not support -aspen_version_min 2.0 + * src/Options.cpp: allow 2.x for -aspen_version_min + + +2008-02-11 Nick Kledzik + + ld_classic: unknown flag: -aspen_version_min + * src/Options.cpp: change -aspen_version_min x.x to -macosx_version_min 10.5 when invoking ld_classic + + +----- Tagged ld64-80.9 + +2008-01-29 Nick Kledzik + + -iphone_version_min ==> -aspen_version_min + * src/Options.cpp: support -aspen_version_min + + +----- Tagged ld64-80.8 + +2008-01-10 Nick Kledzik + + * src/Options.cpp: support transition to new objc ABI for ARM by allowing old .objc_class_name_* + style names in export files and map them to new _OBJC_CLASS_$_ style names. + + +----- Tagged ld64-80.7 + +2008-01-02 Nick Kledzik + + BigBear5A18 isn't fully prebound + * src/Options.cpp: make fNeedsModuleTable true for arm + +----- Tagged ld64-80.6 + +2007-11-30 Nick Kledzik + + -iphone_version_min + * src/Options.cpp: handle -iphone_version_min option + + +----- Tagged ld64-80.5 + +2007-11-26 Nick Kledzik + + need to special case some dylibs in seg_addr_table + * src/Options.cpp: retry seg_add_table lookup for a couple of unusual dylibs + + +----- Tagged ld64-80.4 + +2007-11-06 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: fix parsing of external and scattered thumb branch22 relocs + * unit-tests/test-cases/thumb-blx: add test case to keep blx issues from coming back + +----- Tagged ld64-80.3 + +2007-11-03 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: remove recalc of dstAddr which could cause thumb branches to be +2 + * src/MachOWriterExecutable.hpp: remove incorrect test for relocateableExternal + +----- Tagged ld64-80.2 + +2007-11-01 Nick Kledzik + + * src/ld.cpp: hack my own prototype for log2() until math.h is cleaned up + + +----- Tagged ld64-80.1 + +2007-11-01 Nick Kledzik + + * ld64.xcodeproj/project.pbxproj: add HEADER_SEARCH_PATHS for cross builds + * src/ld.cpp: temporarily disable LLVM_SUPPORT + * src/MachOWriterExecutable.hpp: Don't use CC_MD5() directly + + +2007-10-26 Nick Kledzik + + Cannot build with libm_static.a statically linked + * src/MachOWriterExecutable.hpp: Fix makesExternalRelocatableReference() for -r -d case + * unit-tests/test-cases/tentative-to-real-hidden: add test case + + +----- Tagged ld64-80 + +2007-10-24 Nick Kledzik + + linker should probably warn about trying to export a hidden symbol + * src/ld.cpp: if using -exported_symbols_list check each hidden atom as it is added to symbol table + * src/Options.h,.cpp: add hasExportMaskList() + * unit-tests/test-cases/exported_symbols_list-hidden: added test case + + +2007-10-24 Nick Kledzik + + * src/MachOWriterExecutable.hpp: keep old style dtrace probes externel for kernel builds + + +2007-10-23 Nick Kledzik + + unify error and warning messages + -w should suppress warnings + * src/ld.cpp: use warning() function + * src/Options.h: remove emitWarnings() + * src/MachOReaderDylib.hpp: use warning() function + * src/MachOReaderRelocatable.hpp: use warning() function + * src/Options.cpp: use and implement warning() + * src/MachOWriterExecutable.hpp: use warning() function + * unit-tests/test-cases/visibility-warning: verify -w suppresses warnings + + +2007-10-23 Devang Patel + + * src/ld.cpp: Cover arm support inside __OPEN_SOURCE__ macro check. + * src/LLVMReader.hpp: Cover arm support inside __OPEN_SOURCE__ macro check. + * src/MachOReaderDylib.hpp: Cover arm support inside __OPEN_SOURCE__ macro check. + * src/ObjectFile.h: Cover arm support inside __OPEN_SOURCE__ macro check. + * src/MachOReaderRelocatable.hpp: Cover arm support inside __OPEN_SOURCE__ macro check. + * src/OpaqueSection.hpp: Cover arm support inside __OPEN_SOURCE__ macro check + * src/MachOWriterExecutable.hpp: Cover arm support inside __OPEN_SOURCE__ macro check. + * src/ObjectDump.cpp: Cover arm support inside __OPEN_SOURCE__ macro check. + + +2007-10-22 Nick Kledzik + + * src/Options.cpp: add support for LD_DEAD_STRIP and LD_WARN_COMMONS + * src/MachOReaderRelocatable.hpp: fix problem with -dead_strip of ObjC literal pointers + + +2007-10-22 Nick Kledzik + + * src/Options.cpp: have -static arm code link with ld_classic (for now) + + +2007-10-22 Nick Kledzik + + Recognize all arm architectures + * src/MachOReaderRelocatable.hpp: add support for all ARM sub-types + * unit-tests/test-cases/cpu-sub-types: add test cases for all combinations of ARM sub-types + + +2007-10-19 Nick Kledzik + + * src/*: merge in arm support + * unit-tests/test-cases/*: fix to work for arm and thumb + +----- Tagged ld64-79 + +2007-10-16 Nick Kledzik + + * src/MachOWriterExecutable.hpp: if -r mode, always set custom alignment (SET_COMM_ALIGN) on common symbols + * unit-tests/test-cases/visibility-warning-dylib-v-archive/Makefile: fix warning + * unit-tests/test-cases/static-executable/Makefile: fix spurious failure + + +2007-10-16 Nick Kledzik + + * src/MachOWriterExecutable.hpp: fix edge case in branch island generation + + +2007-10-12 Nick Kledzik + + Add option to create old, slow stubs for i386 + * src/ObjectFile.h/.cpp: support -read_only_stubs + * src/MachOWriterExecutable.hpp: enhance StubAtom to support old style __symbol_stub/__la_symbol_ptr stubs + * unit-tests/test-cases/slow-x86-stubs: add test case + + +2007-10-12 Nick Kledzik + + ld64's re-export cycle detection logic prevents use of X11 libGL on Leopard + * src/Options.cpp: in findFileUsingPaths() don't search for embedded dylibs + * unit-tests/test-cases/indirect-path-search/Makefile: added case for a dylib embedded in a framework + + +2007-10-11 Nick Kledzik + + add option to disable implicit load commands for indirectly used public dylibs + * src/Options.cpp: add support for -no_implicit_dylibs + * src/ObjectFile.h: add fImplicitlyLinkPublicDylibs + * src/MachOReaderDylib.hpp: test fImplicitlyLinkPublicDylibs before hoisting an implicitly linked dylib + * unit-tests/test-cases/implicit_dylib: add test case + + +2007-10-11 Nick Kledzik + + -interposable_list + * src/Options.h/cpp: Add fInterposeList and fInterposeMode to support -interposable_list + * src/MachOWriterExecutable.hpp: pass symbol name to fOptions.interposable() + * unit-tests/test-cases/interposable_list: add test case + + +2007-10-10 Nick Kledzik + + If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB + * src/MachOWriterExecutable.hpp: automatically use LC_LOAD_WEAK_DYLIB if all symbols used from a dylib are weak_import + * unit-tests/test-cases/weak_dylib: added test case + + +2007-10-10 Nick Kledzik + + linker does not error when dylib ordinal exceeds 250 + * src/MachOWriterExecutable.hpp: error out if ordinals exceed max allowed + + +2007-10-10 Nick Kledzik + + overriding 'operator new' or 'operator delete' fails if no weak symbols are present + * src/ld.cpp: at end of checkUndefines() search dylibs for weak versions of any global external symbols + * src/ObjectFile.h: add hasWeakExternals() method to Reader + * src/MachOReaderDylib.hpp: implement hasWeakExternals() method in Reader + * src/ExecutableFile.h: add overridesDylibWeakDefines parameter to write() + * src/MachOWriterExecutable.hpp: use overridesDylibWeakDefines parameter to write() + * unit-tests/test-cases/operator-new: add test case + + +2007-10-05 Nick Kledzik + + No warning about tentative definition conflicting with dylib definition + .comm variables in shared library, worked with XCode 2.4.1, broken with XCode 3? + * src/ld.cpp: at end of checkUndefines() verify if any remaining commons conflict with dylibs + * doc/man/man1/ld.1: document -commons and -warn_commons options + * unit-tests/test-cases/tentative-and-dylib: added test case + + +2007-10-05 Nick Kledzik + + NS/CFString constants are not dead strippable + * src/MachOReaderRelocatable.hpp: break up __cfstring section into one atom per cfstring, make them coalesable + * unit-tests/test-cases/cfstring-coalesce: added test case + + +2007-10-05 Nick Kledzik + + Dead stripping + exported symbols list using wildcards doesn't seem to do the right thing + * src/Options.cpp/h: add hasWildCardExportRestrictList() + * src/ld.cpp: if dead stripping code and have wildcard exports, add all global atoms matching wildcards as roots + * unit-tests/test-cases/exported-symbols-wildcards-dead_strip: added test case + + +2007-10-04 Nick Kledzik + + ld shouldn't search /Network/Library/Frameworks by default + * src/Options.cpp: remove /Network/Library/Frameworks/ from default search path + * doc/man/man1/ld.1: document the change + + +2007-10-04 Nick Kledzik + + all binaries should get LD_UUID load commands, not just those with DWARF symbols + * src/ld.cpp: default fCreateUUID to be true for non object file output types + * unit-tests/test-cases/no-uuid/Makefile: update test case to match new rules + + +----- Tagged ld64-78 + +2007-09-27 Nick Kledzik + + range check load commands + * src/MachOReaderDylib.hpp: check that load commands all fit in load command size from header + * src/MachOReaderRelocatable.hpp: check that load commands all fit in load command size from header + + +2007-09-27 Nick Kledzik + + Xc8M2540a: ld64 crashes when linking Pascal program + * src/ld.cpp: fix findAtomAndOffset() to handle where there are no function atoms + + +2007-09-27 Nick Kledzik + + ADOBE Xcode 3: ld -dead_strip does not work with -init from an archive + * src/ld.cpp: add bool parameter to entryPoint() so -init atom not looked for too soon + * unit-tests/test-cases/dead_strip-init-archive: added test case + + +2007-09-26 Nick Kledzik + + Spurious link warnings for inline members of C++ template classes + * src/ld.cpp: check definition kinds before warning about visibility mismatches + * unit-tests/test-cases/visibility-warning: added test case + + +2007-09-26 Nick Kledzik + + an empty .o file with zero load commands will crash linker + * src/MachOReaderRelocatable.hpp: have Reader constructor return early of no load commands + * unit-tests/test-cases/empty-object: added test case + + +2007-09-26 Nick Kledzik + + 9a527: ppc64 branch islands fail with 4GB pagezeo + * src/MachOWriterExecutable.hpp: start range calculations at start of __text not at zero. + + +----- Tagged ld64-77 (Xcode 3.0) + +2007-07-23 Nick Kledzik + + Kernel is linked with some global symbols unsorted + * src/MachOWriterExecutable.hpp: Add NListNameSorter to allow global atoms and extra labels to be sorted + + +2007-07-20 Nick Kledzik + + Can't do objc_msgSendSuper dispatches after loading a Fix&Continue bundle + * src/MachOWriterExecutable.hpp: when calculating what kind of reloc to use, never use an + external reloc to reference 32-bit ObjC symbols. + + +2007-07-20 Nick Kledzik + + Runtime crash with ICC math library on Leopard + * src/MachOReaderRelocatable.hpp: detect if section starts with a symbol that is not + aligned to section and correct it. + + +----- Tagged ld64-76 + +2007-06-29 Nick Kledzik + + export hiding does not work for frameworks + * src/MachOReaderDylib.hpp: fix checks in isPublicLocation() + * unit-tests/test-cases/symbol-moving: update to test frameworks as well as dylibs + + +2007-06-27 Nick Kledzik + + linker should use undefines from flat dylibs when linking a main flat + * src/ObjectFile.h: added fLinkingMainExecutable + * src/Options.cpp: set up fLinkingMainExecutable + * src/MachOReaderDylib.hpp: when linking a main executable for flat namespace, the reader for + any loaded flat namespace dylib will have a new atoms that has references to all undefined + symbols in the dylib + * unit-tests/test-cases/flat-indirect-undefines: added test case + * doc/man/man1/ld.1: update man page to describe when dylib undefines are used + + +2007-06-27 Nick Kledzik + + OpenGL.framework and X11 both have a libGL.dylib which can cause ld to segfault if both are found + * src/MachOReaderDylib.hpp: add assertNoReExportCycles() method + * unit-tests/test-cases/dylib-re-export-cycle: added test case + + +2007-06-27 Nick Kledzik + + ld64 has slightly different warning message formats than the old ld + * src/ld.cpp: standardize all warning messages to start with "ld: warning" + * src/MachOWriterExecutable.hpp: ditto + * src/MachOReaderRelocatable.hpp: ditto + * src/MachOReaderDylib.hpp:ditto + + +2007-06-26 Nick Kledzik + + -dead_strip can cause duplicate external commons + * src/ld.cpp: don't use discarded coalesced global atoms as dead strip roots + * src/machochecker.cpp: error if duplicate external symbols + * unit-tests/test-cases/commons-coalesced-dead_strip: added test case + + +2007-06-26 Nick Kledzik + + update man page that linker does not search indirect libraries with two-level namespace + * doc/man/man1/ld.1: add new "Indirect dynamic libraries" section to man page + + +2007-06-26 Nick Kledzik + + Xc9A466: Exports file cannot use Mac line ends + * src/Options.cpp: check for \r or \n when parsing .exp files + * unit-tests/test-cases/exported_symbols_list-eol: added test case + + +----- Tagged ld64-75 + +2007-05-31 Nick Kledzik + + Simplier, generalized way to re-export dylibs: LC_REEXPORT_DYLIB + * src/MachOWriterExecutable.hpp: Use LC_REEXPORT_DYLIB when targetting 10.5 + + +----- Tagged ld64-74.5 + +2007-05-31 Nick Kledzik + + set OSO timestamp to zero for when building in buildit + * src/ld.cpp: check for RC_RELEASE and if exists set all OSO timestamps to zero + + +2007-05-30 Nick Kledzik + + BUILD_STABS now causes ld of xnu to bus error + * src/ld.cpp: Change || to && in collectStabs() + + +----- Tagged ld64-74.4 + +2007-05-18 Nick Kledzik + + static probes don't work with libraries in dyld shared cache + * src/OpaqueSection.hpp: the __TEXT segment is executable + + +----- Tagged ld64-74.3 + +2007-05-16 Nick Kledzik + + ppc: linker adds stubs to cstring references + * src/MachOWriterExecutable.hpp: update ppc stubableReference() to only allow high/low references + to be stubed if they reference a symbol in some other dylib. + * unit-tests/test-cases/stub-generation: added test case + + +2007-05-16 Nick Kledzik + + ppc64: need to make LOCAL indirect symbol table entry for now local symbol + * src/MachOWriterExecutable.hpp: factored local tests into indirectSymbolIsLocal() + * unit-tests/test-cases/non-lazy-r: added test case + + +2007-05-15 Nick Kledzik + + ld64 drops fix&continue bit in __OBJC, __image_info. + * src/MachOReaderRelocatable.hpp: implement objcReplacementClasses() + + +2007-05-15 Nick Kledzik + + support __image_info in __DATA segment for 64-bits + * src/MachOReaderRelocatable.hpp: use strncmp() for __objc_imageinfo since it is 16 bytes long + * src/MachOWriterExecutable.hpp: specialize segment/section names for synthesized objc image info section + + +2007-05-15 Nick Kledzik + + * unit-tests/include/common.makefile: set COMPILER_PATH so harness works with latest compiler + + +----- Tagged ld64-74.2 + +2007-05-11 Nick Kledzik + + ld64-74.1 breaks libstdc++ DejaGnu test (G5 only) + * src/MachOWriterExecutable.hpp: don't stub a reference if the target offset is non-zero + + +----- Tagged ld64-74.1 + +2007-05-09 Nick Kledzik + + * src/Options.h: add emitWarnings() + * src/Options.cpp: wire up -w to emitWarnings() + + +2007-05-09 Nick Kledzik + + ld64 won't link wine (regression from Tiger) + * src/Architectures.hpp: add x86::kPointerDiff16 and x86::kPCRel16 + * src/MachOReaderRelocatable.hpp: add support to parse new relocs + * src/MachOWriterExecutable.hpp: add support fo new relocs + + +2007-05-08 Nick Kledzik + + need way for ld and dyld to see different exported symbols in a dylib + * src/MachOReaderDylib.hpp: update parse and use $ld$ symbols + * src/Options.h: move VersionMin to ReaderOptions + * src/ObjectFile.h: move VersionMin to ReaderOptions + * src/Options.cpp: move VersionMin to ReaderOptions + * src/MachOWriterExecutable.hpp: move VersionMin to ReaderOptions + * unit-tests/test-cases/symbol-moving: added test case + + +2007-05-03 Nick Kledzik + + typo in error message for linking -pie + * src/MachOWriterExecutable.hpp: fix typo in error messages + + +----- Tagged ld64-74 + +2007-05-03 Nick Kledzik + + ld64 can't find @executable _path relative dylibs from our umbrella frameworks + ld64 should handle linking against dylibs that have @loader_path based dylib load commands + * src/ObjectFile.h: add from parameter to findDylib() + * src/MachOReaderDylib.hpp: supply from parameter to findDylib() + * src/ld.cpp: use from parameter for @loader_path substitution in findDylib() + * unit-tests/test-cases/re-export-relative-paths: added test case + + +2007-05-02 Nick Kledzik + + * src/ObjectFile.h: add fLogObjectFiles and fLogAllFiles + * src/Options.cpp: hook up -t to fLogAllFiles and -whatsloaded to fLogObjectFiles + * src/MachOReaderDylib.hpp: log if fLogAllFiles + * src/MachOReaderRelocatable.hpp: log if fLogObjectFiles or fLogAllFiles + * src/MachOReaderArchive.hpp: log if fLogAllFiles + * doc/man/man1/ld.1: update man page + + +2007-05-02 Nick Kledzik + + typo in message, frameowrk + * src/Options.cpp: fix typo + + +2007-05-01 Nick Kledzik + + "ld" man page is missing the description for many options + * doc/man/man1/ld.1: add documentation on all obsolete options + + +2007-05-01 Nick Kledzik + + ld doesn't handle -mlong-branch .o files that have had local symbols stripped + warning about dwarf line info with -mlong-branch + * src/MachOReaderRelocatable.hpp: don't lop -mlong-branch stubs off end of functions + * src/MachOWriterExecutable.hpp: allow code references besides BR24 to be stubable + + +2007-04-30 Nick Kledzik + + unable to link VTK because __textcoal_nt too large + * src/MachOReaderRelocatable.hpp: when doing a final link map __textcoal_nt to __text + + +2007-04-30 Nick Kledzik + + ld does not report error when -r is used and exported symbols are not defined. + ld leaves global common symbols not in exported symbols list. + * src/ld.cpp: stop special casing -r mode in checkUndefines() + * src/MachOWriterExecutable.hpp: don't create proxy atom in -r mode if it is supposed to be exported. + mark tentative definitions are private extern in -r mode even without -keep_private_externs + * unit-tests/test-cases/exported_symbols_list-r: added test case + + +2007-04-27 Nick Kledzik + + ld should keep looking when it finds a weak definition in a dylib + * src/ld.cpp: modified addJustInTimeAtoms() to keep looking when a weak defintion is found + * unit-tests/test-cases/weak-def-ordinal: added test case + + +2007-04-27 Nick Kledzik + + better error message for indirect dylibs missing required architecture + * src/ld.cpp: when loading indirect dylib add path to error messages + + +2007-04-25 Nick Kledzik + + the i386 slice of dyld does not need __IMPORT segment + * src/ObjectFile.h: add fForDyld + * src/Options.cpp: set up fForDyld + * src/MachOReaderRelocatable.hpp: if fForDyld, change __IMPORT segment to __DATA + * src/MachOWriterExecutable.hpp: recognize __DATA/__pointers in dyld as a non-lazy section + + +2007-04-24 Nick Kledzik + + ppc64: need to make LOCAL indirect symbol table entry for now local symbol + * src/MachOWriterExecutable.hpp: use INDIRECT_SYMBOL_LOCAL for any non-global symbol + * unit-tests/test-cases/strip_local: update test case + + +2007-04-24 Nick Kledzik + + ld64 -sectorder and -order_file files don't accept white space following the : + * src/Options.cpp: prune white space after colon and before symbol name + * unit-tests/test-cases/order_file: update test case to have a space after the colon + + +2007-04-24 Nick Kledzik + + ld64 corrupts debug symbol table entries, nm doesn't print them + * src/MachOWriterExecutable.hpp: properly set ilocalsym in module table + + +2007-04-24 Nick Kledzik + + support __image_info in __DATA segment for 64-bits + * src/MachOReaderRelocatable.hpp: look for new objc info section name too + + +2007-04-24 Nick Kledzik + + * src/MachOWriterExecutable.hpp: fix -non_global_symbols_strip_list to work with -r + * unit-tests/test-cases/local-symbol-partial-stripping: update test case + + + +----- Tagged ld64-73.7 + +2007-05-10 Nick Kledzik + + can't use dtrace static probes in x86_64 dylib + * src/MachOWriterExecutable.hpp: x86_64:kPointerDiff32 is ok in shared region + * unit-tests/test-cases/dtrace-static-probes: update to build dylib too + + +2007-05-09 Nick Kledzik + + 9A430: using -dead_strip with static dtrace probes causes ld to crash + * src/ld.cpp: fix markLive() to look at right name in dtrace probe refernce + * unit-tests/test-cases/dtrace-static-probes: added -dead_strip case + + +----- Tagged ld64-73.6 + +2007-04-17 Nick Kledzik + + Add options to do partial stripping of local symbols + * src/MachOWriterExecutable.hpp: use fOptions.keepLocalSymbol() + * src/Options.cpp: implement -non_global_symbols_no_strip_list and -non_global_symbols_strip_list + * src/Options.h: replace stripLocalSymbols() with localSymbolHandling() and keepLocalSymbol() + * doc/man/man1/ld.1: document -non_global_symbols_no_strip_list and -non_global_symbols_strip_list + * unit-tests/test-cases/local-symbol-partial-stripping: added test case + + +----- Tagged ld64-73.5 + +2007-04-17 Nick Kledzik + + ld64-73.3 XBS logging incorrectly reporting "direct" dynamic libraries + * src/ld.cpp: restore direct vs indirect library for LD_TRACE_DYLIBS logging + + +2007-04-16 Nick Kledzik + + data initialized to a weak imported symbol is missing relocation + * src/MachOWriterExecutable.hpp: check for A::kPointerWeakImport in buildExecutableFixups() + * unit-tests/test-cases/weak_import: updated test case to catch this problem + + +2007-04-13 Nick Kledzik + + Support -U + * src/MachOWriterExecutable.hpp: create proxies for -U symbols + * src/Options.cpp: process -U + * src/Options.h: add allowedUndefined() and someAllowedUndefines() + * src/ld.cpp: create proxies for -U symbols + * doc/man/man1/ld.1: document -U and -undefined options + * unit-tests/test-cases/undefined-dynamic-lookup: added test case + + +----- Tagged ld64-73.4 + +2007-04-12 Nick Kledzik + + ld changes needed to support read-only DOF + * src/Options.cpp: remove -read_only_dof + * src/Options.h: remove fReadOnlyDOFs + * src/ld.cpp: only generate read-only DOF sections + + +----- Tagged ld64-73.3.1 + +2007-04-13 Nick Kledzik + + -framework vecLib -framework Accelerate causes bad ordinals + * src/MachOWriterExecutable.hpp: fix bug optimizeDylibReferences() when there are two readers with same install name + + +----- Tagged ld64-73.3 + +2007-04-03 Nick Kledzik + + * src/ld.cpp: read-only-dofs should use 32-bit offsets for x86_64 + * src/MachOReaderDylib.hpp: if "public" re-export is not marked implict, still mark it as re-exported + + +2007-04-02 Nick Kledzik + + if replacement file for -dylib_file is missing, warn instead of error + * src/ld.cpp: a try/catch to turn -dylib_file error into a warning. + * unit-tests/test-cases/dylib_file-missing: add test case + * doc/man/man1/ld.1: update man page about -dead_strip_dylibs + + +----- Tagged ld64-73.2 + +2007-03-31 Nick Kledzik + + ld64-73: atom sorting error with duplicate zero sized bss symbols + * src/MachOReaderRelocatable.hpp: suppress warning on sorting zero size zero fill atoms + +2007-03-31 Nick Kledzik + + ld64-73 fails anything linking with -lm + * src/ld.cpp: when processing dylbs that are sylinks ensure that fDylibMap contains all paths + * src/MachOWriterExecutable.hpp: when dead stripping dylibs and renumbering ordinals make sure + aliases dylib get renumbered too + * unit-tests/test-cases/dylib-aliases: added + + +----- Tagged ld64-73.1 + +2007-03-30 Nick Kledzik + + * src/MachOWriterExecutable.hpp: back out use of LC_REEXPORT_DYLIB until rdar://problem/5009909 is in build fleet + + +----- Tagged ld64-73 + +2007-03-30 Nick Kledzik + + ER: -dead_strip_dylibs + linker should add implicit load commands for indirectly used public dylibs + * src/ObjectFile.h: change dylib reader interface to implictly/explicitlyLinked + * src/ld.cpp: use new dylib reader interface + * src/Options.h: add deadStripDylibs() + * src/Options.cpp: support -dead_strip_dylibs + * src/MachOReaderDylib.hpp: use new dylib reader interface + * src/MachOWriterExecutable.hpp: remove dylib load commands for unused dylibs and alter ordinals + * unit-tests/test-cases/re-export-optimizations: added + * unit-tests/test-cases/dead_strip_dylibs: added + + +2007-03-30 Nick Kledzik + + * src/Options.cpp: enable -lfoo to search for libfoo.so as well as libfoo.dylib, + remove seg addr table hack for transitioning to new linker + +2007-03-30 Nick Kledzik + + ADOBE XCODE3: Linker is slow with large C++ .o files + * src/MachOReaderRelocatable.hpp: the compiler generates stubs to weak functions in the + same translation unit. Don't treat those like the spurios stubs to static functions. + + +2007-03-29 Nick Kledzik + + ld64 should link mach_kernel during xnu builds to support dtrace + * src/MachOReaderRelocatable.hpp: To handle duplicate labels properly, rework how atoms sizes are set + by iterating through sorted fAtoms rather than fAddrToAtom, . Change default alignment of commons + to be the natural alignment of the size rounded up to the closest power of two and max it at 12. + Build atoms in reverse symbol table order so that global atoms are constructed before locals. + This assures that if there is a global and local label at the same location, the global label + will become the atom's name and the local will be an alias. Properly handle a label + at the end of a section. Handle R_ABS in relocations. Handle sect-diff relocs with addends. + Don't auto-strip 'l' symbols in static executables (mach_kernel). + * src/OpaqueSection.hpp: opaque_section now has an ordinal + * src/ld.cpp: opaque_section now requires an ordinal + * src/ObjectFile.h: add ReaderOptions.fForStatic + * src/Options.cpp: set fForStatic when building a static executable + * src/MachOWriterExecutable.hpp: add from atom to StubAtom. Properly write out i386 + sect-diff relocs with addends. properly write out ppc PICbase relocs where pic base + is not in the atom. + + +2007-03-27 Nick Kledzik + + Typo in ld man page (-exported_symbols_list) + * doc/man/man1/ld.1: fix typo + + +2007-03-26 Nick Kledzik + + consider generating LC_UUID from a checksum of the file + * src/Options.h: change emitUUID() to getUUIDMode() + * src/Options.cpp: support -random_uuid + * src/MachOWriterExecutable.hpp: set uuid to be md5 hash of entire output file + + +2007-03-24 Nick Kledzik + + * src/MachOWriterExecutable.hpp: restructure writeAtoms() to copy all atoms in memory if possible + + +2007-03-24 Nick Kledzik + + ld -r of stripped .o file can incorrectly merge non-lazy pointers + * src/MachOWriterExecutable.hpp: when generating a .o file, non-lazy pointer with target offsets should be + encoded as LOCAL in the indirect symbol table + * unit-tests/test-cases/stripped-indirect-symbol-table: added test case + + +2007-03-23 Nick Kledzik + + SWB: ld64-72 errors building with gcc-4.2 + * src/MachOReaderDylib.hpp: add curly brackets in switch cases + * src/MachOWriterExecutable.hpp: rearrange classes so there are no template specialization forward references + + +2007-03-23 Nick Kledzik + + * src/ld.cpp: fix -print_statistics when using -dead_strip + + +2007-03-23 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: generate better names for non-lazy pointers to the interior of atoms + + +2007-03-16 Nick Kledzik + + * src/MachOWriterExecutable.hpp: speed up ld -r a little by reversing relocs en mas + + +2007-03-16 Nick Kledzik + + ld Bus Error on missing command line arguments + * src/Options.cpp: check next argv[] is not NULL + + +2007-03-16 Nick Kledzik + + need to be able to order symbols in anonymous namespaces + * src/ld.cpp: add logic to do fuzzy matching of symbols with anonymous namespace usage + * unit-tests/test-cases/order_file-ans: added test case + + +2007-03-16 Nick Kledzik + + headerpad_max_install_names deprecated for 64-bit + * src/ld.cpp: make sure dylib load command order matches command line order + * src/Options.h: add maxMminimumHeaderPad() + * src/Options.cpp: add maxMminimumHeaderPad() set by -headerpad_max_install_names + * src/src/MachOWriterExecutable.hpp: check maxMminimumHeaderPad() + * doc/man/man1/ld.1: update man page about -headerpad_max_install_names + + +2007-03-16 Nick Kledzik + + Linker returns success although exported symbols are undefined. + * src/ld.cpp: turn missing symbols back into an error + + +2007-03-16 Nick Kledzik + + ld64 should handle linking against dylibs that have @loader_path based dylib load commands + * unit-tests/test-cases/loader_path: added test case + + +2007-03-16 Nick Kledzik + + linker should add implicit load commands for indirectly used public dylibs + Indirect libraries should be found using -F and -L options + Simplier, generalized way to re-export dylibs: LC_REEXPORT_DYLIB + * src/ld.cpp: reworked all dylib processing. Readers can now add the dylib list. + * src/Options.h: add findFileUsingPaths() + * src/MachOReaderDylib.hpp: look in re-exported children instead of requring linker to do that + * src/ObjectFile.h: add processIndirectLibraries(), remove getDependentLibraryPaths() + * src/machochecker.cpp: support LC_REEXPORT_DYLIB + * src/ExecutableFile.h: simplify DyLibUsed + * src/Options.cpp: add findFileUsingPaths(). add new re-export options + * src/MachOWriterExecutable.hpp: Use LC_REEXPORT_DYLIB when targetting 10.5 + * doc/man/man1/ld.1: updated with new re-export options + * unit-tests/test-cases/indirect-path-search: added tests that -F and -L work with indirect dylibs + * unit-tests/test-cases/re-export-cases: added tests for all combinations of re-exporting + + +2007-03-14 Nick Kledzik + + sort external relocations to optimize dyld performance + * src/MachOWriterExecutable.hpp: added ExternalRelocSorter + * src/machochecker.cpp: verify external relocations are grouped by symbol number + * unit-tests/test-cases/external-reloc-sorting: added test case + + +----- Tagged ld64-72 + +2007-03-06 Nick Kledzik + + * src/Options.cpp: ignore .objc_category_name_* symbols in .exp files + + +2007-03-06 Nick Kledzik + + * src/Options.cpp: stop special casing mach_kernel and instead requre kernel to be built with -new_linker + + +2007-03-06 Nick Kledzik + + ld64-72 (experimental) is causing DejaGnu test failures + * src/MachOWriterExecutable.hpp: add optimizableGOTReferenceKind() to track GOT uses that cannot be optimized + + +2007-03-06 Nick Kledzik + + minimum header padding should be 32 to allow code signing + * src/Options.cpp: initialize fMinimumHeaderPad to 32 + * src/MachOWriterExecutable.hpp: better calculation of header padding + + +2007-03-06 Nick Kledzik + + Linker crashes with -flat_namespace against two-level dylibs that might have re-exports + * src/ld.cpp: flat namespace should not allow NULL indirect readers + + +2007-03-06 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: don't error on S_COALESCED sections with anonymous atoms + * src/MachOWriterExecutable.hpp: set MH_PIE bit when linking -pie + * ld64.xcodeproj/project.pbxproj: don't echo environment when running unit test + + +2007-03-01 Nick Kledzik + + * doc/man/man1/ld.1: Add descriptions to all "rarely used options" + + +2007-03-01 Nick Kledzik + + Remove support for Essential Symbols: Warn about use of -Sp option; remove man page entry + * src/Options.cpp: make -Sp obsolete + * doc/man/man1/ld.1: make -Sp obsolete + + +2007-03-01 Nick Kledzik + + Support -pie + * src/Options.h: Add positionIndependentExecutable() + * src/Options.cpp: Support -pie option to set positionIndependentExecutable() + * src/MachOWriterExecutable: if -pie is used, add extra local relocations and error if any + absolute addressing is used + + +2007-03-01 Nick Kledzik + + ld64 should link mach_kernel during xnu builds to support dtrace + * src/ld.cpp: Ensure segments are laid out in discovery order. Add support for kAbsoluteSymbol. + Warn when merging symbols of different visiblity. Warn when a tentative definition + is replaced by one a real definition with a smaller size. Lay out __common section + so that ones built with -fno-commons come before regular commons. + * src/ObjectFile.h: remove SegmentOffset ivar and getter/setters + * src/machochecker.cpp: allow images with no r/w segments + * src/MachOReaderRelocatable: Add AbsoluteAtom. Sort tentative definitions by name instead of by size + Add support for custom commons alignment. + * src/Options.cpp: Fix spurious -sectalign warnings. Don't use ld_classic when linking mach_kernel + * src/MachOWriterExecutable.hpp: Support kAbsoluteSymbol atoms. In -r mode, set custom alignment + for commons if alignment is not its size. Support global __dtrace_probe labels. + * src/ObjectDump.cpp: add support for kAbsoluteSymbol atoms. + * unit-tests/test-cases/commons-alignment: Added test case for custom commons alignment + * unit-tests/test-cases/absolute-symbol: Added test case for basic absolute symbols + * unit-tests/test-cases/segment-order: Added test case that segments lay out in discovery order + * unit-tests/test-cases/commons-order: Added test case that commons lay out correctly + * unit-tests/test-cases/end-label: Added test case that a label used to mark the end of a section does not + get associcated with the next section. + + +2007-02-23 Nick Kledzik + + gcc-5005: DejaGnu failures due to -frepo + * src/ld.cpp: Add quotes to referenced from name to make collect2 and -frepo happy + + +2007-02-22 Nick Kledzik + + * src/MachOWriterExecutable.hpp: rework how padding after load commands is calculated + + +2007-02-21 Nick Kledzik + + * src/MachOWriterExecutable.hpp: extend special case of __mh_execute_header to static executables too + + +2007-02-21 Nick Kledzik + + gcc link map option ( "-M" ) should be redirectable to file + * doc/man/man1/ld.1: added -map option description + * src/Options.h: added generatedMapPath() + * src/Options.cpp: set up generatedMapPath() if -map option is used + * src/MachOWriterExecutable.hpp: add writeMap() method to generate map file + + +2007-02-19 Nick Kledzik + + Implement GOT Load elimination optimization + * src/ld.cpp: track size of all atoms and if > 2GB sort large zero-fill atoms to end + * src/MachOWriterExecutable.hpp: If image size < 2GB, only generate GOT entries if value must be + updatable by dyld. If > 2GB, only eliminate GOT entries to non-zero-fill atoms. Any use + of an eliminated GOT entry has its code changed from MOVQ _foo@GOT(%rip) to LEAQ _foo(%rip). + * unit-tests/test-cases/large-data: added + * unit-tests/test-cases/got-elimination: added + + +----- Tagged ld64-71.2 + +2007-02-13 Nick Kledzik + + new ld ignores -segprot option + * src/Options.h: expose customSegmentProtections() + * src/Options.cpp: parse -segprot option and populate customSegmentProtections() + * src/MachOWriterExecutable.hpp: use customSegmentProtections() + + +2007-02-13 Nick Kledzik + + i386 -stack_addr doesn't work + * src/MachOWriterExecutable.hpp: use correct offset into thread state record + + +----- Tagged ld64-71.1 + +2007-02-07 Nick Kledzik + + * src/ld.cpp: sort __OBJC2 segment to be next to __OBJC segment + + +2007-02-07 Nick Kledzik + + * src/Options.cpp: change missing -seg_addr_table from an error to a warning + + +2007-02-06 Nick Kledzik + + Leopard 9A357: -dylib_file broken? + * src/MachOWriterExecutable.hpp: remove use of fInstallPathOverride + * src/Options.cpp: wire up -dylib_file option + * src/Options.h: remove fInstallPathOverride. add fDylibOverrides + * src/ld.cpp: check dylibOverrides() for indirect libraries + * unit-tests/test-cases/dylib_file: add test case + + +2007-02-05 Nick Kledzik + + * src/MachOReaderDylib.hpp: don't warn about zero size __image_info sections + + +2007-02-04 Rick Balocca + Enable the failing cases for missing command line arguments + +2007-02-04 Rick Balocca + Make sure that all .o's are checked by ObjectDump + and all macho are checked by machochecker + +2007-02-04 Rick Balocca + Fix an endian problem with machochecker + Fix blank-stubs Makefile + +----- Tagged ld64-71 + +2007-02-02 Rick Balocca + blank-stubs test case: handle the case of a native ppc compile--this + sets the subtype, which must be passed to lipo + +2007-02-01 Rick Balocca + make cpu-sub-types test more robust + +2007-02-01 Rick Balocca + auto-arch tests were resulting in a false FAILs + +2007-02-01 Rick Balocca + test cpu-sub-types was resulting in a false FAIL + +2007-02-01 Nick Kledzik + + STD:VSC: c99 -o writes to file that does not have write permission + * src/MachOWriterExecutable.hpp: check file is writable before using it + +2007-02-01 Nick Kledzik + + debug map (N_OSO) timestamps for object files in ranlib archive are incorrect + * src/MachOReaderArchive.hpp: parse modTime for .o files out of archive header + +2007-01-31 Nick Kledzik + + 9A354: ld -all_load does *NOT* produce the same dSYM as *.o or -u + * src/ld.cpp: when using -all_load don't assume that all atoms have same reader + * unit-tests/test-cases/dwarf-archive-all_load: added + +----- Tagged ld64-70.1 + +2007-01-31 Nick Kledzik + + * src/MachOWriterExecutable.hpp: in addObjectRelocs_powerpc() mask scattered r_address to 16-bits + +----- Tagged ld64-70 + + +2007-01-30 Nick Kledzik + + linker should verify GC consistency of modules being linked into library + Support cpu-sub-types for ppc + * src/ObjectFile.h: Add getObjCConstraint() and getCpuConstraint() + * src/MachOReaderRelocatable.hpp: don't make atom for __image_info section, instead parse constaints + * src/MachOReaderDylib.hpp: look at __image_info content to get constaints + * src/ld.cpp: add updateContraints() and checkObjc() + * src/MachOWriterExecutable.hpp: add ObjCInfoAtom to sythesize __image_info content + + +2007-01-28 Nick Kledzik + + src/*: remove ObjectFile::requiresFollowOnAtom() method + + +2007-01-28 Nick Kledzik + + src/ld.cpp: enable LLVM_SUPPORT by default + src/LLVMReader.hpp: don't use absolute paths for llvm headers and libraries + + +2007-01-26 Rick Balocca + * src/ObjectDump.cpp: The usage() message was incorrect. + + +2007-01-25 Rick Balocca + * unit-tests/test-cases/zero-fill3: It was reporting FAIL on ld64 error return. + It should have been checking for non-error return. + + +2007-01-24 Nick Kledzik + + x86 fast stubs should not cross 64-byte boundries + * src/MachOWriterExecutable.hpp: for x86, 64-byte align __jump_table section + and make 64-btye crossing stubs be empty entries with indirect symbol table + entry of INDIRECT_SYMBOL_ABS + + +2007-01-19 Nick Kledzik + + * src/Options.h: add readOnlyx86Stubs() + * src/Options.cpp: support -read_only_stubs + * src/MachOWriterExecutable.hpp: make __IMPORT segment not writable if -read_only_stubs is used + + +2007-01-16 Eric Christopher + + ld64 --help isn't recognized + * src/Options.cpp (Options::parse): Support --help and -help. + + +2007-01-15 Nick Kledzik + + * src/MachOFileAbstraction.hpp: add range checking on macho_scattered_relocation_info::set_r_address() + + +2007-01-14 Nick Kledzik + + Support wildcards in contents of -exported_symbols_list + * src/Options.h: add SetWithWildcards class + * src/Options.cpp: add -exported_symbol and -unexported_symbol and use SetWithWildcards + * doc/man/man1/ld.1: add -exported_symbol and wildcard explanation + * unit-tests/test-cases/exported-symbols-wildcards: added test case + + +2007-01-10 Nick Kledzik + + [U]SDT probes should use C calling convention + * src/Options.cpp: Add -read_only_dof + * src/ld.cpp: create __dof section(s) based on probe and isenabled sites + * src/MachOReaderRelocatable.hpp: parse new sdt 2.0 probes encoded in .o files + * src/MachOWriterExecutable.hpp: handle regenerating dtrace probes into .o files + * unit-tests/test-cases/dtrace-static-probes: added test case + + +----- Tagged ld64-69.8 + +2007-01-30 Nick Kledzik + + Support LD_FORCE_NO_SEG_ADDR_TABLE + * src/Options.cpp: Support LD_FORCE_NO_SEG_ADDR_TABLE + + +----- Tagged ld64-69.7 + +2007-01-25 Nick Kledzik + + Leopard9A351: CFM Apps Are Broken because CFM glue is missing + * src/MachOReaderRelocatable.hpp: check S_ATTR_NO_DEAD_STRIP in dontDeadStrip() + + +----- Tagged ld64-69.6 + +2007-01-24 Nick Kledzik + + LD_TRACE_ARCHIVES should only print out when a .o is actually used from an archive + * src/ld.cpp: create and use logArchive() + + +----- Tagged ld64-69.5 + +2007-01-22 Nick Kledzik + + 9A350: can't link ppc programs with ld_classic + * src/Options.cpp: Remove support for LD_NO_CLASSIC_LINKER. Add support for -classic_linker + + +----- Tagged ld64-69.4 + +2007-01-17 Nick Kledzik + + QTComponents does not link with ld64 + * src/MachOReaderRelocatable.hpp: handle N_RSYM and N_PSYM stabs + + +----- Tagged ld64-69.3 + +2007-01-03 Nick Kledzik + + * src/Options.cpp: If the same dylib is specified twice and the second is specified weak, make it weak + + +----- Tagged ld64-69.2 + +2006-12-18 Nick Kledzik + + -dead_strip without -exported_symbols_list should not strip global functions from archives + * src/ld.cpp: when adding a .o file from an archive, add all its global symbols to live roots + * unit-tests/test-cases/dead_strip-archive: added + + +2006-12-18 Nick Kledzik + + flat_namespace main executables do not need to indirect interior references + * src/MachOWriterExecutable.hpp: don't indirect references to global symbols in main executables + * unit-tests/test-cases/flat-main: updated to test for indirection + * unit-tests/test-cases/flat-dylib: added + + +----- Tagged ld64-69.1 + +2006-12-15 Nick Kledzik + + -flat_namespace does not work with -mdynamic-no-pic + * src/MachOWriterExecutable.hpp: rework checking for use of ppc absolute addressing to allow them as long as + the target is within the same linkage unit. + + +2006-12-15 Nick Kledzik + + -ObjC should only load .o with .objc_ symbols + * src/Options.cpp: remove warning from -ObjC and have it instead set fLoadAllObjcObjectsFromArchives + * src/MachOReaderArchive.hpp: when -ObjC is used, preload all .o files from archives that contain .objc_ symbols + + +----- Tagged ld64-69 + +2006-12-13 Nick Kledzik + + prebound interior pointers must be non-zero + * src/MachOWriterExecutable.hpp: in fixUpReference_powerpc() set lazy pointers bound to with the dylib to + their target value. Properly set REFERENCE_FLAG_UNDEFINED_* flags in reference table and n_desc + + +2006-12-09 Nick Kledzik + + ld64 fails to detect error that ld_classic does + * src/MachOWriterExecutable.hpp: check for absolute reloc to an external symbol + * src/MachOReaderRelocatable.hpp: ignore -mlong-branch stubs in .o files + + +2006-12-09 Nick Kledzik + + symbols with REFERENCED_DYNAMICALLY should never be stripped + * src/MachOWriterExecutable.hpp: update Writer::shouldExport() to check for kSymbolTableInAndNeverStrip + * unit-tests/test-cases/main-stripped: add test that dynamically referenced symbol cannot be stripped + + +2006-12-08 Nick Kledzik + + * unit-tests/test-cases/allowable-client: add variant test cases (e.g. CoreServices_profile) + * src/ld.cpp: allow frameworks with variant install names (e.g. CoreServices_profile) to be private clients + + +2006-12-08 Nick Kledzik + + * doc/man/man1/ld.1: rewrite man page + * src/Options.h: add warnObsolete() + * src/Options.cpp: use warnObsolete() on many options. Make nonWeak the weak-mis-match default. + Make -ObjC mean -all_load. + +----- Tagged ld64-68.3 + +2006-12-05 Nick Kledzik + + * src/ld.cpp: allow umbrella frameworks to have variant install names (e.g. CoreServices_profile) and still link + + +----- Tagged ld64-68.2 + +2006-12-05 Nick Kledzik + + * src/MachOWriterExecutable.cpp: Use N_PBUD in the symbol table for undefined symbols in prebound dylibs + + +----- Tagged ld64-68.1 + +2006-12-01 Nick Kledzik + + * src/Options.cpp: always generate module tables for 32-bit architectures so that ld_classic + can link against them + + +----- Tagged ld64-68 + +2006-12-01 Nick Kledzik + + seg_addr_table needs matching fuzziness + * src/Options.cpp: special case a how a dozen dylib are looked up in the seg_addr_table + + +2006-12-01 Nick Kledzik + + * src/Options.cpp: have all -static links for 32-bit archs roll over to ld_classic unless + LD_NO_CLASSIC_LINKER_STATIC is set. + * unit-tests/bin/make-recursive.pl: set LD_NO_CLASSIC_LINKER_STATIC for unit tests + + +2006-11-29 Nick Kledzik + + ld64-67: QTComponents fails to build + * src/MachOReaderRelocatable.hpp: don't error out when a local non-lazy pointer does not point to a symbol + * unit-tests/test-cases/strip_local: added test case + + +2006-11-28 Nick Kledzik + + Need a way to mark libraries usable by dynamic linker but unusable by static linker + * src/Options.cpp: allow -client_name to be used with main executables + * src/ld.cpp: generalize -allowable_client. Any dylib can now restrict who can link against it. As a convention + linking with -allowable_client '!' will mean no one can statically link with the dylib. It can still be loaded + dynamically, or by any existing clients, but no new clients can link with it. + * unit-tests/test-cases/allowable-client/Makefile: enable previously commented out test cases. Add test cases + of a dylib that allows no clients and just one client + +2006-11-27 Nick Kledzik + + -final_output should be used if -install_name not used + * src/Options.cpp: fall back to using -final_output for install name + + +----- Tagged ld64-67 + +2006-11-17 Nick Kledzik + + * src/MachOWriterExecutable.hpp: support __IMPORT segment being slide independently of __DATA segment in shared cache + + +2006-11-16 Nick Kledzik + + 9a303: ld -filelist Bus Error + * src/Options.cpp: add check that -filelist is followed by an argument + + +2006-11-16 Nick Kledzik + + * src/MachOWriterExecutable.hpp: when building split-seg dylibs, LINKEDIT goes in read-only side + + +2006-11-15 Nick Kledzik + + * src/MachOWriterExecutable.hpp: set proper attributes for __eh_frame in ld -r mode + * unit-tests/test-cases/eh_frame: added test case + + +2006-11-10 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: redirect references to static weak stubs to the real target + + +2006-11-09 Nick Kledzik + + * src/MachOWriterExecutable.hpp: r_address is offset from first LC_SEGMENT vmaddr - not from segment with lowest address + + +----- Tagged ld64-66.1 + +2006-11-09 Nick Kledzik + + * src/MachOWriterExecutable.hpp: initialize fModuleInfoAtom to zero + + +2006-11-08 Nick Kledzik + + FSF GCC's libjava doesn't link with Ochre ld64 + * src/MachOReaderRelocatable.hpp: ignore debug_line section if debug_info section is missing or empty + +----- Tagged ld64-66 + +2006-11-07 Nick Kledzik + + SWB: d64-65 does not built usage split-seg dylibs + * src/MachOWriterExecutable.hpp: when prebinding split-seg correctly set r_address fields and on + disk values for external relocations + * unit-tests/test-cases/prebound-split-seg: added test case + + +2006-11-03 Nick Kledzik + + * src/MachOReaderDylib.hpp: don't report dependent libraries if MH_NO_REEXPORTED_DYLIBS bit is set + * src/MachOWriterExecutable.hpp: set MH_NO_REEXPORTED_DYLIBS bit if dylib does not logically re-export any other dylibs + * unit-tests/test-cases/re-export-flag: added test case + * src/machochecker.cpp: validate use of MH_NO_REEXPORTED_DYLIBS + + +2006-11-02 Nick Kledzik + + Mysterious messages from ld64 with MACOSX_DEPLOYMENT_TARGET = 10.5 + * src/MachOWriterExecutable.hpp: kPointerWeakImport is a valid reference type to cross segments + + +2006-11-02 Nick Kledzik + + * src/Options.cpp,h: Add support for -rpath + * src/MachOFileAbstraction.hpp: add macho_rpath_command + * src/MachOWriterExecutable.hpp: add RPathLoadCommandsAtom to create LC_RPATH for each -rpath + + +----- Tagged ld64-65 + +2006-10-30 Nick Kledzik + + x86_64 default stack_addr is wrong + * src/Options.cpp: change default 64-bit stack location when using -stack_size + + +2006-10-30 Nick Kledzik + + dylibs need modules for 10.3 and for ld_classic in Salt + * src/MachOWriterExecutable.hpp: add ModuleInfoLinkEditAtom to create module table stuff + * src/Options.cpp,h: Add needsModuleTable() + * src/MachOFileAbstraction.hpp: Add macho_dylib_module, macho_dylib_reference, and macho_dylib_table_of_contents + + +2006-10-27 Nick Kledzik + + * unit-tests/test-cases/no-uuid/Makefile: add -gstabs+ to be compatible with latest compiler + * unit-tests/test-cases/stabs-coalesce/Makefile: add -gstabs+ to be compatible with latest compiler + + +2006-10-26 Nick Kledzik + + i386 -mdynamic-no-pic switch statement jump table is out of line + * src/MachOWriterExecutable.hpp: for i386 don't check for direct references to weak symbols + + +2006-10-26 Devang Patel + + * src/LLVMReader.hpp: Supply final output file path to optimizer. + +2006-10-26 Devang Patel + + * src/ObjectFile.h: Make setSection* methods virtual. + * src/LLVMReader.hpp: Override setSection* methods. + +2006-10-26 Devang Patel + + * unit-tests/test-case/llvm-integration/a13.h: New. + * unit-tests/test-case/llvm-integration/a13.cc: New. + * unit-tests/test-case/llvm-integration/main13.cc: New. + +2006-10-26 Devang Patel + + * src/options.h, src/options.cpp: Add -save-temps command line option. + * src/LLVMReader.hpp: Use saveTemps option. + + +2006-10-26 Devang Patel + + * src/LLVMReader.hpp: Remove invalid module from memory. + +2006-10-26 Devang Patel + + * src/LLVMReader.hpp: Collect symbol alignment info from LLVM optimizer. + +2006-10-21 Eric Christopher + + * src/ld.cpp (Linker::Linker): Check for LD_NO_CLASSIC_LINKER before + invoking ld_classic. + * unit-tests/test-cases/relocs-literals/Makefile: Run for -mdynamic-no-pic + and pic. + * unit-tests/test-cases/static-executable/Makefile: Skip for 64-bit. Add + -dead_strip to command line. + +----- Tagged ld64-64.2 + +2006-10-19 Nick Kledzik + + * ld64.xcodeproj/project.pbxproj: stop copying LLVMReader.hpp into man1 directory + +----- Tagged ld64-64.1 + +2006-10-19 Nick Kledzik + + ld64-63.1 erroneously coalesces an empty string with a non-empty string + * src/MachOReaderRelocatable.hpp: rework cstring parsing to not assume all strings are start + at section alignment boundaries, and when coalescing empty strings always use one with greatest + alignment requirement + * src/MachOWriterExecutable.hpp: in -r mode, don't pad end of cstring section + * src/ObjectFile.h: correctly name leadingZeros() as trailingZeros() + * src/ld.cpp: leadingZeros() --> trailingZeros() + + +2006-10-18 Eric Christopher + + * unit-tests/test-cases/read-only-relocs/Makefile: Skip for x86_64. + * unit-tests/test-cases/llvm-integration/Makefile: Skip if llvm isn't + present. + +2006-10-18 Nick Kledzik + + ld64 change required to go with assembler cstring change + ld64 should error when a local relocation references an address outside its section + * src/MachOReaderRelocatable.hpp: for x86_64 in order to work with local or external relocations to cstrings + change parser to allow atoms with a pending name that is resolved after references are instantiated. + Make direct references to kRegularDefinition atoms. + * src/MachOWriterExecutable.hpp: in -r mode for x86_64 generate L* labels for cstrings and use external relocations + * unit-tests/test-cases/relocs-literals/test.c: add two cases of cstring literal plus addend + + +2006-10-06 Nick Kledzik + + check MACOSX_DEPLOYMENT_TARGET if -macosx_version_min is not used + * src/Options.cpp: if -macosx_version_min is not used, check MACOSX_DEPLOYMENT_TARGET, if + that is unused, default to 10.5 + +----- Tagged ld64-64 + +2006-10-06 Nick Kledzik + + crash in ppc64 program - bl to saveFP, but saveFP is too far away? + * src/MachOWriterExecutable.hpp: in addPPCBranchIslands(), properly account for growth of __text + + +2006-10-06 Nick Kledzik + + Linker-defined alias converts reference into definition and generates error. + * src/MachOReaderRelocatable.hpp: only alias symbols actually in the symbol table + + +2006-10-06 Nick Kledzik + + * unit-tests/test-cases/dwarf-debug-notes/Makefile: crt1.o no longer has stabs, so don't need to strip it + * unit-tests/test-cases/dwarf-debug-notes-r/Makefile: crt1.o no longer has stabs, so don't need to strip it + + +2006-10-06 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: rework dwarf line parsing to fix warnings that starting + showing up with gcc-5421 + + +2006-10-05 Eric Christopher + + ld64 needs to support libtool options + * src/Options.cpp (Options::parse): Add -noall_load, -install_name, + -current_version and -compatibility_version. + +2006-10-03 Eric Christopher + + * src/Options.cpp (Options::gotoClassicLinker): Use execvp + to call ld_classic. + +2006-10-03 Eric Christopher + + * unit-tests/test-cases/tentative-to-real/Makefile: Clean up after tests. + +2006-10-03 Eric Christopher + + * unit-tests/include/common.makefile (VALID_ARCHS): Add x86_64. + (OTOOL): Remove munging based on ARCH. + +2006-09-29 Nick Kledzik + + problem merging .o files built with and without -fno-common + src/Options.*: make MakeTentativeDefinitionsReal a reader option + src/ObjectFile.h: make MakeTentativeDefinitionsReal a reader option + src/MachOWriterExecutable.hpp: make MakeTentativeDefinitionsReal a reader option + src/MachOReaderRelocatable.hpp: only assign a section name of __common to + tentative defintions when making a final linked image + + +2006-09-28 Nick Kledzik + + src/Options.h/.cpp: add support for -segaddr option + src/MachOWriterExecutable.hpp: In Writer::assignFileOffsets(), use -segaddr info + + +2006-09-28 Nick Kledzik + + Emit new CPU subtypes for ppc64 and x86-64 when targeting 10.5 or later + src/MachOWriterExecutable.hpp: set high bit of cpusubtype of 64-bit main executables when targeting 10.5 or later + + +2006-09-28 Devang Patel + + Add LLVM LTO support + src/LLVMReader.hpp: New file. + src/ld.cpp: Add optimization phase. Use LLVM LTO. + unit-tests/test-cases/llvm-integration: New tests. + +2006-09-27 Nick Kledzik + + ld64.xcodeproj/project.pbxproj: remove accidental install of source file into man1 + + +2006-09-25 Nick Kledzik + + src/Architectures.hpp: add kPointerDiff16 for ppc and ppc64 + src/MachOReaderRelocatable.hpp: support kPointerDiff16 + src/MachOWriterExecutable.hpp: support kPointerDiff16 + +----- Tagged ld64-63.1 + +2006-09-22 Nick Kledzik + + src/MachOWriterExecutable.hpp: include stubs in LC_SEGMENT_SPLIT_INFO + + +2006-09-21 Nick Kledzik + + src/Options.cpp: disable split-seg dylibs for 64-bit architectures + + +2006-09-19 Nick Kledzik + + src/MachOReaderRelocatable.hpp: rework __cstring parsing to better handle mixed alignment cstrings + src/MachOWriterExecutable.hpp: in -r mode, make all __cstrings aligned to section alignment + + +2006-09-19 Nick Kledzik + + src/MachOWriterExecutable.hpp: rework encoding of LC_SEGMENT_SPLIT_INFO + + +2006-09-19 Nick Kledzik + + src/Options.cpp: check for -search_paths_first in first pass + + +----- Tagged ld64-63 + +2006-09-15 Nick Kledzik + + src/Options.cpp: since the ld64 will repeatedly search an archive, and some project list archives + multiple times on command line to work with traditional linkers, automatically ignore duplicate libraries + unit-tests/test-cases/archive-duplicate: added test case + + +2006-09-15 Nick Kledzik + + src/Options.cpp: support -r -static + src/MachOWriterExecutable.hpp: support -r -static an don't generate LC_DYSYMTAB + + +2006-09-14 Nick Kledzik + + src/MachOWriterExecutable.hpp: in -r mode references to weak symbols should not create external relocations + as that can cause nmedit to errror later. + + +2006-09-13 Nick Kledzik + + ld64: Handle .objc_class_name exports specially + src/Options.cpp: add hack so that .objc_class_name_XXX in -exported_symbols_list imples _OBJC_CLASS_$_XXX + src/ld.cpp: add hack to supporess errors about .objc_class_name_XXX or _OBJC_CLASS_$_XXX being undefined + + +2006-09-12 Nick Kledzik + + Support -prebind when targeting ppc and OS < 10.4 + src/Options.h: add splitSeg() and baseWritableAddress() + src/Options.cpp: Add support for -seg_addr_table and LD_SEG_ADDR_TABLE, and -prebind and LD_PREBIND. + src/src/MachOWriterExecutable.hpp: support split-seg and canonical prebound files to be generated + + +2006-09-11 Nick Kledzik + + Linking a dylib or binary from identical binaries should produce the same output + src/MachOWriterExecutable.hpp: set the timestamps to be constant + + +2006-09-11 Nick Kledzik + + Linker support for ordering all sections and symbols + src/Options.cpp: Add -order_file_statistics. Allow architecture prefixes in order files + src/ld.cpp: Use fOptions.printOrderFileStatistics() + + +2006-09-11 Nick Kledzik + + Support -sectorder + unit-tests/test-cases/order_file: added test case + src/ld.cpp: Implement order file support in Linker::sortAtoms() + src/Options.h: add Options.orderedSymbols() + src/Options.cpp: add parseOrderFile(), implement -order_file + + +2006-09-07 Nick Kledzik + + need -i for 64-bit (or equivalent) + Support -i for aliasing exported symbols + unit-tests/test-cases/alias-objects: added + unit-tests/test-cases/alias-command-line: added + src/ObjectFile.h: Added Atom::getOrdinal() as new way to sort atoms. Added ReaderOptions.fAliases + src/MachOReaderRelocatable.hpp: Added SymbolAliasAtom to handle multiple symbols to same address + src/MachOReaderArchive.hpp: implement Atom::getOrdinal() to space out atom ordinals across member objects + src/Options.cpp: support -i, -alias, -alias_list. Move search of /Network/Library/Frameworks to after /System/Library/Frameworks + src/MachOWriterExecutable.hpp: pad out seg_info data. Implement getOrdinal(). + src/ObjectDump.cpp: call constructors directly instead of using make() wrapper + + +2006-09-01 Nick Kledzik + + Need the ability to tag libraries/plug-ins with security attributes + src/MachOReaderDylib.hpp: add warning if using -root_safe or -setuid_safe and link against dylib that is not + src/ObjectFile.h: add ReaderOption fRootSafe and fSetuidSafe + src/Options.cpp: handle -root_safe or -setuid_safe command line options + src/MachOWriterExecutable.hpp: set MH_ROOT_SAFE and MH_SETUID_SAFE flags + + +2006-08-31 Nick Kledzik + + src/ld.cpp: Add Linker::processDTrace() for processing dtrace static probes + src/OpaqueSection.hpp: renamed, add symbol name, add ability to add references + ld64.xcodeproj/project.pbxproj: remove SectCreate.cpp, add OpaqueSection.hpp + + +2006-08-28 Nick Kledzik + + Add convention for removing symbols at link time + Assembler -L option causes ld64 to split stubs + unit-tests/test-cases/special-labels: added test case + src/MachOReaderRelocatable.hpp: ignore L* labels, make l* labels as kSymbolTableNotIn + + +2006-08-28 Nick Kledzik + + src/lObjectFile.h: refactor isTargetUnbound() into getTargetBinding() + src/ld.cpp: create __dof section in final linked images from dtrace static probes + src/Architectures.hpp: add kDtraceProbe + src/Options.h/cpp: Add support for -dtrace + src/machochecker.cpp: support LC_SEGMENT_SPLIT_INFO + src/MachOWriterExecutable.hpp: support kDtraceProbe + src/MachOReaderRelocatable.hpp: suppport kDtraceProbe + + +2006-08-25 Nick Kledzik + + generate LC_SEGMENT_SPLIT_INFO for 10.5 or later dylibs + src/Options.h&.cpp: implement sharedRegionEligible() to control when LC_SEGMENT_SPLIT_INFO is added + src/MachOFileAbstraction.hpp: add macho_linkedit_data_command + src/MachOWriterExecutable.hpp: generate LC_SEGMENT_SPLIT_INFO load command and linkedit content + +----- Tagged ld64-62 + +2006-08-15 Nick Kledzik + + wrong error message when symbol is found in unused indirect library + src/ld.cpp: remove indirect libraries if they are not re-exported + unit-tests/test-cases/indirect-dylib: added test case + + +2006-08-15 Nick Kledzik + + alignment needs to be richer + src/ObjectFile.h: define ObjectFile::Alignment class for tracking rich alignment info + src/ld.cpp: modify SymbolTable::add() to work with new Alignment type + src/MachOReaderRelocatable.hpp: use new Alignment type. Remove alignAtLeast() and handleAnonymousNonLazyPointers() + src/MachOWriterExecutable.hpp: update for new Alignment type, use modulus when calculating layout address + src/ObjectDump.cpp: print richer Alignment info + unit-tests/test-cases/align-modulus: added test case + + +2006-08-11 Nick Kledzik + + remove OPEN_SOURCE conditionals around x86_64 support + + +2006-07-31 Nick Kledzik + + ld64 while linking cc1 [ when dead_strip is ON] + src/ld.cpp: Add ivar fAtomsWithUnresolvedReferences to track atoms not initially resolvable + unit-tests/test-cases/dead_strip-archive: added test case + + +2006-07-31 Nick Kledzik + + x86_64: instructions with immediate and rip-relative operands need to use new relocation types + src/MachOWriterExecutable.hpp: generate new reloc types in -r mode + src/MachOReaderRelocatable.hpp: parse new reloc types + unit-tests/test-cases/relocs-asm/relocs-asm.s: add test cases for new reloc type + + +2006-07-18 Nick Kledzik + + src/MachOReaderRelocatable.hpp: suppress warning about dwarf info parsing for one benign no-op case + the compiler emits when there are not functions in the __text section + + +2006-07-17 Nick Kledzik + + faster debug note generation + src/ld.cpp: rework collectDebugInfo() to produce all debug notes in one pass, intead of a + pass per .o file. Added timing info for collectDebugInfo() to -print_statistics + unit-tests/test-cases/dwarf-debug-notes-r/Makefile: add expliced -arch to ld -r + unit-tests/test-cases/dwarf-debug-notes-r/expected-stabs: alter for new debug notes order + + +2006-07-17 Nick Kledzik + + ld64 VSIZE is 1.18GB when building Finder ppc64 + src/ld.cpp: fixed typo in createReader() that prevented dylibs from being unmapped + +----- Tagged ld64-61.1 + +2006-07-11 Nick Kledzik + + ld64-61: gcc DejaGnu tests failing due to -arch followed by unknown architecture name + src/Options.cpp: map ppc750, ppc7400, ppc7450, and ppc970 to ppc. Improve error message + +2006-07-11 Nick Kledzik + + If -arch is missing, rollover to ld_classic does not happen + src/Options.h: make gotoClassicLinker() public + src/ld.cpp: call gotoClassicLinker() if the inferred architecture is ppc or i386 + +----- Tagged ld64-61 + +2006-06-29 Nick Kledzik + + ld64 should be renamed to ld + src/Options.cpp: exec() ld_classic if -arch ppc or -arch i386 is seen + src/ld.cpp: alter version string + ld64.xcodeproj/project.pbxproj: change install location to /usr/bin/ld, add symlink from /usr/bin/ld64 + doc/man/man1/ld.1: added + +----- Tagged ld64-60 + +2006-06-28 Nick Kledzik + + Can't link large ppc64 program: ld64 says "bl out of range" + MachOWriterExecutable.hpp: fix branch island generation to work for weak_import functions + and properly chain together branch islands + MachOReaderRelocatable.hpp: improve performance of huge .o file reading by sorted references + only when done + +2006-06-28 Nick Kledzik + + MySQL-36 fails to build with ld64-59 + src/MachOReaderRelocatable.hpp: back out fix for 4585335 + src/MachOWriterExecutable.hpp: back out fix for 4585335 + +2006-06-27 Nick Kledzik + + src/MachOReaderRelocatable.hpp: handle N_GSYM without ending :G() since that is how + dwarf debug notes are formed. + +2006-06-23 Nick Kledzik + + + + ld64 doesn't support variant linking -framework fw,_debug + src/Options.cpp: enhance findFramework() to support suffixes + +----- Tagged ld64-59 + +2006-06-22 Nick Kledzik + + ld64 lost DWARF debug notes + src/MachOReaderRelocatable.hpp: add fHasUUID so kDebugInfoStabsUUID can be set later + unit-tests/test-cases/dwarf-debug-notes-r: added test case + +2006-06-21 Nick Kledzik + + python 64-bit address miscalculation + src/MachOReaderRelocatable.hpp: change getTargetOffset() to sign extend the 32-bit value to 64-bits + +2006-06-21 Nick Kledzik + + ld64 seems to offset things incorrectly when using -r + src/MachOWriterExecutable.hpp: in -r mode, virtual sections should not increment address + + +----- Tagged ld64-58 + +2006-06-16 Nick Kledzik + + src/rebase.cpp: fix page alignment problem + src/rebase.cpp: fix endianess problem with local non-lazy pointers + +2006-06-15 Nick Kledzik + + src/rebase.cpp: fix to build in CurryWeed + ld64.xcodeproj/project.pbxproj: fix to build properly in CurryWeed + +2006-06-15 Nick Kledzik + + Support .objc_class_name_* symbols + src/ObjectFile.h: Add kSymbolTableInAsAbsolute + src/MachOReaderRelocatable.hpp: synthesize references to required objc classes + src/MachOWriterExecutable.hpp: write objc_class_name as absolute symbol + unit-tests/test-cases/objc-references: added + +2006-06-15 Nick Kledzik + + SECTION_ATTRIBUTES unset in ppc64 mach-o header + src/MachOWriterExecutable.hpp: add section attribute for sections with code + +2006-06-15 Nick Kledzik + + ld64 bogus duplicate symbol name linking GNU libobjc + src/MachOReaderRelocatable.hpp: only special case Apple objc runtime objc classes + +2006-06-15 Nick Kledzik + + x86_64: ".align" directive not honored + src/MachOReaderRelocatable.hpp: change code alignment to not depend on atom size + +2006-06-14 Nick Kledzik + + jump table into middle of weak symbol causes error + src/MachOReaderRelocatable.hpp: create direct references to the interior of weak symbols + src/MachOWriterExecutable.hpp: do not error on absolute references to interior of weak symbols + +2006-06-13 Nick Kledzik + + src/Options.cpp: allow -image_base as an alias for -seg1addr + +2006-06-13 Nick Kledzik + + implement -d + src/Options.h: add fMakeTentativeDefinitionsReal + src/Options.cpp: set fMakeTentativeDefinitionsReal if -d option is found + src/MachOWriterExecutable.hpp: turn tentative into real definition if makeTentativeDefinitionsReal + unit-tests/test-cases/btentative-to-real: added test case + +2006-06-13 Nick Kledzik + + implement -bundle_loader + src/Options.h: add fBundleLoader bit to DynamicLibraryOptions + src/Options.cpp: handle -bundle_loader + src/ld.cpp: pass fBundleLoader bit to MachOReaderDylib + src/MachOReaderDylib.hpp: support reading MH_EXECUTE files if fBundleLoader is set + src/MachOWriterExecutable.hpp: set bundle loader ordinal as EXECUTABLE_ORDINAL + unit-tests/test-cases/bundle_loader: added test case + +2006-06-12 Nick Kledzik + + -syslibroot can cause "can't find ordinal for imported" error + src/MachOReaderDylib.hpp: in Reader::reExports() compare install path in addition to load path + + +2006-06-10 Nick Kledzik + + Need rebasing tool + src/rebase.cpp: added + unit-tests/test-cases/rebase-basic: added + doc/man/man1/rebase.1: added + ld64.xcodeproj/project.pbxproj: added rebase target. changed all targets to build with dwarf + + +2006-06-10 Nick Kledzik + + src/machochecker.cpp: add some ppc reloc sanity checking + +----- Tagged ld64-57 + +2006-06-06 Nick Kledzik + + ld64 is not adding a final '/' char on the initial directory-name SO stab debug map entry + ld.cpp: Change Linker::synthesizeStabs() to assure directory SO always has a trailing slash + unit-tests/test-cases/dwarf-debug-notes/expected-stabs: update with trailing / + +2006-06-06 Nick Kledzik + + -sectcreate of a 0-byte section fails + MachOWriterExecutable.cpp: Don't error out on zero length segments + MachOWriterExecutable.cpp: For ppc64 reloc base address is the first writable segment iff + there is a writable segment >4GB from base address + +2006-06-04 Eric Christopher + + Radar 4560240 + Radar 3964999 + * src/ld.cpp (createReader): Fixed error message. + (resolve): Ditto. + (resolveFrom): Ditto. + (checkUndefines): Ditto. + +----- Tagged ld64-56 + +2006-05-23 Nick Kledzik + + No debug notes for ObjC methods when linking with ld64 + ld.cpp: don't limit debug notes to functions starting with underscore + +2006-05-22 Nick Kledzik + + ld64 spends much time in mach_o::relocatable::Reader::findAtomByName + * src/MachOReaderRelocatable.hpp: add makeReferenceToSymbol() so that x86_64 does not need to do by-name lookups + +2006-05-22 Nick Kledzik + + remove inferring warning + * ld.cpp: Remove "inferring" warning. If a link failed and now arch was specifed add which arch was + inferred to error message + +2006-05-19 Nick Kledzik + + ld64 does not honor -arch_multiple + * ld.cpp: If fOptions.printArchPrefix(), add architecture name to error message + +2006-05-19 Nick Kledzik + + Support S_16BYTE_LITERALS section types + * src/MachOReaderRelocatable.hpp: support S_16BYTE_LITERALS + * src/MachOWriterExecutable.hpp: support S_16BYTE_LITERALS + +2006-05-19 Nick Kledzik + + "warning can't parse dwarf compilation unit info" warnings building debug + * src/MachOReaderRelocatable.hpp: fix bugs in dwarf line table parsing + +----- Tagged ld64-55 + +2006-05-18 Nick Kledzik + + Default the pagezero size to 4GB for x86-64 + * src/Options.cpp: Chnage default the pagezero size to 4GB for x86-64 + +2006-05-18 Nick Kledzik + + x86_64 CarbonCore fails to link with "atom not found in symbolIndex" + * src/MachOWriterExecutable.hpp: in buildObjectFileFixups() don't call addObjectRelocs() on kNoFixUp references + +2006-05-18 Nick Kledzik + + ld64: .section defaults to read-only + * src/MachOReaderRelocatable.hpp: default unknown segments to r/w + +2006-05-18 Nick Kledzik + + -fvisibility=hidden causes crashes for x86_64 + * src/MachOWriterExecutable.hpp: properly handle RIP relative tentative definitions + +2006-05-12 Nick Kledzik + + * src/Architectures.hpp: add x86::kAbsolute32 + * src/MachOReaderRelocatable.hpp: generate x86::kAbsolute32 for mdynamic-no-pic instructions + * src/MachOWriterExecutable.hpp: process x86::kAbsolute32 reference kind + +----- Tagged ld64-54 + +2006-05-11 Nick Kledzik + + CF-393 failes to link for x86_64 + * src/MachOWriterExecutable.cpp: fix sign extension for Rel32 relocs in Writer::fixUpReferenceRelocatable + +2006-05-11 Nick Kledzik + + warning arch x86_64 not found using i386 + * src/ld.cpp: remove hack to allow x86_64 to link against i386 dylibs + + +2006-05-10 Nick Kledzik + + x86_64: .objc_class_name symbol names scrambled + * src/MachOReaderRelocatable.hpp: properly compute alignment of __OBJC __class sections + + +2006-05-08 Nick Kledzik + + Support -dead_strip + * src/Options.h/cpp: implement -why_load and -why_live. Enable -dead_strip. + * src/MachOReaderArchive.hpp: implement -why_load + * src/MachOReaderRelocatable.hpp: suppress GCC_except_table* symbols in final output + * src/ld.cpp: implement dead code stripping + * unit-tests/test-cases/dead_strip: added + +----- Tagged ld64-53 + +2006-05-05 Nick Kledzik + + * src/Options.cpp: make 10.4 be minimum OS version for newer architectures + +2006-05-05 Nick Kledzik + + N_SO symbols in 64-bit builds have a zero address for n.n_value + * src/ld.cpp: for SO stabs, associate first and last atom in the SO range + * src/MachOWriterExecutable.hpp: use atom associated with SO stab to set ins n_value + +2006-05-05 Nick Kledzik + + * MachOWriterExecutable.hpp: fix end FUN stab to have length of function + + +2006-05-02 Nick Kledzik + + 64-bit main executables should have 4GB zero page by default + * src/Opptions.cpp: change default pagezero_size to 4GB for ppc64 + 64 bit: apps with -mdynamic-no-pic seg fault when page zero > 4GB + * src/MachOWriterExecutable.cpp: rework pagezero for ppc64 so that if any mdynamic-no-pic code + is found, the code is kept in the low 2GB, and a new segment is create to map away up to 4GB. + +2006-05-02 Nick Kledzik + + * src/Opptions.cpp: remove warning about -stack_addr not specified. Add warning if 32-bit stack + overlaps shared region + +----- Tagged ld64-52.1 + +2006-05-01 Nick Kledzik + + * src/MachOReaderRelocatable.cpp: rework handleAnonymousNonLazyPointers() to handle anl's in the middle + the __data section too. + +----- Tagged ld64-52 + +2006-04-28 Nick Kledzik + + 64-bit: 9A152 TextEdit crashes in dlopen on bring-up + * src/MachOReaderRelocatable.cpp: rework anonymous non-lazy-pointer detection + +2006-04-28 Nick Kledzik + + 64 Bit: Development build of ppc64 TextEdit gets confused about static variables + * src/MachOReaderRelocatable.cpp: mark non-lazy-pointer atoms as scopeTranslationUnit if targetting a static symbol + + + +2006-04-21 Nick Kledzik + + * src/Options.cpp: fix default address for ppc64 custom stack + * src/MachOWriterExecutable.cpp: fix set up of ppc64 custom stack + + +2006-04-14 Nick Kledzik + + * src/Options.cpp: fix -sub_library processing to work it dylib is specifed with leaf name + +----- Tagged ld64-51.1 + +2006-04-13 Nick Kledzik + + 64-bit: 9A152 TextEdit crashes in dlopen on bring-up + * src/MachOReaderRelocatable.hpp: when detecting anonymous non-lazy-pointers disqualify data + that points to static or global symbols + * src/ld.cpp: print version of ld64 in error messages + + +----- Tagged ld64-51 + +2006-04-11 Nick Kledzik + + exported symbols not properly stripped + * src/MachOReaderRelocatable.hpp: enable AnonymousAtom::setScope() + +2006-03-31 Nick Kledzik + + ld64 fails when linking debug ppc64 HIToolbox + * src/MachOReaderRelocatable.hpp: handle anonymous non-lazy pointers encoded with local relocations + * src/MachOWriterExecutable.hpp: in -r mode, only generated INDIRECT_SYMBOL_LOCAL for non-lazy targets that + + +2006-03-31 Nick Kledzik + + ld64 should remove generated file if link errors out + * src/MachOWriterExecutable.hpp: catch exceptions in Writer::write(), delete output file, and rethrow + + +----- Tagged ld64-50 + + +2006-03-29 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: synthesize .objc_class_name symbols + * src/MachOFileAbstraction.hpp: use strncpy for sect/seg names to zero fill trailing space + +2006-03-28 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: fix spurious warning about dwarf line info + +----- Tagged ld64-49.1 + +2006-03-25 Nick Kledzik + + * MachOWriterExecutable.hpp : don't complain about ppc64 dyld being based > 4GB + +----- Tagged ld64-49 + +2006-03-24 Nick Kledzik + + * src/MachOWriterExecutable.hpp: dyld is allowed to have synthesized non-lazy pointers + ld64 is after processing bad GSYM stabs + * src/MachOReaderRelocatable.hpp: if a GSYM is found that does not match any data symbol, suppress it + +2006-03-23 Nick Kledzik + + * src/MachOWriterExecutable.hpp: in Writer::fixUpReferenceFinal() fix when x86::kPointer is for an + external relocation + +2006-03-23 Nick Kledzik + + * src/Options.cpp: change macosx-min-version to default to a per-architecture setting + add warning if -pagezero_size is not page aligned + * src/MachOWriterExecutable.hpp: properly handle external relocations for ppc64 with 4GB pagezero + * src/machochecker.cpp: sanity check relocation records + +----- Tagged ld64-48 + +2006-03-21 Nick Kledzik + + 64bit: passing function pointer to another function passes the wrong function address + * src/MachOReaderRelocatable.hpp: when processing a non-lazy pointer to a static function, don't accidentally + match it to a STAB symbol. + +2006-03-21 Nick Kledzik + + .eh symbols make up 13% of libstdc++'s stripped binary size + * src/ObjectFile.h: add ReaderOptions.fForFinalLinkedImage + * src/Options.cpp: setup ReaderOptions.fForFinalLinkedImage + * src/MachOReaderRelocatable.hpp: mark .eh symbols kSymbolTableNotIn when building final linked image + +2006-03-21 Nick Kledzik + + ld64 does not parse optional second argument to -filelist + * unit-tests/test-cases/filelist: added + * src/Options.cpp: in Options::loadFileList() handle comma option + + +----- Tagged ld64-47.1 + + +----- Tagged ld64-47 + + +----- Tagged ld64-46 + +2006-03-10 Nick Kledzik + + ld64 should figure out architecture from .o files + * unit-tests/test-cases/auto-arch: added + * src/ld.cpp: added Linker::inferArchitecture() to scan .o files are infer architecture to link + * src/MachOReaderArchive.hpp: enhanced validFile() to look deeper into archive and really valdate + * src/MachOWriterExecutable.hpp: stop using fOptions.architecture() + * src/Options.cpp: stop defaulting to ppc64 + + +2006-03-09 Nick Kledzik + + Need "intentionally left blank" dylib stubs + * unit-tests/include/common.makefile: add VALID_ARCHS + * unit-tests/run-all-unit-tests: set up VALID_ARCHS + * unit-tests/test-cases/blank-stubs: add test case + * src/ld.cpp: in addDylib(), detect and ignore blank stubs + * src/MachOReaderDylib.hpp: in constructor, handle blank stubs + +2006-03-09 Nick Kledzik + + crash in stub with 2GB pagezero + * src/MachOWriterExecutable.hpp: StubAtom can't be no-pic if a large zero-page is used + +2006-03-06 Nick Kledzik + + * src/Options.cpp: addSectionAlignment, warn if -sectalign alignment is not a power of two + +----- Tagged ld64-45 + + +2006-03-06 Nick Kledzik + + LP64/9A122: ld64: hang when trying to link DiscRecording framework + * src/Options.cpp: addSectionAlignment, warn on zero. Use log2() for alignment conversion + + +----- Tagged ld64-44 + +2006-03-04 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: fix again test for detection of anonymous non-lazy-pointer. + Error out if .o file contains old __DWARFA style dwarf. + +2006-03-02 Nick Kledzik + + * src/ld.cpp: only re-map page aligned sub-parts of a fat file. A conformat mmap() requires alignment. + +----- Tagged ld64-43 + + +2006-03-02 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: tighten detection of anonymous non-lazy-pointer + +----- Tagged ld64-42 + +2006-02-28 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: fix x86 __IMPORT permissions for class Segment + +2006-02-28 Nick Kledzik + + SWB: ld64-37 (can't resolve symbol ___dso_handle) + * src/MachOWriterExecutable.hpp: add class DsoHandleAtom + +2006-02-28 Nick Kledzik + + * unit-tests/test-cases/literals-coalesce-alignment: added test case + * src/ld.cpp: when coalescing strings pick one with greater alignment + ld64: CG link failed because lo14 reference to anonymous non-lazy-pointer not aligned + * unit-tests/test-cases/relocs-c/test.c: tweak to fail like 4458660 + * src/MachOReaderRelocatable.hpp: detect anonymous non-lazy-pointer and transform into real non-lazy-pointers + +----- Tagged ld64-41 + +2006-02-24 Nick Kledzik + + * src/Options.cpp: Warning about -no_dead_strip_inits_and_terms and -i options. + Fix -weak-l option. + +----- Tagged ld64-40 + +2006-02-24 Nick Kledzik + + Leopard9A113: ppc64 libstdc++.dylib initializer crashes in pthread_once + * unit-tests/test-cases/multiple-entry-points: added + * src/MachOReaderRelocatable.hpp: make sure that if there are multiple symbols with the same + address, that we properly make zero length atoms for all but last symbol + +2006-02-24 Nick Kledzik + + * src/Options.cpp: ld64 doesn't realpath(3) B&I tracing paths + +2006-02-24 Nick Kledzik + + * src/Options.cpp: 9A110: ld64 can't deal with section names >16 chars + +2006-02-23 Nick Kledzik + + * src/MachOWriterExecutable.hpp: use vector.reserve() to minimize re-allocations + * src/Options.cpp: use vector.reserve() to minimize re-allocations + * src/MachOReaderRelocatable.hpp: use vector.reserve() to minimize re-allocations + * src/MachOReaderDylib.hpp: use vector.reserve() to minimize re-allocations + * src/ld.cpp: use vector.reserve() to minimize re-allocations + +2006-02-23 Nick Kledzik + + ld64 creates corrupt executables (and has malloc errors) with -headerpad option + * src/MachOWriterExecutable.hpp: Change LoadCommandsPaddingAtom::setSize() to update fLargestAtomSize + * unit-tests/test-cases/header-pad: added + +2006-02-23 Nick Kledzik + + ld64 creates invalid static executables + * src/MachOWriterExecutable.hpp: Change MachHeaderAtom::copyRawContent() to create correct header + for static executables. Change SymbolTableLoadCommandsAtom to skip LC_DYSYMTAB for static executables + * src/machochecker.cpp: Add tests that static executables are well formed + * unit-tests/test-cases/static-executable: added + +2006-02-22 Nick Kledzik + + * src/Options.cpp: chnage printf on unknown arg to a throw + +----- Tagged ld64-39 + +2006-02-20 Nick Kledzik + + * unit-tests/test-cases/read-only-relocs: added new test case + * src/MachOWriterExecutable.hpp: detect and error on relocs in read-only sections + * src/MachOReaderRelocatable.hpp: fix parsing of i386 absolute addressing relocs + +2006-02-20 Nick Kledzik + + * unit-tests/test-cases/stabs-coalesce: added new test case + * src/ld.cpp.hpp: in collectStabs removed unused stabs + +----- Tagged ld64-38 + +2006-02-17 Nick Kledzik + + * src/MachOWriterExecutable.hpp: set correct n_sect field of stabs + +2006-02-15 Nick Kledzik + + * src/MachOReaderArchive.hpp: with -all_load skip over both kinds of SYMDEFs + * unit-tests/test-cases/archive-basic/Makefile: add -all_load test case + +----- Tagged ld64-37 + +2006-02-13 Eric Christopher + + * src/MachOWriterExecutable.hpp (assignFileOffsets): Simplify. Add comments. + Adjust whitespace. + +2006-02-13 Nick Kledzik + + * src/MachOWriterExecutable.hpp: in Writer::fixUpReferenceRelocatable() fix kPCRel32 for external case + +2006-02-13 Nick Kledzik + + * unit-tests/test-cases/zero-fill: added + * src/machochecker.cpp: check that S_ZEROFILL have no file offset + * src/MachOWriterExecutable.hpp: rework assignFileOffsets() to fix rdar://problem/4441145 + +2006-02-12 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: fix use of first zero-length c-string in .o file + +2006-02-12 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: fix uninitialized fAlignment + +2006-02-12 Nick Kledzik + + * unit-tests/test-cases/relocs-asm/relocs-asm.s: add pointer-diff cases + * src/Architectures.hpp: make size explicit in ppc/ppc64 kPointerDiff + * src/MachOReaderRelocatable.hpp: don't allow kPointerDiff64 for ppc (just ppc64) + * src/MachOWriterExecutable.cpp: set proper r_length for ld -r of kPointerDiff + +----- Tagged ld64-36 + +2006-02-08 Nick Kledzik + + * src/MachOReaderRelocatable.cpp: rdar://problem/4438677 Handle when a .o file dwarf line info entries but no functions + +2006-02-08 Nick Kledzik + + * src/MachOWriterExecutable.cpp: Properly set address of first TEXT section + Keep S_COALESCED attribute for __eh_frame + +2006-02-08 Nick Kledzik + + * src/ld.cpp: Temporarily turn allowable client errors into warnings + * unit-tests/test-cases/allowable-clientMakefile: Temporarily let warnings be ok for above + * src/MachOWriterExecutable.hpp: fix ld -r to not use external relocations for symbols make static + +2006-02-08 Nick Kledzik + + * src/ld.cpp: A sibling in an umbrella can always link with its other siblings + * unit-tests/test-cases/allowable-client: add test case for above + +2006-02-08 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: support LOCAL non-lazy pointers to hidden symbols + * src/machochecker.cpp: verify indirect symbol table + * unit-tests/test-cases/private-non-lazy: added test case + +2006-02-07 Nick Kledzik + + * src/MachOWriterExecutable.hpp: fix calculation of file offsets in ld -r mode + * src/machochecker.cpp: verify segment file offsets are within file + +----- Tagged ld64-35 + +2006-02-06 Nick Kledzik + + * ld.cpp: allow parent of sub-framework to link + * unit-tests/test-cases/allowable-client/Makefile: added cases for parent and clients of parent + +2006-02-04 Nick Kledzik + + * unit-tests/test-cases/relocs-c/test.c: added some array cases + * src/MachOReaderRelocatable.hpp: factor out makeReferenceToEH() + * src/MachOWriterExecutable.hpp: add initial support for non-lazy pointer synthesis + +----- Tagged ld64-34 + +2006-02-04 Nick Kledzik + + * src/ld.cpp: fix -no_arch_warnings + fix -undefined warning + Do BINCL/EINCL optimization for gfull stabs + Implement "essential symbols" for stabs (-Sp) + Fix allowable clients to only test on direct libraries + * src/MachOReaderRelocatable.hpp: support BINCL/EINCL stabs + +2006-02-03 Nick Kledzik + + * src/machochecker.cpp: add code to check load command alignment + * src/MachOWriterExecutable.hpp: make load command alignment depend on architecture + +2006-02-03 Nick Kledzik + + * unit-tests/test-cases/literals-coalesce: added + * src/MachOReaderRelocatable.hpp: assure all targets of low14 ppc relocs are at least 4-byte alignmented + +----- Tagged ld64-33 + +2006-02-02 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: properly coalesce 8-byte literals + * src/MachOWriterExecutable.hpp: support ppc64::kPointerDiff32 + +----- Tagged ld64-32 + +2006-02-02 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: support anonymous zero fill atoms + +2006-02-02 Nick Kledzik + + * src/ld.cpp: A weak definition is good enough, do not search archives for a non-weak one + * unit-tests/test-cases/archive-weak: add test case for above + * src/MachOReaderRelocatable.hpp: an atom should never have a by-name reference to itself + * src/Options.cpp: prevent .eh symbols from being exported via a -exported_symbols_list + +2006-02-01 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: Support -macosx_version_min 10.5 + +2006-02-01 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: don't try to parse debug_line dwarf if no symboled atoms + +----- Tagged ld64-31 + +2006-02-01 Eric Christopher + + * unit-tests/test-cases/allow-stack-execute/Makefile: Move otool handling... + * unit-tests/include/common.makefile: ... here. + * unit-tests/bin/fail-if-stdin.pl: New. + * unit-tests/test-cases/no-uuid: Ditto. + * src/ld.cpp (Linker::) Add fCreateUUID. + (::Linker): Initialize. + (::collectStabs): Use. Set if dwarf or we have a UUID already. + (::writeOutput): Pass as argument to Writer::write along with option. + * src/Options.h (Option::emitUUID): Declare. + (Option::fEmitUUID): Ditto. + * src/Options.cpp (Option::emitUUID): New. + (parse): Handle -no_uuid. + * src/MachOReaderRelocatable (Reader::Reader): Handle LC_UUID. + * src/ExecutableFile.h (Writer::Write): Add createUUID boolean. + * src/MachOWriterExecutable: Add UUID forward declaration. + (fUUIDAtom): New. + (UUIDLoadCommandAtom): Emit LC_UUID if fEmit. New function emit. Size + to zero at start. + (Writer::writer): Add handle for LC_UUID. If createUUID emit LC_UUID. + (MachHeaderAtom::copyRawContent): Don't count a load command if its size is + 0. + (UUIDLoadCommandAtom::copyRawContent): Depend on fEmit. + + +2006-01-31 Nick Kledzik + + * unit-tests/test-cases/dwarf-debug-notes : Added + * src/ld.cpp: don't generate debug note for .eh symbols + * src/MachOReaderRelocatable.hpp: make dwarf line info to atom matching faster and better + +2006-01-31 Nick Kledzik + + * ld64.xcodeproj/project.pbxproj : Make buildable on Leopard + * src/MachOFileAbstraction.hpp: make buildable without latest cctools headers + +2006-01-31 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: better error message for bad relocs + * src/ObjectDump.cpp: add emacs tab settings + * src/SectCreate.h: ditto + * src/SectCreate.cpp: ditto + * src/machochecker.cpp: ditto + * src/ExecutableFile.h: ditto + +2006-01-30 Eric Christopher + + * src/ExecutableFile.h: Indent. + +2006-01-30 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: performance improvements + * src/ld.cpp: now that stubs are synthesized in write, don't need to special case anymore + +2006-01-30 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: fix parsing of pcc relocs + * unit-tests/test-cases/relocs-asm/relocs-asm.s: add test case for above + +2006-01-29 Nick Kledzik + + * unit-tests/test-cases/weak_import: added test case + * src/ld.cpp: move code for weak_import mismatch to writer + * src/ObjectFile.h: remove ImportWeakness methods + * src/MachOReaderDylib.hpp: ditto + * src/SectCreate.cpp: ditto + * src/Architectures.hpp: add new ReferenceKinds for weak_imports + * src/MachOReaderRelocatable.hpp: implement new ReferenceKinds + * src/MachOWriterExecutable.hpp: handle new ReferenceKinds and weak_import mismatches + +2006-01-29 Nick Kledzik + + * src/Options.cpp: verify -allow_stack_execute is only used on main executables + +2006-01-29 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: sync with latest dwarf reader from Geoff + * src/debugline.c: sync with latest dwarf reader from Geoff + +2006-01-27 Eric Christopher + + * src/ld.cpp (Linker::syntesizeStabs): Correct spelling. Update all uses. + +2006-01-27 Eric Christopher + + * src/Options.h (Options): Add hasExecutableStack, fExecutableStack. + * src/Options.cpp (Options::hasExecutableStack): New. + (Options::parse): Parse -allow_stack_execute. + * src/MachOWriterExecutable.hpp (MachHeaderAtom::copyRawContent): + Implement MH_ALLOW_STACK_EXECUTION. + * unit-tests/include/common.makefile (FAIL_IF_EMPTY): New. + * unit-tests/bin/fail-if-no-stdin.pl: New file. + * unit-tests/test-cases/allow-stack-execute: New directory. + +2006-01-27 Nick Kledzik + + * src/MachOFileAbstraction.hpp: rely on latest system headers + * src/MachOWriterExecutable.hpp: fix ppc stubs. + wrote new relocationNeededInFinalLinkedImage() to replace common code + +2006-01-27 Eric Christopher + + * src/ld.cpp (logTraceInfo): New. + (Linker::addArchive): Use. + (Linker::addDylib): Ditto. + * src/ObjectFile (ReaderOptions::fTraceOutputFile): New. + * src/MachOReaderArchive.hpp (Reader::Reader): Move trace + logging to Linker::addArchive. + * src/Options.cpp (parsePreCommandLineEnvironment): Check + LD_PRINT_FILE if tracing dylibs or archives. + +2006-01-26 Nick Kledzik + + * src/MachOWriterExecutable.hpp: handle NULL strings in SO debug notes + +2006-01-26 Nick Kledzik + + * src/MachOWriterExecutable.hpp: fix header padding calculation and thread state + +2006-01-26 Nick Kledzik + + Rewrite all stabs processing. + Move sythesize of debug notes into ld.cpp + +2006-01-26 Nick Kledzik + + * src/MachOWriterExecutable.hpp: fix ppc and ppc64 stub relocs + +2006-01-25 Nick Kledzik + + * ld64.xcodeproj/project.pbxproj: special case building in Curry + +2006-01-25 Nick Kledzik + + * src/MachOWriterExecutable.hpp: fix bugs in stub/lazy-pointer synthesis + +2006-01-24 Eric Christopher + + * src/ld.cpp (Linker::createReaders): Change logging title to XBS. + (Linker::addDylib): Ditto. + * src/MachOReaderArchive.hpp (Reader::Reader): Ditto. + * src/Options.h (fPrintOptions): New. + * src/Options.cpp (Options::Options): Initialize above. + (Options::checkForFile): Change logging title to XBS. + (Options::findFramework): Ditto. + (Options::parse): Add log for options. + (Options::parsePreCommandLineEnvironmentSettings): Add LD_TRACE_ARCHIVES, + LD_TRACE_DYLIBS, and LD_PRINT_OPTIONS. + +2006-01-24 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: better C++ eh parsing + +2006-01-23 Eric Christopher + + * unit-tests/bin/fail-if-exit-zero.pl: New. + * unit-tests/include/common.makefile (FAIL_IF_SUCCESS): Use. + * unit-tests/allowable-client: New test. + * src/ld.cpp (Linker::addDylib): Check allowable clients before adding dylib. + * src/Options.h (allowableClients): New. + (clientName): Ditto. + (fAllowableClients): Ditto. + (fClientName): Ditto. + * src/Options.cpp: Implement above. + (parse): Handle -allowable_client and -client_name. + * src/MachOReaderDylib.hpp (getAllowableClients): New. + (fAllowableClients): Ditto. + (Reader): Process LC_SUB_CLIENT load command. + * src/ObjectFile.h (parentUmbrella): New. + (getAllowableClients): New. + * src/MachOWriterExecutable.hpp (AllowableClientLoadCommandsAtom): New. + +2006-01-23 Nick Kledzik + + * unit-tests/test-cases/archive-basic: added + * src/ld.cpp: fix shadowed local variable + * src/FileAbstraction.hpp: ld64 shouldn't inline when building debug + +2006-01-23 Nick Kledzik + + * src/ld.cpp: fix symbol not found error message + * src/MachOReaderDylib.hpp: add logging to hash table + * src/MachOReaderRelocatable.hpp: enable stabs processing. Handle static functions with stubs + handle labeled cstrings. + * src/MachOWriterExecutable.hpp: properly suppress atoms not in symbol table. fix low14 error check. + add StubAtomHelper. + * unit-tests/test-cases/relocs-literals/test.c: add more interesting edge cases + +2006-01-17 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: tweaks to synthesizing debug notes + +2006-01-16 Nick Kledzik + + * src/debugline.{sh}: added + * src/MachOReaderRelocatable.hpp: synthesize debug notes SOL from dwarf + * src/MachOWriterExecutable.hpp: fix lazy pointer section + * src/ObjectDump.hpp: Fix conditionalization + * unit-tests/test-cases/dwarf-strip: added + +2006-01-11 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: support Tiger crt1.o build with old ld64 + * src/ObjectDump.hpp: Support -arch option + +2006-01-10 Nick Kledzik + + * src/MachOWriterExecutable.hpp: fix stubs for ppc64 + * src/MachOFileAbstraction.hpp: fix typo for macho_routines + * ld64.xcodeproj/project.pbxproj: add machochecker target + * src/machochecker.cpp: new skeleton for checking mach-o file bit + * unit-tests/: Add support for running machochecker + +2006-01-10 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: warn if dwarf can't be parsed + * src/MachOReaderArchive.hpp: modTime for OSO stabs from archives is .a modTime + +2006-01-09 Nick Kledzik + + * track modification time of .o files so that sythesized OSO stab will have it + +2006-01-09 Nick Kledzik + + * src/MachOFileAbstraction.hpp: add macho_uuid_command + * src/MachOWriterExecutable.cpp: add UUID load command to generated files + +2006-01-09 Nick Kledzik + + * src/MachOReaderDylib.hpp: no longer keep dylib memory mapped + * src/ld.cpp: don't track dylib sizes because they are not longer memory mapped + +2006-01-05 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: support new relocations + +2006-01-05 Nick Kledzik + + * src/MachOReaderDylib.hpp: support MH_DYLIB_STUB + * src/MachOReaderRelocatable.hpp: Add Geoff's comp unit extractor + +2006-01-05 Nick Kledzik + + refactor: transform Atom::dontStripName() to getSymbolTableInclusion() + * src/ld.cpp: pass dyld_stub_binding_helper to writer + * src/MachOReaderRelocatable.hpp: update synthesized stabs + Ignore stubs and lazy pointers in .o files + Support initializers and terminators + * src/MachOWriterExecutable.hpp: synthesize stubs and lazy pointers as needed + * ld64.xcodeproj/project.pbxproj: change Release target to build with dwarf + +2006-01-03 Eric Christopher + + * src/Options.h (multipleDefinitionsInDylibs): Declare. + (overridingDefinitionInDependentDylib): Ditto. + (warnOnMultipleDefinitionsInObjectFiles): Ditto. + (multiplyDefined): Remove. + (multiplyDefinedUnused): Ditto. + (fMultiplyDefined): Ditto. + (fWarnOnMultiplyDefined): New. + (fMultiplyDefinedDynamic): Ditto. + * src/Options.cpp (Options::Options): Initialize above. + (overridingDefinitionInDependentDylib): New. + (multipleDefinitionsInDylibs): Ditto. + (warnOnMultipleDefinitionsInObjectFiles): Ditto. + (parse): Update comments. Fix parsing of -y option. + Update error message for -dead_strip. Parse above + options. + +2006-01-02 Nick Kledzik + + * Refactor: move Atom::writeContent() to Writer + +2005-12-23 Nick Kledzik + + * Reworked, simplify, and document test harness + * unit-tests/README: Added + +2005-12-23 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: fixes for Objective-C + * unit-tests/test-cases/relocs-objc: Added + +2005-12-22 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: fix check that next reloc is pair + * src/MachOReaderRelocatable.hpp: Add code to synthesize essential stabs from dwarf + +2005-12-21 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: Fix parsing of literal sections + * src/MachOWriterExecutable.hpp: Fix writing of literal sections + * unit-tests/test-cases/relocs-literals: Added + +2005-12-15 Eric Christopher + + * src/Options.h (enum Treatment): New. + (enum PICTreatment): Delete. + (enum VersionMin): New. + (prebind): Declare. + (macosxVersionMin): Ditto. + (multiplyDefined): Ditto. + (multiplyDefinedUnused): Ditto. + (setVersionMin): Ditto. + (setPICTreatment): Delete. + (setReadOnlyRelocTreatment): Ditto. + (picTreatment): Adjust return type. + (parseTreatment): New. + (fPrebind): Ditto. + (fVersionMin): Ditto. + (fPICTreatment): Change type. + (fMultiplyDefined): New. + (fMultiplyDefinedUnused): Ditto. + (fLimitUndefinedSymbols): Ditto. + + * src/Options.cpp: Fix whitespace. Add comments on options. + (Options::Options): Add initializers for new variables. + (Options::prebind): New. + (Options::macosxVersionMin): Ditto. + (Options::parseTreatment): Ditto. + (Options::setVersionMin): Ditto. + (Options::setReadOnlyRelocTreatment): Delete. + (Options::setPICTreatment): Ditto. + (Options::Parse): Update for above. Add comments. + +2005-12-15 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: Add comments about dwarf + +2005-12-14 Nick Kledzik + + * src/ELFFileAbstraction.hpp: Added + * src/ELFReaderRelocatable.hpp: Added + * Lot of fixes for new architecture + * Added __OPEN_SOURCE__ to "Preprocessor Macros" to disable new architecture support by default + +2005-12-13 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: check for S_ATTR_DEBUG and ignore those sections + * unit-tests/test-cases/dwarf-ignore: added + +2005-12-12 Nick Kledzik + + * Added test harness and three initial tests: + relocs-asm, relocs-c, and hello-world + +2005-12-12 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: Massive refactoring: + Now there are three Atom classes, Chopping into Atoms + is done on label boundaries or by knowledge of special + sections, Share lots of ppc/ppc64 code. + Stabs process code is temporarily disabled. + +2005-12-12 Nick Kledzik + + * src/ObjectDump.cpp: Add command line options: -no_content, -stabs, -no_sort + +2005-12-11 Eric Christopher + + * src/Options.cpp: Reformat. + * src/Options.h: Ditto. + +2005-12-07 Eric Christopher + + * src/MachOReaderRelocatable.hpp (Atom::getAlignment): + When calculating alignment of an Atom, take into account + the alignment from which we pulled the Atom. + +2005-12-06 Nick Kledzik + + * src/Options.cpp src/Options.h: Add design comments + +2005-12-05 Eric Christopher + + * src/ld.cpp (Linker::createWriter): Uncomment ppc64 and + i386 linkers. + +2005-12-05 Eric Christopher + + * ChangeLog: New file. + +2005-12-02 Nick Kledzik + + * src/ObjectFile.h: Add design comments + +2005-11-30 Nick Kledzik + + * Fix uses of __OPEN_SOURCE__ + +2005-11-28 Nick Kledzik + + * Refactor Atom to use getDefinitionKind() + +2005-11-21 Nick Kledzik + + * src/MachOWriterExecutable.hpp: don't generate section for commons in -r mode + +2005-11-18 Nick Kledzik + + * x86 tweaks + +2005-11-18 Nick Kledzik + + * src/ObjectDump.cpp: make work with command line arguments + +2005-11-18 Nick Kledzik + + * Massive rework to remove preprocessor conditionals and use templates + +2005-11-14 Nick Kledzik + + * Created new Subversion repository for ld64 from cvs tag ld64-27.2 diff --git a/ld64.xcodeproj/project.pbxproj b/ld64.xcodeproj/project.pbxproj index fd0213c..55fd5ea 100644 --- a/ld64.xcodeproj/project.pbxproj +++ b/ld64.xcodeproj/project.pbxproj @@ -726,7 +726,6 @@ F933D91D09291AC90083EAC8 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = x86_64; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -951,12 +950,23 @@ ALWAYS_SEARCH_USER_PATHS = NO; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_MISSING_PARENTHESES = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; + GCC_WARN_UNUSED_LABEL = NO; + GCC_WARN_UNUSED_VALUE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; INSTALL_PATH = /usr/local/bin; PREBINDING = NO; PRODUCT_NAME = dyldinfo; + WARNING_CFLAGS = "-Wall"; }; name = Debug; }; diff --git a/src/abstraction/MachOFileAbstraction.hpp b/src/abstraction/MachOFileAbstraction.hpp index 330a8cb..50982a1 100644 --- a/src/abstraction/MachOFileAbstraction.hpp +++ b/src/abstraction/MachOFileAbstraction.hpp @@ -471,7 +471,7 @@ public: void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); } const uint8_t* uuid() const INLINE { return fields.uuid; } - void set_uuid(uint8_t uuid[16]) INLINE { memcpy(&fields.uuid, uuid, 16); } + void set_uuid(uint8_t u[16]) INLINE { memcpy(&fields.uuid, u, 16); } typedef typename P::E E; private: diff --git a/src/ld/Architectures.hpp b/src/ld/Architectures.hpp index 0d141cf..2a449f1 100644 --- a/src/ld/Architectures.hpp +++ b/src/ld/Architectures.hpp @@ -61,7 +61,7 @@ struct x86 enum ReferenceKinds { kNoFixUp, kFollowOn, kGroupSubordinate, kPointer, kPointerWeakImport, kPointerDiff, kPointerDiff32=kPointerDiff, kPointerDiff16, kPCRel32, kPCRel32WeakImport, kAbsolute32, kPCRel16, kPCRel8, - kImageOffset32, kPointerDiff24, + kImageOffset32, kPointerDiff24, kSectionOffset24, kDtraceProbe, kDtraceProbeSite, kDtraceIsEnabledSite, kDtraceTypeReference }; }; @@ -74,7 +74,7 @@ struct x86_64 kBranchPCRel32, kBranchPCRel32WeakImport, kPCRel32GOTLoad, kPCRel32GOTLoadWeakImport, kPCRel32GOT, kPCRel32GOTWeakImport, kBranchPCRel8, kGOTNoFixUp, - kImageOffset32, kPointerDiff24, + kImageOffset32, kPointerDiff24, kSectionOffset24, kDtraceProbe, kDtraceProbeSite, kDtraceIsEnabledSite, kDtraceTypeReference }; }; @@ -82,7 +82,8 @@ struct arm { typedef Pointer32 P; - enum ReferenceKinds { kNoFixUp, kFollowOn, kGroupSubordinate, kPointer, kPointerWeakImport, kPointerDiff, kPointerDiff32=kPointerDiff, kReadOnlyPointer, + enum ReferenceKinds { kNoFixUp, kFollowOn, kGroupSubordinate, kPointer, kPointerWeakImport, kPointerDiff, + kPointerDiff32=kPointerDiff, kReadOnlyPointer, kPointerDiff12, kBranch24, kBranch24WeakImport, kThumbBranch22, kThumbBranch22WeakImport, kDtraceProbe, kDtraceProbeSite, kDtraceIsEnabledSite, kDtraceTypeReference }; }; diff --git a/src/ld/ExecutableFile.h b/src/ld/ExecutableFile.h index 675d3da..dca22f7 100644 --- a/src/ld/ExecutableFile.h +++ b/src/ld/ExecutableFile.h @@ -1,6 +1,6 @@ /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- * - * Copyright (c) 2005-2007 Apple Inc. All rights reserved. + * Copyright (c) 2005-2009 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -51,15 +51,18 @@ namespace ExecutableFile { virtual ObjectFile::Atom& makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, bool objcReplacementClasses) = 0; virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name) = 0; + virtual void addSynthesizedAtoms(const std::vector& existingAtoms, + class ObjectFile::Atom* dyldClassicHelperAtom, + class ObjectFile::Atom* dyldCompressedHelperAtom, + class ObjectFile::Atom* dyldLazyDylibHelperAtom, + bool biggerThanTwoGigs, + uint32_t dylibSymbolCount, + std::vector& newAtoms) = 0; virtual uint64_t write(std::vector& atoms, std::vector& stabs, class ObjectFile::Atom* entryPointAtom, - class ObjectFile::Atom* dyldClassicHelperAtom, - class ObjectFile::Atom* dyldCompressedHelperAtom, - class ObjectFile::Atom* dyldLazyDylibHelperAtom, bool createUUID, bool canScatter, ObjectFile::Reader::CpuConstraint cpuConstraint, - bool biggerThanTwoGigs, std::set& atomsThatOverrideWeak, bool hasExternalWeakDefinitions) = 0; diff --git a/src/ld/LTOReader.hpp b/src/ld/LTOReader.hpp index 75659e1..0bd200e 100644 --- a/src/ld/LTOReader.hpp +++ b/src/ld/LTOReader.hpp @@ -1,6 +1,6 @@ /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- * - * Copyright (c) 2006-2008 Apple Inc. All rights reserved. + * Copyright (c) 2006-2009 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -406,7 +406,7 @@ const char* Reader::tripletPrefixForArch(cpu_type_t arch) case CPU_TYPE_X86_64: return "x86_64-"; case CPU_TYPE_ARM: - return "arm-"; + return "arm"; } return ""; } @@ -522,14 +522,6 @@ bool Reader::optimize(const std::vector& allAtoms, std::vect warning("could not produce merged bitcode file"); } - // if requested, save off merged bitcode file - if ( saveTemps ) { - char tempBitcodePath[MAXPATHLEN]; - strcpy(tempBitcodePath, outputFilePath); - strcat(tempBitcodePath, ".lto.bc"); - ::lto_codegen_write_merged_modules(generator, tempBitcodePath); - } - // set code-gen model lto_codegen_model model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; switch ( outputKind ) { @@ -551,12 +543,38 @@ bool Reader::optimize(const std::vector& allAtoms, std::vect model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; break; case Options::kStaticExecutable: - model = LTO_CODEGEN_PIC_MODEL_STATIC; + // darwin x86_64 "static" code model is really dynamic code model + if ( fArchitecture == CPU_TYPE_X86_64 ) + model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; + else + model = LTO_CODEGEN_PIC_MODEL_STATIC; break; } if ( ::lto_codegen_set_pic_model(generator, model) ) throwf("could not create set codegen model: %s", lto_get_error_message()); + // if requested, save off merged bitcode file + if ( saveTemps ) { + char tempBitcodePath[MAXPATHLEN]; + strcpy(tempBitcodePath, outputFilePath); + strcat(tempBitcodePath, ".lto.bc"); + ::lto_codegen_write_merged_modules(generator, tempBitcodePath); + } + +#if LTO_API_VERSION >= 3 + // find assembler next to linker + char path[PATH_MAX]; + uint32_t bufSize = PATH_MAX; + if ( _NSGetExecutablePath(path, &bufSize) != -1 ) { + char* lastSlash = strrchr(path, '/'); + if ( lastSlash != NULL ) { + strcpy(lastSlash+1, "as"); + struct stat statInfo; + if ( stat(path, &statInfo) == 0 ) + ::lto_codegen_set_assembler_path(generator, path); + } + } +#endif // run code generator size_t machOFileLen; const uint8_t* machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen); @@ -573,7 +591,12 @@ bool Reader::optimize(const std::vector& allAtoms, std::vect ::write(fd, machOFile, machOFileLen); ::close(fd); } - } + // save off merged bitcode file + char tempOptBitcodePath[MAXPATHLEN]; + strcpy(tempOptBitcodePath, outputFilePath); + strcat(tempOptBitcodePath, ".lto.opt.bc"); + ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath); + } // parse generated mach-o file into a MachOReader ObjectFile::Reader* machoReader = this->makeMachOReader(machOFile, machOFileLen, nextInputOrdinal); @@ -685,9 +708,9 @@ ObjectFile::Reader* Reader::makeMachOReader(const uint8_t* p, size_t len, uint32 }; // namespace lto -extern void printLTOVersion(Options &opts); +extern void printLTOVersion(Options& opts); -void printLTOVersion(Options &opts) { +void printLTOVersion(Options& opts) { const char* vers = lto_get_version(); if ( vers != NULL ) fprintf(stderr, "%s\n", vers); diff --git a/src/ld/MachOReaderDylib.hpp b/src/ld/MachOReaderDylib.hpp index 13faf3d..8aea6ef 100644 --- a/src/ld/MachOReaderDylib.hpp +++ b/src/ld/MachOReaderDylib.hpp @@ -780,13 +780,18 @@ void Reader::processIndirectLibraries(DylibHander* handler) //fprintf(stderr, "processIndirectLibraries() implicitly linking %s\n", child->getInstallPath()); ((Reader*)child)->setImplicitlyLinked(); } - else + else if ( child->explicitlyLinked() || child->implicitlyLinked() ) { + //fprintf(stderr, "processIndirectLibraries() parent is not directly linked, but child is, so no need to re-export child\n"); + } + else { fReExportedChildren.push_back(child); + //fprintf(stderr, "processIndirectLibraries() parent is not directly linked, so parent=%s will re-export child=%s\n", this->getInstallPath(), it->path); + } } else { // add all child's symbols to me fReExportedChildren.push_back(child); - //fprintf(stderr, "processIndirectLibraries() parent=%s will re-export child=%s\n", this->getInstallPath(), it->path); + //fprintf(stderr, "processIndirectLibraries() child is not public, so parent=%s will re-export child=%s\n", this->getInstallPath(), it->path); } } else if ( !fExplictReExportFound ) { diff --git a/src/ld/MachOReaderRelocatable.hpp b/src/ld/MachOReaderRelocatable.hpp index ef8cfb2..e6a182c 100644 --- a/src/ld/MachOReaderRelocatable.hpp +++ b/src/ld/MachOReaderRelocatable.hpp @@ -296,6 +296,7 @@ public: virtual ObjectFile::UnwindInfo::iterator beginUnwind() { return fHasCompactUnwindInfo ? &fSingleUnwindInfo[0] : NULL; } virtual ObjectFile::UnwindInfo::iterator endUnwind() { return fHasCompactUnwindInfo ? &fSingleUnwindInfo[1] : NULL; } virtual ObjectFile::Reference* getLSDA(); + virtual ObjectFile::Reference* getFDE(); virtual Atom* getPersonalityPointer(); virtual void setCompactUnwindEncoding(uint64_t ehAtomAddress); @@ -320,6 +321,19 @@ ObjectFile::Reference* BaseAtom::getLSDA() return NULL; } +ObjectFile::Reference* BaseAtom::getFDE() +{ + const uint8_t groupKind = this->getLSDAReferenceKind(); + const std::vector& refs = this->getReferences(); + for (std::vector::const_iterator it=refs.begin(); it != refs.end(); it++) { + ObjectFile::Reference* ref = *it; + if ( (ref->getKind() == groupKind) && (ref->getTarget().getContentType() == ObjectFile::Atom::kCFIType) ) { + return ref; + } + } + return NULL; +} + ObjectFile::Atom* BaseAtom::getPersonalityPointer() { const uint8_t personalityKind = this->getPersonalityReferenceKind(); @@ -593,6 +607,7 @@ SymbolAtom::SymbolAtom(Reader& owner, const macho_nlist

* symbol, const fAlignment.modulus = 0; } + template bool SymbolAtom::dontDeadStrip() const { @@ -923,7 +938,7 @@ public: virtual void setSize(uint64_t size) { fSize = size; } virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference*)ref); } virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); } - virtual void addLineInfo(const ObjectFile::LineInfo& info) { warning("can't add line info to anonymous symbol %s from %s", this->getDisplayName(), this->getFile()->getPath()); } + virtual void addLineInfo(const ObjectFile::LineInfo& info); virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; } virtual uint64_t getObjectAddress() const { return fAddress; } virtual const void* getSectionRecord() const { return (const void*)fSection; } @@ -1043,11 +1058,38 @@ AnonymousAtom::AnonymousAtom(Reader& owner, const macho_section

* sectio if ( !fOwner.fOptions.fNoEHLabels ) fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn; } + else if ( section == owner.fUTF16Section ) { + if ( fOwner.fOptions.fForFinalLinkedImage ) { + fDontDeadStrip = false; + fScope = ObjectFile::Atom::scopeLinkageUnit; + fKind = ObjectFile::Atom::kWeakDefinition; + char* name = new char[16+5*size]; + strcpy(name, "utf16-string="); + char* s = &name[13]; + const uint16_t* words = (uint16_t*)((char*)(owner.fHeader) + section->offset() + addr - section->addr()); + unsigned int wordCount = size/2; + // note, the compiler sometimes puts trailing zeros on the end of the data + if ( E::get32(words[wordCount-1]) == 0 ) + --wordCount; + bool needSeperator = false; + for(unsigned int i=0; i < wordCount; ++i) { + if ( needSeperator ) + strcpy(s++, "."); + sprintf(s, "%04X", E::get32(words[i])); + s += 4; + needSeperator = true; + } + fSynthesizedName = name; + } + else { + asprintf((char**)&fSynthesizedName, "lutf16-0x%X", addr); + } + } break; case S_CSTRING_LITERALS: { const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr(); - if ( strcmp(fSection->sectname(), "__cstring") == 0 ) + if ( (strcmp(fSection->sectname(), "__cstring") == 0) && (strcmp(section->segname(), "__TEXT") == 0) ) asprintf((char**)&fSynthesizedName, "cstring=%s", str); else asprintf((char**)&fSynthesizedName, "cstring%s%s=%s", fSection->segname(), fSection->sectname(), str); @@ -1135,6 +1177,16 @@ AnonymousAtom::AnonymousAtom(Reader& owner, const macho_section

* sectio case S_LAZY_SYMBOL_POINTERS: case S_NON_LAZY_SYMBOL_POINTERS: { + // transform i386 __IMPORT/__pointers to __DATA/__nl_symbol_ptr when + // generating the new compressed LINKEDIT format + if ( (type == S_NON_LAZY_SYMBOL_POINTERS) && fOwner.fOptions.fMakeCompressedDyldInfo && (strcmp(fSection->segname(),"__IMPORT") == 0) ) { + macho_section

* dummySection = new macho_section

(*fSection); + dummySection->set_segname("__DATA"); + dummySection->set_sectname("__nl_symbol_ptr"); + fSection = dummySection; + fSegment = new Segment(fSection); + } + fDontDeadStrip = false; fScope = ObjectFile::Atom::scopeLinkageUnit; uint32_t index = (fAddress - fSection->addr()) / sizeof(pint_t); @@ -1159,6 +1211,7 @@ AnonymousAtom::AnonymousAtom(Reader& owner, const macho_section

* sectio // add direct reference to target later, because its atom may not be constructed yet fOwner.fLocalNonLazys.push_back(this); fScope = ObjectFile::Atom::scopeTranslationUnit; + fType = ObjectFile::Atom::kNonLazyPointer; return; } else if ( (sym->n_value() < nonLazyPtrValue) && ((closestSym == NULL) || (sym->n_value() > closestSym->n_value())) ) { @@ -1178,31 +1231,26 @@ AnonymousAtom::AnonymousAtom(Reader& owner, const macho_section

* sectio } fScope = ObjectFile::Atom::scopeTranslationUnit; fOwner.fLocalNonLazys.push_back(this); + fType = ObjectFile::Atom::kNonLazyPointer; return; } const macho_nlist

* targetSymbol = &fOwner.fSymbols[symbolIndex]; const char* name = &fOwner.fStrings[targetSymbol->n_strx()]; char* str = new char[strlen(name)+16]; strcpy(str, name); - if ( type == S_LAZY_SYMBOL_POINTERS ) + if ( type == S_LAZY_SYMBOL_POINTERS ) { strcat(str, "$lazy_ptr"); - else + fType = ObjectFile::Atom::kLazyPointer; + } + else { strcat(str, "$non_lazy_ptr"); + fType = ObjectFile::Atom::kNonLazyPointer; + } fSynthesizedName = str; - // transform i386 __IMPORT/__pointers to __DATA/__nl_symbol_ptr when - // generating the new compressed LINKEDIT format - if ( fOwner.fOptions.fMakeCompressedDyldInfo && (strcmp(fSection->segname(),"__IMPORT") == 0) ) { - macho_section

* dummySection = new macho_section

(*fSection); - dummySection->set_segname("__DATA"); - dummySection->set_sectname("__nl_symbol_ptr"); - fSection = dummySection; - fSegment = new Segment(fSection); - } - if ( type == S_NON_LAZY_SYMBOL_POINTERS ) fKind = ObjectFile::Atom::kWeakDefinition; - + if ( (targetSymbol->n_type() & N_EXT) == 0 ) { // target is translation unit scoped, so add direct reference to target //fOwner.makeReference(A::kPointer, addr, targetSymbol->n_value()); @@ -1217,7 +1265,7 @@ AnonymousAtom::AnonymousAtom(Reader& owner, const macho_section

* sectio } break; default: - throwf("section type %d not supported with address=0x%08X", type, addr); + throwf("section type %d not supported with address=0x%08llX", type, (uint64_t)addr); } //fprintf(stderr, "AnonymousAtom(%p) %s \n", this, this->getDisplayName()); } @@ -1226,6 +1274,13 @@ AnonymousAtom::AnonymousAtom(Reader& owner, const macho_section

* sectio template <> bool AnonymousAtom::cstringsHaveLabels() { return true; } template bool AnonymousAtom::cstringsHaveLabels() { return false; } +template +void AnonymousAtom::addLineInfo(const ObjectFile::LineInfo& info) +{ + // don't warn if line table has entries for stubs + if ( (fSection->flags() & SECTION_TYPE) != S_SYMBOL_STUBS ) + warning("can't add line info to anonymous symbol %s from %s", this->getDisplayName(), this->getFile()->getPath()); +} template void AnonymousAtom::resolveName() @@ -1273,6 +1328,9 @@ void AnonymousAtom::resolveName() if ( (superStr != NULL) && (strncmp(superStr, "cstring=", 8) == 0) ) { asprintf((char**)&fSynthesizedName, "cfstring=%s", &superStr[8]); } + else if ( (superStr != NULL) && (strncmp(superStr, "utf16-string=", 13) == 0) ) { + asprintf((char**)&fSynthesizedName, "cfstring-utf16=%s", &superStr[13]); + } else { // compiled with -fwritable-strings or a non-ASCII string fKind = ObjectFile::Atom::kRegularDefinition; // these are not coalescable @@ -1610,11 +1668,13 @@ public: private: const void* mappedAddress(pint_t addr, pint_t* relocTarget=NULL); pint_t relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount); + void buildRelocatedMap(const macho_section

* sect, std::map& map); Reader& fReader; const uint8_t* fMappingStart; const macho_section

* fSectionsStart; const macho_section

* fSectionsEnd; + std::map fEHFrameOffsetToTargetMap; }; @@ -1634,26 +1694,43 @@ const void* ObjectFileAddressSpace::mappedAddress(pint_t addr, pint_t* relocT fMappingStart = (uint8_t*)fReader.fHeader; fSectionsStart = (macho_section

*)((char*)fReader.fSegment + sizeof(macho_segment_command

)); fSectionsEnd = &fSectionsStart[fReader.fSegment->nsects()]; + // find __eh_frame section and build map of relocations for performance + buildRelocatedMap(fReader.fehFrameSection, fEHFrameOffsetToTargetMap); + } + // special case lookups in __eh_frame section to be fast + const macho_section

* ehSect = fReader.fehFrameSection; + if ( (ehSect->addr() <= addr) && (addr < (ehSect->addr()+ehSect->size())) ) { + pint_t offsetOfAddrInSection = addr - ehSect->addr(); + if ( relocTarget != NULL ) { + std::map::iterator pos = fEHFrameOffsetToTargetMap.find(offsetOfAddrInSection); + if ( pos != fEHFrameOffsetToTargetMap.end() ) + *relocTarget = pos->second; + else + *relocTarget = 0; + } + return fMappingStart + ehSect->offset() + offsetOfAddrInSection; } - for (const macho_section

* sect=fSectionsStart; sect < fSectionsEnd; ++sect) { - if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) ) { - pint_t offsetOfAddrInSection = addr - sect->addr(); - if ( (sect->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) { - const uint32_t indirectTableOffset = sect->reserved1(); - const uint32_t sectionIndex = offsetOfAddrInSection/sizeof(pint_t); - const uint32_t symbolIndex = A::P::E::get32(fReader.fIndirectTable[indirectTableOffset+sectionIndex]); - // return pointer to symbol name which this non-lazy-pointer will point to - if ( relocTarget != NULL ) - *relocTarget = (uintptr_t)&fReader.fStrings[fReader.fSymbols[symbolIndex].n_strx()]; - } - else { - if ( relocTarget != NULL ) - *relocTarget = relocated(offsetOfAddrInSection, sect->reloff(), sect->nreloc()); + else { + for (const macho_section

* sect=fSectionsStart; sect < fSectionsEnd; ++sect) { + if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) ) { + pint_t offsetOfAddrInSection = addr - sect->addr(); + if ( (sect->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) { + const uint32_t indirectTableOffset = sect->reserved1(); + const uint32_t sectionIndex = offsetOfAddrInSection/sizeof(pint_t); + const uint32_t symbolIndex = A::P::E::get32(fReader.fIndirectTable[indirectTableOffset+sectionIndex]); + // return pointer to symbol name which this non-lazy-pointer will point to + if ( relocTarget != NULL ) + *relocTarget = (uintptr_t)&fReader.fStrings[fReader.fSymbols[symbolIndex].n_strx()]; + } + else { + if ( relocTarget != NULL ) + *relocTarget = relocated(offsetOfAddrInSection, sect->reloff(), sect->nreloc()); + } + return fMappingStart + sect->offset() + offsetOfAddrInSection; } - return fMappingStart + sect->offset() + offsetOfAddrInSection; } + throwf("ObjectFileAddressSpace::mappedAddress(0x%0lX) not in any section", (long)addr); } - throwf("ObjectFileAddressSpace::mappedAddress(0x%0lX) not in any section", (long)addr); } @@ -1811,6 +1888,7 @@ private: ObjectFile::Reader::DebugInfoKind fDebugInfo; bool fHasUUID; const macho_section

* fehFrameSection; + const macho_section

* fUTF16Section; std::set fLSDAAtoms; const macho_section

* fDwarfDebugInfoSect; const macho_section

* fDwarfDebugAbbrevSect; @@ -1838,7 +1916,7 @@ template Reader::Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options, uint32_t ordinalBase) : fPath(strdup(path)), fModTime(modTime), fOrdinalBase(ordinalBase), fOptions(options), fHeader((const macho_header

*)fileContent), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL), - fDebugInfo(kDebugInfoNone), fHasUUID(false), fehFrameSection(NULL), + fDebugInfo(kDebugInfoNone), fHasUUID(false), fehFrameSection(NULL), fUTF16Section(NULL), fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL), fDwarfDebugLineSect(NULL), fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL), fAppleObjc(false), fHasDTraceProbes(false), fHaveIndirectSymbols(false), fReplacementClasses(false), fHasLongBranchStubs(false), @@ -1916,8 +1994,12 @@ Reader::Reader(const uint8_t* fileContent, const char* path, time_t modTime, for (const macho_section

* sect=fSectionsStart; sect < fSectionsEnd; ++sect) { if ( (strcmp(sect->sectname(), "__eh_frame") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) ) { fehFrameSection = sect; - if ( libunwind::CFI_Parser >::getCFIs(fObjectAddressSpace, sect->addr(), sect->size(), - fCIEInfos, fFDEInfos) ) { + const char* msg = libunwind::CFI_Parser >::getCFIs(fObjectAddressSpace, sect->addr(), + sect->size(), fFDEInfos, fCIEInfos); + if ( msg != NULL ) { + throwf("malformed __eh_frame section: %s", msg); + } + else { //fprintf(stderr, "%lu CIEs, %lu FDEs\n", fCIEInfos.size(), fFDEInfos.size()); // add anonymous atoms for each CIE for (typename std::vector::const_iterator it = fCIEInfos.begin(); it != fCIEInfos.end(); ++it) { @@ -1939,8 +2021,29 @@ Reader::Reader(const uint8_t* fileContent, const char* path, time_t modTime, } } } - else { - throw "malformed __eh_frame section"; + } + else if ( (strcmp(sect->sectname(), "__ustring") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) ) { + // if there is a __ustring section parse it into AnonymousAtoms based on labels + fUTF16Section = sect; + std::vector utf16Addreses; + for (int i=fSymbolCount-1; i >= 0 ; --i) { + const macho_nlist

& sym = fSymbols[i]; + if ( (sym.n_type() & N_STAB) == 0 ) { + uint8_t type = (sym.n_type() & N_TYPE); + if ( type == N_SECT ) { + if ( &fSectionsStart[sym.n_sect()-1] == fUTF16Section ) { + utf16Addreses.push_back(sym.n_value()); + } + } + } + } + utf16Addreses.push_back(fUTF16Section->addr()+fUTF16Section->size()); + std::sort(utf16Addreses.begin(), utf16Addreses.end()); + for(int i=utf16Addreses.size()-2; i >=0 ; --i) { + pint_t size = utf16Addreses[i+1] - utf16Addreses[i]; + AnonymousAtom* strAtom = new AnonymousAtom(*this, fUTF16Section, utf16Addreses[i], size); + fAtoms.push_back(strAtom); + fAddrToAtom[utf16Addreses[i]] = strAtom; } } } @@ -1972,6 +2075,9 @@ Reader::Reader(const uint8_t* fileContent, const char* path, time_t modTime, else if ( section == fehFrameSection ) { // ignore labels in __eh_frame section } + else if ( section == fUTF16Section ) { + // ignore labels in __ustring section + } else { // ignore labels for atoms in other sections switch ( section->flags() & SECTION_TYPE ) { @@ -2825,6 +2931,44 @@ ObjectFile::Atom* Reader::getFunctionAtomFromLSDAAddress(pint_t addr) } +template <> +void ObjectFileAddressSpace::buildRelocatedMap(const macho_section

* sect, std::map& map) +{ + // mach-o x86_64 is different, the content of a section with a relocation is the addend + const macho_relocation_info

* relocs = (macho_relocation_info

*)((char*)(fReader.fHeader) + sect->reloff()); + const macho_relocation_info

* relocsEnd = &relocs[sect->nreloc()]; + for (const macho_relocation_info

* reloc = relocs; reloc < relocsEnd; ++reloc) { + std::map::iterator pos; + switch ( reloc->r_type() ) { + case X86_64_RELOC_UNSIGNED: + pos = map.find(reloc->r_address()); + if ( pos != map.end() ) + pos->second += fReader.fSymbols[reloc->r_symbolnum()].n_value(); + else + map[reloc->r_address()] = fReader.fSymbols[reloc->r_symbolnum()].n_value(); + break; + case X86_64_RELOC_SUBTRACTOR: + map[reloc->r_address()] = -fReader.fSymbols[reloc->r_symbolnum()].n_value(); + break; + case X86_64_RELOC_GOT: + // there is no good address to return here. + // GOT slots are synthsized by the linker + // this is used for the reference to the personality function in CIEs + map[reloc->r_address()] = 0; + break; + default: + fprintf(stderr, "ObjectFileAddressSpace::buildRelocatedMap() unexpected relocation at r_address=0x%08X\n", reloc->r_address()); + break; + } + } +} + +template +void ObjectFileAddressSpace::buildRelocatedMap(const macho_section

* sect, std::map& map) +{ + // in all architectures except x86_64, the section contents are already fixed up to point + // to content in the same object file. +} template <> uint64_t ObjectFileAddressSpace::relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount) @@ -3100,14 +3244,15 @@ uint32_t SymbolAtom::getCompactUnwindEncoding(uint64_t ehAtomAddress) { pint_t lsda; pint_t personality; + char warningBuffer[1024]; uint32_t result = libunwind::DwarfInstructions, libunwind::Registers_x86>::createCompactEncodingFromFDE( - fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality); - if ( (result & UNWIND_X86_CASE_MASK) == UNWIND_X86_UNWIND_REQUIRES_DWARF ) { + fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer); + if ( (result & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) { //if ( fOwner.fOptions.fForDyld ) // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName()); //else if ( fOwner.fOptions.fWarnCompactUnwind ) - warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath()); + warning("can't make compact unwind encoding from dwarf for %s in %s because %s", this->getDisplayName(), fOwner.getPath(), warningBuffer); } return result; } @@ -3117,14 +3262,15 @@ uint32_t SymbolAtom::getCompactUnwindEncoding(uint64_t ehAtomAddress) { pint_t lsda; pint_t personality; + char warningBuffer[1024]; uint32_t result = libunwind::DwarfInstructions, libunwind::Registers_x86_64>::createCompactEncodingFromFDE( - fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality); - if ( (result & UNWIND_X86_64_CASE_MASK) == UNWIND_X86_64_UNWIND_REQUIRES_DWARF ) { + fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer); + if ( (result & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) { //if ( fOwner.fOptions.fForDyld ) // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName()); //else if ( fOwner.fOptions.fWarnCompactUnwind ) - warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath()); + warning("can't make compact unwind encoding from dwarf for %s in %s because %s", this->getDisplayName(), fOwner.getPath(), warningBuffer); } return result; } @@ -3182,12 +3328,14 @@ uint32_t AnonymousAtom::getCompactUnwindEncoding(uint64_t ehAtomAddress) { pint_t lsda; pint_t personality; + char warningBuffer[1024]; uint32_t result = libunwind::DwarfInstructions, libunwind::Registers_x86>::createCompactEncodingFromFDE( - fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality); - if ( (result & UNWIND_X86_CASE_MASK) == UNWIND_X86_UNWIND_REQUIRES_DWARF ) { + fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer); + if ( (result & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) { //if ( fOwner.fOptions.fForDyld ) // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName()); //else + if ( fOwner.fOptions.fWarnCompactUnwind ) warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath()); } return result; @@ -3198,12 +3346,14 @@ uint32_t AnonymousAtom::getCompactUnwindEncoding(uint64_t ehAtomAddress) { pint_t lsda; pint_t personality; + char warningBuffer[1024]; uint32_t result = libunwind::DwarfInstructions, libunwind::Registers_x86_64>::createCompactEncodingFromFDE( - fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality); - if ( (result & UNWIND_X86_64_CASE_MASK) == UNWIND_X86_64_UNWIND_REQUIRES_DWARF ) { + fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer); + if ( (result & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) { //if ( fOwner.fOptions.fForDyld ) // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName()); //else + if ( fOwner.fOptions.fWarnCompactUnwind ) warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath()); } return result; @@ -3572,8 +3722,8 @@ AtomAndOffset Reader::findAtomAndOffsetForSection(pint_t addr, unsigned int e } } } - // no atom found - return AtomAndOffset(NULL); + // no atom found that matched section, fall back to one orginally found + return ao; } template @@ -3611,9 +3761,10 @@ AtomAndOffset Reader::findAtomAndOffset(pint_t baseAddr, pint_t realAddr) return result; } // getting here means we have a scattered relocation to an address without a label - // we should never get here... - // one case we do get here is because sometimes the compiler generates non-lazy pointers in the __data section - return findAtomAndOffset(realAddr); + // so, find the atom that contains the baseAddr, and offset from that to the readAddr + AtomAndOffset result = findAtomAndOffset(baseAddr); + result.offset += (realAddr-baseAddr); + return result; } @@ -4665,7 +4816,10 @@ bool Reader::addRelocReference(const macho_section* sect, con kind = x86_64::kPointer32; break; case 3: - kind = x86_64::kPointer; + if ( reloc->r_extern() && isWeakImportSymbol(targetSymbol) ) + kind = x86_64::kPointerWeakImport; + else + kind = x86_64::kPointer; break; } dstAddr = E::get64(*((uint64_t*)fixUpPtr)); @@ -5073,7 +5227,7 @@ bool Reader::addRelocReference(const macho_section* sect, break; case ARM_THUMB_32BIT_BRANCH: - // work around for + // ignore old unnecessary relocs break; default: @@ -5277,7 +5431,7 @@ const char* Reference::getDescription() const sprintf(temp, "offset 0x%04X, absolute32 reference to ", fFixUpOffsetInSrc); break; case x86::kImageOffset32: - sprintf(temp, "offset 0x%04X, 32bit offset of ", fFixUpOffsetInSrc); + sprintf(temp, "offset 0x%04X, 32-bit offset of ", fFixUpOffsetInSrc); break; case x86::kPointerDiff24: sprintf(temp, "offset 0x%04X, 24-bit pointer difference: (&%s + 0x%08X) - (&%s + 0x%08X)", @@ -5285,6 +5439,9 @@ const char* Reference::getDescription() const this->getFromTargetDisplayName(), fFromTarget.offset ); return temp; break; + case x86::kSectionOffset24: + sprintf(temp, "offset 0x%04X, 24-bit section offset of ", fFixUpOffsetInSrc); + break; case x86::kDtraceProbe: sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc); break; @@ -5609,6 +5766,9 @@ const char* Reference::getDescription() const case x86_64::kImageOffset32: sprintf(temp, "offset 0x%04llX, 32bit offset of ", fFixUpOffsetInSrc); break; + case x86_64::kSectionOffset24: + sprintf(temp, "offset 0x%04llX, 24-bit section offset of ", fFixUpOffsetInSrc); + break; case x86_64::kDtraceProbe: sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc); break; @@ -5671,6 +5831,16 @@ const char* Reference::getDescription() const fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset ); return temp; } + case arm::kPointerDiff12: + { + // by-name references have quoted names + const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; + const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; + sprintf(temp, "offset 0x%04X, 12-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)", + fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset, + fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset ); + return temp; + } case arm::kReadOnlyPointer: sprintf(temp, "offset 0x%04X, read-only pointer to ", fFixUpOffsetInSrc); break; diff --git a/src/ld/MachOWriterExecutable.hpp b/src/ld/MachOWriterExecutable.hpp index 9e02efa..2ed0feb 100644 --- a/src/ld/MachOWriterExecutable.hpp +++ b/src/ld/MachOWriterExecutable.hpp @@ -107,6 +107,7 @@ template class FastStubHelperHelperAtom; template class LazyPointerAtom; template class NonLazyPointerAtom; template class DylibLoadCommandsAtom; +template class BranchIslandAtom; // SectionInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes @@ -286,15 +287,18 @@ public: virtual ObjectFile::Atom& makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, bool objcReplacementClasses); virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name); + virtual void addSynthesizedAtoms(const std::vector& existingAtoms, + class ObjectFile::Atom* dyldClassicHelperAtom, + class ObjectFile::Atom* dyldCompressedHelperAtom, + class ObjectFile::Atom* dyldLazyDylibHelperAtom, + bool biggerThanTwoGigs, + uint32_t dylibSymbolCount, + std::vector& newAtoms); virtual uint64_t write(std::vector& atoms, std::vector& stabs, class ObjectFile::Atom* entryPointAtom, - class ObjectFile::Atom* dyldClassicHelperAtom, - class ObjectFile::Atom* dyldCompressedHelperAtom, - class ObjectFile::Atom* dyldLazyDylibHelperAtom, bool createUUID, bool canScatter, ObjectFile::Reader::CpuConstraint cpuConstraint, - bool biggerThanTwoGigs, std::set& atomsThatOverrideWeak, bool hasExternalWeakDefinitions); @@ -305,15 +309,19 @@ private: enum RelocKind { kRelocNone, kRelocInternal, kRelocExternal }; void assignFileOffsets(); - void synthesizeStubs(); - void synthesizeKextGOT(); + void synthesizeStubs(const std::vector& existingAtoms, + std::vector& newAtoms); + void synthesizeKextGOT(const std::vector& existingAtoms, + std::vector& newAtoms); void createSplitSegContent(); void synthesizeUnwindInfoTable(); void insertDummyStubs(); void partitionIntoSections(); bool addBranchIslands(); - bool addPPCBranchIslands(); - bool isBranch24Reference(uint8_t kind); + bool createBranchIslands(); + bool isBranchThatMightNeedIsland(uint8_t kind); + uint32_t textSizeWhenMightNeedBranchIslands(); + uint32_t maxDistanceBetweenIslands(); void adjustLoadCommandsAndPadding(); void createDynamicLinkerCommand(); void createDylibCommands(); @@ -422,6 +430,7 @@ private: friend class LazyPointerAtom; friend class NonLazyPointerAtom; friend class DylibLoadCommandsAtom; + friend class BranchIslandAtom; const char* fFilePath; Options& fOptions; @@ -453,6 +462,7 @@ private: std::vector fLocalSymbolAtoms; std::vector > fLocalExtraLabels; std::vector > fGlobalExtraLabels; + std::map fAtomToSymbolIndex; class SectionRelocationsLinkEditAtom* fSectionRelocationsAtom; class CompressedRebaseInfoLinkEditAtom* fCompressedRebaseInfoAtom; class CompressedBindingInfoLinkEditAtom* fCompressedBindingInfoAtom; @@ -492,6 +502,7 @@ private: uint32_t fSymbolTableImportCount; uint32_t fSymbolTableImportStartIndex; uint32_t fLargestAtomSize; + uint32_t fDylibSymbolCountUpperBound; bool fEmitVirtualSections; bool fHasWeakExports; bool fReferencesWeakImports; @@ -500,6 +511,7 @@ private: bool fNoReExportedDylibs; bool fBiggerThanTwoGigs; bool fSlideable; + bool fHasThumbBranches; std::map fWeakImportMap; std::set fDylibReadersWithNonWeakImports; std::set fDylibReadersWithWeakImports; @@ -972,17 +984,20 @@ public: virtual void copyRawContent(uint8_t buffer[]) const; void addUnwindInfo(ObjectFile::Atom* func, uint32_t offset, uint32_t encoding, - ObjectFile::Reference* lsda, ObjectFile::Atom* personalityPointer); + ObjectFile::Reference* fdeRef, ObjectFile::Reference* lsda, + ObjectFile::Atom* personalityPointer); void generate(); private: using WriterAtom::fWriter; typedef typename A::P P; - struct Info { ObjectFile::Atom* func; ObjectFile::Atom* lsda; uint32_t lsdaOffset; ObjectFile::Atom* personalityPointer; uint32_t encoding; }; + struct Info { ObjectFile::Atom* func; ObjectFile::Atom* fde; ObjectFile::Atom* lsda; uint32_t lsdaOffset; ObjectFile::Atom* personalityPointer; uint32_t encoding; }; struct LSDAEntry { ObjectFile::Atom* func; ObjectFile::Atom* lsda; uint32_t lsdaOffset; }; - struct RegFixUp { uint8_t* contentPointer; ObjectFile::Atom* func; }; + struct RegFixUp { uint8_t* contentPointer; ObjectFile::Atom* func; ObjectFile::Atom* fde; }; struct CompressedFixUp { uint8_t* contentPointer; ObjectFile::Atom* func; ObjectFile::Atom* fromFunc; }; + struct CompressedEncodingFixUp { uint8_t* contentPointer; ObjectFile::Atom* fde; }; + bool encodingMeansUseDwarf(compact_unwind_encoding_t encoding); void compressDuplicates(std::vector& uniqueInfos); void findCommonEncoding(const std::vector& uniqueInfos, std::map& commonEncodings); void makeLsdaIndex(const std::vector& uniqueInfos, std::map& lsdaIndexOffsetMap); @@ -1005,6 +1020,7 @@ private: std::vector fLSDAIndex; std::vector fRegFixUps; std::vector fCompressedFixUps; + std::vector fCompressedEncodingFixUps; std::vector fReferences; }; @@ -1451,17 +1467,25 @@ template class BranchIslandAtom : public WriterAtom { public: - BranchIslandAtom(Writer& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset); + BranchIslandAtom(Writer& writer, const char* name, int islandRegion, ObjectFile::Atom& target, + ObjectFile::Atom& finalTarget, uint32_t finalTargetOffset); virtual const char* getName() const { return fName; } virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } virtual uint64_t getSize() const; + virtual bool isThumb() const { return (fIslandKind == kBranchIslandToThumb2); } + virtual ObjectFile::Atom::ContentType getContentType() const { return ObjectFile::Atom::kBranchIsland; } + virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; } virtual const char* getSectionName() const { return "__text"; } virtual void copyRawContent(uint8_t buffer[]) const; + uint64_t getFinalTargetAdress() const { return fFinalTarget.getAddress() + fFinalTargetOffset; } private: using WriterAtom::fWriter; + enum IslandKind { kBranchIslandToARM, kBranchIslandToThumb2, kBranchIslandToThumb1 }; const char* fName; ObjectFile::Atom& fTarget; - uint32_t fTargetOffset; + ObjectFile::Atom& fFinalTarget; + uint32_t fFinalTargetOffset; + IslandKind fIslandKind; }; template @@ -1471,20 +1495,26 @@ public: StubAtom(Writer& writer, ObjectFile::Atom& target, bool forLazyDylib); virtual const char* getName() const { return fName; } virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } + virtual ObjectFile::Atom::ContentType getContentType() const { return ObjectFile::Atom::kStub; } virtual uint64_t getSize() const; virtual ObjectFile::Alignment getAlignment() const; virtual const char* getSectionName() const { return "__symbol_stub1"; } virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } virtual void copyRawContent(uint8_t buffer[]) const; ObjectFile::Atom* getTarget() { return &fTarget; } + virtual uint32_t getOrdinal() const { return fSortingOrdinal; } + void setSortingOrdinal(uint32_t o) { fSortingOrdinal = o; } private: static const char* stubName(const char* importName); - bool pic() const { return fWriter.fSlideable; } + friend class LazyPointerAtom; using WriterAtom::fWriter; + enum StubKind { kStubPIC, kStubNoPIC, kStubShort, kJumpTable }; const char* fName; ObjectFile::Atom& fTarget; std::vector fReferences; bool fForLazyDylib; + StubKind fKind; + uint32_t fSortingOrdinal; }; @@ -1496,11 +1526,13 @@ public: virtual const char* getName() const { return " stub helpers"; } // name sorts to start of helpers virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; } virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } + virtual ObjectFile::Atom::ContentType getContentType() const { return ObjectFile::Atom::kStubHelper; } virtual uint64_t getSize() const; virtual const char* getSectionName() const { return "__stub_helper"; } virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } virtual void copyRawContent(uint8_t buffer[]) const; virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); } + virtual uint32_t getOrdinal() const { return 0; } protected: using WriterAtom::fWriter; std::vector fReferences; @@ -1514,11 +1546,13 @@ public: virtual const char* getName() const { return " stub helpers"; } // name sorts to start of helpers virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; } virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } + virtual ObjectFile::Atom::ContentType getContentType() const { return ObjectFile::Atom::kStubHelper; } virtual uint64_t getSize() const; virtual const char* getSectionName() const { return "__stub_helper"; } virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } virtual void copyRawContent(uint8_t buffer[]) const; virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); } + virtual uint32_t getOrdinal() const { return 0; } protected: using WriterAtom::fWriter; std::vector fReferences; @@ -1537,10 +1571,12 @@ public: virtual const char* getName() const { return fName; } virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } + virtual ObjectFile::Atom::ContentType getContentType() const { return ObjectFile::Atom::kStubHelper; } virtual const char* getSectionName() const { return "__stub_helper"; } virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } ObjectFile::Atom* getTarget() { return &fTarget; } virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); } + virtual uint32_t getOrdinal() const { return 1; } protected: static const char* stubName(const char* importName); using WriterAtom::fWriter; @@ -1596,14 +1632,17 @@ public: LazyPointerAtom(Writer& writer, ObjectFile::Atom& target, StubAtom& stub, bool forLazyDylib); virtual const char* getName() const { return fName; } - virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } + virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; } + virtual ObjectFile::Atom::ContentType getContentType() const { return fForLazyDylib ? ObjectFile::Atom::kLazyDylibPointer : ObjectFile::Atom::kLazyPointer; } virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); } - virtual const char* getSectionName() const { return fForLazyDylib ? "__ld_symbol_ptr" : "__la_symbol_ptr"; } + virtual const char* getSectionName() const; virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } virtual void copyRawContent(uint8_t buffer[]) const; ObjectFile::Atom* getTarget() { return &fExternalTarget; } void setLazyBindingInfoOffset(uint32_t off) { fLazyBindingOffset = off; } uint32_t getLazyBindingInfoOffset() { return fLazyBindingOffset; } + virtual uint32_t getOrdinal() const { return fSortingOrdinal; } + void setSortingOrdinal(uint32_t o) { fSortingOrdinal = o; } private: using WriterAtom::fWriter; static const char* lazyPointerName(const char* importName); @@ -1612,7 +1651,9 @@ private: ObjectFile::Atom& fExternalTarget; std::vector fReferences; bool fForLazyDylib; + bool fCloseStub; uint32_t fLazyBindingOffset; + uint32_t fSortingOrdinal; }; @@ -1625,17 +1666,21 @@ public: NonLazyPointerAtom(Writer& writer); virtual const char* getName() const { return fName; } virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } + virtual ObjectFile::Atom::ContentType getContentType() const { return ObjectFile::Atom::kNonLazyPointer; } virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); } virtual const char* getSectionName() const { return (fWriter.fOptions.outputKind() == Options::kKextBundle) ? "__got" : "__nl_symbol_ptr"; } virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } virtual void copyRawContent(uint8_t buffer[]) const; ObjectFile::Atom* getTarget() { return fTarget; } + virtual uint32_t getOrdinal() const { return fSortingOrdinal; } + void setSortingOrdinal(uint32_t o) { fSortingOrdinal = o; } private: using WriterAtom::fWriter; static const char* nonlazyPointerName(const char* importName); const char* fName; ObjectFile::Atom* fTarget; std::vector fReferences; + uint32_t fSortingOrdinal; }; @@ -1953,7 +1998,7 @@ void FastStubHelperHelperAtom::copyRawContent(uint8_t buffer[]) const buffer[2] = 0x00; buffer[3] = 0x00; buffer[4] = 0x00; - buffer[5] = 0xFF; // jmp *_fast_lazy_bind(%rip) + buffer[5] = 0xFF; // jmp *_fast_lazy_bind buffer[6] = 0x25; buffer[7] = 0x00; buffer[8] = 0x00; @@ -1963,6 +2008,69 @@ void FastStubHelperHelperAtom::copyRawContent(uint8_t buffer[]) const } +template <> +FastStubHelperHelperAtom::FastStubHelperHelperAtom(Writer& writer) + : WriterAtom(writer, Segment::fgTextSegment) +{ + fReferences.push_back(new WriterReference(28, arm::kPointerDiff, new NonLazyPointerAtom(writer), 0, this, 16)); + fReferences.push_back(new WriterReference(32, arm::kPointerDiff, writer.fFastStubGOTAtom, 0, this, 28)); +} + +template <> +uint64_t FastStubHelperHelperAtom::getSize() const +{ + return 36; +} + +template <> +void FastStubHelperHelperAtom::copyRawContent(uint8_t buffer[]) const +{ + // push lazy-info-offset + OSWriteLittleInt32(&buffer[ 0], 0, 0xe52dc004); // str ip, [sp, #-4]! + // push address of dyld_mageLoaderCache + OSWriteLittleInt32(&buffer[ 4], 0, 0xe59fc010); // ldr ip, L1 + OSWriteLittleInt32(&buffer[ 8], 0, 0xe08fc00c); // add ip, pc, ip + OSWriteLittleInt32(&buffer[12], 0, 0xe52dc004); // str ip, [sp, #-4]! + // jump through _fast_lazy_bind + OSWriteLittleInt32(&buffer[16], 0, 0xe59fc008); // ldr ip, L2 + OSWriteLittleInt32(&buffer[20], 0, 0xe08fc00c); // add ip, pc, ip + OSWriteLittleInt32(&buffer[24], 0, 0xe59cf000); // ldr pc, [ip] + OSWriteLittleInt32(&buffer[28], 0, 0x00000000); // L1: .long fFastStubGOTAtom - (helperhelper+16) + OSWriteLittleInt32(&buffer[32], 0, 0x00000000); // L2: .long _fast_lazy_bind - (helperhelper+28) +} + +template <> +ObjectFile::Alignment StubHelperAtom::getAlignment() const { return ObjectFile::Alignment(2); } + +template <> +FastStubHelperAtom::FastStubHelperAtom(Writer& writer, ObjectFile::Atom& target, + class LazyPointerAtom& lazyPointer, bool forLazyDylib) + : StubHelperAtom(writer, target, lazyPointer, forLazyDylib) +{ + if ( fgHelperHelperAtom == NULL ) { + fgHelperHelperAtom = new FastStubHelperHelperAtom::FastStubHelperHelperAtom(fWriter); + fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom); + } + fReferences.push_back(new WriterReference(4, arm::kBranch24, fgHelperHelperAtom)); +} + +template <> +uint64_t FastStubHelperAtom::getSize() const +{ + return 12; +} + +template <> +void FastStubHelperAtom::copyRawContent(uint8_t buffer[]) const +{ + OSWriteLittleInt32(&buffer[0], 0, 0xe59fc000); // ldr ip, [pc, #0] + OSWriteLittleInt32(&buffer[4], 0, 0xea000000); // b _helperhelper + // the lazy binding info is created later than this helper atom, so there + // is no Reference to update. Instead we blast the offset here. + OSWriteLittleInt32(&buffer[8], 0, fLazyPointerAtom.getLazyBindingInfoOffset()); +} + + template <> HybridStubHelperHelperAtom::HybridStubHelperHelperAtom(Writer& writer) : WriterAtom(writer, Segment::fgTextSegment) @@ -2151,13 +2259,22 @@ void FastStubHelperAtom::copyRawContent(uint8_t buffer[]) const memcpy(&buffer[1], &offset, 4); } - +template +const char* LazyPointerAtom::getSectionName() const +{ + if ( fCloseStub ) + return "__lazy_symbol"; + else if ( fForLazyDylib ) + return "__ld_symbol_ptr"; + else + return "__la_symbol_ptr"; +} // specialize lazy pointer for x86_64 to initially pointer to stub helper template <> LazyPointerAtom::LazyPointerAtom(Writer& writer, ObjectFile::Atom& target, StubAtom& stub, bool forLazyDylib) : WriterAtom(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target), - fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fLazyBindingOffset(0) + fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fCloseStub(false), fLazyBindingOffset(0) { if ( forLazyDylib ) writer.fAllSynthesizedLazyDylibPointers.push_back(this); @@ -2190,7 +2307,7 @@ LazyPointerAtom::LazyPointerAtom(Writer& writer, ObjectFile::Ato template <> LazyPointerAtom::LazyPointerAtom(Writer& writer, ObjectFile::Atom& target, StubAtom& stub, bool forLazyDylib) : WriterAtom(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target), - fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib) + fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fCloseStub(false), fLazyBindingOffset(0) { if ( forLazyDylib ) writer.fAllSynthesizedLazyDylibPointers.push_back(this); @@ -2219,10 +2336,45 @@ LazyPointerAtom::LazyPointerAtom(Writer& writer, ObjectFile::Atom& tar fReferences.push_back(new WriterReference(0, x86::kPointer, helper)); } +// specialize lazy pointer for arm to initially pointer to stub helper +template <> +LazyPointerAtom::LazyPointerAtom(Writer& writer, ObjectFile::Atom& target, StubAtom& stub, bool forLazyDylib) + : WriterAtom(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target), + fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fCloseStub(false), fLazyBindingOffset(0) +{ + if ( forLazyDylib ) + writer.fAllSynthesizedLazyDylibPointers.push_back(this); + else + writer.fAllSynthesizedLazyPointers.push_back(this); + + // The one instruction stubs must be close to the lazy pointers + if ( stub.fKind == StubAtom::kStubShort ) + fCloseStub = true; + + ObjectFile::Atom* helper; + if ( forLazyDylib ) { + if ( writer.fDyldLazyDylibHelper == NULL ) + throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)"; + helper = writer.fDyldLazyDylibHelper; + } + else if ( writer.fOptions.makeCompressedDyldInfo() ) { + if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) + helper = ⌖ + else + helper = new FastStubHelperAtom(writer, target, *this, forLazyDylib); + } + else { + if ( writer.fDyldClassicHelperAtom == NULL ) + throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)"; + helper = writer.fDyldClassicHelperAtom; + } + fReferences.push_back(new WriterReference(0, arm::kPointer, helper)); +} + template LazyPointerAtom::LazyPointerAtom(Writer& writer, ObjectFile::Atom& target, StubAtom& stub, bool forLazyDylib) : WriterAtom(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target), - fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib) + fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fCloseStub(false), fLazyBindingOffset(0) { if ( forLazyDylib ) writer.fAllSynthesizedLazyDylibPointers.push_back(this); @@ -2288,20 +2440,6 @@ void NonLazyPointerAtom::copyRawContent(uint8_t buffer[]) const -template <> -bool StubAtom::pic() const -{ - // no-pic stubs for ppc64 don't work if lazy pointer is above low 2GB. - // Usually that only happens if page zero is very large - return ( fWriter.fSlideable || ((fWriter.fPageZeroAtom != NULL) && (fWriter.fPageZeroAtom->getSize() > 4096)) ); -} - - -template <> -bool StubAtom::pic() const -{ - return fWriter.fSlideable; -} template <> ObjectFile::Alignment StubAtom::getAlignment() const @@ -2346,7 +2484,8 @@ StubAtom::StubAtom(Writer& writer, ObjectFile::Atom& target, bool forL lp = new LazyPointerAtom(writer, *writer.fDyldClassicHelperAtom, *this, forLazyDylib); } } - if ( pic() ) { + fKind = ( fWriter.fSlideable ? kStubPIC : kStubNoPIC ); + if ( fKind == kStubPIC ) { // picbase is 8 bytes into atom fReferences.push_back(new WriterReference(12, ppc::kPICBaseHigh16, lp, 0, this, 8)); fReferences.push_back(new WriterReference(20, ppc::kPICBaseLow16, lp, 0, this, 8)); @@ -2375,7 +2514,11 @@ StubAtom::StubAtom(Writer& writer, ObjectFile::Atom& target, bool throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)"; lp = new LazyPointerAtom(writer, *writer.fDyldClassicHelperAtom, *this, forLazyDylib); } - if ( pic() ) { + if ( fWriter.fSlideable || ((fWriter.fPageZeroAtom != NULL) && (fWriter.fPageZeroAtom->getSize() > 4096)) ) + fKind = kStubPIC; + else + fKind = kStubNoPIC; + if ( fKind == kStubPIC ) { // picbase is 8 bytes into atom fReferences.push_back(new WriterReference(12, ppc64::kPICBaseHigh16, lp, 0, this, 8)); fReferences.push_back(new WriterReference(20, ppc64::kPICBaseLow14, lp, 0, this, 8)); @@ -2392,14 +2535,16 @@ StubAtom::StubAtom(Writer& writer, ObjectFile::Atom& target, bool forL fName(NULL), fTarget(target), fForLazyDylib(forLazyDylib) { if ( writer.fOptions.makeCompressedDyldInfo() || forLazyDylib ) { + fKind = kStubNoPIC; fName = stubName(target.getName()); LazyPointerAtom* lp = new LazyPointerAtom(writer, target, *this, forLazyDylib); fReferences.push_back(new WriterReference(2, x86::kAbsolute32, lp)); writer.fAllSynthesizedStubs.push_back(this); } else { + fKind = kJumpTable; if ( &target == NULL ) - fName = "cache-line-crossing-stub"; + asprintf((char**)&fName, "cache-line-crossing-stub %p", this); else { fName = stubName(target.getName()); writer.fAllSynthesizedStubs.push_back(this); @@ -2423,34 +2568,38 @@ StubAtom::StubAtom(Writer& writer, ObjectFile::Atom& target, bool forL : WriterAtom(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target) { writer.fAllSynthesizedStubs.push_back(this); - - LazyPointerAtom* lp; - if ( fWriter.fOptions.prebind() && !forLazyDylib ) { - // for prebound arm, lazy pointer starts out pointing to target symbol's address - // if target is a weak definition within this linkage unit or zero if in some dylib - lp = new LazyPointerAtom(writer, target, *this, forLazyDylib); + if ( (writer.fDylibSymbolCountUpperBound < 900) + && writer.fOptions.makeCompressedDyldInfo() + && (writer.fOptions.outputKind() != Options::kDynamicLibrary) + && !forLazyDylib ) { + // dylibs might have __TEXT and __DATA pulled apart to live in shared region + // if > 1000 stubs, the displacement to the lazy pointer my be > 12 bits. + fKind = kStubShort; + } + else if ( fWriter.fSlideable ) { + fKind = kStubPIC; } else { - // for non-prebound arm, lazy pointer starts out pointing to dyld_stub_binding_helper glue code - ObjectFile::Atom* helper; - if ( forLazyDylib ) { - if ( writer.fDyldLazyDylibHelper == NULL ) - throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)"; - helper = writer.fDyldLazyDylibHelper; - } - else { - if ( writer.fDyldClassicHelperAtom == NULL ) - throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)"; - helper = writer.fDyldClassicHelperAtom; - } - lp = new LazyPointerAtom(writer, *helper, *this, forLazyDylib); + fKind = kStubNoPIC; + } + LazyPointerAtom* lp = new LazyPointerAtom(writer, target, *this, forLazyDylib); + switch ( fKind ) { + case kStubPIC: + fReferences.push_back(new WriterReference(12, arm::kPointerDiff, lp, 0, this, 12)); + break; + case kStubNoPIC: + fReferences.push_back(new WriterReference(8, arm::kReadOnlyPointer, lp)); + break; + case kStubShort: + fReferences.push_back(new WriterReference(0, arm::kPointerDiff12, lp, 0, this, 8)); + break; + default: + throw "internal error"; } - if ( pic() ) - fReferences.push_back(new WriterReference(12, arm::kPointerDiff, lp, 0, this, 12)); - else - fReferences.push_back(new WriterReference(8, arm::kPointer, lp)); } + + template const char* StubAtom::stubName(const char* name) { @@ -2462,29 +2611,43 @@ const char* StubAtom::stubName(const char* name) template <> uint64_t StubAtom::getSize() const { - return ( pic() ? 32 : 16 ); + + return ( (fKind == kStubPIC) ? 32 : 16 ); } template <> uint64_t StubAtom::getSize() const { - return ( pic() ? 32 : 16 ); + return ( (fKind == kStubPIC) ? 32 : 16 ); } template <> uint64_t StubAtom::getSize() const { - return ( pic() ? 16 : 12 ); + switch ( fKind ) { + case kStubPIC: + return 16; + case kStubNoPIC: + return 12; + case kStubShort: + return 4; + default: + throw "internal error"; + } } template <> uint64_t StubAtom::getSize() const { - if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib ) - return 6; - else - return 5; + switch ( fKind ) { + case kStubNoPIC: + return 6; + case kJumpTable: + return 5; + default: + throw "internal error"; + } } template <> @@ -2496,16 +2659,20 @@ uint64_t StubAtom::getSize() const template <> ObjectFile::Alignment StubAtom::getAlignment() const { - if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib ) - return 1; - else - return 0; // special case x86 self-modifying stubs to be byte aligned + switch ( fKind ) { + case kStubNoPIC: + return 1; + case kJumpTable: + return 0; // special case x86 self-modifying stubs to be byte aligned + default: + throw "internal error"; + } } template <> void StubAtom::copyRawContent(uint8_t buffer[]) const { - if ( pic() ) { + if ( fKind == kStubPIC ) { OSWriteBigInt32(&buffer [0], 0, 0x7c0802a6); // mflr r0 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11 @@ -2526,7 +2693,7 @@ void StubAtom::copyRawContent(uint8_t buffer[]) const template <> void StubAtom::copyRawContent(uint8_t buffer[]) const { - if ( pic() ) { + if ( fKind == kStubPIC ) { OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6); // mflr r0 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11 @@ -2547,31 +2714,35 @@ void StubAtom::copyRawContent(uint8_t buffer[]) const template <> void StubAtom::copyRawContent(uint8_t buffer[]) const { - if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib ) { - buffer[0] = 0xFF; // jmp *foo$lazy_pointer - buffer[1] = 0x25; - buffer[2] = 0x00; - buffer[3] = 0x00; - buffer[4] = 0x00; - buffer[5] = 0x00; - } - else { - if ( fWriter.fOptions.prebind() ) { - uint32_t address = this->getAddress(); - int32_t rel32 = 0 - (address+5); - buffer[0] = 0xE9; - buffer[1] = rel32 & 0xFF; - buffer[2] = (rel32 >> 8) & 0xFF; - buffer[3] = (rel32 >> 16) & 0xFF; - buffer[4] = (rel32 >> 24) & 0xFF; - } - else { - buffer[0] = 0xF4; - buffer[1] = 0xF4; - buffer[2] = 0xF4; - buffer[3] = 0xF4; - buffer[4] = 0xF4; - } + switch ( fKind ) { + case kStubNoPIC: + buffer[0] = 0xFF; // jmp *foo$lazy_pointer + buffer[1] = 0x25; + buffer[2] = 0x00; + buffer[3] = 0x00; + buffer[4] = 0x00; + buffer[5] = 0x00; + break; + case kJumpTable: + if ( fWriter.fOptions.prebind() ) { + uint32_t address = this->getAddress(); + int32_t rel32 = 0 - (address+5); + buffer[0] = 0xE9; + buffer[1] = rel32 & 0xFF; + buffer[2] = (rel32 >> 8) & 0xFF; + buffer[3] = (rel32 >> 16) & 0xFF; + buffer[4] = (rel32 >> 24) & 0xFF; + } + else { + buffer[0] = 0xF4; + buffer[1] = 0xF4; + buffer[2] = 0xF4; + buffer[3] = 0xF4; + buffer[4] = 0xF4; + } + break; + default: + throw "internal error"; } } @@ -2589,16 +2760,23 @@ void StubAtom::copyRawContent(uint8_t buffer[]) const template <> void StubAtom::copyRawContent(uint8_t buffer[]) const { - if ( pic() ) { - OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 12 - OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip - OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); // ldr pc, [ip] - OSWriteLittleInt32(&buffer[12], 0, 0x00000000); // .long L_foo$lazy_ptr - (L1$scv + 8) - } - else { - OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); // ldr ip, [pc, #0] - OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); // ldr pc, [ip] - OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); // .long L_foo$lazy_ptr + switch ( fKind ) { + case kStubPIC: + OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 12 + OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip + OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); // ldr pc, [ip] + OSWriteLittleInt32(&buffer[12], 0, 0x00000000); // .long L_foo$lazy_ptr - (L1$scv + 8) + break; + case kStubNoPIC: + OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); // ldr ip, [pc, #0] + OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); // ldr pc, [ip] + OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); // .long L_foo$lazy_ptr + break; + case kStubShort: + OSWriteLittleInt32(&buffer[ 0], 0, 0xE59FF000);// ldr pc, [pc, #foo$lazy_ptr] + break; + default: + throw "internal error"; } } @@ -2612,28 +2790,41 @@ ObjectFile::Alignment StubAtom::getAlignment() const template <> const char* StubAtom::getSectionName() const { - return ( pic() ? "__picsymbolstub1" : "__symbol_stub1"); + return ( (fKind == kStubPIC) ? "__picsymbolstub1" : "__symbol_stub1"); } template <> const char* StubAtom::getSectionName() const { - return ( pic() ? "__picsymbolstub1" : "__symbol_stub1"); + return ( (fKind == kStubPIC) ? "__picsymbolstub1" : "__symbol_stub1"); } template <> const char* StubAtom::getSectionName() const { - return ( pic() ? "__picsymbolstub4" : "__symbol_stub4"); + switch ( fKind ) { + case kStubPIC: + return "__picsymbolstub4"; + case kStubNoPIC: + return "__symbol_stub4"; + case kStubShort: + return "__symbolstub1"; + default: + throw "internal error"; + } } template <> const char* StubAtom::getSectionName() const { - if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib ) - return "__symbol_stub"; - else - return "__jump_table"; + switch ( fKind ) { + case kStubNoPIC: + return "__symbol_stub"; + case kJumpTable: + return "__jump_table"; + default: + throw "internal error"; + } } @@ -2678,7 +2869,7 @@ Writer::Writer(const char* path, Options& options, std::vector::Writer(const char* path, Options& options, std::vector::makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint return *(new ObjCInfoAtom(*this, objcContraint, objcReplacementClasses)); } +template +void Writer::addSynthesizedAtoms(const std::vector& existingAtoms, + class ObjectFile::Atom* dyldClassicHelperAtom, + class ObjectFile::Atom* dyldCompressedHelperAtom, + class ObjectFile::Atom* dyldLazyDylibHelperAtom, + bool biggerThanTwoGigs, + uint32_t dylibSymbolCount, + std::vector& newAtoms) +{ + fDyldClassicHelperAtom = dyldClassicHelperAtom; + fDyldCompressedHelperAtom = dyldCompressedHelperAtom; + fDyldLazyDylibHelper = dyldLazyDylibHelperAtom; + fBiggerThanTwoGigs = biggerThanTwoGigs; + fDylibSymbolCountUpperBound = dylibSymbolCount; + + // create inter-library stubs + synthesizeStubs(existingAtoms, newAtoms); +} + template uint64_t Writer::write(std::vector& atoms, std::vector& stabs, class ObjectFile::Atom* entryPointAtom, - class ObjectFile::Atom* dyldClassicHelperAtom, - class ObjectFile::Atom* dyldCompressedHelperAtom, - class ObjectFile::Atom* dyldLazyDylibHelperAtom, bool createUUID, bool canScatter, ObjectFile::Reader::CpuConstraint cpuConstraint, - bool biggerThanTwoGigs, std::set& atomsThatOverrideWeak, bool hasExternalWeakDefinitions) { fAllAtoms = &atoms; fStabs = &stabs; fEntryPoint = entryPointAtom; - fDyldClassicHelperAtom = dyldClassicHelperAtom; - fDyldCompressedHelperAtom = dyldCompressedHelperAtom; - fDyldLazyDylibHelper = dyldLazyDylibHelperAtom; fCanScatter = canScatter; fCpuConstraint = cpuConstraint; - fBiggerThanTwoGigs = biggerThanTwoGigs; fHasWeakExports = hasExternalWeakDefinitions; // dyld needs to search this image as if it had weak exports fRegularDefAtomsThatOverrideADylibsWeakDef = &atomsThatOverrideWeak; @@ -3110,9 +3312,6 @@ uint64_t Writer::write(std::vector& atoms, // check for mdynamic-no-pic codegen scanForAbsoluteReferences(); - // create inter-library stubs - synthesizeStubs(); - // create table of unwind info synthesizeUnwindInfoTable(); @@ -3235,6 +3434,8 @@ void Writer::setExportNlist(const ObjectFile::Atom* atom, macho_nlist

* ent desc |= N_ARM_THUMB_DEF; if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ) desc |= REFERENCED_DYNAMICALLY; + if ( atom->dontDeadStrip() && (fOptions.outputKind() == Options::kObjectFile) ) + desc |= N_NO_DEAD_STRIP; if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) { desc |= N_WEAK_DEF; fHasWeakExports = true; @@ -3319,8 +3520,14 @@ void Writer::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist

* entr const char* symbolName = this->symbolTableName(atom); char anonName[32]; if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.keepLocalSymbol(symbolName) ) { - sprintf(anonName, "l%u", fAnonNameIndex++); - symbolName = anonName; + if ( stringsNeedLabelsInObjects() && (atom->getContentType() == ObjectFile::Atom::kCStringType) ) { + // don't use 'l' labels for x86_64 strings + // x86_64 obj-c runtime confused when static lib is stripped + } + else { + sprintf(anonName, "l%u", fAnonNameIndex++); + symbolName = anonName; + } } entry->set_n_strx(this->fStringsAtom->add(symbolName)); @@ -3343,6 +3550,8 @@ void Writer::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist

* entr // set n_desc uint16_t desc = 0; + if ( atom->dontDeadStrip() && (fOptions.outputKind() == Options::kObjectFile) ) + desc |= N_NO_DEAD_STRIP; if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) desc |= N_WEAK_DEF; if ( atom->isThumb() ) @@ -3481,6 +3690,27 @@ void Writer::buildSymbolTable() // set up module table if ( fModuleInfoAtom != NULL ) fModuleInfoAtom->setName(); + + // create atom to symbol index map + // imports + int i = 0; + for(std::vector::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) { + fAtomToSymbolIndex[*it] = i + fSymbolTableImportStartIndex; + ++i; + } + // locals + i = 0; + for(std::vector::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) { + fAtomToSymbolIndex[*it] = i + fSymbolTableLocalStartIndex; + ++i; + } + // exports + i = 0; + for(std::vector::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) { + fAtomToSymbolIndex[*it] = i + fSymbolTableExportStartIndex; + ++i; + } + } @@ -3516,62 +3746,69 @@ void Writer::collectExportedAndImportedAndLocalAtoms() fImportedAtoms.reserve(100); fExportedAtoms.reserve(atomCount/2); fLocalSymbolAtoms.reserve(atomCount); - for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { - ObjectFile::Atom* atom = *it; - // only named atoms go in symbol table - if ( atom->getName() != NULL ) { - // put atom into correct bucket: imports, exports, locals - //fprintf(stderr, "collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName()); - switch ( atom->getDefinitionKind() ) { - case ObjectFile::Atom::kExternalDefinition: - case ObjectFile::Atom::kExternalWeakDefinition: - fImportedAtoms.push_back(atom); - break; - case ObjectFile::Atom::kTentativeDefinition: - if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fMakeTentativeDefinitionsReal ) { - fImportedAtoms.push_back(atom); - break; + + for (std::vector::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) { + std::vector& sectionInfos = (*segit)->fSections; + for (std::vector::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) { + std::vector& sectionAtoms = (*secit)->fAtoms; + for (std::vector::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) { + ObjectFile::Atom* atom = *ait; + // only named atoms go in symbol table + if ( atom->getName() != NULL ) { + // put atom into correct bucket: imports, exports, locals + //fprintf(stderr, "collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName()); + switch ( atom->getDefinitionKind() ) { + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + fImportedAtoms.push_back(atom); + break; + case ObjectFile::Atom::kTentativeDefinition: + if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fMakeTentativeDefinitionsReal ) { + fImportedAtoms.push_back(atom); + break; + } + // else fall into + case ObjectFile::Atom::kWeakDefinition: + if ( stringsNeedLabelsInObjects() + && (fOptions.outputKind() == Options::kObjectFile) + && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableIn) + && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) + && (atom->getContentType() == ObjectFile::Atom::kCStringType) ) { + fLocalSymbolAtoms.push_back(atom); + break; + } + // else fall into + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kAbsoluteSymbol: + if ( this->shouldExport(*atom) ) + fExportedAtoms.push_back(atom); + else if ( (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) + && ((fOptions.outputKind() == Options::kObjectFile) || fOptions.keepLocalSymbol(atom->getName())) ) + fLocalSymbolAtoms.push_back(atom); + break; } - // else fall into - case ObjectFile::Atom::kWeakDefinition: - if ( stringsNeedLabelsInObjects() - && (fOptions.outputKind() == Options::kObjectFile) - && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableIn) - && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) - && (atom->getContentType() == ObjectFile::Atom::kCStringType) ) { - fLocalSymbolAtoms.push_back(atom); - break; + } + // when geneating a .o file, dtrace static probes become local labels + if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fForStatic ) { + std::vector& references = atom->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + ObjectFile::Reference* ref = *rit; + if ( ref->getKind() == A::kDtraceProbe ) { + // dtrace probe points to be add back into generated .o file + this->addLocalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName()); + } } - // else fall into - case ObjectFile::Atom::kRegularDefinition: - case ObjectFile::Atom::kAbsoluteSymbol: - if ( this->shouldExport(*atom) ) - fExportedAtoms.push_back(atom); - else if ( (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) - && ((fOptions.outputKind() == Options::kObjectFile) || fOptions.keepLocalSymbol(atom->getName())) ) - fLocalSymbolAtoms.push_back(atom); - break; - } - } - // when geneating a .o file, dtrace static probes become local labels - if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fForStatic ) { - std::vector& references = atom->getReferences(); - for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { - ObjectFile::Reference* ref = *rit; - if ( ref->getKind() == A::kDtraceProbe ) { - // dtrace probe points to be add back into generated .o file - this->addLocalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName()); } - } - } - // when linking kernel, old style dtrace static probes become global labels - else if ( fOptions.readerOptions().fForStatic ) { - std::vector& references = atom->getReferences(); - for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { - ObjectFile::Reference* ref = *rit; - if ( ref->getKind() == A::kDtraceProbe ) { - // dtrace probe points to be add back into generated .o file - this->addGlobalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName()); + // when linking kernel, old style dtrace static probes become global labels + else if ( fOptions.readerOptions().fForStatic ) { + std::vector& references = atom->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + ObjectFile::Reference* ref = *rit; + if ( ref->getKind() == A::kDtraceProbe ) { + // dtrace probe points to be add back into generated .o file + this->addGlobalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName()); + } + } } } } @@ -3690,30 +3927,9 @@ void Writer::addStabs(uint32_t startIndex) template uint32_t Writer::symbolIndex(ObjectFile::Atom& atom) { - // search imports - int i = 0; - for(std::vector::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) { - if ( &atom == *it ) - return i + fSymbolTableImportStartIndex; - ++i; - } - - // search locals - i = 0; - for(std::vector::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) { - if ( &atom == *it ) - return i + fSymbolTableLocalStartIndex; - ++i; - } - - // search exports - i = 0; - for(std::vector::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) { - if ( &atom == *it ) - return i + fSymbolTableExportStartIndex; - ++i; - } - + std::map::iterator pos = fAtomToSymbolIndex.find(&atom); + if ( pos != fAtomToSymbolIndex.end() ) + return pos->second; throwf("atom not found in symbolIndex(%s) for %s", atom.getDisplayName(), atom.getFile()->getPath()); } @@ -3918,6 +4134,9 @@ uint32_t Writer::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Ref case x86_64::kImageOffset32: throw "internal linker error, kImageOffset32 can't be encoded into object files"; + case x86_64::kSectionOffset24: + throw "internal linker error, kSectionOffset24 can't be encoded into object files"; + case x86_64::kDtraceTypeReference: case x86_64::kDtraceProbe: // generates no relocs @@ -4040,6 +4259,9 @@ uint32_t Writer::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Refere case x86::kImageOffset32: throw "internal linker error, kImageOffset32 can't be encoded into object files"; + case x86::kSectionOffset24: + throw "internal linker error, kSectionOffset24 can't be encoded into object files"; + case x86::kDtraceTypeReference: case x86::kDtraceProbe: // generates no relocs @@ -4170,6 +4392,9 @@ uint32_t Writer::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Refere fSectionRelocs.push_back(reloc1); return 1; + case arm::kPointerDiff12: + throw "internal error. no reloc for 12-bit pointer diffs"; + case arm::kDtraceTypeReference: case arm::kDtraceProbe: // generates no relocs @@ -4889,6 +5114,9 @@ bool Writer::generatesLocalTextReloc(const ObjectFile::Reference& ref, cons reloc.set_r_type(GENERIC_RELOC_VANILLA); fInternalRelocs.push_back(reloc); atomSection->fHasTextLocalRelocs = true; + if ( fOptions.makeCompressedDyldInfo() ) { + fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_TEXT_ABSOLUTE32, atom.getAddress() + ref.getFixUpOffset())); + } return true; } return false; @@ -5247,11 +5475,23 @@ void Writer::buildExecutableFixups() uint64_t addresss = atom->getAddress(); if ( targetRequiresWeakBinding(ref->getTarget()) ) { fWeakBindingInfo.push_back(BindingInfo(type, ref->getTarget().getName(), false, addresss, 0)); - // if this is a non-lazy pointer to a weak definition with this linkage unit + // if this is a non-lazy pointer to a weak definition within this linkage unit // the pointer needs to initially point within linkage unit and have - // rease command to slide it. - if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) - fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress())); + // rebase command to slide it. + if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) { + // unless if this is a hybrid format, in which case the non-lazy pointer + // is zero on disk. So use a bind instead of a rebase to set initial value + if ( fOptions.makeClassicDyldInfo() ) + fBindingInfo.push_back(BindingInfo(type, BIND_SPECIAL_DYLIB_SELF, ref->getTarget().getName(), false, addresss, 0)); + else + fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress())); + } + // if this is a non-lazy pointer to a weak definition in a dylib, + // the pointer needs to initially bind to the dylib + else if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition ) { + int ordinal = compressedOrdinalForImortedAtom(pointerTarget); + fBindingInfo.push_back(BindingInfo(BIND_TYPE_POINTER, ordinal, pointerTarget->getName(), false, addresss, 0)); + } } else { int ordinal = compressedOrdinalForImortedAtom(pointerTarget); @@ -5320,6 +5560,16 @@ void Writer::buildExecutableFixups() uint8_t type = BIND_TYPE_POINTER; if ( targetRequiresWeakBinding(ref->getTarget()) ) { fWeakBindingInfo.push_back(BindingInfo(type, ref->getTarget().getName(), false, addresss, addend)); + if ( fOptions.makeClassicDyldInfo() && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) { + // hybrid linkedit puts addend in data, so we need bind phase to reset pointer to local definifion + fBindingInfo.push_back(BindingInfo(type, BIND_SPECIAL_DYLIB_SELF, ref->getTarget().getName(), false, addresss, addend)); + } + // if this is a pointer to a weak definition in a dylib, + // the pointer needs to initially bind to the dylib + else if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition ) { + int ordinal = compressedOrdinalForImortedAtom(&ref->getTarget()); + fBindingInfo.push_back(BindingInfo(BIND_TYPE_POINTER, ordinal, ref->getTarget().getName(), false, addresss, addend)); + } } else { int ordinal = compressedOrdinalForImortedAtom(&ref->getTarget()); @@ -5847,7 +6097,7 @@ uint64_t Writer::writeAtoms() uint64_t atomSize = atom->getSize(); if ( streaming ) { if ( atomSize > fLargestAtomSize ) - throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX", + throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%llX > 0x%X", atom->getDisplayName(), atomSize, fLargestAtomSize); } else { @@ -6038,6 +6288,13 @@ void Writer::fixUpReferenceFinal(const ObjectFile::Reference* ref, const Ob break; } } + else if ( !fOptions.makeClassicDyldInfo() + && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) { + // when using only compressed dyld info, pointer is initially set to point directly to weak definition + if ( ref->getTarget().isThumb() ) + targetAddr |= 1; + LittleEndian::set32(*fixUp, targetAddr); + } else { // external relocation ==> pointer contains addend LittleEndian::set32(*fixUp, ref->getTargetOffset()); @@ -6078,15 +6335,25 @@ void Writer::fixUpReferenceFinal(const ObjectFile::Reference* ref, const Ob case arm::kBranch24WeakImport: case arm::kBranch24: displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset()); + // check if this is a branch to a branch island that can be skipped + if ( ref->getTarget().getContentType() == ObjectFile::Atom::kBranchIsland ) { + uint64_t finalTargetAddress = ((BranchIslandAtom*)(&(ref->getTarget())))->getFinalTargetAdress(); + int64_t altDisplacment = finalTargetAddress - (inAtom->getAddress() + ref->getFixUpOffset()); + if ( (altDisplacment < 33554428LL) && (altDisplacment > (-33554432LL)) ) { + //fprintf(stderr, "using altDisplacment = %lld\n", altDisplacment); + // yes, we can skip the branch island + displacement = altDisplacment; + } + } // The pc added will be +8 from the pc displacement -= 8; - // fprintf(stderr, "bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement); + //fprintf(stderr, "bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement); // max positive displacement is 0x007FFFFF << 2 // max negative displacement is 0xFF800000 << 2 if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) { - throwf("b/bl/blx out of range (%lld max is +/-32M) from %s in %s to %s in %s", - displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(), - ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath()); + throwf("b/bl/blx out of range (%lld max is +/-32M) from 0x%08llX %s in %s to 0x%08llX %s in %s", + displacement, inAtom->getAddress(), inAtom->getDisplayName(), inAtom->getFile()->getPath(), + ref->getTarget().getAddress(), ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath()); } instruction = LittleEndian::get32(*fixUp); // Make sure we are calling arm with bl, thumb with blx @@ -6233,8 +6500,22 @@ void Writer::fixUpReferenceFinal(const ObjectFile::Reference* ref, const Ob case arm::kDtraceProbe: // nothing to fix up break; - default: - throw "boom shaka laka"; + case arm::kPointerDiff12: + displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()); + if ( (displacement > 4092LL) || (displacement <-4092LL) ) { + throwf("ldr 12-bit displacement out of range (%lld max +/-4096) in %s", displacement, inAtom->getDisplayName()); + } + instruction = LittleEndian::get32(*fixUp); + if ( displacement >= 0 ) { + instruction &= 0xFFFFF000; + instruction |= ((uint32_t)displacement & 0xFFF); + } + else { + instruction &= 0xFF7FF000; + instruction |= ((uint32_t)(-displacement) & 0xFFF); + } + LittleEndian::set32(*fixUp, instruction); + break; } } @@ -6466,6 +6747,8 @@ void Writer::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, co case arm::kDtraceTypeReference: // nothing to fix up break; + case arm::kPointerDiff12: + throw "internal error. no reloc for 12-bit pointer diffs"; } } @@ -6508,9 +6791,9 @@ void Writer::fixUpReferenceFinal(const ObjectFile::Reference* ref, const Ob break; } } - else if ( fOptions.makeCompressedDyldInfo() + else if ( !fOptions.makeClassicDyldInfo() && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) { - // lazy pointer is initially set to point directly to weak definition + // when using only compressed dyld info, pointer is initially set to point directly to weak definition LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset()); } else { @@ -6544,6 +6827,15 @@ void Writer::fixUpReferenceFinal(const ObjectFile::Reference* ref, const Ob temp |= (displacement & 0x00FFFFFF); LittleEndian::set32(*fixUp, temp); break; + case x86::kSectionOffset24: + displacement = ref->getTarget().getSectionOffset(); + if ( (displacement > kSixteenMegLimit) || (displacement < 0) ) + throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName()); + temp = LittleEndian::get32(*fixUp); + temp &= 0xFF000000; + temp |= (displacement & 0x00FFFFFF); + LittleEndian::set32(*fixUp, temp); + break; case x86::kDtraceProbeSite: // change call site to a NOP dtraceProbeSite = (uint8_t*)fixUp; @@ -6733,6 +7025,8 @@ void Writer::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, co throw "internal linker error, kPointerDiff24 can't be encoded into object files"; case x86::kImageOffset32: throw "internal linker error, kImageOffset32 can't be encoded into object files"; + case x86::kSectionOffset24: + throw "internal linker error, kSectionOffset24 can't be encoded into object files"; case x86::kDtraceProbe: case x86::kDtraceTypeReference: // nothing to fix up @@ -6762,9 +7056,9 @@ void Writer::fixUpReferenceFinal(const ObjectFile::Reference* ref, const if ( &ref->getTarget() != NULL ) { //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName()); if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal) { - if ( fOptions.makeCompressedDyldInfo() - && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) { - // lazy pointer is initially set to point directly to weak definition + if ( !fOptions.makeClassicDyldInfo() + && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) { + // when using only compressed dyld info, pointer is initially set to point directly to weak definition LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset()); } else { @@ -6833,6 +7127,15 @@ void Writer::fixUpReferenceFinal(const ObjectFile::Reference* ref, const temp |= (displacement & 0x00FFFFFF); LittleEndian::set32(*((uint32_t*)fixUp), temp); break; + case x86_64::kSectionOffset24: + displacement = ref->getTarget().getSectionOffset(); + if ( (displacement > kSixteenMegLimit) || (displacement < 0) ) + throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName()); + temp = LittleEndian::get32(*((uint32_t*)fixUp)); + temp &= 0xFF000000; + temp |= (displacement & 0x00FFFFFF); + LittleEndian::set32(*((uint32_t*)fixUp), temp); + break; case x86_64::kPCRel32GOTLoad: case x86_64::kPCRel32GOTLoadWeakImport: // if GOT entry was optimized away, change movq instruction to a leaq @@ -6894,7 +7197,7 @@ void Writer::fixUpReferenceFinal(const ObjectFile::Reference* ref, const } else { if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) { - fprintf(stderr, "call out of range from %s (%llX) in %s to %s (%llX) in %s\n", + fprintf(stderr, "reference out of range from %s (%llX) in %s to %s (%llX) in %s\n", inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath()); throw "rel32 out of range"; } @@ -7050,6 +7353,8 @@ void Writer::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, throw "internal linker error, kPointerDiff24 can't be encoded into object files"; case x86_64::kImageOffset32: throw "internal linker error, kImageOffset32 can't be encoded into object files"; + case x86_64::kSectionOffset24: + throw "internal linker error, kSectionOffset24 can't be encoded into object files"; case x86_64::kDtraceTypeReference: case x86_64::kDtraceProbe: // nothing to fix up @@ -7433,8 +7738,10 @@ bool Writer::stubableReference(const ObjectFile::Atom* inAtom, const Object switch ( (arm::ReferenceKinds)kind ) { case arm::kBranch24: case arm::kBranch24WeakImport: + return true; case arm::kThumbBranch22: case arm::kThumbBranch22WeakImport: + fHasThumbBranches = true; return true; case arm::kNoFixUp: case arm::kFollowOn: @@ -7447,6 +7754,7 @@ bool Writer::stubableReference(const ObjectFile::Atom* inAtom, const Object case arm::kDtraceProbeSite: case arm::kDtraceIsEnabledSite: case arm::kDtraceTypeReference: + case arm::kPointerDiff12: return false; } return false; @@ -7704,6 +8012,10 @@ void Writer::scanForAbsoluteReferences() if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) { for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { ObjectFile::Atom* atom = *it; + if ( atom->getContentType() == ObjectFile::Atom::kStub ) + continue; + if ( atom->getContentType() == ObjectFile::Atom::kStubHelper ) + continue; std::vector& references = atom->getReferences(); for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { ObjectFile::Reference* ref = *rit; @@ -7799,11 +8111,12 @@ void Writer::insertDummyStubs() template -void Writer::synthesizeKextGOT() +void Writer::synthesizeKextGOT(const std::vector& existingAtoms, + std::vector& newAtoms) { // walk every atom and reference - for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { - ObjectFile::Atom* atom = *it; + for (std::vector::const_iterator it=existingAtoms.begin(); it != existingAtoms.end(); it++) { + const ObjectFile::Atom* atom = *it; std::vector& references = atom->getReferences(); for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { ObjectFile::Reference* ref = *rit; @@ -7826,6 +8139,7 @@ void Writer::synthesizeKextGOT() if ( pos == fGOTMap.end() ) { nlp = new NonLazyPointerAtom(*this, target); fGOTMap[&target] = nlp; + newAtoms.push_back(nlp); } else { nlp = pos->second; @@ -7845,36 +8159,12 @@ void Writer::synthesizeKextGOT() } } } - - // add non-lazy pointers to fAllAtoms - if ( fAllSynthesizedNonLazyPointers.size() != 0 ) { - ObjectFile::Section* curSection = NULL; - ObjectFile::Atom* prevAtom = NULL; - bool inserted = false; - for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { - ObjectFile::Atom* atom = *it; - ObjectFile::Section* nextSection = atom->getSection(); - if ( nextSection != curSection ) { - if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__data") == 0) ) { - // found end of __data section, insert lazy pointers here - fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end()); - inserted = true; - break; - } - curSection = nextSection; - } - prevAtom = atom; - } - if ( !inserted ) { - throw "can't insert non-lazy pointers, __data section not found"; - } - } - } template -void Writer::synthesizeStubs() +void Writer::synthesizeStubs(const std::vector& existingAtoms, + std::vector& newAtoms) { switch ( fOptions.outputKind() ) { case Options::kObjectFile: @@ -7883,7 +8173,7 @@ void Writer::synthesizeStubs() return; case Options::kKextBundle: // new kext need a synthesized GOT only - synthesizeKextGOT(); + synthesizeKextGOT(existingAtoms, newAtoms); return; case Options::kStaticExecutable: case Options::kDyld: @@ -7895,7 +8185,7 @@ void Writer::synthesizeStubs() } // walk every atom and reference - for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { + for (std::vector::const_iterator it=existingAtoms.begin(); it != existingAtoms.end(); it++) { ObjectFile::Atom* atom = *it; std::vector& references = atom->getReferences(); for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { @@ -8032,184 +8322,35 @@ void Writer::synthesizeStubs() // sort stubs std::sort(fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end(), AtomByNameSorter()); - std::sort(fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end(), AtomByNameSorter()); - // add dummy self-modifying stubs (x86 only) if ( ! fOptions.makeCompressedDyldInfo() ) this->insertDummyStubs(); + // set ordinals so sorting is preserved + uint32_t sortOrder = 0; + for (typename std::vector*>::iterator it=fAllSynthesizedStubs.begin(); it != fAllSynthesizedStubs.end(); it++) + (*it)->setSortingOrdinal(sortOrder++); + std::sort(fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end(), AtomByNameSorter()); // sort lazy pointers std::sort(fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end(), AtomByNameSorter()); + sortOrder = 0; + for (typename std::vector*>::iterator it=fAllSynthesizedLazyPointers.begin(); it != fAllSynthesizedLazyPointers.end(); it++) + (*it)->setSortingOrdinal(sortOrder++); std::sort(fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end(), AtomByNameSorter()); - - - // add stubs to fAllAtoms - if ( fAllSynthesizedStubs.size() != 0 ) { - std::vector textStubs; - std::vector importStubs; - for (typename std::vector*>::iterator sit=fAllSynthesizedStubs.begin(); sit != fAllSynthesizedStubs.end(); ++sit) { - ObjectFile::Atom* stubAtom = *sit; - if ( strcmp(stubAtom->getSegment().getName(), "__TEXT") == 0 ) - textStubs.push_back(stubAtom); - else - importStubs.push_back(stubAtom); - } - // any helper stubs go right after regular stubs - if ( fAllSynthesizedStubHelpers.size() != 0 ) - textStubs.insert(textStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end()); - // insert text stubs right after __text section - ObjectFile::Section* curSection = NULL; - ObjectFile::Atom* prevAtom = NULL; - for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { - ObjectFile::Atom* atom = *it; - ObjectFile::Section* nextSection = atom->getSection(); - if ( nextSection != curSection ) { - if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) { - // found end of __text section, insert stubs here - fAllAtoms->insert(it, textStubs.begin(), textStubs.end()); - break; - } - curSection = nextSection; - } - prevAtom = atom; - } - if ( importStubs.size() != 0 ) { - // insert __IMPORTS stubs right before __LINKEDIT - for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { - ObjectFile::Atom* atom = *it; - ObjectFile::Section* nextSection = atom->getSection(); - if ( nextSection != curSection ) { - // for i386 where stubs are not in __TEXT segment - if ( ((prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__IMPORT") == 0)) - || (strcmp(atom->getSegment().getName(), "__LINKEDIT") == 0) ) { - // insert stubs at end of __IMPORT segment, or before __LINKEDIT - fAllAtoms->insert(it, importStubs.begin(), importStubs.end()); - break; - } - curSection = nextSection; - } - prevAtom = atom; - } - } - } - - - // add non-lazy pointers to fAllAtoms - if ( fAllSynthesizedNonLazyPointers.size() != 0 ) { - ObjectFile::Section* curSection = NULL; - ObjectFile::Atom* prevAtom = NULL; - bool inserted = false; - // first try to insert at end of __nl_symbol_ptr - for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { - ObjectFile::Atom* atom = *it; - ObjectFile::Section* nextSection = atom->getSection(); - if ( nextSection != curSection ) { - if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__nl_symbol_ptr") == 0) ) { - // found end of __nl_symbol_ptr section, insert non-lazy pointers at end of it - fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end()); - inserted = true; - break; - } - curSection = nextSection; - } - prevAtom = atom; - } - if ( !inserted ) { - // next try to insert after __dyld section - for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { - ObjectFile::Atom* atom = *it; - ObjectFile::Section* nextSection = atom->getSection(); - if ( nextSection != curSection ) { - if ( strcmp(atom->getSegment().getName(), "__DATA") == 0 ) { - const char* prevSectionName = (prevAtom != NULL) ? prevAtom->getSectionName() : ""; - if ( (strcmp(prevSectionName, "__dyld") != 0) - && (strcmp(prevSectionName, "__program_vars") != 0) - && (strcmp(prevSectionName, "__mod_init_func") != 0) ) { - // found end of __dyld section, insert non-lazy pointers here - fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end()); - inserted = true; - break; - } - } - } - prevAtom = atom; - } - if ( !inserted ) { - // might not be any __DATA sections, insert after end of __TEXT - for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { - ObjectFile::Atom* atom = *it; - ObjectFile::Section* nextSection = atom->getSection(); - if ( nextSection != curSection ) { - if ( (prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__TEXT") == 0) && (strcmp(atom->getSegment().getName(), "__TEXT") != 0)) { - // found end of __TEXT segment, insert non-lazy pointers at end of it - fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end()); - inserted = true; - break; - } - curSection = nextSection; - } - prevAtom = atom; - } - } - if ( !inserted ) - throw "can't insert non-lazy pointers, __dyld section not found"; - } - } - - // add lazy dylib pointers to fAllAtoms - if ( fAllSynthesizedLazyDylibPointers.size() != 0 ) { - ObjectFile::Section* curSection = NULL; - ObjectFile::Atom* prevAtom = NULL; - bool inserted = false; - for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { - ObjectFile::Atom* atom = *it; - ObjectFile::Section* nextSection = atom->getSection(); - if ( nextSection != curSection ) { - if ( (prevAtom != NULL) && - ( (strcmp(prevAtom->getSectionName(), "__dyld") == 0) - || (strcmp(prevAtom->getSectionName(), "__program_vars") == 0) - || (strcmp(prevAtom->getSectionName(), "__nl_symbol_ptr") == 0) ) ) { - // found end of __dyld section, insert lazy pointers here - fAllAtoms->insert(it, fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end()); - inserted = true; - break; - } - curSection = nextSection; - } - prevAtom = atom; - } - if ( !inserted ) { - throw "can't insert lazy pointers, __dyld section not found"; - } - } - - // add lazy pointers to fAllAtoms - if ( fAllSynthesizedLazyPointers.size() != 0 ) { - ObjectFile::Section* curSection = NULL; - ObjectFile::Atom* prevAtom = NULL; - bool inserted = false; - for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { - ObjectFile::Atom* atom = *it; - ObjectFile::Section* nextSection = atom->getSection(); - if ( nextSection != curSection ) { - if ( (prevAtom != NULL) && - ( (strcmp(prevAtom->getSectionName(), "__dyld") == 0) - || (strcmp(prevAtom->getSectionName(), "__program_vars") == 0) - || (strcmp(prevAtom->getSectionName(), "__nl_symbol_ptr") == 0) ) ) { - // found end of __dyld section, insert lazy pointers here - fAllAtoms->insert(it, fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end()); - inserted = true; - break; - } - curSection = nextSection; - } - prevAtom = atom; - } - if ( !inserted ) { - throw "can't insert lazy pointers, __dyld section not found"; - } - } + // sort non-lazy pointers + std::sort(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), AtomByNameSorter()); + sortOrder = 0; + for (typename std::vector*>::iterator it=fAllSynthesizedNonLazyPointers.begin(); it != fAllSynthesizedNonLazyPointers.end(); it++) + (*it)->setSortingOrdinal(sortOrder++); + std::sort(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), AtomByNameSorter()); + + // tell linker about all synthesized atoms + newAtoms.insert(newAtoms.end(), fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end()); + newAtoms.insert(newAtoms.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end()); + newAtoms.insert(newAtoms.end(), fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end()); + newAtoms.insert(newAtoms.end(), fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end()); + newAtoms.insert(newAtoms.end(), fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end()); } @@ -8253,12 +8394,12 @@ void Writer::synthesizeUnwindInfoTable() if ( atom->beginUnwind() == atom->endUnwind() ) { // be sure to mark that we have no unwind info for stuff in the TEXT segment without unwind info if ( strcmp(atom->getSegment().getName(), "__TEXT") == 0 ) - fUnwindInfoAtom->addUnwindInfo(atom, 0, 0, NULL, NULL); + fUnwindInfoAtom->addUnwindInfo(atom, 0, 0, NULL, NULL, NULL); } else { // atom has unwind for ( ObjectFile::UnwindInfo::iterator uit = atom->beginUnwind(); uit != atom->endUnwind(); ++uit ) { - fUnwindInfoAtom->addUnwindInfo(atom, uit->startOffset, uit->unwindInfo, atom->getLSDA(), atom->getPersonalityPointer()); + fUnwindInfoAtom->addUnwindInfo(atom, uit->startOffset, uit->unwindInfo, atom->getFDE(), atom->getLSDA(), atom->getPersonalityPointer()); } } } @@ -8266,7 +8407,6 @@ void Writer::synthesizeUnwindInfoTable() } - template void Writer::partitionIntoSections() { @@ -8364,43 +8504,38 @@ void Writer::partitionIntoSections() fLoadCommandsSection = currentSectionInfo; fLoadCommandsSegment = currentSegmentInfo; } - if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) ) - currentSectionInfo->fAllLazyPointers = true; - if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) ) - currentSectionInfo->fAllLazyPointers = true; - if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__ld_symbol_ptr") == 0) ) - currentSectionInfo->fAllLazyDylibPointers = true; - if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) ) - currentSectionInfo->fAllNonLazyPointers = true; - if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) ) - currentSectionInfo->fAllNonLazyPointers = true; - if ( (fOptions.outputKind() == Options::kDyld) && (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) ) - currentSectionInfo->fAllNonLazyPointers = true; - if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) ) - currentSectionInfo->fAllStubs = true; - if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) ) - currentSectionInfo->fAllStubs = true; - if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) ) - currentSectionInfo->fAllStubs = true; - if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) ) - currentSectionInfo->fAllStubs = true; - if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub4") == 0) ) - currentSectionInfo->fAllStubs = true; - if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub4") == 0) ) - currentSectionInfo->fAllStubs = true; - if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) ) { - currentSectionInfo->fAllSelfModifyingStubs = true; - currentSectionInfo->fAlignment = 6; // force x86 fast stubs to start on 64-byte boundary - } - if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__stub_helper") == 0) ) - currentSectionInfo->fAllStubHelpers = true; - if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__eh_frame") == 0) ) - currentSectionInfo->fAlignment = __builtin_ctz(sizeof(pint_t)); // always start CFI info pointer aligned - curSection = atom->getSection(); - if ( currentSectionInfo->fAllNonLazyPointers || currentSectionInfo->fAllLazyPointers || currentSectionInfo->fAllLazyDylibPointers - || currentSectionInfo->fAllStubs || currentSectionInfo->fAllSelfModifyingStubs ) { + switch ( atom->getContentType() ) { + case ObjectFile::Atom::kLazyPointer: + currentSectionInfo->fAllLazyPointers = true; + fSymbolTableCommands->needDynamicTable(); + break; + case ObjectFile::Atom::kNonLazyPointer: + currentSectionInfo->fAllNonLazyPointers = true; fSymbolTableCommands->needDynamicTable(); + break; + case ObjectFile::Atom::kLazyDylibPointer: + currentSectionInfo->fAllLazyDylibPointers = true; + break; + case ObjectFile::Atom::kStubHelper: + currentSectionInfo->fAllStubHelpers = true; + break; + case ObjectFile::Atom::kCFIType: + currentSectionInfo->fAlignment = __builtin_ctz(sizeof(pint_t)); // always start CFI info pointer aligned + break; + case ObjectFile::Atom::kStub: + if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) ) { + currentSectionInfo->fAllSelfModifyingStubs = true; + currentSectionInfo->fAlignment = 6; // force x86 fast stubs to start on 64-byte boundary + } + else { + currentSectionInfo->fAllStubs = true; + } + fSymbolTableCommands->needDynamicTable(); + break; + default: + break; } + curSection = atom->getSection(); } // any non-zero fill atoms make whole section marked not-zero-fill if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() ) @@ -8463,13 +8598,13 @@ public: template <> bool Writer::addBranchIslands() { - return this->addPPCBranchIslands(); + return this->createBranchIslands(); } template <> bool Writer::addBranchIslands() { - return this->addPPCBranchIslands(); + return this->createBranchIslands(); } template <> @@ -8489,13 +8624,11 @@ bool Writer::addBranchIslands() template <> bool Writer::addBranchIslands() { - // arm branch islands not (yet) supported - // you can instead compile with -mlong-call - return false; + return this->createBranchIslands(); } template <> -bool Writer::isBranch24Reference(uint8_t kind) +bool Writer::isBranchThatMightNeedIsland(uint8_t kind) { switch (kind) { case ppc::kBranch24: @@ -8506,7 +8639,7 @@ bool Writer::isBranch24Reference(uint8_t kind) } template <> -bool Writer::isBranch24Reference(uint8_t kind) +bool Writer::isBranchThatMightNeedIsland(uint8_t kind) { switch (kind) { case ppc64::kBranch24: @@ -8516,17 +8649,77 @@ bool Writer::isBranch24Reference(uint8_t kind) return false; } +template <> +bool Writer::isBranchThatMightNeedIsland(uint8_t kind) +{ + switch (kind) { + case arm::kBranch24: + case arm::kBranch24WeakImport: + case arm::kThumbBranch22: + case arm::kThumbBranch22WeakImport: + return true; + } + return false; +} + +template <> +uint32_t Writer::textSizeWhenMightNeedBranchIslands() +{ + return 16000000; +} + +template <> +uint32_t Writer::textSizeWhenMightNeedBranchIslands() +{ + return 16000000; +} + +template <> +uint32_t Writer::textSizeWhenMightNeedBranchIslands() +{ + if ( fHasThumbBranches == false ) + return 32000000; // ARM can branch +/- 32MB + else if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) + return 16000000; // thumb2 can branch +/- 16MB + else + return 4000000; // thumb1 can branch +/- 4MB +} + +template <> +uint32_t Writer::maxDistanceBetweenIslands() +{ + return 14*1024*1024; +} + +template <> +uint32_t Writer::maxDistanceBetweenIslands() +{ + return 14*1024*1024; +} + +template <> +uint32_t Writer::maxDistanceBetweenIslands() +{ + if ( fHasThumbBranches == false ) + return 30*1024*1024; + else if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) + return 14*1024*1024; + else + return 3500000; +} + + // // PowerPC can do PC relative branches as far as +/-16MB. // If a branch target is >16MB then we insert one or more // "branch islands" between the branch and its target that -// allows island hoping to the target. +// allows island hopping to the target. // // Branch Island Algorithm // // If the __TEXT segment < 16MB, then no branch islands needed // Otherwise, every 14MB into the __TEXT segment a region is -// added which can contain branch islands. Every out of range +// added which can contain branch islands. Every out-of-range // bl instruction is checked. If it crosses a region, an island // is added to that region with the same target and the bl is // adjusted to target the island instead. @@ -8535,18 +8728,18 @@ bool Writer::isBranch24Reference(uint8_t kind) // could grow the __TEXT enough that other previously in-range // bl branches could be pushed out of range. We reduce the // probability this could happen by placing the ranges every -// 15MB which means the region would have to be 1MB (256K islands) +// 14MB which means the region would have to be 2MB (512,000 islands) // before any branches could be pushed out of range. // template -bool Writer::addPPCBranchIslands() +bool Writer::createBranchIslands() { bool log = false; bool result = false; // Can only possibly need branch islands if __TEXT segment > 16M - if ( fLoadCommandsSegment->fSize > 16000000 ) { + if ( fLoadCommandsSegment->fSize > textSizeWhenMightNeedBranchIslands() ) { if ( log) fprintf(stderr, "ld: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize); - const uint32_t kBetweenRegions = 14*1024*1024; // place regions of islands every 14MB in __text section + const uint32_t kBetweenRegions = maxDistanceBetweenIslands(); // place regions of islands every 14MB in __text section SectionInfo* textSection = NULL; for (std::vector::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) { if ( strcmp((*it)->fSectionName, "__text") == 0 ) { @@ -8560,7 +8753,7 @@ bool Writer::addPPCBranchIslands() AtomToIsland regionsMap[kIslandRegionsCount]; std::vector regionsIslands[kIslandRegionsCount]; unsigned int islandCount = 0; - if ( log) fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount); + if (log) fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount); // create islands for branch references that are out of range for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { @@ -8568,68 +8761,62 @@ bool Writer::addPPCBranchIslands() std::vector& references = atom->getReferences(); for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { ObjectFile::Reference* ref = *rit; - if ( this->isBranch24Reference(ref->getKind()) ) { + if ( this->isBranchThatMightNeedIsland(ref->getKind()) ) { ObjectFile::Atom& target = ref->getTarget(); int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset(); int64_t dstAddr = target.getAddress() + ref->getTargetOffset(); int64_t displacement = dstAddr - srcAddr; TargetAndOffset finalTargetAndOffset = { &target, ref->getTargetOffset() }; - const int64_t kFifteenMegLimit = kBetweenRegions; - if ( displacement > kFifteenMegLimit ) { + const int64_t kBranchLimit = kBetweenRegions; + if ( displacement > kBranchLimit ) { // create forward branch chain ObjectFile::Atom* nextTarget = ⌖ - uint64_t nextTargetOffset = ref->getTargetOffset(); for (int i=kIslandRegionsCount-1; i >=0 ; --i) { AtomToIsland* region = ®ionsMap[i]; int64_t islandRegionAddr = kBetweenRegions * (i+1) + textSection->getBaseAddress(); if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) { AtomToIsland::iterator pos = region->find(finalTargetAndOffset); if ( pos == region->end() ) { - BranchIslandAtom* island = new BranchIslandAtom(*this, target.getDisplayName(), i, *nextTarget, nextTargetOffset); + BranchIslandAtom* island = new BranchIslandAtom(*this, target.getDisplayName(), i, *nextTarget, *finalTargetAndOffset.atom, finalTargetAndOffset.offset); island->setSection(textSection); (*region)[finalTargetAndOffset] = island; if (log) fprintf(stderr, "added island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName()); regionsIslands[i].push_back(island); ++islandCount; nextTarget = island; - nextTargetOffset = 0; } else { nextTarget = pos->second; - nextTargetOffset = 0; } } } if (log) fprintf(stderr, "using island %s for branch to %s from %s\n", nextTarget->getDisplayName(), target.getDisplayName(), atom->getDisplayName()); - ref->setTarget(*nextTarget, nextTargetOffset); + ref->setTarget(*nextTarget, 0); } - else if ( displacement < (-kFifteenMegLimit) ) { + else if ( displacement < (-kBranchLimit) ) { // create back branching chain ObjectFile::Atom* prevTarget = ⌖ - uint64_t prevTargetOffset = ref->getTargetOffset(); for (int i=0; i < kIslandRegionsCount ; ++i) { AtomToIsland* region = ®ionsMap[i]; int64_t islandRegionAddr = kBetweenRegions * (i+1); if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) { AtomToIsland::iterator pos = region->find(finalTargetAndOffset); if ( pos == region->end() ) { - BranchIslandAtom* island = new BranchIslandAtom(*this, target.getDisplayName(), i, *prevTarget, prevTargetOffset); + BranchIslandAtom* island = new BranchIslandAtom(*this, target.getDisplayName(), i, *prevTarget, *finalTargetAndOffset.atom, finalTargetAndOffset.offset); island->setSection(textSection); (*region)[finalTargetAndOffset] = island; if (log) fprintf(stderr, "added back island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName()); regionsIslands[i].push_back(island); ++islandCount; prevTarget = island; - prevTargetOffset = 0; } else { prevTarget = pos->second; - prevTargetOffset = 0; } } } if (log) fprintf(stderr, "using back island %s for %s\n", prevTarget->getDisplayName(), atom->getDisplayName()); - ref->setTarget(*prevTarget, prevTargetOffset); + ref->setTarget(*prevTarget, 0); } } } @@ -8657,6 +8844,7 @@ bool Writer::addPPCBranchIslands() uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2); sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) ); islandAtom->setSectionOffset(sectionOffset); + if ( log ) fprintf(stderr, "assigning __text offset 0x%08llx to %s\n", sectionOffset, islandAtom->getDisplayName()); sectionOffset += islandAtom->getSize(); } ++regionIndex; @@ -8678,6 +8866,7 @@ bool Writer::addPPCBranchIslands() uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2); sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) ); islandAtom->setSectionOffset(sectionOffset); + if ( log ) fprintf(stderr, "assigning __text offset 0x%08llx to %s\n", sectionOffset, islandAtom->getDisplayName()); sectionOffset += islandAtom->getSize(); } } @@ -8712,6 +8901,7 @@ void Writer::adjustLoadCommandsAndPadding() offset += atomSize; fLoadCommandsSection->fSize = offset; } + const uint32_t sizeOfLoadCommandsPlusHeader = offset + sizeof(macho_header); std::vector& sectionInfos = fLoadCommandsSegment->fSections; const int sectionCount = sectionInfos.size(); @@ -8736,11 +8926,6 @@ void Writer::adjustLoadCommandsAndPadding() // mach-o MH_PRELOAD files need no padding between load commands and first section paddingSize = 0; } - else if ( fOptions.makeEncryptable() ) { - // want load commands to end on a page boundary, so __text starts on page boundary - paddingSize = 4096 - ((totalSizeOfTEXTLessHeaderAndLoadCommands+fOptions.minimumHeaderPad()) % 4096) + fOptions.minimumHeaderPad(); - fEncryptionLoadCommand->setStartEncryptionOffset(totalSizeOfTEXTLessHeaderAndLoadCommands+paddingSize); - } else { // work backwards from end of segment and lay out sections so that extra room goes to padding atom uint64_t addr = 0; @@ -8769,6 +8954,19 @@ void Writer::adjustLoadCommandsAndPadding() int extraPages = (minPad - paddingSize + fOptions.segmentAlignment() - 1)/fOptions.segmentAlignment(); paddingSize += extraPages * fOptions.segmentAlignment(); } + + if ( fOptions.makeEncryptable() ) { + // load commands must be on a separate non-encrypted page + int loadCommandsPage = (sizeOfLoadCommandsPlusHeader + minPad)/fOptions.segmentAlignment(); + int textPage = (sizeOfLoadCommandsPlusHeader + paddingSize)/fOptions.segmentAlignment(); + if ( loadCommandsPage == textPage ) { + paddingSize += fOptions.segmentAlignment(); + textPage += 1; + } + + //paddingSize = 4096 - ((totalSizeOfTEXTLessHeaderAndLoadCommands+fOptions.minimumHeaderPad()) % 4096) + fOptions.minimumHeaderPad(); + fEncryptionLoadCommand->setStartEncryptionOffset(textPage*fOptions.segmentAlignment()); + } } // adjust atom size and update section size @@ -8874,7 +9072,6 @@ void Writer::assignFileOffsets() else { address = ( (address+alignment-1) & (-alignment) ); } - // adjust file offset to match address if ( prevSection != NULL ) { if ( virtualSectionOccupyAddressSpace || !prevSection->fVirtualSection ) @@ -9679,7 +9876,7 @@ void DylibLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const cmd->set_cmd(LC_LAZY_LOAD_DYLIB); else if ( fInfo.options.fWeakImport || autoWeakLoadDylib ) cmd->set_cmd(LC_LOAD_WEAK_DYLIB); - else if ( fInfo.options.fReExport && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) ) + else if ( fInfo.options.fReExport && fWriter.fOptions.useSimplifiedDylibReExports() ) cmd->set_cmd(LC_REEXPORT_DYLIB); else cmd->set_cmd(LC_LOAD_DYLIB); @@ -9988,10 +10185,15 @@ void LoadCommandsPaddingAtom::setSize(uint64_t newSize) template void UnwindInfoAtom::addUnwindInfo(ObjectFile::Atom* func, uint32_t offset, uint32_t encoding, - ObjectFile::Reference* lsdaRef, ObjectFile::Atom* personalityPointer) + ObjectFile::Reference* fdeRef, ObjectFile::Reference* lsdaRef, + ObjectFile::Atom* personalityPointer) { Info info; info.func = func; + if ( fdeRef != NULL ) + info.fde = &fdeRef->getTarget(); + else + info.fde = NULL; if ( lsdaRef != NULL ) { info.lsda = &lsdaRef->getTarget(); info.lsdaOffset = lsdaRef->getTargetOffset(); @@ -10007,6 +10209,24 @@ void UnwindInfoAtom::addUnwindInfo(ObjectFile::Atom* func, uint32_t offset, u // encoding, info.lsda, info.lsdaOffset, personalityPointer, func->getDisplayName()); } +template <> +bool UnwindInfoAtom::encodingMeansUseDwarf(compact_unwind_encoding_t encoding) +{ + return ( (encoding & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF); +} + +template <> +bool UnwindInfoAtom::encodingMeansUseDwarf(compact_unwind_encoding_t encoding) +{ + return ( (encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF); +} + +template +bool UnwindInfoAtom::encodingMeansUseDwarf(compact_unwind_encoding_t encoding) +{ + return false; +} + template void UnwindInfoAtom::compressDuplicates(std::vector& uniqueInfos) @@ -10020,9 +10240,10 @@ void UnwindInfoAtom::compressDuplicates(std::vector& uniqueInfos) last.personalityPointer = NULL; last.encoding = 0xFFFFFFFF; for(typename std::vector::iterator it=fInfos.begin(); it != fInfos.end(); ++it) { - Info newInfo = *it; + Info& newInfo = *it; + bool newNeedsDwarf = encodingMeansUseDwarf(newInfo.encoding); // remove infos which have same encoding and personalityPointer as last one - if ( (newInfo.encoding != last.encoding) || (newInfo.personalityPointer != last.personalityPointer) + if ( newNeedsDwarf || (newInfo.encoding != last.encoding) || (newInfo.personalityPointer != last.personalityPointer) || (newInfo.lsda != NULL) || (last.lsda != NULL) ) { uniqueInfos.push_back(newInfo); } @@ -10038,6 +10259,9 @@ void UnwindInfoAtom::findCommonEncoding(const std::vector& uniqueInfos, std::map encodingsUsed; unsigned int mostCommonEncodingUsageCount = 0; for(typename std::vector::const_iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) { + // never put dwarf into common table + if ( encodingMeansUseDwarf(it->encoding) ) + continue; std::map::iterator pos = encodingsUsed.find(it->encoding); if ( pos == encodingsUsed.end() ) { encodingsUsed[it->encoding] = 1; @@ -10113,7 +10337,8 @@ unsigned int UnwindInfoAtom::makeRegularSecondLevelPage(const std::vector::makeCompressedSecondLevelPage(const std::vector< uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd) { const bool log = false; + if (log) fprintf(stderr, "makeCompressedSecondLevelPage(pageSize=%u, endIndex=%u)\n", pageSize, endIndex); // first pass calculates how many compressed entries we could fit in this sized page // keep adding entries to page until: // 1) encoding table plus entry table plus header exceed page size @@ -10149,14 +10375,20 @@ unsigned int UnwindInfoAtom::makeCompressedSecondLevelPage(const std::vector< encodingIndex = pos->second; } else { - std::map::iterator ppos = pageSpecificEncodings.find(info.encoding); + // no commmon entry, so add one on this page + uint32_t encoding = info.encoding; + if ( encodingMeansUseDwarf(encoding) ) { + // make unique pseudo encoding so this dwarf will gets is own encoding entry slot + encoding += (index+1); + } + std::map::iterator ppos = pageSpecificEncodings.find(encoding); if ( ppos != pageSpecificEncodings.end() ) { encodingIndex = pos->second; } else { encodingIndex = commonEncodings.size() + pageSpecificEncodings.size(); if ( encodingIndex <= 255 ) { - pageSpecificEncodings[info.encoding] = encodingIndex; + pageSpecificEncodings[encoding] = encodingIndex; } else { canDo = false; // case 3) @@ -10178,52 +10410,72 @@ unsigned int UnwindInfoAtom::makeCompressedSecondLevelPage(const std::vector< ++entryCount; } // check room for entry - if ( (pageSpecificEncodings.size()+entryCount) > space4 ) { + if ( (pageSpecificEncodings.size()+entryCount) >= space4 ) { canDo = false; // case 1) --entryCount; if (log) fprintf(stderr, "end of compressed page with %u entries because full\n", entryCount); } + //if (log) fprintf(stderr, "space4=%d, pageSpecificEncodings.size()=%ld, entryCount=%d\n", space4, pageSpecificEncodings.size(), entryCount); } - // sanity check that we fit more entries into this page than a regular page would hold - const int compressPageUsed = sizeof(unwind_info_compressed_second_level_page_header) + // check for cases where it would be better to use a regular (non-compressed) page + const unsigned int compressPageUsed = sizeof(unwind_info_compressed_second_level_page_header) + pageSpecificEncodings.size()*sizeof(uint32_t) + entryCount*sizeof(uint32_t); - const int regularEntriesPerPage = (compressPageUsed - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry); - if ( entryCount < regularEntriesPerPage ) { - return makeRegularSecondLevelPage(uniqueInfos, pageSize, endIndex, pageEnd); + if ( (compressPageUsed < (pageSize-4) && (index >= 0) ) ) { + const int regularEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry); + if ( entryCount < regularEntriesPerPage ) { + return makeRegularSecondLevelPage(uniqueInfos, pageSize, endIndex, pageEnd); + } } - + + // check if we need any padding because adding another entry would take 8 bytes but only have room for 4 + uint32_t pad = 0; + if ( compressPageUsed == (pageSize-4) ) + pad = 4; + // second pass fills in page - uint8_t* pageStart = pageEnd - compressPageUsed; + uint8_t* pageStart = pageEnd - compressPageUsed - pad; macho_unwind_info_compressed_second_level_page_header

* page = (macho_unwind_info_compressed_second_level_page_header

*)pageStart; page->set_kind(UNWIND_SECOND_LEVEL_COMPRESSED); page->set_entryPageOffset(sizeof(macho_unwind_info_compressed_second_level_page_header

)); page->set_entryCount(entryCount); page->set_encodingsPageOffset(page->entryPageOffset()+entryCount*sizeof(uint32_t)); page->set_encodingsCount(pageSpecificEncodings.size()); + uint32_t* const encodingsArray = (uint32_t*)&pageStart[page->encodingsPageOffset()]; // fill in entry table uint32_t* const entiresArray = (uint32_t*)&pageStart[page->entryPageOffset()]; ObjectFile::Atom* firstFunc = uniqueInfos[endIndex-entryCount].func; for(unsigned int i=endIndex-entryCount; i < endIndex; ++i) { const Info& info = uniqueInfos[i]; uint8_t encodingIndex; - std::map::const_iterator pos = commonEncodings.find(info.encoding); - if ( pos != commonEncodings.end() ) - encodingIndex = pos->second; - else - encodingIndex = pageSpecificEncodings[info.encoding]; + if ( encodingMeansUseDwarf(info.encoding) ) { + // dwarf entries are always in page specific encodings + encodingIndex = pageSpecificEncodings[info.encoding+i]; + } + else { + std::map::const_iterator pos = commonEncodings.find(info.encoding); + if ( pos != commonEncodings.end() ) + encodingIndex = pos->second; + else + encodingIndex = pageSpecificEncodings[info.encoding]; + } uint32_t entryIndex = i - endIndex + entryCount; A::P::E::set32(entiresArray[entryIndex], encodingIndex << 24); - CompressedFixUp fixup; - fixup.contentPointer = (uint8_t*)(&entiresArray[entryIndex]); - fixup.func = info.func; - fixup.fromFunc = firstFunc; - fCompressedFixUps.push_back(fixup); + CompressedFixUp funcStartFixUp; + funcStartFixUp.contentPointer = (uint8_t*)(&entiresArray[entryIndex]); + funcStartFixUp.func = info.func; + funcStartFixUp.fromFunc = firstFunc; + fCompressedFixUps.push_back(funcStartFixUp); + if ( encodingMeansUseDwarf(info.encoding) ) { + CompressedEncodingFixUp dwarfStartFixup; + dwarfStartFixup.contentPointer = (uint8_t*)(&encodingsArray[encodingIndex-commonEncodings.size()]); + dwarfStartFixup.fde = info.fde; + fCompressedEncodingFixUps.push_back(dwarfStartFixup); + } } // fill in encodings table - uint32_t* const encodingsArray = (uint32_t*)&pageStart[page->encodingsPageOffset()]; - for(std::map::iterator it = pageSpecificEncodings.begin(); it != pageSpecificEncodings.end(); ++it) { + for(std::map::const_iterator it = pageSpecificEncodings.begin(); it != pageSpecificEncodings.end(); ++it) { A::P::E::set32(encodingsArray[it->second-commonEncodings.size()], it->first); } @@ -10271,8 +10523,8 @@ void UnwindInfoAtom::generate() fPagesSize = 0; if ( fPagesContentForDelete == NULL ) throw "could not allocate space for compact unwind info"; - ObjectFile::Atom* secondLevelFirstFuncs[pageCount]; - uint8_t* secondLevelPagesStarts[pageCount]; + ObjectFile::Atom* secondLevelFirstFuncs[pageCount*3]; + uint8_t* secondLevelPagesStarts[pageCount*3]; // make last second level page smaller so that all other second level pages can be page aligned uint32_t maxLastPageSize = unwindSectionInfo->fFileOffset % 4096; @@ -10366,12 +10618,18 @@ void UnwindInfoAtom::generate() for (typename std::vector::iterator it = fRegFixUps.begin(); it != fRegFixUps.end(); ++it) { uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize; fReferences.push_back(new WriterReference(offset, A::kImageOffset32, it->func)); + if ( it->fde != NULL ) + fReferences.push_back(new WriterReference(offset+4, A::kSectionOffset24, it->fde)); } // make references for compressed second level entries for (typename std::vector::iterator it = fCompressedFixUps.begin(); it != fCompressedFixUps.end(); ++it) { uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize; fReferences.push_back(new WriterReference(offset, A::kPointerDiff24, it->func, 0, it->fromFunc, 0)); } + for (typename std::vector::iterator it = fCompressedEncodingFixUps.begin(); it != fCompressedEncodingFixUps.end(); ++it) { + uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize; + fReferences.push_back(new WriterReference(offset, A::kSectionOffset24, it->fde)); + } // update section record with new size unwindSectionInfo->fSize = this->getSize(); @@ -10670,27 +10928,48 @@ const char* StringsLinkEditAtom::stringForIndex(int32_t index) const template -BranchIslandAtom::BranchIslandAtom(Writer& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset) - : WriterAtom(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset) +BranchIslandAtom::BranchIslandAtom(Writer& writer, const char* name, int islandRegion, ObjectFile::Atom& target, + ObjectFile::Atom& finalTarget, uint32_t finalTargetOffset) + : WriterAtom(writer, Segment::fgTextSegment), fTarget(target), fFinalTarget(finalTarget), fFinalTargetOffset(finalTargetOffset) { - char* buf = new char[strlen(name)+32]; - if ( targetOffset == 0 ) { + if ( finalTargetOffset == 0 ) { if ( islandRegion == 0 ) - sprintf(buf, "%s$island", name); + asprintf((char**)&fName, "%s$island", name); else - sprintf(buf, "%s$island_%d", name, islandRegion); + asprintf((char**)&fName, "%s$island$%d", name, islandRegion+1); } else { - sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion); + asprintf((char**)&fName, "%s_plus_%d$island$%d", name, finalTargetOffset, islandRegion); + } + + if ( finalTarget.isThumb() ) { + if ( writer.fOptions.preferSubArchitecture() && writer.fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) { + fIslandKind = kBranchIslandToThumb2; + } + else { + fIslandKind = kBranchIslandToThumb1; + } + } + else { + fIslandKind = kBranchIslandToARM; } - fName = buf; } template <> void BranchIslandAtom::copyRawContent(uint8_t buffer[]) const { - int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress(); + int64_t displacement; + const int64_t bl_sixteenMegLimit = 0x00FFFFFF; + if ( fTarget.getContentType() == ObjectFile::Atom::kBranchIsland ) { + displacement = getFinalTargetAdress() - this->getAddress(); + if ( (displacement > bl_sixteenMegLimit) && (displacement < (-bl_sixteenMegLimit)) ) { + displacement = fTarget.getAddress() - this->getAddress(); + } + } + else { + displacement = fTarget.getAddress() + fFinalTargetOffset - this->getAddress(); + } int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC); OSWriteBigInt32(buffer, 0, branchInstruction); } @@ -10698,11 +10977,123 @@ void BranchIslandAtom::copyRawContent(uint8_t buffer[]) const template <> void BranchIslandAtom::copyRawContent(uint8_t buffer[]) const { - int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress(); + int64_t displacement; + const int64_t bl_sixteenMegLimit = 0x00FFFFFF; + if ( fTarget.getContentType() == ObjectFile::Atom::kBranchIsland ) { + displacement = getFinalTargetAdress() - this->getAddress(); + if ( (displacement > bl_sixteenMegLimit) && (displacement < (-bl_sixteenMegLimit)) ) { + displacement = fTarget.getAddress() - this->getAddress(); + } + } + else { + displacement = fTarget.getAddress() + fFinalTargetOffset - this->getAddress(); + } int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC); OSWriteBigInt32(buffer, 0, branchInstruction); } +template <> +void BranchIslandAtom::copyRawContent(uint8_t buffer[]) const +{ + const bool log = false; + switch ( fIslandKind ) { + case kBranchIslandToARM: + { + int64_t displacement; + // an ARM branch can branch farther than a thumb branch. The branch + // island generation was conservative and put islands every thumb + // branch distance apart. Check to see if this is a an island + // hopping branch that could be optimized to go directly to target. + if ( fTarget.getContentType() == ObjectFile::Atom::kBranchIsland ) { + displacement = getFinalTargetAdress() - this->getAddress() - 8; + if ( (displacement < 33554428LL) && (displacement > (-33554432LL)) ) { + // can skip branch island and jump straight to target + if (log) fprintf(stderr, "%s: optimized jump to final target at 0x%08llX, thisAddr=0x%08llX\n", fName, getFinalTargetAdress(), this->getAddress()); + } + else { + // ultimate target is too far, jump to island + displacement = fTarget.getAddress() - this->getAddress() - 8; + if (log) fprintf(stderr, "%s: jump to branch island at 0x%08llX\n", fName, fTarget.getAddress()); + } + } + else { + // target of island is ultimate target + displacement = fTarget.getAddress() + fFinalTargetOffset - this->getAddress() - 8; + if (log) fprintf(stderr, "%s: jump to target at 0x%08llX\n", fName, fTarget.getAddress()); + } + uint32_t imm24 = (displacement >> 2) & 0x00FFFFFF; + int32_t branchInstruction = 0xEA000000 | imm24; + OSWriteLittleInt32(buffer, 0, branchInstruction); + } + break; + case kBranchIslandToThumb2: + { + int64_t displacement; + // an ARM branch can branch farther than a thumb branch. The branch + // island generation was conservative and put islands every thumb + // branch distance apart. Check to see if this is a an island + // hopping branch that could be optimized to go directly to target. + if ( fTarget.getContentType() == ObjectFile::Atom::kBranchIsland ) { + displacement = getFinalTargetAdress() - this->getAddress() - 4; + if ( (displacement < 16777214) && (displacement > (-16777216LL)) ) { + // can skip branch island and jump straight to target + if (log) fprintf(stderr, "%s: optimized jump to final target at 0x%08llX, thisAddr=0x%08llX\n", fName, getFinalTargetAdress(), this->getAddress()); + } + else { + // ultimate target is too far, jump to island + displacement = fTarget.getAddress() - this->getAddress() - 4; + if (log) fprintf(stderr, "%s: jump to branch island at 0x%08llX\n", fName, fTarget.getAddress()); + } + } + else { + // target of island is ultimate target + displacement = fTarget.getAddress() + fFinalTargetOffset - this->getAddress() - 4; + if (log) fprintf(stderr, "%s: jump to target at 0x%08llX\n", fName, fTarget.getAddress()); + } + if ( (displacement > 16777214) || (displacement < (-16777216LL)) ) { + throwf("internal branch island error: thumb2 b/bx out of range (%lld max is +/-16M) from %s to %s in %s", + displacement, this->getDisplayName(), + fTarget.getDisplayName(), fTarget.getFile()->getPath()); + } + // The instruction is really two instructions: + // The lower 16 bits are the first instruction, which contains the high + // 11 bits of the displacement. + // The upper 16 bits are the second instruction, which contains the low + // 11 bits of the displacement, as well as differentiating bl and blx. + uint32_t s = (uint32_t)(displacement >> 24) & 0x1; + uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1; + uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1; + uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF; + uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF; + uint32_t j1 = (i1 == s); + uint32_t j2 = (i2 == s); + uint32_t opcode = 0x9000F000; + uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11; + uint32_t firstDisp = (s << 10) | imm10; + uint32_t newInstruction = opcode | (nextDisp << 16) | firstDisp; + //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n", + // s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName()); + OSWriteLittleInt32(buffer, 0, newInstruction); + } + break; + case kBranchIslandToThumb1: + { + // There is no large displacement thumb1 branch instruction. + // Instead use ARM instructions that can jump to thumb. + // we use a 32-bit displacement, so we can directly jump to target which means no island hopping + int64_t displacement = getFinalTargetAdress() - (this->getAddress() + 12); + if ( fFinalTarget.isThumb() ) + displacement |= 1; + if (log) fprintf(stderr, "%s: 4 ARM instruction jump to final target at 0x%08llX\n", fName, getFinalTargetAdress()); + OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 4 + OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip + OSWriteLittleInt32(&buffer[ 8], 0, 0xe12fff1c); // bx ip + OSWriteLittleInt32(&buffer[12], 0, displacement); // .long target-this + } + break; + }; +} + template <> uint64_t BranchIslandAtom::getSize() const { @@ -10715,6 +11106,20 @@ uint64_t BranchIslandAtom::getSize() const return 4; } +template <> +uint64_t BranchIslandAtom::getSize() const +{ + switch ( fIslandKind ) { + case kBranchIslandToARM: + return 4; + case kBranchIslandToThumb1: + return 16; + case kBranchIslandToThumb2: + return 4; + }; + throw "internal error: no ARM branch island kind"; +} + template @@ -11118,7 +11523,7 @@ void CompressedBindingInfoLinkEditAtom::encode() std::vector mid; const SegmentInfo* currentSegment = NULL; unsigned int segIndex = 0; - int ordinal = 0; + int ordinal = 0x80000000; const char* symbolName = NULL; uint8_t type = 0; uint64_t address = (uint64_t)(-1); @@ -11222,10 +11627,12 @@ void CompressedBindingInfoLinkEditAtom::encode() p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED; p->operand1 = p->operand1/sizeof(pint_t); } + else if ( (p->opcode == BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB) && (p->operand1 <= 15) ) { + p->opcode = BIND_OPCODE_SET_DYLIB_ORDINAL_IMM; + } } dst->opcode = BIND_OPCODE_DONE; - // convert to compressed encoding const static bool log = false; fEncodedData.reserve(info.size()*2); diff --git a/src/ld/ObjectFile.h b/src/ld/ObjectFile.h index 87396fb..7bba72a 100644 --- a/src/ld/ObjectFile.h +++ b/src/ld/ObjectFile.h @@ -66,7 +66,7 @@ public: fForFinalLinkedImage(false), fNoEHLabels(false), fForStatic(false), fForDyld(false), fMakeTentativeDefinitionsReal(false), fWhyLoad(false), fRootSafe(false), fSetuidSafe(false),fDebugInfoStripping(kDebugInfoFull), fImplicitlyLinkPublicDylibs(true), - fAddCompactUnwindEncoding(false), + fAddCompactUnwindEncoding(true), fWarnCompactUnwind(false), fRemoveDwarfUnwindIfCompactExists(false), fMakeCompressedDyldInfo(false), @@ -77,7 +77,7 @@ public: fTraceOutputFile(NULL), fMacVersionMin(kMinMacVersionUnset), fIPhoneVersionMin(kMinIPhoneVersionUnset) {} enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull }; enum MacVersionMin { kMinMacVersionUnset, k10_1, k10_2, k10_3, k10_4, k10_5, k10_6 }; - enum IPhoneVersionMin { kMinIPhoneVersionUnset, k2_0, k2_1, k2_2, k3_0 }; + enum IPhoneVersionMin { kMinIPhoneVersionUnset, k2_0, k3_0, k3_1 }; struct AliasPair { const char* realName; @@ -282,7 +282,8 @@ class Atom public: enum Scope { scopeTranslationUnit, scopeLinkageUnit, scopeGlobal }; enum DefinitionKind { kRegularDefinition, kWeakDefinition, kTentativeDefinition, kExternalDefinition, kExternalWeakDefinition, kAbsoluteSymbol }; - enum ContentType { kUnclassifiedType, kCStringType, kCFIType, kLSDAType, kSectionStart, kSectionEnd }; + enum ContentType { kUnclassifiedType, kCStringType, kCFIType, kLSDAType, kSectionStart, kSectionEnd, kBranchIsland, + kLazyPointer, kStub, kNonLazyPointer, kLazyDylibPointer, kStubHelper }; enum SymbolTableInclusion { kSymbolTableNotIn, kSymbolTableIn, kSymbolTableInAndNeverStrip, kSymbolTableInAsAbsolute }; virtual Reader* getFile() const = 0; @@ -310,6 +311,7 @@ public: virtual UnwindInfo::iterator beginUnwind() { return NULL; } virtual UnwindInfo::iterator endUnwind() { return NULL; } virtual Reference* getLSDA() { return NULL; } + virtual Reference* getFDE() { return NULL; } virtual Atom* getPersonalityPointer() { return NULL; } uint64_t getSectionOffset() const { return fSectionOffset; } diff --git a/src/ld/Options.cpp b/src/ld/Options.cpp index 58bb74c..6521abe 100644 --- a/src/ld/Options.cpp +++ b/src/ld/Options.cpp @@ -103,7 +103,8 @@ Options::Options(int argc, const char* argv[]) fDeadStripDylibs(false), fAllowTextRelocs(false), fWarnTextRelocs(false), fUsingLazyDylibLinking(false), fEncryptable(true), fOrderData(true), fMarkDeadStrippableDylib(false), - fMakeClassicDyldInfo(true), fMakeCompressedDyldInfo(true), fAllowCpuSubtypeMismatches(false), fSaveTempFiles(false) + fMakeClassicDyldInfo(true), fMakeCompressedDyldInfo(true), fAllowCpuSubtypeMismatches(false), + fUseSimplifiedDylibReExports(false), fSaveTempFiles(false) { this->checkForClassic(argc, argv); this->parsePreCommandLineEnvironmentSettings(); @@ -1261,41 +1262,24 @@ void Options::setIPhoneVersionMin(const char* version) { if ( version == NULL ) throw "-iphoneos_version_min argument missing"; - - if ( strncmp(version, "1.", 2) == 0 ) { - warning("pre-2.0 iPhone OS version not supported"); + if ( ! isdigit(version[0]) ) + throw "-iphoneos_version_min argument is not a number"; + if ( version[1] != '.' ) + throw "-iphoneos_version_min argument is missing period as second character"; + if ( ! isdigit(version[2]) ) + throw "-iphoneos_version_min argument is not a number"; + + if ( version[0] == '2' ) fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_0; - } - else if ( strncmp(version, "2.", 2) == 0 ) { - int num = version[2] - '0'; - switch ( num ) { - case 0: - fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_0; - break; - case 1: - fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_1; - break; - case 2: - fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_2; - break; - default: - fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_2; - break; - } - } - else if ( strncmp(version, "3.", 2) == 0 ) { - int num = version[2] - '0'; - switch ( num ) { - case 0: - fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k3_0; - break; - default: - fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k3_0; - break; - } - } + else if ( (version[0] == '3') && (version[2] == '0') ) + fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_0; + else if ( (version[0] == '3') && (version[2] >= '1') ) + fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k3_1; + else if ( (version[0] >= '4') ) + fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k3_1; else { - warning("unknown option to -iphoneos_version_min, not 2.x or 3.x"); + fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_0; + warning("unknown option to -iphoneos_version_min, not 2.x, 3.x, or 4.x"); } } @@ -3006,7 +2990,7 @@ void Options::reconfigureDefaults() // determine if info for shared region should be added if ( fOutputKind == Options::kDynamicLibrary ) { - if ( minOS(ObjectFile::ReaderOptions::k10_5, ObjectFile::ReaderOptions::k3_0) ) + if ( minOS(ObjectFile::ReaderOptions::k10_5, ObjectFile::ReaderOptions::k3_1) ) if ( !fPrebind ) if ( (strncmp(this->installPath(), "/usr/lib/", 9) == 0) || (strncmp(this->installPath(), "/System/Library/", 16) == 0) ) @@ -3091,7 +3075,9 @@ void Options::reconfigureDefaults() break; } - // only use compressed LINKEDIT for x86_64 and i386 + // only use compressed LINKEDIT for: + // x86_64 and i386 on Mac OS X 10.6 or later + // arm on iPhoneOS 3.1 or later if ( fMakeCompressedDyldInfo ) { switch (fArchitecture) { case CPU_TYPE_I386: @@ -3101,13 +3087,19 @@ void Options::reconfigureDefaults() else if ( fReaderOptions.fMacVersionMin < ObjectFile::ReaderOptions::k10_5 ) fMakeCompressedDyldInfo = false; break; - case CPU_TYPE_POWERPC: case CPU_TYPE_ARM: + if ( fReaderOptions.fIPhoneVersionMin >= ObjectFile::ReaderOptions::k3_1 ) + fMakeClassicDyldInfo = false; + else if ( fReaderOptions.fIPhoneVersionMin < ObjectFile::ReaderOptions::k3_1 ) + fMakeCompressedDyldInfo = false; + break; + case CPU_TYPE_POWERPC: case CPU_TYPE_POWERPC64: default: fMakeCompressedDyldInfo = false; } } + // only use compressed LINKEDIT for final linked images if ( fMakeCompressedDyldInfo ) { @@ -3134,7 +3126,27 @@ void Options::reconfigureDefaults() // only final linked images can not optimize zero fill sections if ( fOutputKind == Options::kObjectFile ) fReaderOptions.fOptimizeZeroFill = true; - + + // only dynamic final linked images should warn about use of commmons + if ( fWarnCommons ) { + switch ( fOutputKind ) { + case Options::kDynamicExecutable: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + break; + case Options::kPreload: + case Options::kStaticExecutable: + case Options::kObjectFile: + case Options::kDyld: + case Options::kKextBundle: + fWarnCommons = false; + break; + } + } + + // Mac OS X 10.5 and iPhoneOS 2.0 support LC_REEXPORT_DYLIB + if ( minOS(ObjectFile::ReaderOptions::k10_5, ObjectFile::ReaderOptions::k2_0) ) + fUseSimplifiedDylibReExports = true; } void Options::checkIllegalOptionCombinations() @@ -3231,12 +3243,12 @@ void Options::checkIllegalOptionCombinations() warning("custom stack placement overlaps and will disable shared region"); break; case CPU_TYPE_ARM: - if ( fStackSize > 0xFFFFFFFF ) - throw "-stack_size must be < 4G for 32-bit processes"; + if ( fStackSize > 0x2F000000 ) + throw "-stack_size must be < 752MB"; if ( fStackAddr == 0 ) - fStackAddr = 0x30000000; - if ( fStackAddr > 0x40000000) - throw "-stack_addr must be < 1G for arm"; + 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 ) { @@ -3359,7 +3371,7 @@ void Options::checkIllegalOptionCombinations() if ( fZeroPageSize != ULLONG_MAX ) { for (std::vector::iterator it = fCustomSegmentAddresses.begin(); it != fCustomSegmentAddresses.end(); ++it) { if ( (it->address >= 0) && (it->address < fZeroPageSize) ) - throwf("-segaddr %s 0x%X conflicts with -pagezero_size", it->name, it->address); + throwf("-segaddr %s 0x%llX conflicts with -pagezero_size", it->name, it->address); } } // verify no duplicates @@ -3584,13 +3596,17 @@ void Options::checkForClassic(int argc, const char* argv[]) void Options::gotoClassicLinker(int argc, const char* argv[]) { argv[0] = "ld_classic"; + char rawPath[PATH_MAX]; char path[PATH_MAX]; uint32_t bufSize = PATH_MAX; - if ( _NSGetExecutablePath(path, &bufSize) != -1 ) { - char* lastSlash = strrchr(path, '/'); - if ( lastSlash != NULL ) { - strcpy(lastSlash+1, "ld_classic"); - execvp(path, (char**)argv); + if ( _NSGetExecutablePath(rawPath, &bufSize) != -1 ) { + if ( realpath(rawPath, path) != NULL ) { + char* lastSlash = strrchr(path, '/'); + if ( lastSlash != NULL ) { + strcpy(lastSlash+1, "ld_classic"); + argv[0] = path; + execvp(path, (char**)argv); + } } } // in case of error in above, try searching for ld_classic via PATH diff --git a/src/ld/Options.h b/src/ld/Options.h index 9b8890e..2fa364e 100644 --- a/src/ld/Options.h +++ b/src/ld/Options.h @@ -35,8 +35,8 @@ #include "ObjectFile.h" -extern void throwf (const char* format, ...) __attribute__ ((noreturn)); -extern void warning(const char* format, ...); +extern void throwf (const char* format, ...) __attribute__ ((noreturn,format(printf, 1, 2))); +extern void warning(const char* format, ...) __attribute__((format(printf, 1, 2))); class LibraryOptions { @@ -231,6 +231,7 @@ public: bool errorOnOtherArchFiles() { return fErrorOnOtherArchFiles; } bool markAutoDeadStripDylib() { return fMarkDeadStrippableDylib; } bool removeEHLabels() { return fReaderOptions.fNoEHLabels; } + bool useSimplifiedDylibReExports() { return fUseSimplifiedDylibReExports; } private: class CStringEquals @@ -380,6 +381,7 @@ private: bool fMakeCompressedDyldInfo; bool fNoEHLabels; bool fAllowCpuSubtypeMismatches; + bool fUseSimplifiedDylibReExports; std::vector fInitialUndefines; NameSet fAllowedUndefined; NameSet fWhyLive; diff --git a/src/ld/ld.cpp b/src/ld/ld.cpp index 6d93c0b..f9d9ecb 100644 --- a/src/ld/ld.cpp +++ b/src/ld/ld.cpp @@ -1,5 +1,5 @@ /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-* - * Copyright (c) 2005-2007 Apple Inc. All rights reserved. + * Copyright (c) 2005-2009 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -101,8 +101,8 @@ private: typedef __gnu_cxx::hash_map, CStringEquals> NameToSection; //typedef std::map NameToSection; - const char* fSectionName; - const char* fSegmentName; + char fSectionName[18]; + char fSegmentName[18]; bool fZeroFill; bool fUntrustedZeroFill; @@ -116,22 +116,49 @@ std::vector Section::fgSections; Section::NameToOrdinal Section::fgSegmentDiscoverOrder; Section::Section(const char* sectionName, const char* segmentName, bool zeroFill, bool untrustedZeroFill) - : fSectionName(sectionName), fSegmentName(segmentName), fZeroFill(zeroFill), fUntrustedZeroFill(untrustedZeroFill) + : fZeroFill(zeroFill), fUntrustedZeroFill(untrustedZeroFill) { + strlcpy(fSectionName, sectionName, sizeof(fSectionName)); + strlcpy(fSegmentName, segmentName, sizeof(fSegmentName)); + this->fIndex = fgSections.size() + 20; // room for 20 standard sections // special placement of some sections if ( strcmp(segmentName, "__TEXT") == 0 ) { + // sort mach header and load commands to start of TEXT + if ( strcmp(sectionName, "._mach_header") == 0 ) + this->fIndex = 1; + else if ( strcmp(sectionName, "._load_commands") == 0 ) + this->fIndex = 2; + else if ( strcmp(sectionName, "._load_cmds_pad") == 0 ) + this->fIndex = 3; + // sort __text after load commands + else if ( strcmp(sectionName, "__text") == 0 ) + this->fIndex = 10; + // sort arm/ppc stubs after text to make branch islands feasible + else if ( strcmp(sectionName, "__picsymbolstub4") == 0 ) + this->fIndex = 11; + else if ( strcmp(sectionName, "__symbol_stub4") == 0 ) + this->fIndex = 11; + else if ( strcmp(sectionName, "__picsymbolstub1") == 0 ) + this->fIndex = 11; + else if ( strcmp(sectionName, "__symbol_stub1") == 0 ) + this->fIndex = 11; // sort unwind info to end of segment - if ( strcmp(sectionName, "__eh_frame") == 0 ) + else if ( strcmp(sectionName, "__eh_frame") == 0 ) this->fIndex = INT_MAX; else if ( strcmp(sectionName, "__unwind_info") == 0 ) this->fIndex = INT_MAX-1; else if ( strcmp(sectionName, "__gcc_except_tab") == 0 ) - this->fIndex = INT_MAX-2; + this->fIndex = INT_MAX-2; + else if ( strcmp(sectionName, "__symbolstub1") == 0 ) + this->fIndex = INT_MAX-3; // sort to end of __TEXT to be close to lazy pointers } else if ( strcmp(segmentName, "__DATA") == 0 ) { + // sort arm lazy symbol pointers that must be at start of __DATA + if ( strcmp(sectionName, "__lazy_symbol") == 0 ) + this->fIndex = 0; // sort sections dyld will touch to start of segment - if ( strcmp(sectionName, "__dyld") == 0 ) + else if ( strcmp(sectionName, "__dyld") == 0 ) this->fIndex = 1; else if ( strcmp(sectionName, "__program_vars") == 0 ) this->fIndex = 1; @@ -171,6 +198,8 @@ Section::Section(const char* sectionName, const char* segmentName, bool zeroFill this->fIndex = 18; else if ( strcmp(sectionName, "__objc_imageinfo") == 0 ) this->fIndex = 19; + else if ( strcmp(sectionName, "__huge") == 0 ) + this->fIndex = INT_MAX; } @@ -313,6 +342,7 @@ private: void loadAndResolve(); void processDTrace(); void checkObjC(); + void addSynthesizedAtoms(); void loadUndefines(); void checkUndefines(); void resolveReferences(); @@ -366,12 +396,14 @@ private: void require(const char* name); bool add(ObjectFile::Atom& atom); ObjectFile::Atom* find(const char* name); + void erase(const char* name); unsigned int getRequireCount() { return fRequireCount; } void getUndefinesNames(std::vector& undefines); void getTentativesNames(std::vector& tents); bool hasExternalTentativeDefinitions() { return fHasExternalTentativeDefinitions; } bool hasExternalWeakDefinitions() { return fHasExternalWeakDefinitions; } void setHasExternalWeakDefinitions(bool value) { fHasExternalWeakDefinitions = value; } + uint32_t dylibSymbolCount() { return fDylibSymbolCount; } Mapper::iterator begin() { return fTable.begin(); } Mapper::iterator end() { return fTable.end(); } @@ -381,6 +413,7 @@ private: unsigned int fRequireCount; bool fHasExternalTentativeDefinitions; bool fHasExternalWeakDefinitions; + uint32_t fDylibSymbolCount; }; class AtomSorter @@ -631,6 +664,20 @@ void Linker::loadAndResolve() } } +void Linker::addSynthesizedAtoms() +{ + // give write a chance to synthesize stub, GOT, and lazy pointer atoms + std::vector newAtoms; + fOutputFile->addSynthesizedAtoms(fAllAtoms, this->dyldClassicHelper(), + this->dyldCompressedHelper(), this->dyldLazyLibraryHelper(), + fBiggerThanTwoGigOutput, + fGlobalSymbolTable.dylibSymbolCount(), + newAtoms); + + // add all newly created atoms to fAllAtoms and update symbol table + this->addAtoms(newAtoms); +} + void Linker::optimize() { // give each reader a chance to do any optimizations @@ -648,6 +695,24 @@ void Linker::optimize() // only do next steps if some optimization was actually done if ( didSomething ) { + + if ( fOptions.deadStrip() != Options::kDeadStripOff ) { + for(std::vector::iterator itr = newAtoms.begin(); itr != newAtoms.end(); ++itr) { + ObjectFile::Atom* atom = *itr; + const char* name = atom->getName(); + if ( name != NULL ) { + ObjectFile::Atom* existingAtom = fGlobalSymbolTable.find(name); + if ( (existingAtom != NULL) && fLiveAtoms.count(existingAtom) == 0 ) { + // While dead code stripping, the atoms were not removed from fGlobalSymbolTable + // for performance reasons. Normally, libLTO will never recreate an atom + // that was previously dead stripped away, but if it does remove + // the remnents of the previous so the new one can be added + fGlobalSymbolTable.erase(name); + } + } + } + } + // add all newly created atoms to fAllAtoms and update symbol table this->addAtoms(newAtoms); @@ -748,6 +813,7 @@ void Linker::link() this->checkObjC(); this->processDTrace(); this->tweakLayout(); + this->addSynthesizedAtoms(); this->sortSections(); this->sortAtoms(); this->writeDotOutput(); @@ -1871,7 +1937,7 @@ void Linker::processDTrace() uint64_t offset = offsetsInDOF[i]; //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset); if ( offset > dofSectionSize ) - throwf("offsetsInDOF[i]=%0llX > dofSectionSize=%0lX\n", i, offset, dofSectionSize); + throwf("offsetsInDOF[%d]=%0llX > dofSectionSize=%0lX\n", i, offset, dofSectionSize); reader->addSectionReference(pcRelKind(fArchitecture), offset, probes[i].atom, probes[i].offset, reader->getAtoms()[0], 0); } this->addAtoms(reader->getAtoms()); @@ -2192,10 +2258,15 @@ void Linker::sortAtoms() theOrdinalOverrideMap[atom] = index; if (log ) fprintf(stderr, "override ordinal %u assigned to %s from %s\n", index, atom->getDisplayName(), atom->getFile()->getPath()); } + ++matchCount; } else { - ++matchCount; - //fprintf(stderr, "can't find match for order_file entry %s/%s\n", it->objectFileName, it->symbolName); + if ( fOptions.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; } @@ -2209,7 +2280,7 @@ void Linker::sortAtoms() //fprintf(stderr, "Sorted atoms:\n"); //for (std::vector::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) { - // fprintf(stderr, "\t%p, %u %s\t%s\n", (*it)->getSection(), (*it)->getSection()->getIndex(), (*it)->getDisplayName(), (*it)->getFile()->getPath()); + // fprintf(stderr, "\t%s, %u %s\t%s\n", (*it)->getSectionName(), (*it)->getSection()->getIndex(), (*it)->getDisplayName(), (*it)->getFile()->getPath()); //} } @@ -3110,9 +3181,8 @@ void Linker::writeOutput() fStartWriteTime = mach_absolute_time(); // tell writer about each segment's atoms fOutputFileSize = fOutputFile->write(fAllAtoms, fStabs, this->entryPoint(true), - this->dyldClassicHelper(),this->dyldCompressedHelper(), this->dyldLazyLibraryHelper(), fCreateUUID, fCanScatter, - fCurrentCpuConstraint, fBiggerThanTwoGigOutput, + fCurrentCpuConstraint, fRegularDefAtomsThatOverrideADylibsWeakDef, fGlobalSymbolTable.hasExternalWeakDefinitions()); } @@ -3940,6 +4010,10 @@ bool Linker::SymbolTable::add(ObjectFile::Atom& newAtom) case ObjectFile::Atom::kWeakDefinition: fHasExternalWeakDefinitions = true; break; + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + ++fDylibSymbolCount; + break; default: break; } @@ -3962,6 +4036,9 @@ ObjectFile::Atom* Linker::SymbolTable::find(const char* name) return NULL; } +void Linker::SymbolTable::erase(const char* name) { + fTable.erase(name); +} void Linker::SymbolTable::getUndefinesNames(std::vector& undefines) { diff --git a/src/other/dyldinfo.cpp b/src/other/dyldinfo.cpp index 4af50ff..5c42471 100644 --- a/src/other/dyldinfo.cpp +++ b/src/other/dyldinfo.cpp @@ -1,6 +1,6 @@ /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- * - * Copyright (c) 2008 Apple Inc. All rights reserved. + * Copyright (c) 2008-2009 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -47,6 +47,7 @@ static bool printOpcodes = false; static bool printExport = false; static bool printExportGraph = false; static cpu_type_t sPreferredArch = CPU_TYPE_I386; +static cpu_type_t sPreferredSubArch = 0; __attribute__((noreturn)) @@ -97,6 +98,13 @@ private: void printLazyBindingOpcodes(); void printExportInfo(); void printExportInfoGraph(); + void printRelocRebaseInfo(); + void printSymbolTableExportInfo(); + void printClassicLazyBindingInfo(); + void printClassicBindingInfo(); + pint_t relocBase(); + const char* relocTypeName(uint8_t r_type); + uint8_t segmentIndexForAddress(pint_t addr); void processExportNode(const uint8_t* const start, const uint8_t* p, const uint8_t* const end, char* cummulativeString, int curStrOffset); void processExportGraphNode(const uint8_t* const start, const uint8_t* const end, @@ -109,6 +117,9 @@ private: const char* sectionName(uint8_t segIndex, pint_t address); const char* getSegAndSectName(uint8_t segIndex, pint_t address); const char* ordinalName(int libraryOrdinal); + const char* classicOrdinalName(int libraryOrdinal); + pint_t* mappedAddressForVMAddress(pint_t vmaddress); + const char* fPath; @@ -120,6 +131,10 @@ private: uint32_t fSymbolCount; const macho_dyld_info_command

* fInfo; uint64_t fBaseAddress; + const macho_dysymtab_command

* fDynamicSymbolTable; + const macho_segment_command

* fFirstSegment; + const macho_segment_command

* fFirstWritableSegment; + bool fWriteableSegmentWithAddrOver4G; std::vector*>fSegments; std::vector fDylibs; }; @@ -216,11 +231,12 @@ bool DyldInfoPrinter::validFile(const uint8_t* fileContent) return false; } - template DyldInfoPrinter::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path) : fHeader(NULL), fLength(fileLength), - fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fInfo(NULL), fBaseAddress(0) + fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fInfo(NULL), + fBaseAddress(0), fDynamicSymbolTable(NULL), fFirstSegment(NULL), fFirstWritableSegment(NULL), + fWriteableSegmentWithAddrOver4G(false) { // sanity check if ( ! validFile(fileContent) ) @@ -236,7 +252,6 @@ DyldInfoPrinter::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen const macho_load_command

* const cmds = (macho_load_command

*)((uint8_t*)fHeader + sizeof(macho_header

)); const macho_load_command

* cmd = cmds; for (uint32_t i = 0; i < cmd_count; ++i) { - uint32_t size = cmd->cmdsize(); const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize(); if ( endOfCmd > endOfLoadCommands ) throwf("load command #%d extends beyond the end of the load commands", i); @@ -253,6 +268,14 @@ DyldInfoPrinter::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen fSegments.push_back(segCmd); if ( (segCmd->fileoff() == 0) && (segCmd->filesize() != 0) ) fBaseAddress = segCmd->vmaddr(); + if ( fFirstSegment == NULL ) + fFirstSegment = segCmd; + if ( (segCmd->initprot() & VM_PROT_WRITE) != 0 ) { + if ( fFirstWritableSegment == NULL ) + fFirstWritableSegment = segCmd; + if ( segCmd->vmaddr() > 0x100000000ULL ) + fWriteableSegmentWithAddrOver4G = true; + } } break; case LC_LOAD_DYLIB: @@ -274,20 +297,48 @@ DyldInfoPrinter::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen } } break; + case LC_DYSYMTAB: + fDynamicSymbolTable = (macho_dysymtab_command

*)cmd; + break; + case LC_SYMTAB: + { + const macho_symtab_command

* symtab = (macho_symtab_command

*)cmd; + fSymbolCount = symtab->nsyms(); + fSymbols = (const macho_nlist

*)((char*)fHeader + symtab->symoff()); + fStrings = (char*)fHeader + symtab->stroff(); + fStringsEnd = fStrings + symtab->strsize(); + } + break; } cmd = (const macho_load_command

*)endOfCmd; } - if ( printRebase ) - printRebaseInfo(); - if ( printBind ) - printBindingInfo(); + if ( printRebase ) { + if ( fInfo != NULL ) + printRebaseInfo(); + else + printRelocRebaseInfo(); + } + if ( printBind ) { + if ( fInfo != NULL ) + printBindingInfo(); + else + printClassicBindingInfo(); + } if ( printWeakBind ) printWeakBindingInfo(); - if ( printLazyBind ) - printLazyBindingInfo(); - if ( printExport ) - printExportInfo(); + if ( printLazyBind ) { + if ( fInfo != NULL ) + printLazyBindingInfo(); + else + printClassicLazyBindingInfo(); + } + if ( printExport ) { + if ( fInfo != NULL ) + printExportInfo(); + else + printSymbolTableExportInfo(); + } if ( printOpcodes ) { printRebaseInfoOpcodes(); printBindingInfoOpcodes(false); @@ -427,6 +478,29 @@ const char* DyldInfoPrinter::getSegAndSectName(uint8_t segIndex, pint_t addre return "??"; } +template +uint8_t DyldInfoPrinter::segmentIndexForAddress(pint_t address) +{ + for(unsigned int i=0; i < fSegments.size(); ++i) { + if ( (fSegments[i]->vmaddr() <= address) && (address < (fSegments[i]->vmaddr()+fSegments[i]->vmsize())) ) { + return i; + } + } + throwf("address 0x%llX is not in any segment", (uint64_t)address); +} + +template +typename A::P::uint_t* DyldInfoPrinter::mappedAddressForVMAddress(pint_t vmaddress) +{ + for(unsigned int i=0; i < fSegments.size(); ++i) { + if ( (fSegments[i]->vmaddr() <= vmaddress) && (vmaddress < (fSegments[i]->vmaddr()+fSegments[i]->vmsize())) ) { + unsigned long offsetInMappedFile = fSegments[i]->fileoff()+vmaddress-fSegments[i]->vmaddr(); + return (pint_t*)((uint8_t*)fHeader + offsetInMappedFile); + } + } + throwf("address 0x%llX is not in any segment", (uint64_t)vmaddress); +} + template const char* DyldInfoPrinter::ordinalName(int libraryOrdinal) { @@ -440,11 +514,26 @@ const char* DyldInfoPrinter::ordinalName(int libraryOrdinal) } if ( libraryOrdinal < BIND_SPECIAL_DYLIB_FLAT_LOOKUP ) throw "unknown special ordinal"; - if ( libraryOrdinal > fDylibs.size() ) + if ( libraryOrdinal > (int)fDylibs.size() ) throw "libraryOrdinal out of range"; return fDylibs[libraryOrdinal-1]; } +template +const char* DyldInfoPrinter::classicOrdinalName(int libraryOrdinal) +{ + switch ( libraryOrdinal) { + case SELF_LIBRARY_ORDINAL: + return "this-image"; + case EXECUTABLE_ORDINAL: + return "main-executable"; + case DYNAMIC_LOOKUP_ORDINAL: + return "flat-namespace"; + } + if ( libraryOrdinal > (int)fDylibs.size() ) + throw "libraryOrdinal out of range"; + return fDylibs[libraryOrdinal-1]; +} template void DyldInfoPrinter::printRebaseInfo() @@ -453,7 +542,7 @@ void DyldInfoPrinter::printRebaseInfo() printf("no compressed rebase info\n"); } else { - printf("rebase information:\n"); + printf("rebase information (from compressed dyld info):\n"); printf("segment section address type\n"); const uint8_t* p = (uint8_t*)fHeader + fInfo->rebase_off(); @@ -722,7 +811,7 @@ void DyldInfoPrinter::printBindingInfo() } else { printf("bind information:\n"); - printf("segment section address type addend dylib symbol\n"); + printf("segment section address type weak addend dylib symbol\n"); const uint8_t* p = (uint8_t*)fHeader + fInfo->bind_off(); const uint8_t* end = &p[fInfo->bind_size()]; @@ -738,6 +827,7 @@ void DyldInfoPrinter::printBindingInfo() pint_t segStartAddr = 0; const char* segName = "??"; const char* typeName = "??"; + const char* weak_import = ""; bool done = false; while ( !done && (p < end) ) { uint8_t immediate = *p & BIND_IMMEDIATE_MASK; @@ -770,6 +860,10 @@ void DyldInfoPrinter::printBindingInfo() while (*p != '\0') ++p; ++p; + if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 ) + weak_import = "weak"; + else + weak_import = ""; break; case BIND_OPCODE_SET_TYPE_IMM: type = immediate; @@ -788,22 +882,22 @@ void DyldInfoPrinter::printBindingInfo() segOffset += read_uleb128(p, end); break; case BIND_OPCODE_DO_BIND: - printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName ); + printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName ); segOffset += sizeof(pint_t); break; case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: - printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName ); + printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName ); segOffset += read_uleb128(p, end) + sizeof(pint_t); break; case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: - printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName ); + printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName ); segOffset += immediate*sizeof(pint_t) + sizeof(pint_t); break; case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: count = read_uleb128(p, end); skip = read_uleb128(p, end); for (uint32_t i=0; i < count; ++i) { - printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName ); + printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName ); segOffset += skip + sizeof(pint_t); } break; @@ -909,7 +1003,7 @@ void DyldInfoPrinter::printLazyBindingInfo() printf("no compressed lazy binding info\n"); } else { - printf("lazy binding information:\n"); + printf("lazy binding information (from lazy_bind part of dyld info):\n"); printf("segment section address index dylib symbol\n"); const uint8_t* const start = (uint8_t*)fHeader + fInfo->lazy_bind_off(); const uint8_t* const end = &start[fInfo->lazy_bind_size()]; @@ -985,90 +1079,6 @@ void DyldInfoPrinter::printLazyBindingInfo() } -#if 0 - uint8_t type = BIND_TYPE_POINTER; - uint8_t flags; - uint64_t address = fBaseAddress; - const char* symbolName = NULL; - int libraryOrdinal = 0; - int64_t addend = 0; - uint32_t segmentIndex = 0; - uint32_t count; - uint32_t skip; - for (const uint8_t* p = start; p < end; ) { - uint8_t immediate = *p & BIND_IMMEDIATE_MASK; - uint8_t opcode = *p & BIND_OPCODE_MASK; - uint32_t opcodeOffset = p-start; - ++p; - switch (opcode) { - case BIND_OPCODE_DONE: - printf("0x%08X BIND_OPCODE_DONE\n", opcodeOffset); - break; - case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: - libraryOrdinal = immediate; - printf("0x%08X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset, libraryOrdinal); - break; - case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: - libraryOrdinal = read_uleb128(p, end); - printf("0x%08X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset, libraryOrdinal); - break; - case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: - // the special ordinals are negative numbers - if ( immediate == 0 ) - libraryOrdinal = 0; - else { - int8_t signExtended = BIND_OPCODE_MASK | immediate; - libraryOrdinal = signExtended; - } - printf("0x%08X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset, libraryOrdinal); - break; - case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: - flags = immediate; - symbolName = (char*)p; - while (*p != '\0') - ++p; - ++p; - printf("0x%08X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset, flags, symbolName); - break; - case BIND_OPCODE_SET_TYPE_IMM: - type = immediate; - printf("0x%08X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type); - break; - case BIND_OPCODE_SET_ADDEND_SLEB: - addend = read_sleb128(p, end); - printf("0x%08X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset, addend); - break; - case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: - segmentIndex = immediate; - address = read_uleb128(p, end); - printf("0x%08X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset, segmentIndex, address); - break; - case BIND_OPCODE_ADD_ADDR_ULEB: - skip = read_uleb128(p, end); - printf("0x%08X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip); - break; - case BIND_OPCODE_DO_BIND: - printf("0x%08X BIND_OPCODE_DO_BIND()\n", opcodeOffset); - break; - case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: - skip = read_uleb128(p, end); - printf("0x%08X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip); - break; - case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: - skip = immediate*sizeof(pint_t) + sizeof(pint_t); - printf("0x%08X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset, skip); - break; - case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: - count = read_uleb128(p, end); - skip = read_uleb128(p, end); - printf("0x%08X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip); - break; - default: - throwf("unknown bind opcode %d", *p); - } - } -#endif - template void DyldInfoPrinter::printLazyBindingOpcodes() { @@ -1211,6 +1221,7 @@ void DyldInfoPrinter::printExportInfo() printf("no compressed export info\n"); } else { + printf("export information (from trie):\n"); const uint8_t* start = (uint8_t*)fHeader + fInfo->export_off(); const uint8_t* end = &start[fInfo->export_size()]; std::vector list; @@ -1236,6 +1247,7 @@ void DyldInfoPrinter::processExportGraphNode(const uint8_t* const start, cons const uint8_t* children = p + terminalSize; if ( terminalSize != 0 ) { uint32_t flags = read_uleb128(p, end); + (void)flags; // currently unused uint64_t address = read_uleb128(p, end); printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me-start), cummulativeString, address); } @@ -1275,8 +1287,307 @@ void DyldInfoPrinter::printExportInfoGraph() } +template <> +ppc::P::uint_t DyldInfoPrinter::relocBase() +{ + if ( fHeader->flags() & MH_SPLIT_SEGS ) + return fFirstWritableSegment->vmaddr(); + else + return fFirstSegment->vmaddr(); +} + +template <> +ppc64::P::uint_t DyldInfoPrinter::relocBase() +{ + if ( fWriteableSegmentWithAddrOver4G ) + return fFirstWritableSegment->vmaddr(); + else + return fFirstSegment->vmaddr(); +} + +template <> +x86::P::uint_t DyldInfoPrinter::relocBase() +{ + if ( fHeader->flags() & MH_SPLIT_SEGS ) + return fFirstWritableSegment->vmaddr(); + else + return fFirstSegment->vmaddr(); +} + +template <> +x86_64::P::uint_t DyldInfoPrinter::relocBase() +{ + // check for split-seg + return fFirstWritableSegment->vmaddr(); +} + +template <> +arm::P::uint_t DyldInfoPrinter::relocBase() +{ + if ( fHeader->flags() & MH_SPLIT_SEGS ) + return fFirstWritableSegment->vmaddr(); + else + return fFirstSegment->vmaddr(); +} +template <> +const char* DyldInfoPrinter::relocTypeName(uint8_t r_type) +{ + if ( r_type == GENERIC_RELOC_VANILLA ) + return "pointer"; + else if ( r_type == PPC_RELOC_PB_LA_PTR ) + return "pb pointer"; + else + return "??"; +} + +template <> +const char* DyldInfoPrinter::relocTypeName(uint8_t r_type) +{ + if ( r_type == GENERIC_RELOC_VANILLA ) + return "pointer"; + else + return "??"; +} + +template <> +const char* DyldInfoPrinter::relocTypeName(uint8_t r_type) +{ + if ( r_type == GENERIC_RELOC_VANILLA ) + return "pointer"; + else if ( r_type == GENERIC_RELOC_PB_LA_PTR ) + return "pb pointer"; + else + return "??"; +} + +template <> +const char* DyldInfoPrinter::relocTypeName(uint8_t r_type) +{ + if ( r_type == X86_64_RELOC_UNSIGNED ) + return "pointer"; + else + return "??"; +} + +template <> +const char* DyldInfoPrinter::relocTypeName(uint8_t r_type) +{ + if ( r_type == ARM_RELOC_VANILLA ) + return "pointer"; + else if ( r_type == ARM_RELOC_PB_LA_PTR ) + return "pb pointer"; + else + return "??"; +} + + +template +void DyldInfoPrinter::printRelocRebaseInfo() +{ + if ( fDynamicSymbolTable == NULL ) { + printf("no classic dynamic symbol table"); + } + else { + printf("rebase information (from local relocation records and indirect symbol table):\n"); + printf("segment section address type\n"); + // walk all local relocations + pint_t rbase = relocBase(); + const macho_relocation_info

* const relocsStart = (macho_relocation_info

*)(((uint8_t*)fHeader) + fDynamicSymbolTable->locreloff()); + const macho_relocation_info

* const relocsEnd = &relocsStart[fDynamicSymbolTable->nlocrel()]; + for (const macho_relocation_info

* reloc=relocsStart; reloc < relocsEnd; ++reloc) { + if ( (reloc->r_address() & R_SCATTERED) == 0 ) { + pint_t addr = reloc->r_address() + rbase; + uint8_t segIndex = segmentIndexForAddress(addr); + const char* typeName = relocTypeName(reloc->r_type()); + const char* segName = segmentName(segIndex); + const char* sectName = sectionName(segIndex, addr); + printf("%-8s %-16s 0x%08llX %s\n", segName, sectName, (uint64_t)addr, typeName); + } + else { + const macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; + pint_t addr = sreloc->r_address() + rbase; + uint8_t segIndex = segmentIndexForAddress(addr); + const char* typeName = relocTypeName(sreloc->r_type()); + const char* segName = segmentName(segIndex); + const char* sectName = sectionName(segIndex, addr); + printf("%-8s %-16s 0x%08llX %s\n", segName, sectName, (uint64_t)addr, typeName); + } + } + // look for local non-lazy-pointers + const uint32_t* indirectSymbolTable = (uint32_t*)(((uint8_t*)fHeader) + fDynamicSymbolTable->indirectsymoff()); + uint8_t segIndex = 0; + for(typename std::vector*>::iterator segit=fSegments.begin(); segit != fSegments.end(); ++segit, ++segIndex) { + const macho_segment_command

* segCmd = *segit; + macho_section

* const sectionsStart = (macho_section

*)((char*)segCmd + sizeof(macho_segment_command

)); + macho_section

* const sectionsEnd = §ionsStart[segCmd->nsects()]; + for(macho_section

* sect = sectionsStart; sect < sectionsEnd; ++sect) { + uint8_t type = sect->flags() & SECTION_TYPE; + if ( type == S_NON_LAZY_SYMBOL_POINTERS ) { + uint32_t indirectOffset = sect->reserved1(); + uint32_t count = sect->size() / sizeof(pint_t); + for (uint32_t i=0; i < count; ++i) { + uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]); + if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) { + pint_t addr = sect->addr() + i*sizeof(pint_t); + const char* typeName = "pointer"; + const char* segName = segmentName(segIndex); + const char* sectName = sectionName(segIndex, addr); + printf("%-8s %-16s 0x%08llX %s\n", segName, sectName, (uint64_t)addr, typeName); + } + } + } + } + } + } +} + + +template +void DyldInfoPrinter::printSymbolTableExportInfo() +{ + if ( fDynamicSymbolTable == NULL ) { + printf("no classic dynamic symbol table"); + } + else { + printf("export information (from symbol table):\n"); + const macho_nlist

* lastExport = &fSymbols[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()]; + for (const macho_nlist

* sym = &fSymbols[fDynamicSymbolTable->iextdefsym()]; sym < lastExport; ++sym) { + const char* flags = ""; + if ( sym->n_desc() & N_WEAK_DEF ) + flags = "[weak_def] "; + pint_t thumb = 0; + if ( sym->n_desc() & N_ARM_THUMB_DEF ) + thumb = 1; + printf("0x%08llX %s%s\n", sym->n_value()+thumb, flags, &fStrings[sym->n_strx()]); + } + } +} + + +template +void DyldInfoPrinter::printClassicBindingInfo() +{ + if ( fDynamicSymbolTable == NULL ) { + printf("no classic dynamic symbol table"); + } + else { + printf("binding information (from relocations and indirect symbol table):\n"); + printf("segment section address type weak addend dylib symbol\n"); + // walk all external relocations + pint_t rbase = relocBase(); + const macho_relocation_info

* const relocsStart = (macho_relocation_info

*)(((uint8_t*)fHeader) + fDynamicSymbolTable->extreloff()); + const macho_relocation_info

* const relocsEnd = &relocsStart[fDynamicSymbolTable->nextrel()]; + for (const macho_relocation_info

* reloc=relocsStart; reloc < relocsEnd; ++reloc) { + pint_t addr = reloc->r_address() + rbase; + uint32_t symbolIndex = reloc->r_symbolnum(); + const macho_nlist

* sym = &fSymbols[symbolIndex]; + const char* symbolName = &fStrings[sym->n_strx()]; + const char* weak_import = (sym->n_desc() & N_WEAK_REF) ? "weak" : ""; + const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc())); + uint8_t segIndex = segmentIndexForAddress(addr); + const char* typeName = relocTypeName(reloc->r_type()); + const char* segName = segmentName(segIndex); + const char* sectName = sectionName(segIndex, addr); + const pint_t* addressMapped = mappedAddressForVMAddress(addr); + int64_t addend = P::getP(*addressMapped); + if ( fHeader->flags() & MH_PREBOUND ) { + // In prebound binaries the content is already pointing to the target. + // To get the addend requires subtracting out the base address it was prebound to. + addend -= sym->n_value(); + } + printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectName, (uint64_t)addr, + typeName, weak_import, addend, fromDylib, symbolName); + } + // look for non-lazy pointers + const uint32_t* indirectSymbolTable = (uint32_t*)(((uint8_t*)fHeader) + fDynamicSymbolTable->indirectsymoff()); + for(typename std::vector*>::iterator segit=fSegments.begin(); segit != fSegments.end(); ++segit) { + const macho_segment_command

* segCmd = *segit; + macho_section

* const sectionsStart = (macho_section

*)((char*)segCmd + sizeof(macho_segment_command

)); + macho_section

* const sectionsEnd = §ionsStart[segCmd->nsects()]; + for(macho_section

* sect = sectionsStart; sect < sectionsEnd; ++sect) { + uint8_t type = sect->flags() & SECTION_TYPE; + if ( type == S_NON_LAZY_SYMBOL_POINTERS ) { + uint32_t indirectOffset = sect->reserved1(); + uint32_t count = sect->size() / sizeof(pint_t); + for (uint32_t i=0; i < count; ++i) { + uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]); + if ( symbolIndex != INDIRECT_SYMBOL_LOCAL ) { + const macho_nlist

* sym = &fSymbols[symbolIndex]; + const char* symbolName = &fStrings[sym->n_strx()]; + const char* weak_import = (sym->n_desc() & N_WEAK_REF) ? "weak" : ""; + const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc())); + pint_t addr = sect->addr() + i*sizeof(pint_t); + uint8_t segIndex = segmentIndexForAddress(addr); + const char* typeName = "pointer"; + const char* segName = segmentName(segIndex); + const char* sectName = sectionName(segIndex, addr); + int64_t addend = 0; + printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectName, (uint64_t)addr, + typeName, weak_import, addend, fromDylib, symbolName); + } + } + } + } + } + } +} + + +template +void DyldInfoPrinter::printClassicLazyBindingInfo() +{ + if ( fDynamicSymbolTable == NULL ) { + printf("no classic dynamic symbol table"); + } + else { + printf("lazy binding information (from section records and indirect symbol table):\n"); + printf("segment section address index dylib symbol\n"); + const uint32_t* indirectSymbolTable = (uint32_t*)(((uint8_t*)fHeader) + fDynamicSymbolTable->indirectsymoff()); + for(typename std::vector*>::iterator segit=fSegments.begin(); segit != fSegments.end(); ++segit) { + const macho_segment_command

* segCmd = *segit; + macho_section

* const sectionsStart = (macho_section

*)((char*)segCmd + sizeof(macho_segment_command

)); + macho_section

* const sectionsEnd = §ionsStart[segCmd->nsects()]; + for(macho_section

* sect = sectionsStart; sect < sectionsEnd; ++sect) { + uint8_t type = sect->flags() & SECTION_TYPE; + if ( type == S_LAZY_SYMBOL_POINTERS ) { + uint32_t indirectOffset = sect->reserved1(); + uint32_t count = sect->size() / sizeof(pint_t); + for (uint32_t i=0; i < count; ++i) { + uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]); + const macho_nlist

* sym = &fSymbols[symbolIndex]; + const char* symbolName = &fStrings[sym->n_strx()]; + const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc())); + pint_t addr = sect->addr() + i*sizeof(pint_t); + uint8_t segIndex = segmentIndexForAddress(addr); + const char* segName = segmentName(segIndex); + const char* sectName = sectionName(segIndex, addr); + printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName, sectName, (uint64_t)addr, symbolIndex, fromDylib, symbolName); + } + } + else if ( (type == S_SYMBOL_STUBS) && (((sect->flags() & S_ATTR_SELF_MODIFYING_CODE) != 0)) && (sect->reserved2() == 5) ) { + // i386 self-modifying stubs + uint32_t indirectOffset = sect->reserved1(); + uint32_t count = sect->size() / 5; + for (uint32_t i=0; i < count; ++i) { + uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]); + if ( symbolIndex != INDIRECT_SYMBOL_ABS ) { + const macho_nlist

* sym = &fSymbols[symbolIndex]; + const char* symbolName = &fStrings[sym->n_strx()]; + const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc())); + pint_t addr = sect->addr() + i*5; + uint8_t segIndex = segmentIndexForAddress(addr); + const char* segName = segmentName(segIndex); + const char* sectName = sectionName(segIndex, addr); + printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName, sectName, (uint64_t)addr, symbolIndex, fromDylib, symbolName); + } + } + } + } + } + } +} static void dump(const char* path) { @@ -1301,7 +1612,9 @@ static void dump(const char* path) size_t offset = OSSwapBigToHostInt32(archs[i].offset); size_t size = OSSwapBigToHostInt32(archs[i].size); cpu_type_t cputype = OSSwapBigToHostInt32(archs[i].cputype); - if ( cputype == (uint32_t)sPreferredArch ) { + cpu_type_t cpusubtype = OSSwapBigToHostInt32(archs[i].cpusubtype); + if ( (cputype == sPreferredArch) + && ((sPreferredSubArch==0) || (sPreferredSubArch==cpusubtype)) ) { switch(cputype) { case CPU_TYPE_POWERPC: if ( DyldInfoPrinter::validFile(p + offset) ) @@ -1399,6 +1712,24 @@ int main(int argc, const char* argv[]) sPreferredArch = CPU_TYPE_I386; else if ( strcmp(arch, "x86_64") == 0 ) sPreferredArch = CPU_TYPE_X86_64; + else if ( strcmp(arch, "arm") == 0 ) + sPreferredArch = CPU_TYPE_ARM; + else if ( strcmp(arch, "armv4t") == 0 ) { + sPreferredArch = CPU_TYPE_ARM; + sPreferredSubArch = CPU_SUBTYPE_ARM_V4T; + } + else if ( strcmp(arch, "armv5") == 0 ) { + sPreferredArch = CPU_TYPE_ARM; + sPreferredSubArch = CPU_SUBTYPE_ARM_V5TEJ; + } + else if ( strcmp(arch, "armv6") == 0 ) { + sPreferredArch = CPU_TYPE_ARM; + sPreferredSubArch = CPU_SUBTYPE_ARM_V6; + } + else if ( strcmp(arch, "armv7") == 0 ) { + sPreferredArch = CPU_TYPE_ARM; + sPreferredSubArch = CPU_SUBTYPE_ARM_V7; + } else throwf("unknown architecture %s", arch); } diff --git a/src/other/unwinddump.cpp b/src/other/unwinddump.cpp index d8d699d..098d932 100644 --- a/src/other/unwinddump.cpp +++ b/src/other/unwinddump.cpp @@ -83,6 +83,7 @@ private: void getSymbolTableInfo(); const char* functionName(pint_t addr); static const char* archName(); + static void decode(uint32_t encoding, const uint8_t* funcStart, char* str); const char* fPath; const macho_header

* fHeader; @@ -251,7 +252,7 @@ const char* UnwindPrinter::functionName(pint_t addr) } } } - return "??"; + return "--anonymous function--"; } @@ -288,8 +289,379 @@ bool UnwindPrinter::findUnwindSection() return false; } +#define EXTRACT_BITS(value, mask) \ + ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) ) +template <> +void UnwindPrinter::decode(uint32_t encoding, const uint8_t* funcStart, char* str) +{ + *str = '\0'; + switch ( encoding & UNWIND_X86_64_MODE_MASK ) { + case UNWIND_X86_64_MODE_RBP_FRAME: + { + uint32_t savedRegistersOffset = EXTRACT_BITS(encoding, UNWIND_X86_64_RBP_FRAME_OFFSET); + uint32_t savedRegistersLocations = EXTRACT_BITS(encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); + if ( savedRegistersLocations == 0 ) { + strcpy(str, "rbp frame, no saved registers"); + } + else { + sprintf(str, "rbp frame, at -%d:", savedRegistersOffset*8); + bool needComma = false; + for (int i=0; i < 5; ++i) { + if ( needComma ) + strcat(str, ","); + else + needComma = true; + switch (savedRegistersLocations & 0x7) { + case UNWIND_X86_64_REG_NONE: + strcat(str, "-"); + break; + case UNWIND_X86_64_REG_RBX: + strcat(str, "rbx"); + break; + case UNWIND_X86_64_REG_R12: + strcat(str, "r12"); + break; + case UNWIND_X86_64_REG_R13: + strcat(str, "r13"); + break; + case UNWIND_X86_64_REG_R14: + strcat(str, "r14"); + break; + case UNWIND_X86_64_REG_R15: + strcat(str, "r15"); + break; + default: + strcat(str, "r?"); + } + savedRegistersLocations = (savedRegistersLocations >> 3); + if ( savedRegistersLocations == 0 ) + break; + } + } + } + break; + case UNWIND_X86_64_MODE_STACK_IMMD: + case UNWIND_X86_64_MODE_STACK_IND: + { + uint32_t stackSize = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); + uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); + uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); + uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); + if ( (encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_STACK_IND ) { + // stack size is encoded in subl $xxx,%esp instruction + uint32_t subl = x86_64::P::E::get32(*((uint32_t*)(funcStart+stackSize))); + sprintf(str, "stack size=0x%08X, ", subl + 8*stackAdjust); + } + else { + sprintf(str, "stack size=%d, ", stackSize*8); + } + if ( regCount == 0 ) { + strcat(str, "no registers saved"); + } + else { + int permunreg[6]; + switch ( regCount ) { + case 6: + permunreg[0] = permutation/120; + permutation -= (permunreg[0]*120); + permunreg[1] = permutation/24; + permutation -= (permunreg[1]*24); + permunreg[2] = permutation/6; + permutation -= (permunreg[2]*6); + permunreg[3] = permutation/2; + permutation -= (permunreg[3]*2); + permunreg[4] = permutation; + permunreg[5] = 0; + break; + case 5: + permunreg[0] = permutation/120; + permutation -= (permunreg[0]*120); + permunreg[1] = permutation/24; + permutation -= (permunreg[1]*24); + permunreg[2] = permutation/6; + permutation -= (permunreg[2]*6); + permunreg[3] = permutation/2; + permutation -= (permunreg[3]*2); + permunreg[4] = permutation; + break; + case 4: + permunreg[0] = permutation/60; + permutation -= (permunreg[0]*60); + permunreg[1] = permutation/12; + permutation -= (permunreg[1]*12); + permunreg[2] = permutation/3; + permutation -= (permunreg[2]*3); + permunreg[3] = permutation; + break; + case 3: + permunreg[0] = permutation/20; + permutation -= (permunreg[0]*20); + permunreg[1] = permutation/4; + permutation -= (permunreg[1]*4); + permunreg[2] = permutation; + break; + case 2: + permunreg[0] = permutation/5; + permutation -= (permunreg[0]*5); + permunreg[1] = permutation; + break; + case 1: + permunreg[0] = permutation; + break; + } + // renumber registers back to standard numbers + int registers[6]; + bool used[7] = { false, false, false, false, false, false, false }; + for (int i=0; i < regCount; ++i) { + int renum = 0; + for (int u=1; u < 7; ++u) { + if ( !used[u] ) { + if ( renum == permunreg[i] ) { + registers[i] = u; + used[u] = true; + break; + } + ++renum; + } + } + } + bool needComma = false; + for (int i=0; i < regCount; ++i) { + if ( needComma ) + strcat(str, ","); + else + needComma = true; + switch ( registers[i] ) { + case UNWIND_X86_64_REG_RBX: + strcat(str, "rbx"); + break; + case UNWIND_X86_64_REG_R12: + strcat(str, "r12"); + break; + case UNWIND_X86_64_REG_R13: + strcat(str, "r13"); + break; + case UNWIND_X86_64_REG_R14: + strcat(str, "r14"); + break; + case UNWIND_X86_64_REG_R15: + strcat(str, "r15"); + break; + case UNWIND_X86_64_REG_RBP: + strcat(str, "rbp"); + break; + default: + strcat(str, "r??"); + } + } + } + } + break; + case UNWIND_X86_64_MODE_DWARF: + sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_X86_64_DWARF_SECTION_OFFSET); + break; + default: + if ( encoding == 0 ) + strcat(str, "no unwind information"); + else + strcat(str, "tbd "); + } + if ( encoding & UNWIND_HAS_LSDA ) { + strcat(str, " LSDA"); + } + +} + +template <> +void UnwindPrinter::decode(uint32_t encoding, const uint8_t* funcStart, char* str) +{ + *str = '\0'; + switch ( encoding & UNWIND_X86_MODE_MASK ) { + case UNWIND_X86_MODE_EBP_FRAME: + { + uint32_t savedRegistersOffset = EXTRACT_BITS(encoding, UNWIND_X86_EBP_FRAME_OFFSET); + uint32_t savedRegistersLocations = EXTRACT_BITS(encoding, UNWIND_X86_EBP_FRAME_REGISTERS); + if ( savedRegistersLocations == 0 ) { + strcpy(str, "ebp frame, no saved registers"); + } + else { + sprintf(str, "ebp frame, at -%d:", savedRegistersOffset*4); + bool needComma = false; + for (int i=0; i < 5; ++i) { + if ( needComma ) + strcat(str, ","); + else + needComma = true; + switch (savedRegistersLocations & 0x7) { + case UNWIND_X86_REG_NONE: + strcat(str, "-"); + break; + case UNWIND_X86_REG_EBX: + strcat(str, "ebx"); + break; + case UNWIND_X86_REG_ECX: + strcat(str, "ecx"); + break; + case UNWIND_X86_REG_EDX: + strcat(str, "edx"); + break; + case UNWIND_X86_REG_EDI: + strcat(str, "edi"); + break; + case UNWIND_X86_REG_ESI: + strcat(str, "esi"); + break; + default: + strcat(str, "e??"); + } + savedRegistersLocations = (savedRegistersLocations >> 3); + if ( savedRegistersLocations == 0 ) + break; + } + } + } + break; + case UNWIND_X86_MODE_STACK_IMMD: + case UNWIND_X86_MODE_STACK_IND: + { + uint32_t stackSize = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); + uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST); + uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT); + uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION); + if ( (encoding & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_STACK_IND ) { + // stack size is encoded in subl $xxx,%esp instruction + uint32_t subl = x86::P::E::get32(*((uint32_t*)(funcStart+stackSize))); + sprintf(str, "stack size=0x%08X, ", subl+4*stackAdjust); + } + else { + sprintf(str, "stack size=%d, ", stackSize*4); + } + if ( regCount == 0 ) { + strcat(str, "no saved regs"); + } + else { + int permunreg[6]; + switch ( regCount ) { + case 6: + permunreg[0] = permutation/120; + permutation -= (permunreg[0]*120); + permunreg[1] = permutation/24; + permutation -= (permunreg[1]*24); + permunreg[2] = permutation/6; + permutation -= (permunreg[2]*6); + permunreg[3] = permutation/2; + permutation -= (permunreg[3]*2); + permunreg[4] = permutation; + permunreg[5] = 0; + break; + case 5: + permunreg[0] = permutation/120; + permutation -= (permunreg[0]*120); + permunreg[1] = permutation/24; + permutation -= (permunreg[1]*24); + permunreg[2] = permutation/6; + permutation -= (permunreg[2]*6); + permunreg[3] = permutation/2; + permutation -= (permunreg[3]*2); + permunreg[4] = permutation; + break; + case 4: + permunreg[0] = permutation/60; + permutation -= (permunreg[0]*60); + permunreg[1] = permutation/12; + permutation -= (permunreg[1]*12); + permunreg[2] = permutation/3; + permutation -= (permunreg[2]*3); + permunreg[3] = permutation; + break; + case 3: + permunreg[0] = permutation/20; + permutation -= (permunreg[0]*20); + permunreg[1] = permutation/4; + permutation -= (permunreg[1]*4); + permunreg[2] = permutation; + break; + case 2: + permunreg[0] = permutation/5; + permutation -= (permunreg[0]*5); + permunreg[1] = permutation; + break; + case 1: + permunreg[0] = permutation; + break; + } + // renumber registers back to standard numbers + int registers[6]; + bool used[7] = { false, false, false, false, false, false, false }; + for (int i=0; i < regCount; ++i) { + int renum = 0; + for (int u=1; u < 7; ++u) { + if ( !used[u] ) { + if ( renum == permunreg[i] ) { + registers[i] = u; + used[u] = true; + break; + } + ++renum; + } + } + } + bool needComma = false; + for (int i=0; i < regCount; ++i) { + if ( needComma ) + strcat(str, ","); + else + needComma = true; + switch ( registers[i] ) { + case UNWIND_X86_REG_EBX: + strcat(str, "ebx"); + break; + case UNWIND_X86_REG_ECX: + strcat(str, "ecx"); + break; + case UNWIND_X86_REG_EDX: + strcat(str, "edx"); + break; + case UNWIND_X86_REG_EDI: + strcat(str, "edi"); + break; + case UNWIND_X86_REG_ESI: + strcat(str, "esi"); + break; + case UNWIND_X86_REG_EBP: + strcat(str, "ebp"); + break; + default: + strcat(str, "e??"); + } + } + } + } + break; + case UNWIND_X86_MODE_DWARF: + sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_X86_DWARF_SECTION_OFFSET); + break; + default: + if ( encoding == 0 ) + strcat(str, "no unwind information"); + else + strcat(str, "tbd "); + } + if ( encoding & UNWIND_HAS_LSDA ) { + strcat(str, " LSDA"); + } + +} + + +template +void UnwindPrinter::decode(uint32_t encoding, const uint8_t* funcStart, char* str) +{ + + +} template void UnwindPrinter::printUnwindSection() @@ -309,7 +681,7 @@ void UnwindPrinter::printUnwindSection() printf("\tcommon encodings: (count=%u)\n", sectionHeader->commonEncodingsArrayCount()); const uint32_t* commonEncodings = (uint32_t*)§ionContent[sectionHeader->commonEncodingsArraySectionOffset()]; for (uint32_t i=0; i < sectionHeader->commonEncodingsArrayCount(); ++i) { - printf("\t\tencoding[%2u]=0x%08X\n", i, A::P::E::get32(commonEncodings[i])); + printf("\t\tencoding[%3u]=0x%08X\n", i, A::P::E::get32(commonEncodings[i])); } printf("\tpersonalities: (count=%u)\n", sectionHeader->personalityArrayCount()); const uint32_t* personalityArray = (uint32_t*)§ionContent[sectionHeader->personalityArraySectionOffset()]; @@ -343,10 +715,10 @@ void UnwindPrinter::printUnwindSection() printf("\t\tentryCount=0x%08X\n", page->entryCount()); const macho_unwind_info_regular_second_level_entry

* entry = (macho_unwind_info_regular_second_level_entry

*)((char*)page+page->entryPageOffset()); for (uint32_t j=0; j < page->entryCount(); ++j) { + uint32_t funcOffset = entry[j].functionOffset(); if ( entry[j].encoding() & UNWIND_HAS_LSDA ) { // verify there is a corresponding entry in lsda table bool found = false; - uint32_t funcOffset = entry[j].functionOffset(); for (uint32_t k=0; k < lsdaIndexArrayCount; ++k) { if ( lindex[k].functionOffset() == funcOffset ) { found = true; @@ -357,8 +729,10 @@ void UnwindPrinter::printUnwindSection() fprintf(stderr, "MISSING LSDA entry for %s\n", functionName(funcOffset+fMachHeaderAddress)); } } - printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X %s\n", - j, entry[j].functionOffset(), entry[j].encoding(), functionName(entry[j].functionOffset()+fMachHeaderAddress)); + char encodingString[100]; + decode(entry[j].encoding(), ((const uint8_t*)fHeader)+funcOffset, encodingString); + printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X (%-40s) %s\n", + j, funcOffset, entry[j].encoding(), encodingString, functionName(funcOffset+fMachHeaderAddress)); } } else if ( page->kind() == UNWIND_SECOND_LEVEL_COMPRESSED ) { @@ -378,7 +752,9 @@ void UnwindPrinter::printUnwindSection() encoding = A::P::E::get32(commonEncodings[encodingIndex]); else encoding = A::P::E::get32(encodings[encodingIndex-sectionHeader->commonEncodingsArrayCount()]); + char encodingString[100]; uint32_t funcOff = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entries[j])+baseFunctionOffset; + decode(encoding, ((const uint8_t*)fHeader)+funcOff, encodingString); const char* name = functionName(funcOff+fMachHeaderAddress); if ( encoding & UNWIND_HAS_LSDA ) { // verify there is a corresponding entry in lsda table @@ -393,8 +769,8 @@ void UnwindPrinter::printUnwindSection() fprintf(stderr, "MISSING LSDA entry for %s\n", name); } } - printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%2u]=0x%08X %s\n", - j, funcOff, encodingIndex, encoding, name); + printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%3u]=0x%08X (%-40s) %s\n", + j, funcOff, encodingIndex, encoding, encodingString, name); } } else { diff --git a/unit-tests/test-cases/branch-islands/Makefile b/unit-tests/test-cases/branch-islands/Makefile index c85f382..471e446 100644 --- a/unit-tests/test-cases/branch-islands/Makefile +++ b/unit-tests/test-cases/branch-islands/Makefile @@ -1,5 +1,5 @@ ## -# Copyright (c) 2008 Apple Inc. All rights reserved. +# Copyright (c) 2008-2009 Apple Inc. All rights reserved. # # @APPLE_LICENSE_HEADER_START@ # @@ -23,13 +23,6 @@ TESTROOT = ../.. include ${TESTROOT}/include/common.makefile -ifeq ($(ARCH),armv6) - ARCH_FLAGS = -mlong-branch -else - ARCH_FLAGS = -endif - - # # Simple test for branch islands @@ -38,7 +31,6 @@ endif run: all - all: ${CC} ${CCFLAGS} hello.c space.s extra.c -o hello ${ARCH_FLAGS} ${PASS_IFF_GOOD_MACHO} hello diff --git a/unit-tests/test-cases/branch-islands/space.s b/unit-tests/test-cases/branch-islands/space.s index dd28637..0218bea 100644 --- a/unit-tests/test-cases/branch-islands/space.s +++ b/unit-tests/test-cases/branch-islands/space.s @@ -1,5 +1,5 @@ -#if __ppc__ +#if __ppc__ .text @@ -27,13 +27,50 @@ _space2: #if __arm__ + .text +_prejunk: + mov r0, #1 + nop + +#if __thumb2__ + // thumb2 branches are +/- 16MB +_space1: + .space 14*1024*1024 +_space2: + .space 14*1024*1024 +_space3: + .space 14*1024*1024 + +#elif __thumb__ + // thumb1 branches are +/- 4MB _space1: - .space 32*1024*1024 + 2 + .space 3*1024*1024 +_space2: + .space 3*1024*1024 +_space3: + .space 3*1024*1024 + +#else + // ARM branches are +/- 32MB +_space1: + .space 14*1024*1024 +_space2: + .space 14*1024*1024 +_space3: + .space 14*1024*1024 #endif + .align 5 +_junk: + mov r0, #1 + nop + + +_space4: + .space 2*1024*1024 +#endif .subsections_via_symbols - \ No newline at end of file diff --git a/unit-tests/test-cases/cfstring-utf16/Makefile b/unit-tests/test-cases/cfstring-utf16/Makefile index 3375aae..3957151 100644 --- a/unit-tests/test-cases/cfstring-utf16/Makefile +++ b/unit-tests/test-cases/cfstring-utf16/Makefile @@ -1,5 +1,5 @@ ## -# Copyright (c) 2008 Apple Inc. All rights reserved. +# Copyright (c) 2008-2009 Apple Inc. All rights reserved. # # @APPLE_LICENSE_HEADER_START@ # @@ -24,17 +24,17 @@ TESTROOT = ../.. include ${TESTROOT}/include/common.makefile # -# Test that utf16 cfstring literals are not coalesced. +# Test that utf16 cfstring literals are coalesced. # There is 3 CFSTR in foo.m and 1 CFSTR in bar.m -# After coalescing and dead stripping there should be only one CFSTR in the output +# After coalescing and dead stripping there should be only two CFSTR in the output # ifeq (,${findstring 64,$(ARCH)}) - CFSTRING_SIZE = 48 + CFSTRING_SIZE = 32 else - CFSTRING_SIZE = 96 + CFSTRING_SIZE = 64 endif - USTRING_SIZE = 37 + USTRING_SIZE = 27 diff --git a/unit-tests/test-cases/coalesce_weak_def_in_dylib/Makefile b/unit-tests/test-cases/coalesce_weak_def_in_dylib/Makefile new file mode 100644 index 0000000..72f365b --- /dev/null +++ b/unit-tests/test-cases/coalesce_weak_def_in_dylib/Makefile @@ -0,0 +1,55 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Test the if all symbols from a dylib are weak_import, that the whole dylib is weakly loaded +# + +run: all-${ARCH} + + +all-ppc: + ${PASS_IFF} true + +all-arm: + ${PASS_IFF} true + +all-i386: all-real + +all-x86_64: all-real + + +all-real: + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib + ${FAIL_IF_BAD_MACHO} libfoo.dylib + + ${CC} ${CCFLAGS} main.c -o main libfoo.dylib + dyldinfo -bind main | grep wfoo | ${FAIL_IF_EMPTY} + + ${PASS_IFF_GOOD_MACHO} main + + +clean: + rm -rf libfoo.dylib main diff --git a/unit-tests/test-cases/coalesce_weak_def_in_dylib/foo.c b/unit-tests/test-cases/coalesce_weak_def_in_dylib/foo.c new file mode 100644 index 0000000..1906d16 --- /dev/null +++ b/unit-tests/test-cases/coalesce_weak_def_in_dylib/foo.c @@ -0,0 +1,4 @@ + + +__attribute__((weak)) void wfoo() {} +void foo() {} diff --git a/unit-tests/test-cases/coalesce_weak_def_in_dylib/main.c b/unit-tests/test-cases/coalesce_weak_def_in_dylib/main.c new file mode 100644 index 0000000..afd696d --- /dev/null +++ b/unit-tests/test-cases/coalesce_weak_def_in_dylib/main.c @@ -0,0 +1,17 @@ + +extern void foo(); +extern void wfoo(); + +void* pfoo = &foo; +void* pwfoo = &wfoo; + +int main (void) +{ + if (pfoo != &foo) + return 1; + if (pwfoo != &wfoo) + return 1; + + return 0; +} + diff --git a/unit-tests/test-cases/cstring-alt-segment/Makefile b/unit-tests/test-cases/cstring-alt-segment/Makefile new file mode 100644 index 0000000..4e55304 --- /dev/null +++ b/unit-tests/test-cases/cstring-alt-segment/Makefile @@ -0,0 +1,39 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Check that __cstring sections in other segments are not coalesced +# ld coalesces C strings in different segments +# + +run: all + +all: + ${CC} ${CCFLAGS} main.c custom.s -o main + size -l main | grep __cstring | wc -l | grep 2 | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm main diff --git a/unit-tests/test-cases/cstring-alt-segment/custom.s b/unit-tests/test-cases/cstring-alt-segment/custom.s new file mode 100644 index 0000000..33705e5 --- /dev/null +++ b/unit-tests/test-cases/cstring-alt-segment/custom.s @@ -0,0 +1,8 @@ + + + + .section __MYSEG, __cstring, cstring_literals +LC: .ascii "hello" + + + diff --git a/unit-tests/test-cases/cstring-alt-segment/main.c b/unit-tests/test-cases/cstring-alt-segment/main.c new file mode 100644 index 0000000..8fe18db --- /dev/null +++ b/unit-tests/test-cases/cstring-alt-segment/main.c @@ -0,0 +1,7 @@ +#include + +int main() +{ + printf("hello"); + return 0; +} diff --git a/unit-tests/test-cases/cstring-labels/foo.c b/unit-tests/test-cases/cstring-labels/foo.c index efed306..0780b62 100644 --- a/unit-tests/test-cases/cstring-labels/foo.c +++ b/unit-tests/test-cases/cstring-labels/foo.c @@ -1,4 +1,6 @@ +void func() {} + const char kFoo[] = "foo"; const char* kFoo2 = "hello"; diff --git a/unit-tests/test-cases/dead_strip-r_symbol_desc/Makefile b/unit-tests/test-cases/dead_strip-r_symbol_desc/Makefile new file mode 100644 index 0000000..e60513e --- /dev/null +++ b/unit-tests/test-cases/dead_strip-r_symbol_desc/Makefile @@ -0,0 +1,43 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Test that N_NO_DEAD_STRIP bit survives ld -r +# + +run: all + +all: + ${CC} ${CCFLAGS} main.c -c -o main.o + nm -m main.o | grep _bar | grep "no dead strip" | ${FAIL_IF_EMPTY} + nm -m main.o | grep _foo | grep "no dead strip" | ${FAIL_IF_EMPTY} + ${LD} -r main.o -o main2.o + nm -m main2.o | grep _bar | grep "no dead strip" | ${FAIL_IF_EMPTY} + nm -m main2.o | grep _foo | grep "no dead strip" | ${FAIL_IF_EMPTY} + ${CC} main2.o -o main + nm -m main | grep _bar | grep "no dead strip" | ${PASS_IFF_EMPTY} + +clean: + rm -rf main.o main2.o main diff --git a/unit-tests/test-cases/dead_strip-r_symbol_desc/main.c b/unit-tests/test-cases/dead_strip-r_symbol_desc/main.c new file mode 100644 index 0000000..7e206e5 --- /dev/null +++ b/unit-tests/test-cases/dead_strip-r_symbol_desc/main.c @@ -0,0 +1,41 @@ +/* -*- 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@ + */ + + +__attribute__((used)) static void foo() +{ +} + + +__attribute__((used)) void bar() +{ +} + + +int main() +{ + foo(); + bar(); + return 0; +} diff --git a/unit-tests/test-cases/dead_strip-weak-coalesce/Makefile b/unit-tests/test-cases/dead_strip-weak-coalesce/Makefile new file mode 100644 index 0000000..45886c0 --- /dev/null +++ b/unit-tests/test-cases/dead_strip-weak-coalesce/Makefile @@ -0,0 +1,41 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Check that symbols in no-dead-strip sections can be coalesced. +# -dead_strip inhibits weak coalescing in no_dead_strip section +# + +run: all + +all: + ${CC} ${CCFLAGS} baz.c -c -o baz.o + libtool -static baz.o -o libbaz.a + ${CC} ${CCFLAGS} main.c foo.c libbaz.a -dead_strip -o main + nm -j main | grep _hidden | wc -l | grep 1 | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf main baz.o libbaz.a diff --git a/unit-tests/test-cases/dead_strip-weak-coalesce/baz.c b/unit-tests/test-cases/dead_strip-weak-coalesce/baz.c new file mode 100644 index 0000000..7d76bdd --- /dev/null +++ b/unit-tests/test-cases/dead_strip-weak-coalesce/baz.c @@ -0,0 +1,7 @@ +void baz() +{ +} + + +#include "foo.c" + diff --git a/unit-tests/test-cases/dead_strip-weak-coalesce/foo.c b/unit-tests/test-cases/dead_strip-weak-coalesce/foo.c new file mode 100644 index 0000000..4cd4cfb --- /dev/null +++ b/unit-tests/test-cases/dead_strip-weak-coalesce/foo.c @@ -0,0 +1,25 @@ + +// function can be coalesced and should not be dead stripped +void __attribute__ ((weak, section ("__TEXT,__text_no_strip,regular,no_dead_strip"))) foo() +{ + +} + + +// function should not be exported, can be coalesced, and should not be dead stripped +void __attribute__ ((weak, visibility("hidden"), section ("__TEXT,__text_no_strip,regular,no_dead_strip"))) hidden() +{ + +} + +// bar should be dead stripped +void __attribute__ ((weak, section ("__DATA,__text2"))) bar() +{ + +} + +__attribute__((constructor)) static void init() +{ + foo(); + hidden(); +} diff --git a/unit-tests/test-cases/dead_strip-weak-coalesce/main.c b/unit-tests/test-cases/dead_strip-weak-coalesce/main.c new file mode 100644 index 0000000..e4c564c --- /dev/null +++ b/unit-tests/test-cases/dead_strip-weak-coalesce/main.c @@ -0,0 +1,13 @@ + +// baz is in a lazily loaded archive +extern void baz(); + +int main() +{ + baz(); + return 0; +} + + +#include "foo.c" + diff --git a/unit-tests/test-cases/eh-coalescing-no-labels/Makefile b/unit-tests/test-cases/eh-coalescing-no-labels/Makefile index 8ce50d6..27cd180 100644 --- a/unit-tests/test-cases/eh-coalescing-no-labels/Makefile +++ b/unit-tests/test-cases/eh-coalescing-no-labels/Makefile @@ -43,7 +43,7 @@ all: ${LD} -r foo.no.o bar.no.o baz.no.o -o foobarbaz.no.o ${OBJECTDUMP} -no_content -no_sort foobarbaz.o > foobarbaz.dump ${OBJECTDUMP} -no_content -no_sort foobarbaz.no.o > foobarbaz.no.dump - ${FAIL_IF_ERROR} dwarfdump --eh-frame --verify >/dev/null + ${FAIL_IF_ERROR} dwarfdump --eh-frame --verify foobarbaz.no.o >/dev/null ${PASS_IFF_SUCCESS} diff foobarbaz.dump foobarbaz.no.dump diff --git a/unit-tests/test-cases/init-order/Makefile b/unit-tests/test-cases/init-order/Makefile index bb67908..7e8c6e1 100644 --- a/unit-tests/test-cases/init-order/Makefile +++ b/unit-tests/test-cases/init-order/Makefile @@ -33,8 +33,8 @@ include ${TESTROOT}/include/common.makefile run: all all: - ${CXX} ${CXXFLAGS} main.cxx foo.cxx bar.cxx -o main - nm -s __TEXT __text -nj main | c++filt > actual-order.txt + ${CXX} ${CXXFLAGS} main.cxx foo.cxx bar.cxx -o main -dead_strip + nm -s __TEXT __text -nj main | grep -v dyld_stub_binding_helper | c++filt > actual-order.txt ${PASS_IFF} diff actual-order.txt expected-order.txt diff --git a/unit-tests/test-cases/init-order/expected-order.txt b/unit-tests/test-cases/init-order/expected-order.txt index 1de60f3..9a303d3 100644 --- a/unit-tests/test-cases/init-order/expected-order.txt +++ b/unit-tests/test-cases/init-order/expected-order.txt @@ -8,8 +8,6 @@ Bar::Bar() __static_initialization_and_destruction_0(int, int) global constructors keyed to b1 start -dyld_stub_binding_helper -__dyld_func_lookup _main M::~M() Foo::~Foo() diff --git a/unit-tests/test-cases/kext-basic/Makefile b/unit-tests/test-cases/kext-basic/Makefile index 6a318b3..d233171 100644 --- a/unit-tests/test-cases/kext-basic/Makefile +++ b/unit-tests/test-cases/kext-basic/Makefile @@ -23,7 +23,6 @@ all: nm -nm mykext | grep '(undefined) external _extern_global' | ${FAIL_IF_EMPTY} nm -nm mykext | grep '(__DATA,__data) external _my_global' | ${FAIL_IF_EMPTY} otool -rv mykext | grep '_extern_global' | ${FAIL_IF_EMPTY} - otool -rv mykext | grep '_OSRuntimeFinalizeCPP' | ${FAIL_IF_EMPTY} ${PASS_IFF} true clean: diff --git a/unit-tests/test-cases/label-on-end-of-section/Makefile b/unit-tests/test-cases/label-on-end-of-section/Makefile old mode 100644 new mode 100755 diff --git a/unit-tests/test-cases/label-on-end-of-section/foo.s b/unit-tests/test-cases/label-on-end-of-section/foo.s old mode 100644 new mode 100755 diff --git a/unit-tests/test-cases/lto-dead_strip-all-hidden/Makefile b/unit-tests/test-cases/lto-dead_strip-all-hidden/Makefile new file mode 100644 index 0000000..060e5a1 --- /dev/null +++ b/unit-tests/test-cases/lto-dead_strip-all-hidden/Makefile @@ -0,0 +1,41 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Link Time Optimization error with 'dead code strip' + hidden symbol +# + +LLVMGCC = /Developer/usr/bin/llvm-gcc-4.2 -arch ${ARCH} +LLVMGXX = /Developer/usr/bin/llvm-g++-4.2 -arch ${ARCH} + +run: all + +all: + ${LLVMGCC} ${CCFLAGS} --emit-llvm bar.c -c -o bar.o -fvisibility=hidden + ${LLVMGCC} ${CCFLAGS} -dynamiclib bar.o -o libbar.dylib -dead_strip + ${PASS_IFF_GOOD_MACHO} libbar.dylib + +clean: + rm bar.o libbar.dylib diff --git a/unit-tests/test-cases/lto-dead_strip-all-hidden/bar.c b/unit-tests/test-cases/lto-dead_strip-all-hidden/bar.c new file mode 100644 index 0000000..b3e3958 --- /dev/null +++ b/unit-tests/test-cases/lto-dead_strip-all-hidden/bar.c @@ -0,0 +1,4 @@ + + +void bar() {} + diff --git a/unit-tests/test-cases/lto-llvm-options/Makefile b/unit-tests/test-cases/lto-llvm-options/Makefile index 5d4e991..1edf08a 100644 --- a/unit-tests/test-cases/lto-llvm-options/Makefile +++ b/unit-tests/test-cases/lto-llvm-options/Makefile @@ -34,10 +34,10 @@ LLVMGXX = /Developer/usr/bin/llvm-g++-4.2 -arch ${ARCH} run: all all: - ${LLVMGCC} ${CCFLAGS} --emit-llvm main.c -c -o main.o + ${LLVMGCC} ${CCFLAGS} --emit-llvm main.c -c -o main.o -fvisibility=hidden ${LLVMGCC} ${CCFLAGS} main.o -o main nm main | grep _foo | ${FAIL_IF_STDIN} - ${LLVMGCC} ${CCFLAGS} main.o -o main2 -Wl,-mllvm -Wl,--disable-inlining + ${LLVMGCC} ${CCFLAGS} main.o -o main2 -fvisibility=hidden -Wl,-mllvm -Wl,--disable-inlining nm main2 | grep _foo | ${FAIL_IF_EMPTY} ${PASS_IFF_GOOD_MACHO} main diff --git a/unit-tests/test-cases/lto-objc-archive/Makefile b/unit-tests/test-cases/lto-objc-archive/Makefile new file mode 100644 index 0000000..57fae1d --- /dev/null +++ b/unit-tests/test-cases/lto-objc-archive/Makefile @@ -0,0 +1,47 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# link failure with -O4 on i386# +# Check that LTO can bring in an ObjC class from an archive member +# + +LLVMGCC = /Developer/usr/bin/llvm-gcc-4.2 -arch ${ARCH} +LLVMGXX = /Developer/usr/bin/llvm-g++-4.2 -arch ${ARCH} + +run: all + +all: + ${CC} ${CCFLAGS} foo.m -c -o foo.o + ${CC} ${CCFLAGS} bar.m -c -o bar.o + ${CC} ${CCFLAGS} foo2.c -c -o foo2.o + ${CC} ${CCFLAGS} bar2.c -c -o bar2.o + libtool -static foo.o bar.o foo2.o bar2.o -o libfoobar.a + ${LLVMGCC} ${CCFLAGS} --emit-llvm main.m -c -o main.o + ${LLVMGCC} ${CCFLAGS} main.o -o main libfoobar.a -framework Foundation + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf main foo.o bar.o foo2.o bar2.o libfoobar.a main.o diff --git a/unit-tests/test-cases/lto-objc-archive/bar.h b/unit-tests/test-cases/lto-objc-archive/bar.h new file mode 100644 index 0000000..b7daf1f --- /dev/null +++ b/unit-tests/test-cases/lto-objc-archive/bar.h @@ -0,0 +1,6 @@ +#include + +@interface Bar : NSObject +@end + +extern void bar2(); diff --git a/unit-tests/test-cases/lto-objc-archive/bar.m b/unit-tests/test-cases/lto-objc-archive/bar.m new file mode 100644 index 0000000..ef32e97 --- /dev/null +++ b/unit-tests/test-cases/lto-objc-archive/bar.m @@ -0,0 +1,7 @@ +#include "bar.h" + +@implementation Bar +- (void) test { + bar2(); +} +@end diff --git a/unit-tests/test-cases/lto-objc-archive/bar2.c b/unit-tests/test-cases/lto-objc-archive/bar2.c new file mode 100644 index 0000000..1422109 --- /dev/null +++ b/unit-tests/test-cases/lto-objc-archive/bar2.c @@ -0,0 +1,2 @@ + +void bar2() {} diff --git a/unit-tests/test-cases/lto-objc-archive/foo.h b/unit-tests/test-cases/lto-objc-archive/foo.h new file mode 100644 index 0000000..6c3fab2 --- /dev/null +++ b/unit-tests/test-cases/lto-objc-archive/foo.h @@ -0,0 +1,8 @@ +#include + +@interface Foo : NSObject +@end + + +extern void foo2(); + diff --git a/unit-tests/test-cases/lto-objc-archive/foo.m b/unit-tests/test-cases/lto-objc-archive/foo.m new file mode 100644 index 0000000..90543e0 --- /dev/null +++ b/unit-tests/test-cases/lto-objc-archive/foo.m @@ -0,0 +1,8 @@ + +#include "foo.h" + +@implementation Foo +- (void) test { + foo2(); +} +@end diff --git a/unit-tests/test-cases/lto-objc-archive/foo2.c b/unit-tests/test-cases/lto-objc-archive/foo2.c new file mode 100644 index 0000000..9d2ab14 --- /dev/null +++ b/unit-tests/test-cases/lto-objc-archive/foo2.c @@ -0,0 +1,2 @@ + +void foo2() {} diff --git a/unit-tests/test-cases/lto-objc-archive/main.m b/unit-tests/test-cases/lto-objc-archive/main.m new file mode 100644 index 0000000..b84612d --- /dev/null +++ b/unit-tests/test-cases/lto-objc-archive/main.m @@ -0,0 +1,20 @@ + +#include +#include "foo.h" +#include "bar.h" + + +@interface FooSubClass : Foo +@end + + +@implementation FooSubClass +@end + + +int main() +{ + [Bar alloc]; + return 0; +} + diff --git a/unit-tests/test-cases/lto-weak_import/Makefile b/unit-tests/test-cases/lto-weak_import/Makefile new file mode 100644 index 0000000..e53ad48 --- /dev/null +++ b/unit-tests/test-cases/lto-weak_import/Makefile @@ -0,0 +1,43 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# link failure with -O4 on i386# +# Check that LTO can bring in an ObjC class from an archive member +# + +LLVMGCC = /Developer/usr/bin/llvm-gcc-4.2 -arch ${ARCH} +LLVMGXX = /Developer/usr/bin/llvm-g++-4.2 -arch ${ARCH} + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib + ${LLVMGCC} ${CCFLAGS} --emit-llvm main.c -c -o main.o + ${LLVMGCC} ${CCFLAGS} main.o -o main libfoo.dylib + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf main main.o libfoo.dylib diff --git a/unit-tests/test-cases/lto-weak_import/foo.c b/unit-tests/test-cases/lto-weak_import/foo.c new file mode 100644 index 0000000..b586675 --- /dev/null +++ b/unit-tests/test-cases/lto-weak_import/foo.c @@ -0,0 +1,3 @@ + + +void foo() {} diff --git a/unit-tests/test-cases/lto-weak_import/main.c b/unit-tests/test-cases/lto-weak_import/main.c new file mode 100644 index 0000000..d36ba48 --- /dev/null +++ b/unit-tests/test-cases/lto-weak_import/main.c @@ -0,0 +1,13 @@ + +#include + +extern void foo() __attribute__((weak_import)); + + +int main() +{ + if ( &foo != NULL ) + foo(); + return 0; +} + diff --git a/unit-tests/test-cases/no-data-bundle/Makefile b/unit-tests/test-cases/no-data-bundle/Makefile new file mode 100644 index 0000000..e1417fd --- /dev/null +++ b/unit-tests/test-cases/no-data-bundle/Makefile @@ -0,0 +1,38 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Check that a bundle built with no data links +# gcc DejaGnu failure: building longcall/dylib library +# + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -bundle -o foo.bundle + ${PASS_IFF_GOOD_MACHO} foo.bundle + +clean: + rm foo.bundle diff --git a/unit-tests/test-cases/no-data-bundle/foo.c b/unit-tests/test-cases/no-data-bundle/foo.c new file mode 100644 index 0000000..5cb3e31 --- /dev/null +++ b/unit-tests/test-cases/no-data-bundle/foo.c @@ -0,0 +1,6 @@ +#include + +void foo() +{ + rand(); +} \ No newline at end of file diff --git a/unit-tests/test-cases/no_zero_fill_sections/Makefile b/unit-tests/test-cases/no_zero_fill_sections/Makefile old mode 100644 new mode 100755 diff --git a/unit-tests/test-cases/no_zero_fill_sections/main.c b/unit-tests/test-cases/no_zero_fill_sections/main.c old mode 100644 new mode 100755 diff --git a/unit-tests/test-cases/objc-literal-pointers-strip/Makefile b/unit-tests/test-cases/objc-literal-pointers-strip/Makefile new file mode 100644 index 0000000..76a7347 --- /dev/null +++ b/unit-tests/test-cases/objc-literal-pointers-strip/Makefile @@ -0,0 +1,57 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + + +# +# Verify an Objective-C object file when run through +# ld -r -x +# x86_64 obj-c runtime confused when static lib is stripped +# +# + +SELECTOR_REFS = "__OBJC,__message_refs" + +ifeq ($(ARCH),x86_64) + SELECTOR_REFS = "__DATA,__objc_selrefs" +endif +ifeq ($(ARCH),armv6) + SELECTOR_REFS = "__DATA,__objc_selrefs" +endif + + + +run: all + +all: + ${CC} ${CCFLAGS} test.m -c -o test.o + ${OBJECTDUMP} -no_content test.o | grep -B3 -A6 ${SELECTOR_REFS} > test.dump + + ${LD} -arch ${ARCH} -r test.o -x -o test-r.o + ${OBJECTDUMP} -no_content test-r.o | grep -B3 -A6 ${SELECTOR_REFS} > test-r.dump + + diff test.dump test-r.dump | ${PASS_IFF_EMPTY} + +clean: + rm -rf test.o test.dump test-r.o test-r.dump diff --git a/unit-tests/test-cases/objc-literal-pointers-strip/test.m b/unit-tests/test-cases/objc-literal-pointers-strip/test.m new file mode 100644 index 0000000..4837911 --- /dev/null +++ b/unit-tests/test-cases/objc-literal-pointers-strip/test.m @@ -0,0 +1,46 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2009 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include +#include + +@interface Foo @end +@implementation Foo ++(void)initialize { } ++(void)foo { + fprintf(stderr, "GOOD\n"); + exit(0); +} ++(void)bar { + fprintf(stderr, "BAD\n"); + abort(); +} +@end + +void PublicFunction(void) +{ + [Foo foo]; + [Foo bar]; +} diff --git a/unit-tests/test-cases/operator-new/Makefile b/unit-tests/test-cases/operator-new/Makefile index 8abf3e1..447ee87 100644 --- a/unit-tests/test-cases/operator-new/Makefile +++ b/unit-tests/test-cases/operator-new/Makefile @@ -1,5 +1,5 @@ ## -# Copyright (c) 2006-2007 Apple Inc. All rights reserved. +# Copyright (c) 2006-2009 Apple Inc. All rights reserved. # # @APPLE_LICENSE_HEADER_START@ # @@ -30,6 +30,9 @@ all: # verify if operator new is overridden that WEAK_DEFINES is set ${CXX} ${CXXFLAGS} -DOP_NEW -I${TESTROOT}/include -o main main.cxx otool -hv main | grep WEAK_DEFINES | ${FAIL_IF_EMPTY} + # verify if operator new is overridden but not exported, WEAK_DEFINES is not set + ${CXX} ${CXXFLAGS} -DOP_NEW -I${TESTROOT}/include -o main main.cxx -Wl,-exported_symbol,_main + otool -hv main | grep WEAK_DEFINES | ${FAIL_IF_STDIN} # verify if operator new is not overridden that WEAK_DEFINES is not set ${CXX} ${CXXFLAGS} -I${TESTROOT}/include -o main main.cxx otool -hv main | grep WEAK_DEFINES | ${PASS_IFF_EMPTY} diff --git a/unit-tests/test-cases/operator-new/main.cxx b/unit-tests/test-cases/operator-new/main.cxx index 3c99e35..b5d3272 100644 --- a/unit-tests/test-cases/operator-new/main.cxx +++ b/unit-tests/test-cases/operator-new/main.cxx @@ -36,7 +36,7 @@ #if OP_NEW void* operator new(size_t s) throw (std::bad_alloc) { - return malloc(s);; + return malloc(s); } #endif diff --git a/unit-tests/test-cases/re-export-optimizations-indirect/Makefile b/unit-tests/test-cases/re-export-optimizations-indirect/Makefile new file mode 100644 index 0000000..fdb13d5 --- /dev/null +++ b/unit-tests/test-cases/re-export-optimizations-indirect/Makefile @@ -0,0 +1,64 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Test that a public re-exported library is automatically added as a dependent +# unless nothing is used from it. +# + + +run: all + +all: + +# -sub_library for 10.4 + ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -install_name /usr/lib/libbar.dylib -mmacosx-version-min=10.4 + ${FAIL_IF_BAD_MACHO} libbar.dylib + ${CC} ${CCFLAGS} -dynamiclib middle.c -o libmiddle.dylib -lbar -L. -sub_library libbar -install_name /mid/libmiddle.dylib -mmacosx-version-min=10.4 + ${FAIL_IF_BAD_MACHO} libmiddle.dylib + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lmiddle -L. -sub_library libmiddle -install_name /usr/lib/libfoo.dylib -mmacosx-version-min=10.4 + ${FAIL_IF_BAD_MACHO} libfoo.dylib + ${CC} ${CCFLAGS} -dynamiclib other.c -o libother.dylib -lbar -L. -sub_library libbar -install_name /usr/lib/libother.dylib -mmacosx-version-min=10.4 + ${FAIL_IF_BAD_MACHO} libother.dylib + ${CC} ${CCFLAGS} main.c -DCALL_BAR libfoo.dylib libother.dylib -o main -L. -mmacosx-version-min=10.4 + nm -m main | grep _bar | grep libbar | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main + +# -sub_library for 10.5 + ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -install_name /usr/lib/libbar.dylib -mmacosx-version-min=10.5 + ${FAIL_IF_BAD_MACHO} libbar.dylib + ${CC} ${CCFLAGS} -dynamiclib middle.c -o libmiddle.dylib -lbar -L. -sub_library libbar -install_name /mid/libmiddle.dylib -mmacosx-version-min=10.5 + ${FAIL_IF_BAD_MACHO} libmiddle.dylib + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lmiddle -L. -sub_library libmiddle -install_name /usr/lib/libfoo.dylib -mmacosx-version-min=10.5 + ${FAIL_IF_BAD_MACHO} libfoo.dylib + ${CC} ${CCFLAGS} -dynamiclib other.c -o libother.dylib -lbar -L. -sub_library libbar -install_name /usr/lib/libother.dylib -mmacosx-version-min=10.5 + ${FAIL_IF_BAD_MACHO} libother.dylib + ${CC} ${CCFLAGS} main.c -DCALL_BAR libfoo.dylib libother.dylib -o main -L. -mmacosx-version-min=10.5 + nm -m main | grep _bar | grep libbar | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main + + +clean: + rm -rf libbar.dylib libfoo.dylib libmiddle.dylib libother.dylib main diff --git a/unit-tests/test-cases/re-export-optimizations-indirect/bar.c b/unit-tests/test-cases/re-export-optimizations-indirect/bar.c new file mode 100644 index 0000000..9c18401 --- /dev/null +++ b/unit-tests/test-cases/re-export-optimizations-indirect/bar.c @@ -0,0 +1,5 @@ + +int bar (void) +{ + return 1; +} diff --git a/unit-tests/test-cases/re-export-optimizations-indirect/foo.c b/unit-tests/test-cases/re-export-optimizations-indirect/foo.c new file mode 100644 index 0000000..d0cdf47 --- /dev/null +++ b/unit-tests/test-cases/re-export-optimizations-indirect/foo.c @@ -0,0 +1,4 @@ +int foo (void) +{ + return 1; +} diff --git a/unit-tests/test-cases/re-export-optimizations-indirect/main.c b/unit-tests/test-cases/re-export-optimizations-indirect/main.c new file mode 100644 index 0000000..672ef9a --- /dev/null +++ b/unit-tests/test-cases/re-export-optimizations-indirect/main.c @@ -0,0 +1,8 @@ + +extern void bar(); + +int main() +{ + bar(); + return 0; +} diff --git a/unit-tests/test-cases/re-export-optimizations-indirect/middle.c b/unit-tests/test-cases/re-export-optimizations-indirect/middle.c new file mode 100644 index 0000000..d3578a6 --- /dev/null +++ b/unit-tests/test-cases/re-export-optimizations-indirect/middle.c @@ -0,0 +1,3 @@ + +void middle() {} + diff --git a/unit-tests/test-cases/re-export-optimizations-indirect/other.c b/unit-tests/test-cases/re-export-optimizations-indirect/other.c new file mode 100644 index 0000000..0cd6dda --- /dev/null +++ b/unit-tests/test-cases/re-export-optimizations-indirect/other.c @@ -0,0 +1 @@ +void other() {} diff --git a/unit-tests/test-cases/relocs-neg-from-local/Makefile b/unit-tests/test-cases/relocs-neg-from-local/Makefile new file mode 100644 index 0000000..36fb47b --- /dev/null +++ b/unit-tests/test-cases/relocs-neg-from-local/Makefile @@ -0,0 +1,51 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# i386 relocation error with negative offsets from local labels +# + +ifeq (${ARCH},i386) + TARGET = run-i386 +else + TARGET = run-other +endif + +run: ${TARGET} + +run-other: + ${PASS_IFF} /usr/bin/true + + +run-i386: + ${CC} ${ASMFLAGS} test.s -c -o test.o + ${OBJECTDUMP} test.o | grep "__data@0 plus 0xFFFFFFE2" | ${FAIL_IF_EMPTY} + + ${LD} -arch ${ARCH} -r -keep_private_externs test.o -o test-r.o + ${OBJECTDUMP} test-r.o | grep "__data@0 plus 0xFFFFFFE2" | ${PASS_IFF_STDIN} + + +clean: + rm -rf *.o diff --git a/unit-tests/test-cases/relocs-neg-from-local/test.s b/unit-tests/test-cases/relocs-neg-from-local/test.s new file mode 100644 index 0000000..3890f35 --- /dev/null +++ b/unit-tests/test-cases/relocs-neg-from-local/test.s @@ -0,0 +1,43 @@ +/* + * 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@ + */ + + + +#if __i386__ + .text + .align 2 + +_negative_offset_from_local_label: + nop + .space 100 + movl -80+L3(,%eax,4), %edx + ret + + .data +L2: .space 50 +L3: .space 50 +_d: .long 0 + +#endif + + diff --git a/unit-tests/test-cases/section-names-long/Makefile b/unit-tests/test-cases/section-names-long/Makefile new file mode 100644 index 0000000..f31d9d6 --- /dev/null +++ b/unit-tests/test-cases/section-names-long/Makefile @@ -0,0 +1,42 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Validate long section names are preserved +# corrupt metaclass entry in dynamic library +# + +all: + ${CC} ${CCFLAGS} main.c a.s c.s b.s -o main + nm -m main | grep __aaaaaaaaaaaaaa | grep __TEXT | grep _at | ${FAIL_IF_EMPTY} + nm -m main | grep __bbbbbbbbbbbbbb | grep __TEXT | grep _bt | ${FAIL_IF_EMPTY} + nm -m main | grep __cccccccccccccc | grep __TEXT | grep _ct | ${FAIL_IF_EMPTY} + nm -m main | grep __aaaaaaaaaaaaaa | grep __DATA | grep _ad | ${FAIL_IF_EMPTY} + nm -m main | grep __bbbbbbbbbbbbbb | grep __DATA | grep _bd | ${FAIL_IF_EMPTY} + nm -m main | grep __cccccccccccccc | grep __DATA | grep _cd | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf main diff --git a/unit-tests/test-cases/section-names-long/a.s b/unit-tests/test-cases/section-names-long/a.s new file mode 100644 index 0000000..d7e5847 --- /dev/null +++ b/unit-tests/test-cases/section-names-long/a.s @@ -0,0 +1,9 @@ + + .section __TEXT,__aaaaaaaaaaaaaa +_at: .space 128 + + .section __DATA,__aaaaaaaaaaaaaa +_ad: .space 128 + + + diff --git a/unit-tests/test-cases/section-names-long/b.s b/unit-tests/test-cases/section-names-long/b.s new file mode 100644 index 0000000..a31d414 --- /dev/null +++ b/unit-tests/test-cases/section-names-long/b.s @@ -0,0 +1,9 @@ + + .section __TEXT,__bbbbbbbbbbbbbb +_bt: .space 128 + + .section __DATA,__bbbbbbbbbbbbbb +_bd: .space 128 + + + diff --git a/unit-tests/test-cases/section-names-long/c.s b/unit-tests/test-cases/section-names-long/c.s new file mode 100644 index 0000000..383b159 --- /dev/null +++ b/unit-tests/test-cases/section-names-long/c.s @@ -0,0 +1,11 @@ + + .section __TEXT,__cccccccccccccc +_ct: .space 128 + + + .section __DATA,__cccccccccccccc +_cd: .space 128 + + + + diff --git a/unit-tests/test-cases/section-names-long/main.c b/unit-tests/test-cases/section-names-long/main.c new file mode 100644 index 0000000..df77448 --- /dev/null +++ b/unit-tests/test-cases/section-names-long/main.c @@ -0,0 +1,4 @@ + + +int main() { return 0; } + diff --git a/unit-tests/test-cases/shared-cache-dylib/Makefile b/unit-tests/test-cases/shared-cache-dylib/Makefile new file mode 100644 index 0000000..cd6dc04 --- /dev/null +++ b/unit-tests/test-cases/shared-cache-dylib/Makefile @@ -0,0 +1,46 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Verify only dylibs with install paths in /System/Library or /usr/lib +# get LC_SEGMENT_SPLIT_INFO +# + + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -install_name /usr/lib/libfoo.dylib + otool -lv libfoo.dylib | grep LC_SEGMENT_SPLIT_INFO | ${FAIL_IF_EMPTY} + ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -install_name /System/Library/Frameworks/Foo.framework/Foo + otool -lv libfoo.dylib | grep LC_SEGMENT_SPLIT_INFO | ${FAIL_IF_EMPTY} + ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -install_name /usr/local/lib/libfoo.dylib + otool -lv libfoo.dylib | grep LC_SEGMENT_SPLIT_INFO | ${FAIL_IF_STDIN} + ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib + otool -lv libfoo.dylib | grep LC_SEGMENT_SPLIT_INFO | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} libfoo.dylib + +clean: + rm libfoo.dylib diff --git a/unit-tests/test-cases/shared-cache-dylib/foo.c b/unit-tests/test-cases/shared-cache-dylib/foo.c new file mode 100644 index 0000000..6924ac6 --- /dev/null +++ b/unit-tests/test-cases/shared-cache-dylib/foo.c @@ -0,0 +1,3 @@ + +void foo() {} + diff --git a/unit-tests/test-cases/stripped-indirect-symbol-table/Makefile b/unit-tests/test-cases/stripped-indirect-symbol-table/Makefile index c0647b3..fcb7e7d 100644 --- a/unit-tests/test-cases/stripped-indirect-symbol-table/Makefile +++ b/unit-tests/test-cases/stripped-indirect-symbol-table/Makefile @@ -1,5 +1,5 @@ ## -# Copyright (c) 2007 Apple Inc. All rights reserved. +# Copyright (c) 2007-2009 Apple Inc. All rights reserved. # # @APPLE_LICENSE_HEADER_START@ # @@ -23,18 +23,14 @@ TESTROOT = ../.. include ${TESTROOT}/include/common.makefile -ifeq "${ARCH}" "i386" - POINTER_SEGMENT = __IMPORT - POINTER_SECTION = __pointers -else - POINTER_SEGMENT = __DATA - POINTER_SECTION = __nl_symbol_ptr -endif +POINTER_SEGMENT = __DATA +POINTER_SECTION = __nl_symbol_ptr # # Test that using strip -R to selectively strip symbol names # of of a .o file still works with ld. +# And for i386 that there are no __IMPORT/__pointers left # run: all @@ -51,6 +47,8 @@ all: ${CC} ${CCFLAGS} all.o -dynamiclib -o dylib2 otool -X -s ${POINTER_SEGMENT} ${POINTER_SECTION} dylib1 >dylib1.pointers otool -X -s ${POINTER_SEGMENT} ${POINTER_SECTION} dylib2 >dylib2.pointers + size -l dylib1 | grep __IMPORT | ${FAIL_IF_STDIN} + size -l dylib2 | grep __IMPORT | ${FAIL_IF_STDIN} ${PASS_IFF} diff dylib1.pointers dylib2.pointers clean: diff --git a/unit-tests/test-cases/weak_import/Makefile b/unit-tests/test-cases/weak_import/Makefile index d1fa1f3..cdacfc9 100644 --- a/unit-tests/test-cases/weak_import/Makefile +++ b/unit-tests/test-cases/weak_import/Makefile @@ -34,7 +34,7 @@ all: ${CC} ${CCFLAGS} -dynamiclib -single_module foo.c -o libfoo-${ARCH}.dylib ${FAIL_IF_BAD_MACHO} libfoo-${ARCH}.dylib - ${CC} ${CCFLAGS} -mmacosx-version-min=10.4 main.c -o main-${ARCH} libfoo-${ARCH}.dylib + ${CC} ${CCFLAGS} main.c -o main-${ARCH} libfoo-${ARCH}.dylib nm -m main-${ARCH} | grep _func1 | grep -v weak >/dev/null nm -m main-${ARCH} | grep _func2 | grep weak >/dev/null nm -m main-${ARCH} | grep _func3 | grep -v weak >/dev/null @@ -43,10 +43,12 @@ all: nm -m main-${ARCH} | grep _data2 | grep weak >/dev/null nm -m main-${ARCH} | grep _data3 | grep -v weak >/dev/null nm -m main-${ARCH} | grep _data4 | grep weak >/dev/null - otool -rv main-${ARCH} | grep _data6 > /dev/null + nm -m main-${ARCH} | grep _data5 | grep -v weak >/dev/null + nm -m main-${ARCH} | grep _data6 | grep weak >/dev/null + #otool -rv main-${ARCH} | grep _data6 > /dev/null ${FAIL_IF_BAD_MACHO} main-${ARCH} - ${CC} ${CCFLAGS} -mmacosx-version-min=10.4 main.c -dynamiclib -o main-${ARCH}.dylib libfoo-${ARCH}.dylib + ${CC} ${CCFLAGS} main.c -dynamiclib -o main-${ARCH}.dylib libfoo-${ARCH}.dylib nm -m main-${ARCH}.dylib | grep _func1 | grep -v weak >/dev/null nm -m main-${ARCH}.dylib | grep _func2 | grep weak >/dev/null nm -m main-${ARCH}.dylib | grep _func3 | grep -v weak >/dev/null @@ -55,7 +57,7 @@ all: nm -m main-${ARCH}.dylib | grep _data2 | grep weak >/dev/null nm -m main-${ARCH}.dylib | grep _data3 | grep -v weak >/dev/null nm -m main-${ARCH}.dylib | grep _data4 | grep weak >/dev/null - otool -rv main-${ARCH}.dylib | grep _data6 > /dev/null + #otool -rv main-${ARCH}.dylib | grep _data6 > /dev/null ${PASS_IFF_GOOD_MACHO} main-${ARCH}.dylib clean: