]> git.saurik.com Git - apple/ld64.git/commitdiff
ld64-127.2.tar.gz developer-tools-42 ios-50 ios-51 ios-511 v127.2
authorApple <opensource@apple.com>
Mon, 15 Aug 2011 22:56:20 +0000 (22:56 +0000)
committerApple <opensource@apple.com>
Mon, 15 Aug 2011 22:56:20 +0000 (22:56 +0000)
192 files changed:
ChangeLog
doc/man/man1/ld.1
ld64.xcodeproj/project.pbxproj
src/abstraction/MachOFileAbstraction.hpp
src/ld/HeaderAndLoadCommands.hpp
src/ld/InputFiles.cpp
src/ld/InputFiles.h
src/ld/LinkEdit.hpp
src/ld/LinkEditClassic.hpp
src/ld/Options.cpp
src/ld/Options.h
src/ld/OutputFile.cpp
src/ld/OutputFile.h
src/ld/Resolver.cpp
src/ld/SymbolTable.cpp
src/ld/debugline.c
src/ld/dwarf2.h
src/ld/ld.cpp
src/ld/ld.hpp
src/ld/parsers/archive_file.cpp
src/ld/parsers/archive_file.h
src/ld/parsers/libunwind/AddressSpace.hpp [new file with mode: 0644]
src/ld/parsers/libunwind/DwarfInstructions.hpp [new file with mode: 0644]
src/ld/parsers/libunwind/DwarfParser.hpp [new file with mode: 0644]
src/ld/parsers/libunwind/InternalMacros.h [new file with mode: 0644]
src/ld/parsers/libunwind/Registers.hpp [new file with mode: 0644]
src/ld/parsers/lto_file.cpp
src/ld/parsers/macho_dylib_file.cpp
src/ld/parsers/macho_dylib_file.h
src/ld/parsers/macho_relocatable_file.cpp
src/ld/passes/branch_island.cpp
src/ld/passes/branch_shim.cpp
src/ld/passes/compact_unwind.cpp
src/ld/passes/dylibs.cpp
src/ld/passes/got.cpp
src/ld/passes/objc.cpp
src/ld/passes/order_file.cpp
src/ld/passes/stubs/stubs.cpp
src/ld/passes/tlvp.cpp
src/other/ObjectDump.cpp
src/other/dyldinfo.cpp
src/other/machochecker.cpp
src/other/rebase.cpp
src/other/unwinddump.cpp
unit-tests/include/common.makefile
unit-tests/run-all-unit-tests
unit-tests/test-cases/absolute-symbol/Makefile
unit-tests/test-cases/absolute-symbol/abs.s
unit-tests/test-cases/alias-command-line/aliases.s
unit-tests/test-cases/alias-objects/aliases.s
unit-tests/test-cases/archive-image_info/Makefile
unit-tests/test-cases/archive-order/Makefile [new file with mode: 0644]
unit-tests/test-cases/archive-order/bar.c [new file with mode: 0644]
unit-tests/test-cases/archive-order/bar2.c [new file with mode: 0644]
unit-tests/test-cases/archive-order/bar3.c [new file with mode: 0644]
unit-tests/test-cases/archive-order/expected.order [new file with mode: 0644]
unit-tests/test-cases/archive-order/foo.c [new file with mode: 0644]
unit-tests/test-cases/archive-order/foo2.c [new file with mode: 0644]
unit-tests/test-cases/archive-order/foo3.c [new file with mode: 0644]
unit-tests/test-cases/archive-order/main.c [new file with mode: 0644]
unit-tests/test-cases/auto-arch/Makefile
unit-tests/test-cases/auto-arch/hello.c
unit-tests/test-cases/bind_at_load/Makefile
unit-tests/test-cases/branch-distance/bar.s
unit-tests/test-cases/branch-distance/foo.s
unit-tests/test-cases/branch-interworking/Makefile
unit-tests/test-cases/branch-interworking/myarm.s
unit-tests/test-cases/branch-interworking/mythumb.s
unit-tests/test-cases/branch-islands/hello.c
unit-tests/test-cases/check-init-abs/.mod_init_func [new file with mode: 0644]
unit-tests/test-cases/check-init-abs/Makefile [new file with mode: 0644]
unit-tests/test-cases/check-init-abs/init.s [new file with mode: 0644]
unit-tests/test-cases/check-init-abs/main.c [new file with mode: 0644]
unit-tests/test-cases/check-init-abs/term.s [new file with mode: 0644]
unit-tests/test-cases/check-init-bind/.mod_init_func [new file with mode: 0644]
unit-tests/test-cases/check-init-bind/Makefile [new file with mode: 0644]
unit-tests/test-cases/check-init-bind/init.s [new file with mode: 0644]
unit-tests/test-cases/check-init-bind/main.c [new file with mode: 0644]
unit-tests/test-cases/check-init-bind/term.s [new file with mode: 0644]
unit-tests/test-cases/check-init-no-rebase/.mod_init_func [new file with mode: 0644]
unit-tests/test-cases/check-init-no-rebase/Makefile [new file with mode: 0644]
unit-tests/test-cases/check-init-no-rebase/init.s [new file with mode: 0644]
unit-tests/test-cases/check-init-no-rebase/main.c [new file with mode: 0644]
unit-tests/test-cases/check-init-no-rebase/term.s [new file with mode: 0644]
unit-tests/test-cases/coalesce_weak_def_in_dylib/Makefile
unit-tests/test-cases/commons-alignment/Makefile
unit-tests/test-cases/commons-alignment/foo.s
unit-tests/test-cases/compact-unwind-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/compact-unwind-basic/test.s [new file with mode: 0644]
unit-tests/test-cases/cpu-sub-types-preference/Makefile
unit-tests/test-cases/cpu-sub-types/Makefile
unit-tests/test-cases/cstring-labels/Makefile
unit-tests/test-cases/custom-segment-layout/Makefile
unit-tests/test-cases/custom-segment-layout/zero.s
unit-tests/test-cases/dead_strip-archive/Makefile
unit-tests/test-cases/dead_strip-entry-archive/Makefile
unit-tests/test-cases/demangle/Makefile
unit-tests/test-cases/dependency-logging/Makefile
unit-tests/test-cases/dwarf-debug-notes/Makefile
unit-tests/test-cases/dwarf-debug-notes/expected-stabs
unit-tests/test-cases/dwarf-debug-notes/hello.order [new file with mode: 0644]
unit-tests/test-cases/dwarf-debug-notes/other.cxx
unit-tests/test-cases/dwarf-ignore/hello.c
unit-tests/test-cases/dwarf-strip-objc/Makefile
unit-tests/test-cases/dwarf-strip/hello.c
unit-tests/test-cases/dylib-re-export-cycle/Makefile
unit-tests/test-cases/efi-basic/Makefile
unit-tests/test-cases/efi-basic/MtocTest.c
unit-tests/test-cases/eh-stripped-symbols/Makefile
unit-tests/test-cases/filelist/hello.c
unit-tests/test-cases/flat-dylib/main.c
unit-tests/test-cases/flat-main/main.c
unit-tests/test-cases/function-starts/Makefile
unit-tests/test-cases/function-starts/main.c
unit-tests/test-cases/got-elimination/Makefile
unit-tests/test-cases/header-pad/hello.c
unit-tests/test-cases/hello-world/hello.c
unit-tests/test-cases/implicit_dylib/Makefile
unit-tests/test-cases/kext-basic/Makefile
unit-tests/test-cases/kext-undefined-export/Makefile [new file with mode: 0644]
unit-tests/test-cases/kext-undefined-export/mykext-i386.exp [new file with mode: 0644]
unit-tests/test-cases/kext-undefined-export/mykext.c [new file with mode: 0644]
unit-tests/test-cases/kext-undefined-export/mykext.exp [new file with mode: 0644]
unit-tests/test-cases/kext-undefined-export/mykextinfo.c [new file with mode: 0644]
unit-tests/test-cases/label-on-end-of-section-order/Makefile [new file with mode: 0755]
unit-tests/test-cases/label-on-end-of-section-order/foo.s [new file with mode: 0755]
unit-tests/test-cases/llvm-integration/Makefile
unit-tests/test-cases/lto-archive-dylib/Makefile
unit-tests/test-cases/lto-dead_strip-all-hidden/Makefile
unit-tests/test-cases/lto-dead_strip-coalesce/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-coalesce/foo.c [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-coalesce/main.c [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-objc/Makefile
unit-tests/test-cases/lto-dead_strip-some-hidden/Makefile
unit-tests/test-cases/lto-dead_strip-tentative/Makefile
unit-tests/test-cases/lto-dead_strip-unused/Makefile
unit-tests/test-cases/lto-llvm-options/Makefile
unit-tests/test-cases/lto-objc-archive/Makefile
unit-tests/test-cases/lto-objc-image-info/Makefile
unit-tests/test-cases/lto-object_path/Makefile
unit-tests/test-cases/lto-weak-native-override/Makefile
unit-tests/test-cases/lto-weak-native-override/main.c
unit-tests/test-cases/lto-weak_import/Makefile
unit-tests/test-cases/merge_zero_fill_sections/Makefile [new file with mode: 0755]
unit-tests/test-cases/merge_zero_fill_sections/main.c [new file with mode: 0755]
unit-tests/test-cases/non-lazy-sections-r/foo.s
unit-tests/test-cases/objc-category-warning/Makefile [new file with mode: 0644]
unit-tests/test-cases/objc-category-warning/cat.m [new file with mode: 0644]
unit-tests/test-cases/objc-category-warning/copycat.m [new file with mode: 0644]
unit-tests/test-cases/objc-category-warning/foo.m [new file with mode: 0644]
unit-tests/test-cases/objc-class-alias/Makefile
unit-tests/test-cases/objc-gc-checks/Makefile
unit-tests/test-cases/objc-properties/Makefile
unit-tests/test-cases/order_file/extra.s
unit-tests/test-cases/prebound-main/Makefile [deleted file]
unit-tests/test-cases/prebound-main/main.c [deleted file]
unit-tests/test-cases/prebound-split-seg/Makefile
unit-tests/test-cases/re-export-and-use/Makefile
unit-tests/test-cases/re-export-cases/Makefile
unit-tests/test-cases/re-export-layers/Makefile
unit-tests/test-cases/re-export-optimizations-indirect/Makefile
unit-tests/test-cases/re-export-optimizations/Makefile
unit-tests/test-cases/read-only-relocs/Makefile
unit-tests/test-cases/relocs-asm/relocs-asm.s
unit-tests/test-cases/shared-cache-dylib/foo.c
unit-tests/test-cases/stabs-directory-slash/Makefile
unit-tests/test-cases/stabs-directory-slash/main.c
unit-tests/test-cases/stack_addr_size/Makefile
unit-tests/test-cases/stack_size_no_addr/Makefile
unit-tests/test-cases/strip_local/hello.c
unit-tests/test-cases/switch-jump-table/Makefile
unit-tests/test-cases/switch-jump-table/switch.s
unit-tests/test-cases/tentative-and-archive-code/Makefile [new file with mode: 0644]
unit-tests/test-cases/tentative-and-archive-code/foo_code.c [new file with mode: 0644]
unit-tests/test-cases/tentative-and-archive-code/foo_data.c [new file with mode: 0644]
unit-tests/test-cases/tentative-and-archive-code/foo_tent.c [new file with mode: 0644]
unit-tests/test-cases/tentative-and-archive-code/junk.c [new file with mode: 0644]
unit-tests/test-cases/tentative-and-archive-code/main.c [new file with mode: 0644]
unit-tests/test-cases/tlv-dead_strip/Makefile [new file with mode: 0644]
unit-tests/test-cases/tlv-dead_strip/main.c [new file with mode: 0644]
unit-tests/test-cases/umbrella-dylib/Makefile
unit-tests/test-cases/weak-def-auto-hide/other.s
unit-tests/test-cases/weak-def-hidden-and-global/Makefile [new file with mode: 0644]
unit-tests/test-cases/weak-def-hidden-and-global/myglobal.c [new file with mode: 0644]
unit-tests/test-cases/weak-def-hidden-and-global/myhidden.s [new file with mode: 0644]
unit-tests/test-cases/weak_dylib/Makefile
unit-tests/test-cases/weak_dylib/data.c [new file with mode: 0644]
unit-tests/test-cases/weak_import-addend/Makefile [new file with mode: 0644]
unit-tests/test-cases/weak_import-addend/test.s [new file with mode: 0644]
unit-tests/test-cases/weak_import-local/Makefile
unit-tests/test-cases/weak_import3/Makefile
unit-tests/test-cases/zero-fill3/Makefile

index e2d1d2c5911e04948da3d56cfd77d5c3d025d8cb..fd449c8e84271e20e17be723d9b405ce7d961496 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,398 @@
 
+-------- tagged ld64-127.2
+
+2011-08-15    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9945513> suppress version load command for simulator builds
+
+-------- tagged ld64-127.1
+
+2011-07-26    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9847280> Csu needs to support for armv7 variants
+
+-------- tagged ld64-127
+
+2011-07-26    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9838090> crash with TLS + -dead_strip
+
+2011-07-20    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9778727> ld64-123.2.1/ChangeLog contains internal train names and radar titles
+
+2011-07-17    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9777977> ld crashes with an assertion failure when linking WebKit with LTO
+       
+2011-07-14    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9779759> Personalities missing when using compact unwind
+
+2011-07-13    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9740166> force loaded archives not listed in LD_TRACE
+
+2011-07-05    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9716724> spurious warning: Codegen prevents image from working in dyld shared cache
+
+2011-07-01    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9707126> Fix -classic_linker option
+
+-------- tagged ld64-126.5
+
+2011-06-15    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9618702> ld64-124.6: ld -r introduces duplicate symbols
+       
+2011-06-15    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9610466> loosen check for 32-bit absolute address out of range 
+               
+-------- tagged ld64-126.3.1
+
+2011-06-15    Nick Kledzik    <kledzik@apple.com>
+
+       Update armv7 variants
+
+-------- tagged ld64-126.2
+
+2011-06-13    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9461567> iOS ld -r loses dont-dead-strip attribute on __objc_nlclslist section
+
+2011-06-13    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9231829> LC_ENCRYPTION_INFO size can be wrong
+       
+
+-------- tagged ld64-126.1
+
+2011-06-10    Nick Kledzik    <kledzik@apple.com>
+
+       Add back support for armv7 variants
+
+-------- tagged ld64-126
+
+2011-06-09    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9581690> -ObjC does not work for simulator
+       
+2011-06-09    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9551362> clang ld: bad codegen, pointer diff
+       Added test case: unit-tests/test-cases/weak-def-hidden-and-global
+
+2011-06-03    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9553065> warning then assertion when libSystem.dylib is missing
+
+2011-06-02    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9544194> ld crash with resolver functions
+
+2011-06-01    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/7259423> define way for compilers to specify compact unwind info
+       Added test case: unit-tests/test-cases/compact-unwind-basic
+       Updated unwinddump tool to display compact unwind info in .o files
+       
+2011-06-01    Nick Kledzik    <kledzik@apple.com>
+
+       Allow 8612550 (turn ordered zero fill symbols into zero data) to work not just for dyld
+
+2011-06-01    Nick Kledzik    <kledzik@apple.com>
+
+       Remove trailing /. in dwarf source dirs to cannoicalize paths
+
+2011-06-01    Nick Kledzik    <kledzik@apple.com>
+
+       Sort debug notes by output order instead of input order.
+
+2011-06-01    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9537755> remove support for invoking ld_classic in iOS
+
+2011-06-01    Nick Kledzik    <kledzik@apple.com>
+
+       Fix arm branch interworking in -r for armv6
+
+2011-06-01    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9521882> i386 regression with pointer-diff of same pointer
+
+2011-05-27    Nick Kledzik    <kledzik@apple.com>
+
+       Canonicalize dwarf source file dirname to always end in / 
+
+2011-05-27    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9513487> support arm branch interworking in -r mode (use extern relocs)
+
+2011-05-27    Nick Kledzik    <kledzik@apple.com>
+
+       Add -page_align_data_atoms option
+
+2011-05-24    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9292295> align(16384) doesn't produce 16K aligned globals on ARMv7
+
+2011-05-24    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9493908> support arm shims in sections other than __text
+
+2011-05-23    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/8750693> ld64 should only install to the platform in iOS
+
+2011-05-19    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9452006> Ld assertion with unusual section order
+
+2011-05-17    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9441273> Linker is not automatically weak loading dylibs when all references are weak
+
+-------- tagged ld64-125.3
+
+2011-05-12    Nick Kledzik    <kledzik@apple.com>
+
+       Fix missing split-seg-info for kindSetTargetImageOffset
+
+2011-05-12    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9420745> Linker crashes with __gcc_except_tab data belonging to no FDE
+
+2011-05-11    Nick Kledzik    <kledzik@apple.com>
+
+       Fix nop padding for arm code
+
+2011-05-05    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9394006> x86_64: cmp of GOT slot loses weak_import bit
+
+-------- tagged ld64-125.2
+
+2011-05-02    Nick Kledzik    <kledzik@apple.com>
+
+       Fix -flat_namespace issue with not all indirect dylibs being processed
+
+2011-04-29    Nick Kledzik    <kledzik@apple.com>
+
+       Fix sign extention on i386 addends of extern vanilla relocs 
+
+2011-04-29    Nick Kledzik    <kledzik@apple.com>
+
+       Don't let -ObjC double load any archive members
+
+2011-04-29    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9356572> better warning about unaligned ARM functions
+
+-------- tagged ld64-125.1
+
+2011-04-28    Nick Kledzik    <kledzik@apple.com>
+
+       Fix sign extention on arm sect-diff relocs so as to not trip rangeCheckAbsolute32() 
+
+-------- tagged ld64-125
+
+2011-04-24    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/8866673> the entry point should start out initially undefined
+
+2011-04-24    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/5804214> ld should never have a symbol in the non-lazy indirect symbol table with index 0
+
+2011-04-24    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/6978069> ld adds undefined symbol from .exp file to kext bundle 
+
+2011-04-24    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/7664544> Linker typo suggestions should ignore l- and L- symbols
+
+2011-04-24    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/7952137> -order_file_statistics warns about syms in multiple .o files even when names in order file are prefixed
+
+2011-04-23    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/8642343> warning when a method is overridden in a category in the same link unit
+       Add test case: unit-tests/test-cases/objc-category-warning
+
+2011-04-23    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/7890410> don't let function from archive override a tentative definition
+       Add test case: unit-tests/test-cases/tentative-and-archive-code
+
+2011-04-23    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/8822887> x86_64 -- lossy relocation at static link time (push/mov $imm)
+
+2011-04-23    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/8989530> Add comment to error message when __ZTV symbols are undefined
+
+2011-04-23    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/8995535> obsolete -no_compact_linkedit
+
+2011-04-23    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9281002> sect->sectname() passed to "%s" formats
+
+2011-04-14    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9275707> linking a sub library of libSystem should not warn about common symbols
+
+2011-04-14    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9282815> support movw/movt in static executables
+
+2011-04-12    Nick Kledzik    <kledzik@apple.com>
+
+       Rework ARM subtype handling to be table driven
+
+2011-04-11    Nick Kledzik    <kledzik@apple.com>
+
+       Error if -init or -e function not in image being linked
+
+2011-04-01    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9216420> -static and -stack_addr don't work together
+
+2011-03-31    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9183821> ld assert in LTO mode if libLTO suppresses a weak symbol it should have perserved
+
+-------- tagged ld64-124.1
+
+2011-03-30    Nick Kledzik    <kledzik@apple.com>
+
+       log warning if ld_classic is invoked
+
+2011-03-30    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9209135> Support "-arch arm -force_cpusubtype_ALL" to keep gcc building
+
+-------- tagged ld64-124
+
+2011-03-24    Nick Kledzik    <kledzik@apple.com>
+       
+       <rdar://problem/9144456> make libgcc_s and libSystem work for any link order
+       
+2011-03-18    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/8750693> ld64 should only install to the platform in iOS trains
+
+2011-03-18    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9127471> ld64 should build stand-alone and not need libunwind headers
+
+2011-03-18    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9139782> add LC_VERSION_MIN_IPHONEOS to iOS targets, warn on mismatches
+
+2011-03-18    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/8836481> Make iOS simulator a real platform with command line versioning
+
+2011-03-15    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/8964869> static executables don't get function start information
+
+2011-03-15    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9112113> allow_sub_type_mismatches linker flag broken
+
+2011-03-15    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9106345> Add option to support merging zero fill sections
+       Add test case: unit-tests/test-cases/merge_zero_fill_sections
+
+2011-03-15    Nick Kledzik    <kledzik@apple.com>
+
+       Improve error message about text-relocs caused by direct access to global weak symbols.
+
+2011-03-10    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9116044> ld assert linking armv7 kext bundle on b/bl to external function
+
+-------- tagged ld64-123.10
+
+2011-03-03    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9085618> linking x86_64 causes assert from changes in ld64-123.9
+
+-------- tagged ld64-123.9
+
+2011-03-03    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9055754> movw/movt don't work in dyld shared cache
+
+2011-03-03    Nick Kledzik    <kledzik@apple.com>
+    
+    <rdar://problem/8995525> classic linkedit does not match compact for non-lazy pointers
+
+2011-02-24    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/9052679> Support armv7 variants
+
+-------- tagged ld64-123.8
+
+2011-02-10    Nick Kledzik    <kledzik@apple.com>
+
+    <rdar://problem/8926992> Switch arm32 kexts to MH_KEXT_BUNDLE
+
+-------- tagged ld64-123.7
+
+2011-02-10    Nick Kledzik    <kledzik@apple.com>
+
+    <rdar://problem/8926992> Switch arm32 kexts to MH_KEXT_BUNDLE, if LD_KEXT_BUNDLE is set
+
+2011-01-28    Nick Kledzik    <kledzik@apple.com>
+
+    <rdar://problem/8931747> spurious 'found branch-22 without store' warning
+
+-------- tagged ld64-123.6
+
+2011-01-26    Nick Kledzik    <kledzik@apple.com>
+
+    <rdar://problem/8904405> crash with arm hi16/lo16 to external symbols
+
+-------- tagged ld64-123.5
+
+2011-01-24    Nick Kledzik    <kledzik@apple.com>
+    
+    <rdar://problem/8910802> dyld synthesized tail call stubs don't always work
+
+-------- tagged ld64-123.4
+
+2011-01-19    Nick Kledzik    <kledzik@apple.com>
+
+    <rdar://problem/8866345> __text with >10 alignment should disable close-stub optimization 
+
+2011-01-18    Nick Kledzik    <kledzik@apple.com>
+
+    <rdar://problem/8877072> :upper16: / :lower16: not working when targeting thumb functions
+
+-------- tagged ld64-123.3
+
+2010-12-14    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/8764917> ld64 making shims when not necessary
+
+2010-12-14    Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/8760268> Add work around for latest llvm-c/lto.h 
+
 -------- tagged ld64-123.2.1
 
-2010-03-07    Nick Kledzik    <kledzik@apple.com>
+2011-03-07    Nick Kledzik    <kledzik@apple.com>
 
     <rdar://problem/8955206> enable i386 ASLR
 
 
 2010-11-01    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/8612861>
+       <rdar://problem/8612861> iOS is missing dof sections for armv7 slice
 
 -------- tagged ld64-120.3
 
 
 2010-08-20    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/8309595> SWB: ld64-117.1 on Durango8F54: Assertion failed:
+       <rdar://problem/8309595> SWB: ld64-117.1 on 8F54: Assertion failed:
        UTF16 CFStrings were not coalesced correctly when gcc built the .o files and the
        last string in the __ustring section only had a single zero byte at the end.
        
 
 2010-08-14    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/8309530> SWB: ld64-117.1 on Durango8F54: Assertion failed: (categoryAtom->size() == Category<A>::size())
+       <rdar://problem/8309530> SWB: ld64-117.1 on 8F54: Assertion failed: (categoryAtom->size() == Category<A>::size())
        gcc-4.0 uses 'L' labels on categories.  This merges them onto previous data and disable category optimzation
 
 2010-08-14    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/8309917> SWB: ld64-117.1 on Durango8F54: bad category optimization
+       <rdar://problem/8309917> SWB: ld64-117.1 on 8F54: bad category optimization
        Disable category optimization for i386 and arm until further testing
 
 2010-08-14    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/8309608> SWB: ld64-117.1 on Durango8F54: address not in any section
+       <rdar://problem/8309608> SWB: ld64-117.1 on 8F54: address not in any section
        Handle pointer diff to stub for weak hidden function
 
 2010-08-13    Nick Kledzik    <kledzik@apple.com>
 
 2010-06-09    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/8076986>
+       <rdar://problem/8076986> 'rebase' makes timestamps invalid/unreadable for GDB
 
 2010-06-09    Nick Kledzik    <kledzik@apple.com>
 
index c1aa2bc01b5a11c3d784920471816fbadd708a91..03f257ad95a8750fe0f2f17845d2b50c3d3efbba 100644 (file)
@@ -295,6 +295,8 @@ need to be listed.
 By default the linker moves all zero fill sections to the end of the __DATA segment and configures
 them to use no space on disk.  This option suppresses that optimization, so zero-filled data occupies
 space on disk in a final linked image.
+.It Fl merge_zero_fill_sections
+Causes all zero-fill sections in the __DATA segment to be merged into one __zerofill section.
 .El
 .Ss Options when creating a dynamic library (dylib) 
 .Bl -tag
@@ -509,10 +511,6 @@ of wildcards.
 .Bl -tag
 .It Fl v
 Prints the version of the linker.
-.It Fl no_compact_linkedit
-Normally when targeting Mac OS X 10.6, the linker will generate compact information 
-in the __LINKEDIT segment.
-This option causes the linker to instead produce traditional relocation information.
 .It Fl allow_heap_execute
 Normally i386 main executables will be marked so that the Mac OS X 10.7 and later kernel 
 will only allow pages with the x-bit to execute instructions. This option overrides that
@@ -687,6 +685,10 @@ option is used, the temporary file will be stored at the specified path and rema
 is complete.  Without the option, the linker picks a path and deletes the object file before the linker 
 tool completes, thus tools such as the debugger or dsymutil will not be able to access the DWARF debug
 info in the temporary object file.
+.It Fl page_align_data_atoms
+During development, this option can be used to space out all global variables so each is on a separate page. 
+This is useful when analyzing dirty and resident pages.  The information can then be used to create an 
+order file  to cluster commonly used/dirty globals onto the same page(s).
 .El
 .Ss Obsolete Options
 .Bl -tag
index cfb54eb2827276bf86b089560ec5647603d73f28..ad733949154f803ca94e3efa02d19f696545bc2c 100644 (file)
@@ -28,6 +28,7 @@
                        isa = PBXAggregateTarget;
                        buildConfigurationList = F9B1A26C0A3A568700DA8FAB /* Build configuration list for PBXAggregateTarget "all" */;
                        buildPhases = (
+                               F9871A3413340B4600DB3F24 /* Platform install */,
                        );
                        dependencies = (
                                F9B1A2690A3A568200DA8FAB /* PBXTargetDependency */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/csh;
-                       shellScript = "# Let tests set MACOSX_DEPLOYMENT_TARGET as they need\nunsetenv MACOSX_DEPLOYMENT_TARGET\n\n# always use new linker\nsetenv LD_NO_CLASSIC_LINKER\nsetenv LD_NO_CLASSIC_LINKER_STATIC\n\n# run full test suite\n\"$SRCROOT\"/unit-tests/run-all-unit-tests\n\nexit 0";
+                       shellScript = "# Let tests set MACOSX_DEPLOYMENT_TARGET as they need\nunsetenv MACOSX_DEPLOYMENT_TARGET\n\n# make linker relative libLTO.dylib\nmkdir -p ${BUILD_DIR}/lib\nln -sf /Developer/usr/lib/libLTO.dylib ${BUILD_DIR}/lib/libLTO.dylib\n\n# always use new linker\nsetenv LD_NO_CLASSIC_LINKER\nsetenv LD_NO_CLASSIC_LINKER_STATIC\n\n# run full test suite\n\"$SRCROOT\"/unit-tests/run-all-unit-tests\n\nexit 0";
+                       showEnvVarsInLog = 0;
+               };
+               F9871A3413340B4600DB3F24 /* Platform install */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       name = "Platform install";
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "\nif [ -n \"${RC_PURPLE}\" ]; then\n\techo \"here\"\n\tmkdir -p  ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer/\n\tmv ${DSTROOT}/usr ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer\nfi\n";
                        showEnvVarsInLog = 0;
                };
                F9E8DB4D11921594007B4D6A /* make config.h */ = {
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
                                GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
                                GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_MODEL_TUNING = G5;
+                               GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
                                HEADER_SEARCH_PATHS = "";
                                INSTALL_PATH = /usr/bin;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = s;
                                GCC_PREPROCESSOR_DEFINITIONS = NDEBUG;
+                               GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
                                HEADER_SEARCH_PATHS = (
                                        "$(SRCROOT)/src/ld",
                                        "$(DEVELOPER_DIR)/usr/local/include",
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
                                INSTALL_PATH = "$(HOME)/bin";
                                PREBINDING = NO;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_MODEL_TUNING = G5;
+                               GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
                                HEADER_SEARCH_PATHS = "";
                                INSTALL_PATH = /usr/bin;
index a9a69a7a54a7205f8af748df52af1efc914fb14d..f5f073b6691a41ac3a48c2e6d072a36264b9f68c 100644 (file)
@@ -35,6 +35,7 @@
 #include <mach-o/arm/reloc.h>
 #include <mach-o/compact_unwind_encoding.h>
 #include <mach/machine.h>
+#include <stddef.h>
 
 #include "FileAbstraction.hpp"
 
@@ -53,6 +54,7 @@
 #ifndef CPU_SUBTYPE_ARM_V7
        #define CPU_SUBTYPE_ARM_V7                      ((cpu_subtype_t) 9)
 #endif
+
 #ifndef ARM_THUMB_32BIT_BRANCH
        #define ARM_THUMB_32BIT_BRANCH  7 
 #endif
 #define ARM_RELOC_HALF 8
 #define ARM_RELOC_HALF_SECTDIFF 9
 
+#ifndef CPU_SUBTYPE_ARM_V7F
+  #define CPU_SUBTYPE_ARM_V7F    ((cpu_subtype_t) 10)
+#endif
+#ifndef CPU_SUBTYPE_ARM_V7K
+  #define CPU_SUBTYPE_ARM_V7K    ((cpu_subtype_t) 12)
+#endif
+
+struct ARMSubType {
+       const char*                     subTypeName;
+       const char*                     llvmTriplePrefix;
+       cpu_subtype_t           subType;
+       bool                            supportsThumb2;
+};
+
+static const ARMSubType ARMSubTypes[] = {
+       { "armv4t","armv4t-",   CPU_SUBTYPE_ARM_V4T,   false },
+       { "armv5", "armv5e-",   CPU_SUBTYPE_ARM_V5TEJ, false },
+       { "armv6", "armv6-",    CPU_SUBTYPE_ARM_V6,    false },
+       { "armv7", "thumbv7-",  CPU_SUBTYPE_ARM_V7,    true },
+       { "armv7f", "thumbv7f-", CPU_SUBTYPE_ARM_V7F,   true },
+       { "armv7k", "thumbv7k-", CPU_SUBTYPE_ARM_V7K,   true },
+       { 0, NULL, false }
+};
+
+
+
 
 //
 // This abstraction layer makes every mach-o file look like a 64-bit mach-o file with native endianness
@@ -1260,6 +1288,42 @@ private:
 };
 
 
+//
+// mach-o __LD, __compact_unwind section in object files
+//
+template <typename P>
+class macho_compact_unwind_entry {
+public:
+       typedef typename P::E           E;
+       typedef typename P::uint_t      pint_t;
+
+       pint_t                  codeStart() const                                               INLINE { return P::getP(_codeStart); }
+       void                    set_codeStart(pint_t value)                             INLINE { P::setP(_codeStart, value); }
+
+       uint32_t                codeLen() const                                                 INLINE { return E::get32(_codeLen); }
+       void                    set_codeLen(uint32_t value)                             INLINE { E::set32(_codeLen, value); }
+
+       uint32_t                compactUnwindInfo() const                               INLINE { return E::get32(_compactUnwindInfo); }
+       void                    set_compactUnwindInfo(uint32_t value)   INLINE { E::set32(_compactUnwindInfo, value);  }
+       
+       pint_t                  personality() const                                             INLINE { return P::getP(_personality); }
+       void                    set_personality(pint_t value)                   INLINE { P::setP(_personality, value);  }
+       
+       pint_t                  lsda() const                                                    INLINE { return P::getP(_lsda); }
+       void                    set_lsda(pint_t value)                                  INLINE { P::setP(_lsda, value);  }
+       
+       static uint32_t codeStartFieldOffset()                                  INLINE { return offsetof(macho_compact_unwind_entry<P>,_codeStart); }
+       static uint32_t personalityFieldOffset()                                INLINE { return offsetof(macho_compact_unwind_entry<P>,_personality); }
+       static uint32_t lsdaFieldOffset()                                               INLINE { return offsetof(macho_compact_unwind_entry<P>,_lsda); }
+       
+private:
+       pint_t          _codeStart;
+       uint32_t        _codeLen;
+       uint32_t        _compactUnwindInfo;
+       pint_t          _personality;
+       pint_t          _lsda;
+};
+
 
 #endif // __MACH_O_FILE_ABSTRACTION__
 
index 2c97dba208e4fa8cfaa2ddb75e3247e4fbbf7dbd..395fc99e95054958857413a2f8e0e5821e3f0fd2 100644 (file)
@@ -647,6 +647,8 @@ uint32_t HeaderAndLoadCommandsAtom<A>::sectionFlags(ld::Internal::FinalSection*
                                return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
                        else if ( (strncmp(sect->sectionName(), "__objc_superrefs", 16) == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
                                return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+                       else if ( (strncmp(sect->sectionName(), "__objc_nlclslist", 16) == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+                               return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
                        else
                                return S_REGULAR;
                case ld::Section::typeCode:
@@ -750,6 +752,8 @@ uint32_t HeaderAndLoadCommandsAtom<A>::sectionFlags(ld::Internal::FinalSection*
                case ld::Section::typeLastSection:
                        assert(0 && "typeLastSection should not make it to final linked image");
                        return S_REGULAR;
+               case ld::Section::typeDebug:
+                       return S_REGULAR | S_ATTR_DEBUG;
        }
        return S_REGULAR;
 }
@@ -1013,9 +1017,9 @@ template <typename A>
 uint8_t* HeaderAndLoadCommandsAtom<A>::copyVersionLoadCommand(uint8_t* p) const
 {
        macho_version_min_command<P>* cmd = (macho_version_min_command<P>*)p;
-       ld::MacVersionMin    macVersion      = _options.macosxVersionMin();
-       ld::IPhoneVersionMin iphoneOSVersion = _options.iphoneOSVersionMin();
-       assert( (macVersion != ld::macVersionUnset) || (iphoneOSVersion != ld::iPhoneVersionUnset) );
+       ld::MacVersionMin macVersion = _options.macosxVersionMin();
+       ld::IOSVersionMin iOSVersion = _options.iOSVersionMin();
+       assert( (macVersion != ld::macVersionUnset) || (iOSVersion != ld::iOSVersionUnset) );
        if ( macVersion != ld::macVersionUnset ) {
                cmd->set_cmd(LC_VERSION_MIN_MACOSX);
                cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
@@ -1025,7 +1029,7 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copyVersionLoadCommand(uint8_t* p) const
        else {
                cmd->set_cmd(LC_VERSION_MIN_IPHONEOS);
                cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
-               cmd->set_version((uint32_t)iphoneOSVersion);
+               cmd->set_version((uint32_t)iOSVersion);
                cmd->set_reserved(0);
        }
        return p + sizeof(macho_version_min_command<P>);
@@ -1177,13 +1181,9 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copyDylibLoadCommand(uint8_t* p, const ld
 {
        uint32_t sz = alignedSize(sizeof(macho_dylib_command<P>) + strlen(dylib->installPath()) + 1);
        macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)p;
-       // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
-       bool autoWeakLoadDylib = false; // FIX
-                                                       //( (fWriter.fDylibReadersWithWeakImports.count(fInfo.reader) > 0) 
-                                                       //&& (fWriter.fDylibReadersWithNonWeakImports.count(fInfo.reader) == 0) );
        if ( dylib->willBeLazyLoadedDylib() )
                cmd->set_cmd(LC_LAZY_LOAD_DYLIB);
-       else if ( dylib->willBeWeakLinked() || autoWeakLoadDylib )
+       else if ( dylib->forcedWeakLinked() || dylib->allSymbolsAreWeakImported() )
                cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
        else if ( dylib->willBeReExported() && _options.useSimplifiedDylibReExports() )
                cmd->set_cmd(LC_REEXPORT_DYLIB);
index bc292bbfca7f0668f2511bac6729996a03b1ff11..84a2297bb72949c50ea45614d6df55711e14516b 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
  *
- * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -186,7 +186,7 @@ const char* InputFiles::fileArch(const uint8_t* p, unsigned len)
 }
 
 
-ld::File* InputFiles::makeFile(const Options::FileInfo& info)
+ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib)
 {
        // map in whole file
        uint64_t len = info.fileLen;
@@ -256,7 +256,7 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info)
        // see if it is an object file
        mach_o::relocatable::ParserOptions objOpts;
        objOpts.architecture            = _options.architecture();
-       objOpts.objSubtypeMustMatch = _options.preferSubArchitecture();
+       objOpts.objSubtypeMustMatch = !_options.allowSubArchitectureMismatches();
        objOpts.logAllFiles                     = _options.logAllFiles();
        objOpts.convertUnwindInfo       = _options.needsUnwindInfoSection();
        objOpts.subType                         = _options.subArchitecture();
@@ -270,22 +270,27 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info)
                return this->addObject(objResult, info, len);
 
        // see if it is a dynamic library
-       ld::dylib::File* dylibResult = mach_o::dylib::parse(p, len, info.path, info.modTime, _options, _nextInputOrdinal, info.options.fBundleLoader);
+       ld::dylib::File* dylibResult = mach_o::dylib::parse(p, len, info.path, info.modTime, _options, _nextInputOrdinal, info.options.fBundleLoader, indirectDylib);
        if ( dylibResult != NULL ) 
                return this->addDylib(dylibResult, info, len);
 
        // see if it is a static library
-       archive::ParserOptions archOpts;
+       ::archive::ParserOptions archOpts;
        archOpts.objOpts                                = objOpts;
        archOpts.forceLoadThisArchive   = info.options.fForceLoad;
        archOpts.forceLoadAll                   = _options.fullyLoadArchives();
        archOpts.forceLoadObjC                  = _options.loadAllObjcObjectsFromArchives();
+       archOpts.objcABI2                               = _options.objCABIVersion2POverride();
        archOpts.verboseLoad                    = _options.whyLoad();
        archOpts.logAllFiles                    = _options.logAllFiles();
-       ld::File* archiveResult = archive::parse(p, len, info.path, info.modTime, _nextInputOrdinal, archOpts);
-       if ( archiveResult != NULL ) 
+       ld::archive::File* archiveResult = ::archive::parse(p, len, info.path, info.modTime, _nextInputOrdinal, archOpts);
+       if ( archiveResult != NULL ) {
+               // <rdar://problem/9740166> force loaded archives should be in LD_TRACE
+               if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && _options.traceArchives() ) 
+                       logArchive(archiveResult);
                return this->addArchive(archiveResult, info, len);
-
+       }
+       
        // does not seem to be any valid linker input file, check LTO misconfiguration problems
        if ( lto::archName((uint8_t*)p, len) != NULL ) {
                if ( lto::libLTOisLoaded() ) {
@@ -404,7 +409,7 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from
                        if ( strcmp(dit->installName,installPath) == 0 ) {
                                try {
                                        Options::FileInfo info = _options.findFile(dit->useInstead);
-                                       ld::File* reader = this->makeFile(info);
+                                       ld::File* reader = this->makeFile(info, true);
                                        ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
                                        if ( dylibReader != NULL ) {
                                                //_installPathToDylibs[strdup(installPath)] = dylibReader;
@@ -434,7 +439,7 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from
                // search for dylib using -F and -L paths
                Options::FileInfo info = _options.findFileUsingPaths(installPath);
                try {
-                       ld::File* reader = this->makeFile(info);
+                       ld::File* reader = this->makeFile(info, true);
                        ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
                        if ( dylibReader != NULL ) {
                                //assert(_installPathToDylibs.find(installPath) !=  _installPathToDylibs.end());
@@ -465,7 +470,7 @@ void InputFiles::createIndirectDylibs()
        
        // keep processing dylibs until no more dylibs are added
        unsigned long lastMapSize = 0;
-       std::set<ld::dylib::File*>      dylibsProcessed;
+       std::set<ld::dylib::File*>  dylibsProcessed;
        while ( lastMapSize != _allDylibs.size() ) {
                lastMapSize = _allDylibs.size();
                // can't iterator _installPathToDylibs while modifying it, so use temp buffer
@@ -659,7 +664,7 @@ InputFiles::InputFiles(Options& opts, const char** archName)
        for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) {
                const Options::FileInfo& entry = *it;
                try {
-                       _inputFiles.push_back(this->makeFile(entry));
+                       _inputFiles.push_back(this->makeFile(entry, false));
                }
                catch (const char* msg) {
                        if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) {
@@ -717,7 +722,7 @@ ld::File* InputFiles::addDylib(ld::dylib::File* reader, const Options::FileInfo&
        }
        // store options about how dylib will be used in dylib itself
        if ( info.options.fWeakImport )
-               reader->setWillBeWeakLinked();
+               reader->setForcedWeakLinked();
        if ( info.options.fReExport )
                reader->setWillBeReExported();
        if ( info.options.fUpward ) {
@@ -778,6 +783,7 @@ bool InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) const
        }
        if ( didSomething || true ) {
                switch ( _options.outputKind() ) {
+                       case Options::kStaticExecutable:
                        case Options::kDynamicExecutable:
                                // add implicit __dso_handle label
                                handler.doAtom(DSOHandleAtom::_s_atomExecutable);
@@ -802,11 +808,6 @@ bool InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) const
                                handler.doAtom(DSOHandleAtom::_s_atomDyld);
                                handler.doAtom(DSOHandleAtom::_s_atomAll);
                                break;
-                       case Options::kStaticExecutable:
-                               // add implicit __dso_handle label
-                               handler.doAtom(DSOHandleAtom::_s_atomExecutable);
-                               handler.doAtom(DSOHandleAtom::_s_atomAll);
-                               break;
                        case Options::kPreload:
                                // add implicit __mh_preload_header label
                                handler.doAtom(DSOHandleAtom::_s_atomPreload);
@@ -824,7 +825,7 @@ bool InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) const
 }
 
 
-bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searchArchives, ld::File::AtomHandler& handler) const
+bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searchArchives, bool dataSymbolOnly, ld::File::AtomHandler& handler) const
 {
        // check each input file 
        for (std::vector<ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); ++it) {
@@ -832,6 +833,7 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc
                // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
                // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
                ld::dylib::File* dylibFile = dynamic_cast<ld::dylib::File*>(file);
+               ld::archive::File* archiveFile = dynamic_cast<ld::archive::File*>(file);
                if ( searchDylibs && (dylibFile != NULL) ) {
                        //fprintf(stderr, "searchLibraries(%s), looking in linked %s\n", name, dylibFile->path() );
                        if ( dylibFile->justInTimeforEachAtom(name, handler) ) {
@@ -842,12 +844,22 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc
                                // else continue search for a non-weak definition
                        }
                }
-               else if ( searchArchives && (dylibFile == NULL) ) {
-                       if ( file->justInTimeforEachAtom(name, handler) ) {
-                               if ( _options.traceArchives() ) 
-                                       logArchive(file);
-                               // found definition in static library, done
-                               return true;
+               else if ( searchArchives && (archiveFile != NULL) ) {
+                       if ( dataSymbolOnly ) {
+                               if ( archiveFile->justInTimeDataOnlyforEachAtom(name, handler) ) {
+                                       if ( _options.traceArchives() ) 
+                                               logArchive(file);
+                                       // found data definition in static library, done
+                                       return true;
+                               }
+                       }
+                       else {
+                               if ( archiveFile->justInTimeforEachAtom(name, handler) ) {
+                                       if ( _options.traceArchives() ) 
+                                               logArchive(file);
+                                       // found definition in static library, done
+                                       return true;
+                               }
                        }
                }
        }
@@ -898,7 +910,7 @@ bool InputFiles::searchWeakDefInDylib(const char* name) const
 
 void InputFiles::dylibs(ld::Internal& state)
 {
-       bool dylibsOK;
+       bool dylibsOK = false;
        switch ( _options.outputKind() ) {
                case Options::kDynamicExecutable:
                case Options::kDynamicLibrary:
index 1565515bf84e8148ca8c4f9ba95195145e275bb8..1842c8ec74a93cd38c4faf88c761f16453d742de 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
  *
- * Copyright (c) 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -60,7 +60,8 @@ public:
        // iterates all atoms in initial files
        bool                                            forEachInitialAtom(ld::File::AtomHandler&) const;
        // searches libraries for name
-       bool                                            searchLibraries(const char* name, bool searchDylibs, bool searchArchives, ld::File::AtomHandler&) const;
+       bool                                            searchLibraries(const char* name, bool searchDylibs, bool searchArchives,  
+                                                                                                                                 bool dataSymbolOnly, ld::File::AtomHandler&) const;
        // see if any linked dylibs export a weak def of symbol
        bool                                            searchWeakDefInDylib(const char* name) const;
        // copy dylibs to link with in command line order
@@ -81,7 +82,7 @@ public:
 private:
        void                                            inferArchitecture(Options& opts, const char** archName);
        const char*                                     fileArch(const uint8_t* p, unsigned len);
-       ld::File*                                       makeFile(const Options::FileInfo& info);
+       ld::File*                                       makeFile(const Options::FileInfo& info, bool indirectDylib);
        ld::File*                                       addDylib(ld::dylib::File* f,        const Options::FileInfo& info, uint64_t mappedLen);
        ld::File*                                       addObject(ld::relocatable::File* f, const Options::FileInfo& info, uint64_t mappedLen);
        ld::File*                                       addArchive(ld::File* f,             const Options::FileInfo& info, uint64_t mappedLen);
index d905a3d7caa0ead85c3a95470d5dff0a4c80c051..bf9026b5bf0cc93295934f48cd195b7d5265ebf8 100644 (file)
@@ -1058,12 +1058,16 @@ private:
        typedef typename A::P::E                                        E;
        typedef typename A::P::uint_t                           pint_t;
 
-       void                                                                            addSplitSegInfo(uint64_t address, ld::Fixup::Kind k) const;
+       void                                                                            addSplitSegInfo(uint64_t address, ld::Fixup::Kind k, uint32_t) const;
        void                                                                            uleb128EncodeAddresses(const std::vector<uint64_t>& locations) const;
 
        mutable std::vector<uint64_t>                           _32bitPointerLocations;
        mutable std::vector<uint64_t>                           _64bitPointerLocations;
        mutable std::vector<uint64_t>                           _ppcHi16Locations;
+       mutable std::vector<uint64_t>                           _thumbLo16Locations;
+       mutable std::vector<uint64_t>                           _thumbHi16Locations[16];
+       mutable std::vector<uint64_t>                           _armLo16Locations;
+       mutable std::vector<uint64_t>                           _armHi16Locations[16];
 
 
        static ld::Section                      _s_section;
@@ -1073,7 +1077,7 @@ template <typename A>
 ld::Section SplitSegInfoAtom<A>::_s_section("__LINKEDIT", "__splitSegInfo", ld::Section::typeLinkEdit, true);
 
 template <>
-void SplitSegInfoAtom<x86_64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind) const
+void SplitSegInfoAtom<x86_64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
 {
        switch (kind) {
                case ld::Fixup::kindStoreX86PCRel32:
@@ -1101,7 +1105,7 @@ void SplitSegInfoAtom<x86_64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind
 }
 
 template <>
-void SplitSegInfoAtom<x86>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind) const
+void SplitSegInfoAtom<x86>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
 {
        switch (kind) {
                case ld::Fixup::kindStoreLittleEndian32:
@@ -1115,12 +1119,26 @@ void SplitSegInfoAtom<x86>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind ki
 }
 
 template <>
-void SplitSegInfoAtom<arm>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind) const
+void SplitSegInfoAtom<arm>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
 {
        switch (kind) {
                case ld::Fixup::kindStoreLittleEndian32:
                        _32bitPointerLocations.push_back(address);
                        break;
+        case ld::Fixup::kindStoreARMLow16:
+                       _armLo16Locations.push_back(address);
+                       break;
+       case ld::Fixup::kindStoreThumbLow16: 
+                       _thumbLo16Locations.push_back(address);
+                       break;
+        case ld::Fixup::kindStoreARMHigh16: 
+            assert(extra < 16);
+                       _armHi16Locations[extra].push_back(address);
+                       break;
+        case ld::Fixup::kindStoreThumbHigh16: 
+            assert(extra < 16);
+                       _thumbHi16Locations[extra].push_back(address);
+                       break;
                default:
                        warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
                        break;
@@ -1129,7 +1147,7 @@ void SplitSegInfoAtom<arm>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind ki
 
 
 template <>
-void SplitSegInfoAtom<ppc>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind) const
+void SplitSegInfoAtom<ppc>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
 {
        switch (kind) {
                case ld::Fixup::kindStorePPCPicHigh16AddLow:
@@ -1146,7 +1164,7 @@ void SplitSegInfoAtom<ppc>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind ki
 
 
 template <>
-void SplitSegInfoAtom<ppc64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind) const
+void SplitSegInfoAtom<ppc64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
 {
        switch (kind) {
                case ld::Fixup::kindStorePPCPicHigh16AddLow:
@@ -1192,7 +1210,7 @@ void SplitSegInfoAtom<A>::encode() const
        // sort into group by pointer adjustment kind
        std::vector<OutputFile::SplitSegInfoEntry>& info = this->_writer._splitSegInfos;
        for (std::vector<OutputFile::SplitSegInfoEntry>::const_iterator it = info.begin(); it != info.end(); ++it) {
-               this->addSplitSegInfo(it->address, it->kind);
+               this->addSplitSegInfo(it->address, it->kind, it->extra);
        }
 
        // delta compress runs of addresses
@@ -1221,6 +1239,42 @@ void SplitSegInfoAtom<A>::encode() const
                this->_encodedData.append_byte(0); // terminator
        }
 
+       if ( _thumbLo16Locations.size() != 0 ) {
+               this->_encodedData.append_byte(5);
+               //fprintf(stderr, "type 5:\n");
+               std::sort(_thumbLo16Locations.begin(), _thumbLo16Locations.end());
+               this->uleb128EncodeAddresses(_thumbLo16Locations);
+               this->_encodedData.append_byte(0); // terminator
+       }
+
+       if ( _armLo16Locations.size() != 0 ) {
+               this->_encodedData.append_byte(6);
+               //fprintf(stderr, "type 6:\n");
+               std::sort(_armLo16Locations.begin(), _armLo16Locations.end());
+               this->uleb128EncodeAddresses(_armLo16Locations);
+               this->_encodedData.append_byte(0); // terminator
+       }
+
+       for (uint32_t i=0; i < 16; ++i) {
+               if ( _thumbHi16Locations[i].size() != 0 ) {
+                       this->_encodedData.append_byte(16+i);
+                       //fprintf(stderr, "type 16+%d:\n", i);
+                       std::sort(_thumbHi16Locations[i].begin(), _thumbHi16Locations[i].end());
+                       this->uleb128EncodeAddresses(_thumbHi16Locations[i]);
+                       this->_encodedData.append_byte(0); // terminator
+               }
+       }
+
+       for (uint32_t i=0; i < 16; ++i) {
+               if ( _armHi16Locations[i].size() != 0 ) {
+                       this->_encodedData.append_byte(32+i);
+                       //fprintf(stderr, "type 32+%d:\n", i);
+                       std::sort(_armHi16Locations[i].begin(), _armHi16Locations[i].end());
+                       this->uleb128EncodeAddresses(_armHi16Locations[i]);
+                       this->_encodedData.append_byte(0); // terminator
+               }
+       }
+
        // always add zero byte to mark end
        this->_encodedData.append_byte(0);
 
index d5438acddd6b4208039b895880490123d74c6b15..1429d95128735a89e31a6447fda153e8e00fcefb 100644 (file)
@@ -485,7 +485,8 @@ void SymbolTableAtom<A>::addImport(const ld::Atom* atom, StringPoolAtom* pool)
                && (atom->combine() == ld::Atom::combineByName) ) {
                        desc |= N_REF_TO_WEAK;
        }
-       if ( atom->weakImported() )     
+       const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(atom->file());
+       if ( atom->weakImported() || ((dylib != NULL) && dylib->forcedWeakLinked()) )
                desc |= N_WEAK_REF;
        entry.set_n_desc(desc);
 
@@ -1384,8 +1385,12 @@ void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection*
                                else
                                        sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
                                sreloc1->set_r_address(address);
-                               if ( entry.toTarget == entry.inAtom )
-                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               if ( entry.toTarget == entry.inAtom ) {
+                                       if ( entry.toAddend > entry.toTarget->size() ) 
+                                               sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.offsetInAtom);
+                                       else
+                                               sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               }
                                else
                                        sreloc1->set_r_value(entry.toTarget->finalAddress());
                                sreloc2->set_r_scattered(true);
@@ -1513,10 +1518,15 @@ void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection*
                                else
                                        sreloc1->set_r_type(ARM_RELOC_SECTDIFF);
                                sreloc1->set_r_address(address);
-                               if ( entry.toTarget == entry.inAtom )
-                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
-                               else
+                               if ( entry.toTarget == entry.inAtom ) {
+                                       if ( entry.toAddend > entry.toTarget->size() ) 
+                                               sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.offsetInAtom);
+                                       else
+                                               sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               }
+                               else {
                                        sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               }
                                sreloc2->set_r_scattered(true);
                                sreloc2->set_r_pcrel(false);
                                sreloc2->set_r_length(2);
@@ -1632,7 +1642,7 @@ void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection*
                                                reloc1.set_r_symbolnum(symbolNum);
                                                reloc1.set_r_pcrel(false);
                                                reloc1.set_r_length(len);
-                                               reloc1.set_r_extern(false);
+                                               reloc1.set_r_extern(external);
                                                reloc1.set_r_type(ARM_RELOC_HALF);
                                                reloc2.set_r_address(otherHalf);  // other half
                                                reloc2.set_r_symbolnum(0);
@@ -2393,10 +2403,6 @@ uint32_t IndirectSymbolTableAtom<A>::symIndexOfNonLazyPointerAtom(const ld::Atom
                        default:
                                throw "internal error: unexpected non-lazy pointer binding";
                }
-               // Special case non-lazy-pointer slot used to point to "dyld_stub_binder"
-               // That slot is never bound using indirect symbol table
-               if ( target == _state.compressedFastBinderProxy )
-                       return INDIRECT_SYMBOL_ABS;
                bool targetIsGlobal = (target->scope() == ld::Atom::scopeGlobal);
                switch ( target->definition() ) {
                        case ld::Atom::definitionRegular:
index c06e1f31536fbd3679f301ea5f2361ff4ee3c723..3f5b054eca1e76c35fbaecec88e6ebdbe97d4973 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -87,7 +87,7 @@ void throwf(const char* format, ...)
 
 Options::Options(int argc, const char* argv[])
        : fOutputFile("a.out"), fArchitecture(0), fSubArchitecture(0), fArchitectureName("unknown"), fOutputKind(kDynamicExecutable), 
-         fHasPreferredSubType(false), fPrebind(false), fBindAtLoad(false), fKeepPrivateExterns(false),
+         fHasPreferredSubType(false), fArchSupportsThumb2(false), fPrebind(false), fBindAtLoad(false), fKeepPrivateExterns(false),
          fNeedsModuleTable(false), fIgnoreOtherArchFiles(false), fErrorOnOtherArchFiles(false), fForceSubtypeAll(false), 
          fInterposeMode(kInterposeNone), fDeadStrip(false), fNameSpace(kTwoLevelNameSpace),
          fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fFinalName(NULL), fEntryName("start"), 
@@ -120,19 +120,17 @@ Options::Options(int argc, const char* argv[])
          fForDyld(false), fMakeTentativeDefinitionsReal(false), fWhyLoad(false), fRootSafe(false),
          fSetuidSafe(false), fImplicitlyLinkPublicDylibs(true), fAddCompactUnwindEncoding(true),
          fWarnCompactUnwind(false), fRemoveDwarfUnwindIfCompactExists(false),
-         fAutoOrderInitializers(true), fOptimizeZeroFill(true), fLogObjectFiles(false),
+         fAutoOrderInitializers(true), fOptimizeZeroFill(true), fMergeZeroFill(false), fLogObjectFiles(false),
          fLogAllFiles(false), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false),
          fOutputSlidable(false), fWarnWeakExports(false), 
          fObjcGcCompaction(false), fObjCGc(false), fObjCGcOnly(false), 
          fDemangle(false), fTLVSupport(false), 
-#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1070
-         fVersionLoadCommand(false), fFunctionStartsLoadCommand(false),
-#else
-         fVersionLoadCommand(true), fFunctionStartsLoadCommand(true),
-#endif
-         fCanReExportSymbols(false), fObjcCategoryMerging(true), 
+         fVersionLoadCommand(false), fVersionLoadCommandForcedOn(false), 
+         fVersionLoadCommandForcedOff(false), fFunctionStartsLoadCommand(false),
+         fFunctionStartsForcedOn(false), fFunctionStartsForcedOff(false),
+         fCanReExportSymbols(false), fObjcCategoryMerging(true), fPageAlignDataAtoms(false), 
          fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL), 
-         fMacVersionMin(ld::macVersionUnset), fIPhoneVersionMin(ld::iPhoneVersionUnset), 
+         fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), 
          fSaveTempFiles(false)
 {
        this->checkForClassic(argc, argv);
@@ -175,8 +173,6 @@ bool Options::interposable(const char* name) const
 }
 
 
-
-
 bool Options::printWhyLive(const char* symbolName) const
 {
        return ( fWhyLive.find(symbolName) != fWhyLive.end() );
@@ -264,7 +260,7 @@ uint32_t Options::initialSegProtection(const char* segName) const
 uint32_t Options::maxSegProtection(const char* segName) const
 {
        // iPhoneOS always uses same protection for max and initial
-       if ( fIPhoneVersionMin != ld::iPhoneVersionUnset ) 
+       if ( fIOSVersionMin != ld::iOSVersionUnset ) 
                return initialSegProtection(segName);
 
        for(std::vector<Options::SegmentProtect>::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) {
@@ -474,7 +470,6 @@ bool Options::keepLocalSymbol(const char* symbolName) const
        throw "internal error";
 }
 
-
 void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype)
 {
        fArchitecture = type;
@@ -553,32 +548,19 @@ void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype)
                        fMakeCompressedDyldInfo = true;
                break;
        case CPU_TYPE_ARM:
-               switch ( subtype ) {
-               case CPU_SUBTYPE_ARM_V4T:
-                       fArchitectureName = "armv4t";
-                       fHasPreferredSubType = true;
-                       break;
-               case CPU_SUBTYPE_ARM_V5TEJ:
-                       fArchitectureName = "armv5";
-                       fHasPreferredSubType = true;
-                       break;
-               case CPU_SUBTYPE_ARM_V6:
-                       fArchitectureName = "armv6";
-                       fHasPreferredSubType = true;
-                       break;
-               case CPU_SUBTYPE_ARM_V7:
-                       fArchitectureName = "armv7";
-                       fHasPreferredSubType = true;
-                       break;
-               default:
-                       assert(0 && "unknown arm subtype");
-                       fArchitectureName = "arm";
-                       break;
+               fHasPreferredSubType = true;
+               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
+                       if ( t->subType == subtype ) {
+                               fArchitectureName = t->subTypeName;
+                               fArchSupportsThumb2 = t->supportsThumb2;
+                               break;
+                       }
                }
-               if ( (fMacVersionMin == ld::macVersionUnset) && (fIPhoneVersionMin == ld::iPhoneVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
+               assert(fArchitectureName != NULL);
+               if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
 #if defined(DEFAULT_IPHONEOS_MIN_VERSION)
                        warning("-ios_version_min not specificed, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
-                       setIPhoneVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
+                       setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
 #elif defined(DEFAULT_MACOSX_MIN_VERSION)
                        warning("-macosx_version_min not specificed, assuming " DEFAULT_MACOSX_MIN_VERSION);
                        setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
@@ -587,7 +569,7 @@ void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype)
                        fMacVersionMin = ld::mac10_6;
 #endif
                }
-               if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iPhone3_1) && !fMakeCompressedDyldInfoForceOff )
+               if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff )
                        fMakeCompressedDyldInfo = true;
                break;
        default:
@@ -642,33 +624,18 @@ void Options::parseArch(const char* arch)
                fSubArchitecture = CPU_SUBTYPE_POWERPC_970;
                fHasPreferredSubType = true;
        }
-       else if ( strcmp(arch, "armv6") == 0 ) {
-               fArchitecture = CPU_TYPE_ARM;
-               fSubArchitecture = CPU_SUBTYPE_ARM_V6;
-               fHasPreferredSubType = true;
-       }
-       else if ( strcmp(arch, "armv5") == 0 ) {
-               fArchitecture = CPU_TYPE_ARM;
-               fSubArchitecture = CPU_SUBTYPE_ARM_V5TEJ;
-               fHasPreferredSubType = true;
-       }
-       else if ( strcmp(arch, "armv4t") == 0 ) {
-               fArchitecture = CPU_TYPE_ARM;
-               fSubArchitecture = CPU_SUBTYPE_ARM_V4T;
-               fHasPreferredSubType = true;
-       }
-       else if ( strcmp(arch, "xscale") == 0 ) {
-               fArchitecture = CPU_TYPE_ARM;
-               fSubArchitecture = CPU_SUBTYPE_ARM_XSCALE;
-               fHasPreferredSubType = true;
-       }
-       else if ( strcmp(arch, "armv7") == 0 ) {
-               fArchitecture = CPU_TYPE_ARM;
-               fSubArchitecture = CPU_SUBTYPE_ARM_V7;
-               fHasPreferredSubType = true;
-       }
-       else
+       else {
+               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
+                       if ( strcmp(t->subTypeName,arch) == 0 ) {
+                               fArchitecture = CPU_TYPE_ARM;
+                               fSubArchitecture = t->subType;
+                               fArchSupportsThumb2 = t->supportsThumb2;
+                               fHasPreferredSubType = true;
+                               return;
+                       }
+               }
                throwf("unknown/unsupported architecture name for: -arch %s", arch);
+       }
 }
 
 bool Options::checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result) const
@@ -1346,7 +1313,7 @@ void Options::setMacOSXVersionMin(const char* version)
        }
 }
 
-void Options::setIPhoneVersionMin(const char* version)
+void Options::setIOSVersionMin(const char* version)
 {
        if ( version == NULL )
                throw "-ios_version_min argument missing";
@@ -1359,16 +1326,16 @@ void Options::setIPhoneVersionMin(const char* version)
 
        unsigned int majorVersion = version[0] - '0';
        unsigned int minorVersion = version[2] - '0';
-       fIPhoneVersionMin = (ld::IPhoneVersionMin)((majorVersion << 16) | (minorVersion << 8));
+       fIOSVersionMin = (ld::IOSVersionMin)((majorVersion << 16) | (minorVersion << 8));
 }
 
-bool Options::minOS(ld::MacVersionMin requiredMacMin, ld::IPhoneVersionMin requirediPhoneOSMin)
+bool Options::minOS(ld::MacVersionMin requiredMacMin, ld::IOSVersionMin requirediPhoneOSMin)
 {
        if ( fMacVersionMin != ld::macVersionUnset ) {
                return ( fMacVersionMin >= requiredMacMin );
        }
        else {
-               return ( fIPhoneVersionMin >= requirediPhoneOSMin);
+               return ( fIOSVersionMin >= requirediPhoneOSMin);
        }
 }
 
@@ -2020,7 +1987,8 @@ void Options::parse(int argc, const char* argv[])
                                 fIgnoreOtherArchFiles = true;
                        }
                        else if ( strcmp(arg, "-force_cpusubtype_ALL") == 0 ) {
-                                fForceSubtypeAll = true;
+                               fForceSubtypeAll = true;
+                               fAllowCpuSubtypeMismatches = true;
                        }
                        // Similar to -weak-l but uses the absolute path name to the library.
                        else if ( strcmp(arg, "-weak_library") == 0 ) {
@@ -2255,8 +2223,11 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-macosx_version_min") == 0 ) {
                                setMacOSXVersionMin(argv[++i]);
                        }
-                       else if ( (strcmp(arg, "-iphoneos_version_min") == 0) || (strcmp(arg, "-ios_version_min") == 0) ) {
-                               setIPhoneVersionMin(argv[++i]);
+                       else if ( (strcmp(arg, "-ios_version_min") == 0) || (strcmp(arg, "-iphoneos_version_min") == 0) ) {
+                               setIOSVersionMin(argv[++i]); 
+                       }
+                       else if ( strcmp(arg, "-ios_simulator_version_min") == 0 ) {
+                               setIOSVersionMin(argv[++i]);
                        }
                        else if ( strcmp(arg, "-multiply_defined") == 0 ) {
                                //warnObsolete(arg);
@@ -2589,8 +2560,7 @@ void Options::parse(int argc, const char* argv[])
                                loadSymbolOrderFile(argv[++i], fExportSymbolsOrder);
                        }
                        else if ( strcmp(arg, "-no_compact_linkedit") == 0 ) {
-                               fMakeCompressedDyldInfo = false;
-                               fMakeCompressedDyldInfoForceOff = true;
+                               warnObsolete("-no_compact_linkedit");
                        }
                        else if ( strcmp(arg, "-no_eh_labels") == 0 ) {
                                fNoEHLabels = true;
@@ -2604,6 +2574,9 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-no_zero_fill_sections") == 0 ) {
                                fOptimizeZeroFill = false;
                        }
+                       else if ( strcmp(arg, "-merge_zero_fill_sections") == 0 ) {
+                               fMergeZeroFill = true;
+                       }
                        else if ( strcmp(arg, "-objc_abi_version") == 0 ) {
                                const char* version = argv[++i];
                                 if ( version == NULL )
@@ -2643,16 +2616,20 @@ void Options::parse(int argc, const char* argv[])
                                fDemangle = true;
                        }
                        else if ( strcmp(arg, "-version_load_command") == 0 ) {
-                               fVersionLoadCommand = true;
+                               fVersionLoadCommandForcedOn = true;
+                               fVersionLoadCommandForcedOff = false;
                        }
                        else if ( strcmp(arg, "-no_version_load_command") == 0 ) {
-                               fVersionLoadCommand = false;
+                               fVersionLoadCommandForcedOff = true;
+                               fVersionLoadCommandForcedOn = false;
                        }
                        else if ( strcmp(arg, "-function_starts") == 0 ) {
-                               fFunctionStartsLoadCommand = true;
+                               fFunctionStartsForcedOn = true;
+                               fFunctionStartsForcedOff = false;
                        }
                        else if ( strcmp(arg, "-no_function_starts") == 0 ) {
-                               fFunctionStartsLoadCommand = false;
+                               fFunctionStartsForcedOff = true;
+                               fFunctionStartsForcedOn = false;
                        }
                        else if ( strcmp(arg, "-object_path_lto") == 0 ) {
                                fTempLtoObjectPath = argv[++i];
@@ -2693,6 +2670,9 @@ void Options::parse(int argc, const char* argv[])
                                        throw "-dyld_env missing ENV=VALUE";
                                fDyldEnvironExtras.push_back(envarg);
                        }
+                       else if ( strcmp(arg, "-page_align_data_atoms") == 0 ) {
+                               fPageAlignDataAtoms = true;
+                       }
                        else {
                                throwf("unknown option: %s", arg);
                        }
@@ -2954,12 +2934,6 @@ void Options::parsePreCommandLineEnvironmentSettings()
        if (getenv("LD_ALLOW_CPU_SUBTYPE_MISMATCHES") != NULL)
                fAllowCpuSubtypeMismatches = true;
        
-       // for now disable compressed linkedit functionality
-       if ( getenv("LD_NO_COMPACT_LINKEDIT") != NULL ) {
-               fMakeCompressedDyldInfo = false;
-               fMakeCompressedDyldInfoForceOff = true;
-       }
-
        sWarningsSideFilePath = getenv("LD_WARN_FILE");
        
        const char* customDyldPath = getenv("LD_DYLD_PATH");
@@ -3039,17 +3013,20 @@ void Options::reconfigureDefaults()
 
        // set default min OS version
        if ( (fMacVersionMin == ld::macVersionUnset)
-               && (fIPhoneVersionMin == ld::iPhoneVersionUnset) ) {
+               && (fIOSVersionMin == ld::iOSVersionUnset) ) {
                // if neither -macosx_version_min nor -iphoneos_version_min used, try environment variables
                const char* macVers = getenv("MACOSX_DEPLOYMENT_TARGET");
                const char* iPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET");
                const char* iOSVers = getenv("IOS_DEPLOYMENT_TARGET");
+               const char* iOSSimulatorVers = getenv("IOS_SIMULATOR_DEPLOYMENT_TARGET");
                if ( macVers != NULL ) 
                        setMacOSXVersionMin(macVers);
                else if ( iPhoneVers != NULL )
-                       setIPhoneVersionMin(iPhoneVers);
+                       setIOSVersionMin(iPhoneVers);
                else if ( iOSVers != NULL )
-                       setIPhoneVersionMin(iOSVers);
+                       setIOSVersionMin(iOSVers);
+               else if ( iOSSimulatorVers != NULL )
+                       setIOSVersionMin(iOSSimulatorVers);
                else {
                        // if still nothing, set default based on architecture
                        switch ( fArchitecture ) {
@@ -3070,7 +3047,7 @@ void Options::reconfigureDefaults()
                                        if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) {
                        #if defined(DEFAULT_IPHONEOS_MIN_VERSION)
                                                warning("-ios_version_min not specificed, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
-                                               setIPhoneVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
+                                               setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
                        #elif defined(DEFAULT_MACOSX_MIN_VERSION)
                                                warning("-macosx_version_min not specificed, assuming " DEFAULT_MACOSX_MIN_VERSION);
                                                setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
@@ -3091,7 +3068,7 @@ void Options::reconfigureDefaults()
        // adjust min based on architecture
        switch ( fArchitecture ) {
                case CPU_TYPE_I386:
-                       if ( (fMacVersionMin < ld::mac10_4) && (fIPhoneVersionMin == ld::iPhoneVersionUnset) ) {
+                       if ( (fMacVersionMin < ld::mac10_4) && (fIOSVersionMin == ld::iOSVersionUnset) ) {
                                //warning("-macosx_version_min should be 10.4 or later for i386");
                                fMacVersionMin = ld::mac10_4;
                        }
@@ -3120,9 +3097,18 @@ void Options::reconfigureDefaults()
                                fAllowTextRelocs = true;
                                fUndefinedTreatment = kUndefinedDynamicLookup;
                                break;
+                       case CPU_TYPE_ARM:
+                               if ( fIOSVersionMin >= ld::iOS_5_0 ) {
+                    // iOS 5.0 and later use new MH_KEXT_BUNDLE type
+                    fMakeCompressedDyldInfo = false;
+                    fMakeCompressedDyldInfoForceOff = true;
+                    fAllowTextRelocs = true;
+                    fUndefinedTreatment = kUndefinedDynamicLookup;
+                                       break;
+                               }
+                               // else use object file
                        case CPU_TYPE_POWERPC:
                        case CPU_TYPE_I386:
-                       case CPU_TYPE_ARM:
                                // use .o files
                                fOutputKind = kObjectFile;
                                break;
@@ -3131,7 +3117,7 @@ void Options::reconfigureDefaults()
 
        // disable implicit dylibs when targeting 10.3
        // <rdar://problem/5451987> add option to disable implicit load commands for indirectly used public dylibs
-       if ( !minOS(ld::mac10_4, ld::iPhone2_0) )
+       if ( !minOS(ld::mac10_4, ld::iOS_2_0) )
                fImplicitlyLinkPublicDylibs = false;
 
 
@@ -3242,6 +3228,10 @@ void Options::reconfigureDefaults()
                                        // in 10.5 nothing is prebound
                                        fPrebind = false;
                                }
+                               else if ( fIOSVersionMin != ld::iOSVersionUnset ) {
+                                       // nothing in simulator is prebound
+                                       fPrebind = false;
+                               }
                                else {
                                        // in 10.3 and earlier only dylibs and main executables could be prebound
                                        switch ( fOutputKind ) {
@@ -3291,7 +3281,7 @@ void Options::reconfigureDefaults()
 
        // determine if info for shared region should be added
        if ( fOutputKind == Options::kDynamicLibrary ) {
-               if ( minOS(ld::mac10_5, ld::iPhone3_1) )
+               if ( minOS(ld::mac10_5, ld::iOS_3_1) )
                        if ( !fPrebind )
                                if ( (strncmp(this->installPath(), "/usr/lib/", 9) == 0)
                                        || (strncmp(this->installPath(), "/System/Library/", 16) == 0) )
@@ -3301,8 +3291,10 @@ void Options::reconfigureDefaults()
        // figure out if module table is needed for compatibility with old ld/dyld
        if ( fOutputKind == Options::kDynamicLibrary ) {
                switch ( fArchitecture ) {
+                       case CPU_TYPE_I386:
+                               if ( fIOSVersionMin != ld::iOSVersionUnset ) // simulator never needs modules
+                                       break;
                        case CPU_TYPE_POWERPC:  // 10.3 and earlier dyld requires a module table
-                       case CPU_TYPE_I386:             // ld_classic for 10.4.x requires a module table
                                if ( fMacVersionMin <= ld::mac10_5 )
                                        fNeedsModuleTable = true;
                                break;
@@ -3400,12 +3392,14 @@ void Options::reconfigureDefaults()
        if ( fMakeCompressedDyldInfo ) {
                switch (fArchitecture) {
                        case CPU_TYPE_I386:
+                               if ( fIOSVersionMin != ld::iOSVersionUnset ) // simulator always uses compressed LINKEDIT
+                                       break;
                        case CPU_TYPE_X86_64:
                                if ( fMacVersionMin < ld::mac10_6 ) 
                                        fMakeCompressedDyldInfo = false;
                                break;
             case CPU_TYPE_ARM:
-                               if ( !minOS(ld::mac10_6, ld::iPhone3_1) )
+                               if ( !minOS(ld::mac10_6, ld::iOS_3_1) )
                                        fMakeCompressedDyldInfo = false;
                                break;
                        case CPU_TYPE_POWERPC:
@@ -3446,14 +3440,14 @@ void Options::reconfigureDefaults()
        }
        
        // Mac OS X 10.5 and iPhoneOS 2.0 support LC_REEXPORT_DYLIB
-       if ( minOS(ld::mac10_5, ld::iPhone2_0) )
+       if ( minOS(ld::mac10_5, ld::iOS_2_0) )
                fUseSimplifiedDylibReExports = true;
        
        // Mac OS X 10.7 and iOS 4.2 support LC_LOAD_UPWARD_DYLIB
-       if ( minOS(ld::mac10_7, ld::iPhone4_2) && (fOutputKind == kDynamicLibrary) )
+       if ( minOS(ld::mac10_7, ld::iOS_4_2) && (fOutputKind == kDynamicLibrary) )
                fCanUseUpwardDylib = true;
                
-       // x86_64 for MacOSX 10.7 defaults to PIE
+       // MacOSX 10.7 defaults to PIE
        if ( ((fArchitecture == CPU_TYPE_X86_64) || (fArchitecture == CPU_TYPE_I386))
                && (fOutputKind == kDynamicExecutable)
                && (fMacVersionMin >= ld::mac10_7) ) {
@@ -3462,9 +3456,9 @@ void Options::reconfigureDefaults()
 
        // armv7 for iOS4.3 defaults to PIE
        if ( (fArchitecture == CPU_TYPE_ARM) 
-               && (fSubArchitecture == CPU_SUBTYPE_ARM_V7)
+               && fArchSupportsThumb2
                && (fOutputKind == kDynamicExecutable) 
-               && (fIPhoneVersionMin >= ld::iPhone4_3) ) {
+               && (fIOSVersionMin >= ld::iOS_4_3) ) {
                        fPositionIndependentExecutable = true;
        }
 
@@ -3497,24 +3491,55 @@ void Options::reconfigureDefaults()
                fTLVSupport = true;
        }
        
-       // version load command is only in some kinds of output files
+       // default to adding version load command for dynamic code, static code must opt-in
        switch ( fOutputKind ) {
                case Options::kObjectFile:
+                       fVersionLoadCommand = false;
+                       break;
                case Options::kStaticExecutable:
                case Options::kPreload:
                case Options::kKextBundle:
-                       fVersionLoadCommand = false;
-                       fFunctionStartsLoadCommand = false;
+                       if ( fVersionLoadCommandForcedOn )
+                               fVersionLoadCommand = true;
                        break;
                case Options::kDynamicExecutable:
                case Options::kDyld:
                case Options::kDynamicLibrary:
                case Options::kDynamicBundle:
+                       if ( !fVersionLoadCommandForcedOff )
+                               fVersionLoadCommand = true;
+                       // <rdar://problem/9945513> for now, don't create version load commands for iOS simulator builds
+                       if ( fVersionLoadCommand && (fArchitecture == CPU_TYPE_I386) ) {
+                               for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) {
+                                       if ( strstr(*sdkit, "/iPhoneSimulator.platform/") != NULL )
+                                               fVersionLoadCommand = false;
+                               }
+                       }
                        break;
        }
        
+       // default to adding functions start for dynamic code, static code must opt-in
+       switch ( fOutputKind ) {
+               case Options::kObjectFile:
+                       fFunctionStartsLoadCommand = false;
+                       break;
+               case Options::kPreload:
+               case Options::kStaticExecutable:
+               case Options::kKextBundle:
+                       if ( fFunctionStartsForcedOn )
+                               fFunctionStartsLoadCommand = true;
+                       break;
+               case Options::kDynamicExecutable:
+               case Options::kDyld:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+                       if ( !fFunctionStartsForcedOff )
+                               fFunctionStartsLoadCommand = true;
+                       break;
+       }
+               
        // support re-export of individual symbols in MacOSX 10.7 and iOS 4.2
-       if ( (fOutputKind == kDynamicLibrary) && minOS(ld::mac10_7, ld::iPhone4_2) )
+       if ( (fOutputKind == kDynamicLibrary) && minOS(ld::mac10_7, ld::iOS_4_2) )
                fCanReExportSymbols = true;
        
        // ObjC optimization is only in dynamic final linked images
@@ -3794,10 +3819,25 @@ void Options::checkIllegalOptionCombinations()
                fInitialUndefines.push_back(*it);
        }
        
-       // make sure that -init symbol exist
+       // make sure that -init symbol exists
        if ( fInitFunctionName != NULL )
                fInitialUndefines.push_back(fInitFunctionName);
 
+       // make sure that entry symbol exists
+       switch ( fOutputKind ) {
+               case Options::kDynamicExecutable:
+               case Options::kStaticExecutable:
+               case Options::kDyld:
+               case Options::kPreload:
+                       fInitialUndefines.push_back(fEntryName);
+                       break;
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+               case Options::kObjectFile:
+               case Options::kKextBundle:
+                       break;
+       }
+
        // make sure every alias base exists
        for (std::vector<AliasPair>::iterator it=fAliases.begin(); it != fAliases.end(); ++it) {
                fInitialUndefines.push_back(it->realName);
@@ -3880,7 +3920,7 @@ void Options::checkIllegalOptionCombinations()
 
        // can't use -rpath unless targeting 10.5 or later
        if ( fRPaths.size() > 0 ) {
-               if ( !minOS(ld::mac10_5, ld::iPhone2_0) )
+               if ( !minOS(ld::mac10_5, ld::iOS_2_0) )
                        throw "-rpath can only be used when targeting Mac OS X 10.5 or later";
                switch ( fOutputKind ) {
                        case Options::kDynamicExecutable:
@@ -3900,8 +3940,8 @@ void Options::checkIllegalOptionCombinations()
        if ( fPositionIndependentExecutable ) {
                switch ( fOutputKind ) {
                        case Options::kDynamicExecutable:
-                               if ( !minOS(ld::mac10_5, ld::iPhone4_2) ) {
-                                       if ( fIPhoneVersionMin == ld::iPhoneVersionUnset )
+                               if ( !minOS(ld::mac10_5, ld::iOS_4_2) ) {
+                                       if ( fIOSVersionMin == ld::iOSVersionUnset )
                                                throw "-pie can only be used when targeting Mac OS X 10.5 or later";
                                        else
                                                throw "-pie can only be used when targeting iOS 4.2 or later";
@@ -3949,7 +3989,7 @@ void Options::checkIllegalOptionCombinations()
        if ( !fReExportSymbols.empty() ) {
                if ( fOutputKind != Options::kDynamicLibrary )
                        throw "-reexported_symbols_list can only used used when created dynamic libraries";
-               if ( !minOS(ld::mac10_7, ld::iPhone4_2) )
+               if ( !minOS(ld::mac10_7, ld::iOS_4_2) )
                        throw "targeted OS version does not support -reexported_symbols_list";
        }
        
@@ -4031,33 +4071,9 @@ void Options::checkForClassic(int argc, const char* argv[])
                switch ( fArchitecture ) {
                case CPU_TYPE_I386:
                case CPU_TYPE_POWERPC:
-               case CPU_TYPE_ARM:
                        if ( (staticFound || kextFound) && !newLinker ) {
                                // this environment variable will disable use of ld_classic for -static links
                                if ( getenv("LD_NO_CLASSIC_LINKER_STATIC") == NULL ) {
-                                       // ld_classic does not support -iphoneos_version_min, so change
-                                       for(int j=0; j < argc; ++j) {
-                                               if ( (strcmp(argv[j], "-iphoneos_version_min") == 0) || (strcmp(argv[j], "-ios_version_min") == 0) ) {
-                                                       argv[j] = "-macosx_version_min";
-                                                       if ( j < argc-1 )
-                                                               argv[j+1] = "10.5";
-                                                       break;
-                                               }
-                                       }
-                                       // ld classic does not understand -kext (change to -static -r)
-                                       if ( kextFound ) {
-                                               for(int j=0; j < argc; ++j) {
-                                                       if ( strcmp(argv[j], "-kext") == 0) 
-                                                               argv[j] = "-r";
-                                                       else if ( strcmp(argv[j], "-dynamic") == 0) 
-                                                               argv[j] = "-static";
-                                               }
-                                       }
-                                       // ld classic does not understand -demangle 
-                                       for(int j=0; j < argc; ++j) {
-                                               if ( strcmp(argv[j], "-demangle") == 0) 
-                                                       argv[j] = "-noprebind";
-                                       }
                                        this->gotoClassicLinker(argc, argv);
                                }
                        }
@@ -4074,7 +4090,29 @@ void Options::checkForClassic(int argc, const char* argv[])
 
 void Options::gotoClassicLinker(int argc, const char* argv[])
 {
+       warning("using ld_classic");
        argv[0] = "ld_classic";
+       // ld_classic does not support -iphoneos_version_min, so change
+       for(int j=0; j < argc; ++j) {
+               if ( (strcmp(argv[j], "-iphoneos_version_min") == 0) || (strcmp(argv[j], "-ios_version_min") == 0) ) {
+                       argv[j] = "-macosx_version_min";
+                       if ( j < argc-1 )
+                               argv[j+1] = "10.5";
+                       break;
+               }
+       }
+       // ld classic does not understand -kext (change to -static -r)
+       for(int j=0; j < argc; ++j) {
+               if ( strcmp(argv[j], "-kext") == 0) 
+                       argv[j] = "-r";
+               else if ( strcmp(argv[j], "-dynamic") == 0) 
+                       argv[j] = "-static";
+       }
+       // ld classic does not understand -demangle 
+       for(int j=0; j < argc; ++j) {
+               if ( strcmp(argv[j], "-demangle") == 0) 
+                       argv[j] = "-noprebind";
+       }
        // in -v mode, print command line passed to ld_classic
        for(int i=0; i < argc; ++i) {
                if ( strcmp(argv[i], "-v") == 0 ) {
index 7ce5766a20fe280e8038db2b60c15fdecb291321..d9becf3296c5a2358572d4bd199542ed2c53d35b 100644 (file)
@@ -150,6 +150,7 @@ public:
        bool                                            forceCpuSubtypeAll() const { return fForceSubtypeAll; }
        const char*                                     architectureName() const { return fArchitectureName; }
        void                                            setArchitecture(cpu_type_t, cpu_subtype_t subtype);
+       bool                                            archSupportsThumb2() const { return fArchSupportsThumb2; }
        OutputKind                                      outputKind() const { return fOutputKind; }
        bool                                            prebind() const { return fPrebind; }
        bool                                            bindAtLoad() const { return fBindAtLoad; }
@@ -178,8 +179,8 @@ public:
        bool                                            deadCodeStrip() const   { return fDeadStrip; }
        UndefinedTreatment                      undefinedTreatment() const { return fUndefinedTreatment; }
        ld::MacVersionMin                       macosxVersionMin() const { return fMacVersionMin; }
-       ld::IPhoneVersionMin            iphoneOSVersionMin() const { return fIPhoneVersionMin; }
-       bool                                            minOS(ld::MacVersionMin mac, ld::IPhoneVersionMin iPhoneOS);
+       ld::IOSVersionMin                       iOSVersionMin() const { return fIOSVersionMin; }
+       bool                                            minOS(ld::MacVersionMin mac, ld::IOSVersionMin iPhoneOS);
        bool                                            messagesPrefixedWithArchitecture();
        Treatment                                       picTreatment();
        WeakReferenceMismatchTreatment  weakReferenceMismatchTreatment() const { return fWeakReferenceMismatchTreatment; }
@@ -262,6 +263,7 @@ public:
        bool                                            loadAllObjcObjectsFromArchives() const { return fLoadAllObjcObjectsFromArchives; }
        bool                                            autoOrderInitializers() const { return fAutoOrderInitializers; }
        bool                                            optimizeZeroFill() const { return fOptimizeZeroFill; }
+       bool                                            mergeZeroFill() const { return fMergeZeroFill; }
        bool                                            logAllFiles() const { return fLogAllFiles; }
        DebugInfoStripping                      debugInfoStripping() const { return fDebugInfoStripping; }
        bool                                            flatNamespace() const { return fFlatNamespace; }
@@ -285,6 +287,7 @@ public:
        bool                                            canReExportSymbols() const { return fCanReExportSymbols; }
        const char*                                     tempLtoObjectPath() const { return fTempLtoObjectPath; }
        bool                                            objcCategoryMerging() const { return fObjcCategoryMerging; }
+       bool                                            pageAlignDataAtoms() const { return fPageAlignDataAtoms; }
        bool                                            hasWeakBitTweaks() const;
        bool                                            forceWeak(const char* symbolName) const;
        bool                                            forceNotWeak(const char* symbolName) const;
@@ -345,7 +348,7 @@ private:
        void                                            parsePostCommandLineEnvironmentSettings();
        void                                            setUndefinedTreatment(const char* treatment);
        void                                            setMacOSXVersionMin(const char* version);
-       void                                            setIPhoneVersionMin(const char* version);
+       void                                            setIOSVersionMin(const char* version);
        void                                            setWeakReferenceMismatchTreatment(const char* treatment);
        void                                            addDylibOverride(const char* paths);
        void                                            addSectionAlignment(const char* segment, const char* section, const char* alignment);
@@ -369,6 +372,7 @@ private:
        const char*                                                     fArchitectureName;
        OutputKind                                                      fOutputKind;
        bool                                                            fHasPreferredSubType;
+       bool                                                            fArchSupportsThumb2;
        bool                                                            fPrebind;
        bool                                                            fBindAtLoad;
        bool                                                            fKeepPrivateExterns;
@@ -476,6 +480,7 @@ private:
        bool                                                            fRemoveDwarfUnwindIfCompactExists;
        bool                                                            fAutoOrderInitializers;
        bool                                                            fOptimizeZeroFill;
+       bool                                                            fMergeZeroFill;
        bool                                                            fLogObjectFiles;
        bool                                                            fLogAllFiles;
        bool                                                            fTraceDylibs;
@@ -489,13 +494,18 @@ private:
        bool                                                            fDemangle;
        bool                                                            fTLVSupport;
        bool                                                            fVersionLoadCommand;
+       bool                                                            fVersionLoadCommandForcedOn;
+       bool                                                            fVersionLoadCommandForcedOff;
        bool                                                            fFunctionStartsLoadCommand;
+       bool                                                            fFunctionStartsForcedOn;
+       bool                                                            fFunctionStartsForcedOff;
        bool                                                            fCanReExportSymbols;
        bool                                                            fObjcCategoryMerging;
+       bool                                                            fPageAlignDataAtoms;
        DebugInfoStripping                                      fDebugInfoStripping;
        const char*                                                     fTraceOutputFile;
        ld::MacVersionMin                                       fMacVersionMin;
-       ld::IPhoneVersionMin                            fIPhoneVersionMin;
+       ld::IOSVersionMin                                       fIOSVersionMin;
        std::vector<AliasPair>                          fAliases;
        std::vector<const char*>                        fInitialUndefines;
        NameSet                                                         fAllowedUndefined;
index 963e9e5d89357df276985fba65eb5b19877daf2e..65e8b8c985907831a2ba95cd73dc73746f7b75ff 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
  *
- * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -320,10 +320,25 @@ void OutputFile::setSectionSizesAndAlignments(ld::Internal& state)
                        uint64_t offset = 0;
                        for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
                                const ld::Atom* atom = *ait;
-                               if ( atom->alignment().powerOf2 > maxAlignment )
-                                       maxAlignment = atom->alignment().powerOf2;
+                               bool pagePerAtom = false;
+                               uint32_t atomAlignmentPowerOf2 = atom->alignment().powerOf2;
+                               if ( _options.pageAlignDataAtoms() && ( strcmp(atom->section().segmentName(), "__DATA") == 0) ) { 
+                                       switch ( atom->section().type() ) {
+                                               case ld::Section::typeUnclassified:
+                                               case ld::Section::typeTentativeDefs:
+                                               case ld::Section::typeZeroFill:
+                                                       pagePerAtom = true;
+                                                       if ( atomAlignmentPowerOf2 < 12 )
+                                                               atomAlignmentPowerOf2 = 12;
+                                                       break;
+                                               default:
+                                                       break;
+                                       }
+                               }
+                               if ( atomAlignmentPowerOf2 > maxAlignment )
+                                       maxAlignment = atomAlignmentPowerOf2;
                                // calculate section offset for this atom
-                               uint64_t alignment = 1 << atom->alignment().powerOf2;
+                               uint64_t alignment = 1 << atomAlignmentPowerOf2;
                                uint64_t currentModulus = (offset % alignment);
                                uint64_t requiredModulus = atom->alignment().modulus;
                                if ( currentModulus != requiredModulus ) {
@@ -336,6 +351,9 @@ void OutputFile::setSectionSizesAndAlignments(ld::Internal& state)
                                if ( sect->type() != ld::Section::typeLinkEdit ) {
                                        (const_cast<ld::Atom*>(atom))->setSectionOffset(offset);
                                        offset += atom->size();
+                                       if ( pagePerAtom ) {
+                                               offset = (offset + 4095) & (-4096); // round up to end of page
+                                       }
                                }
                                if ( (atom->scope() == ld::Atom::scopeGlobal) 
                                        && (atom->definition() == ld::Atom::definitionRegular) 
@@ -581,7 +599,7 @@ void OutputFile::assignFileOffsets(ld::Internal& state)
                for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
                        ld::Internal::FinalSection* sect = *it;
                        if ( strcmp(sect->segmentName(), "__TEXT") == 0 ) {
-                               _encryptedTEXTendOffset = pageAlign(sect->fileOffset);
+                               _encryptedTEXTendOffset = pageAlign(sect->fileOffset + sect->size);
                        }
                }
        }
@@ -779,10 +797,43 @@ void OutputFile::rangeCheckBranch32(int64_t displacement, ld::Internal& state, c
        }
 }
 
+
+void OutputFile::rangeCheckAbsolute32(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+       const int64_t fourGigLimit  = 0xFFFFFFFF;
+       if ( displacement > fourGigLimit ) {
+               // <rdar://problem/9610466> cannot enforce 32-bit range checks on 32-bit archs because assembler loses sign information
+               //  .long _foo - 0xC0000000
+               // is encoded in mach-o the same as:
+               //  .long _foo + 0x40000000
+               // so if _foo lays out to 0xC0000100, the first is ok, but the second is not.  
+               if ( (_options.architecture() == CPU_TYPE_ARM) || (_options.architecture() == CPU_TYPE_I386) ) {
+                       // Unlikely userland code does funky stuff like this, so warn for them, but not warn for -preload
+                       if ( _options.outputKind() != Options::kPreload ) {
+                               warning("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to 0x%08llX", 
+                                               displacement, atom->name(), fixup->offsetInAtom, atom->finalAddress(), displacement);
+                       }
+                       return;
+               }
+               // show layout of final image
+               printSectionLayout(state);
+               
+               const ld::Atom* target; 
+               if ( fixup->binding == ld::Fixup::bindingNone )
+                       throwf("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to 0x%08llX", 
+                               displacement, atom->name(), fixup->offsetInAtom, atom->finalAddress(), displacement);
+               else
+                       throwf("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), fixup->offsetInAtom, atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+       }
+}
+
+
 void OutputFile::rangeCheckRIP32(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
 {
        const int64_t twoGigLimit  = 0x7FFFFFFF;
-       if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
+       if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {        
                // show layout of final image
                printSectionLayout(state);
                
@@ -822,8 +873,8 @@ void OutputFile::rangeCheckARMBranch24(int64_t displacement, ld::Internal& state
 
 void OutputFile::rangeCheckThumbBranch22(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
 {
-       // armv7 supports a larger displacement
-       if ( _options.preferSubArchitecture() && (_options.subArchitecture() == CPU_SUBTYPE_ARM_V7) ) {
+       // thumb2 supports a larger displacement
+       if ( _options.preferSubArchitecture() && _options.archSupportsThumb2() ) {
                if ( (displacement > 16777214LL) || (displacement < (-16777216LL)) ) {
                        // show layout of final image
                        printSectionLayout(state);
@@ -967,6 +1018,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                set32LE(fixUpLocation, (get32LE(fixUpLocation) & 0xFF000000) | (accumulator & 0x00FFFFFF) );
                                break;
                        case ld::Fixup::kindStoreLittleEndian32:
+                               rangeCheckAbsolute32(accumulator, state, atom, fit);
                                set32LE(fixUpLocation, accumulator);
                                break;
                        case ld::Fixup::kindStoreLittleEndian64:
@@ -979,6 +1031,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                set32BE(fixUpLocation, (get32BE(fixUpLocation) & 0xFF000000) | (accumulator & 0x00FFFFFF) );
                                break;
                        case ld::Fixup::kindStoreBigEndian32:
+                               rangeCheckAbsolute32(accumulator, state, atom, fit);
                                set32BE(fixUpLocation, accumulator);
                                break;
                        case ld::Fixup::kindStoreBigEndian64:
@@ -1198,6 +1251,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        accumulator |= 1;
                                if ( fit->contentAddendOnly )
                                        accumulator = 0;
+                               rangeCheckAbsolute32(accumulator, state, atom, fit);
                                set32LE(fixUpLocation, accumulator);
                                break;
                        case ld::Fixup::kindStoreTargetAddressLittleEndian64:
@@ -1287,6 +1341,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                // Make sure we are calling arm with bl, thumb with blx                 
                                is_bl = ((instruction & 0xFF000000) == 0xEB000000);
                                is_blx = ((instruction & 0xFE000000) == 0xFA000000);
+                               is_b = !is_blx && ((instruction & 0x0F000000) == 0x0A000000);
                                if ( is_bl && thumbTarget ) {
                                        uint32_t opcode = 0xFA000000;
                                        uint32_t disp = (uint32_t)(delta >> 2) & 0x00FFFFFF;
@@ -1298,6 +1353,13 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        uint32_t disp = (uint32_t)(delta >> 2) & 0x00FFFFFF;
                                        newInstruction = opcode | disp;
                                } 
+                               else if ( is_b && thumbTarget ) {
+                                       if ( fit->contentDetlaToAddendOnly )
+                                               newInstruction = (instruction & 0xFF000000) | ((uint32_t)(delta >> 2) & 0x00FFFFFF);
+                                       else
+                                               throwf("no pc-rel bx arm instruction. Can't fix up branch to %s in %s",
+                                                               referenceTargetAtomName(state, fit), atom->name());
+                               } 
                                else if ( !is_bl && !is_blx && thumbTarget ) {
                                        throwf("don't know how to convert instruction %x referencing %s to thumb",
                                                 instruction, referenceTargetAtomName(state, fit));
@@ -1324,14 +1386,14 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                // Since blx cannot have the low bit set, set bit[1] of the target to
                                // bit[1] of the base address, so that the difference is a multiple of
                                // 4 bytes.
-                               if ( !thumbTarget ) {
+                               if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) {
                                  accumulator &= -3ULL;
                                  accumulator |= ((atom->finalAddress() + fit->offsetInAtom ) & 2LL);
                                }
                                // The pc added will be +4 from the pc
                                delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
                                rangeCheckThumbBranch22(delta, state, atom, fit);
-                               if ( _options.preferSubArchitecture() && _options.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
+                               if ( _options.preferSubArchitecture() && _options.archSupportsThumb2() ) {
                                        // The instruction is really two instructions:
                                        // The lower 16 bits are the first instruction, which contains the high
                                        //   11 bits of the displacement.
@@ -1357,12 +1419,13 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                                        instruction = 0xC000F000; // keep blx
                                        }
                                        else if ( is_b ) {
-                                               if ( !thumbTarget ) 
-                                                       throwf("don't know how to convert instruction %x referencing %s to arm",
-                                                                       instruction, referenceTargetAtomName(state, fit));
                                                instruction = 0x9000F000; // keep b
+                                               if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) {
+                                                       throwf("armv7 has no pc-rel bx thumb instruction. Can't fix up branch to %s in %s",
+                                                                       referenceTargetAtomName(state, fit), atom->name());
+                                               }
                                        } 
-                                       else if ( is_b ) {
+                                       else {
                                                if ( !thumbTarget ) 
                                                        throwf("don't know how to convert branch instruction %x referencing %s to bx",
                                                                        instruction, referenceTargetAtomName(state, fit));
@@ -1389,10 +1452,13 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        else if ( is_blx && thumbTarget ) {
                                                instruction = 0xF800F000;
                                        } 
-                                       else if ( !is_bl && !is_blx && !thumbTarget ) {
-                                         throwf("don't know how to convert instruction %x referencing %s to arm",
-                                                        instruction, referenceTargetAtomName(state, fit));
-                                       } 
+                                       else if ( is_b ) {
+                                               instruction = 0x9000F000; // keep b
+                                               if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) {
+                                                       throwf("armv6 has no pc-rel bx thumb instruction. Can't fix up branch to %s in %s",
+                                                                       referenceTargetAtomName(state, fit), atom->name());
+                                               }
+                                       }
                                        else {
                                                instruction = instruction & 0xF800F800;
                                        }
@@ -1456,7 +1522,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
        }
 }
 
-void OutputFile::copyNoOps(uint8_t* from, uint8_t* to)
+void OutputFile::copyNoOps(uint8_t* from, uint8_t* to, bool thumb)
 {
        switch ( _options.architecture() ) {
                case CPU_TYPE_POWERPC:
@@ -1469,9 +1535,14 @@ void OutputFile::copyNoOps(uint8_t* from, uint8_t* to)
                                *p = 0x90;
                        break;
                case CPU_TYPE_ARM:
-                       // fixme: need thumb nop?
-                       for (uint8_t* p=from; p < to; p += 4)
-                               OSWriteBigInt32((uint32_t*)p, 0, 0xe1a00000);
+                       if ( thumb ) {
+                               for (uint8_t* p=from; p < to; p += 2)
+                                       OSWriteLittleInt16((uint16_t*)p, 0, 0x46c0);
+                       }
+                       else {
+                               for (uint8_t* p=from; p < to; p += 4)
+                                       OSWriteLittleInt32((uint32_t*)p, 0, 0xe1a00000);
+                       }
                        break;
                default:
                        for (uint8_t* p=from; p < to; ++p)
@@ -1555,6 +1626,7 @@ void OutputFile::writeOutputFile(ld::Internal& state)
                const bool sectionUsesNops = (sect->type() == ld::Section::typeCode);
                //fprintf(stderr, "file offset=0x%08llX, section %s\n", sect->fileOffset, sect->sectionName());
                std::vector<const ld::Atom*>& atoms = sect->atoms;
+               bool lastAtomWasThumb = false;
                for (std::vector<const ld::Atom*>::iterator ait = atoms.begin(); ait != atoms.end(); ++ait) {
                        const ld::Atom* atom = *ait;
                        if ( atom->definition() == ld::Atom::definitionProxy )
@@ -1563,7 +1635,7 @@ void OutputFile::writeOutputFile(ld::Internal& state)
                                uint64_t fileOffset = atom->finalAddress() - sect->address + sect->fileOffset;
                                // check for alignment padding between atoms
                                if ( (fileOffset != fileOffsetOfEndOfLastAtom) && lastAtomUsesNoOps ) {
-                                       this->copyNoOps(&wholeBuffer[fileOffsetOfEndOfLastAtom], &wholeBuffer[fileOffset]);
+                                       this->copyNoOps(&wholeBuffer[fileOffsetOfEndOfLastAtom], &wholeBuffer[fileOffset], lastAtomWasThumb);
                                }
                                // copy atom content
                                atom->copyRawContent(&wholeBuffer[fileOffset]);
@@ -1571,6 +1643,7 @@ void OutputFile::writeOutputFile(ld::Internal& state)
                                this->applyFixUps(state, mhAddress, atom, &wholeBuffer[fileOffset]);
                                fileOffsetOfEndOfLastAtom = fileOffset+atom->size();
                                lastAtomUsesNoOps = sectionUsesNops;
+                               lastAtomWasThumb = atom->isThumb();
                        }
                        catch (const char* msg) {
                                if ( atom->file() != NULL )
@@ -1658,6 +1731,19 @@ struct AtomByNameSorter
         }
 };
 
+class NotInSet
+{
+public:
+       NotInSet(const std::set<const ld::Atom*>& theSet) : _set(theSet)  {}
+
+       bool operator()(const ld::Atom* atom) const {
+               return ( _set.count(atom) == 0 );
+       }
+private:
+       const std::set<const ld::Atom*>&  _set;
+};
+
+
 void OutputFile::buildSymbolTable(ld::Internal& state)
 {
        unsigned int machoSectionIndex = 0;
@@ -1800,7 +1886,11 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                                                }
                                        }
                                        else {
-                                               if ( _options.keepLocalSymbol(atom->name()) )
+                                               if ( _options.keepLocalSymbol(atom->name()) ) 
+                                                       _localAtoms.push_back(atom);
+                                               // <rdar://problem/5804214> ld should never have a symbol in the non-lazy indirect symbol table with index 0
+                                               // this works by making __mh_execute_header be a local symbol which takes symbol index 0
+                                               else if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip) && !_options.makeCompressedDyldInfo() )
                                                        _localAtoms.push_back(atom);
                                                else
                                                        (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableNotIn);
@@ -1810,10 +1900,35 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                }
        }
        
+       // <rdar://problem/6978069> ld adds undefined symbol from .exp file to binary
+       if ( (_options.outputKind() == Options::kKextBundle) && _options.hasExportRestrictList() ) {
+               // search for referenced undefines
+               std::set<const ld::Atom*> referencedProxyAtoms;
+               for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+                       ld::Internal::FinalSection* sect = *sit;
+                       for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin();  ait != sect->atoms.end(); ++ait) {
+                               const ld::Atom* atom = *ait;
+                               for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                                       switch ( fit->binding ) {
+                                               case ld::Fixup::bindingsIndirectlyBound:
+                                                       referencedProxyAtoms.insert(state.indirectBindingTable[fit->u.bindingIndex]);
+                                                       break;
+                                               case ld::Fixup::bindingDirectlyBound:
+                                                       referencedProxyAtoms.insert(fit->u.target);
+                                                       break;
+                                               default:
+                                                       break;
+                                       }
+                               }
+                       }
+               }
+               // remove any unreferenced _importedAtoms
+               _importedAtoms.erase(std::remove_if(_importedAtoms.begin(), _importedAtoms.end(), NotInSet(referencedProxyAtoms)), _importedAtoms.end());                       
+       }
+       
        // sort by name
        std::sort(_exportedAtoms.begin(), _exportedAtoms.end(), AtomByNameSorter());
        std::sort(_importedAtoms.begin(), _importedAtoms.end(), AtomByNameSorter());
-       
 }
 
 void OutputFile::addPreloadLinkEdit(ld::Internal& state)
@@ -2583,7 +2698,7 @@ void OutputFile::noteTextReloc(const ld::Atom* atom, const ld::Atom* target)
                if ( _options.warnAboutTextRelocs() )
                        warning("text reloc in %s to %s", atom->name(), target->name());
        } 
-       else if ( _options.positionIndependentExecutable() && ((_options.iphoneOSVersionMin() >= ld::iPhone4_3) || (_options.macosxVersionMin() >= ld::mac10_7)) ) {
+       else if ( _options.positionIndependentExecutable() && ((_options.iOSVersionMin() >= ld::iOS_4_3) || (_options.macosxVersionMin() >= ld::mac10_7)) ) {
                if ( ! this->pieDisabled ) {
                        warning("PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, "
                                "but used in %s from %s. " 
@@ -2592,8 +2707,11 @@ void OutputFile::noteTextReloc(const ld::Atom* atom, const ld::Atom* target)
                }
                this->pieDisabled = true;
        }
+       else if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) ) {
+               throwf("illegal text-relocoation (direct reference) to (global,weak) %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
+       }
        else {
-               throwf("illegal text reloc to %s from %s in %s", target->name(), target->file()->path(), atom->name());
+               throwf("illegal text-relocation to %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
        }
 }
 
@@ -2608,8 +2726,22 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
        // no need to rebase or bind PCRel stores
        if ( this->isPcRelStore(fixupWithStore->kind) ) {
                // as long as target is in same linkage unit
-               if ( (target == NULL) || (target->definition() != ld::Atom::definitionProxy) )
+               if ( (target == NULL) || (target->definition() != ld::Atom::definitionProxy) ) {
+                       // make sure target is not global and weak
+                       if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular)) {
+                               if ( (atom->section().type() == ld::Section::typeCFI)
+                                       || (atom->section().type() == ld::Section::typeDtraceDOF)
+                                       || (atom->section().type() == ld::Section::typeUnwindInfo) ) {
+                                       // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
+                                       return;
+                               }
+                               // Have direct reference to weak-global.  This should be an indrect reference
+                               warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. "
+                                               "This was likely caused by different translation units being compiled with different visibility settings.",
+                                                atom->name(), target->name());
+                       }
                        return;
+               }
        }
 
        // no need to rebase or bind PIC internal pointer diff
@@ -2623,13 +2755,18 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                        return;
                }
                
-               // make sure target is not global and weak
-               if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName)
-                               && (atom->section().type() != ld::Section::typeCFI)
-                               && (atom->section().type() != ld::Section::typeDtraceDOF)
-                               && (atom->section().type() != ld::Section::typeUnwindInfo) ) {
-                       // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
-                       throwf("bad codegen, pointer diff in %s to global weak symbol %s", atom->name(), target->name());
+               // check if target of pointer-diff is global and weak
+               if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular) ) {
+                       if ( (atom->section().type() == ld::Section::typeCFI)
+                               || (atom->section().type() == ld::Section::typeDtraceDOF)
+                               || (atom->section().type() == ld::Section::typeUnwindInfo) ) {
+                               // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
+                               return;
+                       }
+                       // Have direct reference to weak-global.  This should be an indrect reference
+                       warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. "
+                                       "This was likely caused by different translation units being compiled with different visibility settings.",
+                                        atom->name(), target->name());
                }
                return;
        }
@@ -2651,7 +2788,7 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
        uint8_t rebaseType = REBASE_TYPE_POINTER;
        uint8_t type = BIND_TYPE_POINTER;
        const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
-       bool weak_import = ((dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()));
+       bool weak_import = ((dylib != NULL) && (fixupWithTarget->weakImport || dylib->forcedWeakLinked()));
        uint64_t address =  atom->finalAddress() + fixupWithTarget->offsetInAtom;
        uint64_t addend = targetAddend - minusTargetAddend;
 
@@ -2764,10 +2901,6 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
        }
        if ( needsWeakBinding )
                _weakBindingInfo.push_back(BindingInfo(type, 0, target->name(), false, address, addend));
-
-       // record if weak imported  
-       if ( weak_import && (target->definition() == ld::Atom::definitionProxy) )
-               (const_cast<ld::Atom*>(target))->setWeakImported();
 }
 
 
@@ -2783,10 +2916,6 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
        if ( (sect->type() == ld::Section::typeNonLazyPointer) && (_options.outputKind() != Options::kKextBundle) ) {
                assert(target != NULL);
                assert(fixupWithTarget != NULL);
-               // record if weak imported  
-               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
-               if ( (dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()) )
-                       (const_cast<ld::Atom*>(target))->setWeakImported();
                return;
        }
        
@@ -2828,12 +2957,7 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
 
        switch ( fixupWithStore->kind ) {
                case ld::Fixup::kindLazyTarget:
-                       {
-                               // lazy pointers don't need relocs, but might need weak_import bit set
-                               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
-                               if ( (dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()) )
-                                       (const_cast<ld::Atom*>(target))->setWeakImported();
-                       }
+                       // lazy pointers don't need relocs
                        break;
                case ld::Fixup::kindStoreLittleEndian32:
                case ld::Fixup::kindStoreLittleEndian64:
@@ -2893,9 +3017,6 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
                                _externalRelocsAtom->addExternalPointerReloc(relocAddress, target);
                                sect->hasExternalRelocs = true;
                                fixupWithTarget->contentAddendOnly = true;
-                               // record if weak imported  
-                               if ( (dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()) )
-                                       (const_cast<ld::Atom*>(target))->setWeakImported();
                        }
                        else if ( needsLocalReloc ) {
                                assert(target != NULL);
@@ -2933,6 +3054,21 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
                                }
                        }
                        break;
+               
+               case ld::Fixup::kindStoreARMLow16:
+               case ld::Fixup::kindStoreThumbLow16:
+                       // no way to encode rebasing of binding for these instructions
+                       if ( _options.outputSlidable() || (target->definition() == ld::Atom::definitionProxy) )
+                               throwf("no supported runtime lo16 relocation in %s from %s to %s", atom->name(), atom->file()->path(), target->name());
+                       break;
+                               
+               case ld::Fixup::kindStoreARMHigh16:
+               case ld::Fixup::kindStoreThumbHigh16:
+                       // no way to encode rebasing of binding for these instructions
+                       if ( _options.outputSlidable() || (target->definition() == ld::Atom::definitionProxy) )
+                               throwf("no supported runtime hi16 relocation in %s from %s to %s", atom->name(), atom->file()->path(), target->name());
+                       break;
+
                default:
                        break;
        }
@@ -2945,6 +3081,22 @@ bool OutputFile::useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* t
                // x86_64 uses external relocations for everthing that has a symbol
                return ( target->symbolTableInclusion() != ld::Atom::symbolTableNotIn );
        }
+       
+       // <rdar://problem/9513487> support arm branch interworking in -r mode 
+       if ( (_options.architecture() == CPU_TYPE_ARM) && (_options.outputKind() == Options::kObjectFile) ) {
+               if ( atom->isThumb() != target->isThumb() ) {
+                       switch ( fixupWithTarget->kind ) {
+                               // have branch that switches mode, then might be 'b' not 'bl'
+                               // Force external relocation, since no way to do local reloc for 'b'
+                               case ld::Fixup::kindStoreTargetAddressThumbBranch22 :
+                               case ld::Fixup::kindStoreTargetAddressARMBranch24:
+                                       return true;
+                               default:
+                                       break;
+                       }
+               }
+       }
+
        // most architectures use external relocations only for references
        // to a symbol in another translation unit or for references to "weak symbols" or tentative definitions
        assert(target != NULL);
@@ -3035,27 +3187,30 @@ void OutputFile::makeSplitSegInfo(ld::Internal& state)
                for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
                        const ld::Atom* atom = *ait;
                        const ld::Atom* target = NULL;
+                       const ld::Atom* fromTarget = NULL;
+            uint64_t accumulator = 0;
+            bool thumbTarget;
                        bool hadSubtract = false;
                        for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
                                if ( fit->firstInCluster() ) 
                                        target = NULL;
-                               if ( fit->kind == ld::Fixup::kindSubtractTargetAddress ) {
-                                       hadSubtract = true;
-                                       continue;
+                               if ( this->setsTarget(fit->kind) ) {
+                                       accumulator = addressOf(state, fit, &target);                   
+                                       thumbTarget = targetIsThumb(state, fit);
+                                       if ( thumbTarget ) 
+                                               accumulator |= 1;
                                }
-                               switch ( fit->binding ) {
-                                       case ld::Fixup::bindingNone:
-                                       case ld::Fixup::bindingByNameUnbound:
+                               switch ( fit->kind ) {
+                                       case ld::Fixup::kindSubtractTargetAddress:
+                        accumulator -= addressOf(state, fit, &fromTarget);
+                                               hadSubtract = true;
                                                break;
-                                       case ld::Fixup::bindingByContentBound:
-                                       case ld::Fixup::bindingDirectlyBound:
-                                               target = fit->u.target;
+                    case ld::Fixup::kindAddAddend:
+                                               accumulator += fit->u.addend;
                                                break;
-                                       case ld::Fixup::bindingsIndirectlyBound:
-                                               target = state.indirectBindingTable[fit->u.bindingIndex];
+                    case ld::Fixup::kindSubtractAddend:
+                                               accumulator -= fit->u.addend;
                                                break;
-                               }
-                               switch ( fit->kind ) {
                                        case ld::Fixup::kindStoreBigEndian32:
                                        case ld::Fixup::kindStoreLittleEndian32:
                                        case ld::Fixup::kindStoreLittleEndian64:
@@ -3065,6 +3220,7 @@ void OutputFile::makeSplitSegInfo(ld::Internal& state)
                                                // there is also a text reloc which update_dyld_shared_cache will use.
                                                if ( ! hadSubtract )
                                                        break;
+                                               // fall through
                                        case ld::Fixup::kindStoreX86PCRel32:
                                        case ld::Fixup::kindStoreX86PCRel32_1:
                                        case ld::Fixup::kindStoreX86PCRel32_2:
@@ -3076,11 +3232,27 @@ void OutputFile::makeSplitSegInfo(ld::Internal& state)
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                    case ld::Fixup::kindStoreARMLow16:
+                    case ld::Fixup::kindStoreThumbLow16: 
                                                assert(target != NULL);
                                                if ( strcmp(sect->segmentName(), target->section().segmentName()) != 0 ) {      
                                                        _splitSegInfos.push_back(SplitSegInfoEntry(atom->finalAddress()+fit->offsetInAtom,fit->kind));
                                                }
                                                break;
+                    case ld::Fixup::kindStoreARMHigh16: 
+                    case ld::Fixup::kindStoreThumbHigh16: 
+                                               assert(target != NULL);
+                                               if ( strcmp(sect->segmentName(), target->section().segmentName()) != 0 ) {
+                            // hi16 needs to know upper 4-bits of low16 to compute carry
+                            uint32_t extra = (accumulator >> 12) & 0xF;
+                                                       _splitSegInfos.push_back(SplitSegInfoEntry(atom->finalAddress()+fit->offsetInAtom,fit->kind, extra));
+                                               }
+                                               break;
+                                       case ld::Fixup::kindSetTargetImageOffset:
+                                               accumulator = addressOf(state, fit, &target);                   
+                                               assert(target != NULL);
+                                               hadSubtract = true;
+                                               break;
                                        default:
                                                break;
                                }
@@ -3218,8 +3390,8 @@ public:
                        return (leftFileOrdinal < rightFileOrdinal);
 
                // then sort by atom objectAddress
-               uint64_t leftAddr  = left->objectAddress();
-               uint64_t rightAddr = right->objectAddress();
+               uint64_t leftAddr  = left->finalAddress();
+               uint64_t rightAddr = right->finalAddress();
                return leftAddr < rightAddr;
        }
 };
@@ -3315,7 +3487,7 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state)
                const ld::relocatable::File* atomObjFile = dynamic_cast<const ld::relocatable::File*>(atomFile);
                const char* newDirPath;
                const char* newFilename;
-               //fprintf(stderr, "debug note for %s\n", atom->getDisplayName());
+               //fprintf(stderr, "debug note for %s\n", atom->name());
                if ( atom->translationUnitSource(&newDirPath, &newFilename) ) {
                        // need SO's whenever the translation unit source file changes
                        if ( newFilename != filename ) {
@@ -3370,7 +3542,7 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state)
                                // add the source file path to seenFiles so it does not show up in SOLs
                                seenFiles.insert(newFilename);
                                char* fullFilePath;
-                               asprintf(&fullFilePath, "%s/%s", newDirPath, newFilename);
+                               asprintf(&fullFilePath, "%s%s", newDirPath, newFilename);
                                // add both leaf path and full path
                                seenFiles.insert(fullFilePath);
                        }
index 9b4928921089bccef4291e2a83f8f31811525142..415d24b29383ad2f6fa86f75d84fd4eb5905f891 100644 (file)
@@ -130,9 +130,10 @@ public:
        };
        
        struct SplitSegInfoEntry {
-                                               SplitSegInfoEntry(uint64_t a, ld::Fixup::Kind k) : address(a), kind(k) {}
+                                               SplitSegInfoEntry(uint64_t a, ld::Fixup::Kind k, uint32_t e=0) : address(a), kind(k), extra(e) {}
                uint64_t                address;
                ld::Fixup::Kind kind;
+        uint32_t        extra;
        };
        
 private:
@@ -175,7 +176,7 @@ private:
        uint64_t                                        addressOf(const ld::Internal& state, const ld::Fixup* fixup, const ld::Atom** target);
        bool                                            targetIsThumb(ld::Internal& state, const ld::Fixup* fixup);
        uint32_t                                        lazyBindingInfoOffsetForLazyPointerAddress(uint64_t lpAddress);
-       void                                            copyNoOps(uint8_t* from, uint8_t* to);
+       void                                            copyNoOps(uint8_t* from, uint8_t* to, bool thumb);
        bool                                            isPointerToTarget(ld::Fixup::Kind kind);
        bool                                            isPointerFromTarget(ld::Fixup::Kind kind);
        bool                                            isPcRelStore(ld::Fixup::Kind kind);
@@ -199,6 +200,8 @@ private:
                                                                                                                                                                                        const ld::Fixup* fixup);
        void                                            rangeCheckBranch32(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
                                                                                                                                                                                        const ld::Fixup* fixup);
+       void                                            rangeCheckAbsolute32(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
+                                                                                                                                                                                       const ld::Fixup* fixup);
        void                                            rangeCheckRIP32(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
                                                                                                                                                                                        const ld::Fixup* fixup);
        void                                            rangeCheckARM12(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
index e17e632ad4b8ef12c4b9ce1c2cdc2dfee154a22c..a56cefe78d8585b9bcf3d5cff1c1e65d66356e48 100644 (file)
@@ -394,6 +394,10 @@ void Resolver::doFile(const ld::File& file)
                                        else if ( nextObjectSubType == CPU_SUBTYPE_ARM_ALL ) {
                                                warning("CPU_SUBTYPE_ARM_ALL subtype is deprecated: %s", file.path());
                                        }
+                                       else if ( _options.allowSubArchitectureMismatches() ) {
+                                               //warning("object file %s was built for different arm sub-type (%d) than link command line (%d)", 
+                                               //      file.path(), nextObjectSubType, _options.subArchitecture());
+                                       }
                                        else {
                                                throwf("object file %s was built for different arm sub-type (%d) than link command line (%d)", 
                                                        file.path(), nextObjectSubType, _options.subArchitecture());
@@ -467,11 +471,11 @@ void Resolver::doAtom(const ld::Atom& atom)
                                                                // marking proxy atom as global triggers the re-export
                                                                (const_cast<ld::Atom*>(&atom))->setScope(ld::Atom::scopeGlobal);
                                                        }
-                                                       else {
+                                                       else if ( _options.outputKind() == Options::kDynamicLibrary ) {
                                                                if ( atom.file() != NULL )
-                                                                       warning("cannot re-export symbol %s from %s\n", SymbolTable::demangle(name), atom.file()->path());
+                                                                       warning("target OS does not support re-exporting symbol %s from %s\n", SymbolTable::demangle(name), atom.file()->path());
                                                                else
-                                                                       warning("cannot re-export symbol %s\n", SymbolTable::demangle(name));
+                                                                       warning("target OS does not support re-exporting symbol %s\n", SymbolTable::demangle(name));
                                                        }
                                                }
                                                else {
@@ -639,7 +643,7 @@ void Resolver::resolveUndefines()
                        const char* undef = *it;
                        // load for previous undefine may also have loaded this undefine, so check again
                        if ( ! _symbolTable.hasName(undef) ) {
-                               _inputFiles.searchLibraries(undef, true, true, *this);
+                               _inputFiles.searchLibraries(undef, true, true, false, *this);
                                if ( !_symbolTable.hasName(undef) && (_options.outputKind() != Options::kObjectFile) ) {
                                        if ( strncmp(undef, "section$", 8) == 0 ) {
                                                if ( strncmp(undef, "section$start$", 14) == 0 ) {
@@ -686,7 +690,7 @@ void Resolver::resolveUndefines()
                                const ld::Atom* curAtom = _symbolTable.atomForSlot(_symbolTable.findSlotForName(*it));
                                assert(curAtom != NULL);
                                if ( curAtom->definition() == ld::Atom::definitionTentative ) {
-                                       _inputFiles.searchLibraries(*it, searchDylibs, true, *this);
+                                       _inputFiles.searchLibraries(*it, searchDylibs, true, true, *this);
                                }
                        }
                }
@@ -760,6 +764,10 @@ void Resolver::markLive(const ld::Atom& atom, WhyLiveBackChain* previous)
                        case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
                        case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
                        case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
+                       case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+                       case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA:
                        case ld::Fixup::kindStoreTargetAddressARMBranch24:
                        case ld::Fixup::kindStoreTargetAddressThumbBranch22:
                        case ld::Fixup::kindStoreTargetAddressPPCBranch24:
@@ -798,14 +806,14 @@ void Resolver::markLive(const ld::Atom& atom, WhyLiveBackChain* previous)
                                                target = _internal.indirectBindingTable[fit->u.bindingIndex];
                                                if ( target == NULL ) {
                                                        const char* targetName = _symbolTable.indirectName(fit->u.bindingIndex);
-                                                       _inputFiles.searchLibraries(targetName, true, true, *this);
+                                                       _inputFiles.searchLibraries(targetName, true, true, false, *this);
                                                        target = _internal.indirectBindingTable[fit->u.bindingIndex];
                                                }
                                                if ( target != NULL ) {
                                                        if ( target->definition() == ld::Atom::definitionTentative ) {
                                                                // <rdar://problem/5894163> need to search archives for overrides of common symbols 
                                                                bool searchDylibs = (_options.commonsMode() == Options::kCommonsOverriddenByDylibs);
-                                                               _inputFiles.searchLibraries(target->name(), searchDylibs, true, *this);
+                                                               _inputFiles.searchLibraries(target->name(), searchDylibs, true, true, *this);
                                                                // recompute target since it may have been overridden by searchLibraries()
                                                                target = _internal.indirectBindingTable[fit->u.bindingIndex];
                                                        }
@@ -826,6 +834,21 @@ void Resolver::markLive(const ld::Atom& atom, WhyLiveBackChain* previous)
 
 }
 
+class NotLiveLTO {
+public:
+       bool operator()(const ld::Atom* atom) const {
+               if (atom->live() || atom->dontDeadStrip() )
+                       return false;
+               // don't kill combinable atoms in first pass
+               switch ( atom->combine() ) {
+                       case ld::Atom::combineByNameAndContent:
+                       case ld::Atom::combineByNameAndReferences:
+                               return false;
+                       default:
+                               return true;
+               }
+       }
+};
 
 void Resolver::deadStripOptimize()
 {
@@ -842,7 +865,7 @@ void Resolver::deadStripOptimize()
        for (Options::UndefinesIterator uit=_options.initialUndefinesBegin(); uit != _options.initialUndefinesEnd(); ++uit) {
                SymbolTable::IndirectBindingSlot slot = _symbolTable.findSlotForName(*uit);
                if ( _internal.indirectBindingTable[slot] == NULL ) {
-                       _inputFiles.searchLibraries(*uit, false, true, *this);
+                       _inputFiles.searchLibraries(*uit, false, true, false, *this);
                }
                if ( _internal.indirectBindingTable[slot] != NULL )
                        _deadStripRoots.insert(_internal.indirectBindingTable[slot]);
@@ -887,7 +910,14 @@ void Resolver::deadStripOptimize()
                        fprintf(stderr, "  live=%d  name=%s\n", (*it)->live(), (*it)->name());
                }
        }
-       _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), NotLive()), _atoms.end());
+       
+       if ( _haveLLVMObjs ) {
+               // <rdar://problem/9777977> don't remove combinable atoms, they may come back in lto output
+               _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), NotLiveLTO()), _atoms.end());
+       }
+       else {
+               _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), NotLive()), _atoms.end());
+       }
 }
 
 
@@ -897,7 +927,8 @@ void Resolver::liveUndefines(std::vector<const char*>& undefs)
        // search all live atoms for references that are unbound
        for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
                const ld::Atom* atom = *it;
-               assert(atom->live());
+               if ( ! atom->live() )
+                       continue;
                for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
                        switch ( (ld::Fixup::TargetBinding)fit->binding ) {
                                case ld::Fixup::bindingByNameUnbound:
@@ -1107,7 +1138,7 @@ void Resolver::checkUndefines(bool force)
                                bool printedStart = false;
                                for (SymbolTable::byNameIterator sit=_symbolTable.begin(); sit != _symbolTable.end(); sit++) {
                                        const ld::Atom* atom = *sit;
-                                       if ( (atom != NULL) && (strstr(atom->name(), name) != NULL) ) {
+                                       if ( (atom != NULL) && (atom->symbolTableInclusion() == ld::Atom::symbolTableIn) && (strstr(atom->name(), name) != NULL) ) {
                                                if ( ! printedStart ) {
                                                        fprintf(stderr, "     (maybe you meant: %s", atom->name());
                                                        printedStart = true;
@@ -1119,6 +1150,10 @@ void Resolver::checkUndefines(bool force)
                                }
                                if ( printedStart )
                                        fprintf(stderr, ")\n");
+                               // <rdar://problem/8989530> Add comment to error message when __ZTV symbols are undefined
+                               if ( strncmp(name, "__ZTV", 5) == 0 ) {
+                                       fprintf(stderr, "  NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.\n");
+                               }
                        }
                }
                if ( doError ) 
@@ -1139,7 +1174,7 @@ void Resolver::checkDylibSymbolCollisions()
                        // <rdar://problem/5048861> No warning about tentative definition conflicting with dylib definition
                        // for each tentative definition in symbol table look for dylib that exports same symbol name
                        if ( atom->definition() == ld::Atom::definitionTentative ) {
-                               _inputFiles.searchLibraries(atom->name(), true, false, *this);
+                               _inputFiles.searchLibraries(atom->name(), true, false, false, *this);
                        }
                        // record any overrides of weak symbols in any linked dylib 
                        if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->symbolTableInclusion() == ld::Atom::symbolTableIn) ) {
@@ -1154,6 +1189,7 @@ void Resolver::checkDylibSymbolCollisions()
 const ld::Atom* Resolver::entryPoint(bool searchArchives)
 {
        const char* symbolName = NULL;
+       bool makingDylib = false;
        switch ( _options.outputKind() ) {
                case Options::kDynamicExecutable:
                case Options::kStaticExecutable:
@@ -1163,6 +1199,7 @@ const ld::Atom* Resolver::entryPoint(bool searchArchives)
                        break;
                case Options::kDynamicLibrary:
                        symbolName = _options.initFunctionName();
+                       makingDylib = true;
                        break;
                case Options::kObjectFile:
                case Options::kDynamicBundle:
@@ -1174,7 +1211,7 @@ const ld::Atom* Resolver::entryPoint(bool searchArchives)
                SymbolTable::IndirectBindingSlot slot = _symbolTable.findSlotForName(symbolName);
                if ( (_internal.indirectBindingTable[slot] == NULL) && searchArchives ) {
                        // <rdar://problem/7043256> ld64 can not find a -e entry point from an archive                          
-                       _inputFiles.searchLibraries(symbolName, false, true, *this);
+                       _inputFiles.searchLibraries(symbolName, false, true, false, *this);
                }
                if ( _internal.indirectBindingTable[slot] == NULL ) {
                        if ( strcmp(symbolName, "start") == 0 )
@@ -1182,6 +1219,12 @@ const ld::Atom* Resolver::entryPoint(bool searchArchives)
                        else
                                throwf("entry point (%s) undefined.", symbolName);
                }
+               else if ( _internal.indirectBindingTable[slot]->definition() == ld::Atom::definitionProxy ) {
+                       if ( makingDylib ) 
+                               throwf("-init function (%s) found in linked dylib, must be in dylib being linked", symbolName);
+                       else
+                               throwf("entry point (%s) found in linked dylib, must be in executable being linked", symbolName);
+               }
                return _internal.indirectBindingTable[slot];
        }
        return NULL;
@@ -1231,7 +1274,7 @@ void Resolver::fillInHelpersInInternalState()
        if ( needsStubHelper && _options.makeCompressedDyldInfo() ) { 
                // "dyld_stub_binder" comes from libSystem.dylib so will need to manually resolve
                if ( !_symbolTable.hasName("dyld_stub_binder") ) {
-                       _inputFiles.searchLibraries("dyld_stub_binder", true, false, *this);
+                       _inputFiles.searchLibraries("dyld_stub_binder", true, false, false, *this);
                }
                if ( _symbolTable.hasName("dyld_stub_binder") ) {
                        SymbolTable::IndirectBindingSlot slot = _symbolTable.findSlotForName("dyld_stub_binder");
@@ -1243,9 +1286,6 @@ void Resolver::fillInHelpersInInternalState()
                                _internal.compressedFastBinderProxy = new UndefinedProxyAtom("dyld_stub_binder");
                                this->doAtom(*_internal.compressedFastBinderProxy);
                        }
-                       else {
-                               warning("symbol dyld_stub_binder not found, normally in libSystem.dylib");
-                       }
                }
        }
 }
@@ -1341,7 +1381,7 @@ void Resolver::linkTimeOptimize()
                const char *targetName = *uit;
                // these symbols may or may not already be in linker's symbol table
                if ( ! _symbolTable.hasName(targetName) ) {
-                       _inputFiles.searchLibraries(targetName, true, true, *this);
+                       _inputFiles.searchLibraries(targetName, true, true, false, *this);
                }
        }
        _addToFinalSection = false;
index f9ed04cb33ebfc8185878908c866ac6339252acf..2716ccfb66e798fc0c5267cbc288ce41cadf8fab 100644 (file)
@@ -137,26 +137,34 @@ bool SymbolTable::addByName(const ld::Atom& newAtom, bool ignoreDuplicates)
                                        case ld::Atom::definitionRegular:
                                                if ( existingAtom->combine() == ld::Atom::combineByName ) {
                                                        if ( newAtom.combine() == ld::Atom::combineByName ) {
-                                                               // both weak, prefer non-auto-hide one
-                                                               if ( newAtom.autoHide() != existingAtom->autoHide() ) {
-                                                                       // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
-                                                                       useNew = existingAtom->autoHide();
-                                                                       // don't check for visibility mismatch
-                                                               }
-                                                               else if ( newAtom.autoHide() && existingAtom->autoHide() ) {
-                                                                       // both have auto-hide, so use one with greater alignment
-                                                                       useNew = ( newAtom.alignment().trailingZeros() > existingAtom->alignment().trailingZeros() );
+                                                               // <rdar://problem/9183821> always choose mach-o over llvm bit code, otherwise LTO may eliminate the llvm atom
+                                                               const bool existingIsLTO = (existingAtom->contentType() == ld::Atom::typeLTOtemporary);
+                                                               const bool newIsLTO = (newAtom.contentType() == ld::Atom::typeLTOtemporary);
+                                                               if ( existingIsLTO != newIsLTO ) {
+                                                                       useNew = existingIsLTO;
                                                                }
                                                                else {
-                                                                       // neither auto-hide, check visibility
-                                                                       if ( newAtom.scope() != existingAtom->scope() ) {
-                                                                               // <rdar://problem/8304984> use more visible weak def symbol
-                                                                               useNew = (newAtom.scope() == ld::Atom::scopeGlobal);
+                                                                       // both weak, prefer non-auto-hide one
+                                                                       if ( newAtom.autoHide() != existingAtom->autoHide() ) {
+                                                                               // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
+                                                                               useNew = existingAtom->autoHide();
+                                                                               // don't check for visibility mismatch
                                                                        }
-                                                                       else {
-                                                                               // both have same visibility, use one with greater alignment
+                                                                       else if ( newAtom.autoHide() && existingAtom->autoHide() ) {
+                                                                               // both have auto-hide, so use one with greater alignment
                                                                                useNew = ( newAtom.alignment().trailingZeros() > existingAtom->alignment().trailingZeros() );
                                                                        }
+                                                                       else {
+                                                                               // neither auto-hide, check visibility
+                                                                               if ( newAtom.scope() != existingAtom->scope() ) {
+                                                                                       // <rdar://problem/8304984> use more visible weak def symbol
+                                                                                       useNew = (newAtom.scope() == ld::Atom::scopeGlobal);
+                                                                               }
+                                                                               else {
+                                                                                       // both have same visibility, use one with greater alignment
+                                                                                       useNew = ( newAtom.alignment().trailingZeros() > existingAtom->alignment().trailingZeros() );
+                                                                               }
+                                                                       }
                                                                }
                                                        }
                                                        else {
@@ -221,6 +229,11 @@ bool SymbolTable::addByName(const ld::Atom& newAtom, bool ignoreDuplicates)
                                                                                        newAtom.name(), existingAtom->size(), existingAtom->file()->path(),
                                                                                        newAtom.size(), newAtom.file()->path());
                                                }
+                                               if ( newAtom.section().type() == ld::Section::typeCode ) {
+                                                       warning("for symbol %s tentative (data) defintion from %s is "
+                                                                       "being replaced by code from %s", newAtom.name(), existingAtom->file()->path(),
+                                                                       newAtom.file()->path());
+                                               }
                                                break;
                                        case ld::Atom::definitionTentative:
                                                // new and existing are both tentative definitions, use largest
index c367d00615dfeebb035f895dd66839a652776db6..c4e151dd95483f66caec6ccc4c9574b8a5fff8be 100644 (file)
@@ -152,6 +152,7 @@ line_file (struct line_reader_data *lnd, uint64_t n)
   size_t filelen, dirlen;
   uint64_t dir;
   char * result;
+  const char * dirpath;
 
   /* I'm not sure if this is actually an error.  */
   if (n == 0
@@ -168,9 +169,14 @@ line_file (struct line_reader_data *lnd, uint64_t n)
   else if (dir > lnd->numdir)
     return NULL;
 
-  dirlen = strlen ((const char *) lnd->dirnames[dir - 1]);
+  dirpath = (const char *)lnd->dirnames[dir - 1];
+  dirlen = strlen (dirpath);
+  if ( dirpath[dirlen-1] == '/' )
+    --dirlen;
+  if ( (dirpath[dirlen-1] == '.') && (dirpath[dirlen-2] == '/') )
+    dirlen -= 2;
   result = malloc (dirlen + filelen + 2);
-  memcpy (result, lnd->dirnames[dir - 1], dirlen);
+  memcpy (result, dirpath, dirlen);
   result[dirlen] = '/';
   memcpy (result + dirlen + 1, lnd->filenames[n - 1], filelen);
   result[dirlen + 1 + filelen] = '\0';
index 7a7b4f28a3d2832be4c9f8dede7044b9a8fb4fc3..411dbbc94d9bd40b023b4a4cfe831a73b954fcca 100644 (file)
@@ -87,4 +87,223 @@ enum {
   DW_LNE_define_file
 };
 
+
+// dwarf unwind instructions
+enum {
+       DW_CFA_nop                 = 0x0,
+       DW_CFA_set_loc             = 0x1,
+       DW_CFA_advance_loc1        = 0x2,
+       DW_CFA_advance_loc2        = 0x3,
+       DW_CFA_advance_loc4        = 0x4,
+       DW_CFA_offset_extended     = 0x5,
+       DW_CFA_restore_extended    = 0x6,
+       DW_CFA_undefined           = 0x7,
+       DW_CFA_same_value          = 0x8,
+       DW_CFA_register            = 0x9,
+       DW_CFA_remember_state      = 0xA,
+       DW_CFA_restore_state       = 0xB,
+       DW_CFA_def_cfa             = 0xC,
+       DW_CFA_def_cfa_register    = 0xD,
+       DW_CFA_def_cfa_offset      = 0xE,
+       DW_CFA_def_cfa_expression  = 0xF,
+       DW_CFA_expression         = 0x10,
+       DW_CFA_offset_extended_sf = 0x11,
+       DW_CFA_def_cfa_sf         = 0x12,
+       DW_CFA_def_cfa_offset_sf  = 0x13,
+       DW_CFA_val_offset         = 0x14,
+       DW_CFA_val_offset_sf      = 0x15,
+       DW_CFA_val_expression     = 0x16,
+       DW_CFA_advance_loc        = 0x40, // high 2 bits are 0x1, lower 6 bits are delta
+       DW_CFA_offset             = 0x80, // high 2 bits are 0x2, lower 6 bits are register
+       DW_CFA_restore            = 0xC0, // high 2 bits are 0x3, lower 6 bits are register
+       
+       // GNU extensions
+    DW_CFA_GNU_window_save                             = 0x2D,
+    DW_CFA_GNU_args_size                               = 0x2E,
+    DW_CFA_GNU_negative_offset_extended = 0x2F
+};
+
+
+// FSF exception handling Pointer-Encoding constants 
+// Used in CFI augmentation by gcc compiler
+enum {
+       DW_EH_PE_ptr       = 0x00,
+       DW_EH_PE_uleb128   = 0x01,
+       DW_EH_PE_udata2    = 0x02,
+       DW_EH_PE_udata4    = 0x03,
+       DW_EH_PE_udata8    = 0x04,
+       DW_EH_PE_signed    = 0x08,
+       DW_EH_PE_sleb128   = 0x09,
+       DW_EH_PE_sdata2    = 0x0A,
+       DW_EH_PE_sdata4    = 0x0B,
+       DW_EH_PE_sdata8    = 0x0C,
+       DW_EH_PE_absptr    = 0x00,
+       DW_EH_PE_pcrel     = 0x10,
+       DW_EH_PE_textrel   = 0x20,
+       DW_EH_PE_datarel   = 0x30,
+       DW_EH_PE_funcrel   = 0x40,
+       DW_EH_PE_aligned   = 0x50,
+       DW_EH_PE_indirect  = 0x80,
+       DW_EH_PE_omit      = 0xFF
+};
+
+
+// DWARF  expressions
+enum {
+       DW_OP_addr               = 0x03, // constant address (size target specific)
+       DW_OP_deref              = 0x06,
+       DW_OP_const1u            = 0x08, // 1-byte constant
+       DW_OP_const1s            = 0x09, // 1-byte constant
+       DW_OP_const2u            = 0x0A, // 2-byte constant
+       DW_OP_const2s            = 0x0B, // 2-byte constant
+       DW_OP_const4u            = 0x0C, // 4-byte constant
+       DW_OP_const4s            = 0x0D, // 4-byte constant
+       DW_OP_const8u            = 0x0E, // 8-byte constant
+       DW_OP_const8s            = 0x0F, // 8-byte constant
+       DW_OP_constu             = 0x10, // ULEB128 constant
+       DW_OP_consts             = 0x11, // SLEB128 constant
+       DW_OP_dup                = 0x12,
+       DW_OP_drop               = 0x13,
+       DW_OP_over               = 0x14,
+       DW_OP_pick               = 0x15, // 1-byte stack index
+       DW_OP_swap               = 0x16,
+       DW_OP_rot                = 0x17,
+       DW_OP_xderef             = 0x18,
+       DW_OP_abs                = 0x19,
+       DW_OP_and                = 0x1A,
+       DW_OP_div                = 0x1B,
+       DW_OP_minus              = 0x1C,
+       DW_OP_mod                = 0x1D,
+       DW_OP_mul                = 0x1E,
+       DW_OP_neg                = 0x1F,
+       DW_OP_not                = 0x20,
+       DW_OP_or                 = 0x21,
+       DW_OP_plus               = 0x22,
+       DW_OP_plus_uconst        = 0x23, // ULEB128 addend
+       DW_OP_shl                = 0x24,
+       DW_OP_shr                = 0x25,
+       DW_OP_shra               = 0x26,
+       DW_OP_xor                = 0x27,
+       DW_OP_skip               = 0x2F, // signed 2-byte constant
+       DW_OP_bra                = 0x28, // signed 2-byte constant
+       DW_OP_eq                 = 0x29,
+       DW_OP_ge                 = 0x2A,
+       DW_OP_gt                 = 0x2B,
+       DW_OP_le                 = 0x2C,
+       DW_OP_lt                 = 0x2D,
+       DW_OP_ne                 = 0x2E,
+       DW_OP_lit0               = 0x30, // Literal 0
+       DW_OP_lit1               = 0x31, // Literal 1
+       DW_OP_lit2               = 0x32, // Literal 2
+       DW_OP_lit3               = 0x33, // Literal 3
+       DW_OP_lit4               = 0x34, // Literal 4
+       DW_OP_lit5               = 0x35, // Literal 5
+       DW_OP_lit6               = 0x36, // Literal 6
+       DW_OP_lit7               = 0x37, // Literal 7
+       DW_OP_lit8               = 0x38, // Literal 8
+       DW_OP_lit9               = 0x39, // Literal 9
+       DW_OP_lit10              = 0x3A, // Literal 10
+       DW_OP_lit11              = 0x3B, // Literal 11
+       DW_OP_lit12              = 0x3C, // Literal 12
+       DW_OP_lit13              = 0x3D, // Literal 13
+       DW_OP_lit14              = 0x3E, // Literal 14
+       DW_OP_lit15              = 0x3F, // Literal 15
+       DW_OP_lit16              = 0x40, // Literal 16
+       DW_OP_lit17              = 0x41, // Literal 17
+       DW_OP_lit18              = 0x42, // Literal 18
+       DW_OP_lit19              = 0x43, // Literal 19
+       DW_OP_lit20              = 0x44, // Literal 20
+       DW_OP_lit21              = 0x45, // Literal 21
+       DW_OP_lit22              = 0x46, // Literal 22
+       DW_OP_lit23              = 0x47, // Literal 23
+       DW_OP_lit24              = 0x48, // Literal 24
+       DW_OP_lit25              = 0x49, // Literal 25
+       DW_OP_lit26              = 0x4A, // Literal 26
+       DW_OP_lit27              = 0x4B, // Literal 27
+       DW_OP_lit28              = 0x4C, // Literal 28
+       DW_OP_lit29              = 0x4D, // Literal 29
+       DW_OP_lit30              = 0x4E, // Literal 30
+       DW_OP_lit31              = 0x4F, // Literal 31
+       DW_OP_reg0               = 0x50, // Contents of reg0
+       DW_OP_reg1               = 0x51, // Contents of reg1
+       DW_OP_reg2               = 0x52, // Contents of reg2
+       DW_OP_reg3               = 0x53, // Contents of reg3
+       DW_OP_reg4               = 0x54, // Contents of reg4
+       DW_OP_reg5               = 0x55, // Contents of reg5
+       DW_OP_reg6               = 0x56, // Contents of reg6
+       DW_OP_reg7               = 0x57, // Contents of reg7
+       DW_OP_reg8               = 0x58, // Contents of reg8
+       DW_OP_reg9               = 0x59, // Contents of reg9
+       DW_OP_reg10              = 0x5A, // Contents of reg10
+       DW_OP_reg11              = 0x5B, // Contents of reg11
+       DW_OP_reg12              = 0x5C, // Contents of reg12
+       DW_OP_reg13              = 0x5D, // Contents of reg13
+       DW_OP_reg14              = 0x5E, // Contents of reg14
+       DW_OP_reg15              = 0x5F, // Contents of reg15
+       DW_OP_reg16              = 0x60, // Contents of reg16
+       DW_OP_reg17              = 0x61, // Contents of reg17
+       DW_OP_reg18              = 0x62, // Contents of reg18
+       DW_OP_reg19              = 0x63, // Contents of reg19
+       DW_OP_reg20              = 0x64, // Contents of reg20
+       DW_OP_reg21              = 0x65, // Contents of reg21
+       DW_OP_reg22              = 0x66, // Contents of reg22
+       DW_OP_reg23              = 0x67, // Contents of reg23
+       DW_OP_reg24              = 0x68, // Contents of reg24
+       DW_OP_reg25              = 0x69, // Contents of reg25
+       DW_OP_reg26              = 0x6A, // Contents of reg26
+       DW_OP_reg27              = 0x6B, // Contents of reg27
+       DW_OP_reg28              = 0x6C, // Contents of reg28
+       DW_OP_reg29              = 0x6D, // Contents of reg29
+       DW_OP_reg30              = 0x6E, // Contents of reg30
+       DW_OP_reg31              = 0x6F, // Contents of reg31
+       DW_OP_breg0              = 0x70, // base register 0 + SLEB128 offset
+       DW_OP_breg1              = 0x71, // base register 1 + SLEB128 offset
+       DW_OP_breg2              = 0x72, // base register 2 + SLEB128 offset
+       DW_OP_breg3              = 0x73, // base register 3 + SLEB128 offset
+       DW_OP_breg4              = 0x74, // base register 4 + SLEB128 offset
+       DW_OP_breg5              = 0x75, // base register 5 + SLEB128 offset
+       DW_OP_breg6              = 0x76, // base register 6 + SLEB128 offset
+       DW_OP_breg7              = 0x77, // base register 7 + SLEB128 offset
+       DW_OP_breg8              = 0x78, // base register 8 + SLEB128 offset
+       DW_OP_breg9              = 0x79, // base register 9 + SLEB128 offset
+       DW_OP_breg10             = 0x7A, // base register 10 + SLEB128 offset
+       DW_OP_breg11             = 0x7B, // base register 11 + SLEB128 offset
+       DW_OP_breg12             = 0x7C, // base register 12 + SLEB128 offset
+       DW_OP_breg13             = 0x7D, // base register 13 + SLEB128 offset
+       DW_OP_breg14             = 0x7E, // base register 14 + SLEB128 offset
+       DW_OP_breg15             = 0x7F, // base register 15 + SLEB128 offset
+       DW_OP_breg16             = 0x80, // base register 16 + SLEB128 offset
+       DW_OP_breg17             = 0x81, // base register 17 + SLEB128 offset
+       DW_OP_breg18             = 0x82, // base register 18 + SLEB128 offset
+       DW_OP_breg19             = 0x83, // base register 19 + SLEB128 offset
+       DW_OP_breg20             = 0x84, // base register 20 + SLEB128 offset
+       DW_OP_breg21             = 0x85, // base register 21 + SLEB128 offset
+       DW_OP_breg22             = 0x86, // base register 22 + SLEB128 offset
+       DW_OP_breg23             = 0x87, // base register 23 + SLEB128 offset
+       DW_OP_breg24             = 0x88, // base register 24 + SLEB128 offset
+       DW_OP_breg25             = 0x89, // base register 25 + SLEB128 offset
+       DW_OP_breg26             = 0x8A, // base register 26 + SLEB128 offset
+       DW_OP_breg27             = 0x8B, // base register 27 + SLEB128 offset
+       DW_OP_breg28             = 0x8C, // base register 28 + SLEB128 offset
+       DW_OP_breg29             = 0x8D, // base register 29 + SLEB128 offset
+       DW_OP_breg30             = 0x8E, // base register 30 + SLEB128 offset
+       DW_OP_breg31             = 0x8F, // base register 31 + SLEB128 offset
+       DW_OP_regx               = 0x90, // ULEB128 register
+       DW_OP_fbreg              = 0x91, // SLEB128 offset
+       DW_OP_bregx              = 0x92, // ULEB128 register followed by SLEB128 offset
+       DW_OP_piece              = 0x93, // ULEB128 size of piece addressed
+       DW_OP_deref_size         = 0x94, // 1-byte size of data retrieved
+       DW_OP_xderef_size        = 0x95, // 1-byte size of data retrieved
+       DW_OP_nop                = 0x96,
+       DW_OP_push_object_addres = 0x97,
+       DW_OP_call2              = 0x98, // 2-byte offset of DIE
+       DW_OP_call4              = 0x99, // 4-byte offset of DIE
+       DW_OP_call_ref           = 0x9A, // 4- or 8-byte offset of DIE
+       DW_OP_lo_user            = 0xE0,
+       DW_OP_APPLE_uninit       = 0xF0,
+       DW_OP_hi_user            = 0xFF
+};
+
+
+
 #endif
index d9d66a679ab86b4e0ea3df0ec2c3e08b88a37cda..5b21c63c1d260a2d48f7c147fd6bd53bf77bce1f 100644 (file)
@@ -103,7 +103,7 @@ private:
        public:
                                                        FinalSection(const ld::Section& sect, uint32_t sectionsSeen, bool objFile);
                static int                                      sectionComparer(const void* l, const void* r);
-               static const ld::Section&       outputSection(const ld::Section& sect);
+               static const ld::Section&       outputSection(const ld::Section& sect, bool mergeZeroFill);
                static const ld::Section&       objectOutputSection(const ld::Section& sect, bool makeTentativeDefsReal);
        private:
                friend class InternalState;
@@ -119,6 +119,7 @@ private:
                static ld::Section              _s_TEXT_const;
                static ld::Section              _s_DATA_nl_symbol_ptr;
                static ld::Section              _s_DATA_common;
+               static ld::Section              _s_DATA_zerofill;
        };
        
        
@@ -141,6 +142,7 @@ ld::Section InternalState::FinalSection::_s_TEXT_text( "__TEXT", "__text",  ld::
 ld::Section    InternalState::FinalSection::_s_TEXT_const("__TEXT", "__const", ld::Section::typeUnclassified);
 ld::Section    InternalState::FinalSection::_s_DATA_nl_symbol_ptr("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
 ld::Section    InternalState::FinalSection::_s_DATA_common("__DATA", "__common", ld::Section::typeZeroFill);
+ld::Section    InternalState::FinalSection::_s_DATA_zerofill("__DATA", "__zerofill", ld::Section::typeZeroFill);
 std::vector<const char*> InternalState::FinalSection::_s_segmentsSeen;
 
 
@@ -168,7 +170,7 @@ InternalState::FinalSection::FinalSection(const ld::Section& sect, uint32_t sect
        //              this->segmentName(), this->sectionName(), _segmentOrder, _sectionOrder);
 }
 
-const ld::Section& InternalState::FinalSection::outputSection(const ld::Section& sect)
+const ld::Section& InternalState::FinalSection::outputSection(const ld::Section& sect, bool mergeZeroFill)
 {
        // merge sections in final linked image
        switch ( sect.type() ) {
@@ -188,6 +190,10 @@ const ld::Section& InternalState::FinalSection::outputSection(const ld::Section&
                                        return _s_TEXT_const;
                        }
                        break;
+               case ld::Section::typeZeroFill:
+                       if ( mergeZeroFill )
+                               return _s_DATA_zerofill;
+                       break;
                case ld::Section::typeCode:
                        if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
                                if ( strcmp(sect.sectionName(), "__textcoal_nt") == 0 )
@@ -207,7 +213,10 @@ const ld::Section& InternalState::FinalSection::outputSection(const ld::Section&
                        }
                        break;
                case ld::Section::typeTentativeDefs:
-                       return _s_DATA_common;
+                       if ( mergeZeroFill )
+                               return _s_DATA_zerofill;
+                       else
+                               return _s_DATA_common;
                        break;
                        // FIX ME: more 
                default:
@@ -436,7 +445,7 @@ ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
        switch ( atom.section().type() ) {
                case ld::Section::typeZeroFill:
                case ld::Section::typeTentativeDefs:
-                       if ( (_options.outputKind() == Options::kDyld) && (atom.symbolTableInclusion() == ld::Atom::symbolTableIn) 
+                       if ( (atom.symbolTableInclusion() == ld::Atom::symbolTableIn) 
                                        && (atom.size() <= 512) && (_options.orderedSymbolsCount() != 0) ) {
                                for(Options::OrderedSymbolsIterator it = _options.orderedSymbolsBegin(); it != _options.orderedSymbolsEnd(); ++it) {
                                        if ( (it->objectFileName == NULL) && (strcmp(it->symbolName, atom.name()) == 0) ) {
@@ -482,7 +491,7 @@ ld::Internal::FinalSection* InternalState::getFinalSection(const ld::Section& in
                case Options::kPreload:
                        {
                                // coalesce some sections
-                               const ld::Section& outSect = FinalSection::outputSection(inputSection);
+                               const ld::Section& outSect = FinalSection::outputSection(inputSection, _options.mergeZeroFill());
                                pos = _sectionInToFinalMap.find(&outSect);
                                if ( pos != _sectionInToFinalMap.end() ) {
                                        _sectionInToFinalMap[&inputSection] = pos->second;
index e5319bbdaec48e38544fdf35bcdcf8a6b0e4617c..96075a7398967a98c9447c8b47af804d0fa3b238 100644 (file)
@@ -83,8 +83,8 @@ private:
 //
 enum MacVersionMin { macVersionUnset=0, mac10_4=0x000A0400, mac10_5=0x000A0500, 
                                                mac10_6=0x000A0600, mac10_7=0x000A0700 };
-enum IPhoneVersionMin { iPhoneVersionUnset=0, iPhone2_0=0x00020000, iPhone3_1=0x00030100, 
-                                               iPhone4_2=0x00040200, iPhone4_3=0x00040300 };
+enum IOSVersionMin { iOSVersionUnset=0, iOS_2_0=0x00020000, iOS_3_1=0x00030100, 
+                                               iOS_4_2=0x00040200, iOS_4_3=0x00040300, iOS_5_0=0x00050000 };
  
 namespace relocatable {
        //
@@ -153,9 +153,8 @@ namespace dylib {
                                                                                                : ld::File(pth, modTime, ord), _dylibInstallPath(NULL),
                                                                                                _dylibTimeStamp(0), _dylibCurrentVersion(0), _dylibCompatibilityVersion(0),
                                                                                                _explicitlyLinked(false), _implicitlyLinked(false),
-                                                                                               _lazyLoadedDylib(false), _weakLinked(false), _reExported(false),
-                                                                                               _upward(false), _hasNonWeakImportedSymbols(false), 
-                                                                                               _hasWeakImportedSymbols(false), _dead(false) { }
+                                                                                               _lazyLoadedDylib(false), _forcedWeakLinked(false), _reExported(false),
+                                                                                               _upward(false), _dead(false) { }
                                const char*                                     installPath() const                     { return _dylibInstallPath; }
                                uint32_t                                        timestamp() const                       { return _dylibTimeStamp; }
                                uint32_t                                        currentVersion() const          { return _dylibCurrentVersion; }
@@ -167,15 +166,13 @@ namespace dylib {
                                // attributes of how dylib will be used when linked
                                void                                            setWillBeLazyLoadedDylb()               { _lazyLoadedDylib = true; }
                                bool                                            willBeLazyLoadedDylib() const   { return _lazyLoadedDylib; }
-                               void                                            setWillBeWeakLinked()                   { _weakLinked = true; }
-                               bool                                            willBeWeakLinked() const                { return _weakLinked ||
-                                                                                                                       (_hasWeakImportedSymbols && !_hasNonWeakImportedSymbols); }
+                               void                                            setForcedWeakLinked()                   { _forcedWeakLinked = true; }
+                               bool                                            forcedWeakLinked() const                { return _forcedWeakLinked; }
+                                                                                                                       
                                void                                            setWillBeReExported()                   { _reExported = true; }
                                bool                                            willBeReExported() const                { return _reExported; }
                                void                                            setWillBeUpwardDylib()                  { _upward = true; }
                                bool                                            willBeUpwardDylib() const               { return _upward; }
-                               void                                            setUsingNonWeakImportedSymbols(){ _hasNonWeakImportedSymbols = true; }
-                               void                                            setUsingWeakImportedSymbols()   { _hasWeakImportedSymbols = true; }
                                void                                            setWillBeRemoved(bool value)    { _dead = value; }
                                bool                                            willRemoved() const                             { return _dead; }
                                
@@ -187,6 +184,7 @@ namespace dylib {
                virtual bool                                            deadStrippable() const = 0;
                virtual bool                                            hasWeakDefinition(const char* name) const = 0;
                virtual bool                                            hasPublicInstallName() const = 0;
+               virtual bool                                            allSymbolsAreWeakImported() const = 0;
        protected:
                const char*                                                     _dylibInstallPath;
                uint32_t                                                        _dylibTimeStamp;
@@ -195,16 +193,30 @@ namespace dylib {
                bool                                                            _explicitlyLinked;
                bool                                                            _implicitlyLinked;
                bool                                                            _lazyLoadedDylib;
-               bool                                                            _weakLinked;
+               bool                                                            _forcedWeakLinked;
                bool                                                            _reExported;
                bool                                                            _upward;
-               bool                                                            _hasNonWeakImportedSymbols;
-               bool                                                            _hasWeakImportedSymbols;
                bool                                                            _dead;
        };
 } // namespace dylib
 
 
+namespace archive {
+       //
+       // ld::archive::File 
+       //
+       // Abstract base class for static libraries read by the linker processes.
+       //
+       class File : public ld::File
+       {
+       public:
+                                                                                       File(const char* pth, time_t modTime, uint32_t ord)
+                                                                                               : ld::File(pth, modTime, ord) { }
+               virtual                                                         ~File() {}
+               virtual bool                                            justInTimeDataOnlyforEachAtom(const char* name, AtomHandler&) const = 0;
+       };
+} // namespace archive 
+
 
 //
 // ld::Section
@@ -220,7 +232,7 @@ public:
                                typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers,
                                typeStubClose, typeLazyPointerClose, typeAbsoluteSymbols, 
                                typeTLVDefs, typeTLVZeroFill, typeTLVInitialValues, typeTLVInitializerPointers, typeTLVPointers,
-                               typeFirstSection, typeLastSection };
+                               typeFirstSection, typeLastSection, typeDebug };
 
 
                                        Section(const char* sgName, const char* sctName,
@@ -494,6 +506,8 @@ public:
        enum SymbolTableInclusion { symbolTableNotIn, symbolTableNotInFinalLinkedImages, symbolTableIn,
                                                                symbolTableInAndNeverStrip, symbolTableInAsAbsolute, 
                                                                symbolTableInWithRandomAutoStripLabel };
+       enum WeakImportState { weakImportUnset, weakImportTrue, weakImportFalse };
+       
        struct Alignment { 
                                        Alignment(int p2, int m=0) : powerOf2(p2), modulus(m) {}
                uint8_t         trailingZeros() const { return (modulus==0) ? powerOf2 : __builtin_ctz(modulus); }
@@ -522,7 +536,7 @@ public:
                                                                                                        _contentType(ct), _symbolTableInclusion(i),
                                                                                                        _scope(s), _mode(modeSectionOffset), 
                                                                                                        _overridesADylibsWeakDef(false), _coalescedAway(false),
-                                                                                                       _weakImport(false), _live(false), _machoSection(0)
+                                                                                                       _live(false), _machoSection(0), _weakImportState(weakImportUnset)
                                                                                                         {
                                                                                                        #ifndef NDEBUG
                                                                                                                switch ( _combine ) {
@@ -551,7 +565,8 @@ public:
        Alignment                                                               alignment() const                       { return Alignment(_alignmentPowerOf2, _alignmentModulus); }
        bool                                                                    overridesDylibsWeakDef() const  { return _overridesADylibsWeakDef; }
        bool                                                                    coalescedAway() const           { return _coalescedAway; }
-       bool                                                                    weakImported() const            { return _weakImport; }
+       bool                                                                    weakImported() const            { return _weakImportState == weakImportTrue; }
+       WeakImportState                                                 weakImportState() const         { return _weakImportState; }
        bool                                                                    autoHide() const                        { return _autoHide; }
        bool                                                                    live() const                            { return _live; }
        uint8_t                                                                 machoSection() const            { assert(_machoSection != 0); return _machoSection; }
@@ -562,7 +577,7 @@ public:
        void                                                                    setCombine(Combine c)           { _combine = c; }
        void                                                                    setOverridesDylibsWeakDef()     { _overridesADylibsWeakDef = true; }
        void                                                                    setCoalescedAway()                      { _coalescedAway = true; }
-       void                                                                    setWeakImported()                       { _weakImport = true; assert(_definition == definitionProxy); }
+       void                                                                    setWeakImportState(bool w)      { assert(_definition == definitionProxy); _weakImportState = ( w ? weakImportTrue : weakImportFalse); }
        void                                                                    setAutoHide()                           { _autoHide = true; }
        void                                                                    setLive()                                       { _live = true; }
        void                                                                    setLive(bool value)                     { _live = value; }
@@ -607,7 +622,7 @@ protected:
                                                                                                        _mode = a._mode;
                                                                                                        _overridesADylibsWeakDef = a._overridesADylibsWeakDef;
                                                                                                        _coalescedAway = a._coalescedAway;
-                                                                                                       _weakImport = a._weakImport;
+                                                                                                       _weakImportState = a._weakImportState;
                                                                                                }
 
        const Section *                                         _section;
@@ -626,9 +641,9 @@ protected:
        AddressMode                                                     _mode: 2;
        bool                                                            _overridesADylibsWeakDef : 1;
        bool                                                            _coalescedAway : 1;
-       bool                                                            _weakImport : 1;
        bool                                                            _live : 1;
        unsigned                                                        _machoSection : 8;
+       WeakImportState                                         _weakImportState : 2;
 };
 
 
index 8c866cd03ff9fefadef0bc8039d3617dc5526326..66f9432af5f203c01d4df8bd2575b02ee0384e08 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -31,6 +31,7 @@
 
 #include <vector>
 #include <set>
+#include <map>
 #include <algorithm>
 #include <ext/hash_map>
 
@@ -69,7 +70,7 @@ public:
 };
 
 template <typename A>
-class File : public ld::File
+class File : public ld::archive::File
 {
 public:
        static bool                                                                             validFile(const uint8_t* fileContent, uint64_t fileLength,
@@ -84,6 +85,9 @@ public:
        virtual bool                                                                            justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const;
        virtual uint32_t                                                                        subFileCount() const  { return _archiveFilelength/sizeof(ar_hdr); }
        
+       // overrides of ld::archive::File
+       virtual bool                                                                            justInTimeDataOnlyforEachAtom(const char* name, ld::File::AtomHandler& handler) const;
+
 private:
        static bool                                                                             validMachOFile(const uint8_t* fileContent, uint64_t fileLength, 
                                                                                                                                        const mach_o::relocatable::ParserOptions& opts);
@@ -91,7 +95,6 @@ private:
                                                                                                                                        const mach_o::relocatable::ParserOptions& opts);
        static cpu_type_t                                                               architecture();
 
-
        class Entry : ar_hdr
        {
        public:
@@ -116,8 +119,12 @@ private:
        typedef typename A::P                                                   P;
        typedef typename A::P::E                                                E;
 
+       struct MemberState { ld::relocatable::File* file; bool logged; bool loaded; };
+       
+       typedef std::map<const class Entry*, MemberState> MemberToStateMap;
+
        const struct ranlib*                                                    ranlibHashSearch(const char* name) const;
-       ld::relocatable::File*                                                  makeObjectFileForMember(const Entry* member) const;
+       MemberState&                                                                    makeObjectFileForMember(const Entry* member) const;
        bool                                                                                    memberHasObjCCategories(const Entry* member) const;
        void                                                                                    dumpTableOfContents();
        void                                                                                    buildHashTable();
@@ -127,12 +134,12 @@ private:
        const struct ranlib*                                                    _tableOfContents;
        uint32_t                                                                                _tableOfContentCount;
        const char*                                                                             _tableOfContentStrings;
-       mutable std::vector<ld::relocatable::File*>             _instantiatedFiles;
-       mutable std::set<const class Entry*>                    _instantiatedEntries;
+       mutable MemberToStateMap                                                _instantiatedEntries;
        NameToEntryMap                                                                  _hashTable;
        const bool                                                                              _forceLoadAll;
        const bool                                                                              _forceLoadObjC;
        const bool                                                                              _forceLoadThis;
+       const bool                                                                              _objc2ABI;
        const bool                                                                              _verboseLoad;
        const bool                                                                              _logAllFiles;
        const mach_o::relocatable::ParserOptions                _objOpts;
@@ -266,11 +273,11 @@ bool File<A>::validFile(const uint8_t* fileContent, uint64_t fileLength, const m
 template <typename A>
 File<A>::File(const uint8_t fileContent[], uint64_t fileLength, const char* pth, time_t modTime, 
                                        uint32_t ord, const ParserOptions& opts)
- : ld::File(strdup(pth), modTime, ord),
+ : ld::archive::File(strdup(pth), modTime, ord),
        _archiveFileContent(fileContent), _archiveFilelength(fileLength), 
        _tableOfContents(NULL), _tableOfContentCount(0), _tableOfContentStrings(NULL), 
        _forceLoadAll(opts.forceLoadAll), _forceLoadObjC(opts.forceLoadObjC), 
-       _forceLoadThis(opts.forceLoadThisArchive), _verboseLoad(opts.verboseLoad), 
+       _forceLoadThis(opts.forceLoadThisArchive), _objc2ABI(opts.objcABI2), _verboseLoad(opts.verboseLoad), 
        _logAllFiles(opts.logAllFiles), _objOpts(opts.objOpts)
 {
        if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
@@ -297,8 +304,14 @@ File<A>::File(const uint8_t fileContent[], uint64_t fileLength, const char* pth,
 template <>
 bool File<x86>::memberHasObjCCategories(const Entry* member) const
 {
-       // i386 uses ObjC1 ABI which has .objc_category* global symbols
-       return false;
+       if ( _objc2ABI ) {      
+               // i386 for iOS simulator uses ObjC2 which has no global symbol for categories
+               return mach_o::relocatable::hasObjC2Categories(member->content());
+       }
+       else {
+               // i386 uses ObjC1 ABI which has .objc_category* global symbols
+               return false;
+       }
 }
 
 template <>
@@ -318,8 +331,13 @@ bool File<A>::memberHasObjCCategories(const Entry* member) const
 
 
 template <typename A>
-ld::relocatable::File* File<A>::makeObjectFileForMember(const Entry* member) const
+typename File<A>::MemberState& File<A>::makeObjectFileForMember(const Entry* member) const
 {
+       // in case member was instantiated earlier but not needed yet
+       typename MemberToStateMap::iterator pos = _instantiatedEntries.find(member);
+       if ( pos != _instantiatedEntries.end() )
+               return pos->second;
+
        const char* memberName = member->name();
        char memberPath[strlen(this->path()) + strlen(memberName)+4];
        strcpy(memberPath, this->path());
@@ -340,14 +358,20 @@ ld::relocatable::File* File<A>::makeObjectFileForMember(const Entry* member) con
                ld::relocatable::File* result = mach_o::relocatable::parse(member->content(), member->contentSize(), 
                                                                                                                                        mPath, member->modificationTime(), 
                                                                                                                                        this->ordinal() + memberIndex, _objOpts);
-               if ( result != NULL )
-                       return result;
+               if ( result != NULL ) {
+                       MemberState state = {result, false, false};
+                       _instantiatedEntries[member] = state;
+                       return _instantiatedEntries[member];
+               }
                // see if member is llvm bitcode file
                result = lto::parse(member->content(), member->contentSize(), 
                                                                mPath, member->modificationTime(), this->ordinal() + memberIndex, 
                                                                _objOpts.architecture, _objOpts.subType, _logAllFiles);
-               if ( result != NULL )
-                       return result;
+               if ( result != NULL ) {
+                       MemberState state = {result, false, false};
+                       _instantiatedEntries[member] = state;
+                       return _instantiatedEntries[member];
+               }
                        
                throwf("archive member '%s' with length %d is not mach-o or llvm bitcode", memberName, member->contentSize());
        }
@@ -369,14 +393,16 @@ bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
                        const char* memberName = p->name();
                        if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) )
                                continue;
+                       MemberState& state = this->makeObjectFileForMember(p);
                        if ( _verboseLoad ) {
                                if ( _forceLoadThis )
                                        printf("-force_load forced load of %s(%s)\n", this->path(), memberName);
                                else
                                        printf("-all_load forced load of %s(%s)\n", this->path(), memberName);
+                               state.logged = true;
                        }
-                       ld::relocatable::File* file = this->makeObjectFileForMember(p);
-                       didSome |= file->forEachAtom(handler);
+                       didSome |= state.file->forEachAtom(handler);
+                       state.loaded = true;
                }
        }
        else if ( _forceLoadObjC ) {
@@ -384,18 +410,18 @@ bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
                for(typename NameToEntryMap::const_iterator it = _hashTable.begin(); it != _hashTable.end(); ++it) {
                        if ( (strncmp(it->first, ".objc_c", 7) == 0) || (strncmp(it->first, "_OBJC_CLASS_$_", 14) == 0) ) {
                                const Entry* member = (Entry*)&_archiveFileContent[E::get32(it->second->ran_off)];
-                               if ( _instantiatedEntries.count(member) == 0 ) {
-                                       if ( _verboseLoad )
-                                               printf("-ObjC forced load of %s(%s)\n", this->path(), member->name());
-                                       // only return these atoms once
-                                       _instantiatedEntries.insert(member);
-                                       ld::relocatable::File* file = this->makeObjectFileForMember(member);
-                                       didSome |= file->forEachAtom(handler);
-                                       _instantiatedFiles.push_back(file);
+                               MemberState& state = this->makeObjectFileForMember(member);
+                               if ( _verboseLoad && !state.logged ) {
+                                       printf("-ObjC forced load of %s(%s)\n", this->path(), member->name());
+                                       state.logged = true;
+                               }
+                               if ( ! state.loaded ) {
+                                       didSome |= state.file->forEachAtom(handler);
+                                       state.loaded = true;
                                }
                        }
                }
-               // ObjC2 has no symbols in .o files with categories, but not classes, look deeper for those
+               // ObjC2 has no symbols in .o files with categories but not classes, look deeper for those
                const Entry* const start = (Entry*)&_archiveFileContent[8];
                const Entry* const end = (Entry*)&_archiveFileContent[_archiveFilelength];
                for (const Entry* member=start; member < end; member = member->next()) {
@@ -403,13 +429,15 @@ bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
                        if ( _instantiatedEntries.count(member) == 0 ) {
                                //fprintf(stderr, "checking member %s\n", member->name());
                                if ( this->memberHasObjCCategories(member) ) {
-                                       if ( _verboseLoad )
+                                       MemberState& state = this->makeObjectFileForMember(member);
+                                       if ( _verboseLoad && !state.logged ) {
                                                printf("-ObjC forced load of %s(%s)\n", this->path(), member->name());
-                                       // only return these atoms once
-                                       _instantiatedEntries.insert(member);
-                                       ld::relocatable::File* file = this->makeObjectFileForMember(member);
-                                       didSome |= file->forEachAtom(handler);
-                                       _instantiatedFiles.push_back(file);
+                                               state.logged = true;
+                                       }
+                                       if ( ! state.loaded ) {
+                                               didSome |= state.file->forEachAtom(handler);
+                                               state.loaded = true;
+                                       }
                                }
                        }
                }
@@ -428,14 +456,64 @@ bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& han
        const struct ranlib* result = ranlibHashSearch(name);
        if ( result != NULL ) {
                const Entry* member = (Entry*)&_archiveFileContent[E::get32(result->ran_off)];
+               MemberState& state = this->makeObjectFileForMember(member);
                // only call handler for each member once
-               if ( _instantiatedEntries.count(member) == 0 ) {
-                       _instantiatedEntries.insert(member);
-                       if ( _verboseLoad ) 
+               if ( ! state.loaded && !state.logged ) {
+                       if ( _verboseLoad ) {
                                printf("%s forced load of %s(%s)\n", name, this->path(), member->name());
-                       ld::relocatable::File* file = this->makeObjectFileForMember(member);
-                       _instantiatedFiles.push_back(file);
-                       return file->forEachAtom(handler);
+                               state.logged = true;
+                       }
+                       state.loaded = true;
+                       return state.file->forEachAtom(handler);
+               }
+       }
+       //fprintf(stderr, "%s NOT found in archive %s\n", name, this->path());
+       return false;
+}
+
+class CheckIsDataSymbolHandler : public ld::File::AtomHandler
+{
+public:
+                                       CheckIsDataSymbolHandler(const char* n) : _name(n), _isData(false) {}
+       virtual void    doAtom(const class ld::Atom& atom) {
+                                               if ( strcmp(atom.name(), _name) == 0 ) {
+                                                       if ( atom.section().type() != ld::Section::typeCode )
+                                                               _isData = true;
+                                               }
+                                       }
+       virtual void    doFile(const class ld::File&) {}
+       bool                    symbolIsDataDefinition() { return _isData; }
+
+private:
+       const char*             _name;
+       bool                    _isData;
+
+};
+
+template <typename A>
+bool File<A>::justInTimeDataOnlyforEachAtom(const char* name, ld::File::AtomHandler& handler) const
+{
+       // in force load case, all members already loaded
+       if ( _forceLoadAll || _forceLoadThis ) 
+               return false;
+       
+       // do a hash search of table of contents looking for requested symbol
+       const struct ranlib* result = ranlibHashSearch(name);
+       if ( result != NULL ) {
+               const Entry* member = (Entry*)&_archiveFileContent[E::get32(result->ran_off)];
+               MemberState& state = this->makeObjectFileForMember(member);
+               // only call handler for each member once
+               if ( ! state.loaded ) {
+                       CheckIsDataSymbolHandler checker(name);
+                       state.file->forEachAtom(checker);
+                       if ( checker.symbolIsDataDefinition() ) {
+                               if ( _verboseLoad && !state.logged ) {
+                                       printf("%s forced load of %s(%s)\n", name, this->path(), member->name());
+                                       state.logged = true;
+                               }
+                               state.loaded = true;
+                               return state.file->forEachAtom(handler);
+                       }
                }
        }
        //fprintf(stderr, "%s NOT found in archive %s\n", name, this->path());
@@ -487,7 +565,7 @@ void File<A>::dumpTableOfContents()
 //
 // main function used by linker to instantiate archive files
 //
-ld::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
+ld::archive::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
                                const char* path, time_t modTime, uint32_t ordinal, const ParserOptions& opts)
 {
        switch ( opts.objOpts.architecture ) {
index 4dcbc8bb53910119479980c70ad15e64ecfc17c3..31bab29c0107bad345f06d8e4c7c9f5f1d4c1592 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -35,11 +35,12 @@ struct ParserOptions {
        bool                                                            forceLoadThisArchive;
        bool                                                            forceLoadAll;
        bool                                                            forceLoadObjC;
+       bool                                                            objcABI2;
        bool                                                            verboseLoad;
        bool                                                            logAllFiles;
 };
 
-extern ld::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
+extern ld::archive::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
                                                const char* path, time_t modTime, uint32_t ordinal, const ParserOptions& opts);
 
 } // namespace archive
diff --git a/src/ld/parsers/libunwind/AddressSpace.hpp b/src/ld/parsers/libunwind/AddressSpace.hpp
new file mode 100644 (file)
index 0000000..bebd3e6
--- /dev/null
@@ -0,0 +1,439 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 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@
+ */
+//
+//     C++ interface to lower levels of libuwind 
+//
+
+#ifndef __ADDRESSSPACE_HPP__
+#define __ADDRESSSPACE_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <mach-o/loader.h>
+#include <mach-o/getsect.h>
+#include <mach-o/dyld_priv.h>
+#include <mach/i386/thread_status.h>
+#include <Availability.h>
+
+#include "FileAbstraction.hpp"
+#include "libunwind.h"
+#include "InternalMacros.h"
+#include "dwarf2.h"
+
+
+#if 0
+#if __i386__ || __x86_64__ 
+// In 10.6 and later i386 and x86_64 don't have a __dyld section
+// We need one to access private _dyld_func_lookup function.
+
+struct __DATA__dyld { long lazy; int (*lookup)(const char*, void**); };
+
+static volatile struct __DATA__dyld  myDyldSection __attribute__ ((section ("__DATA,__dyld"))) = { 0, NULL };
+
+
+static int my_dyld_func_lookup(const char* dyld_func_name, void **address)
+{
+       return (*myDyldSection.lookup)(dyld_func_name, address);
+}
+#else
+       #define my_dyld_func_lookup _dyld_func_lookup
+#endif
+
+
+bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
+{
+    static void* (*p)(void*, dyld_unwind_sections*) = NULL;
+
+       if(p == NULL)
+           my_dyld_func_lookup("__dyld_find_unwind_sections", (void**)&p);
+       return p(addr, info);
+}
+#endif // 0
+
+
+
+namespace libunwind {
+
+///
+/// LocalAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread
+/// in the same process.  It compiles away and making local unwinds very fast.
+///
+class LocalAddressSpace
+{
+public:
+       
+       #if __LP64__
+               typedef uint64_t        pint_t;
+               typedef  int64_t        sint_t;
+       #else
+               typedef uint32_t        pint_t;
+               typedef  int32_t        sint_t;
+       #endif
+               uint8_t                 get8(pint_t addr)       { return *((uint8_t*)addr); }
+               uint16_t                get16(pint_t addr)      { return *((uint16_t*)addr); }
+               uint32_t                get32(pint_t addr)      { return *((uint32_t*)addr); }
+               uint64_t                get64(pint_t addr)      { return *((uint64_t*)addr); }
+               double                  getDouble(pint_t addr)  { return *((double*)addr); }
+               v128                    getVector(pint_t addr)  { return *((v128*)addr); }
+               uintptr_t               getP(pint_t addr);
+       static uint64_t         getULEB128(pint_t& addr, pint_t end);
+       static int64_t          getSLEB128(pint_t& addr, pint_t end);
+       
+               pint_t                  getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
+               bool                    findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset);
+               bool                    findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart);
+       
+};
+
+LocalAddressSpace sThisAddress;
+
+inline uintptr_t LocalAddressSpace::getP(pint_t addr)
+{
+#if __LP64__
+       return get64(addr);
+#else
+       return get32(addr);
+#endif
+}
+
+/* Read a ULEB128 into a 64-bit word.   */
+inline uint64_t
+LocalAddressSpace::getULEB128(pint_t& addr, pint_t end)
+{
+       const uint8_t* p = (uint8_t*)addr;
+       const uint8_t* pend = (uint8_t*)end;
+       uint64_t result = 0;
+       int bit = 0;
+       do  {
+               uint64_t b;
+
+               if ( p == pend )
+                       ABORT("truncated uleb128 expression");
+
+               b = *p & 0x7f;
+
+               if (bit >= 64 || b << bit >> bit != b) {
+                       ABORT("malformed uleb128 expression");
+               }
+               else {
+                       result |= b << bit;
+                       bit += 7;
+               }
+       } while ( *p++ >= 0x80 );
+       addr = (pint_t)p;
+       return result;
+}
+
+/* Read a SLEB128 into a 64-bit word.  */
+inline int64_t
+LocalAddressSpace::getSLEB128(pint_t& addr, pint_t end)
+{
+       const uint8_t* p = (uint8_t*)addr;
+       int64_t result = 0;
+       int bit = 0;
+       uint8_t byte;
+       do {
+               byte = *p++;
+               result |= ((byte & 0x7f) << bit);
+               bit += 7;
+       } while (byte & 0x80);
+       // sign extend negative numbers
+       if ( (byte & 0x40) != 0 )
+               result |= (-1LL) << bit;
+       addr = (pint_t)p;
+       return result;
+}
+
+LocalAddressSpace::pint_t
+LocalAddressSpace::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
+{
+       pint_t startAddr = addr;
+       const uint8_t* p = (uint8_t*)addr;
+       pint_t result;
+       
+       // first get value
+       switch (encoding & 0x0F) {
+               case DW_EH_PE_ptr:
+                       result = getP(addr);
+                       p += sizeof(pint_t);
+                       addr = (pint_t)p;
+                       break;
+               case DW_EH_PE_uleb128:
+                       result = getULEB128(addr, end);
+                       break;
+               case DW_EH_PE_udata2:
+                       result = get16(addr);
+                       p += 2;
+                       addr = (pint_t)p;
+                       break;
+               case DW_EH_PE_udata4:
+                       result = get32(addr);
+                       p += 4;
+                       addr = (pint_t)p;
+                       break;
+               case DW_EH_PE_udata8:
+                       result = get64(addr);
+                       p += 8;
+                       addr = (pint_t)p;
+                       break;
+               case DW_EH_PE_sleb128:
+                       result = getSLEB128(addr, end);
+                       break;
+               case DW_EH_PE_sdata2:
+                       result = (int16_t)get16(addr);
+                       p += 2;
+                       addr = (pint_t)p;
+                       break;
+               case DW_EH_PE_sdata4:
+                       result = (int32_t)get32(addr);
+                       p += 4;
+                       addr = (pint_t)p;
+                       break;
+               case DW_EH_PE_sdata8:
+                       result = get64(addr);
+                       p += 8;
+                       addr = (pint_t)p;
+                       break;
+               default:
+                       ABORT("unknown pointer encoding");
+       }
+       
+       // then add relative offset
+       switch ( encoding & 0x70 ) {
+               case DW_EH_PE_absptr:
+                       // do nothing
+                       break;
+               case DW_EH_PE_pcrel:
+                       result += startAddr;
+                       break;
+               case DW_EH_PE_textrel:
+                       ABORT("DW_EH_PE_textrel pointer encoding not supported");
+                       break;
+               case DW_EH_PE_datarel:
+                       ABORT("DW_EH_PE_datarel pointer encoding not supported");
+                       break;
+               case DW_EH_PE_funcrel:
+                       ABORT("DW_EH_PE_funcrel pointer encoding not supported");
+                       break;
+               case DW_EH_PE_aligned:
+                       ABORT("DW_EH_PE_aligned pointer encoding not supported");
+                       break;
+               default:
+                       ABORT("unknown pointer encoding");
+                       break;
+       }
+       
+       if ( encoding & DW_EH_PE_indirect )
+               result = getP(result);
+       
+       return result;
+}
+
+
+inline bool LocalAddressSpace::findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart)
+{
+       dyld_unwind_sections info;
+       if ( _dyld_find_unwind_sections((void*)addr, &info) ) {
+               mh                              = (pint_t)info.mh;
+               dwarfStart              = (pint_t)info.dwarf_section;
+               dwarfLen                = (pint_t)info.dwarf_section_length;
+               compactStart    = (pint_t)info.compact_unwind_section;
+               return true;
+       }
+       return false;
+}
+
+
+inline bool    LocalAddressSpace::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
+{
+       dl_info dyldInfo;
+       if ( dladdr((void*)addr, &dyldInfo) ) {
+               if ( dyldInfo.dli_sname != NULL ) {
+                       strlcpy(buf, dyldInfo.dli_sname, bufLen);
+                       *offset = (addr - (pint_t)dyldInfo.dli_saddr);
+                       return true;
+               }
+       }
+       return false;
+}
+
+
+
+#if UNW_REMOTE
+
+///
+/// OtherAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread
+/// in the another process.  The other process can be a different endianness and a different
+/// pointer size and is handled by the P template parameter.  
+///
+template <typename P>
+class OtherAddressSpace
+{
+public:
+                                               OtherAddressSpace(task_t task) : fTask(task) {}
+
+               typedef typename P::uint_t      pint_t;
+
+               uint8_t                 get8(pint_t addr);
+               uint16_t                get16(pint_t addr);
+               uint32_t                get32(pint_t addr);
+               uint64_t                get64(pint_t addr);
+               pint_t                  getP(pint_t addr);
+               uint64_t                getULEB128(pint_t& addr, pint_t end);
+               int64_t                 getSLEB128(pint_t& addr, pint_t end);
+               pint_t                  getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
+               bool                    findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset);
+               bool                    findUnwindSections(pint_t addr, unwind_sections& info);
+private:
+               void*                   localCopy(pint_t addr);
+
+
+               task_t                  fTask;
+};
+
+
+template <typename P>
+uint8_t OtherAddressSpace<P>::get8(pint_t addr)
+{
+       return *((uint8_t*)localCopy(addr));
+}
+
+template <typename P>
+uint16_t OtherAddressSpace<P>::get16(pint_t addr)
+{
+       return P::E::get16(*(uint16_t*)localCopy(addr));
+}
+
+template <typename P>
+uint32_t OtherAddressSpace<P>::get32(pint_t addr)
+{
+       return P::E::get32(*(uint32_t*)localCopy(addr));
+}
+
+template <typename P>
+uint64_t OtherAddressSpace<P>::get64(pint_t addr)
+{
+       return P::E::get64(*(uint64_t*)localCopy(addr));
+}
+
+template <typename P>
+typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr)
+{
+       return P::getP(*(uint64_t*)localCopy(addr));
+}
+
+template <typename P>
+uint64_t OtherAddressSpace<P>::getULEB128(pint_t& addr, pint_t end)
+{
+       uintptr_t size = (end - addr);
+       LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t)localCopy(addr);
+       LocalAddressSpace::pint_t sladdr = laddr;
+       uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr+size);
+       addr += (laddr-sladdr);
+       return result;
+}
+
+template <typename P>
+int64_t OtherAddressSpace<P>::getSLEB128(pint_t& addr, pint_t end)
+{
+       uintptr_t size = (end - addr);
+       LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t)localCopy(addr);
+       LocalAddressSpace::pint_t sladdr = laddr;
+       uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr+size);
+       addr += (laddr-sladdr);
+       return result;
+}
+
+template <typename P>
+void* OtherAddressSpace<P>::localCopy(pint_t addr)
+{
+       // FIX ME
+}
+
+template <typename P>
+bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
+{
+       // FIX ME
+}
+
+
+
+///
+/// unw_addr_space is the base class that abstract unw_addr_space_t type in libunwind.h points to.  
+///
+struct unw_addr_space
+{
+       cpu_type_t                              cpuType;
+       task_t                                  taskPort;
+};
+
+
+///
+/// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points to when examining
+/// a 32-bit intel process.
+///
+struct unw_addr_space_i386 : public unw_addr_space
+{
+                                                                                                       unw_addr_space_i386(task_t task) : oas(task) {}
+       OtherAddressSpace<Pointer32<LittleEndian> >             oas;
+};
+
+
+///
+/// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t points to when examining
+/// a 64-bit intel process.
+///
+struct unw_addr_space_x86_64 : public unw_addr_space
+{
+                                                                                                       unw_addr_space_x86_64(task_t task) : oas(task) {}
+       OtherAddressSpace<Pointer64<LittleEndian> >             oas;
+};
+
+
+///
+/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points to when examining
+/// a 32-bit PowerPC process.
+///
+struct unw_addr_space_ppc : public unw_addr_space
+{
+                                                                                                       unw_addr_space_ppc(task_t task) : oas(task) {}
+       OtherAddressSpace<Pointer32<BigEndian> >                oas;
+};
+
+
+#endif // UNW_REMOTE
+
+
+} // namespace libunwind 
+
+
+
+#endif // __ADDRESSSPACE_HPP__
+
+
+
+
diff --git a/src/ld/parsers/libunwind/DwarfInstructions.hpp b/src/ld/parsers/libunwind/DwarfInstructions.hpp
new file mode 100644 (file)
index 0000000..b04582d
--- /dev/null
@@ -0,0 +1,1726 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 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@
+ */
+//
+// processor specific parsing of dwarf unwind instructions
+//
+
+#ifndef __DWARF_INSTRUCTIONS_HPP__
+#define __DWARF_INSTRUCTIONS_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <algorithm>
+#include <vector>
+
+#include <libunwind.h>
+#include <mach-o/compact_unwind_encoding.h>
+
+#include "dwarf2.h"
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+#include "DwarfParser.hpp"
+#include "InternalMacros.h"
+//#include "CompactUnwinder.hpp"
+
+#define EXTRACT_BITS(value, mask) \
+       ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
+
+#define CFI_INVALID_ADDRESS ((pint_t)(-1))
+
+namespace libunwind {
+
+///
+/// Used by linker when parsing __eh_frame section
+///  
+template <typename A>
+struct CFI_Reference {
+       typedef typename A::pint_t              pint_t; 
+       uint8_t         encodingOfTargetAddress;
+       uint32_t        offsetInCFI;
+       pint_t          targetAddress;
+};
+template <typename A>
+struct CFI_Atom_Info {
+       typedef typename A::pint_t              pint_t; 
+       pint_t                  address;
+       uint32_t                size;
+       bool                    isCIE;
+       union {
+               struct {
+                       CFI_Reference<A>        function;
+                       CFI_Reference<A>        cie;
+                       CFI_Reference<A>        lsda;
+                       uint32_t                compactUnwindInfo;
+               }                       fdeInfo;
+               struct {
+                       CFI_Reference<A>        personality;
+               }                       cieInfo;
+       } u;
+};
+
+typedef void (*WarnFunc)(void* ref, uint64_t funcAddr, const char* msg);  
+
+///
+/// DwarfInstructions maps abtract dwarf unwind instructions to a particular architecture
+///  
+template <typename A, typename R>
+class DwarfInstructions
+{
+public:
+       typedef typename A::pint_t              pint_t; 
+       typedef typename A::sint_t              sint_t; 
+
+       static const char* parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, 
+                                               CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn);
+
+
+       static compact_unwind_encoding_t createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart, 
+                                                                                                                               pint_t* lsda, pint_t* personality,
+                                                                                                                               char warningBuffer[1024]);
+
+       static int stepWithDwarf(A& addressSpace, pint_t pc, pint_t fdeStart, R& registers);
+                                                                               
+private:
+
+       enum {
+               DW_X86_64_RET_ADDR = 16
+       };
+
+       enum {
+               DW_X86_RET_ADDR = 8
+       };
+
+       static pint_t evaluateExpression(pint_t expression, A& addressSpace, const R& registers, pint_t initialStackValue);
+       static pint_t getSavedRegister(A& addressSpace, const R& registers, pint_t cfa, 
+                                                                               const typename CFI_Parser<A>::RegisterLocation& savedReg);
+       static double getSavedFloatRegister(A& addressSpace, const R& registers, pint_t cfa, 
+                                                                               const typename CFI_Parser<A>::RegisterLocation& savedReg);
+       static v128 getSavedVectorRegister(A& addressSpace, const R& registers, pint_t cfa, 
+                                                                               const typename CFI_Parser<A>::RegisterLocation& savedReg);
+                                                                               
+       // x86 specific variants
+       static int    lastRestoreReg(const Registers_x86&);
+       static bool   isReturnAddressRegister(int regNum, const Registers_x86&);
+       static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_x86&);
+
+       static uint32_t getEBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure);
+       static compact_unwind_encoding_t encodeToUseDwarf(const Registers_x86&);
+       static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+                                                                                               const Registers_x86&, const typename CFI_Parser<A>::PrologInfo& prolog,
+                                                                                               char warningBuffer[1024]);
+
+       // x86_64 specific variants
+       static int    lastRestoreReg(const Registers_x86_64&);
+       static bool   isReturnAddressRegister(int regNum, const Registers_x86_64&);
+       static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_x86_64&);
+
+       static uint32_t getRBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure);
+       static compact_unwind_encoding_t encodeToUseDwarf(const Registers_x86_64&);
+       static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+                                                                                               const Registers_x86_64&, const typename CFI_Parser<A>::PrologInfo& prolog,
+                                                                                               char warningBuffer[1024]);
+       
+       // ppc specific variants
+       static int    lastRestoreReg(const Registers_ppc&);
+       static bool   isReturnAddressRegister(int regNum, const Registers_ppc&);
+       static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_ppc&);
+       static compact_unwind_encoding_t encodeToUseDwarf(const Registers_ppc&);
+       static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+                                                                                               const Registers_ppc&, const typename CFI_Parser<A>::PrologInfo& prolog,
+                                                                                               char warningBuffer[1024]);
+};
+
+
+                                                                                       
+
+template <typename A, typename R>
+const char* DwarfInstructions<A,R>::parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, 
+                                                                                               CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn)
+{
+       typename CFI_Parser<A>::CIE_Info cieInfo;
+       CFI_Atom_Info<A>* entry = infos;
+       CFI_Atom_Info<A>* end = &infos[infosCount];
+       const pint_t ehSectionEnd = ehSectionStart + sectionLength;
+       for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
+               pint_t currentCFI = p;
+               uint64_t cfiLength = addressSpace.get32(p);
+               p += 4;
+               if ( cfiLength == 0xffffffff ) {
+                       // 0xffffffff means length is really next 8 bytes
+                       cfiLength = addressSpace.get64(p);
+                       p += 8;
+               }
+               if ( cfiLength == 0 ) 
+                       return NULL;    // end marker
+               if ( entry >= end )
+                       return "too little space allocated for parseCFIs";
+               pint_t nextCFI = p + cfiLength;
+               uint32_t id = addressSpace.get32(p);
+               if ( id == 0 ) {
+                       // is CIE
+                       const char* err = CFI_Parser<A>::parseCIE(addressSpace, currentCFI, &cieInfo);
+                       if ( err != NULL ) 
+                               return err;
+                       entry->address = currentCFI;
+                       entry->size = nextCFI - currentCFI;
+                       entry->isCIE = true;
+                       entry->u.cieInfo.personality.targetAddress = cieInfo.personality;
+                       entry->u.cieInfo.personality.offsetInCFI = cieInfo.personalityOffsetInCIE;
+                       entry->u.cieInfo.personality.encodingOfTargetAddress = cieInfo.personalityEncoding;
+                       ++entry;
+               }
+               else {
+                       // is FDE
+                       entry->address = currentCFI;
+                       entry->size = nextCFI - currentCFI;
+                       entry->isCIE = false;
+                       entry->u.fdeInfo.function.targetAddress = CFI_INVALID_ADDRESS;
+                       entry->u.fdeInfo.cie.targetAddress = CFI_INVALID_ADDRESS;
+                       entry->u.fdeInfo.lsda.targetAddress = CFI_INVALID_ADDRESS;
+                       uint32_t ciePointer = addressSpace.get32(p);
+                       pint_t cieStart = p-ciePointer;
+                       // validate pointer to CIE is within section
+                       if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) )
+                               return "FDE points to CIE outside __eh_frame section";
+                       // optimize usual case where cie is same for all FDEs
+                       if ( cieStart != cieInfo.cieStart ) {
+                               const char* err = CFI_Parser<A>::parseCIE(addressSpace, cieStart, &cieInfo);
+                               if ( err != NULL ) 
+                                       return err;
+                       }
+                       entry->u.fdeInfo.cie.targetAddress = cieStart;
+                       entry->u.fdeInfo.cie.offsetInCFI = p-currentCFI;
+                       entry->u.fdeInfo.cie.encodingOfTargetAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
+                       p += 4;
+                       // parse pc begin and range
+                       pint_t offsetOfFunctionAddress = p-currentCFI;
+                       pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
+                       pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
+                       //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+                       // test if pc is within the function this FDE covers
+                       entry->u.fdeInfo.function.targetAddress = pcStart;
+                       entry->u.fdeInfo.function.offsetInCFI = offsetOfFunctionAddress;
+                       entry->u.fdeInfo.function.encodingOfTargetAddress = cieInfo.pointerEncoding;
+                       // check for augmentation length
+                       if ( cieInfo.fdesHaveAugmentationData ) {
+                               uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+                               pint_t endOfAug = p + augLen;
+                               if ( cieInfo.lsdaEncoding != 0 ) {
+                                       // peek at value (without indirection).  Zero means no lsda
+                                       pint_t lsdaStart = p;
+                                       if ( addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding & 0x0F) != 0 ) {
+                                               // reset pointer and re-parse lsda address
+                                               p = lsdaStart;
+                                               pint_t offsetOfLSDAAddress = p-currentCFI;
+                                               entry->u.fdeInfo.lsda.targetAddress = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding);
+                                               entry->u.fdeInfo.lsda.offsetInCFI = offsetOfLSDAAddress;
+                                               entry->u.fdeInfo.lsda.encodingOfTargetAddress = cieInfo.lsdaEncoding;
+                                       }
+                               }
+                               p = endOfAug;
+                       }
+                       // compute compact unwind encoding
+                       typename CFI_Parser<A>::FDE_Info fdeInfo;
+                       fdeInfo.fdeStart = currentCFI;
+                       fdeInfo.fdeLength = nextCFI - currentCFI;
+                       fdeInfo.fdeInstructions = p;
+                       fdeInfo.pcStart = pcStart;
+                       fdeInfo.pcEnd = pcStart +  pcRange;
+                       fdeInfo.lsda = entry->u.fdeInfo.lsda.targetAddress;
+                       typename CFI_Parser<A>::PrologInfo prolog;
+                       R dummy; // for proper selection of architecture specific functions
+                       if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) {
+                               char warningBuffer[1024];
+                               entry->u.fdeInfo.compactUnwindInfo = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer);
+                               if ( fdeInfo.lsda != CFI_INVALID_ADDRESS ) 
+                                       entry->u.fdeInfo.compactUnwindInfo |= UNWIND_HAS_LSDA;
+                               if ( warningBuffer[0] != '\0' )
+                                       warn(ref, fdeInfo.pcStart, warningBuffer);
+                       }
+                       else {
+                               warn(ref, CFI_INVALID_ADDRESS, "dwarf unwind instructions could not be parsed");
+                               entry->u.fdeInfo.compactUnwindInfo = encodeToUseDwarf(dummy);
+                       }
+                       ++entry;
+               }
+               p = nextCFI;
+       }
+       if ( entry != end )
+               return "wrong entry count for parseCFIs";
+       return NULL; // success
+}
+
+
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart, 
+                                                                                                                                               pint_t* lsda, pint_t* personality,
+                                                                                                                                               char warningBuffer[1024])
+{
+       typename CFI_Parser<A>::FDE_Info fdeInfo;
+       typename CFI_Parser<A>::CIE_Info cieInfo;
+       R dummy; // for proper selection of architecture specific functions
+       if ( CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo) == NULL ) {
+               typename CFI_Parser<A>::PrologInfo prolog;
+               if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) {
+                       *lsda = fdeInfo.lsda;
+                       *personality = cieInfo.personality;
+                       compact_unwind_encoding_t encoding;
+                       encoding = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer);
+                       if ( fdeInfo.lsda != 0 ) 
+                               encoding |= UNWIND_HAS_LSDA;
+                       return encoding;
+               }
+               else {
+                       strcpy(warningBuffer, "dwarf unwind instructions could not be parsed");
+                       return encodeToUseDwarf(dummy);
+               }
+       }
+       else {
+               strcpy(warningBuffer, "dwarf FDE could not be parsed");
+               return encodeToUseDwarf(dummy);
+       }
+}
+
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getSavedRegister(A& addressSpace, const R& registers, pint_t cfa,
+                                                                                                       const typename CFI_Parser<A>::RegisterLocation& savedReg)
+{
+       switch ( savedReg.location ) {
+               case CFI_Parser<A>::kRegisterInCFA:
+                       return addressSpace.getP(cfa + savedReg.value);
+
+               case CFI_Parser<A>::kRegisterAtExpression:
+                       return addressSpace.getP(evaluateExpression(savedReg.value, addressSpace, registers, cfa));
+
+               case CFI_Parser<A>::kRegisterIsExpression:
+                       return evaluateExpression(savedReg.value, addressSpace, registers, cfa);
+
+               case CFI_Parser<A>::kRegisterInRegister:
+                       return registers.getRegister(savedReg.value);
+
+               case CFI_Parser<A>::kRegisterUnused:
+               case CFI_Parser<A>::kRegisterOffsetFromCFA:
+                       // FIX ME
+                       break;
+       }
+       ABORT("unsupported restore location for register");
+}
+
+template <typename A, typename R>
+double DwarfInstructions<A,R>::getSavedFloatRegister(A& addressSpace, const R& registers, pint_t cfa,
+                                                                                                       const typename CFI_Parser<A>::RegisterLocation& savedReg)
+{
+       switch ( savedReg.location ) {
+               case CFI_Parser<A>::kRegisterInCFA:
+                       return addressSpace.getDouble(cfa + savedReg.value);
+
+               case CFI_Parser<A>::kRegisterAtExpression:
+                       return addressSpace.getDouble(evaluateExpression(savedReg.value, addressSpace, registers, cfa));
+
+               case CFI_Parser<A>::kRegisterIsExpression:
+               case CFI_Parser<A>::kRegisterUnused:
+               case CFI_Parser<A>::kRegisterOffsetFromCFA:
+               case CFI_Parser<A>::kRegisterInRegister:
+                       // FIX ME
+                       break;
+       }
+       ABORT("unsupported restore location for float register");
+}
+
+template <typename A, typename R>
+v128 DwarfInstructions<A,R>::getSavedVectorRegister(A& addressSpace, const R& registers, pint_t cfa,
+                                                                                                       const typename CFI_Parser<A>::RegisterLocation& savedReg)
+{
+       switch ( savedReg.location ) {
+               case CFI_Parser<A>::kRegisterInCFA:
+                       return addressSpace.getVector(cfa + savedReg.value);
+
+               case CFI_Parser<A>::kRegisterAtExpression:
+                       return addressSpace.getVector(evaluateExpression(savedReg.value, addressSpace, registers, cfa));
+
+               case CFI_Parser<A>::kRegisterIsExpression:
+               case CFI_Parser<A>::kRegisterUnused:
+               case CFI_Parser<A>::kRegisterOffsetFromCFA:
+               case CFI_Parser<A>::kRegisterInRegister:
+                       // FIX ME
+                       break;
+       }
+       ABORT("unsupported restore location for vector register");
+}
+
+
+template <typename A, typename R>
+int DwarfInstructions<A,R>::stepWithDwarf(A& addressSpace, pint_t pc, pint_t fdeStart, R& registers)
+{
+       //fprintf(stderr, "stepWithDwarf(pc=0x%0llX, fdeStart=0x%0llX)\n", (uint64_t)pc, (uint64_t)fdeStart);
+       typename CFI_Parser<A>::FDE_Info fdeInfo;
+       typename CFI_Parser<A>::CIE_Info cieInfo;
+       if ( CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo) == NULL ) {
+               typename CFI_Parser<A>::PrologInfo prolog;
+               if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
+                       R newRegisters = registers;
+                       
+                       // get pointer to cfa (architecture specific)
+                       pint_t cfa = getCFA(addressSpace, prolog, registers);
+
+                       // restore registers that dwarf says were saved
+                       pint_t returnAddress = 0;
+                       for (int i=0; i <= lastRestoreReg(newRegisters); ++i) {
+                               if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+                                       if ( registers.validFloatRegister(i) )
+                                               newRegisters.setFloatRegister(i, getSavedFloatRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]));
+                                       else if ( registers.validVectorRegister(i) )
+                                               newRegisters.setVectorRegister(i, getSavedVectorRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]));
+                                       else if ( isReturnAddressRegister(i, registers) )
+                                               returnAddress = getSavedRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]);
+                                       else if ( registers.validRegister(i) )
+                                               newRegisters.setRegister(i, getSavedRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]));
+                                       else
+                                               return UNW_EBADREG;
+                               }
+                       }
+                       
+                       // by definition the CFA is the stack pointer at the call site, so restoring SP means setting it to CFA
+                       newRegisters.setSP(cfa);
+
+                       // return address is address after call site instruction, so setting IP to that does a return
+                       newRegisters.setIP(returnAddress);
+                       
+                       // do the actual step by replacing the register set with the new ones
+                       registers = newRegisters;
+
+                       return UNW_STEP_SUCCESS;
+               }
+       }
+       return UNW_EBADFRAME;
+}
+
+
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::evaluateExpression(pint_t expression, A& addressSpace, 
+                                                                                                               const R& registers, pint_t initialStackValue)
+{
+       const bool log = false;
+       pint_t p = expression;
+       pint_t expressionEnd = expression+20; // just need something until length is read
+       uint64_t length = addressSpace.getULEB128(p, expressionEnd);
+       expressionEnd = p + length;
+       if (log) fprintf(stderr, "evaluateExpression(): length=%llu\n", length);
+       pint_t stack[100];
+       pint_t* sp = stack;
+       *(++sp) = initialStackValue;
+       
+       while ( p < expressionEnd ) {
+               if (log) {
+                       for(pint_t* t = sp; t > stack; --t) {
+                               fprintf(stderr, "sp[] = 0x%llX\n", (uint64_t)(*t));
+                       }
+               }
+               uint8_t opcode = addressSpace.get8(p++);
+               sint_t svalue;
+               pint_t value;
+               uint32_t reg;
+               switch (opcode) {
+                       case DW_OP_addr:
+                               // push immediate address sized value
+                               value = addressSpace.getP(p);
+                               p += sizeof(pint_t);
+                               *(++sp) = value;
+                               if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+                               break;
+               
+                       case DW_OP_deref:
+                               // pop stack, dereference, push result
+                               value = *sp--;
+                               *(++sp) = addressSpace.getP(value);
+                               if (log) fprintf(stderr, "dereference 0x%llX\n", (uint64_t)value);
+                               break;
+               
+                       case DW_OP_const1u:
+                               // push immediate 1 byte value
+                               value = addressSpace.get8(p);
+                               p += 1;
+                               *(++sp) = value;
+                               if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+                               break;
+                               
+                       case DW_OP_const1s:
+                               // push immediate 1 byte signed value
+                               svalue = (int8_t)addressSpace.get8(p);
+                               p += 1;
+                               *(++sp) = svalue;
+                               if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+                               break;
+               
+                       case DW_OP_const2u:
+                               // push immediate 2 byte value
+                               value = addressSpace.get16(p);
+                               p += 2;
+                               *(++sp) = value;
+                               if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+                               break;
+                               
+                       case DW_OP_const2s:
+                               // push immediate 2 byte signed value
+                               svalue = (int16_t)addressSpace.get16(p);
+                               p += 2;
+                               *(++sp) = svalue;
+                               if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+                               break;
+               
+                       case DW_OP_const4u:
+                               // push immediate 4 byte value
+                               value = addressSpace.get32(p);
+                               p += 4;
+                               *(++sp) = value;
+                               if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+                               break;
+                               
+                       case DW_OP_const4s:
+                               // push immediate 4 byte signed value
+                               svalue = (int32_t)addressSpace.get32(p);
+                               p += 4;
+                               *(++sp) = svalue;
+                               if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+                               break;
+                               
+                       case DW_OP_const8u:
+                               // push immediate 8 byte value
+                               value = addressSpace.get64(p);
+                               p += 8;
+                               *(++sp) = value;
+                               if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+                               break;
+                               
+                       case DW_OP_const8s:
+                               // push immediate 8 byte signed value
+                               value = (int32_t)addressSpace.get64(p);
+                               p += 8;
+                               *(++sp) = value;
+                               if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+                               break;
+               
+                       case DW_OP_constu:
+                               // push immediate ULEB128 value
+                               value = addressSpace.getULEB128(p, expressionEnd);
+                               *(++sp) = value;
+                               if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+                               break;
+                               
+                       case DW_OP_consts:
+                               // push immediate SLEB128 value
+                               svalue = addressSpace.getSLEB128(p, expressionEnd);
+                               *(++sp) = svalue;
+                               if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+                               break;
+               
+                       case DW_OP_dup:
+                               // push top of stack
+                               value = *sp;
+                               *(++sp) = value;
+                               if (log) fprintf(stderr, "duplicate top of stack\n");
+                               break;
+                               
+                       case DW_OP_drop:
+                               // pop
+                               --sp; 
+                               if (log) fprintf(stderr, "pop top of stack\n");
+                               break;
+                               
+                       case DW_OP_over:
+                               // dup second
+                               value = sp[-1];
+                               *(++sp) = value;
+                               if (log) fprintf(stderr, "duplicate second in stack\n");
+                               break;
+
+                       case DW_OP_pick:
+                               // pick from
+                               reg = addressSpace.get8(p);
+                               p += 1;
+                               value = sp[-reg];
+                               *(++sp) = value;
+                               if (log) fprintf(stderr, "duplicate %d in stack\n", reg);
+                               break;
+
+                       case DW_OP_swap:
+                               // swap top two
+                               value = sp[0];
+                               sp[0] = sp[-1];
+                               sp[-1] = value;
+                               if (log) fprintf(stderr, "swap top of stack\n");
+                               break;
+
+                       case DW_OP_rot:
+                               // rotate top three
+                               value = sp[0];
+                               sp[0] = sp[-1];
+                               sp[-1] = sp[-2];
+                               sp[-2] = value;
+                               if (log) fprintf(stderr, "rotate top three of stack\n");
+                               break;
+
+                       case DW_OP_xderef:
+                               // pop stack, dereference, push result
+                               value = *sp--;
+                               *sp = *((uint64_t*)value);
+                               if (log) fprintf(stderr, "x-dereference 0x%llX\n", (uint64_t)value);
+                               break;
+                       
+                       case DW_OP_abs:
+                               svalue = *sp;
+                               if ( svalue < 0 )
+                                       *sp = -svalue;
+                               if (log) fprintf(stderr, "abs\n");
+                               break;
+               
+                       case DW_OP_and:
+                               value = *sp--;
+                               *sp &= value;
+                               if (log) fprintf(stderr, "and\n");
+                               break;
+                       
+                       case DW_OP_div:
+                               svalue = *sp--;
+                               *sp = *sp / svalue;
+                               if (log) fprintf(stderr, "div\n");
+                               break;
+                       
+                       case DW_OP_minus:
+                               svalue = *sp--;
+                               *sp = *sp - svalue;
+                               if (log) fprintf(stderr, "minus\n");
+                               break;
+
+                       case DW_OP_mod:
+                               svalue = *sp--;
+                               *sp = *sp % svalue;
+                               if (log) fprintf(stderr, "module\n");
+                               break;
+
+                       case DW_OP_mul:
+                               svalue = *sp--;
+                               *sp = *sp * svalue;
+                               if (log) fprintf(stderr, "mul\n");
+                               break;
+
+                       case DW_OP_neg:
+                               *sp =  0 - *sp;
+                               if (log) fprintf(stderr, "neg\n");
+                               break;
+
+                       case DW_OP_not:
+                               svalue = *sp;
+                               *sp =  ~svalue;
+                               if (log) fprintf(stderr, "not\n");
+                               break;
+
+                       case DW_OP_or:
+                               value = *sp--;
+                               *sp |= value;
+                               if (log) fprintf(stderr, "or\n");
+                               break;
+
+                       case DW_OP_plus:
+                               value = *sp--;
+                               *sp += value;
+                               if (log) fprintf(stderr, "plus\n");
+                               break;
+
+                       case DW_OP_plus_uconst:
+                               // pop stack, add uelb128 constant, push result
+                               *sp += addressSpace.getULEB128(p, expressionEnd);
+                               if (log) fprintf(stderr, "add constant\n");
+                               break;
+               
+                       case DW_OP_shl:
+                               value = *sp--;
+                               *sp = *sp << value;
+                               if (log) fprintf(stderr, "shift left\n");
+                               break;
+                       
+                       case DW_OP_shr:
+                               value = *sp--;
+                               *sp = *sp >> value;
+                               if (log) fprintf(stderr, "shift left\n");
+                               break;
+                               
+                       case DW_OP_shra:
+                               value = *sp--;
+                               svalue = *sp;
+                               *sp = svalue >> value;
+                               if (log) fprintf(stderr, "shift left arithmetric\n");
+                               break;
+                       
+                       case DW_OP_xor:
+                               value = *sp--;
+                               *sp ^= value;
+                               if (log) fprintf(stderr, "xor\n");
+                               break;
+
+                       case DW_OP_skip:
+                               svalue = (int16_t)addressSpace.get16(p);
+                               p += 2;
+                               p += svalue;
+                               if (log) fprintf(stderr, "skip %lld\n", (uint64_t)svalue);
+                               break;
+                       
+                       case DW_OP_bra:
+                               svalue = (int16_t)addressSpace.get16(p);
+                               p += 2;
+                               if ( *sp-- )
+                                       p += svalue;
+                               if (log) fprintf(stderr, "bra %lld\n", (uint64_t)svalue);
+                               break;
+                       
+                       case DW_OP_eq:
+                               value = *sp--;
+                               *sp = (*sp == value);
+                               if (log) fprintf(stderr, "eq\n");
+                               break;
+                       
+                       case DW_OP_ge:
+                               value = *sp--;
+                               *sp = (*sp >= value);
+                               if (log) fprintf(stderr, "ge\n");
+                               break;
+                               
+                       case DW_OP_gt:
+                               value = *sp--;
+                               *sp = (*sp > value);
+                               if (log) fprintf(stderr, "gt\n");
+                               break;
+                               
+                       case DW_OP_le:
+                               value = *sp--;
+                               *sp = (*sp <= value);
+                               if (log) fprintf(stderr, "le\n");
+                               break;
+                               
+                       case DW_OP_lt:
+                               value = *sp--;
+                               *sp = (*sp < value);
+                               if (log) fprintf(stderr, "lt\n");
+                               break;
+                               
+                       case DW_OP_ne:
+                               value = *sp--;
+                               *sp = (*sp != value);
+                               if (log) fprintf(stderr, "ne\n");
+                               break;
+                       
+                       case DW_OP_lit0:
+                       case DW_OP_lit1:
+                       case DW_OP_lit2:
+                       case DW_OP_lit3:
+                       case DW_OP_lit4:
+                       case DW_OP_lit5:
+                       case DW_OP_lit6:
+                       case DW_OP_lit7:
+                       case DW_OP_lit8:
+                       case DW_OP_lit9:
+                       case DW_OP_lit10:
+                       case DW_OP_lit11:
+                       case DW_OP_lit12:
+                       case DW_OP_lit13:
+                       case DW_OP_lit14:
+                       case DW_OP_lit15:
+                       case DW_OP_lit16:
+                       case DW_OP_lit17:
+                       case DW_OP_lit18:
+                       case DW_OP_lit19:
+                       case DW_OP_lit20:
+                       case DW_OP_lit21:
+                       case DW_OP_lit22:
+                       case DW_OP_lit23:
+                       case DW_OP_lit24:
+                       case DW_OP_lit25:
+                       case DW_OP_lit26:
+                       case DW_OP_lit27:
+                       case DW_OP_lit28:
+                       case DW_OP_lit29:
+                       case DW_OP_lit30:
+                       case DW_OP_lit31:
+                               value = opcode - DW_OP_lit0;
+                               *(++sp) = value;
+                               if (log) fprintf(stderr, "push literal 0x%llX\n", (uint64_t)value);
+                               break;
+               
+                       case DW_OP_reg0:
+                       case DW_OP_reg1:
+                       case DW_OP_reg2:
+                       case DW_OP_reg3:
+                       case DW_OP_reg4:
+                       case DW_OP_reg5:
+                       case DW_OP_reg6:
+                       case DW_OP_reg7:
+                       case DW_OP_reg8:
+                       case DW_OP_reg9:
+                       case DW_OP_reg10:
+                       case DW_OP_reg11:
+                       case DW_OP_reg12:
+                       case DW_OP_reg13:
+                       case DW_OP_reg14:
+                       case DW_OP_reg15:
+                       case DW_OP_reg16:
+                       case DW_OP_reg17:
+                       case DW_OP_reg18:
+                       case DW_OP_reg19:
+                       case DW_OP_reg20:
+                       case DW_OP_reg21:
+                       case DW_OP_reg22:
+                       case DW_OP_reg23:
+                       case DW_OP_reg24:
+                       case DW_OP_reg25:
+                       case DW_OP_reg26:
+                       case DW_OP_reg27:
+                       case DW_OP_reg28:
+                       case DW_OP_reg29:
+                       case DW_OP_reg30:
+                       case DW_OP_reg31:
+                               reg = opcode - DW_OP_reg0;
+                               *(++sp) = registers.getRegister(reg);
+                               if (log) fprintf(stderr, "push reg %d\n", reg);
+                               break;
+               
+                       case DW_OP_regx:
+                               reg = addressSpace.getULEB128(p, expressionEnd);
+                               *(++sp) = registers.getRegister(reg);
+                               if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue);
+                               break;                  
+
+                       case DW_OP_breg0:
+                       case DW_OP_breg1:
+                       case DW_OP_breg2:
+                       case DW_OP_breg3:
+                       case DW_OP_breg4:
+                       case DW_OP_breg5:
+                       case DW_OP_breg6:
+                       case DW_OP_breg7:
+                       case DW_OP_breg8:
+                       case DW_OP_breg9:
+                       case DW_OP_breg10:
+                       case DW_OP_breg11:
+                       case DW_OP_breg12:
+                       case DW_OP_breg13:
+                       case DW_OP_breg14:
+                       case DW_OP_breg15:
+                       case DW_OP_breg16:
+                       case DW_OP_breg17:
+                       case DW_OP_breg18:
+                       case DW_OP_breg19:
+                       case DW_OP_breg20:
+                       case DW_OP_breg21:
+                       case DW_OP_breg22:
+                       case DW_OP_breg23:
+                       case DW_OP_breg24:
+                       case DW_OP_breg25:
+                       case DW_OP_breg26:
+                       case DW_OP_breg27:
+                       case DW_OP_breg28:
+                       case DW_OP_breg29:
+                       case DW_OP_breg30:
+                       case DW_OP_breg31:
+                               reg = opcode - DW_OP_breg0;
+                               svalue = addressSpace.getSLEB128(p, expressionEnd);
+                               *(++sp) = registers.getRegister(reg) + svalue;
+                               if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue);
+                               break;
+                       
+                       case DW_OP_bregx:
+                               reg = addressSpace.getULEB128(p, expressionEnd);
+                               svalue = addressSpace.getSLEB128(p, expressionEnd);
+                               *(++sp) = registers.getRegister(reg) + svalue;
+                               if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue);
+                               break;
+                       
+                       case DW_OP_fbreg:
+                               ABORT("DW_OP_fbreg not implemented");
+                               break;
+                               
+                       case DW_OP_piece:
+                               ABORT("DW_OP_piece not implemented");
+                               break;
+                               
+                       case DW_OP_deref_size:
+                               // pop stack, dereference, push result
+                               value = *sp--;
+                               switch ( addressSpace.get8(p++) ) {
+                                       case 1:
+                                               value = addressSpace.get8(value);
+                                               break;
+                                       case 2:
+                                               value = addressSpace.get16(value);
+                                               break;
+                                       case 4:
+                                               value = addressSpace.get32(value);
+                                               break;
+                                       case 8:
+                                               value = addressSpace.get64(value);
+                                               break;
+                                       default:
+                                               ABORT("DW_OP_deref_size with bad size");
+                               }
+                               *(++sp) = value;
+                               if (log) fprintf(stderr, "sized dereference 0x%llX\n", (uint64_t)value);
+                               break;
+                       
+                       case DW_OP_xderef_size:
+                       case DW_OP_nop:
+                       case DW_OP_push_object_addres:
+                       case DW_OP_call2:
+                       case DW_OP_call4:
+                       case DW_OP_call_ref:
+                       default:
+                               ABORT("dwarf opcode not implemented");
+               }
+       
+       }
+       if (log) fprintf(stderr, "expression evaluates to 0x%llX\n", (uint64_t)*sp);
+       return *sp;
+}
+
+
+
+//
+//     x86_64 specific functions
+//
+
+template <typename A, typename R>
+int DwarfInstructions<A,R>::lastRestoreReg(const Registers_x86_64&) 
+{
+       COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)DW_X86_64_RET_ADDR );
+       return DW_X86_64_RET_ADDR; 
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_x86_64&) 
+{
+       return (regNum == DW_X86_64_RET_ADDR); 
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, 
+                                                                               const Registers_x86_64& registers)
+{
+       if ( prolog.cfaRegister != 0 )
+               return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+       else if ( prolog.cfaExpression != 0 )
+               return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0);
+       else
+               ABORT("getCFA(): unknown location for x86_64 cfa");
+}
+
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_x86_64&) 
+{
+       return UNWIND_X86_64_MODE_DWARF;
+}
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_x86&) 
+{
+       return UNWIND_X86_MODE_DWARF;
+}
+
+
+
+template <typename A, typename R>
+uint32_t DwarfInstructions<A,R>::getRBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure)
+{
+       if ( (regOffsetFromBaseOffset < 0) || (regOffsetFromBaseOffset > 32) ) {
+               failure = true;
+               return 0;
+       }
+       unsigned int slotIndex = regOffsetFromBaseOffset/8;
+       
+       switch ( reg ) {
+               case UNW_X86_64_RBX:
+                       return UNWIND_X86_64_REG_RBX << (slotIndex*3);
+               case UNW_X86_64_R12:
+                       return UNWIND_X86_64_REG_R12 << (slotIndex*3);
+               case UNW_X86_64_R13:
+                       return UNWIND_X86_64_REG_R13 << (slotIndex*3);
+               case UNW_X86_64_R14:
+                       return UNWIND_X86_64_REG_R14 << (slotIndex*3);
+               case UNW_X86_64_R15:
+                       return UNWIND_X86_64_REG_R15 << (slotIndex*3);
+       }
+       
+       // invalid register
+       failure = true;
+       return 0;
+}
+
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+                                                                                               const Registers_x86_64& r, const typename CFI_Parser<A>::PrologInfo& prolog,
+                                                                                               char warningBuffer[1024])
+{
+       warningBuffer[0] = '\0';
+       
+       if ( prolog.registerSavedTwiceInCIE == DW_X86_64_RET_ADDR ) {
+               warningBuffer[0] = '\0';        // silently disable conversion to compact unwind by linker
+               return UNWIND_X86_64_MODE_DWARF;
+       }
+       // don't create compact unwind info for unsupported dwarf kinds
+       if ( prolog.registerSavedMoreThanOnce ) {
+               strcpy(warningBuffer, "register saved more than once (might be shrink wrap)");
+               return UNWIND_X86_64_MODE_DWARF;
+       }
+       if ( prolog.cfaOffsetWasNegative ) {
+               strcpy(warningBuffer, "cfa had negative offset (dwarf might contain epilog)");
+               return UNWIND_X86_64_MODE_DWARF;
+       }
+       if ( prolog.spExtraArgSize != 0 ) {
+               strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size");
+               return UNWIND_X86_64_MODE_DWARF;
+       }
+       if ( prolog.sameValueUsed ) {
+               strcpy(warningBuffer, "dwarf uses DW_CFA_same_value");
+               return UNWIND_X86_64_MODE_DWARF;
+       }
+
+       // figure out which kind of frame this function uses
+       bool standardRBPframe = ( 
+                (prolog.cfaRegister == UNW_X86_64_RBP) 
+         && (prolog.cfaRegisterOffset == 16)
+         && (prolog.savedRegisters[UNW_X86_64_RBP].location == CFI_Parser<A>::kRegisterInCFA)
+         && (prolog.savedRegisters[UNW_X86_64_RBP].value == -16) );
+       bool standardRSPframe = (prolog.cfaRegister == UNW_X86_64_RSP);
+       if ( !standardRBPframe && !standardRSPframe ) {
+               // no compact encoding for this
+               strcpy(warningBuffer, "does not use RBP or RSP based frame");
+               return UNWIND_X86_64_MODE_DWARF;
+       }
+       
+       // scan which registers are saved
+       int saveRegisterCount = 0;
+       bool rbxSaved = false;
+       bool r12Saved = false;
+       bool r13Saved = false;
+       bool r14Saved = false;
+       bool r15Saved = false;
+       bool rbpSaved = false;
+       for (int i=0; i < 64; ++i) {
+               if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+                       if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
+                               sprintf(warningBuffer, "register %d saved somewhere other that in frame", i);
+                               return UNWIND_X86_64_MODE_DWARF;
+                       }
+                       switch (i) {
+                               case UNW_X86_64_RBX:
+                                       rbxSaved = true;
+                                       ++saveRegisterCount;
+                                       break;
+                               case UNW_X86_64_R12:
+                                       r12Saved = true;
+                                       ++saveRegisterCount;
+                                       break;
+                               case UNW_X86_64_R13:
+                                       r13Saved = true;
+                                       ++saveRegisterCount;
+                                       break;
+                               case UNW_X86_64_R14:
+                                       r14Saved = true;
+                                       ++saveRegisterCount;
+                                       break;
+                               case UNW_X86_64_R15:
+                                       r15Saved = true;
+                                       ++saveRegisterCount;
+                                       break;
+                               case UNW_X86_64_RBP:
+                                       rbpSaved = true;
+                                       ++saveRegisterCount;
+                                       break;
+                               case DW_X86_64_RET_ADDR:
+                                       break;
+                               default:
+                                       sprintf(warningBuffer, "non-standard register %d being saved in prolog", i);
+                                       return UNWIND_X86_64_MODE_DWARF;
+                       }
+               }
+       }
+       const int64_t cfaOffsetRBX = prolog.savedRegisters[UNW_X86_64_RBX].value;
+       const int64_t cfaOffsetR12 = prolog.savedRegisters[UNW_X86_64_R12].value;
+       const int64_t cfaOffsetR13 = prolog.savedRegisters[UNW_X86_64_R13].value;
+       const int64_t cfaOffsetR14 = prolog.savedRegisters[UNW_X86_64_R14].value;
+       const int64_t cfaOffsetR15 = prolog.savedRegisters[UNW_X86_64_R15].value;
+       const int64_t cfaOffsetRBP = prolog.savedRegisters[UNW_X86_64_RBP].value;
+       
+       // encode standard RBP frames
+       compact_unwind_encoding_t  encoding = 0;
+       if ( standardRBPframe ) {
+               //              |              |
+               //              +--------------+   <- CFA
+               //              |   ret addr   |
+               //              +--------------+
+               //              |     rbp      |
+               //              +--------------+   <- rbp
+               //              ~              ~
+               //              +--------------+   
+               //              |  saved reg3  |
+               //              +--------------+   <- CFA - offset+16
+               //              |  saved reg2  |
+               //              +--------------+   <- CFA - offset+8
+               //              |  saved reg1  |
+               //              +--------------+   <- CFA - offset
+               //              |              |
+               //              +--------------+
+               //              |              |
+               //                                                 <- rsp
+               //
+               encoding = UNWIND_X86_64_MODE_RBP_FRAME;
+               
+               // find save location of farthest register from rbp
+               int furthestCfaOffset = 0;
+               if ( rbxSaved & (cfaOffsetRBX < furthestCfaOffset) )
+                       furthestCfaOffset = cfaOffsetRBX;
+               if ( r12Saved & (cfaOffsetR12 < furthestCfaOffset) )
+                       furthestCfaOffset = cfaOffsetR12;
+               if ( r13Saved & (cfaOffsetR13 < furthestCfaOffset) )
+                       furthestCfaOffset = cfaOffsetR13;
+               if ( r14Saved & (cfaOffsetR14 < furthestCfaOffset) )
+                       furthestCfaOffset = cfaOffsetR14;
+               if ( r15Saved & (cfaOffsetR15 < furthestCfaOffset) )
+                       furthestCfaOffset = cfaOffsetR15;
+               
+               if ( furthestCfaOffset == 0 ) {
+                       // no registers saved, nothing more to encode
+                       return encoding;
+               }
+               
+               // add stack offset to encoding
+               int rbpOffset = furthestCfaOffset + 16;
+               int encodedOffset = rbpOffset/(-8);
+               if ( encodedOffset > 255 ) {
+                       strcpy(warningBuffer, "offset of saved registers too far to encode");
+                       return UNWIND_X86_64_MODE_DWARF;
+               }
+               encoding |= (encodedOffset << __builtin_ctz(UNWIND_X86_64_RBP_FRAME_OFFSET));
+               
+               // add register saved from each stack location
+               bool encodingFailure = false;
+               if ( rbxSaved )
+                       encoding |= getRBPEncodedRegister(UNW_X86_64_RBX, cfaOffsetRBX - furthestCfaOffset, encodingFailure);
+               if ( r12Saved )
+                       encoding |= getRBPEncodedRegister(UNW_X86_64_R12, cfaOffsetR12 - furthestCfaOffset, encodingFailure);
+               if ( r13Saved )
+                       encoding |= getRBPEncodedRegister(UNW_X86_64_R13, cfaOffsetR13 - furthestCfaOffset, encodingFailure);
+               if ( r14Saved )
+                       encoding |= getRBPEncodedRegister(UNW_X86_64_R14, cfaOffsetR14 - furthestCfaOffset, encodingFailure);
+               if ( r15Saved )
+                       encoding |= getRBPEncodedRegister(UNW_X86_64_R15, cfaOffsetR15 - furthestCfaOffset, encodingFailure);
+               
+               if ( encodingFailure ){
+                       strcpy(warningBuffer, "saved registers not contiguous");
+                       return UNWIND_X86_64_MODE_DWARF;
+               }
+
+               return encoding;
+       }
+       else {
+               //              |              |
+               //              +--------------+   <- CFA
+               //              |   ret addr   |
+               //              +--------------+
+               //              |  saved reg1  |
+               //              +--------------+   <- CFA - 16
+               //              |  saved reg2  |
+               //              +--------------+   <- CFA - 24
+               //              |  saved reg3  |
+               //              +--------------+   <- CFA - 32
+               //              |  saved reg4  |
+               //              +--------------+   <- CFA - 40
+               //              |  saved reg5  |
+               //              +--------------+   <- CFA - 48
+               //              |  saved reg6  |
+               //              +--------------+   <- CFA - 56
+               //              |              |
+               //                                                 <- esp
+               //
+
+               // for RSP based frames we need to encode stack size in unwind info
+               encoding = UNWIND_X86_64_MODE_STACK_IMMD;
+               uint64_t stackValue = prolog.cfaRegisterOffset / 8;
+               uint32_t stackAdjust = 0;
+               bool immedStackSize = true;
+               const uint32_t stackMaxImmedValue = EXTRACT_BITS(0xFFFFFFFF,UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+               if ( stackValue > stackMaxImmedValue ) {
+                       // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function
+                       if      ( prolog.codeOffsetAtStackDecrement == 0 ) {
+                               strcpy(warningBuffer, "stack size is large but stack subq instruction not found");
+                               return UNWIND_X86_64_MODE_DWARF;
+                       }
+                       pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;                
+                       try {
+                               uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
+                               stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/8;
+                       }
+                       catch (...) {
+                               strcpy(warningBuffer, "stack size is large but stack subq instruction not found");
+                               return UNWIND_X86_64_MODE_DWARF;
+                       }
+                       stackValue = functionContentAdjustStackIns - funcAddr;
+                       immedStackSize = false;
+                       if ( stackAdjust > 7 ) {
+                               strcpy(warningBuffer, "stack subq instruction is too different from dwarf stack size");
+                               return UNWIND_X86_64_MODE_DWARF;
+                       }
+                       encoding = UNWIND_X86_64_MODE_STACK_IND;
+               }       
+               
+               
+               // validate that saved registers are all within 6 slots abutting return address
+               int registers[6];
+               for (int i=0; i < 6;++i)
+                       registers[i] = 0;
+               if ( r15Saved ) {
+                       if ( cfaOffsetR15 < -56 ) {
+                               strcpy(warningBuffer, "r15 is saved too far from return address");
+                               return UNWIND_X86_64_MODE_DWARF;
+                       }
+                       registers[(cfaOffsetR15+56)/8] = UNWIND_X86_64_REG_R15;
+               }
+               if ( r14Saved ) {
+                       if ( cfaOffsetR14 < -56 ) {
+                               strcpy(warningBuffer, "r14 is saved too far from return address");
+                               return UNWIND_X86_64_MODE_DWARF;
+                       }
+                       registers[(cfaOffsetR14+56)/8] = UNWIND_X86_64_REG_R14;
+               }
+               if ( r13Saved ) {
+                       if ( cfaOffsetR13 < -56 ) {
+                               strcpy(warningBuffer, "r13 is saved too far from return address");
+                               return UNWIND_X86_64_MODE_DWARF;
+                       }
+                       registers[(cfaOffsetR13+56)/8] = UNWIND_X86_64_REG_R13;
+               }
+               if ( r12Saved ) {
+                       if ( cfaOffsetR12 < -56 ) {
+                               strcpy(warningBuffer, "r12 is saved too far from return address");
+                               return UNWIND_X86_64_MODE_DWARF;
+                       }
+                       registers[(cfaOffsetR12+56)/8] = UNWIND_X86_64_REG_R12;
+               }
+               if ( rbxSaved ) {
+                       if ( cfaOffsetRBX < -56 ) {
+                               strcpy(warningBuffer, "rbx is saved too far from return address");
+                               return UNWIND_X86_64_MODE_DWARF;
+                       }
+                       registers[(cfaOffsetRBX+56)/8] = UNWIND_X86_64_REG_RBX;
+               }
+               if ( rbpSaved ) {
+                       if ( cfaOffsetRBP < -56 ) {
+                               strcpy(warningBuffer, "rbp is saved too far from return address");
+                               return UNWIND_X86_64_MODE_DWARF;
+                       }
+                       registers[(cfaOffsetRBP+56)/8] = UNWIND_X86_64_REG_RBP;
+               }
+               
+               // validate that saved registers are contiguous and abut return address on stack
+               for (int i=0; i < saveRegisterCount; ++i) {
+                       if ( registers[5-i] == 0 ) {
+                               strcpy(warningBuffer, "registers not save contiguously in stack");
+                               return UNWIND_X86_64_MODE_DWARF;
+                       }
+               }
+                               
+               // encode register permutation
+               // the 10-bits are encoded differently depending on the number of registers saved
+               int renumregs[6];
+               for (int i=6-saveRegisterCount; i < 6; ++i) {
+                       int countless = 0;
+                       for (int j=6-saveRegisterCount; j < i; ++j) {
+                               if ( registers[j] < registers[i] )
+                                       ++countless;
+                       }
+                       renumregs[i] = registers[i] - countless -1;
+               }
+               uint32_t permutationEncoding = 0;
+               switch ( saveRegisterCount ) {
+                       case 6:
+                               permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] + 6*renumregs[2] + 2*renumregs[3] + renumregs[4]);
+                               break;
+                       case 5:
+                               permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] + 6*renumregs[3] + 2*renumregs[4] + renumregs[5]);
+                               break;
+                       case 4:
+                               permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] + 3*renumregs[4] + renumregs[5]);
+                               break;
+                       case 3:
+                               permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] + renumregs[5]);
+                               break;
+                       case 2:
+                               permutationEncoding |= (5*renumregs[4] + renumregs[5]);
+                               break;
+                       case 1:
+                               permutationEncoding |= (renumregs[5]);
+                               break;
+               }
+               
+               encoding |= (stackValue << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_SIZE));
+               encoding |= (stackAdjust << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_ADJUST));
+               encoding |= (saveRegisterCount << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT));
+               encoding |= (permutationEncoding << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION));
+               return encoding;
+       }
+}
+
+
+
+
+//
+//     x86 specific functions
+//
+template <typename A, typename R>
+int DwarfInstructions<A,R>::lastRestoreReg(const Registers_x86&) 
+{
+       COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)DW_X86_RET_ADDR );
+       return DW_X86_RET_ADDR; 
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_x86&) 
+{
+       return (regNum == DW_X86_RET_ADDR); 
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, 
+                                                                               const Registers_x86& registers)
+{
+       if ( prolog.cfaRegister != 0 )
+               return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+       else if ( prolog.cfaExpression != 0 )
+               return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0);
+       else
+               ABORT("getCFA(): unknown location for x86 cfa");
+}
+
+
+
+
+
+template <typename A, typename R>
+uint32_t DwarfInstructions<A,R>::getEBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure)
+{
+       if ( (regOffsetFromBaseOffset < 0) || (regOffsetFromBaseOffset > 16) ) {
+               failure = true;
+               return 0;
+       }
+       unsigned int slotIndex = regOffsetFromBaseOffset/4;
+       
+       switch ( reg ) {
+               case UNW_X86_EBX:
+                       return UNWIND_X86_REG_EBX << (slotIndex*3);
+               case UNW_X86_ECX:
+                       return UNWIND_X86_REG_ECX << (slotIndex*3);
+               case UNW_X86_EDX:
+                       return UNWIND_X86_REG_EDX << (slotIndex*3);
+               case UNW_X86_EDI:
+                       return UNWIND_X86_REG_EDI << (slotIndex*3);
+               case UNW_X86_ESI:
+                       return UNWIND_X86_REG_ESI << (slotIndex*3);
+       }
+       
+       // invalid register
+       failure = true;
+       return 0;
+}
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+                                                                                               const Registers_x86& r, const typename CFI_Parser<A>::PrologInfo& prolog,
+                                                                                               char warningBuffer[1024])
+{
+       warningBuffer[0] = '\0';
+       
+       if ( prolog.registerSavedTwiceInCIE == DW_X86_RET_ADDR ) {
+               warningBuffer[0] = '\0';        // silently disable conversion to compact unwind by linker
+               return UNWIND_X86_64_MODE_DWARF;
+       }
+       // don't create compact unwind info for unsupported dwarf kinds
+       if ( prolog.registerSavedMoreThanOnce ) {
+               strcpy(warningBuffer, "register saved more than once (might be shrink wrap)");
+               return UNWIND_X86_MODE_DWARF;
+       }
+       if ( prolog.spExtraArgSize != 0 ) {
+               strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size");
+               return UNWIND_X86_MODE_DWARF;
+       }
+       if ( prolog.sameValueUsed ) {
+               strcpy(warningBuffer, "dwarf uses DW_CFA_same_value");
+               return UNWIND_X86_MODE_DWARF;
+       }
+       
+       // figure out which kind of frame this function uses
+       bool standardEBPframe = ( 
+                (prolog.cfaRegister == UNW_X86_EBP) 
+         && (prolog.cfaRegisterOffset == 8)
+         && (prolog.savedRegisters[UNW_X86_EBP].location == CFI_Parser<A>::kRegisterInCFA)
+         && (prolog.savedRegisters[UNW_X86_EBP].value == -8) );
+       bool standardESPframe = (prolog.cfaRegister == UNW_X86_ESP);
+       if ( !standardEBPframe && !standardESPframe ) {
+               // no compact encoding for this
+               strcpy(warningBuffer, "does not use EBP or ESP based frame");
+               return UNWIND_X86_MODE_DWARF;
+       }
+       
+       // scan which registers are saved
+       int saveRegisterCount = 0;
+       bool ebxSaved = false;
+       bool ecxSaved = false;
+       bool edxSaved = false;
+       bool esiSaved = false;
+       bool ediSaved = false;
+       bool ebpSaved = false;
+       for (int i=0; i < 64; ++i) {
+               if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+                       if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
+                               sprintf(warningBuffer, "register %d saved somewhere other that in frame", i);
+                               return UNWIND_X86_MODE_DWARF;
+                       }
+                       switch (i) {
+                               case UNW_X86_EBX:
+                                       ebxSaved = true;
+                                       ++saveRegisterCount;
+                                       break;
+                               case UNW_X86_ECX:
+                                       ecxSaved = true;
+                                       ++saveRegisterCount;
+                                       break;
+                               case UNW_X86_EDX:
+                                       edxSaved = true;
+                                       ++saveRegisterCount;
+                                       break;
+                               case UNW_X86_ESI:
+                                       esiSaved = true;
+                                       ++saveRegisterCount;
+                                       break;
+                               case UNW_X86_EDI:
+                                       ediSaved = true;
+                                       ++saveRegisterCount;
+                                       break;
+                               case UNW_X86_EBP:
+                                       ebpSaved = true;
+                                       ++saveRegisterCount;
+                                       break;
+                               case DW_X86_RET_ADDR:
+                                       break;
+                               default:
+                                       sprintf(warningBuffer, "non-standard register %d being saved in prolog", i);
+                                       return UNWIND_X86_MODE_DWARF;
+                       }
+               }
+       }
+       const int32_t cfaOffsetEBX = prolog.savedRegisters[UNW_X86_EBX].value;
+       const int32_t cfaOffsetECX = prolog.savedRegisters[UNW_X86_ECX].value;
+       const int32_t cfaOffsetEDX = prolog.savedRegisters[UNW_X86_EDX].value;
+       const int32_t cfaOffsetEDI = prolog.savedRegisters[UNW_X86_EDI].value;
+       const int32_t cfaOffsetESI = prolog.savedRegisters[UNW_X86_ESI].value;
+       const int32_t cfaOffsetEBP = prolog.savedRegisters[UNW_X86_EBP].value;
+       
+       // encode standard RBP frames
+       compact_unwind_encoding_t  encoding = 0;
+       if ( standardEBPframe ) {
+               //              |              |
+               //              +--------------+   <- CFA
+               //              |   ret addr   |
+               //              +--------------+
+               //              |     ebp      |
+               //              +--------------+   <- ebp
+               //              ~              ~
+               //              +--------------+   
+               //              |  saved reg3  |
+               //              +--------------+   <- CFA - offset+8
+               //              |  saved reg2  |
+               //              +--------------+   <- CFA - offset+e
+               //              |  saved reg1  |
+               //              +--------------+   <- CFA - offset
+               //              |              |
+               //              +--------------+
+               //              |              |
+               //                                                 <- esp
+               //
+               encoding = UNWIND_X86_MODE_EBP_FRAME;
+               
+               // find save location of farthest register from ebp
+               int furthestCfaOffset = 0;
+               if ( ebxSaved & (cfaOffsetEBX < furthestCfaOffset) )
+                       furthestCfaOffset = cfaOffsetEBX;
+               if ( ecxSaved & (cfaOffsetECX < furthestCfaOffset) )
+                       furthestCfaOffset = cfaOffsetECX;
+               if ( edxSaved & (cfaOffsetEDX < furthestCfaOffset) )
+                       furthestCfaOffset = cfaOffsetEDX;
+               if ( ediSaved & (cfaOffsetEDI < furthestCfaOffset) )
+                       furthestCfaOffset = cfaOffsetEDI;
+               if ( esiSaved & (cfaOffsetESI < furthestCfaOffset) )
+                       furthestCfaOffset = cfaOffsetESI;
+               
+               if ( furthestCfaOffset == 0 ) {
+                       // no registers saved, nothing more to encode
+                       return encoding;
+               }
+               
+               // add stack offset to encoding
+               int ebpOffset = furthestCfaOffset + 8;
+               int encodedOffset = ebpOffset/(-4);
+               if ( encodedOffset > 255 ) {
+                       strcpy(warningBuffer, "offset of saved registers too far to encode");
+                       return UNWIND_X86_MODE_DWARF;
+               }
+               encoding |= (encodedOffset << __builtin_ctz(UNWIND_X86_EBP_FRAME_OFFSET));
+               
+               // add register saved from each stack location
+               bool encodingFailure = false;
+               if ( ebxSaved )
+                       encoding |= getEBPEncodedRegister(UNW_X86_EBX, cfaOffsetEBX - furthestCfaOffset, encodingFailure);
+               if ( ecxSaved )
+                       encoding |= getEBPEncodedRegister(UNW_X86_ECX, cfaOffsetECX - furthestCfaOffset, encodingFailure);
+               if ( edxSaved )
+                       encoding |= getEBPEncodedRegister(UNW_X86_EDX, cfaOffsetEDX - furthestCfaOffset, encodingFailure);
+               if ( ediSaved )
+                       encoding |= getEBPEncodedRegister(UNW_X86_EDI, cfaOffsetEDI - furthestCfaOffset, encodingFailure);
+               if ( esiSaved )
+                       encoding |= getEBPEncodedRegister(UNW_X86_ESI, cfaOffsetESI - furthestCfaOffset, encodingFailure);
+               
+               if ( encodingFailure ){
+                       strcpy(warningBuffer, "saved registers not contiguous");
+                       return UNWIND_X86_MODE_DWARF;
+               }
+
+               return encoding;
+       }
+       else {
+               //              |              |
+               //              +--------------+   <- CFA
+               //              |   ret addr   |
+               //              +--------------+
+               //              |  saved reg1  |
+               //              +--------------+   <- CFA - 8
+               //              |  saved reg2  |
+               //              +--------------+   <- CFA - 12
+               //              |  saved reg3  |
+               //              +--------------+   <- CFA - 16
+               //              |  saved reg4  |
+               //              +--------------+   <- CFA - 20
+               //              |  saved reg5  |
+               //              +--------------+   <- CFA - 24
+               //              |  saved reg6  |
+               //              +--------------+   <- CFA - 28
+               //              |              |
+               //                                                 <- esp
+               //
+
+               // for ESP based frames we need to encode stack size in unwind info
+               encoding = UNWIND_X86_MODE_STACK_IMMD;
+               uint64_t stackValue = prolog.cfaRegisterOffset / 4;
+               uint32_t stackAdjust = 0;
+               bool immedStackSize = true;
+               const uint32_t stackMaxImmedValue = EXTRACT_BITS(0xFFFFFFFF,UNWIND_X86_FRAMELESS_STACK_SIZE);
+               if ( stackValue > stackMaxImmedValue ) {
+                       // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function
+                       pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;                
+                       uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
+                       stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/4;
+                       stackValue = functionContentAdjustStackIns - funcAddr;
+                       immedStackSize = false;
+                       if ( stackAdjust > 7 ) {
+                               strcpy(warningBuffer, "stack subq instruction is too different from dwarf stack size");
+                               return UNWIND_X86_MODE_DWARF;
+                       }
+                       encoding = UNWIND_X86_MODE_STACK_IND;
+               }       
+               
+               
+               // validate that saved registers are all within 6 slots abutting return address
+               int registers[6];
+               for (int i=0; i < 6;++i)
+                       registers[i] = 0;
+               if ( ebxSaved ) {
+                       if ( cfaOffsetEBX < -28 ) {
+                               strcpy(warningBuffer, "ebx is saved too far from return address");
+                               return UNWIND_X86_MODE_DWARF;
+                       }
+                       registers[(cfaOffsetEBX+28)/4] = UNWIND_X86_REG_EBX;
+               }
+               if ( ecxSaved ) {
+                       if ( cfaOffsetECX < -28 ) {
+                               strcpy(warningBuffer, "ecx is saved too far from return address");
+                               return UNWIND_X86_MODE_DWARF;
+                       }
+                       registers[(cfaOffsetECX+28)/4] = UNWIND_X86_REG_ECX;
+               }
+               if ( edxSaved ) {
+                       if ( cfaOffsetEDX < -28 ) {
+                               strcpy(warningBuffer, "edx is saved too far from return address");
+                               return UNWIND_X86_MODE_DWARF;
+                       }
+                       registers[(cfaOffsetEDX+28)/4] = UNWIND_X86_REG_EDX;
+               }
+               if ( ediSaved ) {
+                       if ( cfaOffsetEDI < -28 ) {
+                               strcpy(warningBuffer, "edi is saved too far from return address");
+                               return UNWIND_X86_MODE_DWARF;
+                       }
+                       registers[(cfaOffsetEDI+28)/4] = UNWIND_X86_REG_EDI;
+               }
+               if ( esiSaved ) {
+                       if ( cfaOffsetESI < -28 ) {
+                               strcpy(warningBuffer, "esi is saved too far from return address");
+                               return UNWIND_X86_MODE_DWARF;
+                       }
+                       registers[(cfaOffsetESI+28)/4] = UNWIND_X86_REG_ESI;
+               }
+               if ( ebpSaved ) {
+                       if ( cfaOffsetEBP < -28 ) {
+                               strcpy(warningBuffer, "ebp is saved too far from return address");
+                               return UNWIND_X86_MODE_DWARF;
+                       }
+                       registers[(cfaOffsetEBP+28)/4] = UNWIND_X86_REG_EBP;
+               }
+               
+               // validate that saved registers are contiguous and abut return address on stack
+               for (int i=0; i < saveRegisterCount; ++i) {
+                       if ( registers[5-i] == 0 ) {
+                               strcpy(warningBuffer, "registers not save contiguously in stack");
+                               return UNWIND_X86_MODE_DWARF;
+                       }
+               }
+                               
+               // encode register permutation
+               // the 10-bits are encoded differently depending on the number of registers saved
+               int renumregs[6];
+               for (int i=6-saveRegisterCount; i < 6; ++i) {
+                       int countless = 0;
+                       for (int j=6-saveRegisterCount; j < i; ++j) {
+                               if ( registers[j] < registers[i] )
+                                       ++countless;
+                       }
+                       renumregs[i] = registers[i] - countless -1;
+               }
+               uint32_t permutationEncoding = 0;
+               switch ( saveRegisterCount ) {
+                       case 6:
+                               permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] + 6*renumregs[2] + 2*renumregs[3] + renumregs[4]);
+                               break;
+                       case 5:
+                               permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] + 6*renumregs[3] + 2*renumregs[4] + renumregs[5]);
+                               break;
+                       case 4:
+                               permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] + 3*renumregs[4] + renumregs[5]);
+                               break;
+                       case 3:
+                               permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] + renumregs[5]);
+                               break;
+                       case 2:
+                               permutationEncoding |= (5*renumregs[4] + renumregs[5]);
+                               break;
+                       case 1:
+                               permutationEncoding |= (renumregs[5]);
+                               break;
+               }
+               
+               encoding |= (stackValue << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_SIZE));
+               encoding |= (stackAdjust << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_ADJUST));
+               encoding |= (saveRegisterCount << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_REG_COUNT));
+               encoding |= (permutationEncoding << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION));
+               return encoding;
+       }
+}
+
+
+
+
+
+
+
+//
+//     ppc specific functions
+//
+template <typename A, typename R>
+int DwarfInstructions<A,R>::lastRestoreReg(const Registers_ppc&) 
+{
+       COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)UNW_PPC_SPEFSCR );
+       return UNW_PPC_SPEFSCR; 
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_ppc&) 
+{
+       return (regNum == UNW_PPC_LR); 
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, 
+                                                                               const Registers_ppc& registers)
+{      
+       if ( prolog.cfaRegister != 0 )
+               return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+       else if ( prolog.cfaExpression != 0 )
+               return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0);
+       else
+               ABORT("getCFA(): unknown location for ppc cfa");
+}
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_ppc&) 
+{
+       return UNWIND_X86_MODE_DWARF;
+}
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+                                                                                               const Registers_ppc& r, const typename CFI_Parser<A>::PrologInfo& prolog,
+                                                                                               char warningBuffer[1024])
+{
+       warningBuffer[0] = '\0';
+       return UNWIND_X86_MODE_DWARF;
+}
+
+
+
+
+} // namespace libunwind
+
+
+#endif // __DWARF_INSTRUCTIONS_HPP__
+
+
+
+
diff --git a/src/ld/parsers/libunwind/DwarfParser.hpp b/src/ld/parsers/libunwind/DwarfParser.hpp
new file mode 100644 (file)
index 0000000..3824d2e
--- /dev/null
@@ -0,0 +1,819 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 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@
+ */
+//
+// processor specific parsing of dwarf unwind instructions
+//
+
+#ifndef __DWARF_PARSER_HPP__
+#define __DWARF_PARSER_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <vector>
+
+#include "libunwind.h"
+#include "dwarf2.h"
+
+#include "AddressSpace.hpp"
+
+
+namespace libunwind {
+
+
+///
+/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
+/// See Dwarf Spec for details: 
+///    http://www.linux-foundation.org/spec/booksets/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
+///
+template <typename A>
+class CFI_Parser
+{
+public:
+       typedef typename A::pint_t              pint_t; 
+
+       ///
+       /// Information encoded in a CIE (Common Information Entry)
+       ///  
+       struct CIE_Info {
+               pint_t          cieStart;
+               pint_t          cieLength;
+               pint_t          cieInstructions;
+               uint8_t         pointerEncoding;
+               uint8_t         lsdaEncoding;
+               uint8_t         personalityEncoding;
+               uint8_t         personalityOffsetInCIE;
+               pint_t          personality;
+               int                     codeAlignFactor;
+               int                     dataAlignFactor;
+               bool            isSignalFrame;
+               bool            fdesHaveAugmentationData;
+       };
+       
+       ///
+       /// Information about an FDE (Frame Description Entry)
+       ///  
+       struct FDE_Info {
+               pint_t          fdeStart;
+               pint_t          fdeLength;
+               pint_t          fdeInstructions;
+               pint_t          pcStart;
+               pint_t          pcEnd;
+               pint_t          lsda;
+       };
+
+       ///
+       /// Used by linker when parsing __eh_frame section
+       ///  
+       struct FDE_Reference {
+               pint_t          address;
+               uint32_t        offsetInFDE;
+               uint8_t         encodingOfAddress;
+       };
+       struct FDE_Atom_Info {
+               pint_t                  fdeAddress;
+               FDE_Reference   function;
+               FDE_Reference   cie;
+               FDE_Reference   lsda;
+       };
+       struct CIE_Atom_Info {
+               pint_t                  cieAddress;
+               FDE_Reference   personality;
+       };
+       
+       
+       ///
+       /// Information about a frame layout and registers saved determined 
+       /// by "running" the dwarf FDE "instructions"
+       ///  
+       enum { kMaxRegisterNumber = 120 };
+       enum RegisterSavedWhere { kRegisterUnused, kRegisterInCFA, kRegisterOffsetFromCFA,
+                                                       kRegisterInRegister, kRegisterAtExpression, kRegisterIsExpression } ;
+       struct RegisterLocation {
+               RegisterSavedWhere      location;
+               int64_t                         value;
+       };
+       struct PrologInfo {
+               uint32_t                        cfaRegister;            
+               int32_t                         cfaRegisterOffset;      // CFA = (cfaRegister)+cfaRegisterOffset
+               int64_t                         cfaExpression;          // CFA = expression
+               uint32_t                        spExtraArgSize;
+               uint32_t                        codeOffsetAtStackDecrement;
+               uint8_t                         registerSavedTwiceInCIE;
+               bool                            registersInOtherRegisters;
+               bool                            registerSavedMoreThanOnce;
+               bool                            cfaOffsetWasNegative;
+               bool                            sameValueUsed;
+               RegisterLocation        savedRegisters[kMaxRegisterNumber];     // from where to restore registers
+       };
+
+       struct PrologInfoStackEntry {
+                                                               PrologInfoStackEntry(PrologInfoStackEntry* n, const PrologInfo& i)
+                                                                       : next(n), info(i) {}
+               PrologInfoStackEntry*   next;
+               PrologInfo                              info;
+       };
+
+       static bool findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo);
+       static const char* decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo);
+       static bool parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results);
+       static const char* getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, 
+                                                               std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies);
+       static uint32_t getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength);
+
+       static const char* parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo);
+
+private:
+       static bool parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo, 
+                                                               pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results);
+};
+
+
+///
+/// Parse a FDE into a CIE_Info and an FDE_Info 
+///  
+template <typename A>
+const char* CFI_Parser<A>::decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo)
+{
+       pint_t p = fdeStart;
+       uint64_t cfiLength = addressSpace.get32(p);
+       p += 4;
+       if ( cfiLength == 0xffffffff ) {
+               // 0xffffffff means length is really next 8 bytes
+               cfiLength = addressSpace.get64(p);
+               p += 8;
+       }
+       if ( cfiLength == 0 ) 
+               return "FDE has zero length";   // end marker
+       uint32_t ciePointer = addressSpace.get32(p);
+       if ( ciePointer == 0 ) 
+               return "FDE is really a CIE";   // this is a CIE not an FDE
+       pint_t nextCFI = p + cfiLength;
+       pint_t cieStart = p-ciePointer;
+       const char* err = parseCIE(addressSpace, cieStart, cieInfo);
+       if (err != NULL)
+               return err;
+       p += 4;
+       // parse pc begin and range
+       pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
+       pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
+       // parse rest of info
+       fdeInfo->lsda = 0;
+       // check for augmentation length
+       if ( cieInfo->fdesHaveAugmentationData ) {
+               uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+               pint_t endOfAug = p + augLen;
+               if ( cieInfo->lsdaEncoding != 0 ) {
+                       // peek at value (without indirection).  Zero means no lsda
+                       pint_t lsdaStart = p;
+                       if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
+                               // reset pointer and re-parse lsda address
+                               p = lsdaStart;
+                               fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
+                       }
+               }
+               p = endOfAug;
+       }
+       fdeInfo->fdeStart = fdeStart;
+       fdeInfo->fdeLength = nextCFI - fdeStart;
+       fdeInfo->fdeInstructions = p;
+       fdeInfo->pcStart = pcStart;
+       fdeInfo->pcEnd = pcStart+pcRange;
+       return NULL; // success
+}
+
+
+///
+/// Scan an eh_frame section to find an FDE for a pc
+///  
+template <typename A>
+bool CFI_Parser<A>::findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo)
+{
+       //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
+       pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
+       const pint_t ehSectionEnd = p + sectionLength;
+       while ( p < ehSectionEnd ) {
+               pint_t currentCFI = p;
+               //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
+               uint64_t cfiLength = addressSpace.get32(p);
+               p += 4;
+               if ( cfiLength == 0xffffffff ) {
+                       // 0xffffffff means length is really next 8 bytes
+                       cfiLength = addressSpace.get64(p);
+                       p += 8;
+               }
+               if ( cfiLength == 0 ) 
+                       return false;   // end marker
+               uint32_t id = addressSpace.get32(p);
+               if ( id == 0 ) {
+                       // skip over CIEs
+                       p += cfiLength;
+               }
+               else {
+                       // process FDE to see if it covers pc
+                       pint_t nextCFI = p + cfiLength;
+                       uint32_t ciePointer = addressSpace.get32(p);
+                       pint_t cieStart = p-ciePointer;
+                       // validate pointer to CIE is within section
+                       if ( (ehSectionStart <= cieStart) && (cieStart < ehSectionEnd) ) {
+                               if ( parseCIE(addressSpace, cieStart, cieInfo) == NULL ) {
+                                       p += 4;
+                                       // parse pc begin and range
+                                       pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
+                                       pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
+                                       //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+                                       // test if pc is within the function this FDE covers
+                                       if ( (pcStart < pc) && (pc <= pcStart+pcRange) ) {
+                                               // parse rest of info
+                                               fdeInfo->lsda = 0;
+                                               // check for augmentation length
+                                               if ( cieInfo->fdesHaveAugmentationData ) {
+                                                       uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+                                                       pint_t endOfAug = p + augLen;
+                                                       if ( cieInfo->lsdaEncoding != 0 ) {
+                                                               // peek at value (without indirection).  Zero means no lsda
+                                                               pint_t lsdaStart = p;
+                                                               if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
+                                                                       // reset pointer and re-parse lsda address
+                                                                       p = lsdaStart;
+                                                                       fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
+                                                               }
+                                                       }
+                                                       p = endOfAug;
+                                               }
+                                               fdeInfo->fdeStart = currentCFI;
+                                               fdeInfo->fdeLength = nextCFI - currentCFI;
+                                               fdeInfo->fdeInstructions = p;
+                                               fdeInfo->pcStart = pcStart;
+                                               fdeInfo->pcEnd = pcStart+pcRange;
+                                               //fprintf(stderr, "findFDE(pc=0x%llX) found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+                                               return true;
+                                       }
+                                       else {
+                                               //fprintf(stderr, "findFDE(pc=0x%llX) not found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+                                               // pc is not in begin/range, skip this FDE
+                                       }
+                               }
+                               else {
+                                       // malformed CIE, now augmentation describing pc range encoding
+                                       //fprintf(stderr, "malformed CIE\n");
+                               }
+                       }
+                       else {
+                               // malformed FDE.  CIE is bad
+                               //fprintf(stderr, "malformed FDE, cieStart=0x%llX, ehSectionStart=0x%llX, ehSectionEnd=0x%llX\n",
+                               //      (uint64_t)cieStart, (uint64_t)ehSectionStart, (uint64_t)ehSectionEnd);
+                       }
+                       p = nextCFI;
+               }
+       }
+       //fprintf(stderr, "findFDE(pc=0x%llX) not found\n",(uint64_t)pc);
+       return false;
+}
+
+
+
+///
+/// Extract info from a CIE
+///  
+template <typename A>
+const char* CFI_Parser<A>::parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo)
+{
+       //fprintf(stderr, "parseCIE(0x%llX)\n", (long long)cie);
+       cieInfo->pointerEncoding = 0;
+       cieInfo->lsdaEncoding = 0;
+       cieInfo->personalityEncoding = 0;
+       cieInfo->personalityOffsetInCIE = 0;
+       cieInfo->personality = 0;
+       cieInfo->codeAlignFactor = 0;
+       cieInfo->dataAlignFactor = 0;
+       cieInfo->isSignalFrame = false;
+       cieInfo->fdesHaveAugmentationData = false;
+       cieInfo->cieStart = cie;
+       pint_t p = cie;
+       uint64_t cieLength = addressSpace.get32(p);
+       p += 4;
+       pint_t cieContentEnd = p + cieLength;
+       if ( cieLength == 0xffffffff ) {
+               // 0xffffffff means length is really next 8 bytes
+               cieLength = addressSpace.get64(p);
+               p += 8;
+               cieContentEnd = p + cieLength;
+       }
+       if ( cieLength == 0 ) 
+               return NULL;    
+       // CIE ID is always 0
+       if ( addressSpace.get32(p) != 0 ) 
+               return "CIE ID is not zero";
+       p += 4;
+       // Version is always 1 or 3
+       uint8_t version = addressSpace.get8(p);
+       if ( (version != 1) && (version != 3) )
+               return "CIE version is not 1 or 3";
+       ++p;
+       // save start of augmentation string and find end
+       pint_t strStart = p;
+       while ( addressSpace.get8(p) != 0 )
+               ++p;
+       ++p;
+       // parse code aligment factor
+       cieInfo->codeAlignFactor = addressSpace.getULEB128(p, cieContentEnd);
+       // parse data alignment factor
+       cieInfo->dataAlignFactor = addressSpace.getSLEB128(p, cieContentEnd);
+       // parse return address register
+       addressSpace.getULEB128(p, cieContentEnd);
+       // parse augmentation data based on augmentation string
+       const char* result = NULL;
+       if ( addressSpace.get8(strStart) == 'z' ) {
+               // parse augmentation data length 
+               addressSpace.getULEB128(p, cieContentEnd);
+               for (pint_t s=strStart; addressSpace.get8(s) != '\0'; ++s) {
+                       switch ( addressSpace.get8(s) ) {
+                               case 'z':
+                                       cieInfo->fdesHaveAugmentationData = true;
+                                       break;
+                               case 'P':
+                                       cieInfo->personalityEncoding = addressSpace.get8(p);
+                                       ++p;
+                                       cieInfo->personalityOffsetInCIE = p-cie;
+                                       cieInfo->personality = addressSpace.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
+                                       break;
+                               case 'L':
+                                       cieInfo->lsdaEncoding = addressSpace.get8(p);
+                                       ++p;
+                                       break;
+                               case 'R':
+                                       cieInfo->pointerEncoding = addressSpace.get8(p);
+                                       ++p;
+                                       break;
+                               case 'S':
+                                       cieInfo->isSignalFrame = true;
+                                       break;
+                               default:
+                                       // ignore unknown letters
+                                       break;
+                       }
+               }
+       }
+       cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
+       cieInfo->cieInstructions = p;
+       return result;
+}
+
+
+template <typename A>
+uint32_t CFI_Parser<A>::getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength)
+{
+       uint32_t count = 0;
+       const pint_t ehSectionEnd = ehSectionStart + sectionLength;
+       for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
+               uint64_t cfiLength = addressSpace.get32(p);
+               p += 4;
+               if ( cfiLength == 0xffffffff ) {
+                       // 0xffffffff means length is really next 8 bytes
+                       cfiLength = addressSpace.get64(p);
+                       p += 8;
+               }
+               if ( cfiLength == 0 ) 
+                       return count;   // end marker
+               ++count;
+               p += cfiLength;
+       }
+       return count;
+}
+
+
+
+template <typename A>
+const char* CFI_Parser<A>::getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, 
+                                                                 std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies)
+{
+       const pint_t ehSectionEnd = ehSectionStart + sectionLength;
+       for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
+               pint_t currentCFI = p;
+               uint64_t cfiLength = addressSpace.get32(p);
+               p += 4;
+               if ( cfiLength == 0xffffffff ) {
+                       // 0xffffffff means length is really next 8 bytes
+                       cfiLength = addressSpace.get64(p);
+                       p += 8;
+               }
+               if ( cfiLength == 0 ) 
+                       return NULL;    // end marker
+               uint32_t id = addressSpace.get32(p);
+               if ( id == 0 ) {
+                       // is CIE
+                       CIE_Info cieInfo;
+                       const char* err = parseCIE(addressSpace, currentCFI, &cieInfo);
+                       if ( err != NULL ) 
+                               return err;
+                       CIE_Atom_Info entry;
+                       entry.cieAddress = currentCFI;
+                       entry.personality.address = cieInfo.personality;
+                       entry.personality.offsetInFDE = cieInfo.personalityOffsetInCIE;
+                       entry.personality.encodingOfAddress = cieInfo.personalityEncoding;
+                       cies.push_back(entry);
+                       p += cfiLength;
+               }
+               else {
+                       // is FDE
+                       FDE_Atom_Info entry;
+                       entry.fdeAddress = currentCFI;
+                       entry.function.address = 0;
+                       entry.cie.address = 0;
+                       entry.lsda.address = 0;
+                       pint_t nextCFI = p + cfiLength;
+                       uint32_t ciePointer = addressSpace.get32(p);
+                       pint_t cieStart = p-ciePointer;
+                       // validate pointer to CIE is within section
+                       if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) )
+                               return "FDE points to CIE outside __eh_frame section";
+                       CIE_Info cieInfo;
+                       const char* err = parseCIE(addressSpace, cieStart, &cieInfo);
+                       if ( err != NULL ) 
+                               return err;
+                       entry.cie.address = cieStart;
+                       entry.cie.offsetInFDE = p-currentCFI;
+                       entry.cie.encodingOfAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
+                       p += 4;
+                       // parse pc begin and range
+                       pint_t offsetOfFunctionAddress = p-currentCFI;
+                       pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
+                       pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
+                       //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+                       // test if pc is within the function this FDE covers
+                       entry.function.address = pcStart;
+                       entry.function.offsetInFDE = offsetOfFunctionAddress;
+                       entry.function.encodingOfAddress = cieInfo.pointerEncoding;
+                       // skip over augmentation length
+                       if ( cieInfo.fdesHaveAugmentationData ) {
+                               uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+                               pint_t endOfAug = p + augLen;
+                               if ( (cieInfo.lsdaEncoding != 0) && (addressSpace.getP(p) != 0) ) {
+                                       pint_t offsetOfLSDAAddress = p-currentCFI;
+                                       entry.lsda.address = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding);
+                                       entry.lsda.offsetInFDE = offsetOfLSDAAddress;
+                                       entry.lsda.encodingOfAddress = cieInfo.lsdaEncoding;
+                               }
+                               p = endOfAug;
+                       }
+                       fdes.push_back(entry);
+                       p = nextCFI;
+               }
+       }
+       return NULL; // success
+}
+
+       
+
+///
+/// "run" the dwarf instructions and create the abstact PrologInfo for an FDE
+///  
+template <typename A>
+bool CFI_Parser<A>::parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results)
+{
+       // clear results
+       bzero(results, sizeof(PrologInfo));
+       PrologInfoStackEntry* rememberStack = NULL;
+
+       // parse CIE then FDE instructions
+       return parseInstructions(addressSpace, cieInfo.cieInstructions, cieInfo.cieStart+cieInfo.cieLength, 
+                                               cieInfo, (pint_t)(-1), rememberStack, results)
+           && parseInstructions(addressSpace, fdeInfo.fdeInstructions, fdeInfo.fdeStart+fdeInfo.fdeLength, 
+                                                       cieInfo, upToPC-fdeInfo.pcStart, rememberStack, results);
+}
+
+
+///
+/// "run" the dwarf instructions
+///  
+template <typename A>
+bool CFI_Parser<A>::parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo,
+                                                                       pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results)
+{
+       const bool logDwarf = false;
+       pint_t p = instructions;
+       uint32_t codeOffset = 0;
+       PrologInfo initialState = *results;
+       if ( logDwarf ) fprintf(stderr, "parseInstructions(instructions=0x%0llX)\n", (uint64_t)instructionsEnd);
+       
+       // see Dwarf Spec, section 6.4.2 for details on unwind opcodes
+       while ( (p < instructionsEnd) && (codeOffset < pcoffset) ) {
+               uint64_t reg;
+               uint64_t reg2;
+               int64_t offset;
+               uint64_t length;
+               uint8_t opcode = addressSpace.get8(p);
+               uint8_t operand;
+               PrologInfoStackEntry* entry;
+               ++p;
+               switch (opcode) {
+                       case DW_CFA_nop:
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_nop\n");
+                               break;
+                       case DW_CFA_set_loc:
+                               codeOffset = addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_set_loc\n");
+                               break;
+                       case DW_CFA_advance_loc1:
+                               codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
+                               p += 1;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc1: new offset=%u\n", codeOffset);
+                               break;
+                       case DW_CFA_advance_loc2:
+                               codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
+                               p += 2;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc2: new offset=%u\n", codeOffset);
+                               break;
+                       case DW_CFA_advance_loc4:
+                               codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
+                               p += 4;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc4: new offset=%u\n", codeOffset);
+                               break;
+                       case DW_CFA_offset_extended:
+                               reg = addressSpace.getULEB128(p, instructionsEnd);
+                               offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+                               if ( reg > kMaxRegisterNumber ) {
+                                       fprintf(stderr, "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n");
+                                       return false;
+                               }
+                               if ( results->savedRegisters[reg].location != kRegisterUnused ) 
+                                       results->registerSavedMoreThanOnce = true;
+                               results->savedRegisters[reg].location = kRegisterInCFA;
+                               results->savedRegisters[reg].value = offset;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended(reg=%lld, offset=%lld)\n", reg, offset);
+                               break;
+                       case DW_CFA_restore_extended:
+                               reg = addressSpace.getULEB128(p, instructionsEnd);;
+                               if ( reg > kMaxRegisterNumber ) {
+                                       fprintf(stderr, "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n");
+                                       return false;
+                               }
+                               results->savedRegisters[reg] = initialState.savedRegisters[reg];
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_extended(reg=%lld)\n", reg);
+                               break;
+                       case DW_CFA_undefined:
+                               reg = addressSpace.getULEB128(p, instructionsEnd);
+                               if ( reg > kMaxRegisterNumber ) {
+                                       fprintf(stderr, "malformed DW_CFA_undefined dwarf unwind, reg too big\n");
+                                       return false;
+                               }
+                               results->savedRegisters[reg].location = kRegisterUnused;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_undefined(reg=%lld)\n", reg);
+                               break;
+                       case DW_CFA_same_value:
+                               reg = addressSpace.getULEB128(p, instructionsEnd);
+                               if ( reg > kMaxRegisterNumber ) {
+                                       fprintf(stderr, "malformed DW_CFA_same_value dwarf unwind, reg too big\n");
+                                       return false;
+                               }
+                               // <rdar://problem/8456377> DW_CFA_same_value unsupported
+                               // "same value" means register was stored in frame, but its current
+                               // value has not changed, so no need to restore from frame.
+                               // We model this as if the register was never saved.
+                               results->savedRegisters[reg].location = kRegisterUnused;
+                               // set flag to disable conversion to compact unwind
+                               results->sameValueUsed = true;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_same_value(reg=%lld)\n", reg);
+                               break;
+                       case DW_CFA_register:
+                               reg = addressSpace.getULEB128(p, instructionsEnd);
+                               reg2 = addressSpace.getULEB128(p, instructionsEnd);
+                               if ( reg > kMaxRegisterNumber ) {
+                                       fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg too big\n");
+                                       return false;
+                               }
+                               if ( reg2 > kMaxRegisterNumber ) {
+                                       fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg2 too big\n");
+                                       return false;
+                               }
+                               results->savedRegisters[reg].location = kRegisterInRegister;
+                               results->savedRegisters[reg].value = reg2;
+                               // set flag to disable conversion to compact unwind
+                               results->registersInOtherRegisters = true;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_register(reg=%lld, reg2=%lld)\n", reg, reg2);
+                               break;
+                       case DW_CFA_remember_state:
+                               // avoid operator new, because that would be an upward dependency
+                               entry = (PrologInfoStackEntry*)malloc(sizeof(PrologInfoStackEntry));
+                               if ( entry != NULL ) {
+                                       entry->next = rememberStack;
+                                       entry->info = *results;
+                                       rememberStack = entry;
+                               }
+                               else {
+                                       return false;
+                               }
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_remember_state\n");
+                               break;
+                       case DW_CFA_restore_state:
+                               if ( rememberStack != NULL ) {
+                                       PrologInfoStackEntry* top = rememberStack;
+                                       *results = top->info;
+                                       rememberStack = top->next;
+                                       free((char*)top);
+                               }
+                               else {
+                                       return false;
+                               }
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_state\n");
+                               break;
+                       case DW_CFA_def_cfa:
+                               reg = addressSpace.getULEB128(p, instructionsEnd);
+                               offset = addressSpace.getULEB128(p, instructionsEnd);
+                               if ( reg > kMaxRegisterNumber ) {
+                                       fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n");
+                                       return false;
+                               }
+                               results->cfaRegister = reg;
+                               results->cfaRegisterOffset = offset;
+                               if ( offset > 0x80000000 ) 
+                                       results->cfaOffsetWasNegative = true;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa(reg=%lld, offset=%lld)\n", reg, offset);
+                               break;
+                       case DW_CFA_def_cfa_register:
+                               reg = addressSpace.getULEB128(p, instructionsEnd);
+                               if ( reg > kMaxRegisterNumber ) {
+                                       fprintf(stderr, "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n");
+                                       return false;
+                               }
+                               results->cfaRegister = reg;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_register(%lld)\n", reg);
+                               break;
+                       case DW_CFA_def_cfa_offset:
+                               results->cfaRegisterOffset = addressSpace.getULEB128(p, instructionsEnd);
+                               results->codeOffsetAtStackDecrement = codeOffset;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", results->cfaRegisterOffset);
+                               break;
+                       case DW_CFA_def_cfa_expression:
+                               results->cfaRegister = 0;
+                               results->cfaExpression = p;
+                               length = addressSpace.getULEB128(p, instructionsEnd);
+                               p += length;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%llX, length=%llu)\n", 
+                                                                                                       results->cfaExpression, length);
+                               break;
+                       case DW_CFA_expression:
+                               reg = addressSpace.getULEB128(p, instructionsEnd);
+                               if ( reg > kMaxRegisterNumber ) {
+                                       fprintf(stderr, "malformed DW_CFA_expression dwarf unwind, reg too big\n");
+                                       return false;
+                               }
+                               results->savedRegisters[reg].location = kRegisterAtExpression;
+                               results->savedRegisters[reg].value = p;
+                               length = addressSpace.getULEB128(p, instructionsEnd);
+                               p += length;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_expression(reg=%lld, expression=0x%llX, length=%llu)\n", 
+                                                                                                       reg, results->savedRegisters[reg].value, length);
+                               break;
+                       case DW_CFA_offset_extended_sf:
+                               reg = addressSpace.getULEB128(p, instructionsEnd);
+                               if ( reg > kMaxRegisterNumber ) {
+                                       fprintf(stderr, "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n");
+                                       return false;
+                               }
+                               offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+                               if ( results->savedRegisters[reg].location != kRegisterUnused ) 
+                                       results->registerSavedMoreThanOnce = true;
+                               results->savedRegisters[reg].location = kRegisterInCFA;
+                               results->savedRegisters[reg].value = offset;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%lld, offset=%lld)\n", reg, offset);
+                               break;
+                       case DW_CFA_def_cfa_sf:
+                               reg = addressSpace.getULEB128(p, instructionsEnd);
+                               offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+                               if ( reg > kMaxRegisterNumber ) {
+                                       fprintf(stderr, "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n");
+                                       return false;
+                               }
+                               results->cfaRegister = reg;
+                               results->cfaRegisterOffset = offset;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_sf(reg=%lld, offset=%lld)\n", reg, offset);
+                               break;
+                       case DW_CFA_def_cfa_offset_sf:
+                               results->cfaRegisterOffset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+                               results->codeOffsetAtStackDecrement = codeOffset;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", results->cfaRegisterOffset);
+                               break;
+                       case DW_CFA_val_offset:
+                               reg = addressSpace.getULEB128(p, instructionsEnd);
+                               offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+                               results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
+                               results->savedRegisters[reg].value = offset;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset(reg=%lld, offset=%lld\n", reg, offset);
+                               break;
+                       case DW_CFA_val_offset_sf:
+                               reg = addressSpace.getULEB128(p, instructionsEnd);
+                               if ( reg > kMaxRegisterNumber ) {
+                                       fprintf(stderr, "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n");
+                                       return false;
+                               }
+                               offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+                               results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
+                               results->savedRegisters[reg].value = offset;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset_sf(reg=%lld, offset=%lld\n", reg, offset);
+                               break;
+                       case DW_CFA_val_expression:
+                               reg = addressSpace.getULEB128(p, instructionsEnd);
+                               if ( reg > kMaxRegisterNumber ) {
+                                       fprintf(stderr, "malformed DW_CFA_val_expression dwarf unwind, reg too big\n");
+                                       return false;
+                               }
+                               results->savedRegisters[reg].location = kRegisterIsExpression;
+                               results->savedRegisters[reg].value = p;
+                               length = addressSpace.getULEB128(p, instructionsEnd);
+                               p += length;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_val_expression(reg=%lld, expression=0x%llX, length=%lld)\n", 
+                                                                                                       reg, results->savedRegisters[reg].value, length);
+                               break;
+                       case DW_CFA_GNU_args_size:
+                               offset = addressSpace.getULEB128(p, instructionsEnd);
+                               results->spExtraArgSize = offset;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_args_size(%lld)\n", offset);
+                               break;
+                       case DW_CFA_GNU_negative_offset_extended:
+                               reg = addressSpace.getULEB128(p, instructionsEnd);
+                               if ( reg > kMaxRegisterNumber ) {
+                                       fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf unwind, reg too big\n");
+                                       return false;
+                               }
+                               offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+                               if ( results->savedRegisters[reg].location != kRegisterUnused ) 
+                                       results->registerSavedMoreThanOnce = true;
+                               results->savedRegisters[reg].location = kRegisterInCFA;
+                               results->savedRegisters[reg].value = -offset;
+                               if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%lld)\n", offset);
+                               break;
+                       default:
+                               operand = opcode & 0x3F;
+                               switch ( opcode & 0xC0 ) {
+                                       case DW_CFA_offset:
+                                               reg = operand;
+                                               offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+                                               if ( results->savedRegisters[reg].location != kRegisterUnused ) {
+                                                       // look for idiom of PC saved twice in CIE to mean disable compact unwind encoding
+                                                       if ( (pcoffset == (pint_t)(-1)) 
+                                                               && (results->savedRegisters[reg].location == kRegisterInCFA) 
+                                                               && (results->savedRegisters[reg].value == offset)  )
+                                                               results->registerSavedTwiceInCIE = reg;
+                                                       else
+                                                               results->registerSavedMoreThanOnce = true;
+                                               }
+                                               results->savedRegisters[reg].location = kRegisterInCFA;
+                                               results->savedRegisters[reg].value = offset;
+                                               if ( logDwarf ) fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%lld)\n", operand, offset);
+                                               break;
+                                       case DW_CFA_advance_loc:
+                                               codeOffset += operand * cieInfo.codeAlignFactor;
+                                               if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc: new offset=%u\n", codeOffset);
+                                               break;
+                                       case DW_CFA_restore:
+                                               // <rdar://problem/7503075> Python crashes when handling an exception thrown by an obj-c object
+                                               // libffi uses DW_CFA_restore in the middle of some custom dwarf, so it is not a good epilog flag
+                                               //return true; // gcc-4.5 starts the epilog with this
+                                               reg = operand;
+                                               results->savedRegisters[reg] = initialState.savedRegisters[reg];
+                                               if ( logDwarf ) fprintf(stderr, "DW_CFA_restore(reg=%lld)\n", reg);
+                                               break;
+                                       default: 
+                                               if ( logDwarf ) fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
+                                               return false;
+                               }
+               }
+       }
+
+       return true;
+}
+
+
+} // namespace libunwind 
+
+
+#endif // __DWARF_PARSER_HPP__
+
+
+
+
diff --git a/src/ld/parsers/libunwind/InternalMacros.h b/src/ld/parsers/libunwind/InternalMacros.h
new file mode 100644 (file)
index 0000000..25c1631
--- /dev/null
@@ -0,0 +1,105 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef INTERNAL_MACROS_H
+#define INTERNAL_MACROS_H
+
+#include <assert.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+       extern void __assert_rtn(const char *, const char *, int, const char *) __attribute__((noreturn));
+#ifdef __cplusplus
+}
+#endif
+
+#define UNW_STEP_SUCCESS 1
+#define UNW_STEP_END     0
+
+
+struct v128 { unsigned int vec[4]; };
+
+
+#define EXPORT __attribute__((visibility("default"))) 
+
+#define COMPILE_TIME_ASSERT( expr )    \
+               extern int compile_time_assert_failed[ ( expr ) ? 1 : -1 ] __attribute__( ( unused ) );
+
+#define ABORT(msg) __assert_rtn(__func__, __FILE__, __LINE__, msg) 
+
+#if NDEBUG
+       #define DEBUG_MESSAGE(msg, ...)  
+       #define DEBUG_PRINT_API(msg, ...)
+       #define DEBUG_PRINT_UNWINDING_TEST 0
+       #define DEBUG_PRINT_UNWINDING(msg, ...)
+       #define DEBUG_LOG_NON_ZERO(x) x;
+       #define INITIALIZE_DEBUG_PRINT_API
+       #define INITIALIZE_DEBUG_PRINT_UNWINDING
+#else
+       #define DEBUG_MESSAGE(msg, ...)  fprintf(stderr, "libuwind: " msg, __VA_ARGS__)
+       #ifdef __cplusplus
+               extern "C" {
+       #endif
+               extern  bool logAPIs();
+               extern  bool logUnwinding();
+       #ifdef __cplusplus
+               }
+       #endif
+       #define DEBUG_LOG_NON_ZERO(x) { int _err = x; if ( _err != 0 ) fprintf(stderr, "libuwind: " #x "=%d in %s", _err, __FUNCTION__); }
+       #define DEBUG_PRINT_API(msg, ...) do { if ( logAPIs() ) fprintf(stderr,  msg, __VA_ARGS__); } while(0)
+       #define DEBUG_PRINT_UNWINDING(msg, ...) do { if ( logUnwinding() ) fprintf(stderr,  msg, __VA_ARGS__); } while(0)
+       #define DEBUG_PRINT_UNWINDING_TEST logUnwinding()
+       #define INITIALIZE_DEBUG_PRINT_API bool logAPIs() { static bool log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); return log; }
+       #define INITIALIZE_DEBUG_PRINT_UNWINDING bool logUnwinding() { static bool log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); return log; }
+#endif
+
+
+// note hack for <rdar://problem/6175741>
+// Once libgcc_s.dylib vectors to libSystem, then we can remove the $ld$hide$os10.6$ lines
+#if __ppc__
+       #define NOT_HERE_BEFORE_10_6(sym) \
+               extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
+               extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+               extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0; 
+       #define NEVER_HERE(sym) \
+               extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
+               extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+               extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
+               extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
+#else
+       #define NOT_HERE_BEFORE_10_6(sym) \
+               extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+               extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0; 
+       #define NEVER_HERE(sym) \
+               extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+               extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
+               extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
+#endif
+
+
+
+#endif // INTERNAL_MACROS_H
diff --git a/src/ld/parsers/libunwind/Registers.hpp b/src/ld/parsers/libunwind/Registers.hpp
new file mode 100644 (file)
index 0000000..7d39fd7
--- /dev/null
@@ -0,0 +1,1050 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007-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@
+ */
+//
+//     C++ interface to lower levels of libuwind 
+//
+
+#ifndef __REGISTERS_HPP__
+#define __REGISTERS_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <mach-o/loader.h>
+#include <mach-o/getsect.h>
+#include <mach/i386/thread_status.h>
+
+#include "libunwind.h"
+#include "InternalMacros.h"
+
+namespace libunwind {
+
+
+///
+/// Registers_x86 holds the register state of a thread in a 32-bit intel process.  
+///
+class Registers_x86
+{
+public:        
+                                       Registers_x86();
+                                       Registers_x86(const void* registers);
+
+       bool                    validRegister(int num) const;
+       uint32_t                getRegister(int num) const;
+       void                    setRegister(int num, uint32_t value);
+       bool                    validFloatRegister(int num) const { return false; }
+       double                  getFloatRegister(int num) const;
+       void                    setFloatRegister(int num, double value); 
+       bool                    validVectorRegister(int num) const { return false; }
+       v128                    getVectorRegister(int num) const;
+       void                    setVectorRegister(int num, v128 value);
+       const char*             getRegisterName(int num);
+       void                    jumpto();
+       
+       uint32_t                getSP() const                   { return fRegisters.__esp; }
+       void                    setSP(uint32_t value)   { fRegisters.__esp = value; }
+       uint32_t                getIP() const                   { return fRegisters.__eip; }
+       void                    setIP(uint32_t value)   { fRegisters.__eip = value; }
+       uint32_t                getEBP() const                  { return fRegisters.__ebp; }
+       void                    setEBP(uint32_t value)  { fRegisters.__ebp = value; }
+       uint32_t                getEBX() const                  { return fRegisters.__ebx; }
+       void                    setEBX(uint32_t value)  { fRegisters.__ebx = value; }
+       uint32_t                getECX() const                  { return fRegisters.__ecx; }
+       void                    setECX(uint32_t value)  { fRegisters.__ecx = value; }
+       uint32_t                getEDX() const                  { return fRegisters.__edx; }
+       void                    setEDX(uint32_t value)  { fRegisters.__edx = value; }
+       uint32_t                getESI() const                  { return fRegisters.__esi; }
+       void                    setESI(uint32_t value)  { fRegisters.__esi = value; }
+       uint32_t                getEDI() const                  { return fRegisters.__edi; }
+       void                    setEDI(uint32_t value)  { fRegisters.__edi = value; }
+       
+private:
+       i386_thread_state_t  fRegisters;
+};
+
+inline Registers_x86::Registers_x86(const void* registers)
+{
+       COMPILE_TIME_ASSERT( sizeof(Registers_x86) < sizeof(unw_context_t) );
+       fRegisters = *((i386_thread_state_t*)registers); 
+}
+
+inline Registers_x86::Registers_x86()
+{
+       bzero(&fRegisters, sizeof(fRegisters)); 
+}
+
+
+inline bool Registers_x86::validRegister(int regNum) const
+{
+       if ( regNum == UNW_REG_IP )
+               return true;
+       if ( regNum == UNW_REG_SP )
+               return true;
+       if ( regNum < 0 )
+               return false;
+       if ( regNum > 7 )
+               return false;
+       return true;
+}
+
+inline uint32_t Registers_x86::getRegister(int regNum) const
+{
+       switch ( regNum ) {
+               case UNW_REG_IP:
+                       return fRegisters.__eip;
+               case UNW_REG_SP:
+                       return fRegisters.__esp;
+               case UNW_X86_EAX:
+                       return fRegisters.__eax;
+               case UNW_X86_ECX:
+                       return fRegisters.__ecx;
+               case UNW_X86_EDX:
+                       return fRegisters.__edx;
+               case UNW_X86_EBX:
+                       return fRegisters.__ebx;
+               case UNW_X86_EBP:
+                       return fRegisters.__ebp;
+               case UNW_X86_ESP:
+                       return fRegisters.__esp;
+               case UNW_X86_ESI:
+                       return fRegisters.__esi;
+               case UNW_X86_EDI:
+                       return fRegisters.__edi;
+       }
+       ABORT("unsupported x86 register");
+}
+
+inline void Registers_x86::setRegister(int regNum, uint32_t value)
+{
+       switch ( regNum ) {
+               case UNW_REG_IP:
+                       fRegisters.__eip = value;
+                       return;
+               case UNW_REG_SP:
+                       fRegisters.__esp = value;
+                       return;
+               case UNW_X86_EAX:
+                       fRegisters.__eax = value;
+                       return;
+               case UNW_X86_ECX:
+                       fRegisters.__ecx = value;
+                       return;
+               case UNW_X86_EDX:
+                       fRegisters.__edx = value;
+                       return;
+               case UNW_X86_EBX:
+                       fRegisters.__ebx = value;
+                       return;
+               case UNW_X86_EBP:
+                       fRegisters.__ebp = value;
+                       return;
+               case UNW_X86_ESP:
+                       fRegisters.__esp = value;
+                       return;
+               case UNW_X86_ESI:
+                       fRegisters.__esi = value;
+                       return;
+               case UNW_X86_EDI:
+                       fRegisters.__edi = value;
+                       return;
+       }
+       ABORT("unsupported x86 register");
+}
+
+inline const char* Registers_x86::getRegisterName(int regNum)
+{
+       switch ( regNum ) {
+               case UNW_REG_IP:
+                       return "ip";
+               case UNW_REG_SP:
+                       return "esp";
+               case UNW_X86_EAX:
+                       return "eax";
+               case UNW_X86_ECX:
+                       return "ecx";
+               case UNW_X86_EDX:
+                       return "edx";
+               case UNW_X86_EBX:
+                       return "ebx";
+               case UNW_X86_EBP:
+                       return "ebp";
+               case UNW_X86_ESP:
+                       return "esp";
+               case UNW_X86_ESI:
+                       return "esi";
+               case UNW_X86_EDI:
+                       return "edi";
+               default:
+                       return "unknown register";
+       }
+}
+
+inline double Registers_x86::getFloatRegister(int num) const
+{
+       ABORT("no x86 float registers");
+}
+
+inline void Registers_x86::setFloatRegister(int num, double value)
+{
+       ABORT("no x86 float registers");
+}
+
+inline v128 Registers_x86::getVectorRegister(int num) const
+{
+       ABORT("no x86 vector registers");
+}
+
+inline void Registers_x86::setVectorRegister(int num, v128 value)
+{
+       ABORT("no x86 vector registers");
+}
+
+
+
+
+///
+/// Registers_x86_64  holds the register state of a thread in a 64-bit intel process.  
+///
+class Registers_x86_64
+{
+public:        
+                                       Registers_x86_64();
+                                       Registers_x86_64(const void* registers); 
+
+       bool                    validRegister(int num) const;
+       uint64_t                getRegister(int num) const;
+       void                    setRegister(int num, uint64_t value);
+       bool                    validFloatRegister(int num) const{ return false; }
+       double                  getFloatRegister(int num) const;
+       void                    setFloatRegister(int num, double value);
+       bool                    validVectorRegister(int num) const { return false; }
+       v128                    getVectorRegister(int num) const;
+       void                    setVectorRegister(int num, v128 value);
+       const char*             getRegisterName(int num);
+       void                    jumpto();
+       uint64_t                getSP() const                   { return fRegisters.__rsp; }
+       void                    setSP(uint64_t value)   { fRegisters.__rsp = value; }
+       uint64_t                getIP() const                   { return fRegisters.__rip; }
+       void                    setIP(uint64_t value)   { fRegisters.__rip = value; }
+       uint64_t                getRBP() const                  { return fRegisters.__rbp; }
+       void                    setRBP(uint64_t value)  { fRegisters.__rbp = value; }
+       uint64_t                getRBX() const                  { return fRegisters.__rbx; }
+       void                    setRBX(uint64_t value)  { fRegisters.__rbx = value; }
+       uint64_t                getR12() const                  { return fRegisters.__r12; }
+       void                    setR12(uint64_t value)  { fRegisters.__r12 = value; }
+       uint64_t                getR13() const                  { return fRegisters.__r13; }
+       void                    setR13(uint64_t value)  { fRegisters.__r13 = value; }
+       uint64_t                getR14() const                  { return fRegisters.__r14; }
+       void                    setR14(uint64_t value)  { fRegisters.__r14 = value; }
+       uint64_t                getR15() const                  { return fRegisters.__r15; }
+       void                    setR15(uint64_t value)  { fRegisters.__r15 = value; }
+private:
+       x86_thread_state64_t fRegisters;
+};
+
+inline Registers_x86_64::Registers_x86_64(const void* registers)
+{
+       COMPILE_TIME_ASSERT( sizeof(Registers_x86_64) < sizeof(unw_context_t) );
+       fRegisters = *((x86_thread_state64_t*)registers); 
+}
+
+inline Registers_x86_64::Registers_x86_64()
+{
+       bzero(&fRegisters, sizeof(fRegisters)); 
+}
+
+
+inline bool Registers_x86_64::validRegister(int regNum) const
+{
+       if ( regNum == UNW_REG_IP )
+               return true;
+       if ( regNum == UNW_REG_SP )
+               return true;
+       if ( regNum < 0 )
+               return false;
+       if ( regNum > 15 )
+               return false;
+       return true;
+}
+
+inline uint64_t Registers_x86_64::getRegister(int regNum) const
+{
+       switch ( regNum ) {
+               case UNW_REG_IP:
+                       return fRegisters.__rip;
+               case UNW_REG_SP:
+                       return fRegisters.__rsp;
+               case UNW_X86_64_RAX:
+                       return fRegisters.__rax;
+               case UNW_X86_64_RDX:
+                       return fRegisters.__rdx;
+               case UNW_X86_64_RCX:
+                       return fRegisters.__rcx;
+               case UNW_X86_64_RBX:
+                       return fRegisters.__rbx;
+               case UNW_X86_64_RSI:
+                       return fRegisters.__rsi;
+               case UNW_X86_64_RDI:
+                       return fRegisters.__rdi;
+               case UNW_X86_64_RBP:
+                       return fRegisters.__rbp;
+               case UNW_X86_64_RSP:
+                       return fRegisters.__rsp;
+               case UNW_X86_64_R8:
+                       return fRegisters.__r8;
+               case UNW_X86_64_R9:
+                       return fRegisters.__r9;
+               case UNW_X86_64_R10:
+                       return fRegisters.__r10;
+               case UNW_X86_64_R11:
+                       return fRegisters.__r11;
+               case UNW_X86_64_R12:
+                       return fRegisters.__r12;
+               case UNW_X86_64_R13:
+                       return fRegisters.__r13;
+               case UNW_X86_64_R14:
+                       return fRegisters.__r14;
+               case UNW_X86_64_R15:
+                       return fRegisters.__r15;
+       }
+       ABORT("unsupported x86_64 register");
+}
+
+inline void Registers_x86_64::setRegister(int regNum, uint64_t value)
+{
+       switch ( regNum ) {
+               case UNW_REG_IP:
+                       fRegisters.__rip = value;
+                       return;
+               case UNW_REG_SP:
+                       fRegisters.__rsp = value;
+                       return;
+               case UNW_X86_64_RAX:
+                       fRegisters.__rax = value;
+                       return;
+               case UNW_X86_64_RDX:
+                       fRegisters.__rdx = value;
+                       return;
+               case UNW_X86_64_RCX:
+                       fRegisters.__rcx = value;
+                       return;
+               case UNW_X86_64_RBX:
+                       fRegisters.__rbx = value;
+                       return;
+               case UNW_X86_64_RSI:
+                       fRegisters.__rsi = value;
+                       return;
+               case UNW_X86_64_RDI:
+                       fRegisters.__rdi = value;
+                       return;
+               case UNW_X86_64_RBP:
+                       fRegisters.__rbp = value;
+                       return;
+               case UNW_X86_64_RSP:
+                       fRegisters.__rsp = value;
+                       return;
+               case UNW_X86_64_R8:
+                       fRegisters.__r8 = value;
+                       return;
+               case UNW_X86_64_R9:
+                       fRegisters.__r9 = value;
+                       return;
+               case UNW_X86_64_R10:
+                       fRegisters.__r10 = value;
+                       return;
+               case UNW_X86_64_R11:
+                       fRegisters.__r11 = value;
+                       return;
+               case UNW_X86_64_R12:
+                       fRegisters.__r12 = value;
+                       return;
+               case UNW_X86_64_R13:
+                       fRegisters.__r13 = value;
+                       return;
+               case UNW_X86_64_R14:
+                       fRegisters.__r14 = value;
+                       return;
+               case UNW_X86_64_R15:
+                       fRegisters.__r15 = value;
+                       return;
+       }
+       ABORT("unsupported x86_64 register");
+}
+
+inline const char* Registers_x86_64::getRegisterName(int regNum)
+{
+       switch ( regNum ) {
+               case UNW_REG_IP:
+                       return "rip";
+               case UNW_REG_SP:
+                       return "rsp";
+               case UNW_X86_64_RAX:
+                       return "rax";
+               case UNW_X86_64_RDX:
+                       return "rdx";
+               case UNW_X86_64_RCX:
+                       return "rcx";
+               case UNW_X86_64_RBX:
+                       return "rbx";
+               case UNW_X86_64_RSI:
+                       return "rsi";
+               case UNW_X86_64_RDI:
+                       return "rdi";
+               case UNW_X86_64_RBP:
+                       return "rbp";
+               case UNW_X86_64_RSP:
+                       return "rsp";
+               case UNW_X86_64_R8:
+                       return "r8";
+               case UNW_X86_64_R9:
+                       return "r9";
+               case UNW_X86_64_R10:
+                       return "r10";
+               case UNW_X86_64_R11:
+                       return "r11";
+               case UNW_X86_64_R12:
+                       return "r12";
+               case UNW_X86_64_R13:
+                       return "r13";
+               case UNW_X86_64_R14:
+                       return "r14";
+               case UNW_X86_64_R15:
+                       return "r15";
+               default:
+                       return "unknown register";
+       }
+}
+
+double Registers_x86_64::getFloatRegister(int num) const
+{
+       ABORT("no x86_64 float registers");
+}
+
+void Registers_x86_64::setFloatRegister(int num, double value)
+{
+       ABORT("no x86_64 float registers");
+}
+
+inline v128 Registers_x86_64::getVectorRegister(int num) const
+{
+       ABORT("no x86_64 vector registers");
+}
+
+inline void Registers_x86_64::setVectorRegister(int num, v128 value)
+{
+       ABORT("no x86_64 vector registers");
+}
+
+
+///
+/// Registers_ppc holds the register state of a thread in a 32-bit PowerPC process.  
+///
+class Registers_ppc
+{
+public:        
+                                       Registers_ppc();
+                                       Registers_ppc(const void* registers);
+
+       bool                    validRegister(int num) const;
+       uint32_t                getRegister(int num) const;
+       void                    setRegister(int num, uint32_t value);
+       bool                    validFloatRegister(int num) const;
+       double                  getFloatRegister(int num) const;
+       void                    setFloatRegister(int num, double value);
+       bool                    validVectorRegister(int num) const;
+       v128                    getVectorRegister(int num) const;
+       void                    setVectorRegister(int num, v128 value);
+       void                    jumpto();
+       const char*             getRegisterName(int num);
+       uint64_t                getSP() const                   { return fRegisters.__r1; }
+       void                    setSP(uint64_t value)   { fRegisters.__r1 = value; }
+       uint64_t                getIP() const                   { return fRegisters.__srr0; }
+       void                    setIP(uint64_t value)   { fRegisters.__srr0 = value; }
+private:
+       struct ppc_thread_state_t
+       {
+               unsigned int __srr0;    /* Instruction address register (PC) */
+               unsigned int __srr1;    /* Machine state register (supervisor) */
+               unsigned int __r0;
+               unsigned int __r1;
+               unsigned int __r2;
+               unsigned int __r3;
+               unsigned int __r4;
+               unsigned int __r5;
+               unsigned int __r6;
+               unsigned int __r7;
+               unsigned int __r8;
+               unsigned int __r9;
+               unsigned int __r10;
+               unsigned int __r11;
+               unsigned int __r12;
+               unsigned int __r13;
+               unsigned int __r14;
+               unsigned int __r15;
+               unsigned int __r16;
+               unsigned int __r17;
+               unsigned int __r18;
+               unsigned int __r19;
+               unsigned int __r20;
+               unsigned int __r21;
+               unsigned int __r22;
+               unsigned int __r23;
+               unsigned int __r24;
+               unsigned int __r25;
+               unsigned int __r26;
+               unsigned int __r27;
+               unsigned int __r28;
+               unsigned int __r29;
+               unsigned int __r30;
+               unsigned int __r31;
+               unsigned int __cr;      /* Condition register */
+               unsigned int __xer;     /* User's integer exception register */
+               unsigned int __lr;      /* Link register */
+               unsigned int __ctr;     /* Count register */
+               unsigned int __mq;      /* MQ register (601 only) */
+               unsigned int __vrsave;  /* Vector Save Register */
+       };
+       
+       struct ppc_float_state_t
+       {
+               double  __fpregs[32];
+
+               unsigned int __fpscr_pad; /* fpscr is 64 bits, 32 bits of rubbish */
+               unsigned int __fpscr;   /* floating point status register */
+       };
+
+       ppc_thread_state_t      fRegisters;
+       ppc_float_state_t       fFloatRegisters;
+       v128                            fVectorRegisters[32];   // offset 424 
+};
+
+
+
+inline Registers_ppc::Registers_ppc(const void* registers) 
+{
+       COMPILE_TIME_ASSERT( sizeof(Registers_ppc) < sizeof(unw_context_t) );
+       fRegisters = *((ppc_thread_state_t*)registers); 
+       fFloatRegisters = *((ppc_float_state_t*)((char*)registers+160));
+       memcpy(fVectorRegisters, ((char*)registers+424), sizeof(fVectorRegisters));
+}
+
+inline Registers_ppc::Registers_ppc() 
+{ 
+       bzero(&fRegisters, sizeof(fRegisters)); 
+       bzero(&fFloatRegisters, sizeof(fFloatRegisters)); 
+       bzero(&fVectorRegisters, sizeof(fVectorRegisters)); 
+}
+
+
+inline bool Registers_ppc::validRegister(int regNum) const
+{
+       if ( regNum == UNW_REG_IP )
+               return true;
+       if ( regNum == UNW_REG_SP )
+               return true;
+       if ( regNum == UNW_PPC_VRSAVE )
+               return true;
+       if ( regNum < 0 )
+               return false;
+       if ( regNum <= UNW_PPC_R31 )
+               return true;
+       if ( regNum == UNW_PPC_MQ )
+               return true;
+       if ( regNum == UNW_PPC_LR )
+               return true;
+       if ( regNum == UNW_PPC_CTR )
+               return true;
+       if ( (UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7) )
+               return true;
+       return false;
+}
+
+
+inline uint32_t Registers_ppc::getRegister(int regNum) const
+{
+       switch ( regNum ) {
+               case UNW_REG_IP:
+                       return fRegisters.__srr0;
+               case UNW_REG_SP:
+                       return fRegisters.__r1;
+               case UNW_PPC_R0:
+                       return fRegisters.__r0;
+               case UNW_PPC_R1:
+                       return fRegisters.__r1;
+               case UNW_PPC_R2:
+                       return fRegisters.__r2;
+               case UNW_PPC_R3:
+                       return fRegisters.__r3;
+               case UNW_PPC_R4:
+                       return fRegisters.__r4;
+               case UNW_PPC_R5:
+                       return fRegisters.__r5;
+               case UNW_PPC_R6:
+                       return fRegisters.__r6;
+               case UNW_PPC_R7:
+                       return fRegisters.__r7;
+               case UNW_PPC_R8:
+                       return fRegisters.__r8;
+               case UNW_PPC_R9:
+                       return fRegisters.__r9;
+               case UNW_PPC_R10:
+                       return fRegisters.__r10;
+               case UNW_PPC_R11:
+                       return fRegisters.__r11;
+               case UNW_PPC_R12:
+                       return fRegisters.__r12;
+               case UNW_PPC_R13:
+                       return fRegisters.__r13;
+               case UNW_PPC_R14:
+                       return fRegisters.__r14;
+               case UNW_PPC_R15:
+                       return fRegisters.__r15;
+               case UNW_PPC_R16:
+                       return fRegisters.__r16;
+               case UNW_PPC_R17:
+                       return fRegisters.__r17;
+               case UNW_PPC_R18:
+                       return fRegisters.__r18;
+               case UNW_PPC_R19:
+                       return fRegisters.__r19;
+               case UNW_PPC_R20:
+                       return fRegisters.__r20;
+               case UNW_PPC_R21:
+                       return fRegisters.__r21;
+               case UNW_PPC_R22:
+                       return fRegisters.__r22;
+               case UNW_PPC_R23:
+                       return fRegisters.__r23;
+               case UNW_PPC_R24:
+                       return fRegisters.__r24;
+               case UNW_PPC_R25:
+                       return fRegisters.__r25;
+               case UNW_PPC_R26:
+                       return fRegisters.__r26;
+               case UNW_PPC_R27:
+                       return fRegisters.__r27;
+               case UNW_PPC_R28:
+                       return fRegisters.__r28;
+               case UNW_PPC_R29:
+                       return fRegisters.__r29;
+               case UNW_PPC_R30:
+                       return fRegisters.__r30;
+               case UNW_PPC_R31:
+                       return fRegisters.__r31;
+               case UNW_PPC_LR:
+                       return fRegisters.__lr;
+               case UNW_PPC_CR0:
+                       return (fRegisters.__cr & 0xF0000000);
+               case UNW_PPC_CR1:
+                       return (fRegisters.__cr & 0x0F000000);
+               case UNW_PPC_CR2:
+                       return (fRegisters.__cr & 0x00F00000);
+               case UNW_PPC_CR3:
+                       return (fRegisters.__cr & 0x000F0000);
+               case UNW_PPC_CR4:
+                       return (fRegisters.__cr & 0x0000F000);
+               case UNW_PPC_CR5:
+                       return (fRegisters.__cr & 0x00000F00);
+               case UNW_PPC_CR6:
+                       return (fRegisters.__cr & 0x000000F0);
+               case UNW_PPC_CR7:
+                       return (fRegisters.__cr & 0x0000000F);
+               case UNW_PPC_VRSAVE:
+                       return fRegisters.__vrsave;
+       }
+       ABORT("unsupported ppc register");
+}
+
+
+inline void Registers_ppc::setRegister(int regNum, uint32_t value)
+{
+       //fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value);   
+       switch ( regNum ) {
+               case UNW_REG_IP:
+                       fRegisters.__srr0 = value;
+                       return;
+               case UNW_REG_SP:
+                       fRegisters.__r1 = value;
+                       return;
+               case UNW_PPC_R0:
+                       fRegisters.__r0 = value;
+                       return;
+               case UNW_PPC_R1:
+                       fRegisters.__r1 = value;
+                       return;
+               case UNW_PPC_R2:
+                       fRegisters.__r2 = value;
+                       return;
+               case UNW_PPC_R3:
+                       fRegisters.__r3 = value;
+                       return;
+               case UNW_PPC_R4:
+                       fRegisters.__r4 = value;
+                       return;
+               case UNW_PPC_R5:
+                       fRegisters.__r5 = value;
+                       return;
+               case UNW_PPC_R6:
+                       fRegisters.__r6 = value;
+                       return;
+               case UNW_PPC_R7:
+                       fRegisters.__r7 = value;
+                       return;
+               case UNW_PPC_R8:
+                       fRegisters.__r8 = value;
+                       return;
+               case UNW_PPC_R9:
+                       fRegisters.__r9 = value;
+                       return;
+               case UNW_PPC_R10:
+                       fRegisters.__r10 = value;
+                       return;
+               case UNW_PPC_R11:
+                       fRegisters.__r11 = value;
+                       return;
+               case UNW_PPC_R12:
+                       fRegisters.__r12 = value;
+                       return;
+               case UNW_PPC_R13:
+                       fRegisters.__r13 = value;
+                       return;
+               case UNW_PPC_R14:
+                       fRegisters.__r14 = value;
+                       return;
+               case UNW_PPC_R15:
+                       fRegisters.__r15 = value;
+                       return;
+               case UNW_PPC_R16:
+                       fRegisters.__r16 = value;
+                       return;
+               case UNW_PPC_R17:
+                       fRegisters.__r17 = value;
+                       return;
+               case UNW_PPC_R18:
+                       fRegisters.__r18 = value;
+                       return;
+               case UNW_PPC_R19:
+                       fRegisters.__r19 = value;
+                       return;
+               case UNW_PPC_R20:
+                       fRegisters.__r20 = value;
+                       return;
+               case UNW_PPC_R21:
+                       fRegisters.__r21 = value;
+                       return;
+               case UNW_PPC_R22:
+                       fRegisters.__r22 = value;
+                       return;
+               case UNW_PPC_R23:
+                       fRegisters.__r23 = value;
+                       return;
+               case UNW_PPC_R24:
+                       fRegisters.__r24 = value;
+                       return;
+               case UNW_PPC_R25:
+                       fRegisters.__r25 = value;
+                       return;
+               case UNW_PPC_R26:
+                       fRegisters.__r26 = value;
+                       return;
+               case UNW_PPC_R27:
+                       fRegisters.__r27 = value;
+                       return;
+               case UNW_PPC_R28:
+                       fRegisters.__r28 = value;
+                       return;
+               case UNW_PPC_R29:
+                       fRegisters.__r29 = value;
+                       return;
+               case UNW_PPC_R30:
+                       fRegisters.__r30 = value;
+                       return;
+               case UNW_PPC_R31:
+                       fRegisters.__r31 = value;
+                       return;
+               case UNW_PPC_MQ:
+                       fRegisters.__mq = value;
+                       return;
+               case UNW_PPC_LR:
+                       fRegisters.__lr = value;
+                       return;
+               case UNW_PPC_CTR:
+                       fRegisters.__ctr = value;
+                       return;
+               case UNW_PPC_CR0:
+                       fRegisters.__cr &= 0x0FFFFFFF;
+                       fRegisters.__cr |= (value & 0xF0000000);
+                       return;
+               case UNW_PPC_CR1:
+                       fRegisters.__cr &= 0xF0FFFFFF;
+                       fRegisters.__cr |= (value & 0x0F000000);
+                       return;
+               case UNW_PPC_CR2:
+                       fRegisters.__cr &= 0xFF0FFFFF;
+                       fRegisters.__cr |= (value & 0x00F00000);
+                       return;
+               case UNW_PPC_CR3:
+                       fRegisters.__cr &= 0xFFF0FFFF;
+                       fRegisters.__cr |= (value & 0x000F0000);
+                       return;
+               case UNW_PPC_CR4:
+                       fRegisters.__cr &= 0xFFFF0FFF;
+                       fRegisters.__cr |= (value & 0x0000F000);
+                       return;
+               case UNW_PPC_CR5:
+                       fRegisters.__cr &= 0xFFFFF0FF;
+                       fRegisters.__cr |= (value & 0x00000F00);
+                       return;
+               case UNW_PPC_CR6:
+                       fRegisters.__cr &= 0xFFFFFF0F;
+                       fRegisters.__cr |= (value & 0x000000F0);
+                       return;
+               case UNW_PPC_CR7:
+                       fRegisters.__cr &= 0xFFFFFFF0;
+                       fRegisters.__cr |= (value & 0x0000000F);
+                       return;
+               case UNW_PPC_VRSAVE:
+                       fRegisters.__vrsave = value;
+                       return;
+                       // not saved
+                       return;
+               case UNW_PPC_XER:
+                       fRegisters.__xer = value;
+                       return;
+               case UNW_PPC_AP:
+               case UNW_PPC_VSCR:
+               case UNW_PPC_SPEFSCR:
+                       // not saved
+                       return;
+       }
+       ABORT("unsupported ppc register");
+}
+
+inline bool Registers_ppc::validFloatRegister(int regNum) const
+{
+       if ( regNum < UNW_PPC_F0 )
+               return false;
+       if ( regNum > UNW_PPC_F31 )
+               return false;
+       return true;
+}
+
+inline double Registers_ppc::getFloatRegister(int regNum) const
+{
+       assert(validFloatRegister(regNum));
+       return fFloatRegisters.__fpregs[regNum-UNW_PPC_F0];
+}
+
+inline void Registers_ppc::setFloatRegister(int regNum, double value)
+{
+       //fprintf(stderr, "Registers_ppc::setFloatRegister(%d, %g))\n", regNum, value);
+       assert(validFloatRegister(regNum));
+       fFloatRegisters.__fpregs[regNum-UNW_PPC_F0] = value;
+}
+
+
+inline bool Registers_ppc::validVectorRegister(int regNum) const
+{
+       if ( regNum < UNW_PPC_V0 )
+               return false;
+       if ( regNum > UNW_PPC_V31 )
+               return false;
+       return true;
+}
+
+v128 Registers_ppc::getVectorRegister(int regNum) const
+{
+       assert(validVectorRegister(regNum));
+       v128 result = fVectorRegisters[regNum-UNW_PPC_V0];
+       //fprintf(stderr, "Registers_ppc::getVectorRegister(this=%p, %d) => <0x%08X, 0x%08X, 0x%08X, 0x%08X> \n", 
+       //              this, regNum, result.vec[0], result.vec[1], result.vec[2], result.vec[3]);
+       return result;
+}
+
+void Registers_ppc::setVectorRegister(int regNum, v128 value) 
+{
+       assert(validVectorRegister(regNum));
+       //fprintf(stderr, "Registers_ppc::setVectorRegister(this=%p, %d) <0x%08X, 0x%08X, 0x%08X, 0x%08X> => <0x%08X, 0x%08X, 0x%08X, 0x%08X> \n", 
+       //              this, regNum, fVectorRegisters[regNum-UNW_PPC_V0].vec[0], fVectorRegisters[regNum-UNW_PPC_V0].vec[1], fVectorRegisters[regNum-UNW_PPC_V0].vec[2], 
+       //                      fVectorRegisters[regNum-UNW_PPC_V0].vec[3], value.vec[0], value.vec[1], value.vec[2], value.vec[3]);
+       fVectorRegisters[regNum-UNW_PPC_V0] = value;
+}
+
+
+inline const char* Registers_ppc::getRegisterName(int regNum)
+{
+       switch ( regNum ) {
+               case UNW_REG_IP:
+                       return "ip";
+               case UNW_REG_SP:
+                       return "sp";
+               case UNW_PPC_R0:
+                       return "r0";
+               case UNW_PPC_R1:
+                       return "r1";
+               case UNW_PPC_R2:
+                       return "r2";
+               case UNW_PPC_R3:
+                       return "r3";
+               case UNW_PPC_R4:
+                       return "r4";
+               case UNW_PPC_R5:
+                       return "r5";
+               case UNW_PPC_R6:
+                       return "r6";
+               case UNW_PPC_R7:
+                       return "r7";
+               case UNW_PPC_R8:
+                       return "r8";
+               case UNW_PPC_R9:
+                       return "r9";
+               case UNW_PPC_R10:
+                       return "r10";
+               case UNW_PPC_R11:
+                       return "r11";
+               case UNW_PPC_R12:
+                       return "r12";
+               case UNW_PPC_R13:
+                       return "r13";
+               case UNW_PPC_R14:
+                       return "r14";
+               case UNW_PPC_R15:
+                       return "r15";
+               case UNW_PPC_R16:
+                       return "r16";
+               case UNW_PPC_R17:
+                       return "r17";
+               case UNW_PPC_R18:
+                       return "r18";
+               case UNW_PPC_R19:
+                       return "r19";
+               case UNW_PPC_R20:
+                       return "r20";
+               case UNW_PPC_R21:
+                       return "r21";
+               case UNW_PPC_R22:
+                       return "r22";
+               case UNW_PPC_R23:
+                       return "r23";
+               case UNW_PPC_R24:
+                       return "r24";
+               case UNW_PPC_R25:
+                       return "r25";
+               case UNW_PPC_R26:
+                       return "r26";
+               case UNW_PPC_R27:
+                       return "r27";
+               case UNW_PPC_R28:
+                       return "r28";
+               case UNW_PPC_R29:
+                       return "r29";
+               case UNW_PPC_R30:
+                       return "r30";
+               case UNW_PPC_R31:
+                       return "r31";
+               case UNW_PPC_F0:
+                       return "fp0";
+               case UNW_PPC_F1:
+                       return "fp1";
+               case UNW_PPC_F2:
+                       return "fp2";
+               case UNW_PPC_F3:
+                       return "fp3";
+               case UNW_PPC_F4:
+                       return "fp4";
+               case UNW_PPC_F5:
+                       return "fp5";
+               case UNW_PPC_F6:
+                       return "fp6";
+               case UNW_PPC_F7:
+                       return "fp7";
+               case UNW_PPC_F8:
+                       return "fp8";
+               case UNW_PPC_F9:
+                       return "fp9";
+               case UNW_PPC_F10:
+                       return "fp10";
+               case UNW_PPC_F11:
+                       return "fp11";
+               case UNW_PPC_F12:
+                       return "fp12";
+               case UNW_PPC_F13:
+                       return "fp13";
+               case UNW_PPC_F14:
+                       return "fp14";
+               case UNW_PPC_F15:
+                       return "fp15";
+               case UNW_PPC_F16:
+                       return "fp16";
+               case UNW_PPC_F17:
+                       return "fp17";
+               case UNW_PPC_F18:
+                       return "fp18";
+               case UNW_PPC_F19:
+                       return "fp19";
+               case UNW_PPC_F20:
+                       return "fp20";
+               case UNW_PPC_F21:
+                       return "fp21";
+               case UNW_PPC_F22:
+                       return "fp22";
+               case UNW_PPC_F23:
+                       return "fp23";
+               case UNW_PPC_F24:
+                       return "fp24";
+               case UNW_PPC_F25:
+                       return "fp25";
+               case UNW_PPC_F26:
+                       return "fp26";
+               case UNW_PPC_F27:
+                       return "fp27";
+               case UNW_PPC_F28:
+                       return "fp28";
+               case UNW_PPC_F29:
+                       return "fp29";
+               case UNW_PPC_F30:
+                       return "fp30";
+               case UNW_PPC_F31:
+                       return "fp31";
+               case UNW_PPC_LR:
+                       return "lr";
+               default:
+                       return "unknown register";
+       }
+
+
+}
+
+
+} // namespace libunwind 
+
+
+
+#endif // __REGISTERS_HPP__
+
+
+
+
index 6221c9040ce093642784470c8ff364de165f197a..46d350df801f5af86106e39dceacc92ea48085cb 100644 (file)
@@ -41,6 +41,9 @@
 #include "macho_relocatable_file.h"
 #include "lto_file.h"
 
+// #defines are a work around for <rdar://problem/8760268>
+#define __STDC_LIMIT_MACROS 1
+#define __STDC_CONSTANT_MACROS 1
 #include "llvm-c/lto.h"
 
 
@@ -249,11 +252,9 @@ bool Parser::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type
                case CPU_TYPE_X86_64:
                        return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, "x86_64-");
                case CPU_TYPE_ARM:
-                       switch ( subarch ) {
-                               case CPU_SUBTYPE_ARM_V6:
-                                       return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, "armv6-");
-                               case CPU_SUBTYPE_ARM_V7:
-                                       return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, "thumbv7-");
+                       for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
+                               if ( subarch == t->subType )
+                                       return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, t->llvmTriplePrefix);
                        }
                        break;
                case CPU_TYPE_POWERPC:
@@ -274,10 +275,10 @@ const char* Parser::fileKind(const uint8_t* p, uint64_t fileLength)
                        case CPU_TYPE_X86_64:
                                return "x86_64";
                        case CPU_TYPE_ARM:
-                               if ( ::lto_module_is_object_file_in_memory_for_target(p, fileLength, "armv6-") )
-                                       return "armv6";
-                               if ( ::lto_module_is_object_file_in_memory_for_target(p, fileLength, "thumbv7-") )
-                                       return "armv7";
+                               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
+                                       if ( ::lto_module_is_object_file_in_memory_for_target(p, fileLength, t->llvmTriplePrefix) )
+                                               return t->subTypeName;
+                               }
                                return "arm";
                }
                return "unknown bitcode architecture";
index 40dad13f869569a2090303fc46ce687e392b6b7e..436f3e6ab9c142114ea2f7078737d5ee36c31ec7 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -146,8 +146,8 @@ public:
                                                                                        File(const uint8_t* fileContent, uint64_t fileLength, const char* path,   
                                                                                                        time_t mTime, uint32_t ordinal, bool linkingFlatNamespace, 
                                                                                                        bool linkingMainExecutable, bool hoistImplicitPublicDylibs, 
-                                                                                                       ld::MacVersionMin macMin, ld::IPhoneVersionMin iPhoneMin,
-                                                                                                       bool logAllFiles);
+                                                                                                       ld::MacVersionMin macMin, ld::IOSVersionMin iPhoneMin, bool addVers, 
+                                                                                                       bool logAllFiles, const char* installPath, bool indirectDylib);
        virtual                                                                 ~File() {}
 
        // overrides of ld::File
@@ -164,6 +164,7 @@ public:
        virtual bool                                                    deadStrippable() const          { return _deadStrippable; }
        virtual bool                                                    hasPublicInstallName() const{ return _hasPublicInstallName; }
        virtual bool                                                    hasWeakDefinition(const char* name) const;
+       virtual bool                                                    allSymbolsAreWeakImported() const;
 
 
 protected:
@@ -185,7 +186,7 @@ private:
        public:
                bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
        };
-       struct AtomAndWeak { ld::Atom* atom; bool weak; bool tlv; pint_t address; };
+       struct AtomAndWeak { ld::Atom* atom; bool weakDef; bool tlv; pint_t address; };
        typedef __gnu_cxx::hash_map<const char*, AtomAndWeak, __gnu_cxx::hash<const char*>, CStringEquals> NameToAtomMap;
        typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  NameSet;
 
@@ -204,7 +205,8 @@ private:
        static const char*                                                      objCInfoSectionName();
        
        const ld::MacVersionMin                                         _macVersionMin;
-       const ld::IPhoneVersionMin                                      _iPhoneVersionMin;
+       const ld::IOSVersionMin                                         _iOSVersionMin;
+       const bool                                                                      _addVersionLoadCommand;
        bool                                                                            _linkingFlat;
        bool                                                                            _implicitlyLinkPublicDylibs;
        ld::File::ObjcConstraint                                        _objcContraint;
@@ -240,9 +242,10 @@ template <typename A> const char* File<A>::objCInfoSectionName() { return "__ima
 template <typename A>
 File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth, time_t mTime, uint32_t ord,
                                bool linkingFlatNamespace, bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
-                               ld::MacVersionMin macMin, ld::IPhoneVersionMin iPhoneMin, bool logAllFiles)
+                               ld::MacVersionMin macMin, ld::IOSVersionMin iOSMin, bool addVers,
+                               bool logAllFiles, const char* targetInstallPath, bool indirectDylib)
        : ld::dylib::File(strdup(pth), mTime, ord), 
-       _macVersionMin(macMin), _iPhoneVersionMin(iPhoneMin), 
+       _macVersionMin(macMin), _iOSVersionMin(iOSMin), _addVersionLoadCommand(addVers), 
        _linkingFlat(linkingFlatNamespace), _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs),
        _objcContraint(ld::File::objcConstraintNone),
        _importProxySection("__TEXT", "__import", ld::Section::typeImportProxies, true),
@@ -322,6 +325,14 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                        case LC_SUB_CLIENT:
                                _allowableClients.push_back(strdup(((macho_sub_client_command<P>*)cmd)->client()));
                                break;
+                       case LC_VERSION_MIN_MACOSX:
+                               if ( _addVersionLoadCommand && !indirectDylib && (_iOSVersionMin != ld::iOSVersionUnset) )
+                                       warning("building for iOS, but linking against dylib built for MacOSX: %s", pth);
+                               break;
+                       case LC_VERSION_MIN_IPHONEOS:
+                               if ( _addVersionLoadCommand && !indirectDylib && (_macVersionMin != ld::macVersionUnset) )
+                                       warning("building for MacOSX, but linking against dylib built for iOS: %s", pth);
+                               break;
                        case macho_segment_command<P>::CMD:
                                // check for Objective-C info
                                if ( strcmp(((macho_segment_command<P>*)cmd)->segname(), objCInfoSegmentName()) == 0 ) {
@@ -381,7 +392,8 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                                        entry.path = strdup(((macho_dylib_command<P>*)cmd)->name());
                                        entry.dylib = NULL;
                                        entry.reExport = (cmd->cmd() == LC_REEXPORT_DYLIB);
-                                       _dependentDylibs.push_back(entry);
+                                       if ( (targetInstallPath == NULL) || (strcmp(targetInstallPath, entry.path) != 0) )
+                                               _dependentDylibs.push_back(entry);
                                        break;
                        }
                        cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
@@ -546,8 +558,8 @@ void File<A>::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address
                        if ( _macVersionMin != ld::macVersionUnset ) {
                                sprintf(curOSVers, "$os%d.%d$", (_macVersionMin >> 16), ((_macVersionMin >> 8) & 0xFF));
                        }
-                       else if ( _iPhoneVersionMin != ld::iPhoneVersionUnset ) {
-                               sprintf(curOSVers, "$os%d.%d$", (_iPhoneVersionMin >> 16), ((_iPhoneVersionMin >> 8) & 0xFF));
+                       else if ( _iOSVersionMin != ld::iOSVersionUnset ) {
+                               sprintf(curOSVers, "$os%d.%d$", (_iOSVersionMin >> 16), ((_iOSVersionMin >> 8) & 0xFF));
                        }
                        else {
                                assert(0 && "targeting neither macosx nor iphoneos");
@@ -580,7 +592,7 @@ void File<A>::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address
        if ( _ignoreExports.count(name) == 0 ) {
                AtomAndWeak bucket;
                bucket.atom = NULL;
-               bucket.weak = weakDef;
+               bucket.weakDef = weakDef;
                bucket.tlv = tlv;
                bucket.address = address;
                if ( _s_logHashtable ) fprintf(stderr, "  adding %s to hash table for %s\n", name, this->path());
@@ -611,7 +623,7 @@ bool File<A>::hasWeakDefinition(const char* name) const
                
        typename NameToAtomMap::const_iterator pos = _atoms.find(name);
        if ( pos != _atoms.end() ) {
-               return pos->second.weak;
+               return pos->second.weakDef;
        }
        else {
                // look in children that I re-export
@@ -620,20 +632,48 @@ bool File<A>::hasWeakDefinition(const char* name) const
                                //fprintf(stderr, "getJustInTimeAtomsFor: %s NOT found in %s, looking in child %s\n", name, this->path(), (*it)->getInstallPath());
                                typename NameToAtomMap::iterator cpos = it->dylib->_atoms.find(name);
                                if ( cpos != it->dylib->_atoms.end() ) 
-                                       return cpos->second.weak;
+                                       return cpos->second.weakDef;
                        }
                }
        }
        return false;
 }
 
+
+// <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
+template <typename A>
+bool File<A>::allSymbolsAreWeakImported() const
+{
+       bool foundNonWeakImport = false;
+       bool foundWeakImport = false;
+       //fprintf(stderr, "%s:\n", this->path());
+       for (typename NameToAtomMap::const_iterator it = _atoms.begin(); it != _atoms.end(); ++it) {
+               const ld::Atom* atom = it->second.atom;
+               if ( atom != NULL ) {
+                       if ( atom->weakImported() )
+                               foundWeakImport = true;
+                       else
+                               foundNonWeakImport = true;
+                       //fprintf(stderr, "  weak_import=%d, name=%s\n", atom->weakImported(), it->first);
+               }
+       }
+       
+       // don't automatically weak link dylib with no imports
+       // so at least one weak import symbol and no non-weak-imported symbols must be found
+       return foundWeakImport && !foundNonWeakImport;
+}
+
+
 template <typename A>
 bool File<A>::containsOrReExports(const char* name, bool* weakDef, bool* tlv, pint_t* defAddress) const
 {
-       // check myself
+       if ( _ignoreExports.count(name) != 0 )
+               return false;
+
+// check myself
        typename NameToAtomMap::iterator pos = _atoms.find(name);
        if ( pos != _atoms.end() ) {
-               *weakDef = pos->second.weak;
+               *weakDef = pos->second.weakDef;
                *tlv = pos->second.tlv;
                *defAddress = pos->second.address;
                return true;
@@ -660,8 +700,8 @@ bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& han
        
        
        AtomAndWeak bucket;
-       if ( this->containsOrReExports(name, &bucket.weak, &bucket.tlv, &bucket.address) ) {
-               bucket.atom = new ExportAtom<A>(*this, name, bucket.weak, bucket.tlv, bucket.address);
+       if ( this->containsOrReExports(name, &bucket.weakDef, &bucket.tlv, &bucket.address) ) {
+               bucket.atom = new ExportAtom<A>(*this, name, bucket.weakDef, bucket.tlv, bucket.address);
                _atoms[name] = bucket;
                _providedAtom = true;
                if ( _s_logHashtable ) fprintf(stderr, "getJustInTimeAtomsFor: %s found in %s\n", name, this->path());
@@ -789,15 +829,6 @@ void File<A>::assertNoReExportCycles(ReExportChain* prev)
 }
 
 
-struct ParserOptions {
-       bool                                    linkingFlat;
-       bool                                    linkingMain;
-       bool                                    addImplictDylibs;
-       ld::MacVersionMin               macOSMin;
-       ld::IPhoneVersionMin    iphoneOSMin;
-};
-
-
 template <typename A>
 class Parser 
 {
@@ -807,14 +838,17 @@ public:
        static bool                                                                             validFile(const uint8_t* fileContent, bool executableOrDyliborBundle);
        static ld::dylib::File*                                                 parse(const uint8_t* fileContent, uint64_t fileLength, 
                                                                                                                        const char* path, time_t mTime, 
-                                                                                                                       uint32_t ordinal, const Options& opts) {
+                                                                                                                       uint32_t ordinal, const Options& opts, bool indirectDylib) {
                                                                                                                         return new File<A>(fileContent, fileLength, path, mTime,
                                                                                                                                                        ordinal, opts.flatNamespace(), 
                                                                                                                                                        opts.linkingMainExecutable(),
                                                                                                                                                        opts.implicitlyLinkIndirectPublicDylibs(), 
                                                                                                                                                        opts.macosxVersionMin(), 
-                                                                                                                                                       opts.iphoneOSVersionMin(),
-                                                                                                                                                       opts.logAllFiles());
+                                                                                                                                                       opts.iOSVersionMin(),
+                                                                                                                                                       opts.addVersionLoadCommand(),
+                                                                                                                                                       opts.logAllFiles(), 
+                                                                                                                                                       opts.installPath(),
+                                                                                                                                                       indirectDylib);
                                                                                                                }
 
 };
@@ -962,28 +996,29 @@ bool Parser<arm>::validFile(const uint8_t* fileContent, bool executableOrDylibor
 // main function used by linker to instantiate ld::Files
 //
 ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
-                                                       const char* path, time_t modTime, const Options& opts, uint32_t ordinal, bool bundleLoader)
+                                                       const char* path, time_t modTime, const Options& opts, uint32_t ordinal, 
+                                                       bool bundleLoader, bool indirectDylib)
 {
        switch ( opts.architecture() ) {
                case CPU_TYPE_X86_64:
                        if ( Parser<x86_64>::validFile(fileContent, bundleLoader) )
-                               return Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                               return Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
                        break;
                case CPU_TYPE_I386:
                        if ( Parser<x86>::validFile(fileContent, bundleLoader) )
-                               return Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                               return Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
                        break;
                case CPU_TYPE_ARM:
                        if ( Parser<arm>::validFile(fileContent, bundleLoader) )
-                               return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                               return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
                        break;
                case CPU_TYPE_POWERPC:
                        if ( Parser<ppc>::validFile(fileContent, bundleLoader) )
-                               return Parser<ppc>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                               return Parser<ppc>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
                        break;
                case CPU_TYPE_POWERPC64:
                        if ( Parser<ppc64>::validFile(fileContent, bundleLoader) )
-                               return Parser<ppc64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                               return Parser<ppc64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
                        break;
        }
        return NULL;
index 5c858e256f598c142877b7eccb0ccd9d7e495c1c..d26f50e3d514eec1c00040b01b2160c2717faaaf 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -32,7 +32,8 @@ namespace mach_o {
 namespace dylib {
 
 extern ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, 
-                                                               time_t modTime, const Options& opts, uint32_t ordinal, bool bundleLoader);
+                                                               time_t modTime, const Options& opts, uint32_t ordinal, 
+                                                               bool bundleLoader, bool indirectDylib);
 
 } // namespace dylib
 } // namespace mach_o
index 25c19653aa4bde31d963f4306b97548a863d87c2..abd44fa106bd04b945f4ce801a42bc81b39bc3af 100644 (file)
@@ -21,7 +21,7 @@
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
-
 
 #include <stdint.h>
 #include <stdlib.h>
@@ -34,9 +34,9 @@
 
 #include "MachOFileAbstraction.hpp"
 
-#include <libunwind/DwarfInstructions.hpp>
-#include <libunwind/AddressSpace.hpp>
-#include <libunwind/Registers.hpp>
+#include "libunwind/DwarfInstructions.hpp"
+#include "libunwind/AddressSpace.hpp"
+#include "libunwind/Registers.hpp"
 
 #include <vector>
 #include <set>
@@ -64,6 +64,7 @@ template <typename A> class Parser;
 template <typename A> class Atom;
 template <typename A> class Section;
 template <typename A> class CFISection;
+template <typename A> class CUSection;
 
 template <typename A>
 class File : public ld::relocatable::File
@@ -147,15 +148,16 @@ public:
        virtual bool                                    addFollowOnFixups() const       { return ! _file.canScatterAtoms(); }
        virtual uint32_t                                appendAtoms(class Parser<A>& parser, uint8_t* buffer, 
                                                                                                struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                                               const struct Parser<A>::CFIInfoArray&) = 0;
+                                                                                               const struct Parser<A>::CFI_CU_InfoArrays&) = 0;
        virtual uint32_t                                computeAtomCount(class Parser<A>& parser, 
                                                                                                                struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                                                               const struct Parser<A>::CFIInfoArray&) = 0;
-       virtual void                                    makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray&);
+                                                                                                               const struct Parser<A>::CFI_CU_InfoArrays&) = 0;
+       virtual void                                    makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&);
        virtual bool                                    addRelocFixup(class Parser<A>& parser, const macho_relocation_info<P>*);
        virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const { return 0; }
        virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
                                                                                                        const ld::IndirectBindingTable& ind) const { return false; }
+       static const char*                              makeSectionName(const macho_section<typename A::P>* s);
 
 protected:     
                                                Section(File<A>& f, const macho_section<typename A::P>* s)
@@ -170,7 +172,6 @@ protected:
        Atom<A>*                                                findContentAtomByAddress(pint_t addr, class Atom<A>* start, class Atom<A>* end);
        uint32_t                                                x86_64PcRelOffset(uint8_t r_type);
        static const char*                              makeSegmentName(const macho_section<typename A::P>* s);
-       static const char*                              makeSectionName(const macho_section<typename A::P>* s);
        static bool                                             readable(const macho_section<typename A::P>* s);
        static bool                                             writable(const macho_section<typename A::P>* s);
        static bool                                             exectuable(const macho_section<typename A::P>* s);
@@ -193,9 +194,9 @@ public:
        uint32_t                        cfiCount();
 
        virtual ld::Atom::ContentType   contentType()           { return ld::Atom::typeCFI; }
-       virtual uint32_t        computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFIInfoArray&);
-       virtual uint32_t        appendAtoms(class Parser<A>& parser, uint8_t* buffer, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFIInfoArray&);
-       virtual void            makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray&);
+       virtual uint32_t        computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFI_CU_InfoArrays&);
+       virtual uint32_t        appendAtoms(class Parser<A>& parser, uint8_t* buffer, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFI_CU_InfoArrays&);
+       virtual void            makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&);
        virtual bool            addFollowOnFixups() const       { return false; }
 
 
@@ -248,6 +249,46 @@ private:
 };
 
 
+template <typename A>
+class CUSection : public Section<A>
+{
+public:
+                                               CUSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : Section<A>(f, s) { }
+
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+       typedef typename A::P::E                E;
+                                       
+       virtual uint32_t                computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFI_CU_InfoArrays&) { return 0; }
+       virtual uint32_t                appendAtoms(class Parser<A>& parser, uint8_t* buffer, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFI_CU_InfoArrays&) { return 0; }
+       virtual void                    makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&);
+       virtual bool                    addFollowOnFixups() const       { return false; }
+       
+       struct Info {
+               pint_t          functionStartAddress;
+               uint32_t        functionSymbolIndex;
+               uint32_t        rangeLength;
+               uint32_t        compactUnwindInfo;
+               const char*     personality;
+               pint_t          lsdaAddress;
+               Atom<A>*        function;
+               Atom<A>*        lsda;
+       };
+
+       uint32_t                                count();
+       void                                    parse(class Parser<A>& parser, uint32_t cnt, Info array[]);
+       
+       
+private:
+       
+       const char*                             personalityName(class Parser<A>& parser, const macho_relocation_info<P>* reloc);
+
+       static int                              infoSorter(const void* l, const void* r);
+
+};
+
+
 template <typename A>
 class TentativeDefinitionSection : public Section<A>
 {
@@ -259,11 +300,11 @@ public:
        virtual bool            addFollowOnFixups() const       { return false; }
        virtual Atom<A>*        findAtomByAddress(typename A::P::uint_t addr) { throw "TentativeDefinitionSection::findAtomByAddress() should never be called"; }
        virtual uint32_t        computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                                       const struct Parser<A>::CFIInfoArray&);
+                                                                                       const struct Parser<A>::CFI_CU_InfoArrays&);
        virtual uint32_t        appendAtoms(class Parser<A>& parser, uint8_t* buffer, 
                                                                                struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                               const struct Parser<A>::CFIInfoArray&);
-       virtual void            makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray&) {}
+                                                                               const struct Parser<A>::CFI_CU_InfoArrays&);
+       virtual void            makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&) {}
 private:
        typedef typename A::P::uint_t   pint_t;
        typedef typename A::P                   P;
@@ -283,11 +324,11 @@ public:
        virtual bool            addFollowOnFixups() const       { return false; }
        virtual Atom<A>*        findAtomByAddress(typename A::P::uint_t addr) { throw "AbsoluteSymbolSection::findAtomByAddress() should never be called"; }
        virtual uint32_t        computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                                       const struct Parser<A>::CFIInfoArray&);
+                                                                                       const struct Parser<A>::CFI_CU_InfoArrays&);
        virtual uint32_t        appendAtoms(class Parser<A>& parser, uint8_t* buffer, 
                                                                                struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                               const struct Parser<A>::CFIInfoArray&);
-       virtual void            makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray&) {}
+                                                                               const struct Parser<A>::CFI_CU_InfoArrays&);
+       virtual void            makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&) {}
        virtual Atom<A>*        findAbsAtomForValue(typename A::P::uint_t);
        
 private:
@@ -304,10 +345,10 @@ public:
        virtual ld::Atom::ContentType   contentType() { return _type; }
        virtual bool                                    dontDeadStrip();
        virtual uint32_t        computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                                       const struct Parser<A>::CFIInfoArray&);
+                                                                                       const struct Parser<A>::CFI_CU_InfoArrays&);
        virtual uint32_t        appendAtoms(class Parser<A>& parser, uint8_t* buffer, 
                                                                        struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                       const struct Parser<A>::CFIInfoArray&);
+                                                                       const struct Parser<A>::CFI_CU_InfoArrays&);
 protected:
        typedef typename A::P::uint_t   pint_t;
        typedef typename A::P                   P;
@@ -334,8 +375,8 @@ class ImplicitSizeSection : public Section<A>
 public:
                                                ImplicitSizeSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
                                                        : Section<A>(f, s) { }
-       virtual uint32_t        computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFIInfoArray&);
-       virtual uint32_t        appendAtoms(class Parser<A>& parser, uint8_t* buffer, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFIInfoArray&);
+       virtual uint32_t        computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFI_CU_InfoArrays&);
+       virtual uint32_t        appendAtoms(class Parser<A>& parser, uint8_t* buffer, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFI_CU_InfoArrays&);
 protected:
        typedef typename A::P::uint_t   pint_t;
        typedef typename A::P                   P;
@@ -437,7 +478,7 @@ protected:
        typedef typename A::P::uint_t   pint_t;
        typedef typename A::P                   P;
 
-       virtual void                                    makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray&);
+       virtual void                                    makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&);
        virtual ld::Atom::ContentType   contentType()                                                   { return ld::Atom::typeNonLazyPointer; }
        virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr)                { return ld::Atom::Alignment(log2(sizeof(pint_t))); }
        virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "non_lazy_ptr"; }
@@ -598,6 +639,7 @@ protected:
        virtual Atom<A>*                                findAtomByAddress(pint_t addr);
        virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "cstring"; }
        virtual pint_t                                  elementSizeAtAddress(pint_t addr);
+       virtual bool                                    ignoreLabel(const char* label);
        virtual bool                                    useElementAt(Parser<A>& parser, 
                                                                                                struct Parser<A>::LabelAndCFIBreakIterator& it, pint_t addr);
        virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndContent; }
@@ -668,6 +710,7 @@ public:
                        File<A>&                                                        machofile() const                       { return ((Section<A>*)(this->_section))->file(); }
                        void                                                            setFixupsRange(uint32_t s, uint32_t c);
                        void                                                            setUnwindInfoRange(uint32_t s, uint32_t c);
+                       void                                                            extendUnwindInfoRange();
                        void                                                            setLineInfoRange(uint32_t s, uint32_t c);
                        bool                                                            roomForMoreLineInfoCount() { return (_lineInfoCount < ((1<<kLineInfoCountBits)-1)); }
                        void                                                            incrementLineInfoCount() { assert(roomForMoreLineInfoCount()); ++_lineInfoCount; }
@@ -758,6 +801,14 @@ void Atom<A>::setUnwindInfoRange(uint32_t startIndex, uint32_t count)
        _unwindInfoCount = count; 
 }
 
+template <typename A>
+void Atom<A>::extendUnwindInfoRange()
+{
+       if ( _unwindInfoCount+1 >= (1 << kUnwindInfoCountBits) ) 
+               throwf("too many compact unwind infos in function %s", this->name());
+       _unwindInfoCount += 1;
+}
+
 template <typename A>
 void Atom<A>::setLineInfoRange(uint32_t startIndex, uint32_t count)
 { 
@@ -792,8 +843,8 @@ template <>
 void Atom<arm>::verifyAlignment() const
 {
        if ( (this->section().type() == ld::Section::typeCode) && ! isThumb() ) {
-               if ( (_objAddress % 4) != 0 )
-                       warning("ARM function %s not 4-byte aligned", this->name());
+               if ( ((_objAddress % 4) != 0) || (this->alignment().powerOf2 < 2) )
+                       warning("ARM function not 4-byte aligned: %s from %s", this->name(), this->file()->path());
        }
 }
 
@@ -951,14 +1002,19 @@ public:
                uint32_t                                        symIndex;
        };
 
-       struct CFIInfoArray {
+       struct CFI_CU_InfoArrays {
                        typedef typename CFISection<A>::CFI_Atom_Info CFI_Atom_Info;
-                                                       CFIInfoArray(const CFI_Atom_Info* cfia, uint32_t cfiac) : array(cfia), count(cfiac) {} 
-               const CFI_Atom_Info* const      array;
-               const uint32_t                          count;
+                       typedef typename CUSection<A>::Info CU_Info;
+                                               CFI_CU_InfoArrays(const CFI_Atom_Info* cfiAr, uint32_t cfiC, CU_Info* cuAr, uint32_t cuC) 
+                                                       : cfiArray(cfiAr), cuArray(cuAr), cfiCount(cfiC), cuCount(cuC) {} 
+               const CFI_Atom_Info* const      cfiArray;
+                       CU_Info* const                  cuArray;
+               const uint32_t                          cfiCount;
+               const uint32_t                          cuCount;
        };
 
 
+
 private:
        friend class Section<A>;
        
@@ -966,7 +1022,8 @@ private:
                                                sectionTypeNonLazy, sectionTypeCFI, sectionTypeCString, sectionTypeCStringPointer, 
                                                sectionTypeUTF16Strings, sectionTypeCFString, sectionTypeObjC2ClassRefs, typeObjC2CategoryList,
                                                sectionTypeObjC1Classes, sectionTypeSymboled, sectionTypeObjC1ClassRefs,
-                                               sectionTypeTentativeDefinitions, sectionTypeAbsoluteSymbols, sectionTypeTLVDefs };
+                                               sectionTypeTentativeDefinitions, sectionTypeAbsoluteSymbols, sectionTypeTLVDefs,
+                                               sectionTypeCompactUnwind };
 
        template <typename P>
        struct MachOSectionAndSectionClass
@@ -986,6 +1043,9 @@ private:
                                return 1;
                }
        };
+       
+       struct ParserAndSectionsArray { Parser* parser; const uint32_t* sortedSectionsArray; };
+       
 
                                                                                                        Parser(const uint8_t* fileContent, uint64_t fileLength, 
                                                                                                                        const char* path, time_t modTime, 
@@ -994,11 +1054,13 @@ private:
        uint8_t                                                                                 loadCommandSizeMask();
        bool                                                                                    parseLoadCommands();
        void                                                                                    makeSections();
-       void                                                                                    checkForLSDA();
        void                                                                                    prescanSymbolTable();
-       void                                                                                    makeSortedSymbolsArray(uint32_t array[]);
+       void                                                                                    makeSortedSymbolsArray(uint32_t symArray[], const uint32_t sectionArray[]);
+       void                                                                                    makeSortedSectionsArray(uint32_t array[]);
        static int                                                                              pointerSorter(const void* l, const void* r);
        static int                                                                              symbolIndexSorter(void* extra, const void* l, const void* r);
+       static int                                                                              sectionIndexSorter(void* extra, const void* l, const void* r);
+
        void                                                                                    parseDebugInfo();
        void                                                                                    parseStabs();
        static bool                                                                             isConstFunStabs(const char *stabStr);
@@ -1032,9 +1094,8 @@ private:
        
        // filled in by parse()
        CFISection<A>*                                                          _EHFrameSection;
+       CUSection<A>*                                                           _compactUnwindSection;
        AbsoluteSymbolSection<A>*                                       _absoluteSection;
-       uint32_t                                                                        _lsdaTextSectionNum;
-       uint32_t                                                                        _lsdaDataSectionNum;
        uint32_t                                                                        _tentativeDefinitionCount;
        uint32_t                                                                        _absoluteSymbolCount;
        uint32_t                                                                        _symbolsInSections;
@@ -1059,8 +1120,7 @@ Parser<A>::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* p
                        _indirectTable(NULL), _indirectTableCount(0), 
                        _undefinedStartIndex(0), _undefinedEndIndex(0), 
                        _sectionsStart(NULL), _machOSectionsCount(0), _hasUUID(false), 
-                       _EHFrameSection(NULL), _absoluteSection(NULL),
-                       _lsdaTextSectionNum(0), _lsdaDataSectionNum(0),
+                       _EHFrameSection(NULL), _compactUnwindSection(NULL), _absoluteSection(NULL),
                        _tentativeDefinitionCount(0), _absoluteSymbolCount(0),
                        _symbolsInSections(0), _hasLongBranchStubs(false),  _AppleObjc(false),
                        _overlappingSymbols(false), _convertUnwindInfo(convertDUI), 
@@ -1206,17 +1266,10 @@ const char* Parser<arm>::fileKind(const uint8_t* fileContent)
                return NULL;
        if ( header->cputype() != CPU_TYPE_ARM )
                return NULL;
-       switch ( header->cpusubtype() ) {
-               case CPU_SUBTYPE_ARM_V4T:
-                       return "armv4t";
-               case CPU_SUBTYPE_ARM_V5TEJ:
-                       return "armv5";
-               case CPU_SUBTYPE_ARM_V6:
-                       return "armv6";
-               case CPU_SUBTYPE_ARM_V7:
-                       return "armv7";
-               case CPU_SUBTYPE_ARM_ALL:
-                       return "arm-ALL";
+       for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
+               if ( t->subType == (cpu_subtype_t)header->cpusubtype() ) {
+                       return t->subTypeName;
+               }
        }
        return "arm???";
 }
@@ -1302,7 +1355,8 @@ bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, uint32_t sectN
                while ( symIndex < sortedSymbolCount ) {
                        const macho_nlist<P>& sym = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]);
                        pint_t nextSymbolAddr = sym.n_value();
-                       if ( (nextSymbolAddr >= startAddr) && (sym.n_sect() >= sectNum) )
+                       //fprintf(stderr, "sectNum=%d, nextSymbolAddr=0x%08llX, name=%s\n", sectNum, (uint64_t)nextSymbolAddr, parser.nameFromSymbol(sym));
+                       if ( (nextSymbolAddr > startAddr) || ((nextSymbolAddr == startAddr) && (sym.n_sect() == sectNum)) )
                                break;
                        ++symIndex;
                }
@@ -1444,16 +1498,28 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
        if ( ! parseLoadCommands() )
                return _file;
        
+       // make array of 
+       uint32_t sortedSectionIndexes[_machOSectionsCount];
+       this->makeSortedSectionsArray(sortedSectionIndexes);
+       
        // make symbol table sorted by address
-       this->checkForLSDA();
        this->prescanSymbolTable();
        uint32_t sortedSymbolIndexes[_symbolsInSections];
-       this->makeSortedSymbolsArray(sortedSymbolIndexes);
+       this->makeSortedSymbolsArray(sortedSymbolIndexes, sortedSectionIndexes);
                
        // allocate Section<A> object for each mach-o section
        makeSections();
        
-       // if it exists, do special parsing of __eh_frame section 
+       // if it exists, do special early parsing of __compact_unwind section
+       uint32_t countOfCUs = 0;
+       if ( _compactUnwindSection != NULL )
+               countOfCUs = _compactUnwindSection->count();
+       uint8_t cuInfoBuffer[sizeof(typename CUSection<A>::Info) * countOfCUs];
+       typename CUSection<A>::Info*  cuInfoArray = (typename CUSection<A>::Info*)cuInfoBuffer;
+       if ( countOfCUs != 0 )
+               _compactUnwindSection->parse(*this, countOfCUs, cuInfoArray);
+       
+       // if it exists, do special early parsing of __eh_frame section 
        // stack allocate array of CFI_Atom_Info
        uint32_t countOfCFIs = 0;
        if ( _EHFrameSection != NULL )
@@ -1489,7 +1555,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
                                ++cfiStartsCount;
                }
        }
-       CFIInfoArray cfis(cfiArray, countOfCFIs);
+       CFI_CU_InfoArrays cfis(cfiArray, countOfCFIs, cuInfoArray, countOfCUs);
        
        // create sorted array of function starts and lsda starts
        pint_t cfiStartsArray[cfiStartsCount];
@@ -1539,7 +1605,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
                uint8_t* atoms = _file->_atomsArray + _file->_atomsArrayCount*sizeof(Atom<A>);
                breakIterator2.beginSection();
                uint32_t count = sections[i]->appendAtoms(*this, atoms, breakIterator2, cfis);
-               //fprintf(stderr, "append count=%u for section %s\n", count, sections[i]->machoSection()->sectname());
+               //fprintf(stderr, "append count=%u for section %s/%s\n", count, sections[i]->machoSection()->segname(), sections[i]->machoSection()->sectname());
                _file->_atomsArrayCount += count;
        }
        assert( _file->_atomsArrayCount == computedAtomCount && "more atoms allocated than expected");
@@ -1574,7 +1640,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
        _allFixups.clear();
 
        // add unwind info
-       _file->_unwindInfos.reserve(countOfFDEs);
+       _file->_unwindInfos.reserve(countOfFDEs+countOfCUs);
        for(uint32_t i=0; i < countOfCFIs; ++i) {
                if ( cfiArray[i].isCIE )
                        continue;
@@ -1587,7 +1653,33 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
                        func->setUnwindInfoRange(_file->_unwindInfos.size()-1, 1);
                }
        }
-
+       // apply compact infos in __LD,__compact_unwind section to each function
+       // if function also has dwarf unwind, CU will override it
+       Atom<A>* lastFunc = NULL;
+       uint32_t lastEnd = 0;
+       for(uint32_t i=0; i < countOfCUs; ++i) {
+               typename CUSection<A>::Info* info = &cuInfoArray[i];
+               assert(info->function != NULL);
+               ld::Atom::UnwindInfo ui;
+               ui.startOffset = info->functionStartAddress - info->function->objectAddress();
+               ui.unwindInfo = info->compactUnwindInfo;                
+               _file->_unwindInfos.push_back(ui);
+               // if previous is for same function, extend range
+               if ( info->function == lastFunc ) {
+                       if ( lastEnd != ui.startOffset ) {
+                               if ( lastEnd < ui.startOffset )
+                                       warning("__LD,__compact_unwind entries for %s have a gap at offset 0x%0X", info->function->name(), lastEnd);
+                               else
+                                       warning("__LD,__compact_unwind entries for %s overlap at offset 0x%0X", info->function->name(), lastEnd);
+                       }
+                       lastFunc->extendUnwindInfoRange();
+               }
+               else 
+                       info->function->setUnwindInfoRange(_file->_unwindInfos.size()-1, 1);
+               lastFunc = info->function;
+               lastEnd = ui.startOffset + info->rangeLength;
+       }
+       
        // parse dwarf debug info to get line info
        this->parseDebugInfo();
 
@@ -1686,31 +1778,6 @@ bool Parser<A>::parseLoadCommands()
        return true;
 }
 
-template <>
-void Parser<arm>::checkForLSDA()
-{
-       // ARM has no FDEs, so need labels to break up section into atoms
-}
-
-template <typename A>
-void Parser<A>::checkForLSDA()
-{
-       // ignore labels on __gcc_except_tab section, we'll break it into atoms based on FDE info
-       for (uint32_t i=0; i < _machOSectionsCount; ++i) {
-               const macho_section<P>* sect = &_sectionsStart[i];
-               if ( strncmp(sect->sectname(), "__gcc_except_tab", 16) == 0 ) {
-                       if ( strcmp(sect->segname(), "__TEXT") == 0 ) {
-                               assert(_lsdaTextSectionNum == 0);
-                               _lsdaTextSectionNum = i+1;
-                       }
-                       else if ( strcmp(sect->segname(), "__DATA") == 0 ) {
-                               assert(_lsdaDataSectionNum == 0);
-                               _lsdaDataSectionNum = i+1;
-                       }
-               }
-       }
-}
-
 
 template <typename A>
 void Parser<A>::prescanSymbolTable()
@@ -1766,12 +1833,6 @@ void Parser<A>::prescanSymbolTable()
                if ( symbolName[0] == 'L' )
                        continue;
                
-               // ignore labels in __gcc_except_tab section
-               if ( (_lsdaTextSectionNum != 0) && (sym.n_sect() == _lsdaTextSectionNum) )
-                       continue;
-               if ( (_lsdaDataSectionNum != 0) && (sym.n_sect() == _lsdaDataSectionNum) )
-                       continue;
-               
                // how many def syms in each section
                if ( sym.n_sect() > _machOSectionsCount )
                        throw "bad n_sect in symbol table";
@@ -1781,11 +1842,68 @@ void Parser<A>::prescanSymbolTable()
 }
 
 template <typename A>
-int Parser<A>::symbolIndexSorter(void* extra, const void* l, const void* r)
+int Parser<A>::sectionIndexSorter(void* extra, const void* l, const void* r)
 {
        Parser<A>* parser = (Parser<A>*)extra;
        const uint32_t* left = (uint32_t*)l;
        const uint32_t* right = (uint32_t*)r;
+       const macho_section<P>* leftSect =      parser->machOSectionFromSectionIndex(*left);
+       const macho_section<P>* rightSect = parser->machOSectionFromSectionIndex(*right);
+       
+       // can't just return difference because 64-bit diff does not fit in 32-bit return type
+       int64_t result = leftSect->addr() - rightSect->addr();
+       if ( result == 0 ) {
+               // two sections with same start address
+               // one with zero size goes first
+               bool leftEmpty = ( leftSect->size() == 0 );
+               bool rightEmpty = ( rightSect->size() == 0 );
+               if ( leftEmpty != rightEmpty ) {
+                       return ( rightEmpty ? 1 : -1 );
+               }
+               if ( !leftEmpty && !rightEmpty )
+                       throwf("overlapping sections");
+               // both empty, so chose file order
+               return ( rightSect - leftSect );
+       }
+       else if ( result < 0 )
+               return -1;
+       else
+               return 1;
+}
+
+template <typename A>
+void Parser<A>::makeSortedSectionsArray(uint32_t array[])
+{
+       const bool log = false;
+       
+       if ( log ) {
+               fprintf(stderr, "unsorted sections:\n");
+               for(unsigned int i=0; i < _machOSectionsCount; ++i ) 
+                       fprintf(stderr, "0x%08llX %s %s\n", _sectionsStart[i].addr(), _sectionsStart[i].segname(), _sectionsStart[i].sectname());
+       }
+       
+       // sort by symbol table address
+       for (uint32_t i=0; i < _machOSectionsCount; ++i)
+               array[i] = i;
+       ::qsort_r(array, _machOSectionsCount, sizeof(uint32_t), this, &sectionIndexSorter);
+
+       if ( log ) {
+               fprintf(stderr, "sorted sections:\n");
+               for(unsigned int i=0; i < _machOSectionsCount; ++i ) 
+                       fprintf(stderr, "0x%08llX %s %s\n", _sectionsStart[array[i]].addr(), _sectionsStart[array[i]].segname(), _sectionsStart[array[i]].sectname());
+       }
+}
+
+
+
+template <typename A>
+int Parser<A>::symbolIndexSorter(void* extra, const void* l, const void* r)
+{
+       ParserAndSectionsArray* extraInfo = (ParserAndSectionsArray*)extra;
+       Parser<A>* parser = extraInfo->parser;
+       const uint32_t* sortedSectionsArray = extraInfo->sortedSectionsArray;
+       const uint32_t* left = (uint32_t*)l;
+       const uint32_t* right = (uint32_t*)r;
        const macho_nlist<P>& leftSym = parser->symbolFromIndex(*left);
        const macho_nlist<P>& rightSym = parser->symbolFromIndex(*right);
        // can't just return difference because 64-bit diff does not fit in 32-bit return type
@@ -1793,9 +1911,15 @@ int Parser<A>::symbolIndexSorter(void* extra, const void* l, const void* r)
        if ( result == 0 ) {
                // two symbols with same address
                // if in different sections, sort earlier section first
-               if ( leftSym.n_sect() != rightSym.n_sect() )
-                       return (leftSym.n_sect() - rightSym.n_sect());
-               //, means one is an alias
+               if ( leftSym.n_sect() != rightSym.n_sect() ) {
+                       for (uint32_t i=0; i < parser->machOSectionCount(); ++i) {
+                               if ( sortedSectionsArray[i]+1 == leftSym.n_sect() )
+                                       return -1;
+                               if ( sortedSectionsArray[i]+1 == rightSym.n_sect() )
+                                       return 1;
+                       }
+               }
+               // two symbols in same section, means one is an alias
                // if only one is global, make the other an alias (sort first)
                if ( (leftSym.n_type() & N_EXT) != (rightSym.n_type() & N_EXT) ) {
                        if ( (rightSym.n_type() & N_EXT) != 0 )
@@ -1812,9 +1936,12 @@ int Parser<A>::symbolIndexSorter(void* extra, const void* l, const void* r)
                return 1;
 }
 
+
 template <typename A>
-void Parser<A>::makeSortedSymbolsArray(uint32_t array[])
+void Parser<A>::makeSortedSymbolsArray(uint32_t array[], const uint32_t sectionArray[])
 {
+       const bool log = false;
+       
        uint32_t* p = array;
        for (uint32_t i=0; i < this->_symbolCount; ++i) {
                const macho_nlist<P>& sym =     symbolFromIndex(i);
@@ -1831,12 +1958,6 @@ void Parser<A>::makeSortedSymbolsArray(uint32_t array[])
                if ( symbolName[0] == 'L' )
                        continue;
 
-               // ignore labels in __gcc_except_tab section
-               if ( (_lsdaTextSectionNum != 0) && (sym.n_sect() == _lsdaTextSectionNum) )
-                       continue;
-               if ( (_lsdaDataSectionNum != 0) && (sym.n_sect() == _lsdaDataSectionNum) )
-                       continue;
-               
                // how many def syms in each section
                if ( sym.n_sect() > _machOSectionsCount )
                        throw "bad n_sect in symbol table";
@@ -1847,7 +1968,8 @@ void Parser<A>::makeSortedSymbolsArray(uint32_t array[])
        assert(p == &array[_symbolsInSections] && "second pass over symbol table yield a different number of symbols");
        
        // sort by symbol table address
-       ::qsort_r(array, _symbolsInSections, sizeof(uint32_t), this, &symbolIndexSorter);
+       ParserAndSectionsArray extra = { this, sectionArray };
+       ::qsort_r(array, _symbolsInSections, sizeof(uint32_t), &extra, &symbolIndexSorter);
        
        // look for two symbols at same address
        _overlappingSymbols = false;
@@ -1858,9 +1980,11 @@ void Parser<A>::makeSortedSymbolsArray(uint32_t array[])
                }
        }
 
-       //fprintf(stderr, "sorted symbols:\n");
-       //for(unsigned int i=0; i < _symbolsInSections; ++i ) 
-       //      fprintf(stderr, "0x%09llX symIndex=%3d sectNum=%2d, %s\n", symbolFromIndex(array[i]).n_value(), array[i], symbolFromIndex(array[i]).n_sect(), nameFromSymbol(symbolFromIndex(array[i])) );
+       if ( log ) {
+               fprintf(stderr, "sorted symbols:\n");
+               for(unsigned int i=0; i < _symbolsInSections; ++i ) 
+                       fprintf(stderr, "0x%09llX symIndex=%d sectNum=%2d, %s\n", symbolFromIndex(array[i]).n_value(), array[i], symbolFromIndex(array[i]).n_sect(), nameFromSymbol(symbolFromIndex(array[i])) );
+       }
 }
 
 
@@ -1876,21 +2000,30 @@ void Parser<A>::makeSections()
        unsigned int count = 0;
        for (uint32_t i=0; i < _machOSectionsCount; ++i) {
                const macho_section<P>* sect = &_sectionsStart[i];
-               // ignore dwarf sections
                if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
-                       // note that .o file has dwarf
-                       _file->_debugInfoKind = ld::relocatable::File::kDebugInfoDwarf;
-                       // save off iteresting dwarf sections
-                       if ( strcmp(sect->sectname(), "__debug_info") == 0 )
-                               _file->_dwarfDebugInfoSect = sect;
-                       else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 )
-                               _file->_dwarfDebugAbbrevSect = sect;
-                       else if ( strcmp(sect->sectname(), "__debug_line") == 0 )
-                               _file->_dwarfDebugLineSect = sect;
-                       else if ( strcmp(sect->sectname(), "__debug_str") == 0 )
-                               _file->_dwarfDebugStringSect = sect;
-                       // linker does not propagate dwarf sections to output file
-                       continue;
+                       if ( strcmp(sect->segname(), "__DWARF") == 0 ) {
+                               // note that .o file has dwarf
+                               _file->_debugInfoKind = ld::relocatable::File::kDebugInfoDwarf;
+                               // save off iteresting dwarf sections
+                               if ( strcmp(sect->sectname(), "__debug_info") == 0 )
+                                       _file->_dwarfDebugInfoSect = sect;
+                               else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 )
+                                       _file->_dwarfDebugAbbrevSect = sect;
+                               else if ( strcmp(sect->sectname(), "__debug_line") == 0 )
+                                       _file->_dwarfDebugLineSect = sect;
+                               else if ( strcmp(sect->sectname(), "__debug_str") == 0 )
+                                       _file->_dwarfDebugStringSect = sect;
+                               // linker does not propagate dwarf sections to output file
+                               continue;
+                       }
+                       else if ( strcmp(sect->segname(), "__LD") == 0 ) {
+                               if ( strncmp(sect->sectname(), "__compact_unwind", 16) == 0 ) {
+                                       machOSects[count].sect = sect;
+                                       totalSectionsSize += sizeof(CUSection<A>);
+                                       machOSects[count++].type = sectionTypeCompactUnwind;
+                                       continue;
+                               }
+                       }
                }
                // ignore empty __OBJC sections
                if ( (sect->size() == 0) && (strcmp(sect->segname(), "__OBJC") == 0) )
@@ -1918,11 +2051,11 @@ void Parser<A>::makeSections()
                                        _file->_ojcReplacmentClass = true;
                                if ( sect->size() > 8 ) {
                                        warning("section %s/%s has unexpectedly large size %llu in %s", 
-                                                       sect->segname(), sect->sectname(), sect->size(), _file->path());
+                                                       sect->segname(), Section<A>::makeSectionName(sect), sect->size(), _file->path());
                                }
                        }
                        else {
-                               warning("can't parse %s/%s section in %s", sect->segname(), sect->sectname(), _file->path());
+                               warning("can't parse %s/%s section in %s", sect->segname(), Section<A>::makeSectionName(sect), _file->path());
                        }
                        continue;
                }
@@ -2101,6 +2234,11 @@ void Parser<A>::makeSections()
                                *objects++ = new (space) TLVDefsSection<A>(*this, *_file, machOSects[i].sect);
                                space += sizeof(TLVDefsSection<A>);
                                break;
+                       case sectionTypeCompactUnwind:
+                               _compactUnwindSection = new (space) CUSection<A>(*this, *_file, machOSects[i].sect);
+                               *objects++ = _compactUnwindSection;
+                               space += sizeof(CUSection<A>);
+                               break;
                        case sectionTypeTentativeDefinitions:
                                *objects++ = new (space) TentativeDefinitionSection<A>(*this, *_file);
                                space += sizeof(TentativeDefinitionSection<A>);
@@ -2462,7 +2600,7 @@ void Parser<A>::addFixups(const SourceLocation& src, ld::Fixup::Kind kind, const
 template <typename A>
 uint32_t TentativeDefinitionSection<A>::computeAtomCount(class Parser<A>& parser, 
                                                                                                                        struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                                                                       const struct Parser<A>::CFIInfoArray&)
+                                                                                                                       const struct Parser<A>::CFI_CU_InfoArrays&)
 {
        return parser.tentativeDefinitionCount();
 }
@@ -2470,7 +2608,7 @@ uint32_t TentativeDefinitionSection<A>::computeAtomCount(class Parser<A>& parser
 template <typename A>
 uint32_t TentativeDefinitionSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p, 
                                                                                                                struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                                                               const struct Parser<A>::CFIInfoArray&)
+                                                                                                               const struct Parser<A>::CFI_CU_InfoArrays&)
 {
        this->_beginAtoms = (Atom<A>*)p;
        uint32_t count = 0;
@@ -2489,8 +2627,8 @@ uint32_t TentativeDefinitionSection<A>::appendAtoms(class Parser<A>& parser, uin
                                        ++alignP2;
                        }
                        // limit alignment of extremely large commons to 2^15 bytes (8-page)
-                       if ( alignP2 > 12 )
-                               alignP2 = 12;
+                       if ( alignP2 > 15 )
+                               alignP2 = 15;
                        Atom<A>* allocatedSpace = (Atom<A>*)p;
                        new (allocatedSpace) Atom<A>(*this, parser.nameFromSymbol(sym), (pint_t)ULLONG_MAX, size,
                                                                                ld::Atom::definitionTentative,  ld::Atom::combineByName, 
@@ -2508,7 +2646,7 @@ uint32_t TentativeDefinitionSection<A>::appendAtoms(class Parser<A>& parser, uin
 template <typename A>
 uint32_t AbsoluteSymbolSection<A>::computeAtomCount(class Parser<A>& parser, 
                                                                                                                        struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                                                                       const struct Parser<A>::CFIInfoArray&)
+                                                                                                                       const struct Parser<A>::CFI_CU_InfoArrays&)
 {
        return parser.absoluteSymbolCount();
 }
@@ -2516,7 +2654,7 @@ uint32_t AbsoluteSymbolSection<A>::computeAtomCount(class Parser<A>& parser,
 template <typename A>
 uint32_t AbsoluteSymbolSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p, 
                                                                                                                struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                                                               const struct Parser<A>::CFIInfoArray&)
+                                                                                                               const struct Parser<A>::CFI_CU_InfoArrays&)
 {
        this->_beginAtoms = (Atom<A>*)p;
        uint32_t count = 0;
@@ -3730,9 +3868,9 @@ void CFISection<arm>::cfiParse(class Parser<arm>& parser, uint8_t* buffer,
 template <typename A>
 uint32_t CFISection<A>::computeAtomCount(class Parser<A>& parser, 
                                                                                        struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                                       const struct Parser<A>::CFIInfoArray& cfis)
+                                                                                       const struct Parser<A>::CFI_CU_InfoArrays& cfis)
 {
-       return cfis.count;
+       return cfis.cfiCount;
 }
 
 
@@ -3740,12 +3878,12 @@ uint32_t CFISection<A>::computeAtomCount(class Parser<A>& parser,
 template <typename A>
 uint32_t CFISection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p, 
                                                                        struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                       const struct Parser<A>::CFIInfoArray& cfis)
+                                                                       const struct Parser<A>::CFI_CU_InfoArrays& cfis)
 {
        this->_beginAtoms = (Atom<A>*)p;
        // walk CFI_Atom_Info array and create atom for each entry
-       const CFI_Atom_Info* start = &cfis.array[0];
-       const CFI_Atom_Info* end   = &cfis.array[cfis.count];
+       const CFI_Atom_Info* start = &cfis.cfiArray[0];
+       const CFI_Atom_Info* end   = &cfis.cfiArray[cfis.cfiCount];
        for(const CFI_Atom_Info* a=start; a < end; ++a) {
                Atom<A>* space = (Atom<A>*)p;
                new (space) Atom<A>(*this, (a->isCIE ? "CIE" : "FDE"), a->address, a->size, 
@@ -3755,7 +3893,7 @@ uint32_t CFISection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p,
                p += sizeof(Atom<A>);
        }
        this->_endAtoms = (Atom<A>*)p;
-       return cfis.count;
+       return cfis.cfiCount;
 }
 
 
@@ -3845,14 +3983,14 @@ void CFISection<A>::addCiePersonalityFixups(class Parser<A>& parser, const CFI_A
 }
 
 template <typename A>
-void CFISection<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray& cfis)
+void CFISection<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays& cfis)
 {
        ld::Fixup::Kind store32 = bigEndian() ? ld::Fixup::kindStoreBigEndian32 : ld::Fixup::kindStoreLittleEndian32;
        ld::Fixup::Kind store64 = bigEndian() ? ld::Fixup::kindStoreBigEndian64 : ld::Fixup::kindStoreLittleEndian64;
 
        // add all references for FDEs, including implicit group references
-       const CFI_Atom_Info* end = &cfis.array[cfis.count];
-       for(const CFI_Atom_Info* p = &cfis.array[0]; p < end; ++p) {
+       const CFI_Atom_Info* end = &cfis.cfiArray[cfis.cfiCount];
+       for(const CFI_Atom_Info* p = &cfis.cfiArray[0]; p < end; ++p) {
                if ( p->isCIE ) {
                        // add reference to personality function if used
                        if ( p->u.cieInfo.personality.targetAddress != CFI_INVALID_ADDRESS ) {
@@ -4072,6 +4210,136 @@ typename A::P::uint_t CFISection<A>::OAS::getEncodedP(pint_t& addr, pint_t end,
        return result;
 }
 
+template <>
+const char* CUSection<x86_64>::personalityName(class Parser<x86_64>& parser, const macho_relocation_info<x86_64::P>* reloc)
+{
+       assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+       assert((reloc->r_type() == X86_64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
+       const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+       return parser.nameFromSymbol(sym);
+}
+
+template <>
+const char* CUSection<x86>::personalityName(class Parser<x86>& parser, const macho_relocation_info<x86::P>* reloc)
+{
+       assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+       assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section");
+       const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+       return parser.nameFromSymbol(sym);
+}
+
+template <typename A>
+const char* CUSection<A>::personalityName(class Parser<A>& parser, const macho_relocation_info<P>* reloc)
+{
+       return NULL;
+}
+
+
+template <typename A>
+int CUSection<A>::infoSorter(const void* l, const void* r)
+{
+       // sort references by symbol index, then address 
+       const Info* left = (Info*)l;
+       const Info* right = (Info*)r;
+       if ( left->functionSymbolIndex == right->functionSymbolIndex )
+               return (left->functionStartAddress - right->functionStartAddress);
+       else
+               return (left->functionSymbolIndex - right->functionSymbolIndex);
+}
+
+template <typename A>
+void CUSection<A>::parse(class Parser<A>& parser, uint32_t cnt, Info array[])
+{
+       // walk section content and copy to Info array
+       const macho_compact_unwind_entry<P>* const entries = (macho_compact_unwind_entry<P>*)(this->file().fileContent() + this->_machOSection->offset());
+       for (uint32_t i=0; i < cnt; ++i) {
+               Info* info = &array[i];
+               const macho_compact_unwind_entry<P>* entry = &entries[i];
+               info->functionStartAddress      = entry->codeStart();
+               info->functionSymbolIndex   = 0xFFFFFFFF;
+               info->rangeLength                       = entry->codeLen();
+               info->compactUnwindInfo         = entry->compactUnwindInfo();
+               info->personality                       = NULL;
+               info->lsdaAddress                       = entry->lsda();
+               info->function                          = NULL;
+               info->lsda                                      = NULL;
+               if ( (info->compactUnwindInfo & UNWIND_PERSONALITY_MASK) != 0 )
+                       warning("no bits should be set in UNWIND_PERSONALITY_MASK of compact unwind encoding in __LD,__compact_unwind section");
+               if ( info->lsdaAddress != 0 ) {
+                       info->compactUnwindInfo |= UNWIND_HAS_LSDA;
+               }
+       }
+       
+       // scan relocs, local relocs are useless - ignore them
+       // extern relocs are needed for personality references (possibly for function/lsda refs??)
+       const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(this->file().fileContent() + this->_machOSection->reloff());
+       const macho_relocation_info<P>* relocsEnd = &relocs[this->_machOSection->nreloc()];
+       for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
+               if ( reloc->r_extern() ) {
+                       // only expect external relocs on some colummns
+                       if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry<P>)) == macho_compact_unwind_entry<P>::personalityFieldOffset() ) {
+                               uint32_t entryIndex = reloc->r_address() / sizeof(macho_compact_unwind_entry<P>);
+                               array[entryIndex].personality = this->personalityName(parser, reloc);
+                       }
+                       else if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry<P>)) == macho_compact_unwind_entry<P>::lsdaFieldOffset() ) {
+                               uint32_t entryIndex = reloc->r_address() / sizeof(macho_compact_unwind_entry<P>);
+                               const macho_nlist<P>& lsdaSym = parser.symbolFromIndex(reloc->r_symbolnum());
+                               if ( (lsdaSym.n_type() & N_TYPE) == N_SECT ) 
+                                       array[entryIndex].lsdaAddress = lsdaSym.n_value();
+                               else
+                                       warning("unexpected extern relocation to lsda in __compact_unwind section");
+                       }
+                       else if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry<P>)) == macho_compact_unwind_entry<P>::codeStartFieldOffset() ) {
+                               uint32_t entryIndex = reloc->r_address() / sizeof(macho_compact_unwind_entry<P>);
+                               array[entryIndex].functionSymbolIndex = reloc->r_symbolnum();
+                       }
+                       else {
+                               warning("unexpected extern relocation in __compact_unwind section");
+                       }
+               }
+       }
+       
+       // sort array by function start address so unwind infos will be contiguous for a given function
+       ::qsort(array, cnt, sizeof(Info), infoSorter);
+}
+
+template <typename A>
+uint32_t CUSection<A>::count()
+{
+       const macho_section<P>* machoSect =     this->machoSection();
+       if ( (machoSect->size() % sizeof(macho_compact_unwind_entry<P>)) != 0 )
+               throw "malformed __LD,__compact_unwind section, bad length";
+               
+       return machoSect->size() / sizeof(macho_compact_unwind_entry<P>);
+}
+
+template <typename A>
+void CUSection<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays& cus)
+{
+       Info* const arrayStart = cus.cuArray;
+       Info* const arrayEnd = &cus.cuArray[cus.cuCount];
+       for (Info* info=arrayStart; info < arrayEnd; ++info) {
+               // if external reloc was used, real address is symbol n_value + addend
+               if ( info->functionSymbolIndex != 0xFFFFFFFF )
+                       info->functionStartAddress += parser.symbolFromIndex(info->functionSymbolIndex).n_value();
+               // find function atom from address
+               info->function = parser.findAtomByAddress(info->functionStartAddress);  
+               // find lsda atom from address
+               if ( info->lsdaAddress != 0 ) {
+                       info->lsda = parser.findAtomByAddress(info->lsdaAddress);               
+                       // add lsda subordinate
+                       typename Parser<A>::SourceLocation src(info->function, info->functionStartAddress - info->function->objectAddress());
+                       parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinateLSDA, info->lsda);
+               }
+               if ( info->personality != NULL ) {
+                       // add personality subordinate
+                       typename Parser<A>::SourceLocation src(info->function, info->functionStartAddress - info->function->objectAddress());
+                       parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinatePersonality, false, info->personality);
+               }
+       }
+       
+}
+
 template <typename A>
 SymboledSection<A>::SymboledSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
        : Section<A>(f, s), _type(ld::Atom::typeUnclassified) 
@@ -4127,7 +4395,7 @@ bool SymboledSection<A>::dontDeadStrip()
 template <typename A>
 uint32_t SymboledSection<A>::computeAtomCount(class Parser<A>& parser, 
                                                                                                struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                                               const struct Parser<A>::CFIInfoArray&)
+                                                                                               const struct Parser<A>::CFI_CU_InfoArrays&)
 {
        const pint_t startAddr = this->_machOSection->addr();
        const pint_t endAddr = startAddr + this->_machOSection->size();
@@ -4147,7 +4415,7 @@ uint32_t SymboledSection<A>::computeAtomCount(class Parser<A>& parser,
 template <typename A>
 uint32_t SymboledSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p, 
                                                                                        struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                                       const struct Parser<A>::CFIInfoArray&)
+                                                                                       const struct Parser<A>::CFI_CU_InfoArrays&)
 {
        this->_beginAtoms = (Atom<A>*)p;
 
@@ -4173,8 +4441,12 @@ uint32_t SymboledSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p,
                                this->_hasAliases = true;
                }
                else {
+                       ld::Atom::SymbolTableInclusion inclusion = ld::Atom::symbolTableNotIn;
+                       ld::Atom::ContentType ctype = this->contentType();
+                       if ( ctype == ld::Atom::typeLSDA )
+                               inclusion = ld::Atom::symbolTableInWithRandomAutoStripLabel;
                        new (allocatedSpace) Atom<A>(*this, "anon", addr, size, ld::Atom::definitionRegular, ld::Atom::combineNever, 
-                                                                               ld::Atom::scopeTranslationUnit, this->contentType(), ld::Atom::symbolTableNotIn, 
+                                                                               ld::Atom::scopeTranslationUnit, ctype, inclusion, 
                                                                                this->dontDeadStrip(), false, false, this->alignmentForAddress(addr));
                }
                p += sizeof(Atom<A>);
@@ -4189,7 +4461,7 @@ uint32_t SymboledSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p,
 template <typename A>
 uint32_t ImplicitSizeSection<A>::computeAtomCount(class Parser<A>& parser, 
                                                                                                        struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                                                       const struct Parser<A>::CFIInfoArray&)
+                                                                                                       const struct Parser<A>::CFI_CU_InfoArrays&)
 {
        uint32_t count = 0;
        const macho_section<P>* sect = this->machoSection();
@@ -4220,7 +4492,7 @@ uint32_t ImplicitSizeSection<A>::computeAtomCount(class Parser<A>& parser,
 template <typename A>
 uint32_t ImplicitSizeSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p, 
                                                                                        struct Parser<A>::LabelAndCFIBreakIterator& it, 
-                                                                                       const struct Parser<A>::CFIInfoArray&)
+                                                                                       const struct Parser<A>::CFI_CU_InfoArrays&)
 {
        this->_beginAtoms = (Atom<A>*)p;
        
@@ -4382,6 +4654,12 @@ bool CStringSection<A>::useElementAt(Parser<A>& parser, struct Parser<A>::LabelA
        return true;
 }
 
+template <typename A>
+bool CStringSection<A>::ignoreLabel(const char* label)  
+{ 
+       return (label[0] == 'L') || (label[0] == 'l'); 
+}
+
 template <typename A>
 Atom<A>* CStringSection<A>::findAtomByAddress(pint_t addr)
 {
@@ -4449,13 +4727,13 @@ ld::Fixup::Kind NonLazyPointerSection<ppc64>::fixupKind()
 }
 
 template <>
-void NonLazyPointerSection<x86_64>::makeFixups(class Parser<x86_64>& parser, const struct Parser<x86_64>::CFIInfoArray&)
+void NonLazyPointerSection<x86_64>::makeFixups(class Parser<x86_64>& parser, const struct Parser<x86_64>::CFI_CU_InfoArrays&)
 {
        assert(0 && "x86_64 should not have non-lazy-pointer sections in .o files");
 }
 
 template <typename A>
-void NonLazyPointerSection<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray&)
+void NonLazyPointerSection<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&)
 {
        // add references for each NLP atom based on indirect symbol table
        const macho_section<P>* sect = this->machoSection();
@@ -5192,7 +5470,7 @@ bool Section<x86>::addRelocFixup(class Parser<x86>& parser, const macho_relocati
                                const macho_nlist<P>& targetSymbol = parser.symbolFromIndex(reloc->r_symbolnum());
                                target.name = parser.nameFromSymbol(targetSymbol);
                                target.weakImport = parser.weakImportFromSymbol(targetSymbol);
-                               target.addend = contentValue;
+                               target.addend = (int32_t)contentValue;
                        }
                        else {
                                parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), target);
@@ -5247,6 +5525,7 @@ bool Section<x86>::addRelocFixup(class Parser<x86>& parser, const macho_relocati
                const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
                srcAddr = sect->addr() + sreloc->r_address();
                src.atom = this->findAtomByAddress(srcAddr);
+               assert(src.atom != NULL);
                src.offsetInAtom = srcAddr - src.atom->_objAddress;
                fixUpPtr = file().fileContent() + sect->offset() + sreloc->r_address();
                uint32_t relocValue = sreloc->r_value();
@@ -5279,17 +5558,17 @@ bool Section<x86>::addRelocFixup(class Parser<x86>& parser, const macho_relocati
                                        switch ( sreloc->r_length() ) {
                                                case 0:
                                                        contentValue = srcAddr + 1 + *fixUpPtr;
-                                                       target.addend = contentValue - relocValue;
+                                                       target.addend = (int32_t)contentValue - (int32_t)relocValue;
                                                        parser.addFixups(src, ld::Fixup::kindStoreX86PCRel8, target);
                                                        break;
                                                case 1:
                                                        contentValue = srcAddr + 2 + LittleEndian::get16(*((uint16_t*)fixUpPtr));
-                                                       target.addend = contentValue - relocValue;
+                                                       target.addend = (int32_t)contentValue - (int32_t)relocValue;
                                                        parser.addFixups(src, ld::Fixup::kindStoreX86PCRel16, target);
                                                        break;
                                                case 2:
                                                        contentValue = srcAddr + 4 + LittleEndian::get32(*((uint32_t*)fixUpPtr));
-                                                       target.addend = contentValue - relocValue;
+                                                       target.addend = (int32_t)contentValue - (int32_t)relocValue;
                                                        parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32, target);
                                                        break;
                                                case 3:
@@ -5301,7 +5580,7 @@ bool Section<x86>::addRelocFixup(class Parser<x86>& parser, const macho_relocati
                                        if ( sreloc->r_length() != 2 )
                                                throwf("unsupported r_length=%d for scattered vanilla reloc", sreloc->r_length());
                                        contentValue = LittleEndian::get32(*((uint32_t*)fixUpPtr));
-                                       target.addend = contentValue - target.atom->objectAddress();
+                                       target.addend = (int32_t)contentValue - (int32_t)(target.atom->objectAddress());
                                        parser.addFixups(src, ld::Fixup::kindStoreLittleEndian32, target);
                                }
                                break;
@@ -5327,7 +5606,7 @@ bool Section<x86>::addRelocFixup(class Parser<x86>& parser, const macho_relocati
                                        uint32_t offsetInFrom = nextRelocValue - fromAtom->_objAddress;
                                        parser.findTargetFromAddress(sreloc->r_value(), target);
                                        // check for addend encoded in the section content
-                                       int32_t addend = contentValue - (sreloc->r_value() - nextRelocValue);
+                                       int64_t addend = (int32_t)contentValue - (int32_t)(sreloc->r_value() - nextRelocValue);
                                        if ( addend < 0 ) {
                                                // switch binding base on coalescing
                                                if ( target.atom == NULL ) {
@@ -5801,12 +6080,18 @@ bool Section<arm>::addRelocFixup(class Parser<arm>& parser, const macho_relocati
                if ( reloc->r_type() != ARM_RELOC_PAIR )
                        instruction = LittleEndian::get32(*fixUpPtr);
                if ( reloc->r_extern() ) {
-                       target.atom = NULL;
                        const macho_nlist<P>& targetSymbol = parser.symbolFromIndex(reloc->r_symbolnum());
-                       target.name = parser.nameFromSymbol(targetSymbol);
-                       target.weakImport = parser.weakImportFromSymbol(targetSymbol);
-                       if ( ((targetSymbol.n_type() & N_TYPE) == N_SECT) &&  (targetSymbol.n_desc() & N_ARM_THUMB_DEF) )
-                               externSymbolIsThumbDef = true;
+                       // use direct reference for local symbols
+                       if ( ((targetSymbol.n_type() & N_TYPE) == N_SECT) && (((targetSymbol.n_type() & N_EXT) == 0) || (parser.nameFromSymbol(targetSymbol)[0] == 'L')) ) {
+                               parser.findTargetFromAddressAndSectionNum(targetSymbol.n_value(), targetSymbol.n_sect(), target);
+                       }
+                       else {
+                               target.atom = NULL;
+                               target.name = parser.nameFromSymbol(targetSymbol);
+                               target.weakImport = parser.weakImportFromSymbol(targetSymbol);
+                               if ( ((targetSymbol.n_type() & N_TYPE) == N_SECT) &&  (targetSymbol.n_desc() & N_ARM_THUMB_DEF) )
+                                       externSymbolIsThumbDef = true;
+                       }
                }
                switch ( reloc->r_type() ) {
                        case ARM_RELOC_BR24:
@@ -5892,7 +6177,7 @@ bool Section<arm>::addRelocFixup(class Parser<arm>& parser, const macho_relocati
                                        throw "bad length for ARM_RELOC_VANILLA";
                                contentValue = LittleEndian::get32(*fixUpPtr);
                                if ( reloc->r_extern() ) {
-                                       target.addend = contentValue;
+                                       target.addend = (int32_t)contentValue;
                                        if ( externSymbolIsThumbDef )
                                                target.addend &= -2; // remove thumb bit
                                }
@@ -5939,13 +6224,27 @@ bool Section<arm>::addRelocFixup(class Parser<arm>& parser, const macho_relocati
                                        if ( reloc->r_length() & 1 ) {
                                                // high 16
                                                dstAddr = ((instruction16 << 16) | other16);
-                                               parser.findTargetFromAddress(dstAddr, target);
+                        if ( reloc->r_extern() ) {
+                            target.addend = dstAddr;
+                        }
+                        else {
+                            parser.findTargetFromAddress(dstAddr, target);
+                            if ( target.atom->isThumb() )
+                                target.addend &= (-2); // remove thumb bit
+                        }
                                                parser.addFixups(src, (isThumb ? ld::Fixup::kindStoreThumbHigh16 : ld::Fixup::kindStoreARMHigh16), target);
                                        }
                                        else {
                                                // low 16
                                                dstAddr = (other16 << 16) | instruction16;
-                                               parser.findTargetFromAddress(dstAddr, target);
+                        if ( reloc->r_extern() ) {
+                            target.addend = dstAddr;
+                        }
+                        else {
+                            parser.findTargetFromAddress(dstAddr, target);
+                            if ( target.atom->isThumb() )
+                                target.addend &= (-2); // remove thumb bit
+                        }
                                                parser.addFixups(src, (isThumb ? ld::Fixup::kindStoreThumbLow16 : ld::Fixup::kindStoreARMLow16), target);
                                        }
                                        result = true;
@@ -6052,7 +6351,7 @@ bool Section<arm>::addRelocFixup(class Parser<arm>& parser, const macho_relocati
                                        uint32_t offsetInTarget;
                                        Atom<arm>* targetAtom = parser.findAtomByAddressOrLocalTargetOfStub(sreloc->r_value(), &offsetInTarget);
                                        // check for addend encoded in the section content
-                    int64_t addend = contentValue - (sreloc->r_value() - nextRelocValue);
+                    int64_t addend = (int32_t)contentValue - (int32_t)(sreloc->r_value() - nextRelocValue);
                                        if ( targetAtom->isThumb() )
                                                addend &= -2; // remove thumb bit
                                        // if reference to LSDA, add group subordinate fixup
@@ -6073,7 +6372,6 @@ bool Section<arm>::addRelocFixup(class Parser<arm>& parser, const macho_relocati
                                                else {
                                                        parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, targetAtom->name());
                                                }
-                                               parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom);
                                                parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, offsetInTarget);
                                                parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom);
                                                parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom-addend);
@@ -6103,8 +6401,6 @@ bool Section<arm>::addRelocFixup(class Parser<arm>& parser, const macho_relocati
                                        uint32_t offsetInFrom = nextRelocValue - fromAtom->_objAddress;
                                        Atom<arm>* targetAtom  = parser.findAtomByAddress(sreloc->r_value());
                                        uint32_t offsetInTarget = sreloc->r_value() - targetAtom->_objAddress;
-                                       //if ( targetAtom->isThumb() )
-                                       //      addend &= -2; // remove thumb bit
                                        uint32_t instruction16;
                                        uint32_t other16 = (nextRelocAddress & 0xFFFF);
                                        bool isThumb;
@@ -6126,6 +6422,8 @@ bool Section<arm>::addRelocFixup(class Parser<arm>& parser, const macho_relocati
                                                dstAddr = ((instruction16 << 16) | other16);
                                        else 
                                                dstAddr = (other16 << 16) | instruction16;
+                                       if ( targetAtom->isThumb() )
+                                               dstAddr &= (-2); // remove thumb bit
                     int32_t addend = dstAddr - (sreloc->r_value() - nextRelocValue);
                                        if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) {
                                                parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom);
@@ -6369,7 +6667,7 @@ bool Objc1ClassReferences<x86>::addRelocFixup(class Parser<x86>& parser, const m
 
 
 template <typename A>
-void Section<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray&)
+void Section<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&)
 {
        const macho_section<P>* sect = this->machoSection();
        const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(file().fileContent() + sect->reloff());
@@ -6380,7 +6678,7 @@ void Section<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI
                                ++r; // skip next
                }
                catch (const char* msg) {
-                       throwf("in section %s,%s reloc %u: %s", sect->segname(), sect->sectname(), r, msg);
+                       throwf("in section %s,%s reloc %u: %s", sect->segname(), Section<A>::makeSectionName(sect), r, msg);
                }
        }
        
@@ -6541,6 +6839,9 @@ bool hasObjC2Categories(const uint8_t* fileContent)
        else if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, false, 0) ) {
                return mach_o::relocatable::Parser<arm>::hasObjC2Categories(fileContent);
        }
+       else if ( mach_o::relocatable::Parser<x86>::validFile(fileContent, false, 0) ) {
+               return mach_o::relocatable::Parser<x86>::hasObjC2Categories(fileContent);
+       }
        return false;
 }                              
 
index d42fa54fb83d4c8a82b2ce41adad5a3f21e9a5f8..99b3eb8f4b70eacb8b6d263f3ceba6219e2d57fe 100644 (file)
@@ -312,7 +312,7 @@ static ld::Atom* makeBranchIsland(const Options& opts, ld::Fixup::Kind kind, int
                case ld::Fixup::kindStoreTargetAddressARMBranch24:
                case ld::Fixup::kindStoreTargetAddressThumbBranch22:
                        if ( finalTarget.atom->isThumb() ) {
-                               if ( opts.preferSubArchitecture() && opts.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
+                               if ( opts.preferSubArchitecture() && opts.archSupportsThumb2() ) {
                                        return new Thumb2toThumbBranchIslandAtom(name, nextTarget, finalTarget);
                                }
                                else if ( opts.outputSlidable() ) {
@@ -344,7 +344,7 @@ static uint64_t textSizeWhenMightNeedBranchIslands(const Options& opts, bool see
                case CPU_TYPE_ARM:
                        if ( ! seenThumbBranch )
                                return 32000000;  // ARM can branch +/- 32MB
-                       else if ( opts.preferSubArchitecture() && opts.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) 
+                       else if ( opts.preferSubArchitecture() && opts.archSupportsThumb2() ) 
                                return 16000000;  // thumb2 can branch +/- 16MB
                        else
                                return  4000000;  // thumb1 can branch +/- 4MB
@@ -365,7 +365,7 @@ static uint64_t maxDistanceBetweenIslands(const Options& opts, bool seenThumbBra
                case CPU_TYPE_ARM:
                        if ( ! seenThumbBranch )
                                return 30*1024*1024;    // 2MB of branch islands per 32MB
-                       else if ( opts.preferSubArchitecture() && opts.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) 
+                       else if ( opts.preferSubArchitecture() && opts.archSupportsThumb2() ) 
                                return 14*1024*1024;    // 2MB of branch islands per 16MB
                        else
                                return 3500000;                 // 0.5MB of branch islands per 4MB
index 70ebcfcf0f668c8529f305672de6ce72a210b1da..7a2bd50ea6b2907cf4f7ab59643da7a943e4332e 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2010-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -42,16 +42,14 @@ namespace branch_shim {
 
 
 static bool _s_log = false;
-static ld::Section _s_text_section("__TEXT", "__text", ld::Section::typeCode);
-
 
 
 class Thumb2ToArmShimAtom : public ld::Atom {
 public:
-                                                                                       Thumb2ToArmShimAtom(const ld::Atom* target)
-                               : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                                                       Thumb2ToArmShimAtom(const ld::Atom* target, const ld::Section& inSect)
+                               : ld::Atom(inSect, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
-                                                       ld::Atom::symbolTableIn, false, true, false, ld::Atom::Alignment(1)), 
+                                                       ld::Atom::symbolTableIn, false, true, false, ld::Atom::Alignment(2)), 
                                _name(NULL),
                                _target(target),
                                _fixup1(8, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, target),
@@ -90,13 +88,50 @@ private:
 };
 
 
+class NoPICThumb2ToArmShimAtom : public ld::Atom {
+public:
+                                                                                       NoPICThumb2ToArmShimAtom(const ld::Atom* target, const ld::Section& inSect)
+                               : ld::Atom(inSect, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
+                                                       ld::Atom::symbolTableIn, false, true, false, ld::Atom::Alignment(2)), 
+                               _name(NULL),
+                               _target(target),
+                               _fixup1(8, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, target)
+                                { asprintf((char**)&_name, "%s$shim", target->name()); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _name; }
+       virtual uint64_t                                                size() const                                    { return 12; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               // Use ARM instructions that can jump to thumb.
+               assert( !  _target->isThumb() );
+               if (_s_log) fprintf(stderr, "3 Thumb2 instruction shim to jump to %s\n", _target->name());
+               OSWriteLittleInt32(&buffer[0], 0, 0xc004f8df);  //      ldr  ip, pc + 4
+               OSWriteLittleInt16(&buffer[4], 0, 0x4760);              //      bx       ip
+               OSWriteLittleInt16(&buffer[6], 0, 0x46C0);              //      nop
+               OSWriteLittleInt32(&buffer[8], 0, 0x00000000);  //      .long target            
+       }
+
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup1)[1]; }
+
+private:
+       const char*                                                             _name;
+       const ld::Atom*                                                 _target;
+       ld::Fixup                                                               _fixup1;
+};
+
 
 class Thumb1ToArmShimAtom : public ld::Atom {
 public:
-                                                                                       Thumb1ToArmShimAtom(const ld::Atom* target)
-                               : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                                                       Thumb1ToArmShimAtom(const ld::Atom* target, const ld::Section& inSect)
+                               : ld::Atom(inSect, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
-                                                       ld::Atom::symbolTableIn, false, true, false, ld::Atom::Alignment(1)), 
+                                                       ld::Atom::symbolTableIn, false, true, false, ld::Atom::Alignment(2)), 
                                _name(NULL),
                                _target(target),
                                _fixup1(12, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, target),
@@ -141,8 +176,8 @@ private:
 
 class ARMtoThumbShimAtom : public ld::Atom {
 public:
-                                                                                       ARMtoThumbShimAtom(const ld::Atom* target)
-                               : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                                                       ARMtoThumbShimAtom(const ld::Atom* target, const ld::Section& inSect)
+                               : ld::Atom(inSect, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
                                                        ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)), 
                                _name(NULL),
@@ -182,6 +217,41 @@ private:
 };
 
 
+class NoPICARMtoThumbShimAtom : public ld::Atom {
+public:
+                                                                                       NoPICARMtoThumbShimAtom(const ld::Atom* target, const ld::Section& inSect)
+                               : ld::Atom(inSect, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
+                                                       ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _name(NULL),
+                               _target(target),
+                               _fixup1(8, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, target)
+                                { asprintf((char**)&_name, "%s$shim", target->name()); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _name; }
+       virtual uint64_t                                                size() const                                    { return 12; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               // Use ARM instructions that can jump to thumb.
+               if (_s_log) fprintf(stderr, "3 ARM instruction shim to jump to %s\n", _target->name());
+               OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); //      ldr  ip, pc + 4
+               OSWriteLittleInt32(&buffer[ 4], 0, 0xe12fff1c); //      bx       ip
+               OSWriteLittleInt32(&buffer[ 8], 0, 0);                  //      .long target            
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup1)[1]; }
+
+private:
+       const char*                                                             _name;
+       const ld::Atom*                                                 _target;
+       ld::Fixup                                                               _fixup1;
+};
+
+
 
 
 
@@ -216,10 +286,6 @@ static void extractTarget(ld::Fixup::iterator fixup, ld::Internal& state, const
 //
 void doPass(const Options& opts, ld::Internal& state)
 {      
-       std::map<const Atom*, const Atom*> atomToThumbMap;
-       std::map<const Atom*, const Atom*> thumbToAtomMap;
-       std::vector<const Atom*> shims;
-
        // only make branch shims in final linked images
        if ( opts.outputKind() == Options::kObjectFile )
                return;
@@ -228,84 +294,108 @@ void doPass(const Options& opts, ld::Internal& state)
        if ( opts.architecture() != CPU_TYPE_ARM )
                return;
        
-       // scan to find __text section
-       ld::Internal::FinalSection* textSection = NULL;
+       const bool makingKextBundle = (opts.outputKind() == Options::kKextBundle);
+
+       // scan all sections
        for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
-               if ( strcmp(sect->sectionName(), "__text") == 0 )
-                       textSection = sect;
-       }
-       if ( textSection == NULL )
-               return;
-       
-       // scan __text section for branch instructions that need to switch mode
-       for (std::vector<const ld::Atom*>::iterator ait=textSection->atoms.begin();  ait != textSection->atoms.end(); ++ait) {
-               const ld::Atom* atom = *ait;
-               const ld::Atom* target;
-               for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
-                       switch ( fit->kind ) {
-                               case ld::Fixup::kindStoreTargetAddressThumbBranch22:
-                                       extractTarget(fit, state, &target);
-                                       if ( ! target->isThumb() ) {
-                                               const uint8_t* fixUpLocation = atom->rawContentPointer() + fit->offsetInAtom;
-                                               uint32_t instruction = *((uint32_t*)fixUpLocation);
-                                               bool is_b = ((instruction & 0xD000F800) == 0x9000F000);
-                                               if ( is_b ) {
-                                                       fprintf(stderr, "need to add thumb->arm instr=0x%08X shim to %s for %s\n", instruction, target->name(), atom->name()); 
-                                                       const Atom* shim = NULL;
-                                                       std::map<const Atom*, const Atom*>::iterator pos = thumbToAtomMap.find(target);
-                                                       if ( pos == thumbToAtomMap.end() ) {
-                                                               if ( opts.subArchitecture() == CPU_SUBTYPE_ARM_V7 )
-                                                                       shim = new Thumb2ToArmShimAtom(target);
-                                                               else
-                                                                       shim = new Thumb1ToArmShimAtom(target);
-                                                               shims.push_back(shim);
-                                                               thumbToAtomMap[target] = shim;
+               std::map<const Atom*, const Atom*> atomToThumbMap;
+               std::map<const Atom*, const Atom*> thumbToAtomMap;
+               std::vector<const Atom*> shims;
+               // scan section for branch instructions that need to switch mode
+               for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin();  ait != sect->atoms.end(); ++ait) {
+                       const ld::Atom* atom = *ait;
+                       const ld::Atom* target = NULL;
+                       bool targetIsProxy;
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                               switch ( fit->kind ) {
+                                       case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                                               extractTarget(fit, state, &target);
+                                               targetIsProxy = (target->definition() == ld::Atom::definitionProxy);
+                                               if ( ! target->isThumb() ) {
+                                                       const uint8_t* fixUpLocation = atom->rawContentPointer();
+                                                       // <rdar://problem/9544194> don't try to scan atom for branches if atom unwilling to supply raw content
+                                                       if ( fixUpLocation == NULL )
+                                                               break;
+                                                       fixUpLocation += fit->offsetInAtom;
+                                                       uint32_t instruction = *((uint32_t*)fixUpLocation);
+                                                       bool is_b = ((instruction & 0xD000F800) == 0x9000F000);
+                                                       // need shim for branch from thumb to arm, or for call to function outside kext
+                                                       if ( is_b || (targetIsProxy && makingKextBundle) ) {
+                                                               if ( _s_log ) fprintf(stderr, "need to add thumb->arm instr=0x%08X shim to %s for %s\n", instruction, target->name(), atom->name()); 
+                                                               const Atom* shim = NULL;
+                                                               std::map<const Atom*, const Atom*>::iterator pos = thumbToAtomMap.find(target);
+                                                               if ( pos == thumbToAtomMap.end() ) {
+                                                                       if ( opts.archSupportsThumb2() ) {
+                                                                               // <rdar://problem/9116044> make long-branch style shims for arm kexts
+                                                                               if ( makingKextBundle )
+                                                                                       shim = new NoPICThumb2ToArmShimAtom(target, *sect);
+                                                                               else
+                                                                                       shim = new Thumb2ToArmShimAtom(target, *sect);
+                                                                       }
+                                                                       else {
+                                                                               shim = new Thumb1ToArmShimAtom(target, *sect);
+                                                                       }
+                                                                       shims.push_back(shim);
+                                                                       thumbToAtomMap[target] = shim;
+                                                               }
+                                                               else {
+                                                                       shim = pos->second;
+                                                               }
+                                                               fit->binding = ld::Fixup::bindingDirectlyBound;
+                                                               fit->u.target = shim;
                                                        }
-                                                       else {
-                                                               shim = pos->second;
-                                                       }
-                                                       fit->binding = ld::Fixup::bindingDirectlyBound;
-                                                       fit->u.target = shim;
                                                }
-                                       }
-                                       break;
-                               case ld::Fixup::kindStoreTargetAddressARMBranch24:
-                                       extractTarget(fit, state, &target);
-                                       if ( target->isThumb() ) {
-                                               const uint8_t* fixUpLocation = atom->rawContentPointer() + fit->offsetInAtom;
-                                               uint32_t instruction = *((uint32_t*)fixUpLocation);
-                                               bool is_b = ((instruction & 0x0F000000) == 0x0A000000);
-                                               if ( is_b ) {
-                                                       fprintf(stderr, "need to add arm->thumb instr=0x%08X shim to %s for %s\n", instruction, target->name(), atom->name()); 
-                                                       const Atom* shim = NULL;
-                                                       std::map<const Atom*, const Atom*>::iterator pos = atomToThumbMap.find(target);
-                                                       if ( pos == atomToThumbMap.end() ) {
-                                                               shim = new ARMtoThumbShimAtom(target);
-                                                               shims.push_back(shim);
-                                                               atomToThumbMap[target] = shim;
-                                                       }
-                                                       else {
-                                                               shim = pos->second;
+                                               break;
+                                       case ld::Fixup::kindStoreTargetAddressARMBranch24:
+                                               extractTarget(fit, state, &target);
+                                               targetIsProxy = (target->definition() == ld::Atom::definitionProxy);
+                                               if ( target->isThumb() || (targetIsProxy && makingKextBundle) ) {
+                                                       const uint8_t* fixUpLocation = atom->rawContentPointer();
+                                                       // <rdar://problem/9544194> don't try to scan atom for branches if atom unwilling to supply raw content
+                                                       if ( fixUpLocation == NULL )
+                                                               break;
+                                                       fixUpLocation += fit->offsetInAtom;
+                                                       uint32_t instruction = *((uint32_t*)fixUpLocation);
+                                                       bool is_b = ((instruction & 0x0F000000) == 0x0A000000) && ((instruction & 0xF0000000) != 0xF0000000);
+                                                       // need shim for branch from arm to thumb, or for call to function outside kext
+                                                       if ( is_b || (targetIsProxy && makingKextBundle) ) {
+                                                               if ( _s_log ) fprintf(stderr, "need to add arm->thumb instr=0x%08X shim to %s for %s\n", instruction, target->name(), atom->name()); 
+                                                               const Atom* shim = NULL;
+                                                               std::map<const Atom*, const Atom*>::iterator pos = atomToThumbMap.find(target);
+                                                               if ( pos == atomToThumbMap.end() ) {
+                                                                       // <rdar://problem/9116044> make long-branch style shims for arm kexts
+                                                                       if ( makingKextBundle )
+                                                                               shim = new NoPICARMtoThumbShimAtom(target, *sect);
+                                                                       else
+                                                                               shim = new ARMtoThumbShimAtom(target, *sect);
+                                                                       shims.push_back(shim);
+                                                                       atomToThumbMap[target] = shim;
+                                                               }
+                                                               else {
+                                                                       shim = pos->second;
+                                                               }
+                                                               fit->binding = ld::Fixup::bindingDirectlyBound;
+                                                               fit->u.target = shim;
                                                        }
-                                                       fit->binding = ld::Fixup::bindingDirectlyBound;
-                                                       fit->u.target = shim;
                                                }
-                                       }
-                                       break;
-                               
-                               case ld::Fixup::kindStoreARMBranch24:
-                               case ld::Fixup::kindStoreThumbBranch22:
-                                       fprintf(stderr, "found branch-22 without store in %s\n", atom->name()); 
-                                       break;
-                               default:
-                                       break;
+                                               break;
+                                       
+                                       //case ld::Fixup::kindStoreARMBranch24:
+                                       //case ld::Fixup::kindStoreThumbBranch22:
+                                       // Note: these fixups will only be seen if the the b/bl is to a symbol plus addend
+                                       // for now we don't handle making shims.  If a shim is needed there will
+                                       // be an error later.
+                                       //      break;
+                                       default:
+                                               break;
+                               }
                        }
                }
-       }
 
-       // append all new shims to end of __text
-       textSection->atoms.insert(textSection->atoms.end(), shims.begin(), shims.end());
+               // append all new shims to end of __text
+               sect->atoms.insert(sect->atoms.end(), shims.begin(), shims.end());
+       }
 }
 
 
index 5b9434ec4cf5aab7c3c5b8d8c5d8910f6cec8c19..86c8eec9789d143e8eb0fd2374a604e146adbe0d 100644 (file)
@@ -706,6 +706,11 @@ static void getAllUnwindInfos(const ld::Internal& state, std::vector<UnwindEntry
                                                        assert(fit->binding == ld::Fixup::bindingDirectlyBound);
                                                        lsda = fit->u.target;
                                                        break;
+                                               case ld::Fixup::kindNoneGroupSubordinatePersonality:
+                                                       assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                                                       personalityPointer = fit->u.target;
+                                                       assert(personalityPointer->section().type() == ld::Section::typeNonLazyPointer);
+                                                       break;
                                                default:
                                                        break;
                                        }
@@ -753,16 +758,8 @@ static void getAllUnwindInfos(const ld::Internal& state, std::vector<UnwindEntry
 }
 
 
-
-
-void doPass(const Options& opts, ld::Internal& state)
+static void makeFinalLinkedImageCompactUnwindSection(const Options& opts, ld::Internal& state)
 {
-       //const bool log = false;
-       
-       // only make make __unwind_info in final linked images
-       if ( !opts.needsUnwindInfoSection() )
-               return;
-
        // walk every atom and gets its unwind info
        std::vector<UnwindEntry> entries;
        entries.reserve(64);
@@ -789,6 +786,146 @@ void doPass(const Options& opts, ld::Internal& state)
 }
 
 
+
+template <typename A>
+class CompactUnwindAtom : public ld::Atom {
+public:
+                                                                                       CompactUnwindAtom(ld::Internal& state,const ld::Atom* funcAtom, 
+                                                                                                                         uint32_t startOffset, uint32_t len, uint32_t cui);
+                                                                                       ~CompactUnwindAtom() {}
+                                                                                       
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "compact unwind info"; }
+       virtual uint64_t                                                size() const                                    { return sizeof(macho_compact_unwind_entry<P>); }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixups[0]; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return (ld::Fixup*)&_fixups[_fixups.size()]; }
+
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+       
+
+       const ld::Atom*                                                 _atom;
+       const uint32_t                                                  _startOffset;
+       const uint32_t                                                  _len;
+       const uint32_t                                                  _compactUnwindInfo;
+       std::vector<ld::Fixup>                                  _fixups;
+       
+       static ld::Fixup::Kind                                  _s_pointerKind;
+       static ld::Fixup::Kind                                  _s_pointerStoreKind;
+       static ld::Section                                              _s_section;
+};
+
+
+template <typename A>
+ld::Section CompactUnwindAtom<A>::_s_section("__LD", "__compact_unwind", ld::Section::typeDebug);
+
+template <> ld::Fixup::Kind CompactUnwindAtom<x86>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian32;
+template <> ld::Fixup::Kind CompactUnwindAtom<x86>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian32;
+template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian64;
+template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian64;
+
+template <typename A>
+CompactUnwindAtom<A>::CompactUnwindAtom(ld::Internal& state,const ld::Atom* funcAtom, uint32_t startOffset,
+                                                                               uint32_t len, uint32_t cui)
+       : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                               ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified, 
+                               symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
+       _atom(funcAtom), _startOffset(startOffset), _len(len), _compactUnwindInfo(cui)
+{
+       _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, funcAtom));
+       _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k2of3, ld::Fixup::kindAddAddend, _startOffset));
+       _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k3of3, _s_pointerKind));
+       // see if atom has subordinate personality function or lsda
+       for (ld::Fixup::iterator fit = funcAtom->fixupsBegin(), end=funcAtom->fixupsEnd(); fit != end; ++fit) {
+               switch ( fit->kind ) {
+                       case ld::Fixup::kindNoneGroupSubordinatePersonality:
+                               assert(fit->binding == ld::Fixup::bindingsIndirectlyBound);
+                               _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::personalityFieldOffset(), ld::Fixup::k1of1, _s_pointerStoreKind, state.indirectBindingTable[fit->u.bindingIndex]));
+                               break;
+                       case ld::Fixup::kindNoneGroupSubordinateLSDA:
+                               assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                               _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::lsdaFieldOffset(), ld::Fixup::k1of1, _s_pointerStoreKind, fit->u.target));
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+}
+
+template <typename A>
+void CompactUnwindAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       macho_compact_unwind_entry<P>* buf = (macho_compact_unwind_entry<P>*)buffer;
+       buf->set_codeStart(0);
+       buf->set_codeLen(_len);
+       buf->set_compactUnwindInfo(_compactUnwindInfo);
+       buf->set_personality(0);
+       buf->set_lsda(0);
+}
+
+
+static void makeCompactUnwindAtom(const Options& opts, ld::Internal& state, const ld::Atom* atom, 
+                                                                                       uint32_t startOffset, uint32_t endOffset, uint32_t cui)
+{
+       switch ( opts.architecture() ) {
+               case CPU_TYPE_X86_64:
+                       state.addAtom(*new CompactUnwindAtom<x86_64>(state, atom, startOffset, endOffset-startOffset, cui));
+                       break;
+               case CPU_TYPE_I386:
+                       state.addAtom(*new CompactUnwindAtom<x86>(state, atom, startOffset, endOffset-startOffset, cui));
+                       break;
+       }
+}
+
+static void makeRelocateableCompactUnwindSection(const Options& opts, ld::Internal& state)
+{
+       // can't add CompactUnwindAtom atoms will iterating, so pre-scan
+       std::vector<const ld::Atom*> atomsWithUnwind;
+       for (std::vector<ld::Internal::FinalSection*>::const_iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                       const ld::Atom* atom = *ait;
+                       if ( atom->beginUnwind() != atom->endUnwind() ) 
+                               atomsWithUnwind.push_back(atom);
+               }
+       }
+       // make one CompactUnwindAtom for each compact unwind range in each atom
+       for (std::vector<const ld::Atom*>::iterator it = atomsWithUnwind.begin(); it != atomsWithUnwind.end(); ++it) {
+               const ld::Atom* atom = *it;
+               uint32_t lastOffset = 0;
+               uint32_t lastCUE = 0;
+               bool first = true;
+               for (ld::Atom::UnwindInfo::iterator uit=atom->beginUnwind(); uit != atom->endUnwind(); ++uit) {
+                       if ( !first ) {
+                               makeCompactUnwindAtom(opts, state, atom, lastOffset, uit->startOffset, lastCUE);
+                       }
+                       lastOffset = uit->startOffset;
+                       lastCUE = uit->unwindInfo;
+                       first = false;
+               }
+               makeCompactUnwindAtom(opts, state, atom, lastOffset, (uint32_t)atom->size(), lastCUE);
+       }
+}
+
+
+void doPass(const Options& opts, ld::Internal& state)
+{
+       if ( opts.outputKind() == Options::kObjectFile )
+               makeRelocateableCompactUnwindSection(opts, state);
+               
+       else if ( opts.needsUnwindInfoSection() ) 
+               makeFinalLinkedImageCompactUnwindSection(opts, state);
+}
+
+
 } // namespace compact_unwind
 } // namespace passes 
 } // namespace ld 
index 2b4452b5fd69825339709f5212ecc0812518769f..47b1647c732254cdf13c96aea724a389c3b8af1b 100644 (file)
@@ -72,12 +72,61 @@ void doPass(const Options& opts, ld::Internal& state)
                // set "willRemoved" bit on any unused explicit when -dead_strip_dylibs is used
                if ( opts.deadStripDylibs() && !aDylib->providedExportAtom() )
                        aDylib->setWillBeRemoved(true);
-       }
-       
-       
+       }       
        // remove unused dylibs
        state.dylibs.erase(std::remove_if(state.dylibs.begin(), state.dylibs.end(), WillBeUsed()), state.dylibs.end());
        
+       
+       // <rdar://problem/9441273> automatically weak-import dylibs when all symbols from it are weak-imported
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin();  ait != sect->atoms.end(); ++ait) {
+                       const ld::Atom* atom = *ait;
+                       const ld::Atom* target = NULL;
+                       bool targetIsWeakImport = false;
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                               if ( fit->firstInCluster() ) 
+                                       target = NULL;
+                               switch ( fit->binding ) {
+                                       case ld::Fixup::bindingsIndirectlyBound:
+                                               target = state.indirectBindingTable[fit->u.bindingIndex];
+                                               targetIsWeakImport = fit->weakImport;
+                                               break;
+                                       case ld::Fixup::bindingDirectlyBound:
+                                               target = fit->u.target;
+                                               targetIsWeakImport = fit->weakImport;
+                                               break;
+                    default:
+                        break;   
+                               }
+                               if ( (target != NULL) && (target->definition() == ld::Atom::definitionProxy) ) {
+                                       ld::Atom::WeakImportState curWI = target->weakImportState();
+                                       if ( curWI == ld::Atom::weakImportUnset ) {
+                                               // first use of this proxy, set weak-import based on this usage
+                                               (const_cast<ld::Atom*>(target))->setWeakImportState(targetIsWeakImport);
+                                       }
+                                       else {
+                                               // proxy already has weak-importness set, check for weakness mismatch
+                                               bool curIsWeakImport = (curWI == ld::Atom::weakImportTrue);
+                                               if ( curIsWeakImport != targetIsWeakImport ) {
+                                                       // found mismatch
+                                                       switch ( opts.weakReferenceMismatchTreatment() ) {
+                                                               case Options::kWeakReferenceMismatchError:
+                                                                       throwf("mismatching weak references for symbol: %s", target->name());
+                                                               case Options::kWeakReferenceMismatchWeak:
+                                                                       (const_cast<ld::Atom*>(target))->setWeakImportState(true);
+                                                                       break;
+                                                               case Options::kWeakReferenceMismatchNonWeak:
+                                                                       (const_cast<ld::Atom*>(target))->setWeakImportState(false);
+                                                                       break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       
 }
 
 
index ff18e0036ed148e62fca1fcc797e24052ee9ae86..bb94ddff4df855b55fb0760f39dcca5e1236b919 100644 (file)
@@ -105,6 +105,9 @@ static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom
                case ld::Fixup::kindStoreX86PCRel32GOT:
                        *optimizable = false;
                        return true;
+               case ld::Fixup::kindNoneGroupSubordinatePersonality:
+                       *optimizable = false;
+                       return true;
                default:
                        break;
        }
@@ -128,8 +131,8 @@ void doPass(const Options& opts, ld::Internal& internal)
        if ( opts.outputKind() == Options::kObjectFile )
                return;
 
-       // walk all atoms and fixups looking for stubable references
-       // don't create stubs inline because that could invalidate the sections walk
+       // walk all atoms and fixups looking for GOT-able references
+       // don't create GOT atoms during this loop because that could invalidate the sections iterator
        std::vector<const ld::Atom*> atomsReferencingGOT;
        std::map<const ld::Atom*,ld::Atom*> gotMap;
        std::map<const ld::Atom*,bool>          weakImportMap;
@@ -140,15 +143,18 @@ void doPass(const Options& opts, ld::Internal& internal)
                        const ld::Atom* atom = *ait;
                        bool atomUsesGOT = false;
                        const ld::Atom* targetOfGOT = NULL;
+                       bool targetIsWeakImport = false;
                        for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
                                if ( fit->firstInCluster() ) 
                                        targetOfGOT = NULL;
                                switch ( fit->binding ) {
                                        case ld::Fixup::bindingsIndirectlyBound:
                                                targetOfGOT = internal.indirectBindingTable[fit->u.bindingIndex];
+                                               targetIsWeakImport = fit->weakImport;
                                                break;
                                        case ld::Fixup::bindingDirectlyBound:
                                                targetOfGOT = fit->u.target;
+                                               targetIsWeakImport = fit->weakImport;
                                                break;
                     default:
                         break;   
@@ -183,19 +189,12 @@ void doPass(const Options& opts, ld::Internal& internal)
                                        std::map<const ld::Atom*,bool>::iterator pos = weakImportMap.find(targetOfGOT);
                                        if ( pos == weakImportMap.end() ) {
                                                // target not in weakImportMap, so add
-                                               weakImportMap[targetOfGOT] = fit->weakImport;
-                                               // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
-                                               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(targetOfGOT->file());
-                                               if ( dylib != NULL ) {
-                                                       if ( fit->weakImport )
-                                                               (const_cast<ld::dylib::File*>(dylib))->setUsingWeakImportedSymbols();
-                                                       else
-                                                               (const_cast<ld::dylib::File*>(dylib))->setUsingNonWeakImportedSymbols();
-                                               }
+                                               if ( log ) fprintf(stderr, "weakImportMap[%s] = %d\n", targetOfGOT->name(), targetIsWeakImport);
+                                               weakImportMap[targetOfGOT] = targetIsWeakImport; 
                                        }
                                        else {
                                                // target in weakImportMap, check for weakness mismatch
-                                               if ( pos->second != fit->weakImport ) {
+                                               if ( pos->second != targetIsWeakImport ) {
                                                        // found mismatch
                                                        switch ( opts.weakReferenceMismatchTreatment() ) {
                                                                case Options::kWeakReferenceMismatchError:
index f420b9ffd515eba7c3018d211295e11c539e6f0c..ed591931062eeedc62609763025b924e0de6144f 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2010-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -918,6 +918,7 @@ MethodListAtom<A>::MethodListAtom(ld::Internal& state, const ld::Atom* baseMetho
                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), _file(NULL), _methodCount(0) 
 {
        unsigned int fixupCount = 0;
+       std::set<const ld::Atom*> baseMethodListMethodNameAtoms;
        // if base class has method list, then associate new method list with file defining class
        if ( baseMethodList != NULL ) {
                _file = baseMethodList->file();
@@ -925,6 +926,14 @@ MethodListAtom<A>::MethodListAtom(ld::Internal& state, const ld::Atom* baseMetho
                _methodCount = MethodList<A>::count(state, baseMethodList);
                deadAtoms.insert(baseMethodList);
                fixupCount = baseMethodList->fixupsEnd() - baseMethodList->fixupsBegin();
+               for (ld::Fixup::iterator fit=baseMethodList->fixupsBegin(); fit != baseMethodList->fixupsEnd(); ++fit) {
+                       if ( (fit->offsetInAtom - 8) % (3*sizeof(pint_t)) == 0 ) {
+                               assert(fit->binding == ld::Fixup::bindingsIndirectlyBound && "malformed method list");
+                               const ld::Atom* target = state.indirectBindingTable[fit->u.bindingIndex];
+                               assert(target->contentType() == ld::Atom::typeCString && "malformed method list");
+                               baseMethodListMethodNameAtoms.insert(target);
+                       }
+               }
        }
        for (std::vector<const ld::Atom*>::const_iterator ait=categories->begin(); ait != categories->end(); ++ait) {
                const ld::Atom* categoryMethodListAtom;
@@ -950,6 +959,7 @@ MethodListAtom<A>::MethodListAtom(ld::Internal& state, const ld::Atom* baseMetho
        // copy fixups and adjust offsets (in reverse order to simulator objc runtime)
        _fixups.reserve(fixupCount);
        uint32_t slide = 0;
+       std::set<const ld::Atom*> categoryMethodNameAtoms;
        for (std::vector<const ld::Atom*>::const_reverse_iterator rit=categories->rbegin(); rit != categories->rend(); ++rit) {
                const ld::Atom* categoryMethodListAtom;
                if ( meta )
@@ -961,8 +971,24 @@ MethodListAtom<A>::MethodListAtom(ld::Internal& state, const ld::Atom* baseMetho
                                ld::Fixup fixup = *fit;
                                fixup.offsetInAtom += slide;
                                _fixups.push_back(fixup);
-                               //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
-                               //      fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
+                               if ( (fixup.offsetInAtom - 8) % (3*sizeof(pint_t)) == 0 ) {
+                                       // <rdar://problem/8642343> warning when a method is overridden in a category in the same link unit
+                                       assert(fixup.binding == ld::Fixup::bindingsIndirectlyBound && "malformed category method list");
+                                       const ld::Atom* target = state.indirectBindingTable[fixup.u.bindingIndex];
+                                       assert(target->contentType() == ld::Atom::typeCString && "malformed method list");
+                                       // this objc pass happens after cstrings are coalesced, so we can just compare the atom addres instead of its content
+                                       if ( baseMethodListMethodNameAtoms.count(target) != 0 ) {
+                                               warning("%s method '%s' in category from %s overrides method from class in %s", 
+                                                       (meta ? "meta" : "instance"), target->rawContentPointer(),
+                                                       categoryMethodListAtom->file()->path(), baseMethodList->file()->path() );
+                                       }
+                                       if ( categoryMethodNameAtoms.count(target) != 0 ) {
+                                               warning("%s method '%s' in category from %s conflicts with same method from another category", 
+                                                       (meta ? "meta" : "instance"), target->rawContentPointer(),
+                                                       categoryMethodListAtom->file()->path());
+                                       }
+                                       categoryMethodNameAtoms.insert(target);
+                               }
                        }
                        slide += 3*sizeof(pint_t) * MethodList<A>::count(state, categoryMethodListAtom);
                }
index 9e336aeadad42c9b1e549bc6aa62108e6298047a..5e814bd90fdcf1808d4187cf4ebc429a6fbd5579 100644 (file)
@@ -274,13 +274,25 @@ void Layout::buildNameTable()
                                        if ( pos == _nameTable.end() )
                                                _nameTable[name] = atom;
                                        else {
-                                               _nameTable[name] = NULL;        // collision, denote with NULL
+                                               const ld::Atom* existing = _nameTable[name];
+                                               if ( existing != NULL ) {
+                                                       _nameCollisionAtoms.push_back(existing);
+                                                       _nameTable[name] = NULL;        // collision, denote with NULL
+                                               }
                                                _nameCollisionAtoms.push_back(atom);
                                        }
                                }
                        }
                }
        }
+       if ( _s_log ) {
+               fprintf(stderr, "buildNameTable() _nameTable:\n");
+               for(NameToAtom::iterator it=_nameTable.begin(); it != _nameTable.end(); ++it)
+                       fprintf(stderr, "  %p <- %s\n", it->second, it->first);
+               fprintf(stderr, "buildNameTable() _nameCollisionAtoms:\n");
+               for(std::vector<const ld::Atom*>::iterator it=_nameCollisionAtoms.begin(); it != _nameCollisionAtoms.end(); ++it)
+                       fprintf(stderr, "  %p, %s\n", *it, (*it)->name());
+       }
 }
 
 
@@ -295,13 +307,14 @@ const ld::Atom* Layout::findAtom(const Options::OrderedSymbol& orderedSymbol)
                }
                if ( pos->second == NULL ) {
                        // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way
+                       if ( ( orderedSymbol.objectFileName == NULL) && _options.printOrderFileStatistics() ) {
+                               warning("%s specified in order_file but it exists in multiple .o files. "
+                                               "Prefix symbol with .o filename in order_file to disambiguate", orderedSymbol.symbolName);
+                       }
                        for (std::vector<const ld::Atom*>::iterator it=_nameCollisionAtoms.begin(); it != _nameCollisionAtoms.end(); it++) {
                                const ld::Atom* atom = *it;
                                if ( strcmp(atom->name(), orderedSymbol.symbolName) == 0 ) {
                                        if ( matchesObjectFile(atom, orderedSymbol.objectFileName) ) {
-                                               if ( _options.printOrderFileStatistics() )
-                                                       warning("%s specified in order_file but it exists in multiple .o files. "
-                                                                       "Prefix symbol with .o filename in order_file to disambiguate", orderedSymbol.symbolName);
                                                return atom;
                                        }
                                }
index 0e23c27f905c63485454a991db661a6bce9a5acb..274878bdc8ee9da4758c337c0726184da7b7b43b 100644 (file)
@@ -171,6 +171,11 @@ ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport)
                forLazyDylib = true;
        bool stubToResolver = (target.contentType() == ld::Atom::typeResolver);
        
+       if ( usingCompressedLINKEDIT() && !forLazyDylib ) {
+               if ( _internal->compressedFastBinderProxy == NULL )
+                       throwf("symbol dyld_stub_binder not found (normally in libSystem.dylib).  Needed to perform lazy binding to function %s", target.name());
+       }
+
        switch ( _architecture ) {
                case CPU_TYPE_POWERPC: 
                        if ( _pic )
@@ -275,14 +280,6 @@ void Pass::process(ld::Internal& state)
                                        if ( pos == weakImportMap.end() ) {
                                                // target not in weakImportMap, so add
                                                weakImportMap[stubableTargetOfFixup] = fit->weakImport;
-                                               // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
-                                               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(stubableTargetOfFixup->file());
-                                               if ( dylib != NULL ) {
-                                                       if ( fit->weakImport )
-                                                               (const_cast<ld::dylib::File*>(dylib))->setUsingWeakImportedSymbols();
-                                                       else
-                                                               (const_cast<ld::dylib::File*>(dylib))->setUsingNonWeakImportedSymbols();
-                                               }
                                        }
                                        else {
                                                // target in weakImportMap, check for weakness mismatch
@@ -329,9 +326,30 @@ void Pass::process(ld::Internal& state)
        if ( !_options.makeCompressedDyldInfo() && (state.classicBindingHelper == NULL) ) 
                throw "symbol dyld_stub_binding_helper not found, normally in crt1.o/dylib1.o/bundle1.o";
 
-       // disable close stubs when branch islands might be needed
-       if ( (_architecture == CPU_TYPE_ARM) && (codeSize > 4*1024*1024) )
-               _largeText = true;
+       // disable arm close stubs in some cases
+       if ( _architecture == CPU_TYPE_ARM ) {
+        if ( codeSize > 4*1024*1024 )
+            _largeText = true;
+        else {
+            for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+                ld::Internal::FinalSection* sect = *sit;
+                if ( sect->type() == ld::Section::typeMachHeader )
+                    continue;
+                if ( strcmp(sect->segmentName(), "__TEXT") == 0) {
+                    for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin();  ait != sect->atoms.end(); ++ait) {
+                        const ld::Atom* atom = *ait;
+                        if ( atom->alignment().powerOf2 > 10 ) {
+                            // overaligned section means might not be able to keep closestubs sect pushed to end of __TEXT
+                            //warning("alignment 1<<%d in atom %s in section %s disables close stubs optimization", 
+                            //        atom->alignment().powerOf2, atom->name(), sect->segmentName());
+                            _largeText = true;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
        
        // make stub atoms 
        for (std::map<const ld::Atom*,ld::Atom*>::iterator it = stubFor.begin(); it != stubFor.end(); ++it) {
index f40d01806518e12633b640d14095f58b1894a9db..a102e97d086f984b55c492099e2b5b68e552aa3d 100644 (file)
@@ -172,14 +172,6 @@ void doPass(const Options& opts, ld::Internal& internal)
                        if ( pos == weakImportMap.end() ) {
                                // target not in weakImportMap, so add
                                weakImportMap[it->targetOfTLV] = it->fixupWithTarget->weakImport;
-                               // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
-                               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(it->targetOfTLV->file());
-                               if ( dylib != NULL ) {
-                                       if ( it->fixupWithTarget->weakImport )
-                                               (const_cast<ld::dylib::File*>(dylib))->setUsingWeakImportedSymbols();
-                                       else
-                                               (const_cast<ld::dylib::File*>(dylib))->setUsingNonWeakImportedSymbols();
-                               }
                        }
                        else {
                                // target in weakImportMap, check for weakness mismatch
index abf716213f3b816b6376c5299aae1fa89b6ecbc5..3d7ac5eaa5c737f4714eaf697652a82484d97d82 100644 (file)
@@ -42,8 +42,9 @@ static bool                   sNMmode         = false;
 static bool                    sShowSection                    = true;
 static bool                    sShowDefinitionKind             = true;
 static bool                    sShowCombineKind                = true;
+static bool                    sShowLineInfo                   = true;
 
-static cpu_type_t              sPreferredArch = CPU_TYPE_I386;
+static cpu_type_t              sPreferredArch = 0xFFFFFFFF;
 static cpu_subtype_t   sPreferredSubArch = 0xFFFFFFFF;
 static const char* sMatchName = NULL;
 static int sPrintRestrict;
@@ -966,7 +967,20 @@ void dumper::dumpAtom(const ld::Atom& atom)
        if ( sShowSection )
                printf("section:  %s,%s\n", atom.section().segmentName(), atom.section().sectionName());
        if ( atom.beginUnwind() != atom.endUnwind() ) {
-               printf("unwind:   0x%08X\n", atom.beginUnwind()->unwindInfo);
+               uint32_t lastOffset = 0;
+               uint32_t lastCUE = 0;
+               bool first = true;
+               const char* label = "unwind:";
+               for (ld::Atom::UnwindInfo::iterator it=atom.beginUnwind(); it != atom.endUnwind(); ++it) {
+                       if ( !first ) {
+                               printf("%s   0x%08X -> 0x%08X: 0x%08X\n", label, lastOffset, it->startOffset, lastCUE);
+                               label = "       ";
+                       }
+                       lastOffset = it->startOffset;
+                       lastCUE = it->unwindInfo;
+                       first = false;
+               }
+               printf("%s   0x%08X -> 0x%08X: 0x%08X\n", label, lastOffset, (uint32_t)atom.size(), lastCUE);
        }
        if ( atom.contentType() == ld::Atom::typeCString ) {
                uint8_t buffer[atom.size()+2];
@@ -1028,13 +1042,15 @@ void dumper::dumpAtom(const ld::Atom& atom)
                        }
                }
        }
-       if ( atom.beginLineInfo() != atom.endLineInfo() ) {
-               printf("line info:\n");
-               for (ld::Atom::LineInfo::iterator it = atom.beginLineInfo(); it != atom.endLineInfo(); ++it) {
-                       printf("   offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName);
+       if ( sShowLineInfo ) {
+               if ( atom.beginLineInfo() != atom.endLineInfo() ) {
+                       printf("line info:\n");
+                       for (ld::Atom::LineInfo::iterator it = atom.beginLineInfo(); it != atom.endLineInfo(); ++it) {
+                               printf("   offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName);
+                       }
                }
        }
-
+       
        printf("\n");
 }
 
@@ -1088,14 +1104,27 @@ static ld::relocatable::File* createReader(const char* path)
        if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
                const struct fat_header* fh = (struct fat_header*)p;
                const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
-               for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
-                       if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) {
-                               if ( ((uint32_t)sPreferredSubArch == 0xFFFFFFFF) || ((uint32_t)sPreferredSubArch == OSSwapBigToHostInt32(archs[i].cpusubtype)) ) {
-                                       p = p + OSSwapBigToHostInt32(archs[i].offset);
-                                       mh = (struct mach_header*)p;
-                                       fileLen = OSSwapBigToHostInt32(archs[i].size);
-                                       foundFatSlice = true;
-                                       break;
+               if ( (uint32_t)sPreferredArch ==  0xFFFFFFFF ) {
+                       // just dump first slice of fat .o file
+                       if ( OSSwapBigToHostInt32(fh->nfat_arch) > 0 )  {
+                               p = p + OSSwapBigToHostInt32(archs[0].offset);
+                               mh = (struct mach_header*)p;
+                               fileLen = OSSwapBigToHostInt32(archs[0].size);
+                               sPreferredArch = OSSwapBigToHostInt32(archs[0].cputype);
+                               sPreferredSubArch = OSSwapBigToHostInt32(archs[0].cpusubtype);
+                               foundFatSlice = true;
+                       }
+               }
+               else {
+                       for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
+                               if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) {
+                                       if ( ((uint32_t)sPreferredSubArch == 0xFFFFFFFF) || ((uint32_t)sPreferredSubArch == OSSwapBigToHostInt32(archs[i].cpusubtype)) ) {
+                                               p = p + OSSwapBigToHostInt32(archs[i].offset);
+                                               mh = (struct mach_header*)p;
+                                               fileLen = OSSwapBigToHostInt32(archs[i].size);
+                                               foundFatSlice = true;
+                                               break;
+                                       }
                                }
                        }
                }
@@ -1186,6 +1215,9 @@ int main(int argc, const char* argv[])
                                else if ( strcmp(arg, "-no_combine") == 0 ) {
                                        sShowCombineKind = false;
                                }
+                               else if ( strcmp(arg, "-no_line_info") == 0 ) {
+                                       sShowLineInfo = false;
+                               }
                                else if ( strcmp(arg, "-arch") == 0 ) {
                                        const char* arch = ++i<argc? argv[i]: "";
                                        if ( strcmp(arch, "ppc64") == 0 )
@@ -1196,26 +1228,19 @@ 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 {
+                                               bool found = false;
+                                               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
+                                                       if ( strcmp(t->subTypeName,arch) == 0 ) {
+                                                               sPreferredArch = CPU_TYPE_ARM;
+                                                               sPreferredSubArch = t->subType;
+                                                               found = true;
+                                                               break;
+                                                       }
+                                               }
+                                               if ( !found )
+                                                       throwf("unknown architecture %s", arch);
                                        }
-                                       else 
-                                               throwf("unknown architecture %s", arch);
                                }
                                else if ( strcmp(arg, "-only") == 0 ) {
                                        sMatchName = ++i<argc? argv[i]: NULL;
index a6988ec2179c0be42375b73d13df7a02763facb9..2c86577133aaa4d0f3dab601eb9e4f261574433f 100644 (file)
@@ -50,7 +50,7 @@ static bool printExportNodes = false;
 static bool printSharedRegion = false;
 static bool printFunctionStarts = false;
 static bool printDylibs = false;
-static cpu_type_t      sPreferredArch = CPU_TYPE_I386;
+static cpu_type_t      sPreferredArch = 0;
 static cpu_type_t      sPreferredSubArch = 0;
 
 
@@ -73,8 +73,8 @@ class DyldInfoPrinter
 {
 public:
        static bool                                                                     validFile(const uint8_t* fileContent);
-       static DyldInfoPrinter<A>*                                      make(const uint8_t* fileContent, uint32_t fileLength, const char* path) 
-                                                                                                               { return new DyldInfoPrinter<A>(fileContent, fileLength, path); }
+       static DyldInfoPrinter<A>*                                      make(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch
+                                                                                                               { return new DyldInfoPrinter<A>(fileContent, fileLength, path, printArch); }
        virtual                                                                         ~DyldInfoPrinter() {}
 
 
@@ -91,7 +91,7 @@ private:
 
        typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  StringSet;
 
-                                                                                               DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path);
+                                                                                               DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch);
        void                                                                            printRebaseInfo();
        void                                                                            printRebaseInfoOpcodes();
        void                                                                            printBindingInfo();
@@ -246,7 +246,7 @@ bool DyldInfoPrinter<arm>::validFile(const uint8_t* fileContent)
 }
 
 template <typename A>
-DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path)
+DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch)
  : fHeader(NULL), fLength(fileLength), 
    fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fInfo(NULL), 
    fSharedRegionInfo(NULL), fFunctionStartsInfo(NULL), 
@@ -336,6 +336,28 @@ DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen
                cmd = (const macho_load_command<P>*)endOfCmd;
        }
        
+       if ( printArch ) {
+               switch ( fHeader->cputype() ) {
+                       case CPU_TYPE_I386:
+                               printf("for arch i386:\n");
+                               break;
+                       case CPU_TYPE_X86_64:
+                               printf("for arch x86_64:\n");
+                               break;
+                       case CPU_TYPE_POWERPC:                  
+                               printf("for arch ppc:\n");
+                               break;
+                       case CPU_TYPE_ARM:
+                               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
+                                       if ( (cpu_subtype_t)fHeader->cpusubtype() == t->subType) {
+                                               printf("for arch %s:\n", t->subTypeName);
+                                               break;
+                                       }
+                               }
+               }
+       }
+       
+       
        if ( printRebase ) {
                if ( fInfo != NULL )
                        printRebaseInfo();
@@ -1428,6 +1450,60 @@ const uint8_t* DyldInfoPrinter<A>::printSharedRegionInfoForEachULEB128Address(co
                case 4:
                        kindStr = "32-bit offset to IMPORT";
                        break;
+               case 5:
+                       kindStr = "thumb2 movw";
+                       break;
+               case 6:
+                       kindStr = "ARM movw";
+                       break;
+               case 0x10:
+                       kindStr = "thumb2 movt low high 4 bits=0";
+                       break;
+               case 0x11:
+                       kindStr = "thumb2 movt low high 4 bits=1";
+                       break;
+               case 0x12:
+                       kindStr = "thumb2 movt low high 4 bits=2";
+                       break;
+               case 0x13:
+                       kindStr = "thumb2 movt low high 4 bits=3";
+                       break;
+               case 0x14:
+                       kindStr = "thumb2 movt low high 4 bits=4";
+                       break;
+               case 0x15:
+                       kindStr = "thumb2 movt low high 4 bits=5";
+                       break;
+               case 0x16:
+                       kindStr = "thumb2 movt low high 4 bits=6";
+                       break;
+               case 0x17:
+                       kindStr = "thumb2 movt low high 4 bits=7";
+                       break;
+               case 0x18:
+                       kindStr = "thumb2 movt low high 4 bits=8";
+                       break;
+               case 0x19:
+                       kindStr = "thumb2 movt low high 4 bits=9";
+                       break;
+               case 0x1A:
+                       kindStr = "thumb2 movt low high 4 bits=0xA";
+                       break;
+               case 0x1B:
+                       kindStr = "thumb2 movt low high 4 bits=0xB";
+                       break;
+               case 0x1C:
+                       kindStr = "thumb2 movt low high 4 bits=0xC";
+                       break;
+               case 0x1D:
+                       kindStr = "thumb2 movt low high 4 bits=0xD";
+                       break;
+               case 0x1E:
+                       kindStr = "thumb2 movt low high 4 bits=0xE";
+                       break;
+               case 0x1F:
+                       kindStr = "thumb2 movt low high 4 bits=0xF";
+                       break;
        }
        uint64_t address = 0;
        uint64_t delta = 0;
@@ -1723,22 +1799,32 @@ void DyldInfoPrinter<A>::printSymbolTableExportInfo()
 template <typename A>
 const char* DyldInfoPrinter<A>::symbolNameForAddress(uint64_t addr)
 {
-       // find exact match in globals
-       const macho_nlist<P>* lastExport = &fSymbols[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
-       for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->iextdefsym()]; sym < lastExport; ++sym) {
-               if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
-                       return &fStrings[sym->n_strx()];
+       if ( fDynamicSymbolTable != NULL ) {
+               // find exact match in globals
+               const macho_nlist<P>* lastExport = &fSymbols[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
+               for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->iextdefsym()]; sym < lastExport; ++sym) {
+                       if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
+                               return &fStrings[sym->n_strx()];
+                       }
+               }
+               // find exact match in local symbols
+               const macho_nlist<P>* lastLocal = &fSymbols[fDynamicSymbolTable->ilocalsym()+fDynamicSymbolTable->nlocalsym()];
+               for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->ilocalsym()]; sym < lastLocal; ++sym) {
+                       if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
+                               return &fStrings[sym->n_strx()];
+                       }
                }
        }
-       // find exact match in local symbols
-       const macho_nlist<P>* lastLocal = &fSymbols[fDynamicSymbolTable->ilocalsym()+fDynamicSymbolTable->nlocalsym()];
-       for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->ilocalsym()]; sym < lastLocal; ++sym) {
-               if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
-                       return &fStrings[sym->n_strx()];
+       else {
+               // find exact match in all symbols
+               const macho_nlist<P>* lastSym = &fSymbols[fSymbolCount];
+               for (const macho_nlist<P>* sym = &fSymbols[0]; sym < lastSym; ++sym) {
+                       if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
+                               return &fStrings[sym->n_strx()];
+                       }
                }
        }
 
-
        return "?";
 }
  
@@ -1889,36 +1975,37 @@ static void dump(const char* path)
                                size_t size = OSSwapBigToHostInt32(archs[i].size);
                                cpu_type_t cputype = OSSwapBigToHostInt32(archs[i].cputype);
                                cpu_type_t cpusubtype = OSSwapBigToHostInt32(archs[i].cpusubtype);
-                               if ( (cputype == sPreferredArch) 
-                                       && ((sPreferredSubArch==0) || (sPreferredSubArch==cpusubtype)) ) {      
+                               if ( ((cputype == sPreferredArch) 
+                                       && ((sPreferredSubArch==0) || (sPreferredSubArch==cpusubtype)))
+                                       || (sPreferredArch == 0) ) {    
                                        switch(cputype) {
                                        case CPU_TYPE_POWERPC:
                                                if ( DyldInfoPrinter<ppc>::validFile(p + offset) )
-                                                       DyldInfoPrinter<ppc>::make(p + offset, size, path);
+                                                       DyldInfoPrinter<ppc>::make(p + offset, size, path, (sPreferredArch == 0));
                                                else
                                                        throw "in universal file, ppc slice does not contain ppc mach-o";
                                                break;
                                        case CPU_TYPE_I386:
                                                if ( DyldInfoPrinter<x86>::validFile(p + offset) )
-                                                       DyldInfoPrinter<x86>::make(p + offset, size, path);
+                                                       DyldInfoPrinter<x86>::make(p + offset, size, path, (sPreferredArch == 0));
                                                else
                                                        throw "in universal file, i386 slice does not contain i386 mach-o";
                                                break;
                                        case CPU_TYPE_POWERPC64:
                                                if ( DyldInfoPrinter<ppc64>::validFile(p + offset) )
-                                                       DyldInfoPrinter<ppc64>::make(p + offset, size, path);
+                                                       DyldInfoPrinter<ppc64>::make(p + offset, size, path, (sPreferredArch == 0));
                                                else
                                                        throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
                                                break;
                                        case CPU_TYPE_X86_64:
                                                if ( DyldInfoPrinter<x86_64>::validFile(p + offset) )
-                                                       DyldInfoPrinter<x86_64>::make(p + offset, size, path);
+                                                       DyldInfoPrinter<x86_64>::make(p + offset, size, path, (sPreferredArch == 0));
                                                else
                                                        throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
                                                break;
                                        case CPU_TYPE_ARM:
-                                               if ( DyldInfoPrinter<arm>::validFile(p + offset) )
-                                                       DyldInfoPrinter<arm>::make(p + offset, size, path);
+                                               if ( DyldInfoPrinter<arm>::validFile(p + offset) ) 
+                                                       DyldInfoPrinter<arm>::make(p + offset, size, path, (sPreferredArch == 0));
                                                else
                                                        throw "in universal file, arm slice does not contain arm mach-o";
                                                break;
@@ -1929,19 +2016,19 @@ static void dump(const char* path)
                        }
                }
                else if ( DyldInfoPrinter<x86>::validFile(p) ) {
-                       DyldInfoPrinter<x86>::make(p, length, path);
+                       DyldInfoPrinter<x86>::make(p, length, path, false);
                }
                else if ( DyldInfoPrinter<ppc>::validFile(p) ) {
-                       DyldInfoPrinter<ppc>::make(p, length, path);
+                       DyldInfoPrinter<ppc>::make(p, length, path, false);
                }
                else if ( DyldInfoPrinter<ppc64>::validFile(p) ) {
-                       DyldInfoPrinter<ppc64>::make(p, length, path);
+                       DyldInfoPrinter<ppc64>::make(p, length, path, false);
                }
                else if ( DyldInfoPrinter<x86_64>::validFile(p) ) {
-                       DyldInfoPrinter<x86_64>::make(p, length, path);
+                       DyldInfoPrinter<x86_64>::make(p, length, path, false);
                }
                else if ( DyldInfoPrinter<arm>::validFile(p) ) {
-                       DyldInfoPrinter<arm>::make(p, length, path);
+                       DyldInfoPrinter<arm>::make(p, length, path, false);
                }
                else {
                        throw "not a known file type";
@@ -1990,26 +2077,19 @@ 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 {
+                                               bool found = false;
+                                               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
+                                                       if ( strcmp(t->subTypeName,arch) == 0 ) {
+                                                               sPreferredArch = CPU_TYPE_ARM;
+                                                               sPreferredSubArch = t->subType;
+                                                               found = true;
+                                                               break;
+                                                       }
+                                               }
+                                               if ( !found )
+                                                       throwf("unknown architecture %s", arch);
                                        }
-                                       else 
-                                               throwf("unknown architecture %s", arch);
                                }
                                else if ( strcmp(arg, "-rebase") == 0 ) {
                                        printRebase = true;
index 295fa19798fa38eab3cbae9e3f56398fc88185f9..4841c7ca0c4ed47c7a4b812f0c566c63b8073f73 100644 (file)
@@ -73,6 +73,26 @@ static uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end)
        return result;
 }
 
+
+static int64_t read_sleb128(const uint8_t*& p, const uint8_t* end)
+{
+       int64_t result = 0;
+       int bit = 0;
+       uint8_t byte;
+       do {
+               if (p == end)
+                       throwf("malformed sleb128");
+               byte = *p++;
+               result |= ((byte & 0x7f) << bit);
+               bit += 7;
+       } while (byte & 0x80);
+       // sign extend negative numbers
+       if ( (byte & 0x40) != 0 )
+               result |= (-1LL) << bit;
+       return result;
+}
+
+
 template <typename A>
 class MachOChecker
 {
@@ -102,6 +122,7 @@ private:
        void                                                                            checkSection(const macho_segment_command<P>* segCmd, const macho_section<P>* sect);
        uint8_t                                                                         loadCommandSizeMask();
        void                                                                            checkSymbolTable();
+       void                                                                            checkInitTerms();
        void                                                                            checkIndirectSymbolTable();
        void                                                                            checkRelocations();
        void                                                                            checkExternalReloation(const macho_relocation_info<P>* reloc);
@@ -110,7 +131,13 @@ private:
        bool                                                                            addressInWritableSegment(pint_t address);
        bool                                                                            hasTextRelocInRange(pint_t start, pint_t end);
        pint_t                                                                          segStartAddress(uint8_t segIndex);
-
+       bool                                                                            addressIsRebaseSite(pint_t addr);
+       bool                                                                            addressIsBindingSite(pint_t addr);
+       pint_t                                                                          getInitialStackPointer(const macho_thread_command<P>*);
+       pint_t                                                                          getEntryPoint(const macho_thread_command<P>*);
+       
+       
+       
        const char*                                                                     fPath;
        const macho_header<P>*                                          fHeader;
        uint32_t                                                                        fLength;
@@ -126,8 +153,10 @@ private:
        const macho_relocation_info<P>*                         fExternalRelocations;
        uint32_t                                                                        fExternalRelocationsCount;
        bool                                                                            fWriteableSegmentWithAddrOver4G;
+       bool                                                                            fSlidableImage;
        const macho_segment_command<P>*                         fFirstSegment;
        const macho_segment_command<P>*                         fFirstWritableSegment;
+       const macho_segment_command<P>*                         fTEXTSegment;
        const macho_dyld_info_command<P>*                       fDyldInfo;
        uint32_t                                                                        fSectionCount;
        std::vector<const macho_segment_command<P>*>fSegments;
@@ -231,11 +260,78 @@ template <> uint8_t MachOChecker<x86>::loadCommandSizeMask()      { return 0x03; }
 template <> uint8_t MachOChecker<x86_64>::loadCommandSizeMask() { return 0x07; }
 template <> uint8_t MachOChecker<arm>::loadCommandSizeMask()   { return 0x03; }
 
+
+template <>
+ppc::P::uint_t MachOChecker<ppc>::getInitialStackPointer(const macho_thread_command<ppc::P>* threadInfo)
+{
+       return threadInfo->thread_register(3);
+}
+
+template <>
+ppc64::P::uint_t MachOChecker<ppc64>::getInitialStackPointer(const macho_thread_command<ppc64::P>* threadInfo)
+{
+       return threadInfo->thread_register(3);
+}
+
+template <>
+x86::P::uint_t MachOChecker<x86>::getInitialStackPointer(const macho_thread_command<x86::P>* threadInfo)
+{
+       return threadInfo->thread_register(7);
+}
+
+template <>
+x86_64::P::uint_t MachOChecker<x86_64>::getInitialStackPointer(const macho_thread_command<x86_64::P>* threadInfo)
+{
+       return threadInfo->thread_register(7);
+}
+
+template <>
+arm::P::uint_t MachOChecker<arm>::getInitialStackPointer(const macho_thread_command<arm::P>* threadInfo)
+{
+       return threadInfo->thread_register(13);
+}
+
+
+
+
+
+template <>
+ppc::P::uint_t MachOChecker<ppc>::getEntryPoint(const macho_thread_command<ppc::P>* threadInfo)
+{
+       return threadInfo->thread_register(0);
+}
+
+template <>
+ppc64::P::uint_t MachOChecker<ppc64>::getEntryPoint(const macho_thread_command<ppc64::P>* threadInfo)
+{
+       return threadInfo->thread_register(0);
+}
+
+template <>
+x86::P::uint_t MachOChecker<x86>::getEntryPoint(const macho_thread_command<x86::P>* threadInfo)
+{
+       return threadInfo->thread_register(10);
+}
+
+template <>
+x86_64::P::uint_t MachOChecker<x86_64>::getEntryPoint(const macho_thread_command<x86_64::P>* threadInfo)
+{
+       return threadInfo->thread_register(16);
+}
+
+template <>
+arm::P::uint_t MachOChecker<arm>::getEntryPoint(const macho_thread_command<arm::P>* threadInfo)
+{
+       return threadInfo->thread_register(15);
+}
+
+
 template <typename A>
 MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path)
  : fHeader(NULL), fLength(fileLength), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fDynamicSymbolTable(NULL), fIndirectTableCount(0),
  fLocalRelocations(NULL),  fLocalRelocationsCount(0),  fExternalRelocations(NULL),  fExternalRelocationsCount(0),
- fWriteableSegmentWithAddrOver4G(false), fFirstSegment(NULL), fFirstWritableSegment(NULL), fDyldInfo(NULL), fSectionCount(0)
+ fWriteableSegmentWithAddrOver4G(false), fSlidableImage(false), fFirstSegment(NULL), fFirstWritableSegment(NULL), 
+ fTEXTSegment(NULL), fDyldInfo(NULL), fSectionCount(0)
 {
        // sanity check
        if ( ! validFile(fileContent) )
@@ -255,6 +351,8 @@ MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, c
        checkRelocations();
        
        checkSymbolTable();
+       
+       checkInitTerms();
 }
 
 
@@ -270,6 +368,18 @@ void MachOChecker<A>::checkMachHeader()
                throw "invalid bits in mach_header flags";
        if ( (flags & MH_NO_REEXPORTED_DYLIBS) && (fHeader->filetype() != MH_DYLIB) ) 
                throw "MH_NO_REEXPORTED_DYLIBS bit of mach_header flags only valid for dylibs";
+       
+       switch ( fHeader->filetype() ) {
+               case MH_EXECUTE:
+                       fSlidableImage = ( flags & MH_PIE );
+                       break;
+               case MH_DYLIB:
+               case MH_BUNDLE:
+                       fSlidableImage = true;
+                       break;
+               default:
+                       throw "not a mach-o file type supported by this tool";
+       }
 }
 
 template <typename A>
@@ -277,6 +387,7 @@ void MachOChecker<A>::checkLoadCommands()
 {
        // check that all load commands fit within the load command space file
        const macho_encryption_info_command<P>* encryption_info = NULL;
+       const macho_thread_command<P>* threadInfo = NULL;
        const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
        const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
        const uint32_t cmd_count = fHeader->ncmds();
@@ -294,7 +405,6 @@ void MachOChecker<A>::checkLoadCommands()
                switch ( cmd->cmd()     ) {
                        case macho_segment_command<P>::CMD:
                        case LC_SYMTAB:
-                       case LC_UNIXTHREAD:
                        case LC_DYSYMTAB:
                        case LC_LOAD_DYLIB:
                        case LC_ID_DYLIB:
@@ -315,6 +425,7 @@ void MachOChecker<A>::checkLoadCommands()
                        case LC_VERSION_MIN_MACOSX:
                        case LC_VERSION_MIN_IPHONEOS:
                        case LC_FUNCTION_STARTS:
+                       case LC_RPATH:
                                break;
                        case LC_DYLD_INFO:
                        case LC_DYLD_INFO_ONLY:
@@ -328,6 +439,11 @@ void MachOChecker<A>::checkLoadCommands()
                                if ( fHeader->flags() & MH_NO_REEXPORTED_DYLIBS )
                                        throw "MH_NO_REEXPORTED_DYLIBS bit of mach_header flags should not be set in an image with LC_SUB_LIBRARY or LC_SUB_UMBRELLA";
                                break;
+                       case LC_UNIXTHREAD:
+                               if ( fHeader->filetype() != MH_EXECUTE )
+                                       throw "LC_UNIXTHREAD can only be used in MH_EXECUTE file types";
+                               threadInfo = (macho_thread_command<P>*)cmd;
+                               break;
                        default:
                                throwf("load command #%d is an unknown kind 0x%X", i, cmd->cmd());
                }
@@ -339,6 +455,7 @@ void MachOChecker<A>::checkLoadCommands()
        std::vector<std::pair<pint_t, pint_t> > segmentAddressRanges;
        std::vector<std::pair<pint_t, pint_t> > segmentFileOffsetRanges;
        const macho_segment_command<P>* linkEditSegment = NULL;
+       const macho_segment_command<P>* stackSegment = NULL;
        for (uint32_t i = 0; i < cmd_count; ++i) {
                if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
                        const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
@@ -389,32 +506,37 @@ void MachOChecker<A>::checkLoadCommands()
                        if ( endOffset > fLength )
                                throw "segment fileoff+filesize does not fit in file";
                                
-                       // keep LINKEDIT segment 
+                       // record special segments
                        if ( strcmp(segCmd->segname(), "__LINKEDIT") == 0 )
                                linkEditSegment = segCmd;
+                       else if ( strcmp(segCmd->segname(), "__UNIXSTACK") == 0 )
+                               stackSegment = segCmd;                  
 
                        // cache interesting segments
                        if ( fFirstSegment == NULL )
                                fFirstSegment = segCmd;
+                       if ( (fTEXTSegment == NULL) && (strcmp(segCmd->segname(), "__TEXT") == 0) )
+                               fTEXTSegment = segCmd;
                        if ( (segCmd->initprot() & VM_PROT_WRITE) != 0 ) {
                                if ( fFirstWritableSegment == NULL )
                                        fFirstWritableSegment = segCmd;
                                if ( segCmd->vmaddr() > 0x100000000ULL )
                                        fWriteableSegmentWithAddrOver4G = true;
                        }
-       
+                               
                        // check section ranges
                        const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
                        const macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
                        for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
-                               // check all sections are within segment
+                               // check all non-zero sized sections are within segment
                                if ( sect->addr() < startAddr )
                                        throwf("section %s vm address not within segment", sect->sectname());
                                if ( (sect->addr()+sect->size()) > endAddr )
                                        throwf("section %s vm address not within segment", sect->sectname());
                                if ( ((sect->flags() & SECTION_TYPE) != S_ZEROFILL) 
                                        && ((sect->flags() & SECTION_TYPE) != S_THREAD_LOCAL_ZEROFILL) 
-                                       && (segCmd->filesize() != 0) ) {
+                                       && (segCmd->filesize() != 0) 
+                                       && (sect->size() != 0) ) {
                                        if ( sect->offset() < startOffset )
                                                throwf("section %s file offset not within segment", sect->sectname());
                                        if ( (sect->offset()+sect->size()) > endOffset )
@@ -431,6 +553,45 @@ void MachOChecker<A>::checkLoadCommands()
        if ( linkEditSegment == NULL )
                throw "no __LINKEDIT segment";
        
+       // verify there was an executable __TEXT segment and load commands are in it
+       if ( fTEXTSegment == NULL )
+               throw "no __TEXT segment";
+       if ( fTEXTSegment->initprot() != (VM_PROT_READ|VM_PROT_EXECUTE) )
+               throw "__TEXT segment does not have r-x init permissions";
+       //if ( fTEXTSegment->maxprot() != (VM_PROT_READ|VM_PROT_EXECUTE|VM_PROT_WRITE) )
+       //      throw "__TEXT segment does not have rwx max permissions";
+       if ( fTEXTSegment->fileoff() != 0 )
+               throw "__TEXT segment does not start at mach_header";
+       if ( fTEXTSegment->filesize() < (sizeof(macho_header<P>)+fHeader->sizeofcmds()) )
+               throw "__TEXT segment smaller than load commands";
+       
+       // verify if custom stack used, that stack is in __UNIXSTACK segment
+       if ( threadInfo != NULL ) {
+               pint_t initialSP = getInitialStackPointer(threadInfo);
+               if ( initialSP != 0 ) {
+                       if ( stackSegment == NULL )
+                               throw "LC_UNIXTHREAD specifics custom initial stack pointer, but no __UNIXSTACK segment";
+                       if ( (initialSP < stackSegment->vmaddr()) || (initialSP > (stackSegment->vmaddr()+stackSegment->vmsize())) )
+                               throw "LC_UNIXTHREAD specifics custom initial stack pointer which does not point into __UNIXSTACK segment";
+               }
+       }
+       
+       // verify __UNIXSTACK is zero fill 
+       if ( stackSegment != NULL ) {
+                if ( (stackSegment->filesize() != 0) || (stackSegment->fileoff() != 0) )
+                       throw "__UNIXSTACK is not a zero-fill segment";
+                if ( stackSegment->vmsize() < 4096 )
+                       throw "__UNIXSTACK segment is too small";
+       }
+       
+       // verify entry point is in __TEXT segment 
+       if ( threadInfo != NULL ) {
+               pint_t initialPC = getEntryPoint(threadInfo);
+               if ( (initialPC < fTEXTSegment->vmaddr()) ||  (initialPC >= (fTEXTSegment->vmaddr()+fTEXTSegment->vmsize())) ) 
+                       throwf("entry point 0x%0llX is outside __TEXT segment", (long long)initialPC);
+       }
+       
+       
        // checks for executables
        bool isStaticExecutable = false;
        if ( fHeader->filetype() == MH_EXECUTE ) {
@@ -583,9 +744,16 @@ void MachOChecker<A>::checkSection(const macho_segment_command<P>* segCmd, const
                        throwf("section offset should be zero for zero-fill section %s", sect->sectname());
        }
        
+       // check section's segment name matches segment
+//     if ( strncmp(sect->segname(), segCmd->segname(), 16) != 0 )
+//             throwf("section %s in segment %s has wrong segment name", sect->sectname(), segCmd->segname());
+       
        // more section tests here
 }
 
+
+
+
 template <typename A>
 void MachOChecker<A>::checkIndirectSymbolTable()
 {
@@ -629,6 +797,8 @@ void MachOChecker<A>::checkIndirectSymbolTable()
 }
 
 
+
+
 template <typename A>
 void MachOChecker<A>::checkSymbolTable()
 {
@@ -674,6 +844,62 @@ void MachOChecker<A>::checkSymbolTable()
 }
 
 
+template <typename A>
+void MachOChecker<A>::checkInitTerms()
+{
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+       const uint32_t cmd_count = fHeader->ncmds();
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+                       const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+                       const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+                       const macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
+                       for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+                               // make sure all magic sections that use indirect symbol table fit within it
+                               uint32_t count;
+                               pint_t* arrayStart;
+                               pint_t* arrayEnd;
+                               const char* kind = "initializer";
+                               switch ( sect->flags() & SECTION_TYPE ) {
+                                       case S_MOD_TERM_FUNC_POINTERS:
+                                               kind = "terminator";
+                                               // fall through
+                                       case S_MOD_INIT_FUNC_POINTERS:
+                                               count = sect->size() / sizeof(pint_t);
+                                               if ( (count*sizeof(pint_t)) != sect->size() )
+                                                       throwf("%s section size is not an even multiple of element size", sect->sectname());
+                                               if ( (sect->addr() % sizeof(pint_t)) != 0 )
+                                                       throwf("%s section size is not pointer size aligned", sect->sectname());
+                                               // check each pointer in array points within TEXT
+                                               arrayStart = (pint_t*)((char*)fHeader + sect->offset());
+                                               arrayEnd = (pint_t*)((char*)fHeader + sect->offset() + sect->size());
+                                               for (pint_t* p=arrayStart; p < arrayEnd; ++p) {
+                                                       pint_t pointer = P::getP(*p);
+                                                       if ( (pointer < fTEXTSegment->vmaddr()) ||  (pointer >= (fTEXTSegment->vmaddr()+fTEXTSegment->vmsize())) ) 
+                                                               throwf("%s 0x%08llX points outside __TEXT segment", kind, (long long)pointer);
+                                               }
+                                               // check each pointer in array will be rebased and not bound
+                                               if ( fSlidableImage ) {
+                                                       pint_t sectionBeginAddr = sect->addr();
+                                                       pint_t sectionEndddr = sect->addr() + sect->size();
+                                                       for(pint_t addr = sectionBeginAddr; addr < sectionEndddr; addr += sizeof(pint_t)) {
+                                                               if ( addressIsBindingSite(addr) )
+                                                                       throwf("%s at 0x%0llX has binding to external symbol", kind, (long long)addr);
+                                                               if ( ! addressIsRebaseSite(addr) )
+                                                                       throwf("%s at 0x%0llX is not rebased", kind, (long long)addr);
+                                                       }
+                                               }
+                                               break;
+                               }
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+
+}
+
+
 template <>
 ppc::P::uint_t MachOChecker<ppc>::relocBase()
 {
@@ -1052,6 +1278,200 @@ bool MachOChecker<A>::hasTextRelocInRange(pint_t rangeStart, pint_t rangeEnd)
        }
 }
 
+template <typename A>
+bool MachOChecker<A>::addressIsRebaseSite(pint_t targetAddr)
+{
+       // look at local relocs
+       const macho_relocation_info<P>* const localRelocsEnd = &fLocalRelocations[fLocalRelocationsCount];
+       for (const macho_relocation_info<P>* reloc = fLocalRelocations; reloc < localRelocsEnd; ++reloc) {
+               pint_t relocAddress = reloc->r_address() + this->relocBase();
+               if ( relocAddress == targetAddr )
+                       return true;
+       }       
+       // look rebase info
+       if ( fDyldInfo != NULL ) {
+               const uint8_t* p = (uint8_t*)fHeader + fDyldInfo->rebase_off();
+               const uint8_t* end = &p[fDyldInfo->rebase_size()];
+               
+               uint8_t type = 0;
+               uint64_t segOffset = 0;
+               uint32_t count;
+               uint32_t skip;
+               int segIndex;
+               pint_t segStartAddr = 0;
+               pint_t addr;
+               bool done = false;
+               while ( !done && (p < end) ) {
+                       uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
+                       uint8_t opcode = *p & REBASE_OPCODE_MASK;
+                       ++p;
+                       switch (opcode) {
+                               case REBASE_OPCODE_DONE:
+                                       done = true;
+                                       break;
+                               case REBASE_OPCODE_SET_TYPE_IMM:
+                                       type = immediate;
+                                       break;
+                               case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                                       segIndex = immediate;
+                                       segStartAddr = segStartAddress(segIndex);
+                                       segOffset = read_uleb128(p, end);
+                                       break;
+                               case REBASE_OPCODE_ADD_ADDR_ULEB:
+                                       segOffset += read_uleb128(p, end);
+                                       break;
+                               case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+                                       segOffset += immediate*sizeof(pint_t);
+                                       break;
+                               case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+                                       for (int i=0; i < immediate; ++i) {
+                                               addr = segStartAddr+segOffset;
+                                               if ( addr == targetAddr )
+                                                       return true;
+                                               //printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                               segOffset += sizeof(pint_t);
+                                       }
+                                       break;
+                               case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+                                       count = read_uleb128(p, end);
+                                       for (uint32_t i=0; i < count; ++i) {
+                                               addr = segStartAddr+segOffset;
+                                               if ( addr == targetAddr )
+                                                       return true;
+                                               //printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                               segOffset += sizeof(pint_t);
+                                       }
+                                       break;
+                               case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+                                       addr = segStartAddr+segOffset;
+                                       if ( addr == targetAddr )
+                                               return true;
+                                       //printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                       segOffset += read_uleb128(p, end) + sizeof(pint_t);
+                                       break;
+                               case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
+                                       count = read_uleb128(p, end);
+                                       skip = read_uleb128(p, end);
+                                       for (uint32_t i=0; i < count; ++i) {
+                                               addr = segStartAddr+segOffset;
+                                               if ( addr == targetAddr )
+                                                       return true;
+                                               //printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                               segOffset += skip + sizeof(pint_t);
+                                       }
+                                       break;
+                               default:
+                                       throwf("bad rebase opcode %d", *p);
+                       }
+               }       
+       }
+       return false;
+}
+
+
+template <typename A>
+bool MachOChecker<A>::addressIsBindingSite(pint_t targetAddr)
+{
+       // look at external relocs
+       const macho_relocation_info<P>* const externRelocsEnd = &fExternalRelocations[fExternalRelocationsCount];
+       for (const macho_relocation_info<P>* reloc = fExternalRelocations; reloc < externRelocsEnd; ++reloc) {
+               pint_t relocAddress = reloc->r_address() + this->relocBase();
+               if ( relocAddress == targetAddr )
+                       return true;
+       }       
+       // look bind info
+       if ( fDyldInfo != NULL ) {
+               const uint8_t* p = (uint8_t*)fHeader + fDyldInfo->bind_off();
+               const uint8_t* end = &p[fDyldInfo->bind_size()];
+               
+               uint8_t type = 0;
+               uint64_t segOffset = 0;
+               uint32_t count;
+               uint32_t skip;
+               uint8_t flags;
+               const char* symbolName = NULL;
+               int libraryOrdinal = 0;
+               int segIndex;
+               int64_t addend = 0;
+               pint_t segStartAddr = 0;
+               pint_t addr;
+               bool done = false;
+               while ( !done && (p < end) ) {
+                       uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+                       uint8_t opcode = *p & BIND_OPCODE_MASK;
+                       ++p;
+                       switch (opcode) {
+                               case BIND_OPCODE_DONE:
+                                       done = true;
+                                       break;
+                               case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+                                       libraryOrdinal = immediate;
+                                       break;
+                               case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                                       libraryOrdinal = read_uleb128(p, end);
+                                       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;
+                                       }
+                                       break;
+                               case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                                       symbolName = (char*)p;
+                                       while (*p != '\0')
+                                               ++p;
+                                       ++p;
+                                       break;
+                               case BIND_OPCODE_SET_TYPE_IMM:
+                                       type = immediate;
+                                       break;
+                               case BIND_OPCODE_SET_ADDEND_SLEB:
+                                       addend = read_sleb128(p, end);
+                                       break;
+                               case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                                       segIndex = immediate;
+                                       segStartAddr = segStartAddress(segIndex);
+                                       segOffset = read_uleb128(p, end);
+                                       break;
+                               case BIND_OPCODE_ADD_ADDR_ULEB:
+                                       segOffset += read_uleb128(p, end);
+                                       break;
+                               case BIND_OPCODE_DO_BIND:
+                                       if ( (segStartAddr+segOffset) == targetAddr )
+                                               return true;
+                                       segOffset += sizeof(pint_t);
+                                       break;
+                               case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                                       if ( (segStartAddr+segOffset) == targetAddr )
+                                               return true;
+                                       segOffset += read_uleb128(p, end) + sizeof(pint_t);
+                                       break;
+                               case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+                                       if ( (segStartAddr+segOffset) == targetAddr )
+                                               return true;
+                                       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) {
+                                               if ( (segStartAddr+segOffset) == targetAddr )
+                                                       return true;
+                                               segOffset += skip + sizeof(pint_t);
+                                       }
+                                       break;
+                               default:
+                                       throwf("bad bind opcode %d", *p);
+                       }
+               }       
+       }
+       return false;
+}
+
+
 static void check(const char* path)
 {
        struct stat stat_buf;
@@ -1139,28 +1559,34 @@ static void check(const char* path)
 
 int main(int argc, const char* argv[])
 {
-       try {
-               for(int i=1; i < argc; ++i) {
-                       const char* arg = argv[i];
-                       if ( arg[0] == '-' ) {
-                               if ( strcmp(arg, "-no_content") == 0 ) {
-                                       
-                               }
-                               else {
-                                       throwf("unknown option: %s\n", arg);
-                               }
+       bool progress = false;
+       int result = 0;
+       for(int i=1; i < argc; ++i) {
+               const char* arg = argv[i];
+               if ( arg[0] == '-' ) {
+                       if ( strcmp(arg, "-progress") == 0 ) {
+                               progress = true;
                        }
                        else {
+                               throwf("unknown option: %s\n", arg);
+                       }
+               }
+               else {
+                       bool success = true;
+                       try {
                                check(arg);
                        }
+                       catch (const char* msg) {
+                               fprintf(stderr, "machocheck failed: %s %s\n", arg, msg);
+                               result = 1;
+                               success = false;
+                       }
+                       if ( success && progress )
+                               printf("ok: %s\n", arg);
                }
        }
-       catch (const char* msg) {
-               fprintf(stderr, "machocheck failed: %s\n", msg);
-               return 1;
-       }
        
-       return 0;
+       return result;
 }
 
 
index c04fb0a941e29b1fe22992f299563109efff0582..d69fc3ca52ca06594972e751944ad3be67d8e102 100644 (file)
@@ -1023,12 +1023,18 @@ int main(int argc, const char* argv[])
                                                onlyArchs.insert(CPU_TYPE_I386);
                                        else if ( strcmp(arch, "x86_64") == 0 )
                                                onlyArchs.insert(CPU_TYPE_X86_64);
-                                       else if ( strcmp(arch, "arm") == 0 )
-                                               onlyArchs.insert(CPU_TYPE_ARM);
-                                       else if ( strcmp(arch, "armv6") == 0 )
-                                               onlyArchs.insert(CPU_TYPE_ARM);
-                                       else 
-                                               throwf("unknown architecture %s", arch);
+                                       else {
+                                               bool found = false;
+                                               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
+                                                       if ( strcmp(t->subTypeName,arch) == 0 ) {
+                                                               onlyArchs.insert(CPU_TYPE_ARM);
+                                                               found = true;
+                                                               break;
+                                                       }
+                                               }
+                                               if ( !found )
+                                                       throwf("unknown architecture %s", arch);
+                                       }
                                }
                                else {
                                        usage();
index 81e677d2939d56186040e70b509c76f615092956..d24e62c57d471f3f19ecdb51184d74eea659a418 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -83,8 +83,12 @@ private:
                                                                                                                                const char* path, bool showFunctionNames);
        bool                                                                            findUnwindSection();
        void                                                                            printUnwindSection(bool showFunctionNames);
+       void                                                                            printObjectUnwindSection(bool showFunctionNames);
        void                                                                            getSymbolTableInfo();
-       const char*                                                                     functionName(pint_t addr);
+       const char*                                                                     functionName(pint_t addr, uint32_t* offset=NULL);
+       const char*                                                                     personalityName(const macho_relocation_info<typename A::P>* reloc);
+       bool                                                                            hasExernReloc(uint64_t sectionOffset, const char** personalityStr, pint_t* addr=NULL);
+
        static const char*                                                      archName();
        static void                                                                     decode(uint32_t encoding, const uint8_t* funcStart, char* str);
                
@@ -106,41 +110,6 @@ template <>         const char*    UnwindPrinter<x86>::archName()          { return "i386"; }
 template <>     const char*    UnwindPrinter<x86_64>::archName()       { return "x86_64"; }
 template <>     const char*    UnwindPrinter<arm>::archName()          { return "arm"; }
 
-template <>
-bool UnwindPrinter<ppc>::validFile(const uint8_t* fileContent)
-{      
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC )
-               return false;
-       if ( header->cputype() != CPU_TYPE_POWERPC )
-               return false;
-       switch (header->filetype()) {
-               case MH_EXECUTE:
-               case MH_DYLIB:
-               case MH_BUNDLE:
-               case MH_DYLINKER:
-                       return true;
-       }
-       return false;
-}
-
-template <>
-bool UnwindPrinter<ppc64>::validFile(const uint8_t* fileContent)
-{      
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC_64 )
-               return false;
-       if ( header->cputype() != CPU_TYPE_POWERPC64 )
-               return false;
-       switch (header->filetype()) {
-               case MH_EXECUTE:
-               case MH_DYLIB:
-               case MH_BUNDLE:
-               case MH_DYLINKER:
-                       return true;
-       }
-       return false;
-}
 
 template <>
 bool UnwindPrinter<x86>::validFile(const uint8_t* fileContent)
@@ -155,6 +124,7 @@ bool UnwindPrinter<x86>::validFile(const uint8_t* fileContent)
                case MH_DYLIB:
                case MH_BUNDLE:
                case MH_DYLINKER:
+               case MH_OBJECT:
                        return true;
        }
        return false;
@@ -173,24 +143,7 @@ bool UnwindPrinter<x86_64>::validFile(const uint8_t* fileContent)
                case MH_DYLIB:
                case MH_BUNDLE:
                case MH_DYLINKER:
-                       return true;
-       }
-       return false;
-}
-
-template <>
-bool UnwindPrinter<arm>::validFile(const uint8_t* fileContent)
-{      
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC )
-               return false;
-       if ( header->cputype() != CPU_TYPE_ARM )
-               return false;
-       switch (header->filetype()) {
-               case MH_EXECUTE:
-               case MH_DYLIB:
-               case MH_BUNDLE:
-               case MH_DYLINKER:
+               case MH_OBJECT:
                        return true;
        }
        return false;
@@ -211,8 +164,12 @@ UnwindPrinter<A>::UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength,
        
        getSymbolTableInfo();
        
-       if ( findUnwindSection() )
-               printUnwindSection(showFunctionNames);
+       if ( findUnwindSection() ) {
+               if ( fHeader->filetype() == MH_OBJECT ) 
+                       printObjectUnwindSection(showFunctionNames);
+               else
+                       printUnwindSection(showFunctionNames);
+       }
 }
 
 
@@ -243,8 +200,11 @@ void UnwindPrinter<A>::getSymbolTableInfo()
 }
 
 template <typename A>
-const char* UnwindPrinter<A>::functionName(pint_t addr)
+const char* UnwindPrinter<A>::functionName(pint_t addr, uint32_t* offset)
 {
+       const macho_nlist<P>* closestSymbol = NULL;
+       if ( offset != NULL )
+               *offset = 0;
        for (uint32_t i=0; i < fSymbolCount; ++i) {
                uint8_t type = fSymbols[i].n_type();
                if ( ((type & N_STAB) == 0) && ((type & N_TYPE) == N_SECT) ) {
@@ -253,8 +213,22 @@ const char* UnwindPrinter<A>::functionName(pint_t addr)
                                //fprintf(stderr, "addr=0x%08llX, i=%u, n_type=0x%0X, r=%s\n", (long long)(fSymbols[i].n_value()), i,  fSymbols[i].n_type(), r);
                                return r;
                        }
+                       else if ( offset != NULL ) {
+                               if ( closestSymbol == NULL ) {
+                                       if ( fSymbols[i].n_value() < addr )
+                                               closestSymbol = &fSymbols[i];
+                               }
+                               else {
+                                       if ( (fSymbols[i].n_value() < addr) && (fSymbols[i].n_value() > closestSymbol->n_value()) )
+                                               closestSymbol = &fSymbols[i];
+                               }
+                       }
                }
        }
+       if ( closestSymbol != NULL ) {
+               *offset = addr - closestSymbol->n_value();
+               return &fStrings[closestSymbol->n_strx()];
+       }
        return "--anonymous function--";
 }
 
@@ -263,6 +237,12 @@ const char* UnwindPrinter<A>::functionName(pint_t addr)
 template <typename A>
 bool UnwindPrinter<A>::findUnwindSection()
 {
+       const char* unwindSectionName = "__unwind_info";
+       const char* unwindSegmentName = "__TEXT";
+       if ( fHeader->filetype() == MH_OBJECT ) {
+               unwindSectionName = "__compact_unwind";
+               unwindSegmentName = "__LD";
+       }
        const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
        const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
        const uint32_t cmd_count = fHeader->ncmds();
@@ -280,7 +260,7 @@ bool UnwindPrinter<A>::findUnwindSection()
                        const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
                        const macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
                        for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
-                               if ( (strcmp(sect->sectname(), "__unwind_info") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) ) {
+                               if ( (strncmp(sect->sectname(), unwindSectionName, 16) == 0) && (strcmp(sect->segname(), unwindSegmentName) == 0) ) {
                                        fUnwindSection = sect;
                                        fMachHeaderAddress = segCmd->vmaddr();
                                        return fUnwindSection;
@@ -659,13 +639,97 @@ void UnwindPrinter<x86>::decode(uint32_t encoding, const uint8_t* funcStart, cha
 }
 
 
+
+template <>
+const char* UnwindPrinter<x86_64>::personalityName(const macho_relocation_info<x86_64::P>* reloc)
+{
+       //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+       //assert((reloc->r_type() == X86_64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
+       const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
+       return &fStrings[sym.n_strx()];
+}
+
+template <>
+const char* UnwindPrinter<x86>::personalityName(const macho_relocation_info<x86::P>* reloc)
+{
+       //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+       //assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section");
+       const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
+       return &fStrings[sym.n_strx()];
+}
+
 template <typename A>
-void UnwindPrinter<A>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
+bool UnwindPrinter<A>::hasExernReloc(uint64_t sectionOffset, const char** personalityStr, pint_t* addr)
 {
-       
+       const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((uint8_t*)fHeader + fUnwindSection->reloff());
+       const macho_relocation_info<P>* relocsEnd = &relocs[fUnwindSection->nreloc()];
+       for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
+               if ( reloc->r_extern() && (reloc->r_address() == sectionOffset) ) {
+                       *personalityStr = this->personalityName(reloc);
+                       if ( addr != NULL )
+                               *addr = fSymbols[reloc->r_symbolnum()].n_value();
+                       return true;
+               }
+       }
+       return false;
+}
+
 
+template <typename A>
+void UnwindPrinter<A>::printObjectUnwindSection(bool showFunctionNames)
+{
+       printf("Arch: %s, Section: __LD,__compact_unwind (size=0x%08llX, => %lld entries)\n", 
+                               archName(), fUnwindSection->size(), fUnwindSection->size() / sizeof(macho_compact_unwind_entry<P>));
+       
+       const macho_compact_unwind_entry<P>* const entriesStart = (macho_compact_unwind_entry<P>*)((uint8_t*)fHeader + fUnwindSection->offset());
+       const macho_compact_unwind_entry<P>* const entriesEnd = (macho_compact_unwind_entry<P>*)((uint8_t*)fHeader + fUnwindSection->offset() + fUnwindSection->size());
+       for (const macho_compact_unwind_entry<P>* entry=entriesStart; entry < entriesEnd; ++entry) {
+               uint64_t entryAddress = ((char*)entry - (char*)entriesStart) + fUnwindSection->addr();
+               printf("0x%08llX:\n", entryAddress);
+               const char* functionNameStr;
+               pint_t funcAddress;
+               uint32_t offsetInFunction;
+               if ( hasExernReloc(((char*)entry-(char*)entriesStart)+macho_compact_unwind_entry<P>::codeStartFieldOffset(), &functionNameStr, &funcAddress) ) {
+                       offsetInFunction = entry->codeStart();
+               }
+               else {
+                       functionNameStr = this->functionName(entry->codeStart(), &offsetInFunction);
+               }
+               if ( offsetInFunction == 0 )
+                       printf("  start:        0x%08llX   %s\n", (uint64_t)funcAddress, functionNameStr);
+               else
+                       printf("  start:        0x%08llX   %s+0x%X\n", (uint64_t)funcAddress+offsetInFunction, functionNameStr, offsetInFunction);
+               
+               printf("  end:          0x%08llX   (len=0x%08X)\n", (uint64_t)(funcAddress+offsetInFunction+entry->codeLen()), entry->codeLen());
+               
+               char encodingString[200];
+               this->decode(entry->compactUnwindInfo(), ((const uint8_t*)fHeader), encodingString);
+               printf("  unwind info:  0x%08X   %s\n", entry->compactUnwindInfo(), encodingString);
+               
+               const char* personalityNameStr;
+               if ( hasExernReloc(((char*)entry-(char*)entriesStart)+macho_compact_unwind_entry<P>::personalityFieldOffset(), &personalityNameStr) ) {
+                       printf("  personality:              %s\n", personalityNameStr);
+               }
+               else {
+                       printf("  personality:\n");
+               }
+               if ( entry->lsda() == 0 ) {
+                       printf("  lsda:\n");
+               }
+               else {
+                       uint32_t lsdaOffset;
+                       const char* lsdaName = this->functionName(entry->lsda(), &lsdaOffset);
+                       if ( lsdaOffset == 0 )
+                               printf("  lsda:         0x%08llX  %s\n", (uint64_t)entry->lsda(), lsdaName);
+                       else
+                               printf("  lsda:         0x%08llX  %s+0x%X\n", (uint64_t)entry->lsda(), lsdaName, lsdaOffset);
+               }
+       }
+       
 }
 
+
+
 template <typename A>
 void UnwindPrinter<A>::printUnwindSection(bool showFunctionNames)
 {
@@ -809,36 +873,18 @@ static void dump(const char* path, const std::set<cpu_type_t>& onlyArchs, bool s
                                unsigned int cputype = OSSwapBigToHostInt32(archs[i].cputype);
                                if ( onlyArchs.count(cputype) ) {
                                        switch(cputype) {
-                                       case CPU_TYPE_POWERPC:
-                                               if ( UnwindPrinter<ppc>::validFile(p + offset) )
-                                                       UnwindPrinter<ppc>::make(p + offset, size, path, showFunctionNames);
-                                               else
-                                                       throw "in universal file, ppc slice does not contain ppc mach-o";
-                                               break;
                                        case CPU_TYPE_I386:
                                                if ( UnwindPrinter<x86>::validFile(p + offset) )
                                                        UnwindPrinter<x86>::make(p + offset, size, path, showFunctionNames);
                                                else
                                                        throw "in universal file, i386 slice does not contain i386 mach-o";
                                                break;
-                                       case CPU_TYPE_POWERPC64:
-                                               if ( UnwindPrinter<ppc64>::validFile(p + offset) )
-                                                       UnwindPrinter<ppc64>::make(p + offset, size, path, showFunctionNames);
-                                               else
-                                                       throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
-                                               break;
                                        case CPU_TYPE_X86_64:
                                                if ( UnwindPrinter<x86_64>::validFile(p + offset) )
                                                        UnwindPrinter<x86_64>::make(p + offset, size, path, showFunctionNames);
                                                else
                                                        throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
                                                break;
-                                       case CPU_TYPE_ARM:
-                                               if ( UnwindPrinter<arm>::validFile(p + offset) )
-                                                       UnwindPrinter<arm>::make(p + offset, size, path, showFunctionNames);
-                                               else
-                                                       throw "in universal file, arm slice does not contain arm mach-o";
-                                               break;
                                        default:
                                                        throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
                                        }
@@ -848,18 +894,9 @@ static void dump(const char* path, const std::set<cpu_type_t>& onlyArchs, bool s
                else if ( UnwindPrinter<x86>::validFile(p) && onlyArchs.count(CPU_TYPE_I386) ) {
                        UnwindPrinter<x86>::make(p, length, path, showFunctionNames);
                }
-               else if ( UnwindPrinter<ppc>::validFile(p) && onlyArchs.count(CPU_TYPE_POWERPC) ) {
-                       UnwindPrinter<ppc>::make(p, length, path, showFunctionNames);
-               }
-               else if ( UnwindPrinter<ppc64>::validFile(p) && onlyArchs.count(CPU_TYPE_POWERPC64) ) {
-                       UnwindPrinter<ppc64>::make(p, length, path, showFunctionNames);
-               }
                else if ( UnwindPrinter<x86_64>::validFile(p) && onlyArchs.count(CPU_TYPE_X86_64) ) {
                        UnwindPrinter<x86_64>::make(p, length, path, showFunctionNames);
                }
-               else if ( UnwindPrinter<arm>::validFile(p) && onlyArchs.count(CPU_TYPE_ARM) ) {
-                       UnwindPrinter<arm>::make(p, length, path, showFunctionNames);
-               }
                else {
                        throw "not a known file type";
                }
@@ -882,16 +919,10 @@ int main(int argc, const char* argv[])
                        if ( arg[0] == '-' ) {
                                if ( strcmp(arg, "-arch") == 0 ) {
                                        const char* arch = argv[++i];
-                                       if ( strcmp(arch, "ppc") == 0 ) 
-                                               onlyArchs.insert(CPU_TYPE_POWERPC);
-                                       else if ( strcmp(arch, "ppc64") == 0 )
-                                               onlyArchs.insert(CPU_TYPE_POWERPC64);
-                                       else if ( strcmp(arch, "i386") == 0 )
+                                       if ( strcmp(arch, "i386") == 0 )
                                                onlyArchs.insert(CPU_TYPE_I386);
                                        else if ( strcmp(arch, "x86_64") == 0 )
                                                onlyArchs.insert(CPU_TYPE_X86_64);
-                                       else if ( strcmp(arch, "arm") == 0 )
-                                               onlyArchs.insert(CPU_TYPE_ARM);
                                        else 
                                                throwf("unknown architecture %s", arch);
                                }
@@ -909,11 +940,8 @@ int main(int argc, const char* argv[])
                
                // use all architectures if no restrictions specified
                if ( onlyArchs.size() == 0 ) {
-                       onlyArchs.insert(CPU_TYPE_POWERPC);
-                       onlyArchs.insert(CPU_TYPE_POWERPC64);
                        onlyArchs.insert(CPU_TYPE_I386);
                        onlyArchs.insert(CPU_TYPE_X86_64);
-                       onlyArchs.insert(CPU_TYPE_ARM);
                }
                
                // process each file
index 642e4917d5c765537ed9b8a3d979c608199d5289..adb5468c1fba2b271daf573e85a2ee17bebefd71 100644 (file)
@@ -8,6 +8,8 @@ ARCH ?= $(shell arch)
 # set default to be all
 VALID_ARCHS ?= "i386 x86_64 armv6"
 
+IOS_SDK = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.Internal.sdk
+
 MYDIR=$(shell cd ../../bin;pwd)
 LD                     = ld
 OBJECTDUMP     = ObjectDump
@@ -19,7 +21,8 @@ DYLDINFO      = dyldinfo
 ifdef BUILT_PRODUCTS_DIR
        # if run within Xcode, add the just built tools to the command path
        PATH := ${BUILT_PRODUCTS_DIR}:${MYDIR}:${PATH}
-       COMPILER_PATH := ${BUILT_PRODUCTS_DIR}:${MYDIR}:${COMPILER_PATH}
+       COMPILER_PATH := ${BUILT_PRODUCTS_DIR}:${COMPILER_PATH}
+       LD_PATH     = ${BUILT_PRODUCTS_DIR}
        LD                      = ${BUILT_PRODUCTS_DIR}/ld
        OBJECTDUMP      = ${BUILT_PRODUCTS_DIR}/ObjectDump
        MACHOCHECK      = ${BUILT_PRODUCTS_DIR}/machocheck
@@ -29,11 +32,11 @@ ifdef BUILT_PRODUCTS_DIR
 else
        ifneq "$(findstring /unit-tests/test-cases/, $(shell pwd))" ""
                # if run from Terminal inside unit-test directory
-               RELEASEDIR=$(shell cd ../../../build/Release;pwd)
                RELEASEADIR=$(shell cd ../../../build/Release-assert;pwd)
                DEBUGDIR=$(shell cd ../../../build/Debug;pwd)
                PATH := ${RELEASEADIR}:${RELEASEDIR}:${DEBUGDIR}:${MYDIR}:${PATH}
-               COMPILER_PATH := ${RELEASEADIR}:${RELEASEDIR}:${DEBUGDIR}:${MYDIR}:${COMPILER_PATH}
+               COMPILER_PATH := ${RELEASEADIR}:${RELEASEDIR}:${DEBUGDIR}:${COMPILER_PATH}
+               LD_PATH     = ${DEBUGDIR}
                LD                      = ${DEBUGDIR}/ld
                OBJECTDUMP      = ${DEBUGDIR}/ObjectDump
                MACHOCHECK      = ${DEBUGDIR}/machocheck
@@ -47,53 +50,76 @@ else
 endif
 export PATH
 export COMPILER_PATH
+export GCC_EXEC_PREFIX=garbage
 
 ifeq ($(ARCH),ppc)
        SDKExtra = -isysroot /Developer/SDKs/MacOSX10.6.sdk
 endif
 
 CC              = cc -arch ${ARCH} ${SDKExtra}
-CCFLAGS = -Wall -std=c99
+CCFLAGS = -Wall 
 ASMFLAGS =
+VERSION_NEW_LINKEDIT = -mmacosx-version-min=10.6
+VERSION_OLD_LINKEDIT = -mmacosx-version-min=10.4
+LD_NEW_LINKEDIT = -macosx_version_min 10.6
 
 CXX              = c++ -arch ${ARCH} ${SDKExtra}
 CXXFLAGS = -Wall
 
 ifeq ($(ARCH),armv6)
-       SDKExtra = -isysroot /Developer/SDKs/Extra
-  LDFLAGS := -syslibroot /Developer/SDKs/Extra
+  LDFLAGS := -syslibroot $(IOS_SDK)
   override FILEARCH = arm
+  CC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  CXX = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang++ -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
+  VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
+  LD_SYSROOT = -syslibroot $(IOS_SDK)
+  LD_NEW_LINKEDIT = -ios_version_min 4.0
 else
   FILEARCH = $(ARCH)
 endif
 
 ifeq ($(ARCH),armv7)
-       SDKExtra = -isysroot /Developer/SDKs/Extra
-  LDFLAGS := -syslibroot /Developer/SDKs/Extra
+  LDFLAGS := -syslibroot $(IOS_SDK)
   override FILEARCH = arm
+  CC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  CXX = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang++ -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
+  VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
+  LD_SYSROOT = -syslibroot $(IOS_SDK)
+  LD_NEW_LINKEDIT = -ios_version_min 4.0
 else
   FILEARCH = $(ARCH)
 endif
 
 ifeq ($(ARCH),thumb)
-       SDKExtra = -isysroot /Developer/SDKs/Extra
-  LDFLAGS := -syslibroot /Developer/SDKs/Extra
+  LDFLAGS := -syslibroot $(IOS_SDK)
   CCFLAGS += -mthumb
   CXXFLAGS += -mthumb
   override ARCH = armv6
   override FILEARCH = arm
+  CC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  CXX = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang++ -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
+  VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
+  LD_SYSROOT = -syslibroot $(IOS_SDK)
+  LD_NEW_LINKEDIT = -ios_version_min 4.0
 else
   FILEARCH = $(ARCH)
 endif
 
 ifeq ($(ARCH),thumb2)
-       SDKExtra = -isysroot /Developer/SDKs/Extra
-  LDFLAGS := -syslibroot /Developer/SDKs/Extra
+  LDFLAGS := -syslibroot $(IOS_SDK)
   CCFLAGS += -mthumb
   CXXFLAGS += -mthumb
   override ARCH = armv7
   override FILEARCH = arm
-       CC = /Volumes/Leopard/Developer/Platforms/iPhoneOS.platform/usr/bin/gcc-4.2 -arch ${ARCH}
+  CC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  CXX = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang++ -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
+  VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
+  LD_SYSROOT = -syslibroot $(IOS_SDK)
+  LD_NEW_LINKEDIT = -ios_version_min 4.0
 else
   FILEARCH = $(ARCH)
 endif
index f6275a758569b5fabf33e1d7f6ceb13b52b3a4e1..c07c947d5ecb63cb5b9252e7789c8308c5b4ef87 100755 (executable)
@@ -12,9 +12,15 @@ cd `echo "$0" | sed 's/run-all-unit-tests/test-cases/'`
 
 [ "$PROCTORRUN" ] && exec ../proctor-run
 
-all_archs="x86_64  ppc i386  "
-#armv6 thumb
-valid_archs="x86_64 armv6 ppc i386  "
+all_archs="x86_64  i386"
+valid_archs="x86_64 i386"
+# only test arm code if iOS platform tools installed
+if [ -d /Developer/Platforms/iPhoneOS.platform/Developer/SDKs ]
+then
+    all_archs="${all_archs}  armv7"
+    valid_archs="${valid_archs} armv7"
+fi
+
 
 # clean first
 ../bin/make-recursive.pl clean > /dev/null
index 806c64ed2251c86d8a658434022b351d83a5e008..bbdfd1150e413f8b8bfc6bc9a3c99e4e5e914c80 100644 (file)
@@ -30,10 +30,10 @@ include ${TESTROOT}/include/common.makefile
 all:
        ${CC} ${CCFLAGS} main.c -static -c
        ${CC} ${CCFLAGS} abs.s -static -c
-       ${LD} -arch ${ARCH} -static main.o abs.o -e _main -o main -new_linker
-       ${LD} -arch ${ARCH} -static -r main.o abs.o -o all.o -new_linker
+       ${LD} -arch ${ARCH} -static main.o abs.o -e _main -o main -new_linker -macosx_version_min 10.6
+       ${LD} -arch ${ARCH} -static -r main.o abs.o -o all.o -new_linker 
        nm -m all.o | grep _myAbs | grep absolute | ${FAIL_IF_EMPTY}
-       ${LD} -arch ${ARCH} -static all.o -e _main -o main2 -new_linker
+       ${LD} -arch ${ARCH} -static all.o -e _main -o main2 -new_linker -macosx_version_min 10.6
        ${PASS_IFF_GOOD_MACHO} main2
        
 clean:
index 1aee96f590010f85f15e834fe84bc5199be16f8c..dc5496fa86349a9192abdfb63b1414ca7da55772 100644 (file)
@@ -1,7 +1,7 @@
 
   .globl _myAbs
 #if __LP64__
-       _myAbs = 0x012345678
+       _myAbs = 0x102345678
 #else
        _myAbs = 0xfe000000
 #endif
index 48e59610cab671dc577e9caf042e8f24f310876e..3f3a9a6536ddea2485e0fb7ecd51a5c450f20584 100644 (file)
@@ -22,7 +22,8 @@
  */
 
        .text
-
+       .align 4
+       
 _temp: nop
                nop
                
index b21f8c7e91591e940b95e852afd78eab48312e8b..5e92d8d41c9d0cb22c9361e6725f0d3aee7ed0eb 100644 (file)
@@ -22,7 +22,8 @@
  */
 
        .text
-
+       .align 4
+       
 _temp: nop
                nop
                
index 5bb026fb4d0d225dba9f758fd729c8af576735d9..ae87948046f73b18cef819b2a43e167940b6bdbe 100644 (file)
@@ -32,7 +32,7 @@ IMAGE_INFO = "__image_info"
 ifeq ($(ARCH),x86_64)
        IMAGE_INFO = "__objc_imageinfo"
 endif
-ifeq ($(ARCH),armv6)
+ifeq (${FILEARCH},arm)
        IMAGE_INFO = "__objc_imageinfo"
 endif
 
diff --git a/unit-tests/test-cases/archive-order/Makefile b/unit-tests/test-cases/archive-order/Makefile
new file mode 100644 (file)
index 0000000..a1b6a3f
--- /dev/null
@@ -0,0 +1,47 @@
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check the order of functions from archives.
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.c -c -o foo.o 
+       ${CC} ${CCFLAGS} foo2.c -c -o foo2.o 
+       ${CC} ${CCFLAGS} foo3.c -c -o foo3.o 
+       ${CC} ${CCFLAGS} bar.c -c -o bar.o 
+       ${CC} ${CCFLAGS} bar2.c -c -o bar2.o 
+       ${CC} ${CCFLAGS} bar3.c -c -o bar3.o 
+       libtool -static foo.o foo2.o foo3.o -o libfoo.a
+       libtool -static bar3.o bar2.o bar.o -o libbar.a
+       ${CC} ${CCFLAGS} main.c -lbar -lfoo -L. -o main 
+       nm -njg main | egrep 'foo|bar' > found.order
+       diff found.order expected.order
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm -rf main *.o *.a found.order
diff --git a/unit-tests/test-cases/archive-order/bar.c b/unit-tests/test-cases/archive-order/bar.c
new file mode 100644 (file)
index 0000000..7fe6403
--- /dev/null
@@ -0,0 +1 @@
+int bar() { return 0; }
diff --git a/unit-tests/test-cases/archive-order/bar2.c b/unit-tests/test-cases/archive-order/bar2.c
new file mode 100644 (file)
index 0000000..54e8ace
--- /dev/null
@@ -0,0 +1 @@
+int bar2() { return 0; }
diff --git a/unit-tests/test-cases/archive-order/bar3.c b/unit-tests/test-cases/archive-order/bar3.c
new file mode 100644 (file)
index 0000000..0b44057
--- /dev/null
@@ -0,0 +1 @@
+int bar3() { return 0; }
diff --git a/unit-tests/test-cases/archive-order/expected.order b/unit-tests/test-cases/archive-order/expected.order
new file mode 100644 (file)
index 0000000..f060170
--- /dev/null
@@ -0,0 +1,6 @@
+_bar3
+_bar2
+_bar
+_foo
+_foo2
+_foo3
diff --git a/unit-tests/test-cases/archive-order/foo.c b/unit-tests/test-cases/archive-order/foo.c
new file mode 100644 (file)
index 0000000..a60f28c
--- /dev/null
@@ -0,0 +1 @@
+int foo() { return 1; }
diff --git a/unit-tests/test-cases/archive-order/foo2.c b/unit-tests/test-cases/archive-order/foo2.c
new file mode 100644 (file)
index 0000000..492879f
--- /dev/null
@@ -0,0 +1 @@
+int foo2() { return 1; }
diff --git a/unit-tests/test-cases/archive-order/foo3.c b/unit-tests/test-cases/archive-order/foo3.c
new file mode 100644 (file)
index 0000000..1de0bce
--- /dev/null
@@ -0,0 +1 @@
+int foo3() { return 1; }
diff --git a/unit-tests/test-cases/archive-order/main.c b/unit-tests/test-cases/archive-order/main.c
new file mode 100644 (file)
index 0000000..242b32a
--- /dev/null
@@ -0,0 +1,41 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+extern int foo();
+extern int foo2();
+extern int foo3();
+extern int bar();
+extern int bar2();
+extern int bar3();
+
+int main()
+{
+    foo();
+    bar();
+    foo2();
+    bar2();
+    foo3();
+    bar3();
+       return 0;
+}
\ No newline at end of file
index 3b1cc7c847ce42ebd6aeb8913c734f9c4d9af80e..06ca6edbb378b186a6ad98c11947c48bd361071f 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+ifeq ($(FILEARCH),arm)
+       LD_VERS = -ios_version_min 4.0 -syslibroot $(IOS_SDK)
+else
+       LD_VERS = -macosx_version_min 10.6
+endif
+
 
 #
 # Check that ld can figure out architecture from .o files without -arch option
@@ -33,8 +39,8 @@ run: all
 all:
        ${CC} ${CCFLAGS} hello.c -c -o hello.o 
        ${FAIL_IF_BAD_OBJ} hello.o
-       ${LD} ${LDFLAGS} -lcrt1.o hello.o -o hello -lSystem
-       file hello | grep ${FILEARCH} | ${PASS_IFF_STDIN}
+       ${LD} ${LDFLAGS} hello.o -dylib -o hello.dylib -lSystem $(LD_VERS) 
+       file hello.dylib | grep ${FILEARCH} | ${PASS_IFF_STDIN}
 
 clean:
-       rm -rf hello.o hello
+       rm -rf hello.o hello.dylib
index 14d9363900d24d879a1812eb6cfe6978dd4cc5a9..463663a37c95106b1a9ab93f16ef7f4c2e17d3d2 100644 (file)
@@ -26,4 +26,5 @@
 int main()
 {
        fprintf(stdout, "hello\n");
+       return 0;
 }
index 007feb5a973ddabd1fadfe4592026e95ee1817b0..3cc0bf2106ed950134bdf337b1ac15fbf07115b2 100644 (file)
@@ -33,8 +33,8 @@ all:
        ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
        ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib
        ${CC} ${CCFLAGS} main.c libfoo.dylib libbar.dylib -o main -Wl,-bind_at_load
-       dyldinfo -lazy_bind main | grep "no compressed lazy binding info" | ${FAIL_IF_EMPTY}
-       dyldinfo -bind main | grep _bar | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -lazy_bind main | grep "no compressed lazy binding info" | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -bind main | grep _bar | ${FAIL_IF_EMPTY}
        ${PASS_IFF_GOOD_MACHO} main
        
 clean:
index 5b1f6ddfd3cbbfdea5f6d47e5daec7143db7d863..999166af0728fc966436062195b17b329585ad4f 100644 (file)
@@ -1,5 +1,7 @@
 
     .text
+       .align 4
+
 #if __thumb__
        .thumb_func _bar
        .code 16
index 18f3a815d1fb234e49251b3cce4650a02243506e..73d01403f5fdfa7197b7deda5f378b1705baed2b 100644 (file)
@@ -1,6 +1,7 @@
 
 
     .text
+       .align 4
 
 #if __thumb__
        .thumb_func _foo
@@ -14,7 +15,7 @@ _foo:
        blx             _bar
 //     b               _bar
 
-
+       .align 4
 _space1:
 
 #if __thumb2__
index c83e25e6fe00a7c81995aff33763f3ebb09e6ce7..d5ad615f2d1ad712d82a4bd9fbf154674b75d26b 100644 (file)
@@ -35,6 +35,7 @@ run: all
 all:
        ${CC} ${CCFLAGS} mythumb.s -c 
        ${CC} ${CCFLAGS} myarm.s -c 
+       ${LD} -arch ${ARCH} mythumb.o myarm.o -r -o all.o
        ${CC} ${CCFLAGS} mythumb.o myarm.o -dynamiclib -o liball.dylib 
        ${PASS_IFF_GOOD_MACHO} liball.dylib 
 
index a3c7818f0df8d488ec3d489dcd8570b28a992079..df759e659607debc65f91f3aefe1aa5273efa6c4 100644 (file)
@@ -1,5 +1,6 @@
 
     .text
+       .align 4
 #if __arm__
        .code 32
        .align 2
index a58c28f4ef78d139206ca4b24ee031dedd0c0c41..32e3d4b48b7e324a4182da005a3effd031ed776d 100644 (file)
@@ -1,5 +1,11 @@
 
     .text
+       .align 4
+_junk:
+         nop
+         nop
+         nop
+         nop
 #if __arm__
        .syntax unified
        .thumb_func _mythumb
index 89caa9d6d6df5e01507fb94c71ac3751a4b5477e..3037663f2113bc1e9886919432cd900792f43dcb 100644 (file)
@@ -6,5 +6,6 @@ int main()
 {
        fprintf(stdout, "hello\n");
     foo();
+       return 0;
 }
 
diff --git a/unit-tests/test-cases/check-init-abs/.mod_init_func b/unit-tests/test-cases/check-init-abs/.mod_init_func
new file mode 100644 (file)
index 0000000..f0e588d
--- /dev/null
@@ -0,0 +1,2 @@
+       .long   0x12340000
+
diff --git a/unit-tests/test-cases/check-init-abs/Makefile b/unit-tests/test-cases/check-init-abs/Makefile
new file mode 100644 (file)
index 0000000..f0dbf19
--- /dev/null
@@ -0,0 +1,21 @@
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Verify machochecker catchs init routines to abolute addresses outside image
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} main.c init.s -o init.exe
+       ${FAIL_IF_SUCCESS} ${MACHOCHECK} init.exe 2>/dev/null
+       ${CC} ${CCFLAGS} main.c term.s -o term.exe
+       ${FAIL_IF_SUCCESS} ${MACHOCHECK} term.exe 2>/dev/null
+       ${PASS_IFF} /usr/bin/true
+       
+clean:
+       rm -f init.exe term.exe
diff --git a/unit-tests/test-cases/check-init-abs/init.s b/unit-tests/test-cases/check-init-abs/init.s
new file mode 100644 (file)
index 0000000..55e93c6
--- /dev/null
@@ -0,0 +1,10 @@
+
+
+       .mod_init_func
+#if __LP64__
+       .quad   0x7FFF123400000000
+#else
+       .long   0x12340000
+#endif
+
+
diff --git a/unit-tests/test-cases/check-init-abs/main.c b/unit-tests/test-cases/check-init-abs/main.c
new file mode 100644 (file)
index 0000000..b54a220
--- /dev/null
@@ -0,0 +1,2 @@
+int main() { return 0; }
+
diff --git a/unit-tests/test-cases/check-init-abs/term.s b/unit-tests/test-cases/check-init-abs/term.s
new file mode 100644 (file)
index 0000000..c69be4f
--- /dev/null
@@ -0,0 +1,10 @@
+
+
+       .mod_term_func
+#if __LP64__
+       .quad   0x7FFF123400000000
+#else
+       .long   0x12340000
+#endif
+
+
diff --git a/unit-tests/test-cases/check-init-bind/.mod_init_func b/unit-tests/test-cases/check-init-bind/.mod_init_func
new file mode 100644 (file)
index 0000000..f0e588d
--- /dev/null
@@ -0,0 +1,2 @@
+       .long   0x12340000
+
diff --git a/unit-tests/test-cases/check-init-bind/Makefile b/unit-tests/test-cases/check-init-bind/Makefile
new file mode 100644 (file)
index 0000000..95c3ce8
--- /dev/null
@@ -0,0 +1,21 @@
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Verify machochecker catchs init routines with bindings to external symbols
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} main.c init.s -Wl,-pie -o init.exe
+       ${FAIL_IF_SUCCESS} ${MACHOCHECK} init.exe 2>/dev/null
+       ${CC} ${CCFLAGS} main.c term.s -Wl,-pie -o term.exe
+       ${FAIL_IF_SUCCESS} ${MACHOCHECK} term.exe 2>/dev/null
+       ${PASS_IFF} /usr/bin/true 
+       
+clean:
+       rm -f init.exe term.exe
diff --git a/unit-tests/test-cases/check-init-bind/init.s b/unit-tests/test-cases/check-init-bind/init.s
new file mode 100644 (file)
index 0000000..f9dce33
--- /dev/null
@@ -0,0 +1,10 @@
+
+
+       .mod_init_func
+#if __LP64__
+       .quad   _malloc + 0x100000010
+#else
+       .long   _malloc + 0x1010
+#endif
+
+
diff --git a/unit-tests/test-cases/check-init-bind/main.c b/unit-tests/test-cases/check-init-bind/main.c
new file mode 100644 (file)
index 0000000..b54a220
--- /dev/null
@@ -0,0 +1,2 @@
+int main() { return 0; }
+
diff --git a/unit-tests/test-cases/check-init-bind/term.s b/unit-tests/test-cases/check-init-bind/term.s
new file mode 100644 (file)
index 0000000..bbdd265
--- /dev/null
@@ -0,0 +1,10 @@
+
+
+       .mod_term_func
+#if __LP64__
+       .quad   _malloc + 0x100000010
+#else
+       .long   _malloc + 0x1010
+#endif
+
+
diff --git a/unit-tests/test-cases/check-init-no-rebase/.mod_init_func b/unit-tests/test-cases/check-init-no-rebase/.mod_init_func
new file mode 100644 (file)
index 0000000..f0e588d
--- /dev/null
@@ -0,0 +1,2 @@
+       .long   0x12340000
+
diff --git a/unit-tests/test-cases/check-init-no-rebase/Makefile b/unit-tests/test-cases/check-init-no-rebase/Makefile
new file mode 100644 (file)
index 0000000..ff7d09a
--- /dev/null
@@ -0,0 +1,21 @@
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Verify machochecker catchs init routines in slidable images that are missing rebasing info
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} main.c init.s -Wl,-pie -o init.exe
+       ${FAIL_IF_SUCCESS} ${MACHOCHECK} init.exe 2>/dev/null
+       ${CC} ${CCFLAGS} main.c term.s -Wl,-pie -o term.exe
+       ${FAIL_IF_SUCCESS} ${MACHOCHECK} term.exe 2>/dev/null
+       ${PASS_IFF} /usr/bin/true 
+       
+clean:
+       rm -f init.exe term.exe
diff --git a/unit-tests/test-cases/check-init-no-rebase/init.s b/unit-tests/test-cases/check-init-no-rebase/init.s
new file mode 100644 (file)
index 0000000..5b282d0
--- /dev/null
@@ -0,0 +1,10 @@
+
+
+       .mod_init_func
+#if __LP64__
+       .quad   0x100000010
+#else
+       .long   0x1010
+#endif
+
+
diff --git a/unit-tests/test-cases/check-init-no-rebase/main.c b/unit-tests/test-cases/check-init-no-rebase/main.c
new file mode 100644 (file)
index 0000000..b54a220
--- /dev/null
@@ -0,0 +1,2 @@
+int main() { return 0; }
+
diff --git a/unit-tests/test-cases/check-init-no-rebase/term.s b/unit-tests/test-cases/check-init-no-rebase/term.s
new file mode 100644 (file)
index 0000000..cfe0b3a
--- /dev/null
@@ -0,0 +1,10 @@
+
+
+       .mod_term_func
+#if __LP64__
+       .quad   0x100000010
+#else
+       .long   0x1010
+#endif
+
+
index cdfe6ac170c01f55c556fbb5585488a1f8219bd3..1f9f2e4225e23829a5de52e77c6668bf5a9771f4 100644 (file)
@@ -27,13 +27,13 @@ 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}
+run: all-${FILEARCH}
 
 
 all-ppc:
        ${PASS_IFF} true
 
-all-armv6:
+all-arm:
        ${PASS_IFF} true
        
 all-i386: all-real
@@ -46,7 +46,7 @@ all-real:
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
        
        ${CC} ${CCFLAGS} main.c -o main libfoo.dylib 
-       dyldinfo -bind main | grep wfoo | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -bind main | grep wfoo | ${FAIL_IF_EMPTY}
        
        ${PASS_IFF_GOOD_MACHO} main
 
index d073c0e41b481a429edb42d6d878510cb0efebfe..15e1abdb317760eea2ab1a9cfe40d952f10d334b 100644 (file)
@@ -29,9 +29,12 @@ include ${TESTROOT}/include/common.makefile
 
 all:
        ${CC} ${CCFLAGS} foo.s -c -o foo.o
-       nm -m foo.o | grep '(alignment 2^6)'  | ${FAIL_IF_EMPTY}
+       nm -m foo.o | grep _mycomm64aligned  | grep '(alignment 2^6)'  | ${FAIL_IF_EMPTY}
+       nm -m foo.o | grep _mycomm16kaligned | grep '(alignment 2^14)'  | ${FAIL_IF_EMPTY}
        ${LD} foo.o -r -o foo2.o
-       nm -m foo2.o | grep '(alignment 2^6)' | ${PASS_IFF_STDIN}
+       nm -m foo2.o | grep _mycomm64aligned  | grep '(alignment 2^6)'  | ${FAIL_IF_EMPTY}
+       nm -m foo2.o | grep _mycomm16kaligned | grep '(alignment 2^14)'  | ${FAIL_IF_EMPTY}
+       ${PASS_IFF} true
        
 clean:
        rm -rf foo.o foo2.o
index 03c28fc08ff2181b197fc40cff02c925bd4a7194..2b11717508fec1b4810c265633b3fa171a53d7e3 100644 (file)
@@ -1,2 +1,3 @@
 
   .comm _mycomm64aligned,15,6
+  .comm _mycomm16kaligned,256,14
diff --git a/unit-tests/test-cases/compact-unwind-basic/Makefile b/unit-tests/test-cases/compact-unwind-basic/Makefile
new file mode 100644 (file)
index 0000000..10d741e
--- /dev/null
@@ -0,0 +1,47 @@
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check compiler emitted compact unwind info
+#
+
+all: all-${FILEARCH}
+
+all-i386: all-cu
+all-x86_64: all-cu
+all-arm: all-good
+
+all-cu:
+       ${CC} ${CCFLAGS} test.s -c -o test.o
+       ${OBJECTDUMP} test.o > test.o.dump
+       ${LD} -r -arch ${ARCH} test.o -o test-r.o
+       ${OBJECTDUMP} test-r.o > test-r.o.dump
+       ${PASS_IFF} diff test.o.dump test-r.o.dump
+
+all-good:
+       ${PASS_IFF} true
+
+clean:
+       rm -f test.o test-r.o test.o.dump test-r.o.dump
diff --git a/unit-tests/test-cases/compact-unwind-basic/test.s b/unit-tests/test-cases/compact-unwind-basic/test.s
new file mode 100644 (file)
index 0000000..e694feb
--- /dev/null
@@ -0,0 +1,99 @@
+#if __LP64__
+       #define pointer quad
+#else
+       #define pointer long
+#endif
+
+
+
+       .text
+       
+_basic:
+       nop
+       nop
+Lbasicend:
+
+
+_multi:
+       nop
+       nop
+Lmulti1:
+       nop
+Lmulti1a:
+       nop
+       nop
+Lmulti2:
+       nop
+Lmultiend:
+       
+       
+_person:
+       nop
+       nop
+Lpersonend:
+       
+       
+_person_lsda:
+       nop
+       nop
+Lpersonlsdaend:
+       
+       
+       .section __TEXT,__gcc_except_tab
+_lsda1:
+       .long 1
+       .long 2
+       
+       
+       .section __LD,__compact_unwind,regular,debug
+
+       .pointer        _basic
+       .set L1,Lbasicend-_basic
+       .long           L1
+       .long           0
+       .pointer        0
+       .pointer        0
+
+       .pointer        _multi
+       .set L2,Lmulti1-_multi
+       .long           L2
+       .long           1
+       .pointer        0
+       .pointer        0
+
+       .pointer        Lmulti1
+       .set L3,Lmulti2-Lmulti1
+       .long           L3
+       .long           2
+       .pointer        0
+       .pointer        0
+
+       .pointer        Lmulti2
+       .set L4,Lmultiend-Lmulti2
+       .long           L4
+       .long           3
+       .pointer        0
+       .pointer        0
+
+
+       .pointer        _person
+       .set L5,Lpersonend-_person
+       .long           L5
+       .long           0
+       .pointer        _gxx_personality_v0
+       .pointer        0
+
+
+       .pointer        _person_lsda
+       .set L6,Lpersonlsdaend-_person_lsda
+       .long           L6
+       .long           0
+       .pointer        _gxx_personality_v0
+       .pointer        _lsda1
+       
+       
+       .subsections_via_symbols
+       
+       
+       
+       
index 7586a518d83366dbf47b980a114529878cb2d030..5f3ca5df2ef678a93c717d3f9735286d795a4929 100644 (file)
@@ -38,12 +38,15 @@ test-i386:
 test-x86_64:
        ${PASS_IFF} true
 
-test-armv6:
-       gcc foo.c -arch armv4t -c -DAAA=1 -o foo4.o
-       gcc foo.c -arch armv5 -c -DBBB=1 -o foo5.o
-       gcc foo.c -arch armv6 -c -DCCC=1 -o foo6.o
-       gcc foo.c -arch xscale -c -DDDD=1 -o foox.o
-       lipo foo4.o foo5.o foo6.o foox.o -create -output foo.o
+test-armv6: test-arm
+test-armv7: test-arm
+
+test-arm:
+       clang foo.c -arch armv4t -c -DAAA=1 -o foo4.o
+       clang foo.c -arch armv5 -c -DBBB=1 -o foo5.o
+       clang foo.c -arch armv6 -c -DCCC=1 -o foo6.o
+       clang foo.c -arch armv7 -c -DDDD=1 -o foo7.o
+       lipo foo4.o foo5.o foo6.o foo7.o -create -output foo.o
        
        # check -arch armv4t pulls out V4 slice
        ${LD} -r -arch armv4t foo.o -o fooa.o
@@ -60,10 +63,10 @@ test-armv6:
        otool -hv fooc.o | grep V6 | ${FAIL_IF_EMPTY}
        nm fooc.o | grep _ccc | ${FAIL_IF_EMPTY}
 
-       # check -arch xscale pulls out xscale slice
-       ${LD} -r -arch xscale foo.o -o fooxx.o
-       otool -hv fooxx.o | grep XSCALE | ${FAIL_IF_EMPTY}
-       nm fooxx.o | grep _ddd | ${FAIL_IF_EMPTY}
+       # check -arch armv7 pulls out V7 slice
+       ${LD} -r -arch armv7 foo.o -o fooc.o
+       otool -hv fooc.o | grep V7 | ${FAIL_IF_EMPTY}
+       nm fooc.o | grep _ddd | ${FAIL_IF_EMPTY}
 
        ${PASS_IFF} true
 
index 695ffbaa9f10459e5bb1c13dcfb75b2e8952ec41..f773c1100033cd7a8cb2c940ce7c046304892e27 100644 (file)
@@ -38,23 +38,30 @@ test-i386:
 test-x86_64:
        ${PASS_IFF} true
 
-test-armv6:
-       gcc  foo.c -arch armv4t -c -o foo-v4.o
+test-armv6: test-arm
+test-armv7: test-arm
+
+test-arm:
+       clang  foo.c -arch armv4t -c -o foo-v4.o
        ${FAIL_IF_BAD_OBJ} foo-v4.o
-       gcc  foo.c -arch armv5  -c -o foo-v5.o
+       clang  foo.c -arch armv5  -c -o foo-v5.o
        ${FAIL_IF_BAD_OBJ} foo-v5.o
-       gcc  foo.c -arch armv6  -c -o foo-v6.o
+       clang  foo.c -arch armv6  -c -o foo-v6.o
        ${FAIL_IF_BAD_OBJ} foo-v6.o
-       gcc  foo.c -arch xscale  -c -o foo-xscale.o
+       clang  foo.c -arch armv7  -c -o foo-v7.o
+       ${FAIL_IF_BAD_OBJ} foo-v7.o
+       clang  foo.c -arch xscale  -c -o foo-xscale.o
        ${FAIL_IF_BAD_OBJ} foo-xscale.o
-       gcc  main.c -arch armv4t  -c -o main-v4.o
+       clang  main.c -arch armv4t  -c -o main-v4.o
        ${FAIL_IF_BAD_OBJ} main-v4.o
-       gcc  main.c -arch armv5  -c -o main-v5.o
+       clang  main.c -arch armv5  -c -o main-v5.o
        ${FAIL_IF_BAD_OBJ} main-v5.o
-       gcc  main.c -arch armv6  -c -o main-v6.o
+       clang  main.c -arch armv6  -c -o main-v6.o
        ${FAIL_IF_BAD_OBJ} main-v6.o
-       gcc  main.c -arch xscale  -c -o main-xscale.o
+       clang  main.c -arch xscale  -c -o main-xscale.o
        ${FAIL_IF_BAD_OBJ} main-xscale.o
+       clang  main.c -arch armv7  -c -o main-v7.o
+       ${FAIL_IF_BAD_OBJ} main-v7.o
 
        # check V4+V4 -> V4
        ${LD} -r main-v4.o foo-v4.o -o all.o
@@ -62,19 +69,19 @@ test-armv6:
        otool -hv all.o | grep V4T | ${FAIL_IF_EMPTY}
 
        # check V4+V5 -> V5
-       ${LD} -r main-v4.o foo-v5.o -o all.o
-       ${FAIL_IF_BAD_OBJ} all.o
-       otool -hv all.o | grep V5 | ${FAIL_IF_EMPTY}
+       #${LD} -r main-v4.o foo-v5.o -o all.o
+       #${FAIL_IF_BAD_OBJ} all.o
+       #otool -hv all.o | grep V5 | ${FAIL_IF_EMPTY}
 
        # check V4+V6 -> V6
-       ${LD} -r main-v4.o foo-v6.o -o all.o
-       ${FAIL_IF_BAD_OBJ} all.o
-       otool -hv all.o | grep V6 | ${FAIL_IF_EMPTY}
+       #${LD} -r main-v4.o foo-v6.o -o all.o
+       #${FAIL_IF_BAD_OBJ} all.o
+       #otool -hv all.o | grep V6 | ${FAIL_IF_EMPTY}
 
        # check V4+xscale -> xscale
-       ${LD} -r main-v4.o foo-xscale.o -o all.o
-       ${FAIL_IF_BAD_OBJ} all.o
-       otool -hv all.o | grep XSCALE | ${FAIL_IF_EMPTY}
+       #${LD} -r main-v4.o foo-xscale.o -o all.o
+       #${FAIL_IF_BAD_OBJ} all.o
+       #otool -hv all.o | grep XSCALE | ${FAIL_IF_EMPTY}
 
        # check V5+V5 -> V5
        ${LD} -r main-v5.o foo-v5.o -o all.o
@@ -82,24 +89,29 @@ test-armv6:
        otool -hv all.o | grep V5 | ${FAIL_IF_EMPTY}
 
        # check V5+V6 -> V6
-       ${LD} -r main-v5.o foo-v6.o -o all.o
-       ${FAIL_IF_BAD_OBJ} all.o
-       otool -hv all.o | grep V6 | ${FAIL_IF_EMPTY}
+       #${LD} -r main-v5.o foo-v6.o -o all.o
+       #${FAIL_IF_BAD_OBJ} all.o
+       #otool -hv all.o | grep V6 | ${FAIL_IF_EMPTY}
 
        # check V5+xscale -> xscale
-       ${LD} -r main-v5.o foo-xscale.o -o all.o
-       ${FAIL_IF_BAD_OBJ} all.o
-       otool -hv all.o | grep XSCALE | ${FAIL_IF_EMPTY}
+       #${LD} -r main-v5.o foo-xscale.o -o all.o
+       #${FAIL_IF_BAD_OBJ} all.o
+       #otool -hv all.o | grep XSCALE | ${FAIL_IF_EMPTY}
 
        # check V6+V6 -> V6
        ${LD} -r main-v6.o foo-v6.o -o all.o
        ${FAIL_IF_BAD_OBJ} all.o
        otool -hv all.o | grep V6 | ${FAIL_IF_EMPTY}
 
-       # check xscale+xscale -> xscale
-       ${LD} -r main-xscale.o foo-xscale.o -o all.o
+       # check V7+V7 -> V7
+       ${LD} -r main-v7.o foo-v7.o -o all.o
        ${FAIL_IF_BAD_OBJ} all.o
-       otool -hv all.o | grep XSCALE | ${FAIL_IF_EMPTY}
+       otool -hv all.o | grep V7 | ${FAIL_IF_EMPTY}
+
+       # check xscale+xscale -> xscale
+       #${LD} -r main-xscale.o foo-xscale.o -o all.o
+       #${FAIL_IF_BAD_OBJ} all.o
+       #otool -hv all.o | grep XSCALE | ${FAIL_IF_EMPTY}
 
        ${PASS_IFF} true
 
index 1c6ee7d4cc20224432521d60853a5cf20b767f6b..76db33a2a23846fab1c434b77b1b25c53523f50a 100644 (file)
@@ -30,9 +30,12 @@ include ${TESTROOT}/include/common.makefile
 # makes them weak/hidden.  Test to make sure that weak/hidden does not leak out.
 #
 
+STRING_LABEL_COUNT = 0
+
 ifeq (${ARCH},x86_64)
        STRING_LABEL_COUNT = 3
-else
+endif
+ifeq (${ARCH},i386)
        STRING_LABEL_COUNT = 1
 endif
 
@@ -49,7 +52,7 @@ all:
        nm -nm foobar.o | grep __cstring | grep "weak private external" | ${FAIL_IF_STDIN}
        nm -m foobar.o | grep __cstring | wc -l | grep ${STRING_LABEL_COUNT}  | ${FAIL_IF_EMPTY}
        ${CC} ${CCFLAGS} foo.o bar.o -dynamiclib -o libfoobar.dylib
-       nm -m libfoobar.dylib | grep __cstring | wc -l | grep 1  | ${FAIL_IF_EMPTY}
+       nm -m libfoobar.dylib | grep __cstring | wc -l |  egrep '[01]'  | ${FAIL_IF_EMPTY}
        ${PASS_IFF} /usr/bin/true
 
 clean:
index 1dfb23f8f2d768a88270596cdf38735bcded404e..e5b13c243c3590a602c21865324351aee04155b4 100644 (file)
@@ -5,11 +5,16 @@ include ${TESTROOT}/include/common.makefile
 #
 # Check that a large page zero works
 #
+ifeq (,${findstring "macosx","$(VERSION_NEW_LINKEDIT)"})
+       SEG_ADDR = 0x20000000
+else
+       SEG_ADDR = 0xb8000000
+endif
 
 run: all
 
 all:
-       ${CC} ${CCFLAGS} main.c zero.s -o main -pagezero_size 0 -segaddr __TEXT 0xb8000000 -segaddr __MYZEROPAGE 0
+       ${CC} ${CCFLAGS} main.c zero.s -o main -pagezero_size 0 -segaddr __TEXT $(SEG_ADDR) -segaddr __MYZEROPAGE 0
        ${PASS_IFF_GOOD_MACHO} main
 
 clean:
index 86bde8349de94eeecd487833993b226444edac3d..94e1a5047798e61f4558ef37495639d6ffb3593d 100644 (file)
@@ -2,9 +2,11 @@
        .section __MYZEROPAGE,_data
 _min:  .long 0
        
-       
+#if __arm__
+       .zerofill __MYZEROPAGE,__zerofill,_padding,536870910
+#else  
        .zerofill __MYZEROPAGE,__zerofill,_padding,2147483644
-       
+#endif 
        
 
 
index 1542d788c1cad06150fd6ae29ef10e71dfc59c3d..54812f3a93ec8d39a3c99a278bab8f23ee0bff8a 100644 (file)
@@ -36,7 +36,7 @@ all:
        ${CC} ${CCFLAGS} foo.c -c -o foo.o
        ${FAIL_IF_BAD_OBJ} foo.o
        libtool -static foo.o -o libfoo.a
-       ${CC} ${CCFLAGS}  main.c -mdynamic-no-pic -Os libfoo.a -dead_strip -o main
+       ${CC} ${CCFLAGS}  main.c -Os libfoo.a -dead_strip -o main
        ${PASS_IFF_GOOD_MACHO} main
 
 clean:
index 1317c489f08f4b1343369a4e9abe854142ef72c0..75b7988db1275a948c95d5212319ff3db481b8aa 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2009 Apple Inc. All rights reserved.
+# Copyright (c) 2009-2011 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -25,6 +25,7 @@ include ${TESTROOT}/include/common.makefile
 
 #
 # <rdar://problem/7043256> ld64 can not find a -e entry point from an archive
+# <rdar://problem/8866673> "start" and other special symbols should start out initially undefined
 #
 
 run: all
@@ -32,6 +33,7 @@ run: all
 all:
        ${CC} ${CCFLAGS} foo.c -c -o foo.o
        libtool -static foo.o -o libfoo.a
+       ${FAIL_IF_ERROR} ${CC} ${CCFLAGS}  bar.c -Os libfoo.a -o foo -Wl,-e,_foo -nostartfiles
        ${FAIL_IF_ERROR} ${CC} ${CCFLAGS}  bar.c -Os libfoo.a -dead_strip -o foo -Wl,-e,_foo 
        ${PASS_IFF_GOOD_MACHO} foo
 
index 6ed52b73112131fbf0ff628faf4977fd864081d7..018bd4c436c653616723304bca151e4b9a5230d2 100644 (file)
@@ -35,9 +35,9 @@ run: all
 
 all:
        ${CXX} ${CXXFLAGS} main.cxx -c
-       ${FAIL_IF_SUCCESS} ${LD} -arch ${ARCH} -dylib main.o -lSystem -o main 2>main1.fail
+       ${FAIL_IF_SUCCESS} ${LD} -arch ${ARCH} -dylib main.o ${LD_SYSROOT} ${LD_NEW_LINKEDIT} -lSystem -o main 2>main1.fail
        grep __ZN3Foo4doitEv main1.fail | ${FAIL_IF_EMPTY}
-       ${FAIL_IF_SUCCESS} ${LD} -arch ${ARCH} -dylib main.o -lSystem -demangle -o main 2>main2.fail
+       ${FAIL_IF_SUCCESS} ${LD} -arch ${ARCH} -dylib main.o ${LD_SYSROOT} ${LD_NEW_LINKEDIT} -lSystem -demangle -o main 2>main2.fail
        grep 'Foo::doit()' main2.fail | ${PASS_IFF_STDIN}
        
 
index e86122652c80ac50467546822983b167eaabc6c1..7f4cf644607465e8f3f457fabe4d30e939004c62 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2010 Apple Inc. All rights reserved.
+# Copyright (c) 2010-2011 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -35,6 +35,10 @@ all:
        rm -rf trace_ars
        export LD_TRACE_ARCHIVES=1 && export LD_TRACE_FILE=trace_ars && ${CC} ${CCFLAGS} main.c libfoo.a -o main
        grep 'libfoo.a' trace_ars | ${FAIL_IF_EMPTY}
+       export LD_TRACE_ARCHIVES=1 && export LD_TRACE_FILE=trace_ars2 && ${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoo.a -o main
+       grep 'libfoo.a' trace_ars2 | ${FAIL_IF_EMPTY}
+       export LD_TRACE_ARCHIVES=1 && export LD_TRACE_FILE=trace_ars3 && ${CC} ${CCFLAGS} main.c libfoo.a -o main -all_load
+       grep 'libfoo.a' trace_ars3 | ${FAIL_IF_EMPTY}
        ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
        rm -rf trace_dylibs
        export LD_TRACE_DYLIBS=1 && export LD_TRACE_FILE=trace_dylibs && ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
@@ -43,4 +47,4 @@ all:
        
 
 clean:
-       rm -rf foo.o libfoo.a libfoo.dylib main trace_ars trace_dylibs
+       rm -rf foo.o libfoo.a libfoo.dylib main trace_ars trace_ars2 trace_ars3 trace_dylibs
index b4fa7ab5bee2d1c514a22b937d77df09c760113f..ea9dc56b7b44de748eddd48b209b9885ca9a9d63 100644 (file)
@@ -33,9 +33,9 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all:
-       ${CXX} ${CCXXFLAGS} -gdwarf-2 hello.cxx -c -o hello.o -mdynamic-no-pic
-       ${CXX} ${CCXXFLAGS} -gdwarf-2 other.cxx -c -o other.o -mdynamic-no-pic
-       ${CXX} ${CCXXFLAGS} -gdwarf-2 hello.o other.o -o hello
+       ${CXX} ${CCXXFLAGS} -gdwarf-2 hello.cxx -c -o hello.o 
+       ${CXX} ${CCXXFLAGS} -gdwarf-2 other.cxx -c -o other.o 
+       ${CXX} ${CCXXFLAGS} -gdwarf-2 hello.o other.o -o hello -Wl,-order_file,hello.order
        ${FAIL_IF_BAD_MACHO} hello
        nm -ap hello | ./stabs-filter.pl > hello.stabs
        ${PASS_IFF} diff hello.stabs expected-stabs
index 95eb33d8c859c601b7e8de180fd1b3ea981123f1..f7eb45a5cb7767b8e4d9a0ee82378d30c0f435e1 100644 (file)
@@ -7,7 +7,7 @@
 0000 ENSYM 
 0000 BNSYM 
 0000   FUN __Z3fooi
-0000   SOL CWD//header.h
+0000   SOL CWD/header.h
 0000   FUN 
 0000 ENSYM 
 0000    SO 
diff --git a/unit-tests/test-cases/dwarf-debug-notes/hello.order b/unit-tests/test-cases/dwarf-debug-notes/hello.order
new file mode 100644 (file)
index 0000000..2860890
--- /dev/null
@@ -0,0 +1,16 @@
+
+# order __data section so even if different compiler lays out data 
+# differently, linker lays out the same, so stabs are in same order
+.my_non_standard_name_static
+.my_non_standard_name
+__ZZ3bariE8bar_init
+_init
+_uninit
+__ZZ3bariE10bar_uninit
+__ZL7suninit
+__ZL5sinit
+
+
+
+
+
index b1b0e7723a13b3300986cd91538976c3f4934ba1..a6b403b5c146df2f600d09acfdd64290e242d3c2 100644 (file)
@@ -3,10 +3,10 @@
 
 int uninit;
 int init = 1;
-static int custom _asm(".my_non_standard_name") = 1;
+static int custom __asm__(".my_non_standard_name") = 1;
 static int suninit;
 static int sinit=0;
-static int scustominit _asm(".my_non_standard_name_static") = 1;
+static int scustominit __asm__(".my_non_standard_name_static") = 1;
 
 int bar(int x)
 {
@@ -19,9 +19,9 @@ int bar(int x)
                bar_init + bar_uninit + foo(x);
 }
 
-extern void disappear() _asm("lbegone");
+extern void disappear() __asm__("lbegone");
 void disappear() {}
 
-extern void foo() _asm(".my_non_standard_function_name");
+extern void foo() __asm__(".my_non_standard_function_name");
 void foo() { disappear(); }
 
index e2f0fe9c1f9d3587a7bf40e8a7cabe84487378e8..4750b51f364f9ed734a7bb638cd7fee048c54094 100644 (file)
@@ -26,4 +26,5 @@
 int main()
 {
        fprintf(stdout, "hello\n");
+       return 0;
 }
\ No newline at end of file
index 3812933337618f398dabbb23e5e55bdfb71fbaf4..866d1786a96f0a580962a7c7b05f25aa7405f1a4 100644 (file)
@@ -10,7 +10,7 @@ IMAGE_INFO = "__image_info"
 ifeq ($(ARCH),x86_64)
        IMAGE_INFO = "__objc_imageinfo"
 endif
-ifeq ($(ARCH),armv6)
+ifeq ($(FILEARCH),arm)
        IMAGE_INFO = "__objc_imageinfo"
 endif
 
index ddca8193c4b8962f70f40fc9bc8763df0f2badba..68509d71bd2cd9de7d00915dec2caf6c35dc6aa4 100644 (file)
@@ -26,4 +26,5 @@
 int main()
 {
        fprintf(stdout, "hello\n");
+       return 0;
 }
\ No newline at end of file
index 057ac03730703998988b937b1045e5ae8a020880..86248c2fba6d899b3e072f1b30c312f515f1a1b9 100644 (file)
@@ -30,9 +30,15 @@ SHELL = bash # use bash shell so we can redirect just stderr
 # <rdar://problem/5277857> OpenGL.framework and X11 both have a libGL.dylib which can cause ld to segfault if both are found
 #
 
-run: all
+all: all-${ARCH}
 
-all: 
+all-i386: all-mac
+all-x86_64: all-mac
+all-armv6: all-good
+all-armv7: all-good
+
+
+all-mac: 
        mkdir -p other
        ${CC} foo.c -dynamiclib -o other/libfoo.dylib -mmacosx-version-min=10.4
        ${CC} bar.c -dynamiclib -o libbar.dylib other/libfoo.dylib -sub_library libfoo -mmacosx-version-min=10.4
@@ -40,7 +46,8 @@ all:
        ${CC} main.c libfoo.dylib -o main -L. 2>errmsg || true
        grep "cycle" errmsg | ${PASS_IFF_STDIN}
 
-
+all-good:
+       ${PASS_IFF} true
 
 
 clean:
index 1f392c5fd795bcd186fdd344c32826bbcfef7e06..99f2fa6edb927073fabd65ded0d2049ae0092409 100644 (file)
@@ -59,7 +59,7 @@ all:
        libtool -static -o LibTest1.lib LibTest1.obj
        ${CC} -arch $(ARCH)  -o MtocTest1.obj $(LOCAL_CC_FLAGS) -c MtocTest.c 
        libtool -static -o MtocTest1.lib MtocTest1.obj  
-       ld -arch $(ARCH)  -o MtocTest1.macho  -u __ModuleEntryPoint -e __ModuleEntryPoint $(LD_ARG) -preload -segalign 0x20 -pie -seg1addr 0x240 -map MtocTest1.map LibTest1.lib MtocTest1.lib
+       ${LD} -arch $(ARCH)  -o MtocTest1.macho  -u __ModuleEntryPoint -e __ModuleEntryPoint $(LD_ARG) -preload -segalign 0x20 -pie -seg1addr 0x240 -map MtocTest1.map LibTest1.lib MtocTest1.lib
        /usr/local/efi/bin/mtoc -subsystem application -align 0x20 -d MtocTest1.macho MtocTest1.macho MtocTest1.pecoff
        otool -rR MtocTest1.macho > otool-reloc.log
        otool -l MtocTest1.macho > otool-load.log 
index 5e3ebd505717b1f4cb2a7104c61cd19278aac268..1d076ba7b066045a667e6bc25d088b5432144474 100644 (file)
@@ -12,7 +12,7 @@ int gWhyAreUninitializedGlobalsBad;
 \r
 void _ModuleEntryPoint(void)\r
 { \r
-  __asm__ __volatile__ ("int $3");  \r
+  //__asm__ __volatile__ ("int $3");  \r
 \r
   LibInit ();\r
   gWhyAreUninitializedGlobalsBad =1;\r
index 15819f06febc9264bac2b6f5c0131d1f95c37ba7..404cc41fd736a4123cd957fd3858e5d0a7b2f7ed 100644 (file)
@@ -7,9 +7,17 @@ include ${TESTROOT}/include/common.makefile
 # the linker can still process unwind info from .o files
 # correctly
 
-run: all
+ifeq (${FILEARCH},arm)
+       FILE_TYPE = KEXTBUNDLE
+endif
 
-all:
+
+all: all-${FILEARCH}
+all-i386: all-zce
+all-x86_64: all-zce
+all-arm: all-good
+
+all-zce:
        ${CXX} ${CCXXFLAGS} main.cxx -g -c -o main1.o -Os
        #strip main1.o -u -s keep.exp -o main2.o
        ${LD} main1.o -r -x -exported_symbols_list keep.exp -o main2.o
@@ -19,5 +27,8 @@ all:
        ${UNWINDDUMP} -arch ${ARCH} -no_symbols main2 > main2.unwind
        ${PASS_IFF} diff main1.unwind main2.unwind
 
+all-good:
+       ${PASS_IFF} true
+
 clean:
        rm -f main1* main2*
index 14d9363900d24d879a1812eb6cfe6978dd4cc5a9..463663a37c95106b1a9ab93f16ef7f4c2e17d3d2 100644 (file)
@@ -26,4 +26,5 @@
 int main()
 {
        fprintf(stdout, "hello\n");
+       return 0;
 }
index 60148298b2a33a5aa0a305d1cb415a09affbf872..affbf90695fc7c095e3ac4a9d3d2383936432cda 100644 (file)
@@ -30,4 +30,5 @@ int main()
 {
        foo();
        fprintf(stdout, "hello\n");
+       return 0;
 }
index 60148298b2a33a5aa0a305d1cb415a09affbf872..affbf90695fc7c095e3ac4a9d3d2383936432cda 100644 (file)
@@ -30,4 +30,5 @@ int main()
 {
        foo();
        fprintf(stdout, "hello\n");
+       return 0;
 }
index 0b43cd5e8584eda66b8278be6539c0cc53a51c90..531bb7a3fa138451e520ec414b0b64daa9bc286c 100644 (file)
@@ -22,8 +22,15 @@ all:
        # as dylib with aliases
        ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain3.dylib -Wl,-function_starts -Wl,-alias,_mid,midalias
        ${DYLDINFO} -function_starts libmain3.dylib | grep _bar | ${FAIL_IF_EMPTY}
+       # as static main executable
+       ${CC} ${CCFLAGS} main.c -static -e _main -o main_static -nostdlib -Wl,-new_linker -Wl,-alias,_myexit,_exit
+       ${DYLDINFO} -function_starts main_static | grep _bar | ${FAIL_IF_STDIN}
+       ${CC} ${CCFLAGS} main.c -static -e _main -o main_static -nostdlib -Wl,-new_linker -Wl,-alias,_myexit,_exit -Wl,-function_starts
+       ${DYLDINFO} -function_starts main_static | grep _bar | ${FAIL_IF_EMPTY}
+
+
        ${PASS_IFF_GOOD_MACHO} main
        
 
 clean:
-       rm  main libmain.dylib libmain2.dylib libmain3.dylib
+       rm  main libmain.dylib libmain2.dylib libmain3.dylib main_static
index 4ff171745fc6d3449747a2a53ab42c5f3cbb5c00..be69aaafe2c5ae21d55d99d5f64e8842951d0a0b 100644 (file)
@@ -8,3 +8,7 @@ static void bar() { foo(); }
 int main() { bar(); return 0; }
 
 
+#if __STATIC__
+void myexit() {}
+#endif
+
index 6fae5ee800a8364b7fb1714cecbed8a8bdc9645a..e3b687b9f849f6fdc7cec419c5784e30dbc123ad 100644 (file)
@@ -27,9 +27,9 @@ include ${TESTROOT}/include/common.makefile
 # Check that ld can remove non-lazy pointers for x86_64
 #
 
-all: all-${ARCH}
+all: all-${FILEARCH}
 
-all-armv6: all-true
+all-arm: all-true
 
 all-ppc: all-true
 
index 14d9363900d24d879a1812eb6cfe6978dd4cc5a9..463663a37c95106b1a9ab93f16ef7f4c2e17d3d2 100644 (file)
@@ -26,4 +26,5 @@
 int main()
 {
        fprintf(stdout, "hello\n");
+       return 0;
 }
index e2f0fe9c1f9d3587a7bf40e8a7cabe84487378e8..4750b51f364f9ed734a7bb638cd7fee048c54094 100644 (file)
@@ -26,4 +26,5 @@
 int main()
 {
        fprintf(stdout, "hello\n");
+       return 0;
 }
\ No newline at end of file
index c982885df7e2bc8619dbbd5852776201be783878..b2cfe02b907abd1b8a4531730f0ea060ce650195 100644 (file)
@@ -35,7 +35,7 @@ run: all
 
 all:
        ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib -install_name /usr/lib/libbar.dylib
-       ${CC} ${CCFLAGS} foo.c  -dynamiclib -o libfoo.dylib -reexport_library libbar.dylib -sub_library libbar
+       ${CC} ${CCFLAGS} foo.c  -dynamiclib -o libfoo.dylib -Wl,-reexport_library,libbar.dylib -sub_library libbar
        # verify that main gets bar from libbar
        ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -L.
        nm -m main | grep _bar | grep libbar | ${FAIL_IF_EMPTY}
index 4844cd77d45b4f8394b1878b339c957f6f195290..e33b66c14717359d63b8f054dad49f947bb1d0d3 100644 (file)
@@ -5,20 +5,22 @@ include ${TESTROOT}/include/common.makefile
 #
 # Sanity check that ld can link a kext
 #
-
+FILE_TYPE = OBJECT
 ifeq (${ARCH},x86_64)
        FILE_TYPE = KEXTBUNDLE
-else
-       FILE_TYPE = OBJECT
+endif
+ifeq (${FILEARCH},arm)
+       FILE_TYPE = KEXTBUNDLE
 endif
 
+#CC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang
 
 run: all
 
 all:
-       ${CC} ${CCFLAGS} -static -fno-common -mkernel -c mykext.c -o mykext.o
-       ${CC} ${CCFLAGS} -static -fno-common -mkernel -c mykextinfo.c -o mykextinfo.o
-       unset LD_NO_CLASSIC_LINKER_STATIC && ${CC} ${CCFLAGS} -Wl,-kext mykext.o mykextinfo.o -nostdlib -lkmodc++ -lkmod -lcc_kext -o mykext -Wl,-w
+       ${CC} ${CCFLAGS} -static  -mkernel -c mykext.c -o mykext.o
+       ${CC} ${CCFLAGS} -static  -mkernel -c mykextinfo.c -o mykextinfo.o
+       ${CC} ${CCFLAGS} -Wl,-kext mykext.o mykextinfo.o -nostdlib -lkmodc++ -lkmod -lcc_kext -o mykext -Wl,-w -Wl,-new_linker
        otool -hv mykext | grep ${FILE_TYPE} | ${FAIL_IF_EMPTY}
        nm -nm mykext | grep '(undefined) external _extern_global' | ${FAIL_IF_EMPTY}
        nm -nm mykext | grep '(__DATA,__data) external _my_global' | ${FAIL_IF_EMPTY}
diff --git a/unit-tests/test-cases/kext-undefined-export/Makefile b/unit-tests/test-cases/kext-undefined-export/Makefile
new file mode 100644 (file)
index 0000000..b6acfd4
--- /dev/null
@@ -0,0 +1,35 @@
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Sanity check that ld can link a kext
+#
+
+EXPORT_LIST = mykext.exp
+FILE_TYPE = OBJECT
+ifeq (${ARCH},x86_64)
+       FILE_TYPE = KEXTBUNDLE
+endif
+ifeq (${FILEARCH},arm)
+       FILE_TYPE = KEXTBUNDLE
+endif
+ifeq (${ARCH},i386)
+       EXPORT_LIST = mykext-i386.exp
+endif
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -static -mkernel -c mykext.c -o mykext.o
+       ${CC} ${CCFLAGS} -static -mkernel -c mykextinfo.c -o mykextinfo.o
+       ${CC} ${CCFLAGS} -Wl,-kext mykext.o mykextinfo.o -nostdlib -lkmodc++ -lkmod -lcc_kext -exported_symbols_list $(EXPORT_LIST) -o mykext -Wl,-w -Wl,-new_linker
+       otool -hv mykext | grep ${FILE_TYPE} | ${FAIL_IF_EMPTY}
+       nm -nm mykext | grep '(undefined) external _extern_global' | ${FAIL_IF_EMPTY}
+       nm -nm mykext | grep '(undefined) external _foo' | ${FAIL_IF_STDIN}
+       nm -nm mykext | grep '(undefined) external _my_used_external_global' | ${FAIL_IF_EMPTY}
+       otool -rv mykext | grep '_extern_global' | ${FAIL_IF_EMPTY}
+       ${PASS_IFF} true
+
+clean:
+       rm -f mykext.o mykextinfo.o mykext
diff --git a/unit-tests/test-cases/kext-undefined-export/mykext-i386.exp b/unit-tests/test-cases/kext-undefined-export/mykext-i386.exp
new file mode 100644 (file)
index 0000000..2449aba
--- /dev/null
@@ -0,0 +1 @@
+_kmod_info
diff --git a/unit-tests/test-cases/kext-undefined-export/mykext.c b/unit-tests/test-cases/kext-undefined-export/mykext.c
new file mode 100644 (file)
index 0000000..d01996f
--- /dev/null
@@ -0,0 +1,27 @@
+#include <mach/mach_types.h>
+
+extern void extern_func();
+
+int my_global = 3;
+extern int extern_global;
+extern int extern_unused_global;
+extern int my_used_external_global;
+
+kern_return_t mykext_start (kmod_info_t * ki, void * d) {
+       ++my_global;
+       ++extern_global;
+       ++my_used_external_global;
+       extern_func();
+    return KERN_SUCCESS;
+}
+
+
+kern_return_t mykext_stop (kmod_info_t * ki, void * d) {
+       --my_global;
+       --extern_global;
+    return KERN_SUCCESS;
+}
+
+void my_dead_code() {
+       ++extern_unused_global;
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/kext-undefined-export/mykext.exp b/unit-tests/test-cases/kext-undefined-export/mykext.exp
new file mode 100644 (file)
index 0000000..eccfe2a
--- /dev/null
@@ -0,0 +1,3 @@
+_kmod_info
+_foo
+_my_used_external_global
diff --git a/unit-tests/test-cases/kext-undefined-export/mykextinfo.c b/unit-tests/test-cases/kext-undefined-export/mykextinfo.c
new file mode 100644 (file)
index 0000000..fe31e7b
--- /dev/null
@@ -0,0 +1,12 @@
+#include <mach/mach_types.h>
+extern kern_return_t _start(kmod_info_t *ki, void *data);
+extern kern_return_t _stop(kmod_info_t *ki, void *data);
+__private_extern__ kern_return_t mykext_start(kmod_info_t *ki, void *data);
+__private_extern__ kern_return_t mykext_stop(kmod_info_t *ki, void *data);
+KMOD_EXPLICIT_DECL(com.yourcompany.kext.mykext, "1.0.0d1", _start, _stop)
+__private_extern__ kmod_start_func_t *_realmain = mykext_start;
+__private_extern__ kmod_stop_func_t *_antimain = mykext_stop;
+__private_extern__ int _kext_apple_cc = __APPLE_CC__ ;
+
diff --git a/unit-tests/test-cases/label-on-end-of-section-order/Makefile b/unit-tests/test-cases/label-on-end-of-section-order/Makefile
new file mode 100755 (executable)
index 0000000..7ec72bc
--- /dev/null
@@ -0,0 +1,37 @@
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/9452006> assert when wacky section order and label at end of section
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.s -c -o foo.o
+       ${PASS_IFF} ${LD} -r foo.o -arch ${ARCH} -o foo-r.o 
+
+clean:
+       rm -f foo.o foo-r.o
diff --git a/unit-tests/test-cases/label-on-end-of-section-order/foo.s b/unit-tests/test-cases/label-on-end-of-section-order/foo.s
new file mode 100755 (executable)
index 0000000..e0fd49c
--- /dev/null
@@ -0,0 +1,24 @@
+       .lcomm  _mybss ,4, 2
+
+       .text
+       .align 4
+       .globl  _main
+_main:
+#if __x86_64__
+       movl $0, _mybss(%rip)
+#elif __i386__
+       movl $0, _mybss
+#elif __arm__
+       .long   _mybss
+#endif
+
+       .section __DATA, _stuff
+       .align 4
+_start_stuff:
+       .long 0x0
+       .long 0x0
+_end_stuff:
+
+
+       .subsections_via_symbols
+       
\ No newline at end of file
index 513dcccf9845c243c25a105eb6d47f67bc90a9ad..8f33f3632280d4d7941e829a723c316970cfdf4d 100644 (file)
@@ -27,8 +27,6 @@ include ${TESTROOT}/include/common.makefile
 SHELL = bash # use bash shell so we can redirect just stderr
 
 
-LLVMGCC = /Developer/usr/bin/llvm-gcc-4.2 -arch ${ARCH}
-LLVMGXX = /Developer/usr/bin/llvm-g++-4.2 -arch ${ARCH}
 LLVMAR  = /usr/local/bin/llvm-ar
 
 #
@@ -52,10 +50,10 @@ zero:
        # MachO : main.c : Ufoo2, Ufoo3
        #
        #echo "Zero..."
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a.c -c -o a.o 
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm b.c -c -o b.o
-       ${LLVMGCC} ${CCFLAGS} main.c -c -o main.o
-       ${LLVMGCC} ${CCFLAGS} a.o b.o main.o -o main.exe
+       ${CC} ${CCFLAGS} -flto a.c -c -o a.o 
+       ${CC} ${CCFLAGS} -flto b.c -c -o b.o
+       ${CC} ${CCFLAGS} main.c -c -o main.o
+       ${CC} ${CCFLAGS} a.o b.o main.o -o main.exe
        ${PASS_IFF_GOOD_MACHO} main.exe
        
 one:
@@ -65,10 +63,10 @@ one:
        # MachO : main1.c : Dfoo4, Ufoo2, Ufoo3
        #
        #echo "One..."
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a1.c -c -o a1.o
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm b1.c -c -o b1.o
-       ${LLVMGCC} ${CCFLAGS} main1.c -c -o main1.o
-       ${LLVMGCC} ${CCFLAGS} a1.o b1.o main1.o -o main1.exe
+       ${CC} ${CCFLAGS} -flto a1.c -c -o a1.o
+       ${CC} ${CCFLAGS} -flto b1.c -c -o b1.o
+       ${CC} ${CCFLAGS} main1.c -c -o main1.o
+       ${CC} ${CCFLAGS} a1.o b1.o main1.o -o main1.exe
        ${PASS_IFF_GOOD_MACHO} main1.exe
 
 two:
@@ -78,10 +76,10 @@ two:
        # MachO : main2.c : Ufoo2, Ufoo3
        #
        #echo "Two..."
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a2.c -c -o a2.o
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm b2.c -c -o b2.o
-       ${LLVMGCC} ${CCFLAGS} main2.c -c -o main2.o
-       ${LLVMGCC} ${CCFLAGS} a2.o b2.o main2.o -o main2.exe
+       ${CC} ${CCFLAGS} -flto a2.c -c -o a2.o
+       ${CC} ${CCFLAGS} -flto b2.c -c -o b2.o
+       ${CC} ${CCFLAGS} main2.c -c -o main2.o
+       ${CC} ${CCFLAGS} a2.o b2.o main2.o -o main2.exe
        ${PASS_IFF_GOOD_MACHO} main2.exe
 
 three:
@@ -91,10 +89,10 @@ three:
        # MachO : main3.c : Ufoo1, Ufoo2, Ubar
        #
        #echo "Three..."
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a3.c -c -o a3.o
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm b3.c -c -o b3.o
-       ${LLVMGCC} ${CCFLAGS} main3.c -c -o main3.o
-       ${LLVMGCC} ${CCFLAGS} a3.o b3.o main3.o -o main3.exe
+       ${CC} ${CCFLAGS} -flto a3.c -c -o a3.o
+       ${CC} ${CCFLAGS} -flto b3.c -c -o b3.o
+       ${CC} ${CCFLAGS} main3.c -c -o main3.o
+       ${CC} ${CCFLAGS} a3.o b3.o main3.o -o main3.exe
        ${PASS_IFF_GOOD_MACHO} main3.exe
 
 four:
@@ -104,10 +102,10 @@ four:
        # MachO : main4.c : Dfoo4, Ufoo2, Ufoo3
        #
        #echo "Four..."
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a4.c -c -o a4.o
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm b4.c -c -o b4.o
-       ${LLVMGCC} ${CCFLAGS} main4.c -c -o main4.o
-       ${LLVMGCC} ${CCFLAGS} a4.o b4.o main4.o -o main4.exe
+       ${CC} ${CCFLAGS} -flto a4.c -c -o a4.o
+       ${CC} ${CCFLAGS} -flto b4.c -c -o b4.o
+       ${CC} ${CCFLAGS} main4.c -c -o main4.o
+       ${CC} ${CCFLAGS} a4.o b4.o main4.o -o main4.exe
        ${PASS_IFF_GOOD_MACHO} main4.exe
 
 five:
@@ -117,10 +115,10 @@ five:
        # MachO : main5.c : Dfoo3, Ufoo1
        #
        #echo "verify that if call to mach-o is optimized away, mach-o func is dead stripped"
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a5.c -c -o a5.o
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm b5.c -c -o b5.o
-       ${LLVMGCC} ${CCFLAGS} main5.c -c -o main5.o
-       ${LLVMGCC} ${CCFLAGS} a5.o b5.o main5.o -o main5.exe  -Wl,-dead_strip
+       ${CC} ${CCFLAGS} -flto a5.c -c -o a5.o
+       ${CC} ${CCFLAGS} -flto b5.c -c -o b5.o
+       ${CC} ${CCFLAGS} main5.c -c -o main5.o
+       ${CC} ${CCFLAGS} a5.o b5.o main5.o -o main5.exe  -Wl,-dead_strip
        ${OTOOL} -tV main5.exe | grep foo3 | ${PASS_IFF_EMPTY}
        ${PASS_IFF_GOOD_MACHO} main5.exe
 
@@ -130,9 +128,9 @@ six:
        # MachO : main6.c : Ufoo1
        #
        #echo "verify dead stripping of foo2 in main executable"
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a6.c -c -o a6.o
-       ${LLVMGCC} ${CCFLAGS} main6.c -c -o main6.o
-       ${LLVMGCC} ${CCFLAGS} a6.o  main6.o -o main6.exe  -Wl,-dead_strip
+       ${CC} ${CCFLAGS} -flto a6.c -c -o a6.o
+       ${CC} ${CCFLAGS} main6.c -c -o main6.o
+       ${CC} ${CCFLAGS} a6.o  main6.o -o main6.exe  -Wl,-dead_strip
        ${PASS_IFF_GOOD_MACHO} main6.exe
        ${OTOOL} -tV main6.exe | grep foo2 | ${PASS_IFF_EMPTY}
 
@@ -143,10 +141,10 @@ seven:
        # MachO : main7.c : Ufoo1
        #
        #echo "Seven..."
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a7.c -c -o a7.o
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm b7.c -c -o b7.o
-       ${LLVMGCC} ${CCFLAGS} main7.c -c -o main7.o
-       ${LLVMGCC} ${CCFLAGS} a7.o b7.o  main7.o -o main7.exe
+       ${CC} ${CCFLAGS} -flto a7.c -c -o a7.o
+       ${CC} ${CCFLAGS} -flto b7.c -c -o b7.o
+       ${CC} ${CCFLAGS} main7.c -c -o main7.o
+       ${CC} ${CCFLAGS} a7.o b7.o  main7.o -o main7.exe
        ${PASS_IFF_GOOD_MACHO} main7.exe
 
 eight:
@@ -155,9 +153,9 @@ eight:
        # MachO : main8.c : Ufoo1
        #
        #echo "Eight..."
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a8.c -c -o a8.o
-       ${LLVMGCC} ${CCFLAGS} main8.c -c -o main8.o
-       ${LLVMGCC} ${CCFLAGS} a8.o main8.o -o main8.exe   -Wl,-dead_strip
+       ${CC} ${CCFLAGS} -flto a8.c -c -o a8.o
+       ${CC} ${CCFLAGS} main8.c -c -o main8.o
+       ${CC} ${CCFLAGS} a8.o main8.o -o main8.exe   -Wl,-dead_strip
        ${OTOOL} -tV main8.exe | grep foo2 | ${PASS_IFF_EMPTY}
        ${OTOOL} -tV main8.exe | grep unnamed_2_1 | ${PASS_IFF_EMPTY}
 
@@ -167,9 +165,9 @@ nine:
        # MachO : main9.c : Ufoo1, Dfoo4
        #
        #echo "Nine..."
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a9.c -c -o a9.o
-       ${LLVMGCC} ${CCFLAGS} main9.c -c -o main9.o
-       ${LLVMGCC} ${CCFLAGS} a9.o main9.o -o main9.exe   -Wl,-dead_strip
+       ${CC} ${CCFLAGS} -flto a9.c -c -o a9.o
+       ${CC} ${CCFLAGS} main9.c -c -o main9.o
+       ${CC} ${CCFLAGS} a9.o main9.o -o main9.exe   -Wl,-dead_strip
        ${OTOOL} -tV main9.exe | grep foo2 | ${PASS_IFF_EMPTY}
        ${OTOOL} -tV main9.exe | grep foo4 | ${PASS_IFF_EMPTY}
        ${OTOOL} -tV main9.exe | grep unnamed_2_1 | ${PASS_IFF_EMPTY}
@@ -181,10 +179,10 @@ ten:
        # MachO : main10.c
        #
        #echo "Ten..."
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a10.c -c -o a10.o
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm b10.c -c -o b10.o
-       ${LLVMGCC} ${CCFLAGS} main10.c -c -o main10.o
-       ${LLVMGCC} ${CCFLAGS} a10.o b10.o main10.o -o main10.exe
+       ${CC} ${CCFLAGS} -flto a10.c -c -o a10.o
+       ${CC} ${CCFLAGS} -flto b10.c -c -o b10.o
+       ${CC} ${CCFLAGS} main10.c -c -o main10.o
+       ${CC} ${CCFLAGS} a10.o b10.o main10.o -o main10.exe
        ${PASS_IFF_GOOD_MACHO} main10.exe
 
 eleven:
@@ -193,9 +191,9 @@ eleven:
        # MachO : main11.c
        #
        #echo "Eleven..."
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a11.c -c -o a11.o
-       ${LLVMGCC} ${CCFLAGS} main11.c -c -o main11.o
-       ${LLVMGCC} ${CCFLAGS} a11.o main11.o -o main11.exe
+       ${CC} ${CCFLAGS} -flto a11.c -c -o a11.o
+       ${CC} ${CCFLAGS} main11.c -c -o main11.o
+       ${CC} ${CCFLAGS} a11.o main11.o -o main11.exe
        ${PASS_IFF_GOOD_MACHO} main11.exe
 
 twelve:
@@ -204,9 +202,9 @@ twelve:
        # MachO : main12.c
        #
        #echo "verify tentative def in llvm .o referenced from mach-o"
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a12.c -c -o a12.o
-       ${LLVMGCC} ${CCFLAGS} main12.c -c -o main12.o
-       ${LLVMGCC} ${CCFLAGS} a12.o main12.o -o main12.exe
+       ${CC} ${CCFLAGS} -flto a12.c -c -o a12.o
+       ${CC} ${CCFLAGS} main12.c -c -o main12.o
+       ${CC} ${CCFLAGS} a12.o main12.o -o main12.exe
        ${PASS_IFF_GOOD_MACHO} main12.exe
 
 thirteen:
@@ -215,49 +213,49 @@ thirteen:
        # MachO : main13.cc
        #
        # echo "Thirteen..."
-       ${LLVMGCC} ${CXXFLAGS} --emit-llvm a13.cc -c -o a13.o
-       ${LLVMGCC} ${CXXFLAGS} main13.cc -c -o main13.o
-       ${LLVMGXX} a13.o main13.o -o main13.exe
+       ${CC} ${CXXFLAGS} -flto a13.cc -c -o a13.o
+       ${CC} ${CXXFLAGS} main13.cc -c -o main13.o
+       ${CXX} a13.o main13.o -o main13.exe
 
 fourteen:
        #
        # llvm : a14.c b14.c
        #
        # echo "verify an used hidden symbol is removed from a dylib"
-       ${LLVMGCC} ${CXXFLAGS} -O4 -dynamiclib a14.c b14.c -o ab14.dylib
+       ${CC} ${CXXFLAGS} -O4 -dynamiclib a14.c b14.c -o ab14.dylib
        ${FAIL_IF_BAD_MACHO} ab14.dylib
        nm -m ab14.dylib | grep _X | ${PASS_IFF_EMPTY}
 
 fifteen:
        # echo "verify -dead_strip works with hidden symbols"
-       ${LLVMGCC} ${CXXFLAGS} -O4 -Wl,-dead_strip a15.c c15.c -o main15.exe
-       ${LLVMGCC} ${CXXFLAGS} -O4 a15.c c15.c -o main15.exe
+       ${CC} ${CXXFLAGS} -O4 -Wl,-dead_strip a15.c c15.c -o main15.exe
+       ${CC} ${CXXFLAGS} -O4 a15.c c15.c -o main15.exe
        ${FAIL_IF_BAD_MACHO} main15.exe
-       ${LLVMGCC} ${CXXFLAGS} -O4 -Wl,-dead_strip -dynamiclib a15.c b15.c -o a15.dylib
-       ${LLVMGCC} ${CXXFLAGS} -O4 a15.c b15.c -dynamiclib -o a15.dylib 
+       ${CC} ${CXXFLAGS} -O4 -Wl,-dead_strip -dynamiclib a15.c b15.c -o a15.dylib
+       ${CC} ${CXXFLAGS} -O4 a15.c b15.c -dynamiclib -o a15.dylib 
        ${FAIL_IF_BAD_MACHO} a15.dylib
        
 sixteen:
        # echo "verify -save-temps"
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm main16.c -c -o main16.o
-       ${LLVMGCC} ${CCFLAGS} main16.o -o main16.exe -Wl,-save-temps
+       ${CC} ${CCFLAGS} -flto main16.c -c -o main16.o
+       ${CC} ${CCFLAGS} main16.o -o main16.exe -Wl,-save-temps
        ${PASS_IFF} test -e main16.exe.lto.bc
        ${PASS_IFF} test -e main16.exe.lto.o
     
 seventeen:
        # echo "verify ld -r of all bitcode files produces a bitcode file"
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a17.c -c -o a17.o
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm b17.c -c -o b17.o
+       ${CC} ${CCFLAGS} -flto a17.c -c -o a17.o
+       ${CC} ${CCFLAGS} -flto b17.c -c -o b17.o
        ${LD} -arch ${ARCH} -r a17.o b17.o -o ab17.o
        file ab17.o | grep "Mach-O" | ${PASS_IFF_EMPTY}
        # echo "verify ld -r of bitcode and mach-o produces mach-o"
-       ${LLVMGCC} ${CCFLAGS} b17.c -c -o b17m.o
+       ${CC} ${CCFLAGS} b17.c -c -o b17m.o
        ${LD} -arch ${ARCH} -r a17.o b17m.o -o ab17m.o
        file ab17m.o | grep "Mach-O" | ${PASS_IFF_STDIN}
 
 eighteen:
        #echo verify ld -r -keep_private_externs works
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a18.c -c -o a18.o
+       ${CC} ${CCFLAGS} -flto a18.c -c -o a18.o
        ${LD} -arch ${ARCH} -r -keep_private_externs a18.o -o a18-rkpe.o
        nm -nm a18-rkpe.o | grep _common_hidden1 | grep "private external" | ${FAIL_IF_EMPTY}
        nm -nm a18-rkpe.o | grep _func_hidden2 | grep "private external" | ${FAIL_IF_EMPTY}
@@ -268,16 +266,16 @@ eighteen:
    
 nineteen:
        #echo verify missing symbol error
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm main19.c -c -o main19.o
-       ${FAIL_IF_SUCCESS} ${LLVMGCC} ${CCFLAGS} main19.o -o main19.exe 2>fail.log
+       ${CC} ${CCFLAGS} -flto main19.c -c -o main19.o
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main19.o -o main19.exe 2>fail.log
        grep _foo fail.log | ${PASS_IFF_STDIN}
 
 twenty:
        #echo verify bitcode files in archives works 
-       #${LLVMGCC} ${CCFLAGS} --emit-llvm a20.c -c -o a20.o
-       #${LLVMGCC} ${CCFLAGS} --emit-llvm b20.c -c -o b20.o
+       #${CC} ${CCFLAGS} -flto a20.c -c -o a20.o
+       #${CC} ${CCFLAGS} -flto b20.c -c -o b20.o
        #libtool -static a20.o b20.o -o lib20.a 
-       #${LLVMGCC} ${CCFLAGS} main20.c lib20.a -all_load -o main20.exe
+       #${CC} ${CCFLAGS} main20.c lib20.a -all_load -o main20.exe
        #nm main20.exe | grep _foo | ${PASS_IFF_STDIN}
        
 
@@ -285,5 +283,5 @@ twenty:
        
        
 clean:
-       rm -rf *.o main*.exe big.* *.dylib main16.exe.lto.bc fail.log lib20.a main21.preload lib21.a 
+       rm -rf *.o main*.exe big.* *.dylib main16.*.bc fail.log lib20.a main21.preload lib21.a 
        
index e538ee138da2686554db9b2a12e71e270ad6ba4f..ba8eed7339d7a24ccb15cce8a630162fa9152cdf 100644 (file)
@@ -30,16 +30,13 @@ include ${TESTROOT}/include/common.makefile
 # symbol from a dylib.
 #
 
-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 -c -o foo.o
        libtool -static foo.o -o libfoo.a 
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm main.c -c -o main.o
-       ${LLVMGCC} ${CCFLAGS} main.o -o main libfoo.a 
+       ${CC} ${CCFLAGS} -flto main.c -c -o main.o
+       ${CC} ${CCFLAGS} main.o -o main libfoo.a 
        ${PASS_IFF_GOOD_MACHO} main
        
 clean:
index 060e5a1beb6efe77abbdc6c22c26c383f1ef08fe..379a28261c4cc762b797177b5a59563f238e1c98 100644 (file)
@@ -27,14 +27,12 @@ include ${TESTROOT}/include/common.makefile
 # <rdar://problem/6806033> 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
+       ${CC} ${CCFLAGS} -flto bar.c  -c -o bar.o -fvisibility=hidden
+       ${CC} ${CCFLAGS} -dynamiclib bar.o -o libbar.dylib -dead_strip
        ${PASS_IFF_GOOD_MACHO} libbar.dylib
        
 clean:
diff --git a/unit-tests/test-cases/lto-dead_strip-coalesce/Makefile b/unit-tests/test-cases/lto-dead_strip-coalesce/Makefile
new file mode 100644 (file)
index 0000000..2f3f504
--- /dev/null
@@ -0,0 +1,39 @@
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+# Test case for <rdar://problem/9777977> 
+# mach-o has coalescable strings which are dead stripped away
+# but come back from bitcode file.
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.c -c -flto -o foo.o
+       ${CC} ${CCFLAGS} main.c -c -o main.o
+       ${CC} ${CCFLAGS} main.o foo.o -o main -dead_strip -framework Foundation
+       ${PASS_IFF_GOOD_MACHO} main
+       
+clean:
+       rm -rf main main.o foo.o
diff --git a/unit-tests/test-cases/lto-dead_strip-coalesce/foo.c b/unit-tests/test-cases/lto-dead_strip-coalesce/foo.c
new file mode 100644 (file)
index 0000000..f47f84d
--- /dev/null
@@ -0,0 +1,21 @@
+
+#include <string.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+void foo1()
+{
+       CFStringGetLength(CFSTR("test1"));
+       strlen("str1");
+}
+
+void foo2()
+{
+       CFStringGetLength(CFSTR("test2"));
+       strlen("str2");
+}
+
+void foo3()
+{
+       CFStringGetLength(CFSTR("test3"));
+       strlen("str3");
+}
diff --git a/unit-tests/test-cases/lto-dead_strip-coalesce/main.c b/unit-tests/test-cases/lto-dead_strip-coalesce/main.c
new file mode 100644 (file)
index 0000000..ecbd4f2
--- /dev/null
@@ -0,0 +1,34 @@
+
+#include <string.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+
+extern void foo1();
+
+
+void t1()
+{
+       CFStringGetLength(CFSTR("test1"));
+       strlen("str1");
+}
+
+void t2()
+{
+       CFStringGetLength(CFSTR("test2"));
+       strlen("str2");
+}
+
+void t3()
+{
+       CFStringGetLength(CFSTR("test3"));
+       strlen("str3");
+}
+
+
+int main()
+{
+       t2();
+       foo1();
+       return 0;
+}
+
index ccd5b5955d553656320825a296958267d6703de5..afd69480379538b8c94bc2aeec10b50014355562 100644 (file)
@@ -27,14 +27,12 @@ include ${TESTROOT}/include/common.makefile
 # <rdar://problem/8481987> Link Time Optimization crashes linker 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 foo.m  -c -o foo.o -fvisibility=hidden
-       ${LLVMGCC} ${CCFLAGS} -dynamiclib foo.o -o libfoo.dylib -dead_strip -framework Foundation
+       ${CC} ${CCFLAGS} -flto foo.m  -c -o foo.o -fvisibility=hidden
+       ${CC} ${CCFLAGS} -dynamiclib foo.o -o libfoo.dylib -dead_strip -framework Foundation
        ${PASS_IFF_GOOD_MACHO} libfoo.dylib
        
 clean:
index d563c92ea861eeeeb1e3793c81cadadc0c26bd9b..ad1fe8b610b851837aa2d5c59952fe4f426fc060 100644 (file)
@@ -27,14 +27,12 @@ include ${TESTROOT}/include/common.makefile
 # <rdar://problem/8481987> Link Time Optimization crashes linker 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
+       ${CC} ${CCFLAGS} -flto bar.c  -c -o bar.o -fvisibility=hidden
+       ${CC} ${CCFLAGS} -dynamiclib bar.o -o libbar.dylib -dead_strip
        ${PASS_IFF_GOOD_MACHO} libbar.dylib
        
 clean:
index fa0a02b6d3ab7341befec815b215629de6ae6d3b..5a54bcfe2c6019d50aa38865a27af238b4beb072 100644 (file)
@@ -27,17 +27,15 @@ include ${TESTROOT}/include/common.makefile
 # <rdar://problem/8708091> Link Time Optimization error with tentative defs and -dead_strip
 #
 
-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 foo.c -c -o foo.o 
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm bar.c -c -o bar.o 
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm baz.c -c -o baz.o 
-       ${LLVMGCC} ${CCFLAGS} main.c -c -o main.o 
-       ${LLVMGCC} ${CCFLAGS} main.o foo.o bar.o baz.o -o main -dead_strip
+       ${CC} ${CCFLAGS} -flto foo.c -c -o foo.o 
+       ${CC} ${CCFLAGS} -flto bar.c -c -o bar.o 
+       ${CC} ${CCFLAGS} -flto baz.c -c -o baz.o 
+       ${CC} ${CCFLAGS} main.c -c -o main.o 
+       ${CC} ${CCFLAGS} main.o foo.o bar.o baz.o -o main -dead_strip
        ${PASS_IFF_GOOD_MACHO} main
        
 clean:
index a518d82ca5440488a5f97c16435cdec9f157c413..b27291a8236a5b09bff1cd90a43fe8d37d65d3f0 100644 (file)
@@ -27,15 +27,12 @@ include ${TESTROOT}/include/common.makefile
 # <rdar://problem/7438246> LTO with 'dead code strip' can't ignore unused functions with undefined references
 #
 
-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
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm main.c -c -o main.o 
-       ${LLVMGCC} ${CCFLAGS} -dead_strip main.o bar.o -o main
+       ${CC} ${CCFLAGS} -flto bar.c  -c -o bar.o
+       ${CC} ${CCFLAGS} -flto main.c -c -o main.o 
+       ${CC} ${CCFLAGS} -dead_strip main.o bar.o -o main
        ${PASS_IFF_GOOD_MACHO} main
        
 clean:
index 1edf08afa22bfe22c1ae0ce89e73ec830e1b3819..095405a344a9c82e3338911c8df256e2c089c2d4 100644 (file)
@@ -28,16 +28,13 @@ include ${TESTROOT}/include/common.makefile
 # results in foo() not being inlined
 #
 
-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 main.c -c -o main.o -fvisibility=hidden
-       ${LLVMGCC} ${CCFLAGS} main.o -o main
+       ${CC} ${CCFLAGS} -flto main.c -c -o main.o -fvisibility=hidden
+       ${CC} ${CCFLAGS} main.o -o main
        nm main | grep  _foo | ${FAIL_IF_STDIN}
-       ${LLVMGCC} ${CCFLAGS} main.o -o main2 -fvisibility=hidden -Wl,-mllvm -Wl,--disable-inlining 
+       ${CC} ${CCFLAGS} main.o -o main2 -fvisibility=hidden -Wl,-mllvm -Wl,--disable-inlining 
        nm main2 | grep  _foo | ${FAIL_IF_EMPTY}
        ${PASS_IFF_GOOD_MACHO} main
        
index 57fae1dfbd6f6d43f10138c066e028f2c6417359..968671a63b46d620486b360551704b4ad5c3ed45 100644 (file)
@@ -28,8 +28,6 @@ include ${TESTROOT}/include/common.makefile
 # 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
 
@@ -39,8 +37,8 @@ all:
        ${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
+       ${CC} ${CCFLAGS} -flto main.m -c -o main.o
+       ${CC} ${CCFLAGS} main.o -o main libfoobar.a -framework Foundation
        ${PASS_IFF_GOOD_MACHO} main
        
 clean:
index 8b13444f8875d63f14cdce504049e195e5fac9ce..1a6f05906c7da958bb300600084c5386660e7010 100644 (file)
@@ -27,16 +27,13 @@ include ${TESTROOT}/include/common.makefile
 # <rdar://problem/8198537> trivial Objective-C app fails when using libLTO
 #
 
-LLVMGCC = /Developer/usr/bin/llvm-gcc-4.2 -arch ${ARCH}
-LLVMGXX = /Developer/usr/bin/llvm-g++-4.2 -arch ${ARCH}
-
 
 IMAGE_INFO = "__image_info"
 
 ifeq ($(ARCH),x86_64)
        IMAGE_INFO = "__objc_imageinfo"
 endif
-ifeq ($(ARCH),armv6)
+ifeq ($(FILEARCH),arm)
        IMAGE_INFO = "__objc_imageinfo"
 endif
 
@@ -44,8 +41,8 @@ endif
 run: all
 
 all:
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm main.m -c -o main.o
-       ${LLVMGCC} ${CCFLAGS} main.o -o main -framework Foundation
+       ${CC} ${CCFLAGS} -flto main.m -c -o main.o
+       ${CC} ${CCFLAGS} main.o -o main -framework Foundation
        size -l main | grep ${IMAGE_INFO} | ${FAIL_IF_EMPTY}
        ${PASS_IFF_GOOD_MACHO} main
        
index aeda85d07d017087b724fb901a8c4cb3f25d94d2..180cfb39b77842fcb71be8d66ebc8d7c442fe638 100644 (file)
@@ -28,13 +28,12 @@ include ${TESTROOT}/include/common.makefile
 # being produced.
 #
 
-LLVMGCC = /Developer/usr/bin/llvm-gcc-4.2 -arch ${ARCH}
 
 run: all
 
 all:
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm main.c -c -o main.o -fvisibility=hidden
-       ${LLVMGCC} ${CCFLAGS} main.o -o main -Wl,-object_path_lto,`pwd`/main.tmp.o
+       ${CC} ${CCFLAGS} -flto main.c -c -o main.o -fvisibility=hidden
+       ${CC} ${CCFLAGS} main.o -o main -Wl,-object_path_lto,`pwd`/main.tmp.o
        nm main.tmp.o | grep _main | ${FAIL_IF_EMPTY}
        ${PASS_IFF_GOOD_MACHO} main
        
index 55ac0f16ebb4204f98b776fd56e2113268bd1207..2be86f33e871dbe85af3e7759945d6c09fb03349 100644 (file)
@@ -28,15 +28,12 @@ include ${TESTROOT}/include/common.makefile
 # and mach-o has a strong _foo.
 #
 
-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 -c -o foo.o
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm main.c -c -o main.o
-       ${LLVMGCC} ${CCFLAGS} main.o foo.o -o main 
+       ${CC} ${CCFLAGS} -flto main.c -c -o main.o
+       ${CC} ${CCFLAGS} main.o foo.o -o main 
        otool -Iv main | grep _abort | ${FAIL_IF_STDIN}
        ${PASS_IFF_GOOD_MACHO} main
        
index 6a433dbefed1f4d8b0bddc22d7849adaadb6afe8..5f5d498d200df57b85578e0f43400e32962884de 100644 (file)
@@ -12,6 +12,6 @@ __attribute__((visibility("hidden"),weak)) void foo()
 int main()
 {
    foo();
-   
+   return 0;
 }
 
index e53ad48aab11c101eccf1ee2f23d89b701358aca..ff4f7cc0caef5b1428d83f0f3a4ed41f664dd14b 100644 (file)
@@ -28,15 +28,12 @@ include ${TESTROOT}/include/common.makefile
 # 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
+       ${CC} ${CCFLAGS} -flto main.c -c -o main.o
+       ${CC} ${CCFLAGS} main.o -o main libfoo.dylib
        ${PASS_IFF_GOOD_MACHO} main
        
 clean:
diff --git a/unit-tests/test-cases/merge_zero_fill_sections/Makefile b/unit-tests/test-cases/merge_zero_fill_sections/Makefile
new file mode 100755 (executable)
index 0000000..bec9e76
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# Copyright (c) 2010 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 the -merge_zero_fill_sections works
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} main.c -o main -Wl,-merge_zero_fill_sections 
+       size -l main | grep __bss  | ${FAIL_IF_STDIN}
+       size -l main | grep __common | ${FAIL_IF_STDIN}
+       size -l main | grep __zerofill | grep "offset 0" | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm  main
diff --git a/unit-tests/test-cases/merge_zero_fill_sections/main.c b/unit-tests/test-cases/merge_zero_fill_sections/main.c
new file mode 100755 (executable)
index 0000000..87528ec
--- /dev/null
@@ -0,0 +1,41 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+static int a[2000];
+int b[2000];
+
+extern void* zerofill_start  __asm("section$start$__DATA$__zerofill");
+extern void* zerofill__end   __asm("section$end$__DATA$__zerofill");
+
+void* start = &zerofill_start;
+void* end = &zerofill__end;
+
+int main()
+{
+       a[0] = 0;
+       b[0] = 0;
+       return 0;
+}
+
index d3078804b87de8c7612ec048a280ce3f61f23e94..1749c7ed627480d9593f70e90cef31ccf3d5081c 100644 (file)
@@ -1,4 +1,5 @@
        .text
+       .align 4
        .globl  _test
 _test:
 #if __i386__
diff --git a/unit-tests/test-cases/objc-category-warning/Makefile b/unit-tests/test-cases/objc-category-warning/Makefile
new file mode 100644 (file)
index 0000000..95cc91d
--- /dev/null
@@ -0,0 +1,55 @@
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Verify optimization in which categories are merged into classes
+#
+OPTIONS = 
+
+ifeq ($(ARCH),i386)
+       OPTIONS = -fobjc-abi-version=2 -Wl,-objc_abi_version,2
+endif
+
+all:   all-${FILEARCH}
+
+all-ppc:
+       ${PASS_IFF} true
+
+all-i386: all-rest
+all-x86_64: all-rest
+all-arm: all-rest
+
+all-rest:
+       ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat.m -DOVERRIDE_CLASS=1 -framework Foundation -o libfoo.dylib 2> warnings1.txt
+       grep warning warnings1.txt | grep instance_method | ${FAIL_IF_EMPTY}
+       grep warning warnings1.txt | grep class_method | ${FAIL_IF_EMPTY}
+       ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat.m copycat.m -framework Foundation -o libfoo2.dylib 2> warnings2.txt
+       grep warning warnings2.txt | grep instance_method_fromcat | ${FAIL_IF_EMPTY}
+       grep warning warnings2.txt | grep class_method_fromcat | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} libfoo2.dylib
+       
+clean:
+       rm -rf  lib*.dylib warnings*.txt
\ No newline at end of file
diff --git a/unit-tests/test-cases/objc-category-warning/cat.m b/unit-tests/test-cases/objc-category-warning/cat.m
new file mode 100644 (file)
index 0000000..e60f37b
--- /dev/null
@@ -0,0 +1,24 @@
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+-(void) method1;
+@end
+
+@interface Foo(fromcat)
+- (void) instance_method_fromcat;
++ (void) class_method_fromcat;
+#if OVERRIDE_CLASS
+- (void) instance_method;
++ (void) class_method;
+#endif
+@end
+
+@implementation Foo(fromcat)
+- (void) instance_method_fromcat {} 
++ (void) class_method_fromcat {}
+#if OVERRIDE_CLASS
+- (void) instance_method {}
++ (void) class_method {}
+#endif
+@end
+
diff --git a/unit-tests/test-cases/objc-category-warning/copycat.m b/unit-tests/test-cases/objc-category-warning/copycat.m
new file mode 100644 (file)
index 0000000..309be02
--- /dev/null
@@ -0,0 +1,16 @@
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+-(void) method1;
+@end
+
+@interface Foo(copycat)
+- (void) instance_method_fromcat;
++ (void) class_method_fromcat;
+@end
+
+@implementation Foo(copycat)
+- (void) instance_method_fromcat {} 
++ (void) class_method_fromcat {}
+@end
+
diff --git a/unit-tests/test-cases/objc-category-warning/foo.m b/unit-tests/test-cases/objc-category-warning/foo.m
new file mode 100644 (file)
index 0000000..2a75794
--- /dev/null
@@ -0,0 +1,13 @@
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+-(void) instance_method;
++(void) class_method;
+@end
+
+
+@implementation Foo
+-(void) instance_method {}
++(void) class_method {}
+@end
+
index c8c1b27debf2a4e8c2d675f4779a77571c7a82d1..52840c9303087365619fe9bde771bfea3f69b0c3 100644 (file)
@@ -30,6 +30,9 @@ CLASS_NAME_FOO = .objc_class_name_Foo
 ifeq (${ARCH},x86_64)
        CLASS_NAME_FOO = '_OBJC_CLASS_$$_Foo'
 endif
+ifeq (${FILEARCH},arm)
+       CLASS_NAME_FOO = '_OBJC_CLASS_$$_Foo'
+endif
 
 
 run: all
index b18012a23030dcdb8d0629d90d1e2a62f5c4a359..67e04a3c7ecc594463aa8f40cece3552cccb7246 100644 (file)
@@ -31,18 +31,19 @@ IMAGE_INFO = "__image_info"
 ifeq ($(ARCH),x86_64)
        IMAGE_INFO = "__objc_imageinfo"
 endif
-ifeq ($(ARCH),armv6)
-       IMAGE_INFO = "__objc_imageinfo"
-endif
 
+test: test-${FILEARCH}
 
+test-i386: test-macosx
+test-x86_64: test-macosx
+test-arm:   test-good
 
 #
 # Validate that the linker catches illegal combinations of .o files 
 # compiled with different GC settings. 
 #
 
-test:
+test-macosx:
        ${CC} ${CCFLAGS} foo.m -c -o foo.o
        ${FAIL_IF_BAD_OBJ} foo.o
 
@@ -127,7 +128,9 @@ test:
        ${CC} ${CCFLAGS} foo.o runtime.c -dynamiclib -o libfoo.dylib 
        ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bar-gc-only.o runtime.c -dynamiclib libfoo.dylib -o libbar.dylib 2> fail.log
 
+       ${PASS_IFF} true
 
+test-good:
        ${PASS_IFF} true
 
 clean:
index 999bf2fce361f8e47b234c216f21cb52e4e150f8..87883645c8cf4dfa89ca845b11a4e5030acb68f4 100644 (file)
@@ -12,7 +12,6 @@ run: all
 
 all:
        ${CC} ${CCFLAGS} test.m -dynamiclib -framework Foundation -o libtest.dylib
-       ${CC} ${CCFLAGS} test.m -dynamiclib -framework Foundation -o libtest.dylib -Wl,-no_compact_linkedit -ldylib1.o
        ${PASS_IFF_GOOD_MACHO} libtest.dylib
        
 clean:
index eba52c08a52e00032fae86f6436a6094863e8df2..9a6b194e226b4f800465eb3d7fae3eb8cf48d8c0 100644 (file)
@@ -1,6 +1,7 @@
 
 
        .text
+       .align 4
        
        .globl _foo1
 _foo1: nop
diff --git a/unit-tests/test-cases/prebound-main/Makefile b/unit-tests/test-cases/prebound-main/Makefile
deleted file mode 100644 (file)
index 285d767..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-
-TESTROOT = ../..
-include ${TESTROOT}/include/common.makefile
-
-SHELL = bash # use bash shell so we can redirect just stderr
-
-#
-# Verify -prebind for 10.3 make ppc prebound and all others not prebound
-#
-
-ifeq (,${findstring 64,$(ARCH)})
-       ifeq (${ARCH},i386)
-               KEYWORD = NOUNDEFS
-       else
-               KEYWORD = PREBOUND
-       endif
-else
-       KEYWORD = NOUNDEFS
-endif
-
-
-run: all
-
-all: 
-       # SnowLeopard is missing libmx.dylib which gcc thinks it needs
-       ${CC} ${CCFLAGS} main.c -o main -prebind -mmacosx-version-min=10.3 -nostdlib -lcrt1.o -lSystem
-       otool -hv main | grep ${KEYWORD} | ${FAIL_IF_EMPTY}
-       ${PASS_IFF_GOOD_MACHO} main
-
-clean:
-       rm main 
diff --git a/unit-tests/test-cases/prebound-main/main.c b/unit-tests/test-cases/prebound-main/main.c
deleted file mode 100644 (file)
index 251979e..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-
-int main() { return 0; }
-
index 07bce595e154f374be908a584f68fbce2e61f2b6..67ed3fa1691eede590f13440a414b9dd6f509187 100644 (file)
@@ -29,11 +29,22 @@ SHELL = bash # use bash shell so we can redirect just stderr
 # The point of this test is to build a prebound split-seg library
 #
 
-run: all
+all: all-${ARCH}
 
-all: 
+all-i386: all-32
+all-ppc: all-32
+all-x86_64: all-good
+all-armv6: all-good
+all-armv7: all-good
+
+
+all-good:
+       ${PASS_IFF} true
+
+
+all-32: 
        ${CC} ${CCFLAGS} -seg_addr_table address_table -prebind bar.c -dynamiclib -o libbar.dylib -install_name /foo/bar/libbar.dylib
        ${PASS_IFF_GOOD_MACHO} libbar.dylib
 
 clean:
-       rm *.dylib 
+       rm -rf *.dylib 
index b220580fc4badf4e6d3bd1501cb339d8cfd99266..b4de5748e0b01e769b3ba0b4b32f8c4e2ebf41b8 100644 (file)
@@ -38,14 +38,14 @@ all:
        ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib  
        # verify uses of symbols from re-exported dylibs have ordinal that allows dyld to search amoung re-exported dylibs 
        ${CC} ${CCFLAGS} -dynamiclib foo.c -DUSE_BAZ -o libfoo2.dylib -Wl,-reexport_library libpub.dylib -Wl,-reexport_library libbar.dylib  -Wl,-reexport_library libbaz.dylib 
-       dyldinfo -bind      libfoo2.dylib | grep _bar | grep this-image | ${FAIL_IF_EMPTY}
-       dyldinfo -lazy_bind libfoo2.dylib | grep _bar | grep this-image | ${FAIL_IF_EMPTY}
-       dyldinfo -bind      libfoo2.dylib | grep _baz | grep this-image | ${FAIL_IF_EMPTY}
-       dyldinfo -lazy_bind libfoo2.dylib | grep _baz | grep this-image | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -bind      libfoo2.dylib | grep _bar | grep this-image | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -lazy_bind libfoo2.dylib | grep _bar | grep this-image | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -bind      libfoo2.dylib | grep _baz | grep this-image | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -lazy_bind libfoo2.dylib | grep _baz | grep this-image | ${FAIL_IF_EMPTY}
        # verify that if only one non-publc re-exported dylib, don't use magic ordinal
        ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo1.dylib -Wl,-reexport_library libpub.dylib -Wl,-reexport_library libbar.dylib 
-       dyldinfo -bind      libfoo1.dylib | grep _bar | grep this-image | ${FAIL_IF_STDIN}
-       dyldinfo -lazy_bind libfoo1.dylib | grep _bar | grep this-image | ${FAIL_IF_STDIN}
+       ${DYLDINFO} -bind      libfoo1.dylib | grep _bar | grep this-image | ${FAIL_IF_STDIN}
+       ${DYLDINFO} -lazy_bind libfoo1.dylib | grep _bar | grep this-image | ${FAIL_IF_STDIN}
        ${PASS_IFF_GOOD_MACHO} libfoo2.dylib
 
 
index 64ec112bb130aa23a935e2b50c0c55041c8fd95d..59887aa8901a0287aecc0263909082adf79160d0 100644 (file)
@@ -28,136 +28,139 @@ include ${TESTROOT}/include/common.makefile
 #
 
 
-run: all
+all: all-${ARCH}
 
-all:
+all-i386: all-new all-old
+all-x86_64: all-new all-old
+all-armv6: all-new 
+all-armv7: all-new 
 
-# -sub_library for 10.4
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib  -mmacosx-version-min=10.4
-       ${FAIL_IF_BAD_MACHO} libbar.dylib
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lbar -L. -sub_library libbar -mmacosx-version-min=10.4
-       ${FAIL_IF_BAD_MACHO} libfoo.dylib
-       otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_EMPTY}
-       otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
-       
-# -sub_library for 10.5
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib   -mmacosx-version-min=10.5
+
+all-new:       
+       # -sub_library for 10.5
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib   ${VERSION_NEW_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} libbar.dylib
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lbar -L. -sub_library libbar -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lbar -L. -sub_library libbar ${VERSION_NEW_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
        otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
        otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_STDIN}
-       
-       
-# -sub_umbrella for 10.4
-       mkdir -p Bar.framework Foo.framework
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar"  -mmacosx-version-min=10.4
-       ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -framework Bar -sub_umbrella Bar  -mmacosx-version-min=10.4
-       ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
-       otool -lv Foo.framework/Foo | grep LC_SUB_UMBRELLA | ${FAIL_IF_EMPTY}
-       otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
 
-# -sub_umbrella for 10.5
+       # -sub_umbrella for 10.5
        mkdir -p Bar.framework Foo.framework
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar"  -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar"  ${VERSION_NEW_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -framework Bar -sub_umbrella Bar  -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -framework Bar -sub_umbrella Bar  ${VERSION_NEW_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
        otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
        otool -lv Foo.framework/Foo | grep LC_SUB_UMBRELLA | ${FAIL_IF_STDIN}
-       
 
-# -umbrella for 10.4
+       # -umbrella for 10.5
        mkdir -p Bar.framework Foo.framework
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" -umbrella Foo -mmacosx-version-min=10.4
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" -umbrella Foo ${VERSION_NEW_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -framework Bar -mmacosx-version-min=10.4
-       ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
-       otool -lv Bar.framework/Bar | grep LC_SUB_FRAMEWORK | ${FAIL_IF_EMPTY}
-       otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
-
-# -umbrella for 10.5
-       mkdir -p Bar.framework Foo.framework
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" -umbrella Foo -mmacosx-version-min=10.5
-       ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -framework Bar -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -framework Bar ${VERSION_NEW_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
        otool -lv Bar.framework/Bar | grep LC_SUB_FRAMEWORK | ${FAIL_IF_EMPTY}
        otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
 
-
-# -reexport_library for 10.4
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib  -mmacosx-version-min=10.4
+       # -reexport_library for 10.5
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib  ${VERSION_NEW_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} libbar.dylib
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport_library,libbar.dylib -mmacosx-version-min=10.4
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport_library,libbar.dylib ${VERSION_NEW_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
-       otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_EMPTY}
-       otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
+       otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
+       otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_STDIN}
        
-# -reexport_library for 10.5
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib  -mmacosx-version-min=10.5
+       # -reexport-l for 10.5
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib   ${VERSION_NEW_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} libbar.dylib
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport_library,libbar.dylib -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport-lbar -L. ${VERSION_NEW_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
        otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
        otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_STDIN}
+
+       # -reexport_framework for 10.5
+       mkdir -p Bar.framework Foo.framework
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar"  ${VERSION_NEW_LINKEDIT}
+       ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -Wl,-reexport_framework,Bar ${VERSION_NEW_LINKEDIT}
+       ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
+       otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
+       otool -lv Foo.framework/Foo | grep LC_SUB_UMBRELLA | ${FAIL_IF_STDIN}
        
+       # -reexport_framework and -umbrella for 10.4
+       mkdir -p Bar.framework Foo.framework
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" -umbrella Foo ${VERSION_NEW_LINKEDIT}
+       ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -Wl,-reexport_framework,Bar ${VERSION_NEW_LINKEDIT}
+       ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
+       otool -lv Bar.framework/Bar | grep LC_SUB_FRAMEWORK | ${FAIL_IF_EMPTY}
+       otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
+
+       ${PASS_IFF} /usr/bin/true
 
-# -reexport-l for 10.4
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib  -mmacosx-version-min=10.4
+
+
+all-old:
+       # -sub_library for 10.4
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib  ${VERSION_OLD_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} libbar.dylib
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport-lbar -L. -mmacosx-version-min=10.4
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lbar -L. -sub_library libbar ${VERSION_OLD_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
        otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_EMPTY}
        otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
        
-# -reexport-l for 10.5
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib   -mmacosx-version-min=10.5
-       ${FAIL_IF_BAD_MACHO} libbar.dylib
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport-lbar -L. -mmacosx-version-min=10.5
-       ${FAIL_IF_BAD_MACHO} libfoo.dylib
-       otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
-       otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_STDIN}
-
-
-# -reexport_framework for 10.4
+       # -sub_umbrella for 10.4
        mkdir -p Bar.framework Foo.framework
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar"  -mmacosx-version-min=10.4
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar"  ${VERSION_OLD_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -Wl,-reexport_framework,Bar -mmacosx-version-min=10.4
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -framework Bar -sub_umbrella Bar  ${VERSION_OLD_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
        otool -lv Foo.framework/Foo | grep LC_SUB_UMBRELLA | ${FAIL_IF_EMPTY}
-       otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
+       otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN} 
 
-# -reexport_framework for 10.5
+       # -umbrella for 10.4
        mkdir -p Bar.framework Foo.framework
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar"  -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" -umbrella Foo ${VERSION_OLD_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -Wl,-reexport_framework,Bar -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -framework Bar ${VERSION_OLD_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
-       otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
-       otool -lv Foo.framework/Foo | grep LC_SUB_UMBRELLA | ${FAIL_IF_STDIN}
-       
+       otool -lv Bar.framework/Bar | grep LC_SUB_FRAMEWORK | ${FAIL_IF_EMPTY}
+       otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
+
+       # -reexport_library for 10.4
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib  ${VERSION_OLD_LINKEDIT}
+       ${FAIL_IF_BAD_MACHO} libbar.dylib
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport_library,libbar.dylib ${VERSION_OLD_LINKEDIT}
+       ${FAIL_IF_BAD_MACHO} libfoo.dylib
+       otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_EMPTY}
+       otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}      
 
-# -reexport_framework and -umbrella for 10.4
+       # -reexport-l for 10.4
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib  ${VERSION_OLD_LINKEDIT}
+       ${FAIL_IF_BAD_MACHO} libbar.dylib
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport-lbar -L. ${VERSION_OLD_LINKEDIT}
+       ${FAIL_IF_BAD_MACHO} libfoo.dylib
+       otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_EMPTY}
+       otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
+       
+       # -reexport_framework for 10.4
        mkdir -p Bar.framework Foo.framework
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" -umbrella Foo -mmacosx-version-min=10.4
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar"  ${VERSION_OLD_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -Wl,-reexport_framework,Bar -mmacosx-version-min=10.4
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -Wl,-reexport_framework,Bar ${VERSION_OLD_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
-       otool -lv Bar.framework/Bar | grep LC_SUB_FRAMEWORK | ${FAIL_IF_EMPTY}
+       otool -lv Foo.framework/Foo | grep LC_SUB_UMBRELLA | ${FAIL_IF_EMPTY}
        otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
 
-
-# -reexport_framework and -umbrella for 10.4
+       # -reexport_framework and -umbrella for 10.4
        mkdir -p Bar.framework Foo.framework
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" -umbrella Foo -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" -umbrella Foo ${VERSION_OLD_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -Wl,-reexport_framework,Bar -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -Wl,-reexport_framework,Bar ${VERSION_OLD_LINKEDIT}
        ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
        otool -lv Bar.framework/Bar | grep LC_SUB_FRAMEWORK | ${FAIL_IF_EMPTY}
-       otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
+       otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
 
        ${PASS_IFF} /usr/bin/true
 
index fc622739aae5367f67100679b367493174bf859f..3ec1fca3767b96999dca7d5fb71f8bfec84c6cfa 100644 (file)
@@ -28,23 +28,17 @@ include ${TESTROOT}/include/common.makefile
 #
 
 
-run: all
 
-all:
+all: all-${ARCH}
 
+all-i386: all-new all-old
+all-x86_64: all-new all-old
+all-armv6: all-new 
+all-armv7: all-new 
 
-# -reexport_library for 10.4
-       ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib  -mmacosx-version-min=10.4
-       ${FAIL_IF_BAD_MACHO} libbaz.dylib
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -Wl,-reexport_library,libbaz.dylib -mmacosx-version-min=10.4
-       ${FAIL_IF_BAD_MACHO} libbar.dylib
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport_library,libbar.dylib -mmacosx-version-min=10.4
-       ${FAIL_IF_BAD_MACHO} libfoo.dylib
-       ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
-       ${FAIL_IF_BAD_MACHO} main
 
-       
-# -reexport_library for 10.5 and later
+all-new:       
+       # -reexport_library for 10.5 and later
        ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib  
        ${FAIL_IF_BAD_MACHO} libbaz.dylib
        ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -Wl,-reexport_library,libbaz.dylib 
@@ -54,6 +48,18 @@ all:
        ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
        ${PASS_IFF_GOOD_MACHO} main
 
+all-old:
+       # -reexport_library for 10.4
+       ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib  -mmacosx-version-min=10.4
+       ${FAIL_IF_BAD_MACHO} libbaz.dylib
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -Wl,-reexport_library,libbaz.dylib -mmacosx-version-min=10.4
+       ${FAIL_IF_BAD_MACHO} libbar.dylib
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport_library,libbar.dylib -mmacosx-version-min=10.4
+       ${FAIL_IF_BAD_MACHO} libfoo.dylib
+       ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
+       ${FAIL_IF_BAD_MACHO} main
+
+
 
 clean:
 
index fdb13d5de83c1dca375440669b74dfdfa02d8182..4eb7b4336e64bfc22e48f512b2165ff7ed2c2dc7 100644 (file)
@@ -29,11 +29,15 @@ include ${TESTROOT}/include/common.makefile
 #
 
 
-run: all
+all: all-${ARCH}
 
-all:
+all-i386: all-new all-old
+all-x86_64: all-new all-old
+all-armv6: all-new 
+all-armv7: all-new 
        
-# -sub_library for 10.4
+all-old:
+       # -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
@@ -45,17 +49,18 @@ all:
        ${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
+
+all-new:               
+       # -sub_library for 10.5
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib  -install_name /usr/lib/libbar.dylib 
        ${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
+       ${CC} ${CCFLAGS} -dynamiclib middle.c -o libmiddle.dylib -lbar -L. -sub_library libbar -install_name /mid/libmiddle.dylib 
        ${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
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lmiddle -L. -sub_library libmiddle -install_name /usr/lib/libfoo.dylib 
        ${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
+       ${CC} ${CCFLAGS} -dynamiclib other.c -o libother.dylib -lbar -L. -sub_library libbar -install_name /usr/lib/libother.dylib 
        ${FAIL_IF_BAD_MACHO} libother.dylib
-       ${CC} ${CCFLAGS} main.c -DCALL_BAR libfoo.dylib libother.dylib -o main -L. -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} main.c -DCALL_BAR libfoo.dylib libother.dylib -o main -L. 
        nm -m main | grep _bar | grep libbar | ${FAIL_IF_EMPTY}
        ${PASS_IFF_GOOD_MACHO} main
        
index a1dfd884c61a068fe957ab2fca733b2e950d7288..e71b8cc595b212ed126a98c7bb778018f087f5e1 100644 (file)
@@ -29,11 +29,17 @@ include ${TESTROOT}/include/common.makefile
 #
 
 
-run: all
 
-all:
+all: all-${ARCH}
 
-# -sub_library for 10.4
+all-i386: all-new all-old
+all-x86_64: all-new all-old
+all-armv6: all-new 
+all-armv7: all-new 
+
+
+all-old:
+       # -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 foo.c -o libfoo.dylib -lbar -L. -sub_library libbar -mmacosx-version-min=10.4
@@ -44,16 +50,17 @@ all:
        ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -L. -mmacosx-version-min=10.4
        otool -L main | grep libbar | ${FAIL_IF_STDIN}
        
-               
-# -sub_library for 10.5
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib  -install_name /usr/lib/libbar.dylib -mmacosx-version-min=10.5
+
+all-new:               
+       # -sub_library for 10.5
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib  -install_name /usr/lib/libbar.dylib 
        ${FAIL_IF_BAD_MACHO} libbar.dylib
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lbar -L. -sub_library libbar -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lbar -L. -sub_library libbar 
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
-       ${CC} ${CCFLAGS} main.c -DCALL_BAR libfoo.dylib -o main -L. -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} main.c -DCALL_BAR libfoo.dylib -o main -L. 
        otool -L main | grep libbar | ${FAIL_IF_EMPTY}
        nm -m main | grep _bar | grep libbar | ${FAIL_IF_EMPTY}
-       ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -L. -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -L. 
        otool -L main | grep libbar | ${FAIL_IF_STDIN}
        
                        
index 8db5b0384fd6876c07827d77117e97bb8642b3ba..e4b80861ca5dafc90c5040a52a3d8ba67c06bb8f 100644 (file)
@@ -1,4 +1,4 @@
-##
+ ##
 # Copyright (c) 2006-2007 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
@@ -51,6 +51,10 @@ ifeq (${ARCH},x86_64)
        XRELOCS_NEEDED =  ${FAIL_IF_STDIN}
        LRELOCS_NEEDED =  ${FAIL_IF_STDIN}
 endif
+ifeq (${FILEARCH},arm)
+       NO_PIC =  -mdynamic-no-pic
+       STATIC =  -static
+endif
 
 
 
index 86716dad291c3cfe856205aca4d5d37d37539d6d..67ff5e50372baf2eb579fbfe88d96c73225b3d2b 100644 (file)
@@ -126,7 +126,7 @@ L101:
        
        .text
 _pointer_diffs:
-       .long _foo-1b
+1:     .long _foo-1b
        .long _foo+10-1b
        .long _test_branches-1b
        .long _test_branches+3-1b
@@ -244,6 +244,12 @@ _arm16tests:
        movt    r0, :upper16:_datahilo16alt+1792
        movw    r0, :lower16:_datahilo16alt+165
        movt    r0, :upper16:_datahilo16alt+165
+       movw    r0, :lower16:_thumbTarget
+       movt    r0, :upper16:_thumbTarget
+       movw    r0, :lower16:_externalTarget
+       movt    r0, :upper16:_externalTarget
+       movw    r0, :lower16:_externalTarget+61447
+       movt    r0, :upper16:_externalTarget+61447
 Lpicbase:
        movw    r0, :lower16:_datahilo16 - Lpicbase
        movt    r0, :upper16:_datahilo16 - Lpicbase
@@ -259,6 +265,8 @@ Lpicbase:
        movt    r0, :upper16:_datahilo16alt+1792 - Lpicbase
        movw    r0, :lower16:_datahilo16alt+165 - Lpicbase
        movt    r0, :upper16:_datahilo16alt+165 - Lpicbase
+       movw    r0, :lower16:_thumbTarget - Lpicbase
+       movt    r0, :upper16:_thumbTarget - Lpicbase
        bx      lr
           
        .code 16
@@ -278,6 +286,12 @@ _thumb16tests:
        movt    r0, :upper16:_datahilo16alt+1792
        movw    r0, :lower16:_datahilo16alt+165
        movt    r0, :upper16:_datahilo16alt+165
+       movw    r0, :lower16:_thumbTarget
+       movt    r0, :upper16:_thumbTarget
+       movw    r0, :lower16:_externalTarget
+       movt    r0, :upper16:_externalTarget
+       movw    r0, :lower16:_externalTarget+61447
+       movt    r0, :upper16:_externalTarget+61447
 Lpicbase2:
        movw    r0, :lower16:_datahilo16 - Lpicbase2
        movt    r0, :upper16:_datahilo16 - Lpicbase2
@@ -293,12 +307,22 @@ Lpicbase2:
        movt    r0, :upper16:_datahilo16alt+1792 - Lpicbase2
        movw    r0, :lower16:_datahilo16alt+165 - Lpicbase2
        movt    r0, :upper16:_datahilo16alt+165 - Lpicbase2
+       movw    r0, :lower16:_thumbTarget - Lpicbase2
+       movt    r0, :upper16:_thumbTarget - Lpicbase2
        bx      lr
-          
+
+       .code 16
+       .thumb_func _thumbTarget
+_thumbTarget:
+        nop
+        bx  lr
+
        .data
 _datahilo16:   .long 0
 _datahilo16alt:        .long 0
 
+
+
 #endif
        
 #endif
@@ -727,6 +751,9 @@ _b:
        .long   _external+16
        .long   _test_weak
        .long   _test_weak+16
+       .long   Lother - . + 0x4000000
+Lother: 
+       .long    0
 #elif __ppc64__ || __x86_64__
        .quad   _test_calls
        .quad   _test_calls+16
@@ -734,6 +761,9 @@ _b:
        .quad   _external+16
        .quad   _test_weak
        .quad   _test_weak+16
+       .quad   Lother - . + 0x4000000
+Lother: 
+       .quad    0
 #endif
 
        # test that reloc sizes are the same
index 6924ac69d2f7b53de357e853ab7b1d1da1a9fc1f..68edc4100f2e1c6023318b933b359ed6875e6aa3 100644 (file)
@@ -1,3 +1,6 @@
 
-void foo() {}
+
+int x;
+
+int foo() { return x; }
 
index 531893310c37028b6a6e8008166aeda14ac8a2d3..d6c5b8233ff079a1c3c0e01827b878907455b6f4 100644 (file)
@@ -31,9 +31,9 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all: 
-       $(CXX) -gstabs+ main.c -o outfile
+       $(CC) -gstabs+ main.c -o outfile
        ${FAIL_IF_BAD_MACHO} outfile
-       nm -ap outfile | ${PASS_IFF} grep '.*\<SO\>.*test-cases.*/$$'
+       nm -ap outfile | grep '.*\<SO\>.*test-cases.*/$$' | ${PASS_IFF_STDIN}
 
 clean:
        rm outfile* 
index 54dc4c51531fc4ee19a211ba17d6be42cfffeeff..a46866d92e52c6cb1a8c4cd3147876271a1a6236 100644 (file)
@@ -1,3 +1,4 @@
-main()
+int main()
 {
+       return 0;
 }
index 670f01436fb975671da5c588590209794760a2a5..c88f66ba5a3de6bf1f58d3a5282d55c367eb0c38 100644 (file)
@@ -25,7 +25,7 @@ include ${TESTROOT}/include/common.makefile
 
 # Test the ld option -stack_addr and -stack_size used together
 
-ifeq ($(ARCH),armv6)
+ifeq ($(FILEARCH),arm)
        STACK_ADDR = 0x2C000000
        STACK_SIZE = 0x05000000
        STACK_TOP  = 0x27000000
@@ -51,7 +51,12 @@ all:
        otool -l main | grep -A6 __UNIXSTACK > main.otool
        grep " vmsize[ ]*${STACK_SIZE}" main.otool | ${FAIL_IF_EMPTY}
        grep " vmaddr[ ]*${STACK_TOP}" main.otool | ${FAIL_IF_EMPTY}
-       ${PASS_IFF_GOOD_MACHO} main
+       ${FAIL_IF_BAD_MACHO} main
+       ${CC} ${CCFLAGS} -static main.c -o main2 -e _main -nostdlib -Wl,-new_linker -Wl,-stack_size,${STACK_SIZE} -Wl,-stack_addr,${STACK_ADDR}
+       otool -l main2 | grep -A6 __UNIXSTACK > main2.otool
+       grep " vmsize[ ]*${STACK_SIZE}" main2.otool | ${FAIL_IF_EMPTY}
+       grep " vmaddr[ ]*${STACK_TOP}" main2.otool | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main2
 
 clean:
-       rm -rf main main.otool
+       rm -rf main main.otool main2.otool main2
index 6134c7ebe850ea22fcc4d628692381325b3fd086..cbb6d490d2caaded19deea7e7d36158c87bd9e7b 100644 (file)
@@ -25,10 +25,10 @@ include ${TESTROOT}/include/common.makefile
 
 # Test the ld option -stack_size adds a custom stack segment
 
-ifeq ($(ARCH),armv6)
+ifeq (${FILEARCH},arm)
        STACK_ADDR = 0x30000000
        STACK_SIZE = 0x05000000
-       STACK_TOP  = 0x2b000000
+       STACK_TOP  = 0x2a000000
 else
 ifeq (,${findstring 64,$(ARCH)})
        STACK_ADDR = 0xC0000000
index 2deed4223f58ee8882446cc993f8683a88caa902..09e802f6b8f22cb50ab428669a87fdbc0844e796 100644 (file)
@@ -29,5 +29,6 @@ extern void func(int);
 int main()
 {
        func(data);
+       return 0;
 }
 
index 847dc7864d8019aef0cc17703db742db7bb9eda0..72bc68b648dea3c08ace5a26fcee9efcc32760d9 100644 (file)
@@ -30,28 +30,25 @@ include ${TESTROOT}/include/common.makefile
 # <rdar://problem/5847206> SPEC2000/eon built with -mdynamic-no-pic won't run
 #
 
-run: test-run-${ARCH}
+all: test-${FILEARCH}
 
 
-test-run-ppc:
-       ${PASS_IFF} true
-
-test-run-x86_64:
-       ${PASS_IFF} true
-       
-test-run-armv6: test-run-i386
+test-ppc:  test-good
+test-x86_64: test-good
+test-i386: test
+test-arm: test
 
-test-run-i386:
+test:
        # check jump table in a weak function
-       ${CC} ${CCFLAGS} main.c switch.s -o main
+       ${CC} ${CCFLAGS} main.c switch.s -o main -Wl,-no_pie
        otool -rv main | grep _foo | ${FAIL_IF_STDIN}
        otool -rv main | grep _bar | ${FAIL_IF_STDIN}
        # check jump table in a regular function with -flat_namespace
-       ${CC} ${CCFLAGS} main.c switch.s -o main  -flat_namespace
+       ${CC} ${CCFLAGS} main.c switch.s -o main  -flat_namespace -Wl,-no_pie
        otool -rv main | grep _foo | ${FAIL_IF_STDIN}
        otool -rv main | grep _bar | ${FAIL_IF_STDIN}
        # check jump table in a regular function that is interposable
-       ${CC} ${CCFLAGS} main.c switch.s -o main  -Wl,-interposable_list,interpose.exp
+       ${CC} ${CCFLAGS} main.c switch.s -o main  -Wl,-interposable_list,interpose.exp -Wl,-no_pie
        otool -rv main | grep _foo | ${FAIL_IF_STDIN}
        otool -rv main | grep _bar | ${FAIL_IF_STDIN}
        # check jump table with -pie, should have no external and some local relocations
@@ -60,6 +57,8 @@ test-run-i386:
 #      otool -rv main | grep "Local relocation" | ${FAIL_IF_EMPTY}
        ${PASS_IFF_GOOD_MACHO} main
 
+test-good:
+       ${PASS_IFF} true
 
 clean:
        rm -f main
index 12b559f28995f7036e2dc1cf269ff573e8eec3eb..b2b024910c3ba29dabec69901c697651b83f30bd 100644 (file)
@@ -9,6 +9,7 @@
 */
        .globl _foo
        .weak_definition _foo
+       .align 4
 _foo:
        nop
        nop
@@ -29,6 +30,7 @@ L3: nop
        to a jump table
 */
        .text
+       .align 4
        .globl _bar
 _bar: nop
        nop
diff --git a/unit-tests/test-cases/tentative-and-archive-code/Makefile b/unit-tests/test-cases/tentative-and-archive-code/Makefile
new file mode 100644 (file)
index 0000000..7c2c28f
--- /dev/null
@@ -0,0 +1,64 @@
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+# Test how tentative definitions interact with archives
+# main.c has a tenative definition for _foo which 
+# should cause libfoo_data.a to be loaded, but not libfoo_tent.a
+# nor libfoo_code.a.
+#
+# <rdar://problem/7890410> Snow Leopard linker bug with common symbols
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} junk.c -c -o junk.o
+       # verify data symbol does get pulled in
+       ${CC} ${CCFLAGS} foo_data.c -c -o foo_data.o
+       libtool -static junk.o foo_data.o -o libfoo_data.a
+       ${CC} ${CCFLAGS} main.c libfoo_data.a -o main_data
+       nm -m main_data | grep _foo | grep __TEXT | ${FAIL_IF_STDIN}
+       # verify tentative does not
+       ${CC} ${CCFLAGS} foo_tent.c -c -o foo_tent.o
+       libtool -static junk.o foo_tent.o -o libfoo_tent.a
+       ${CC} ${CCFLAGS} main.c libfoo_tent.a -o main_tent
+       nm -m main_tent | grep _foo | grep __TEXT | ${FAIL_IF_STDIN}
+       # verify code does not
+       ${CC} ${CCFLAGS} foo_code.c -c -o foo_code.o
+       libtool -static junk.o foo_code.o -o libfoo_code.a
+       ${CC} ${CCFLAGS} main.c libfoo_code.a -o main_code
+       nm -m main_code | grep _foo | grep __TEXT | ${FAIL_IF_STDIN}
+       # verify warning when code force to override tent
+       ${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoo_code.a -o main_code_force 2>main_code_force_warnings.txt
+       grep warning main_code_force_warnings.txt | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main_code
+
+clean:
+       rm -rf junk.o foo_data.o libfoo_data.a main_data foo_tent.o libfoo_tent.a main_tent foo_code.o libfoo_code.a main_code main_code_force main_code_force_warnings.txt
+       
diff --git a/unit-tests/test-cases/tentative-and-archive-code/foo_code.c b/unit-tests/test-cases/tentative-and-archive-code/foo_code.c
new file mode 100644 (file)
index 0000000..277b5ae
--- /dev/null
@@ -0,0 +1,3 @@
+
+int foo() { return 10; }
+
diff --git a/unit-tests/test-cases/tentative-and-archive-code/foo_data.c b/unit-tests/test-cases/tentative-and-archive-code/foo_data.c
new file mode 100644 (file)
index 0000000..e7d3845
--- /dev/null
@@ -0,0 +1,2 @@
+
+int foo = 5;
diff --git a/unit-tests/test-cases/tentative-and-archive-code/foo_tent.c b/unit-tests/test-cases/tentative-and-archive-code/foo_tent.c
new file mode 100644 (file)
index 0000000..42e0a8e
--- /dev/null
@@ -0,0 +1,2 @@
+
+int foo;
diff --git a/unit-tests/test-cases/tentative-and-archive-code/junk.c b/unit-tests/test-cases/tentative-and-archive-code/junk.c
new file mode 100644 (file)
index 0000000..6ecfcf1
--- /dev/null
@@ -0,0 +1 @@
+void junk() {}
diff --git a/unit-tests/test-cases/tentative-and-archive-code/main.c b/unit-tests/test-cases/tentative-and-archive-code/main.c
new file mode 100644 (file)
index 0000000..08ed143
--- /dev/null
@@ -0,0 +1,8 @@
+
+int foo;
+
+int main()
+{
+       foo = 3;
+       return 0;
+}
diff --git a/unit-tests/test-cases/tlv-dead_strip/Makefile b/unit-tests/test-cases/tlv-dead_strip/Makefile
new file mode 100644 (file)
index 0000000..46e695c
--- /dev/null
@@ -0,0 +1,39 @@
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that main executable can use TLVs with -dead_strip
+#
+
+run: all
+
+all:
+       clang ${CCFLAGS} main.c -o main -dead_strip -mmacosx-version-min=10.7
+       otool -lv main | grep S_THREAD_LOCAL_VARIABLES | ${FAIL_IF_EMPTY}
+       otool -lv main | grep S_THREAD_LOCAL_REGULAR | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm  main
diff --git a/unit-tests/test-cases/tlv-dead_strip/main.c b/unit-tests/test-cases/tlv-dead_strip/main.c
new file mode 100644 (file)
index 0000000..a3e3fee
--- /dev/null
@@ -0,0 +1,33 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+__thread int gTLSThreadID = 0;
+
+int foobar() {
+  return gTLSThreadID;
+}
+
+int main(void) {
+  return foobar();
+}
index b20f368b8128fbcfabae4cf315de33f5d24434a6..0835fdb21633db0ae1b859632403847bd9d559c3 100644 (file)
@@ -40,10 +40,10 @@ all:
        ${CC} ${CCFLAGS} -dynamiclib -Wl,-reexport_library,liba.dylib -Wl,-reexport_library,libb.dylib -Wl,-reexport_library,libc.dylib -o libBig.dylib -install_name /usr/lib/libBig.dylib 
        # re-link against correct dylibs now that everything is built
        ${CC} ${CCFLAGS} -dynamiclib a.c -o liba.dylib libc.dylib -install_name /usr/local/lib/big/liba.dylib -umbrella Big
-       dyldinfo -lazy_bind liba.dylib | grep c2 | grep libc | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -lazy_bind liba.dylib | grep c2 | grep libc | ${FAIL_IF_EMPTY}
        ${CC} ${CCFLAGS} -dynamiclib b.c -o libb.dylib libc.dylib -install_name /usr/local/lib/big/libb.dylib -umbrella Big
        ${CC} ${CCFLAGS} -dynamiclib c.c -o libc.dylib liba.dylib -install_name /usr/local/lib/big/libc.dylib -umbrella Big
-       dyldinfo -lazy_bind libc.dylib | grep a2 | grep liba | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -lazy_bind libc.dylib | grep a2 | grep liba | ${FAIL_IF_EMPTY}
        ${CC} ${CCFLAGS} -dynamiclib -Wl,-reexport_library,liba.dylib -Wl,-reexport_library,libb.dylib -Wl,-reexport_library,libc.dylib -o libBig.dylib -install_name /usr/lib/libBig.dylib 
        ${CC} ${CCFLAGS} main.c -o main libBig.dylib -L.
        ${PASS_IFF_GOOD_MACHO} main
index 5fd7ec4d5e4e77db2ca9f6d4192c340b70c5cc17..c524ebf2c6fc449b7c5ee361c243c2bd39655b3b 100644 (file)
@@ -1,7 +1,8 @@
 
 
                        .text
-
+                       .align 4
+                       
                        .globl _my_weak
                        .weak_def_can_be_hidden _my_weak
 _my_weak:      nop
diff --git a/unit-tests/test-cases/weak-def-hidden-and-global/Makefile b/unit-tests/test-cases/weak-def-hidden-and-global/Makefile
new file mode 100644 (file)
index 0000000..b275b62
--- /dev/null
@@ -0,0 +1,46 @@
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+# <rdar://problem/9551362> clang ld: bad codegen, pointer diff
+# Test that codegen needing direct access to a weak symbol just issues
+# a warning.  Check that if export list makes weak symbol hidden, there is
+# no warning.
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} myglobal.c myhidden.s -dynamiclib -o libmy.dylib 2>warnings.txt
+       grep "global weak"  warnings.txt | ${FAIL_IF_EMPTY}
+       ${FAIL_IF_BAD_MACHO} libmy.dylib
+       ${CC} ${CCFLAGS} myglobal.c myhidden.s -dynamiclib -Wl,-exported_symbol,_test -o libmy2.dylib 
+       ${PASS_IFF_GOOD_MACHO} libmy2.dylib
+
+clean:
+       rm -f libmy.dylib  libmy2.dylib warnings.txt
diff --git a/unit-tests/test-cases/weak-def-hidden-and-global/myglobal.c b/unit-tests/test-cases/weak-def-hidden-and-global/myglobal.c
new file mode 100644 (file)
index 0000000..c671809
--- /dev/null
@@ -0,0 +1,4 @@
+
+__attribute__((weak))
+int myweak = 10;
+
diff --git a/unit-tests/test-cases/weak-def-hidden-and-global/myhidden.s b/unit-tests/test-cases/weak-def-hidden-and-global/myhidden.s
new file mode 100644 (file)
index 0000000..9b6a57e
--- /dev/null
@@ -0,0 +1,45 @@
+       .data
+       .globl  _myweak
+       .private_extern _myweak
+       .weak_definition _myweak
+_myweak:
+       .long    0
+       
+
+       .text
+       .align 2
+#if __ARM_ARCH_7A__
+       .code   16
+       .thumb_func     _test
+#endif
+
+       .globl  _test
+_test:
+#if __x86_64__
+       nop
+       movl    _myweak(%rip), %eax
+       ret
+#elif __i386__
+       call    L1
+L1:    popl    %eax
+       movl    _myweak-L1(%eax), %eax
+       ret
+#elif __arm__
+
+#if __ARM_ARCH_7A__
+       movw    r0, :lower16:(_myweak-(L4+4))
+       movt    r0, :upper16:(_myweak-(L4+4))
+L4:    add     r0, pc
+       ldr     r0, [r0]
+       bx      lr
+#else
+       ldr     r0, L2
+L3:    ldr     r0, [pc, r0]
+       bx      lr
+       .align  2
+L2:    .long   _myweak-(L3+8)
+#endif
+
+
+#endif
+
index 0a00a39030de05afe44fd1d3103816daec9d8348..6fd999e231192fa03b8a4836bf34e75372a4ca5f 100644 (file)
@@ -37,13 +37,33 @@ all:
        ${CC} ${CCFLAGS} -dynamiclib  bar.c -o libbar.dylib 
        ${FAIL_IF_BAD_MACHO} libbar.dylib
 
-       ${CC} ${CCFLAGS} -mmacosx-version-min=10.4 main.c -o main libfoo.dylib libbar.dylib
+       ${CC} ${CCFLAGS} ${VERSION_OLD_LINKEDIT} main.c -o main libfoo.dylib libbar.dylib
        # libfoo.dylib should be weakly loaded because all symbols are weakly imported
        otool -lv main | grep -B2 libfoo.dylib | grep LC_LOAD_WEAK_DYLIB | ${FAIL_IF_EMPTY}
-       # libbar.dylib should not be weakly loaded because _bar4 is not weakly imported
+       # libbar.dylib should not be weakly loaded because _bar1 is not weakly imported
        otool -lv main | grep -B2 libbar.dylib | grep LC_LOAD_DYLIB | ${FAIL_IF_EMPTY}
-       ${PASS_IFF_GOOD_MACHO} main
+       ${FAIL_IF_BAD_MACHO} main
+       
+       ${CC} ${CCFLAGS} ${VERSION_NEW_LINKEDIT} main.c -o main2 libfoo.dylib libbar.dylib
+       # libfoo.dylib should be weakly loaded because all symbols are weakly imported
+       otool -lv main2 | grep -B2 libfoo.dylib | grep LC_LOAD_WEAK_DYLIB | ${FAIL_IF_EMPTY}
+       # libbar.dylib should not be weakly loaded because _bar1 is not weakly imported
+       otool -lv main2 | grep -B2 libbar.dylib | grep LC_LOAD_DYLIB | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main2
+
+       ${CC} ${CCFLAGS} ${VERSION_NEW_LINKEDIT} data.c -o data libfoo.dylib libbar.dylib
+       # libfoo.dylib should be weakly loaded because all symbols are weakly imported
+       otool -lv data | grep -B2 libfoo.dylib | grep LC_LOAD_WEAK_DYLIB | ${FAIL_IF_EMPTY}
+       # libbar.dylib should not be weakly loaded because _bar1 is not weakly imported
+       otool -lv data | grep -B2 libbar.dylib | grep LC_LOAD_DYLIB | ${FAIL_IF_EMPTY}
+       ${FAIL_IF_BAD_MACHO} data
 
+       ${CC} ${CCFLAGS} ${VERSION_NEW_LINKEDIT} data.c -o data2 libfoo.dylib libbar.dylib
+       # libfoo.dylib should be weakly loaded because all symbols are weakly imported
+       otool -lv data2 | grep -B2 libfoo.dylib | grep LC_LOAD_WEAK_DYLIB | ${FAIL_IF_EMPTY}
+       # libbar.dylib should not be weakly loaded because _bar1 is not weakly imported
+       otool -lv data2 | grep -B2 libbar.dylib | grep LC_LOAD_DYLIB | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} data2
                
 clean:
-       rm -rf libfoo.dylib libbar.dylib main
+       rm -rf libfoo.dylib libbar.dylib main main2 data data2
diff --git a/unit-tests/test-cases/weak_dylib/data.c b/unit-tests/test-cases/weak_dylib/data.c
new file mode 100644 (file)
index 0000000..98cd752
--- /dev/null
@@ -0,0 +1,15 @@
+
+#include "foo.h"
+#include "bar.h"
+
+void* pfoo4 = &foo4;
+void* pfoo2 = &foo2;
+
+void* pbar2 = &bar2;
+void* pbar1 = &bar1;   // not weak
+
+int main (void)
+{
+   return 0;
+}
+
diff --git a/unit-tests/test-cases/weak_import-addend/Makefile b/unit-tests/test-cases/weak_import-addend/Makefile
new file mode 100644 (file)
index 0000000..898424b
--- /dev/null
@@ -0,0 +1,52 @@
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test the weak_import attribute works
+#
+
+all: all-${ARCH}
+
+all-ppc: all-true
+
+all-ppc64: all-true
+
+all-i386: all-true
+
+all-armv6: all-true
+
+all-armv7: all-true
+
+all-true:
+       ${PASS_IFF} true
+
+all-x86_64:    
+       ${CC} ${CCFLAGS} -dynamiclib test.s -o libtest.dylib -mmacosx-version-min=10.6
+       ${DYLDINFO} -bind -lazy_bind libtest.dylib | grep _malloc | grep weak | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -bind -lazy_bind libtest.dylib | grep _free | grep weak | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} libtest.dylib
+       
+clean:
+       rm -rf libtest.dylib
diff --git a/unit-tests/test-cases/weak_import-addend/test.s b/unit-tests/test-cases/weak_import-addend/test.s
new file mode 100644 (file)
index 0000000..fb39453
--- /dev/null
@@ -0,0 +1,12 @@
+
+
+       .text
+_foo:
+#if __x86_64__
+       .weak_reference _malloc
+       .weak_reference _free
+       cmpq $0, _malloc@GOTPCREL(%rip)
+       cmpq $0xFFFF, _free@GOTPCREL(%rip)
+#endif
+       nop
+       
index 4d21410b151c6fd175851a459f0cf6a29b479a43..bc94bd00d4efe07eac4b1bd0e33a04a5f5c940fd 100644 (file)
@@ -33,7 +33,7 @@ run: all
 all:   
        ${CC} ${CCFLAGS} main.c foo.c -o main
        ${FAIL_IF_BAD_MACHO} main
-       ${CC} ${CCFLAGS} main.c foo.c -o main -mmacosx-version-min=10.4
+       ${CC} ${CCFLAGS} main.c foo.c -o main ${VERSION_OLD_LINKEDIT}
        ${PASS_IFF_GOOD_MACHO} main
        
 clean:
index 98a277991b16b6d8520942771b15e12aa06b2a09..2c8806d89b8ca0a9d3cb95ace4b5e2a470a433be 100644 (file)
@@ -31,13 +31,16 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all:   
-       ${CC} ${CCFLAGS} -c foo.c -o foo-${ARCH}.o
-       ${FAIL_IF_BAD_OBJ} foo-${ARCH}.o
+       ${CC} ${CCFLAGS} -c foo.c -o foo.o
+       ${FAIL_IF_BAD_OBJ} foo.o
 
-       ${CC} ${CCFLAGS} -c foo1.c -o foo1-${ARCH}.o
-       ${FAIL_IF_BAD_OBJ} foo1-${ARCH}.o
+       ${CC} ${CCFLAGS} -c foo1.c -o foo1.o
+       ${FAIL_IF_BAD_OBJ} foo1.o
 
-       ${PASS_IFF_ERROR} ${CC} ${CCFLAGS} -dynamiclib foo-${ARCH}.o foo1-${ARCH}.o -o libfoo-${ARCH}.dylib 2>/dev/null
+       ${PASS_IFF_ERROR} ${CC} ${CCFLAGS} -dynamiclib foo.o foo1.o -o libfoo.dylib 
 
 clean:
-       rm -rf *.o *.dylib main-*
+       rm -rf foo.o foo1.o libfoo.dylib
+
+
+#2>/dev/null
\ No newline at end of file
index 62660197b399c3d96cb18560f08b9a8fc2fb21a1..d16b9d03f185c5e5a521f6e796d77b1f7cdd0194 100644 (file)
@@ -28,22 +28,20 @@ include ${TESTROOT}/include/common.makefile
 # can link a program with a large zero-fill section
 #
 
-run:   test-run-${ARCH}
+all:   test-${FILEARCH}
 
 # i386 catches the problem in the assembler phase
-test-run-i386:
+test-i386:
        ${PASS_IFF} true
 
-test-run-ppc test-run-ppc64: test-${ARCH}
-
-test-run-x86_64 test-ppc64:
+test-x86_64:
        ${CC} ${CCFLAGS} -DSHRINK=1 test.c --save-temps -o test-${ARCH}
        ${PASS_IFF_GOOD_MACHO} test-${ARCH}
 
 test-ppc:
        ${PASS_IFF_ERROR} ${CC} ${CCFLAGS} -DSHRINK=4 test.c --save-temps -o test-${ARCH} 2>/dev/null
 
-test-run-armv6:
+test-arm:
        ${PASS_IFF_ERROR} ${CC} ${CCFLAGS} -DSHRINK=4 test.c --save-temps -o test-${ARCH} 2>/dev/null
 
 clean: