From 4f3e367c520f1fd8affdc77dd9e2b6bc6c3c693b Mon Sep 17 00:00:00 2001 From: Apple Date: Fri, 12 Dec 2008 01:16:55 +0000 Subject: [PATCH] ld64-85.2.1.tar.gz --- ChangeLog | 52 +- FireOpal/APPLE_LICENSE | 367 + FireOpal/ChangeLog | 542 ++ FireOpal/doc/man/man1/ld.1 | 676 ++ FireOpal/doc/man/man1/ld64.1 | 1 + FireOpal/doc/man/man1/rebase.1 | 39 + FireOpal/ld64.xcodeproj/project.pbxproj | 788 ++ FireOpal/src/Architectures.hpp | 88 + FireOpal/src/ArchiveReader.hpp | 454 + FireOpal/src/ExecutableFile.h | 70 + FireOpal/src/FileAbstraction.hpp | 145 + FireOpal/src/LTOReader.hpp | 684 ++ FireOpal/src/MachOFileAbstraction.hpp | 925 ++ FireOpal/src/MachOReaderDylib.hpp | 926 ++ FireOpal/src/MachOReaderRelocatable.hpp | 4583 +++++++++ FireOpal/src/MachOWriterExecutable.hpp | 8579 +++++++++++++++++ FireOpal/src/ObjectDump.cpp | 497 + FireOpal/src/ObjectFile.h | 349 + FireOpal/src/OpaqueSection.hpp | 199 + FireOpal/src/Options.cpp | 3150 ++++++ FireOpal/src/Options.h | 368 + FireOpal/src/SectCreate.h | 43 + FireOpal/src/debugline.c | 546 ++ FireOpal/src/debugline.h | 109 + FireOpal/src/dwarf2.h | 85 + FireOpal/src/ld.cpp | 3778 ++++++++ FireOpal/src/machochecker.cpp | 965 ++ FireOpal/src/rebase.cpp | 945 ++ FireOpal/unit-tests/README | 28 + FireOpal/unit-tests/bin/exit-non-zero-pass.pl | 27 + .../unit-tests/bin/fail-if-exit-non-zero.pl | 16 + FireOpal/unit-tests/bin/fail-if-exit-zero.pl | 22 + FireOpal/unit-tests/bin/fail-if-no-stdin.pl | 22 + FireOpal/unit-tests/bin/fail-if-stdin.pl | 22 + FireOpal/unit-tests/bin/fail-iff-exit-zero.pl | 29 + .../unit-tests/bin/make-recursive-newtest.pl | 127 + FireOpal/unit-tests/bin/make-recursive.pl | 123 + FireOpal/unit-tests/bin/mkld | 73 + .../unit-tests/bin/pass-iff-exit-non-zero.pl | 29 + FireOpal/unit-tests/bin/pass-iff-exit-zero.pl | 23 + FireOpal/unit-tests/bin/pass-iff-no-stdin.pl | 23 + FireOpal/unit-tests/bin/pass-iff-stdin.pl | 24 + FireOpal/unit-tests/bin/result-filter.pl | 131 + FireOpal/unit-tests/bin/rm-stale-test-logs | 36 + FireOpal/unit-tests/clean-tests | 63 + FireOpal/unit-tests/include/common.makefile | 76 + FireOpal/unit-tests/include/test.h | 35 + FireOpal/unit-tests/proctor-run | 204 + FireOpal/unit-tests/run-all-unit-tests | 35 + FireOpal/unit-tests/run-all-unit-tests-debug | 26 + FireOpal/unit-tests/src/Makefile | 9 + FireOpal/unit-tests/src/results-to-xml.cpp | 260 + FireOpal/unit-tests/src/xmlparser/xmlparser.1 | 79 + FireOpal/unit-tests/src/xmlparser/xmlparser.m | 25 + .../xmlparser.xcodeproj/project.pbxproj | 218 + .../src/xmlparser/xmlparser_Prefix.pch | 7 + .../test-cases/16-byte-alignment/Makefile | 44 + .../test-cases/16-byte-alignment/comment.txt | 1 + .../test-cases/16-byte-alignment/tl_test2.c | 43 + .../test-cases/absolute-symbol/Makefile | 40 + .../test-cases/absolute-symbol/abs.s | 3 + .../test-cases/absolute-symbol/main.c | 5 + .../test-cases/alias-command-line/Makefile | 53 + .../test-cases/alias-command-line/aliases.s | 45 + .../test-cases/alias-command-line/aliases.txt | 6 + .../test-cases/alias-objects/Makefile | 44 + .../test-cases/alias-objects/aliases.s | 43 + .../test-cases/align-modulus/Makefile | 40 + .../test-cases/align-modulus/align.s | 36 + .../test-cases/align-modulus/comment.txt | 2 + .../unit-tests/test-cases/align-modulus/foo.c | 32 + .../test-cases/align-modulus/foo.exp | 1 + .../test-cases/allow-stack-execute/Makefile | 46 + .../allow-stack-execute/comment.txt | 1 + .../test-cases/allow-stack-execute/foo.c | 4 + .../test-cases/allowable-client/Makefile | 110 + .../test-cases/allowable-client/bar.c | 6 + .../test-cases/allowable-client/baz.c | 6 + .../test-cases/allowable-client/comment.txt | 1 + .../test-cases/allowable-client/foo.c | 4 + .../test-cases/allowable-client/main.c | 6 + .../test-cases/archive-ObjC/Makefile | 49 + .../unit-tests/test-cases/archive-ObjC/bar.c | 2 + .../unit-tests/test-cases/archive-ObjC/baz.m | 8 + .../unit-tests/test-cases/archive-ObjC/foo.m | 8 + .../unit-tests/test-cases/archive-ObjC/main.c | 31 + .../test-cases/archive-basic/Makefile | 46 + .../unit-tests/test-cases/archive-basic/bar.c | 1 + .../test-cases/archive-basic/comment.txt | 1 + .../unit-tests/test-cases/archive-basic/foo.c | 1 + .../test-cases/archive-basic/main.c | 32 + .../test-cases/archive-duplicate/Makefile | 45 + .../test-cases/archive-duplicate/bar.c | 1 + .../test-cases/archive-duplicate/foo.c | 1 + .../test-cases/archive-duplicate/main.c | 32 + .../test-cases/archive-weak/Makefile | 51 + .../unit-tests/test-cases/archive-weak/bar.c | 1 + .../unit-tests/test-cases/archive-weak/baz.c | 11 + .../test-cases/archive-weak/comment.txt | 7 + .../unit-tests/test-cases/archive-weak/foo.c | 13 + .../unit-tests/test-cases/archive-weak/main.c | 42 + .../unit-tests/test-cases/auto-arch/Makefile | 40 + .../unit-tests/test-cases/auto-arch/hello.c | 29 + .../test-cases/blank-stubs/Makefile | 61 + .../test-cases/blank-stubs/comment.txt | 1 + .../unit-tests/test-cases/blank-stubs/foo.c | 4 + .../unit-tests/test-cases/blank-stubs/main.c | 5 + .../test-cases/branch-islands/Makefile | 47 + .../test-cases/branch-islands/extra.c | 8 + .../test-cases/branch-islands/hello.c | 10 + .../test-cases/branch-islands/space.s | 39 + .../test-cases/bundle_loader/Makefile | 55 + .../unit-tests/test-cases/bundle_loader/bar.c | 31 + .../test-cases/bundle_loader/bundle.c | 31 + .../test-cases/bundle_loader/main.c | 30 + .../test-cases/cfstring-coalesce/Makefile | 52 + .../test-cases/cfstring-coalesce/bar.c | 7 + .../test-cases/cfstring-coalesce/foo.c | 19 + .../test-cases/cfstring-utf16/Makefile | 50 + .../test-cases/cfstring-utf16/bar.m | 7 + .../test-cases/cfstring-utf16/foo.m | 20 + .../test-cases/commons-alignment/Makefile | 37 + .../test-cases/commons-alignment/foo.s | 2 + .../commons-coalesced-dead_strip/Makefile | 42 + .../commons-coalesced-dead_strip/a.c | 4 + .../commons-coalesced-dead_strip/b.c | 4 + .../commons-coalesced-dead_strip/c.c | 3 + .../commons-coalesced-dead_strip/c.h | 4 + .../test-cases/commons-mixed/Makefile | 46 + .../unit-tests/test-cases/commons-mixed/bar.c | 2 + .../unit-tests/test-cases/commons-mixed/foo.c | 2 + .../test-cases/commons-order/Makefile | 40 + .../unit-tests/test-cases/commons-order/bar.c | 3 + .../unit-tests/test-cases/commons-order/baz.c | 3 + .../test-cases/commons-order/expected.order | 8 + .../unit-tests/test-cases/commons-order/foo.c | 3 + .../test-cases/commons-order/main.c | 4 + .../cpu-sub-types-preference/Makefile | 96 + .../test-cases/cpu-sub-types-preference/foo.c | 25 + .../test-cases/cpu-sub-types/Makefile | 157 + .../test-cases/cpu-sub-types/comment.txt | 2 + .../unit-tests/test-cases/cpu-sub-types/foo.c | 3 + .../test-cases/cpu-sub-types/main.c | 10 + .../dead_strip-archive-global/Makefile | 43 + .../dead_strip-archive-global/foo.c | 12 + .../dead_strip-archive-global/main.c | 33 + .../test-cases/dead_strip-archive/Makefile | 43 + .../test-cases/dead_strip-archive/comment.txt | 1 + .../test-cases/dead_strip-archive/foo.c | 7 + .../test-cases/dead_strip-archive/main.c | 37 + .../dead_strip-init-archive/Makefile | 40 + .../test-cases/dead_strip-init-archive/bar.c | 4 + .../test-cases/dead_strip-init-archive/foo.c | 6 + .../unit-tests/test-cases/dead_strip/Makefile | 49 + .../test-cases/dead_strip/comment.txt | 5 + .../test-cases/dead_strip/deadwood.c | 11 + .../unit-tests/test-cases/dead_strip/main.c | 32 + .../unit-tests/test-cases/dead_strip/main.exp | 1 + .../test-cases/dead_strip_dylibs/Makefile | 52 + .../test-cases/dead_strip_dylibs/bar.c | 5 + .../test-cases/dead_strip_dylibs/baz.c | 5 + .../test-cases/dead_strip_dylibs/foo.c | 4 + .../test-cases/dead_strip_dylibs/main.c | 10 + .../dead_strip_section_attribute/Makefile | 40 + .../dead_strip_section_attribute/comment.txt | 2 + .../dead_strip_section_attribute/main.c | 42 + .../dtrace-static-probes-coalescing/Makefile | 59 + .../dtrace-static-probes-coalescing/Number.d | 3 + .../dtrace-static-probes-coalescing/a.cxx | 8 + .../dtrace-static-probes-coalescing/header.h | 11 + .../dtrace-static-probes-coalescing/x.cxx | 6 + .../test-cases/dtrace-static-probes/Makefile | 60 + .../test-cases/dtrace-static-probes/bar.d | 7 + .../dtrace-static-probes/comment.txt | 1 + .../test-cases/dtrace-static-probes/foo.d | 8 + .../test-cases/dtrace-static-probes/main.c | 29 + .../dwarf-archive-all_load/Makefile | 45 + .../test-cases/dwarf-archive-all_load/bar.c | 2 + .../test-cases/dwarf-archive-all_load/baz.c | 1 + .../dwarf-archive-all_load/comment.txt | 2 + .../dwarf-archive-all_load/expected-stabs | 24 + .../test-cases/dwarf-archive-all_load/foo.c | 1 + .../dwarf-archive-all_load/stabs-filter.pl | 25 + .../test-cases/dwarf-debug-notes-r/Makefile | 59 + .../test-cases/dwarf-debug-notes-r/bar.cxx | 4 + .../dwarf-debug-notes-r/comment.txt | 5 + .../dwarf-debug-notes-r/expected-stabs | 24 + .../test-cases/dwarf-debug-notes-r/foo.cxx | 4 + .../test-cases/dwarf-debug-notes-r/main.cxx | 4 + .../dwarf-debug-notes-r/stabs-filter.pl | 25 + .../test-cases/dwarf-debug-notes/Makefile | 50 + .../test-cases/dwarf-debug-notes/comment.txt | 4 + .../dwarf-debug-notes/expected-stabs | 33 + .../test-cases/dwarf-debug-notes/header.h | 8 + .../test-cases/dwarf-debug-notes/hello.cxx | 33 + .../test-cases/dwarf-debug-notes/other.cxx | 27 + .../dwarf-debug-notes/stabs-filter.pl | 25 + .../test-cases/dwarf-ignore/Makefile | 39 + .../test-cases/dwarf-ignore/comment.txt | 1 + .../test-cases/dwarf-ignore/hello.c | 29 + .../test-cases/dwarf-strip/Makefile | 40 + .../test-cases/dwarf-strip/comment.txt | 1 + .../unit-tests/test-cases/dwarf-strip/hello.c | 29 + .../test-cases/dylib-aliases/Makefile | 47 + .../unit-tests/test-cases/dylib-aliases/bar.c | 1 + .../unit-tests/test-cases/dylib-aliases/foo.c | 1 + .../test-cases/dylib-aliases/main.c | 8 + .../test-cases/dylib-re-export-cycle/Makefile | 52 + .../test-cases/dylib-re-export-cycle/bar.c | 1 + .../test-cases/dylib-re-export-cycle/foo.c | 1 + .../test-cases/dylib-re-export-cycle/main.c | 6 + .../test-cases/dylib_file-missing/Makefile | 42 + .../test-cases/dylib_file-missing/bar.c | 13 + .../test-cases/dylib_file-missing/foo.c | 7 + .../test-cases/dylib_file-missing/main.c | 15 + .../unit-tests/test-cases/dylib_file/Makefile | 46 + .../unit-tests/test-cases/dylib_file/bar.c | 13 + .../test-cases/dylib_file/comment.txt | 1 + .../unit-tests/test-cases/dylib_file/foo.c | 7 + .../unit-tests/test-cases/dylib_file/main.c | 15 + .../unit-tests/test-cases/dylib_init/Makefile | 36 + .../unit-tests/test-cases/dylib_init/foo.c | 2 + .../test-cases/eh-coalescing-r/Makefile | 47 + .../test-cases/eh-coalescing-r/bar.cxx | 32 + .../test-cases/eh-coalescing-r/foo.cxx | 32 + .../test-cases/eh-coalescing-r/func.h | 35 + .../test-cases/eh-coalescing/Makefile | 50 + .../test-cases/eh-coalescing/bar.cxx | 31 + .../test-cases/eh-coalescing/foo.cxx | 33 + .../test-cases/eh-coalescing/foo2.cxx | 31 + .../test-cases/eh-coalescing/func.h | 43 + .../test-cases/eh-strip-test/Makefile | 34 + .../test-cases/eh-strip-test/comment.txt | 21 + .../test-cases/eh-strip-test/main.cxx | 6 + .../unit-tests/test-cases/eh_frame/Makefile | 47 + .../unit-tests/test-cases/eh_frame/bar.cxx | 38 + .../unit-tests/test-cases/eh_frame/foo.cxx | 38 + .../test-cases/empty-object/Makefile | 40 + .../unit-tests/test-cases/empty-object/main.c | 1 + .../unit-tests/test-cases/end-label/Makefile | 41 + .../unit-tests/test-cases/end-label/bar.s | 7 + .../unit-tests/test-cases/end-label/foo.s | 11 + .../Makefile | 39 + .../foo.c | 34 + .../exported-symbols-wildcards/Makefile | 78 + .../exported-symbols-wildcards/expect1 | 2 + .../exported-symbols-wildcards/expect2 | 3 + .../exported-symbols-wildcards/expect3 | 4 + .../exported-symbols-wildcards/expect4 | 6 + .../exported-symbols-wildcards/expect5 | 3 + .../exported-symbols-wildcards/expect6 | 4 + .../exported-symbols-wildcards/expect7 | 2 + .../exported-symbols-wildcards/expect8 | 3 + .../exported-symbols-wildcards/foo.c | 55 + .../exported-symbols-wildcards/list5 | 2 + .../exported_symbols_list-eol/Makefile | 41 + .../exported_symbols_list-eol/expected.nm | 2 + .../exported_symbols_list-eol/test.c | 18 + .../exported_symbols_list-eol/test.exp | 1 + .../exported_symbols_list-hidden/Makefile | 41 + .../exported_symbols_list-hidden/test.c | 18 + .../exported_symbols_list-hidden/test.exp | 4 + .../exported_symbols_list-r/Makefile | 55 + .../exported_symbols_list-r/test-bad.exp | 3 + .../test-cases/exported_symbols_list-r/test.c | 18 + .../exported_symbols_list-r/test.exp | 2 + .../external-reloc-sorting/Makefile | 40 + .../test-cases/external-reloc-sorting/foo.c | 5 + .../test-cases/external-reloc-sorting/main.c | 39 + .../unit-tests/test-cases/filelist/Makefile | 47 + .../test-cases/filelist/comment.txt | 1 + .../unit-tests/test-cases/filelist/hello.c | 29 + .../unit-tests/test-cases/flat-dylib/Makefile | 40 + .../unit-tests/test-cases/flat-dylib/main.c | 33 + .../flat-indirect-undefines/Makefile | 49 + .../test-cases/flat-indirect-undefines/bar.c | 4 + .../test-cases/flat-indirect-undefines/foo.c | 8 + .../test-cases/flat-indirect-undefines/main.c | 10 + .../unit-tests/test-cases/flat-main/Makefile | 40 + .../unit-tests/test-cases/flat-main/main.c | 33 + .../test-cases/got-elimination/Makefile | 50 + .../test-cases/got-elimination/bar.c | 28 + .../test-cases/got-elimination/foo.c | 42 + .../unit-tests/test-cases/header-pad/Makefile | 38 + .../test-cases/header-pad/comment.txt | 1 + .../unit-tests/test-cases/header-pad/hello.c | 29 + .../test-cases/hello-world/Makefile | 38 + .../test-cases/hello-world/comment.txt | 1 + .../unit-tests/test-cases/hello-world/hello.c | 29 + .../implicit-common2/Makefile.newtest | 47 + .../test-cases/implicit-common2/a.c | 7 + .../test-cases/implicit-common2/comment.txt | 1 + .../test-cases/implicit-common2/test.c | 26 + .../test-cases/implicit-common3/Makefile | 44 + .../test-cases/implicit-common3/a.c | 8 + .../test-cases/implicit-common3/comment.txt | 1 + .../test-cases/implicit-common3/test.c | 37 + .../implicit-common4/Makefile.newtest | 45 + .../test-cases/implicit-common4/a.c | 7 + .../test-cases/implicit-common4/comment.txt | 1 + .../test-cases/implicit-common4/test.c | 26 + .../implicit-common5/Makefile.newtest | 41 + .../test-cases/implicit-common5/a.c | 7 + .../test-cases/implicit-common5/comment.txt | 1 + .../test-cases/implicit-common5/test.c | 25 + .../test-cases/implicit_dylib/Makefile | 48 + .../test-cases/implicit_dylib/bar.c | 7 + .../test-cases/implicit_dylib/foo.c | 5 + .../test-cases/implicit_dylib/main.c | 11 + .../test-cases/indirect-dylib/Makefile | 46 + .../test-cases/indirect-dylib/bar.c | 31 + .../test-cases/indirect-dylib/comment.txt | 4 + .../test-cases/indirect-dylib/foo.c | 31 + .../test-cases/indirect-dylib/main.c | 33 + .../test-cases/indirect-path-search/Makefile | 106 + .../test-cases/indirect-path-search/bar.c | 5 + .../test-cases/indirect-path-search/baz.c | 5 + .../test-cases/indirect-path-search/foo.c | 4 + .../test-cases/indirect-path-search/main.c | 8 + .../test-cases/interposable_list/Makefile | 47 + .../test-cases/interposable_list/test.c | 57 + .../test-cases/interposable_list/test.exp | 2 + .../unit-tests/test-cases/large-data/Makefile | 50 + .../unit-tests/test-cases/large-data/test1.c | 42 + .../unit-tests/test-cases/large-data/test2.c | 37 + .../unit-tests/test-cases/large-data/test3.c | 37 + .../unit-tests/test-cases/large-data/test4.c | 37 + .../test-cases/late-link-error/Makefile | 41 + .../test-cases/late-link-error/comment.txt | 2 + .../test-cases/late-link-error/link_error.s | 22 + .../test-cases/lazy-dylib-objc/Makefile | 45 + .../test-cases/lazy-dylib-objc/foo.h | 9 + .../test-cases/lazy-dylib-objc/foo.m | 8 + .../test-cases/lazy-dylib-objc/main.m | 12 + .../unit-tests/test-cases/lazy-dylib/Makefile | 46 + .../unit-tests/test-cases/lazy-dylib/bad.c | 12 + .../unit-tests/test-cases/lazy-dylib/bad2.c | 13 + .../unit-tests/test-cases/lazy-dylib/foo.c | 5 + .../unit-tests/test-cases/lazy-dylib/main.c | 18 + .../literals-coalesce-alignment/Makefile | 46 + .../cstring-align-0.s | 26 + .../cstring-align-3.s | 26 + .../literals-coalesce-alignment2/Makefile | 47 + .../literals-coalesce-alignment2/comment.txt | 1 + .../cstring-align-0.s | 27 + .../cstring-align-3.s | 28 + .../literals-coalesce-alignment3/Makefile | 48 + .../literals-coalesce-alignment3/comment.txt | 1 + .../cstring-align-0.s | 27 + .../cstring-align-3.s | 28 + .../test-cases/literals-coalesce/Makefile | 40 + .../test-cases/literals-coalesce/literals.s | 69 + .../literals-coalesce2/Makefile.newtest | 40 + .../test-cases/literals-coalesce2/comment.txt | 1 + .../test-cases/literals-coalesce2/literals.s | 48 + .../test-cases/literals-coalesce2/test.sh | 5 + .../test-cases/llvm-integration/Makefile | 289 + .../test-cases/llvm-integration/a.c | 5 + .../test-cases/llvm-integration/a1.c | 10 + .../test-cases/llvm-integration/a10.c | 5 + .../test-cases/llvm-integration/a11.c | 6 + .../test-cases/llvm-integration/a12.c | 8 + .../test-cases/llvm-integration/a12.h | 8 + .../test-cases/llvm-integration/a13.cc | 3 + .../test-cases/llvm-integration/a13.h | 7 + .../test-cases/llvm-integration/a14.c | 1 + .../test-cases/llvm-integration/a15.c | 3 + .../test-cases/llvm-integration/a17.c | 4 + .../test-cases/llvm-integration/a18.c | 18 + .../test-cases/llvm-integration/a2.c | 6 + .../test-cases/llvm-integration/a20.c | 2 + .../test-cases/llvm-integration/a3.c | 6 + .../test-cases/llvm-integration/a4.c | 6 + .../test-cases/llvm-integration/a5.c | 10 + .../test-cases/llvm-integration/a6.c | 10 + .../test-cases/llvm-integration/a7.c | 11 + .../test-cases/llvm-integration/a8.c | 23 + .../test-cases/llvm-integration/a9.c | 25 + .../test-cases/llvm-integration/a9.list | 3 + .../test-cases/llvm-integration/b.c | 3 + .../test-cases/llvm-integration/b1.c | 4 + .../test-cases/llvm-integration/b10.c | 7 + .../test-cases/llvm-integration/b10.h | 6 + .../test-cases/llvm-integration/b14.c | 7 + .../test-cases/llvm-integration/b15.c | 8 + .../test-cases/llvm-integration/b17.c | 4 + .../test-cases/llvm-integration/b2.c | 9 + .../test-cases/llvm-integration/b20.c | 1 + .../test-cases/llvm-integration/b3.c | 4 + .../test-cases/llvm-integration/b4.c | 13 + .../test-cases/llvm-integration/b5.c | 4 + .../test-cases/llvm-integration/b7.c | 7 + .../test-cases/llvm-integration/c15.c | 9 + .../test-cases/llvm-integration/main.c | 9 + .../test-cases/llvm-integration/main1.c | 13 + .../test-cases/llvm-integration/main10.c | 10 + .../test-cases/llvm-integration/main11.c | 7 + .../test-cases/llvm-integration/main12.c | 7 + .../test-cases/llvm-integration/main13.cc | 8 + .../test-cases/llvm-integration/main16.c | 8 + .../test-cases/llvm-integration/main19.c | 8 + .../test-cases/llvm-integration/main2.c | 9 + .../test-cases/llvm-integration/main20.c | 7 + .../test-cases/llvm-integration/main3.c | 13 + .../test-cases/llvm-integration/main4.c | 9 + .../test-cases/llvm-integration/main5.c | 16 + .../test-cases/llvm-integration/main6.c | 10 + .../test-cases/llvm-integration/main7.c | 10 + .../test-cases/llvm-integration/main8.c | 11 + .../test-cases/llvm-integration/main9.c | 14 + .../test-cases/loader_path/Makefile | 46 + .../unit-tests/test-cases/loader_path/bar.c | 6 + .../unit-tests/test-cases/loader_path/foo.c | 7 + .../unit-tests/test-cases/loader_path/main.c | 8 + .../local-symbol-partial-stripping/Makefile | 75 + .../local-symbol-partial-stripping/a.expect | 2 + .../local-symbol-partial-stripping/a.list | 2 + .../local-symbol-partial-stripping/b.expect | 3 + .../local-symbol-partial-stripping/b.list | 2 + .../local-symbol-partial-stripping/c.list | 1 + .../local-symbol-partial-stripping/foo.c | 11 + .../local-symbol-partial-stripping/main.c | 11 + .../test-cases/lto-llvm-options/Makefile | 45 + .../test-cases/lto-llvm-options/main.c | 15 + .../lto-weak-native-override/Makefile | 45 + .../test-cases/lto-weak-native-override/foo.c | 6 + .../lto-weak-native-override/main.c | 17 + .../test-cases/main-stripped/Makefile | 38 + .../test-cases/main-stripped/main.c | 34 + .../test-cases/main-stripped/main.exp | 1 + .../test-cases/missing-option-args/Makefile | 98 + .../missing-option-args/comment.txt | 1 + .../test-cases/multiple-entry-points/Makefile | 46 + .../multiple-entry-points/comment.txt | 3 + .../test-cases/multiple-entry-points/test.s | 54 + .../no-dynamic-common/Makefile.newtest | 39 + .../test-cases/no-dynamic-common/a.c | 7 + .../test-cases/no-dynamic-common/comment.txt | 1 + .../test-cases/no-dynamic-common/test.c | 25 + .../unit-tests/test-cases/no-uuid/Makefile | 63 + FireOpal/unit-tests/test-cases/no-uuid/bar.c | 4 + .../unit-tests/test-cases/no-uuid/comment.txt | 1 + FireOpal/unit-tests/test-cases/no-uuid/foo.c | 4 + .../unit-tests/test-cases/non-lazy-r/Makefile | 61 + .../unit-tests/test-cases/non-lazy-r/foo.c | 12 + .../unit-tests/test-cases/non-lazy-r/other.c | 2 + .../objc-category-debug-notes/Makefile | 40 + .../objc-category-debug-notes/test.m | 44 + .../objc-exported_symbols_list/Makefile | 40 + .../objc-exported_symbols_list/foo.exp | 1 + .../objc-exported_symbols_list/foo.m | 18 + .../test-cases/objc-gc-checks/Makefile | 84 + .../test-cases/objc-gc-checks/bar.m | 11 + .../test-cases/objc-gc-checks/comment.txt | 1 + .../test-cases/objc-gc-checks/foo.m | 12 + .../test-cases/objc-gc-checks/runtime.c | 2 + .../test-cases/objc-literal-pointers/Makefile | 47 + .../test-cases/objc-literal-pointers/test.m | 33 + .../test-cases/objc-references/Makefile | 47 + .../test-cases/objc-references/comment.txt | 1 + .../test-cases/objc-references/test.m | 52 + .../objc-selector-coalescing/Makefile | 39 + .../objc-selector-coalescing/main.m | 7 + .../objc-selector-coalescing/other.m | 10 + .../test-cases/operator-new/Makefile | 40 + .../test-cases/operator-new/main.cxx | 47 + .../test-cases/order_file-ans/Makefile | 40 + .../test-cases/order_file-ans/main.cxx | 62 + .../test-cases/order_file-ans/main.expected | 4 + .../test-cases/order_file-ans/main.order | 4 + .../unit-tests/test-cases/order_file/Makefile | 57 + .../unit-tests/test-cases/order_file/extra.s | 24 + .../unit-tests/test-cases/order_file/main.c | 33 + .../test-cases/order_file/main1.expected | 4 + .../test-cases/order_file/main1.order | 4 + .../test-cases/order_file/main2.expected | 11 + .../test-cases/order_file/main2.order | 6 + .../test-cases/order_file/main3.expected | 4 + .../test-cases/order_file/main3.order | 8 + .../test-cases/prebound-main/Makefile | 51 + .../test-cases/prebound-main/main.c | 3 + .../test-cases/prebound-split-seg/Makefile | 39 + .../prebound-split-seg/address_table | 4 + .../test-cases/prebound-split-seg/bar.c | 36 + .../test-cases/private-non-lazy/Makefile | 54 + .../test-cases/private-non-lazy/bar.c | 3 + .../test-cases/private-non-lazy/comment.txt | 1 + .../test-cases/private-non-lazy/foo.c | 7 + .../test-cases/private-non-lazy/hello.c | 31 + .../test-cases/re-export-cases/Makefile | 167 + .../test-cases/re-export-cases/bar.c | 5 + .../test-cases/re-export-cases/baz.c | 5 + .../test-cases/re-export-cases/foo.c | 4 + .../test-cases/re-export-flag/Makefile | 48 + .../test-cases/re-export-flag/bar.c | 5 + .../test-cases/re-export-flag/foo.c | 4 + .../re-export-optimizations/Makefile | 65 + .../test-cases/re-export-optimizations/bar.c | 5 + .../test-cases/re-export-optimizations/foo.c | 4 + .../test-cases/re-export-optimizations/main.c | 10 + .../re-export-relative-paths/Makefile | 49 + .../test-cases/re-export-relative-paths/bar.c | 5 + .../test-cases/re-export-relative-paths/foo.c | 4 + .../re-export-relative-paths/main.c | 11 + .../re-export-relative-paths/wrap.c | 2 + .../test-cases/read-only-relocs/Makefile | 63 + .../test-cases/read-only-relocs/foo.c | 6 + .../test-cases/read-only-relocs/test.c | 34 + .../test-cases/rebase-basic/Makefile | 53 + .../unit-tests/test-cases/rebase-basic/bar.m | 13 + .../test-cases/rebase-basic/comment.txt | 1 + .../unit-tests/test-cases/rebase-basic/foo.c | 14 + .../unit-tests/test-cases/relocs-asm/Makefile | 46 + .../test-cases/relocs-asm/comment.txt | 3 + .../test-cases/relocs-asm/relocs-asm.s | 471 + .../unit-tests/test-cases/relocs-c/Makefile | 57 + .../unit-tests/test-cases/relocs-c/test.c | 76 + .../unit-tests/test-cases/relocs-c2/Makefile | 58 + .../test-cases/relocs-c2/comment.txt | 5 + .../unit-tests/test-cases/relocs-c2/test.c | 76 + .../test-cases/relocs-literals/Makefile | 47 + .../test-cases/relocs-literals/test.c | 54 + .../test-cases/relocs-literals2/Makefile | 50 + .../test-cases/relocs-literals2/test.c | 54 + .../test-cases/relocs-literals3/Makefile | 47 + .../test-cases/relocs-literals3/comment.txt | 3 + .../test-cases/relocs-literals3/test.c | 47 + .../test-cases/relocs-objc/Makefile | 47 + .../test-cases/relocs-objc/comment.txt | 3 + .../unit-tests/test-cases/relocs-objc/test.m | 59 + .../test-cases/segment-order/Makefile | 37 + .../test-cases/segment-order/expected.order | 3 + .../test-cases/segment-order/main.c | 4 + .../test-cases/segment-order/segJJJ.s | 7 + .../test-cases/segment-order/segKKK.s | 7 + .../test-cases/segment-order/segLLL.s | 7 + .../test-cases/slow-x86-stubs/Makefile | 42 + .../test-cases/slow-x86-stubs/hello.c | 7 + .../test-cases/special-labels/Makefile | 41 + .../test-cases/special-labels/extra.s | 9 + .../test-cases/special-labels/main.c | 29 + .../test-cases/stabs-coalesce/Makefile | 52 + .../test-cases/stabs-coalesce/comment.txt | 3 + .../test-cases/stabs-coalesce/header.h | 31 + .../test-cases/stabs-coalesce/hello.cxx | 33 + .../test-cases/stabs-coalesce/other.cxx | 41 + .../test-cases/stabs-directory-slash/Makefile | 39 + .../test-cases/stabs-directory-slash/main.c | 3 + .../stack_addr_no_size/Makefile.newtest | 77 + .../test-cases/stack_addr_no_size/comment.txt | 11 + .../test-cases/stack_addr_no_size/main.c | 29 + .../test-cases/stack_addr_size/Makefile | 57 + .../test-cases/stack_addr_size/comment.txt | 11 + .../test-cases/stack_addr_size/main.c | 29 + .../test-cases/stack_size_no_addr/Makefile | 56 + .../test-cases/stack_size_no_addr/comment.txt | 11 + .../test-cases/stack_size_no_addr/main.c | 37 + .../test-cases/static-executable/Makefile | 35 + .../test-cases/static-executable/test.c | 11 + .../test-cases/static-strip/Makefile.newtest | 40 + .../test-cases/static-strip/comment.txt | 1 + .../unit-tests/test-cases/static-strip/test.c | 28 + .../test-cases/strip-test2/Makefile | 70 + .../test-cases/strip-test2/comment.txt | 21 + .../test-cases/strip-test2/main.cxx | 6 + .../test-cases/strip-test3/Makefile.newtest | 71 + .../test-cases/strip-test3/comment.txt | 21 + .../test-cases/strip-test3/main.cxx | 6 + .../test-cases/strip_local/Makefile | 53 + .../unit-tests/test-cases/strip_local/foo.c | 8 + .../unit-tests/test-cases/strip_local/hello.c | 33 + .../stripped-indirect-symbol-table/Makefile | 57 + .../stripped-indirect-symbol-table/a.c | 7 + .../stripped-indirect-symbol-table/b.c | 12 + .../stripped-indirect-symbol-table/c.c | 11 + .../stripped-indirect-symbol-table/func.c | 1 + .../stripped-indirect-symbol-table/strip.list | 2 + .../test-cases/stub-generation-weak/Makefile | 42 + .../test-cases/stub-generation-weak/foo.c | 5 + .../test-cases/stub-generation-weak/main.c | 40 + .../test-cases/stub-generation/Makefile | 41 + .../test-cases/stub-generation/test.c | 40 + .../test-cases/switch-jump-table/Makefile | 56 + .../switch-jump-table/interpose.exp | 2 + .../test-cases/switch-jump-table/main.c | 4 + .../test-cases/switch-jump-table/switch.s | 49 + .../test-cases/symbol-moving/Makefile | 93 + .../unit-tests/test-cases/symbol-moving/aaa.c | 3 + .../test-cases/symbol-moving/anotb.c | 26 + .../unit-tests/test-cases/symbol-moving/bar.c | 1 + .../unit-tests/test-cases/symbol-moving/bbb.c | 1 + .../test-cases/symbol-moving/bnota.c | 25 + .../unit-tests/test-cases/symbol-moving/foo.c | 3 + .../test-cases/symbol-moving/main.c | 17 + .../test-cases/tentative-and-archive/Makefile | 50 + .../test-cases/tentative-and-archive/foo.c | 6 + .../test-cases/tentative-and-archive/main.c | 8 + .../test-cases/tentative-and-dylib/Makefile | 56 + .../test-cases/tentative-and-dylib/bar.c | 1 + .../test-cases/tentative-and-dylib/foo.c | 2 + .../test-cases/tentative-and-dylib/main.c | 8 + .../tentative-to-real-hidden/Makefile | 52 + .../tentative-to-real-hidden/test.c | 11 + .../test-cases/tentative-to-real/Makefile | 45 + .../test-cases/tentative-to-real/comment.txt | 1 + .../test-cases/tentative-to-real/test.c | 3 + .../unit-tests/test-cases/thumb-blx/Makefile | 54 + .../unit-tests/test-cases/thumb-blx/test.c | 36 + .../undefined-dynamic-lookup/Makefile | 47 + .../undefined-dynamic-lookup/main.c | 32 + .../Makefile | 46 + .../visibility-warning-dylib-v-archive/bar.c | 11 + .../visibility-warning-dylib-v-archive/foo.c | 5 + .../visibility-warning-dylib-v-archive/main.c | 11 + .../test-cases/visibility-warning/Makefile | 57 + .../test-cases/visibility-warning/foo.c | 5 + .../visibility-warning/foo_hidden.c | 5 + .../test-cases/visibility-warning/foo_weak.c | 5 + .../visibility-warning/foo_weak_hidden.c | 5 + .../test-cases/weak-def-ordinal/Makefile | 50 + .../test-cases/weak-def-ordinal/bar.c | 6 + .../test-cases/weak-def-ordinal/foo.c | 11 + .../test-cases/weak-def-ordinal/main.c | 35 + .../unit-tests/test-cases/weak_dylib/Makefile | 49 + .../unit-tests/test-cases/weak_dylib/bar.c | 9 + .../unit-tests/test-cases/weak_dylib/bar.h | 9 + .../unit-tests/test-cases/weak_dylib/foo.c | 9 + .../unit-tests/test-cases/weak_dylib/foo.h | 6 + .../unit-tests/test-cases/weak_dylib/main.c | 22 + .../test-cases/weak_import/Makefile | 62 + .../unit-tests/test-cases/weak_import/foo.c | 17 + .../unit-tests/test-cases/weak_import/foo.h | 16 + .../unit-tests/test-cases/weak_import/main.c | 20 + .../test-cases/weak_import2/Makefile.newtest | 58 + .../test-cases/weak_import2/comment.txt | 1 + .../unit-tests/test-cases/weak_import2/foo.c | 17 + .../unit-tests/test-cases/weak_import2/foo.h | 16 + .../unit-tests/test-cases/weak_import2/foo1.c | 10 + .../unit-tests/test-cases/weak_import2/main.c | 20 + .../test-cases/weak_import3/Makefile | 43 + .../test-cases/weak_import3/comment.txt | 1 + .../unit-tests/test-cases/weak_import3/foo.c | 17 + .../unit-tests/test-cases/weak_import3/foo.h | 16 + .../unit-tests/test-cases/weak_import3/foo1.c | 4 + .../unit-tests/test-cases/weak_import3/main.c | 20 + .../unit-tests/test-cases/why_live/Makefile | 44 + FireOpal/unit-tests/test-cases/why_live/bar.c | 1 + FireOpal/unit-tests/test-cases/why_live/foo.c | 12 + .../unit-tests/test-cases/why_live/main.c | 7 + .../unit-tests/test-cases/zero-fill/Makefile | 38 + .../unit-tests/test-cases/zero-fill/test.c | 51 + .../unit-tests/test-cases/zero-fill2/Makefile | 38 + .../test-cases/zero-fill2/comment.txt | 1 + .../unit-tests/test-cases/zero-fill2/test.c | 58 + .../unit-tests/test-cases/zero-fill3/Makefile | 50 + .../test-cases/zero-fill3/comment.txt | 1 + .../unit-tests/test-cases/zero-fill3/test.c | 63 + src/ArchiveReader.hpp | 12 +- src/LTOReader.hpp | 68 +- src/MachOWriterExecutable.hpp | 4 +- src/ObjectDump.cpp | 2 +- src/ObjectFile.h | 5 +- src/Options.cpp | 6 + src/Options.h | 5 +- src/ld.cpp | 3 +- 665 files changed, 46310 insertions(+), 24 deletions(-) create mode 100644 FireOpal/APPLE_LICENSE create mode 100644 FireOpal/ChangeLog create mode 100644 FireOpal/doc/man/man1/ld.1 create mode 100644 FireOpal/doc/man/man1/ld64.1 create mode 100644 FireOpal/doc/man/man1/rebase.1 create mode 100644 FireOpal/ld64.xcodeproj/project.pbxproj create mode 100644 FireOpal/src/Architectures.hpp create mode 100644 FireOpal/src/ArchiveReader.hpp create mode 100644 FireOpal/src/ExecutableFile.h create mode 100644 FireOpal/src/FileAbstraction.hpp create mode 100644 FireOpal/src/LTOReader.hpp create mode 100644 FireOpal/src/MachOFileAbstraction.hpp create mode 100644 FireOpal/src/MachOReaderDylib.hpp create mode 100644 FireOpal/src/MachOReaderRelocatable.hpp create mode 100644 FireOpal/src/MachOWriterExecutable.hpp create mode 100644 FireOpal/src/ObjectDump.cpp create mode 100644 FireOpal/src/ObjectFile.h create mode 100644 FireOpal/src/OpaqueSection.hpp create mode 100644 FireOpal/src/Options.cpp create mode 100644 FireOpal/src/Options.h create mode 100644 FireOpal/src/SectCreate.h create mode 100644 FireOpal/src/debugline.c create mode 100644 FireOpal/src/debugline.h create mode 100644 FireOpal/src/dwarf2.h create mode 100644 FireOpal/src/ld.cpp create mode 100644 FireOpal/src/machochecker.cpp create mode 100644 FireOpal/src/rebase.cpp create mode 100644 FireOpal/unit-tests/README create mode 100755 FireOpal/unit-tests/bin/exit-non-zero-pass.pl create mode 100755 FireOpal/unit-tests/bin/fail-if-exit-non-zero.pl create mode 100755 FireOpal/unit-tests/bin/fail-if-exit-zero.pl create mode 100755 FireOpal/unit-tests/bin/fail-if-no-stdin.pl create mode 100755 FireOpal/unit-tests/bin/fail-if-stdin.pl create mode 100755 FireOpal/unit-tests/bin/fail-iff-exit-zero.pl create mode 100755 FireOpal/unit-tests/bin/make-recursive-newtest.pl create mode 100755 FireOpal/unit-tests/bin/make-recursive.pl create mode 100755 FireOpal/unit-tests/bin/mkld create mode 100755 FireOpal/unit-tests/bin/pass-iff-exit-non-zero.pl create mode 100755 FireOpal/unit-tests/bin/pass-iff-exit-zero.pl create mode 100755 FireOpal/unit-tests/bin/pass-iff-no-stdin.pl create mode 100755 FireOpal/unit-tests/bin/pass-iff-stdin.pl create mode 100755 FireOpal/unit-tests/bin/result-filter.pl create mode 100755 FireOpal/unit-tests/bin/rm-stale-test-logs create mode 100755 FireOpal/unit-tests/clean-tests create mode 100644 FireOpal/unit-tests/include/common.makefile create mode 100644 FireOpal/unit-tests/include/test.h create mode 100755 FireOpal/unit-tests/proctor-run create mode 100755 FireOpal/unit-tests/run-all-unit-tests create mode 100755 FireOpal/unit-tests/run-all-unit-tests-debug create mode 100644 FireOpal/unit-tests/src/Makefile create mode 100644 FireOpal/unit-tests/src/results-to-xml.cpp create mode 100644 FireOpal/unit-tests/src/xmlparser/xmlparser.1 create mode 100644 FireOpal/unit-tests/src/xmlparser/xmlparser.m create mode 100644 FireOpal/unit-tests/src/xmlparser/xmlparser.xcodeproj/project.pbxproj create mode 100644 FireOpal/unit-tests/src/xmlparser/xmlparser_Prefix.pch create mode 100644 FireOpal/unit-tests/test-cases/16-byte-alignment/Makefile create mode 100644 FireOpal/unit-tests/test-cases/16-byte-alignment/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/16-byte-alignment/tl_test2.c create mode 100644 FireOpal/unit-tests/test-cases/absolute-symbol/Makefile create mode 100644 FireOpal/unit-tests/test-cases/absolute-symbol/abs.s create mode 100644 FireOpal/unit-tests/test-cases/absolute-symbol/main.c create mode 100644 FireOpal/unit-tests/test-cases/alias-command-line/Makefile create mode 100644 FireOpal/unit-tests/test-cases/alias-command-line/aliases.s create mode 100644 FireOpal/unit-tests/test-cases/alias-command-line/aliases.txt create mode 100644 FireOpal/unit-tests/test-cases/alias-objects/Makefile create mode 100644 FireOpal/unit-tests/test-cases/alias-objects/aliases.s create mode 100644 FireOpal/unit-tests/test-cases/align-modulus/Makefile create mode 100644 FireOpal/unit-tests/test-cases/align-modulus/align.s create mode 100644 FireOpal/unit-tests/test-cases/align-modulus/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/align-modulus/foo.c create mode 100644 FireOpal/unit-tests/test-cases/align-modulus/foo.exp create mode 100644 FireOpal/unit-tests/test-cases/allow-stack-execute/Makefile create mode 100644 FireOpal/unit-tests/test-cases/allow-stack-execute/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/allow-stack-execute/foo.c create mode 100644 FireOpal/unit-tests/test-cases/allowable-client/Makefile create mode 100644 FireOpal/unit-tests/test-cases/allowable-client/bar.c create mode 100644 FireOpal/unit-tests/test-cases/allowable-client/baz.c create mode 100644 FireOpal/unit-tests/test-cases/allowable-client/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/allowable-client/foo.c create mode 100644 FireOpal/unit-tests/test-cases/allowable-client/main.c create mode 100644 FireOpal/unit-tests/test-cases/archive-ObjC/Makefile create mode 100644 FireOpal/unit-tests/test-cases/archive-ObjC/bar.c create mode 100644 FireOpal/unit-tests/test-cases/archive-ObjC/baz.m create mode 100644 FireOpal/unit-tests/test-cases/archive-ObjC/foo.m create mode 100644 FireOpal/unit-tests/test-cases/archive-ObjC/main.c create mode 100644 FireOpal/unit-tests/test-cases/archive-basic/Makefile create mode 100644 FireOpal/unit-tests/test-cases/archive-basic/bar.c create mode 100644 FireOpal/unit-tests/test-cases/archive-basic/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/archive-basic/foo.c create mode 100644 FireOpal/unit-tests/test-cases/archive-basic/main.c create mode 100644 FireOpal/unit-tests/test-cases/archive-duplicate/Makefile create mode 100644 FireOpal/unit-tests/test-cases/archive-duplicate/bar.c create mode 100644 FireOpal/unit-tests/test-cases/archive-duplicate/foo.c create mode 100644 FireOpal/unit-tests/test-cases/archive-duplicate/main.c create mode 100644 FireOpal/unit-tests/test-cases/archive-weak/Makefile create mode 100644 FireOpal/unit-tests/test-cases/archive-weak/bar.c create mode 100644 FireOpal/unit-tests/test-cases/archive-weak/baz.c create mode 100644 FireOpal/unit-tests/test-cases/archive-weak/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/archive-weak/foo.c create mode 100644 FireOpal/unit-tests/test-cases/archive-weak/main.c create mode 100644 FireOpal/unit-tests/test-cases/auto-arch/Makefile create mode 100644 FireOpal/unit-tests/test-cases/auto-arch/hello.c create mode 100644 FireOpal/unit-tests/test-cases/blank-stubs/Makefile create mode 100644 FireOpal/unit-tests/test-cases/blank-stubs/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/blank-stubs/foo.c create mode 100644 FireOpal/unit-tests/test-cases/blank-stubs/main.c create mode 100644 FireOpal/unit-tests/test-cases/branch-islands/Makefile create mode 100644 FireOpal/unit-tests/test-cases/branch-islands/extra.c create mode 100644 FireOpal/unit-tests/test-cases/branch-islands/hello.c create mode 100644 FireOpal/unit-tests/test-cases/branch-islands/space.s create mode 100644 FireOpal/unit-tests/test-cases/bundle_loader/Makefile create mode 100644 FireOpal/unit-tests/test-cases/bundle_loader/bar.c create mode 100644 FireOpal/unit-tests/test-cases/bundle_loader/bundle.c create mode 100644 FireOpal/unit-tests/test-cases/bundle_loader/main.c create mode 100644 FireOpal/unit-tests/test-cases/cfstring-coalesce/Makefile create mode 100644 FireOpal/unit-tests/test-cases/cfstring-coalesce/bar.c create mode 100644 FireOpal/unit-tests/test-cases/cfstring-coalesce/foo.c create mode 100644 FireOpal/unit-tests/test-cases/cfstring-utf16/Makefile create mode 100644 FireOpal/unit-tests/test-cases/cfstring-utf16/bar.m create mode 100644 FireOpal/unit-tests/test-cases/cfstring-utf16/foo.m create mode 100644 FireOpal/unit-tests/test-cases/commons-alignment/Makefile create mode 100644 FireOpal/unit-tests/test-cases/commons-alignment/foo.s create mode 100644 FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/Makefile create mode 100644 FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/a.c create mode 100644 FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/b.c create mode 100644 FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/c.c create mode 100644 FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/c.h create mode 100644 FireOpal/unit-tests/test-cases/commons-mixed/Makefile create mode 100644 FireOpal/unit-tests/test-cases/commons-mixed/bar.c create mode 100644 FireOpal/unit-tests/test-cases/commons-mixed/foo.c create mode 100644 FireOpal/unit-tests/test-cases/commons-order/Makefile create mode 100644 FireOpal/unit-tests/test-cases/commons-order/bar.c create mode 100644 FireOpal/unit-tests/test-cases/commons-order/baz.c create mode 100644 FireOpal/unit-tests/test-cases/commons-order/expected.order create mode 100644 FireOpal/unit-tests/test-cases/commons-order/foo.c create mode 100644 FireOpal/unit-tests/test-cases/commons-order/main.c create mode 100644 FireOpal/unit-tests/test-cases/cpu-sub-types-preference/Makefile create mode 100644 FireOpal/unit-tests/test-cases/cpu-sub-types-preference/foo.c create mode 100644 FireOpal/unit-tests/test-cases/cpu-sub-types/Makefile create mode 100644 FireOpal/unit-tests/test-cases/cpu-sub-types/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/cpu-sub-types/foo.c create mode 100644 FireOpal/unit-tests/test-cases/cpu-sub-types/main.c create mode 100644 FireOpal/unit-tests/test-cases/dead_strip-archive-global/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dead_strip-archive-global/foo.c create mode 100644 FireOpal/unit-tests/test-cases/dead_strip-archive-global/main.c create mode 100644 FireOpal/unit-tests/test-cases/dead_strip-archive/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dead_strip-archive/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/dead_strip-archive/foo.c create mode 100644 FireOpal/unit-tests/test-cases/dead_strip-archive/main.c create mode 100644 FireOpal/unit-tests/test-cases/dead_strip-init-archive/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dead_strip-init-archive/bar.c create mode 100644 FireOpal/unit-tests/test-cases/dead_strip-init-archive/foo.c create mode 100644 FireOpal/unit-tests/test-cases/dead_strip/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dead_strip/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/dead_strip/deadwood.c create mode 100644 FireOpal/unit-tests/test-cases/dead_strip/main.c create mode 100644 FireOpal/unit-tests/test-cases/dead_strip/main.exp create mode 100644 FireOpal/unit-tests/test-cases/dead_strip_dylibs/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dead_strip_dylibs/bar.c create mode 100644 FireOpal/unit-tests/test-cases/dead_strip_dylibs/baz.c create mode 100644 FireOpal/unit-tests/test-cases/dead_strip_dylibs/foo.c create mode 100644 FireOpal/unit-tests/test-cases/dead_strip_dylibs/main.c create mode 100644 FireOpal/unit-tests/test-cases/dead_strip_section_attribute/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dead_strip_section_attribute/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/dead_strip_section_attribute/main.c create mode 100644 FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/Number.d create mode 100644 FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/a.cxx create mode 100644 FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/header.h create mode 100644 FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/x.cxx create mode 100644 FireOpal/unit-tests/test-cases/dtrace-static-probes/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dtrace-static-probes/bar.d create mode 100644 FireOpal/unit-tests/test-cases/dtrace-static-probes/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/dtrace-static-probes/foo.d create mode 100644 FireOpal/unit-tests/test-cases/dtrace-static-probes/main.c create mode 100644 FireOpal/unit-tests/test-cases/dwarf-archive-all_load/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dwarf-archive-all_load/bar.c create mode 100644 FireOpal/unit-tests/test-cases/dwarf-archive-all_load/baz.c create mode 100644 FireOpal/unit-tests/test-cases/dwarf-archive-all_load/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/dwarf-archive-all_load/expected-stabs create mode 100644 FireOpal/unit-tests/test-cases/dwarf-archive-all_load/foo.c create mode 100755 FireOpal/unit-tests/test-cases/dwarf-archive-all_load/stabs-filter.pl create mode 100644 FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/bar.cxx create mode 100644 FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/expected-stabs create mode 100644 FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/foo.cxx create mode 100644 FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/main.cxx create mode 100755 FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/stabs-filter.pl create mode 100644 FireOpal/unit-tests/test-cases/dwarf-debug-notes/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dwarf-debug-notes/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/dwarf-debug-notes/expected-stabs create mode 100644 FireOpal/unit-tests/test-cases/dwarf-debug-notes/header.h create mode 100644 FireOpal/unit-tests/test-cases/dwarf-debug-notes/hello.cxx create mode 100644 FireOpal/unit-tests/test-cases/dwarf-debug-notes/other.cxx create mode 100755 FireOpal/unit-tests/test-cases/dwarf-debug-notes/stabs-filter.pl create mode 100644 FireOpal/unit-tests/test-cases/dwarf-ignore/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dwarf-ignore/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/dwarf-ignore/hello.c create mode 100644 FireOpal/unit-tests/test-cases/dwarf-strip/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dwarf-strip/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/dwarf-strip/hello.c create mode 100644 FireOpal/unit-tests/test-cases/dylib-aliases/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dylib-aliases/bar.c create mode 100644 FireOpal/unit-tests/test-cases/dylib-aliases/foo.c create mode 100644 FireOpal/unit-tests/test-cases/dylib-aliases/main.c create mode 100644 FireOpal/unit-tests/test-cases/dylib-re-export-cycle/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dylib-re-export-cycle/bar.c create mode 100644 FireOpal/unit-tests/test-cases/dylib-re-export-cycle/foo.c create mode 100644 FireOpal/unit-tests/test-cases/dylib-re-export-cycle/main.c create mode 100644 FireOpal/unit-tests/test-cases/dylib_file-missing/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dylib_file-missing/bar.c create mode 100644 FireOpal/unit-tests/test-cases/dylib_file-missing/foo.c create mode 100644 FireOpal/unit-tests/test-cases/dylib_file-missing/main.c create mode 100644 FireOpal/unit-tests/test-cases/dylib_file/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dylib_file/bar.c create mode 100644 FireOpal/unit-tests/test-cases/dylib_file/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/dylib_file/foo.c create mode 100644 FireOpal/unit-tests/test-cases/dylib_file/main.c create mode 100644 FireOpal/unit-tests/test-cases/dylib_init/Makefile create mode 100644 FireOpal/unit-tests/test-cases/dylib_init/foo.c create mode 100644 FireOpal/unit-tests/test-cases/eh-coalescing-r/Makefile create mode 100644 FireOpal/unit-tests/test-cases/eh-coalescing-r/bar.cxx create mode 100644 FireOpal/unit-tests/test-cases/eh-coalescing-r/foo.cxx create mode 100644 FireOpal/unit-tests/test-cases/eh-coalescing-r/func.h create mode 100644 FireOpal/unit-tests/test-cases/eh-coalescing/Makefile create mode 100644 FireOpal/unit-tests/test-cases/eh-coalescing/bar.cxx create mode 100644 FireOpal/unit-tests/test-cases/eh-coalescing/foo.cxx create mode 100644 FireOpal/unit-tests/test-cases/eh-coalescing/foo2.cxx create mode 100644 FireOpal/unit-tests/test-cases/eh-coalescing/func.h create mode 100644 FireOpal/unit-tests/test-cases/eh-strip-test/Makefile create mode 100644 FireOpal/unit-tests/test-cases/eh-strip-test/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/eh-strip-test/main.cxx create mode 100644 FireOpal/unit-tests/test-cases/eh_frame/Makefile create mode 100644 FireOpal/unit-tests/test-cases/eh_frame/bar.cxx create mode 100644 FireOpal/unit-tests/test-cases/eh_frame/foo.cxx create mode 100644 FireOpal/unit-tests/test-cases/empty-object/Makefile create mode 100644 FireOpal/unit-tests/test-cases/empty-object/main.c create mode 100644 FireOpal/unit-tests/test-cases/end-label/Makefile create mode 100644 FireOpal/unit-tests/test-cases/end-label/bar.s create mode 100644 FireOpal/unit-tests/test-cases/end-label/foo.s create mode 100644 FireOpal/unit-tests/test-cases/exported-symbols-wildcards-dead_strip/Makefile create mode 100644 FireOpal/unit-tests/test-cases/exported-symbols-wildcards-dead_strip/foo.c create mode 100644 FireOpal/unit-tests/test-cases/exported-symbols-wildcards/Makefile create mode 100644 FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect1 create mode 100644 FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect2 create mode 100644 FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect3 create mode 100644 FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect4 create mode 100644 FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect5 create mode 100644 FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect6 create mode 100644 FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect7 create mode 100644 FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect8 create mode 100644 FireOpal/unit-tests/test-cases/exported-symbols-wildcards/foo.c create mode 100644 FireOpal/unit-tests/test-cases/exported-symbols-wildcards/list5 create mode 100644 FireOpal/unit-tests/test-cases/exported_symbols_list-eol/Makefile create mode 100644 FireOpal/unit-tests/test-cases/exported_symbols_list-eol/expected.nm create mode 100644 FireOpal/unit-tests/test-cases/exported_symbols_list-eol/test.c create mode 100644 FireOpal/unit-tests/test-cases/exported_symbols_list-eol/test.exp create mode 100644 FireOpal/unit-tests/test-cases/exported_symbols_list-hidden/Makefile create mode 100644 FireOpal/unit-tests/test-cases/exported_symbols_list-hidden/test.c create mode 100644 FireOpal/unit-tests/test-cases/exported_symbols_list-hidden/test.exp create mode 100644 FireOpal/unit-tests/test-cases/exported_symbols_list-r/Makefile create mode 100644 FireOpal/unit-tests/test-cases/exported_symbols_list-r/test-bad.exp create mode 100644 FireOpal/unit-tests/test-cases/exported_symbols_list-r/test.c create mode 100644 FireOpal/unit-tests/test-cases/exported_symbols_list-r/test.exp create mode 100644 FireOpal/unit-tests/test-cases/external-reloc-sorting/Makefile create mode 100644 FireOpal/unit-tests/test-cases/external-reloc-sorting/foo.c create mode 100644 FireOpal/unit-tests/test-cases/external-reloc-sorting/main.c create mode 100644 FireOpal/unit-tests/test-cases/filelist/Makefile create mode 100644 FireOpal/unit-tests/test-cases/filelist/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/filelist/hello.c create mode 100644 FireOpal/unit-tests/test-cases/flat-dylib/Makefile create mode 100644 FireOpal/unit-tests/test-cases/flat-dylib/main.c create mode 100644 FireOpal/unit-tests/test-cases/flat-indirect-undefines/Makefile create mode 100644 FireOpal/unit-tests/test-cases/flat-indirect-undefines/bar.c create mode 100644 FireOpal/unit-tests/test-cases/flat-indirect-undefines/foo.c create mode 100644 FireOpal/unit-tests/test-cases/flat-indirect-undefines/main.c create mode 100644 FireOpal/unit-tests/test-cases/flat-main/Makefile create mode 100644 FireOpal/unit-tests/test-cases/flat-main/main.c create mode 100644 FireOpal/unit-tests/test-cases/got-elimination/Makefile create mode 100644 FireOpal/unit-tests/test-cases/got-elimination/bar.c create mode 100644 FireOpal/unit-tests/test-cases/got-elimination/foo.c create mode 100644 FireOpal/unit-tests/test-cases/header-pad/Makefile create mode 100644 FireOpal/unit-tests/test-cases/header-pad/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/header-pad/hello.c create mode 100644 FireOpal/unit-tests/test-cases/hello-world/Makefile create mode 100644 FireOpal/unit-tests/test-cases/hello-world/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/hello-world/hello.c create mode 100644 FireOpal/unit-tests/test-cases/implicit-common2/Makefile.newtest create mode 100644 FireOpal/unit-tests/test-cases/implicit-common2/a.c create mode 100644 FireOpal/unit-tests/test-cases/implicit-common2/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/implicit-common2/test.c create mode 100644 FireOpal/unit-tests/test-cases/implicit-common3/Makefile create mode 100644 FireOpal/unit-tests/test-cases/implicit-common3/a.c create mode 100644 FireOpal/unit-tests/test-cases/implicit-common3/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/implicit-common3/test.c create mode 100644 FireOpal/unit-tests/test-cases/implicit-common4/Makefile.newtest create mode 100644 FireOpal/unit-tests/test-cases/implicit-common4/a.c create mode 100644 FireOpal/unit-tests/test-cases/implicit-common4/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/implicit-common4/test.c create mode 100644 FireOpal/unit-tests/test-cases/implicit-common5/Makefile.newtest create mode 100644 FireOpal/unit-tests/test-cases/implicit-common5/a.c create mode 100644 FireOpal/unit-tests/test-cases/implicit-common5/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/implicit-common5/test.c create mode 100644 FireOpal/unit-tests/test-cases/implicit_dylib/Makefile create mode 100644 FireOpal/unit-tests/test-cases/implicit_dylib/bar.c create mode 100644 FireOpal/unit-tests/test-cases/implicit_dylib/foo.c create mode 100644 FireOpal/unit-tests/test-cases/implicit_dylib/main.c create mode 100644 FireOpal/unit-tests/test-cases/indirect-dylib/Makefile create mode 100644 FireOpal/unit-tests/test-cases/indirect-dylib/bar.c create mode 100644 FireOpal/unit-tests/test-cases/indirect-dylib/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/indirect-dylib/foo.c create mode 100644 FireOpal/unit-tests/test-cases/indirect-dylib/main.c create mode 100644 FireOpal/unit-tests/test-cases/indirect-path-search/Makefile create mode 100644 FireOpal/unit-tests/test-cases/indirect-path-search/bar.c create mode 100644 FireOpal/unit-tests/test-cases/indirect-path-search/baz.c create mode 100644 FireOpal/unit-tests/test-cases/indirect-path-search/foo.c create mode 100644 FireOpal/unit-tests/test-cases/indirect-path-search/main.c create mode 100644 FireOpal/unit-tests/test-cases/interposable_list/Makefile create mode 100644 FireOpal/unit-tests/test-cases/interposable_list/test.c create mode 100644 FireOpal/unit-tests/test-cases/interposable_list/test.exp create mode 100644 FireOpal/unit-tests/test-cases/large-data/Makefile create mode 100644 FireOpal/unit-tests/test-cases/large-data/test1.c create mode 100644 FireOpal/unit-tests/test-cases/large-data/test2.c create mode 100644 FireOpal/unit-tests/test-cases/large-data/test3.c create mode 100644 FireOpal/unit-tests/test-cases/large-data/test4.c create mode 100644 FireOpal/unit-tests/test-cases/late-link-error/Makefile create mode 100644 FireOpal/unit-tests/test-cases/late-link-error/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/late-link-error/link_error.s create mode 100644 FireOpal/unit-tests/test-cases/lazy-dylib-objc/Makefile create mode 100644 FireOpal/unit-tests/test-cases/lazy-dylib-objc/foo.h create mode 100644 FireOpal/unit-tests/test-cases/lazy-dylib-objc/foo.m create mode 100644 FireOpal/unit-tests/test-cases/lazy-dylib-objc/main.m create mode 100644 FireOpal/unit-tests/test-cases/lazy-dylib/Makefile create mode 100644 FireOpal/unit-tests/test-cases/lazy-dylib/bad.c create mode 100644 FireOpal/unit-tests/test-cases/lazy-dylib/bad2.c create mode 100644 FireOpal/unit-tests/test-cases/lazy-dylib/foo.c create mode 100644 FireOpal/unit-tests/test-cases/lazy-dylib/main.c create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce-alignment/Makefile create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce-alignment/cstring-align-0.s create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce-alignment/cstring-align-3.s create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/Makefile create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/cstring-align-0.s create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/cstring-align-3.s create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/Makefile create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/cstring-align-0.s create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/cstring-align-3.s create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce/Makefile create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce/literals.s create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce2/Makefile.newtest create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce2/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/literals-coalesce2/literals.s create mode 100755 FireOpal/unit-tests/test-cases/literals-coalesce2/test.sh create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/Makefile create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a1.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a10.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a11.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a12.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a12.h create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a13.cc create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a13.h create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a14.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a15.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a17.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a18.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a2.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a20.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a3.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a4.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a5.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a6.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a7.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a8.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a9.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/a9.list create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/b.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/b1.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/b10.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/b10.h create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/b14.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/b15.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/b17.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/b2.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/b20.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/b3.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/b4.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/b5.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/b7.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/c15.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main1.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main10.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main11.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main12.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main13.cc create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main16.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main19.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main2.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main20.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main3.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main4.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main5.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main6.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main7.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main8.c create mode 100644 FireOpal/unit-tests/test-cases/llvm-integration/main9.c create mode 100644 FireOpal/unit-tests/test-cases/loader_path/Makefile create mode 100644 FireOpal/unit-tests/test-cases/loader_path/bar.c create mode 100644 FireOpal/unit-tests/test-cases/loader_path/foo.c create mode 100644 FireOpal/unit-tests/test-cases/loader_path/main.c create mode 100644 FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/Makefile create mode 100644 FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/a.expect create mode 100644 FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/a.list create mode 100644 FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/b.expect create mode 100644 FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/b.list create mode 100644 FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/c.list create mode 100644 FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/foo.c create mode 100644 FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/main.c create mode 100644 FireOpal/unit-tests/test-cases/lto-llvm-options/Makefile create mode 100644 FireOpal/unit-tests/test-cases/lto-llvm-options/main.c create mode 100644 FireOpal/unit-tests/test-cases/lto-weak-native-override/Makefile create mode 100644 FireOpal/unit-tests/test-cases/lto-weak-native-override/foo.c create mode 100644 FireOpal/unit-tests/test-cases/lto-weak-native-override/main.c create mode 100644 FireOpal/unit-tests/test-cases/main-stripped/Makefile create mode 100644 FireOpal/unit-tests/test-cases/main-stripped/main.c create mode 100644 FireOpal/unit-tests/test-cases/main-stripped/main.exp create mode 100644 FireOpal/unit-tests/test-cases/missing-option-args/Makefile create mode 100644 FireOpal/unit-tests/test-cases/missing-option-args/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/multiple-entry-points/Makefile create mode 100644 FireOpal/unit-tests/test-cases/multiple-entry-points/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/multiple-entry-points/test.s create mode 100644 FireOpal/unit-tests/test-cases/no-dynamic-common/Makefile.newtest create mode 100644 FireOpal/unit-tests/test-cases/no-dynamic-common/a.c create mode 100644 FireOpal/unit-tests/test-cases/no-dynamic-common/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/no-dynamic-common/test.c create mode 100644 FireOpal/unit-tests/test-cases/no-uuid/Makefile create mode 100644 FireOpal/unit-tests/test-cases/no-uuid/bar.c create mode 100644 FireOpal/unit-tests/test-cases/no-uuid/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/no-uuid/foo.c create mode 100644 FireOpal/unit-tests/test-cases/non-lazy-r/Makefile create mode 100644 FireOpal/unit-tests/test-cases/non-lazy-r/foo.c create mode 100644 FireOpal/unit-tests/test-cases/non-lazy-r/other.c create mode 100644 FireOpal/unit-tests/test-cases/objc-category-debug-notes/Makefile create mode 100644 FireOpal/unit-tests/test-cases/objc-category-debug-notes/test.m create mode 100644 FireOpal/unit-tests/test-cases/objc-exported_symbols_list/Makefile create mode 100644 FireOpal/unit-tests/test-cases/objc-exported_symbols_list/foo.exp create mode 100644 FireOpal/unit-tests/test-cases/objc-exported_symbols_list/foo.m create mode 100644 FireOpal/unit-tests/test-cases/objc-gc-checks/Makefile create mode 100644 FireOpal/unit-tests/test-cases/objc-gc-checks/bar.m create mode 100644 FireOpal/unit-tests/test-cases/objc-gc-checks/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/objc-gc-checks/foo.m create mode 100644 FireOpal/unit-tests/test-cases/objc-gc-checks/runtime.c create mode 100644 FireOpal/unit-tests/test-cases/objc-literal-pointers/Makefile create mode 100644 FireOpal/unit-tests/test-cases/objc-literal-pointers/test.m create mode 100644 FireOpal/unit-tests/test-cases/objc-references/Makefile create mode 100644 FireOpal/unit-tests/test-cases/objc-references/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/objc-references/test.m create mode 100644 FireOpal/unit-tests/test-cases/objc-selector-coalescing/Makefile create mode 100644 FireOpal/unit-tests/test-cases/objc-selector-coalescing/main.m create mode 100644 FireOpal/unit-tests/test-cases/objc-selector-coalescing/other.m create mode 100644 FireOpal/unit-tests/test-cases/operator-new/Makefile create mode 100644 FireOpal/unit-tests/test-cases/operator-new/main.cxx create mode 100644 FireOpal/unit-tests/test-cases/order_file-ans/Makefile create mode 100644 FireOpal/unit-tests/test-cases/order_file-ans/main.cxx create mode 100644 FireOpal/unit-tests/test-cases/order_file-ans/main.expected create mode 100644 FireOpal/unit-tests/test-cases/order_file-ans/main.order create mode 100644 FireOpal/unit-tests/test-cases/order_file/Makefile create mode 100644 FireOpal/unit-tests/test-cases/order_file/extra.s create mode 100644 FireOpal/unit-tests/test-cases/order_file/main.c create mode 100644 FireOpal/unit-tests/test-cases/order_file/main1.expected create mode 100644 FireOpal/unit-tests/test-cases/order_file/main1.order create mode 100644 FireOpal/unit-tests/test-cases/order_file/main2.expected create mode 100644 FireOpal/unit-tests/test-cases/order_file/main2.order create mode 100644 FireOpal/unit-tests/test-cases/order_file/main3.expected create mode 100644 FireOpal/unit-tests/test-cases/order_file/main3.order create mode 100644 FireOpal/unit-tests/test-cases/prebound-main/Makefile create mode 100644 FireOpal/unit-tests/test-cases/prebound-main/main.c create mode 100644 FireOpal/unit-tests/test-cases/prebound-split-seg/Makefile create mode 100644 FireOpal/unit-tests/test-cases/prebound-split-seg/address_table create mode 100644 FireOpal/unit-tests/test-cases/prebound-split-seg/bar.c create mode 100644 FireOpal/unit-tests/test-cases/private-non-lazy/Makefile create mode 100644 FireOpal/unit-tests/test-cases/private-non-lazy/bar.c create mode 100644 FireOpal/unit-tests/test-cases/private-non-lazy/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/private-non-lazy/foo.c create mode 100644 FireOpal/unit-tests/test-cases/private-non-lazy/hello.c create mode 100644 FireOpal/unit-tests/test-cases/re-export-cases/Makefile create mode 100644 FireOpal/unit-tests/test-cases/re-export-cases/bar.c create mode 100644 FireOpal/unit-tests/test-cases/re-export-cases/baz.c create mode 100644 FireOpal/unit-tests/test-cases/re-export-cases/foo.c create mode 100644 FireOpal/unit-tests/test-cases/re-export-flag/Makefile create mode 100644 FireOpal/unit-tests/test-cases/re-export-flag/bar.c create mode 100644 FireOpal/unit-tests/test-cases/re-export-flag/foo.c create mode 100644 FireOpal/unit-tests/test-cases/re-export-optimizations/Makefile create mode 100644 FireOpal/unit-tests/test-cases/re-export-optimizations/bar.c create mode 100644 FireOpal/unit-tests/test-cases/re-export-optimizations/foo.c create mode 100644 FireOpal/unit-tests/test-cases/re-export-optimizations/main.c create mode 100644 FireOpal/unit-tests/test-cases/re-export-relative-paths/Makefile create mode 100644 FireOpal/unit-tests/test-cases/re-export-relative-paths/bar.c create mode 100644 FireOpal/unit-tests/test-cases/re-export-relative-paths/foo.c create mode 100644 FireOpal/unit-tests/test-cases/re-export-relative-paths/main.c create mode 100644 FireOpal/unit-tests/test-cases/re-export-relative-paths/wrap.c create mode 100644 FireOpal/unit-tests/test-cases/read-only-relocs/Makefile create mode 100644 FireOpal/unit-tests/test-cases/read-only-relocs/foo.c create mode 100644 FireOpal/unit-tests/test-cases/read-only-relocs/test.c create mode 100644 FireOpal/unit-tests/test-cases/rebase-basic/Makefile create mode 100644 FireOpal/unit-tests/test-cases/rebase-basic/bar.m create mode 100644 FireOpal/unit-tests/test-cases/rebase-basic/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/rebase-basic/foo.c create mode 100644 FireOpal/unit-tests/test-cases/relocs-asm/Makefile create mode 100644 FireOpal/unit-tests/test-cases/relocs-asm/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/relocs-asm/relocs-asm.s create mode 100644 FireOpal/unit-tests/test-cases/relocs-c/Makefile create mode 100644 FireOpal/unit-tests/test-cases/relocs-c/test.c create mode 100644 FireOpal/unit-tests/test-cases/relocs-c2/Makefile create mode 100644 FireOpal/unit-tests/test-cases/relocs-c2/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/relocs-c2/test.c create mode 100644 FireOpal/unit-tests/test-cases/relocs-literals/Makefile create mode 100644 FireOpal/unit-tests/test-cases/relocs-literals/test.c create mode 100644 FireOpal/unit-tests/test-cases/relocs-literals2/Makefile create mode 100644 FireOpal/unit-tests/test-cases/relocs-literals2/test.c create mode 100644 FireOpal/unit-tests/test-cases/relocs-literals3/Makefile create mode 100644 FireOpal/unit-tests/test-cases/relocs-literals3/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/relocs-literals3/test.c create mode 100644 FireOpal/unit-tests/test-cases/relocs-objc/Makefile create mode 100644 FireOpal/unit-tests/test-cases/relocs-objc/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/relocs-objc/test.m create mode 100644 FireOpal/unit-tests/test-cases/segment-order/Makefile create mode 100644 FireOpal/unit-tests/test-cases/segment-order/expected.order create mode 100644 FireOpal/unit-tests/test-cases/segment-order/main.c create mode 100644 FireOpal/unit-tests/test-cases/segment-order/segJJJ.s create mode 100644 FireOpal/unit-tests/test-cases/segment-order/segKKK.s create mode 100644 FireOpal/unit-tests/test-cases/segment-order/segLLL.s create mode 100644 FireOpal/unit-tests/test-cases/slow-x86-stubs/Makefile create mode 100644 FireOpal/unit-tests/test-cases/slow-x86-stubs/hello.c create mode 100644 FireOpal/unit-tests/test-cases/special-labels/Makefile create mode 100644 FireOpal/unit-tests/test-cases/special-labels/extra.s create mode 100644 FireOpal/unit-tests/test-cases/special-labels/main.c create mode 100644 FireOpal/unit-tests/test-cases/stabs-coalesce/Makefile create mode 100644 FireOpal/unit-tests/test-cases/stabs-coalesce/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/stabs-coalesce/header.h create mode 100644 FireOpal/unit-tests/test-cases/stabs-coalesce/hello.cxx create mode 100644 FireOpal/unit-tests/test-cases/stabs-coalesce/other.cxx create mode 100644 FireOpal/unit-tests/test-cases/stabs-directory-slash/Makefile create mode 100644 FireOpal/unit-tests/test-cases/stabs-directory-slash/main.c create mode 100644 FireOpal/unit-tests/test-cases/stack_addr_no_size/Makefile.newtest create mode 100644 FireOpal/unit-tests/test-cases/stack_addr_no_size/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/stack_addr_no_size/main.c create mode 100644 FireOpal/unit-tests/test-cases/stack_addr_size/Makefile create mode 100644 FireOpal/unit-tests/test-cases/stack_addr_size/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/stack_addr_size/main.c create mode 100644 FireOpal/unit-tests/test-cases/stack_size_no_addr/Makefile create mode 100644 FireOpal/unit-tests/test-cases/stack_size_no_addr/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/stack_size_no_addr/main.c create mode 100644 FireOpal/unit-tests/test-cases/static-executable/Makefile create mode 100644 FireOpal/unit-tests/test-cases/static-executable/test.c create mode 100644 FireOpal/unit-tests/test-cases/static-strip/Makefile.newtest create mode 100644 FireOpal/unit-tests/test-cases/static-strip/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/static-strip/test.c create mode 100644 FireOpal/unit-tests/test-cases/strip-test2/Makefile create mode 100644 FireOpal/unit-tests/test-cases/strip-test2/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/strip-test2/main.cxx create mode 100644 FireOpal/unit-tests/test-cases/strip-test3/Makefile.newtest create mode 100644 FireOpal/unit-tests/test-cases/strip-test3/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/strip-test3/main.cxx create mode 100644 FireOpal/unit-tests/test-cases/strip_local/Makefile create mode 100644 FireOpal/unit-tests/test-cases/strip_local/foo.c create mode 100644 FireOpal/unit-tests/test-cases/strip_local/hello.c create mode 100644 FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/Makefile create mode 100644 FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/a.c create mode 100644 FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/b.c create mode 100644 FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/c.c create mode 100644 FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/func.c create mode 100644 FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/strip.list create mode 100644 FireOpal/unit-tests/test-cases/stub-generation-weak/Makefile create mode 100644 FireOpal/unit-tests/test-cases/stub-generation-weak/foo.c create mode 100644 FireOpal/unit-tests/test-cases/stub-generation-weak/main.c create mode 100644 FireOpal/unit-tests/test-cases/stub-generation/Makefile create mode 100644 FireOpal/unit-tests/test-cases/stub-generation/test.c create mode 100644 FireOpal/unit-tests/test-cases/switch-jump-table/Makefile create mode 100644 FireOpal/unit-tests/test-cases/switch-jump-table/interpose.exp create mode 100644 FireOpal/unit-tests/test-cases/switch-jump-table/main.c create mode 100644 FireOpal/unit-tests/test-cases/switch-jump-table/switch.s create mode 100644 FireOpal/unit-tests/test-cases/symbol-moving/Makefile create mode 100644 FireOpal/unit-tests/test-cases/symbol-moving/aaa.c create mode 100644 FireOpal/unit-tests/test-cases/symbol-moving/anotb.c create mode 100644 FireOpal/unit-tests/test-cases/symbol-moving/bar.c create mode 100644 FireOpal/unit-tests/test-cases/symbol-moving/bbb.c create mode 100644 FireOpal/unit-tests/test-cases/symbol-moving/bnota.c create mode 100644 FireOpal/unit-tests/test-cases/symbol-moving/foo.c create mode 100644 FireOpal/unit-tests/test-cases/symbol-moving/main.c create mode 100644 FireOpal/unit-tests/test-cases/tentative-and-archive/Makefile create mode 100644 FireOpal/unit-tests/test-cases/tentative-and-archive/foo.c create mode 100644 FireOpal/unit-tests/test-cases/tentative-and-archive/main.c create mode 100644 FireOpal/unit-tests/test-cases/tentative-and-dylib/Makefile create mode 100644 FireOpal/unit-tests/test-cases/tentative-and-dylib/bar.c create mode 100644 FireOpal/unit-tests/test-cases/tentative-and-dylib/foo.c create mode 100644 FireOpal/unit-tests/test-cases/tentative-and-dylib/main.c create mode 100644 FireOpal/unit-tests/test-cases/tentative-to-real-hidden/Makefile create mode 100644 FireOpal/unit-tests/test-cases/tentative-to-real-hidden/test.c create mode 100644 FireOpal/unit-tests/test-cases/tentative-to-real/Makefile create mode 100644 FireOpal/unit-tests/test-cases/tentative-to-real/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/tentative-to-real/test.c create mode 100644 FireOpal/unit-tests/test-cases/thumb-blx/Makefile create mode 100644 FireOpal/unit-tests/test-cases/thumb-blx/test.c create mode 100644 FireOpal/unit-tests/test-cases/undefined-dynamic-lookup/Makefile create mode 100644 FireOpal/unit-tests/test-cases/undefined-dynamic-lookup/main.c create mode 100644 FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/Makefile create mode 100644 FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/bar.c create mode 100644 FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/foo.c create mode 100644 FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/main.c create mode 100644 FireOpal/unit-tests/test-cases/visibility-warning/Makefile create mode 100644 FireOpal/unit-tests/test-cases/visibility-warning/foo.c create mode 100644 FireOpal/unit-tests/test-cases/visibility-warning/foo_hidden.c create mode 100644 FireOpal/unit-tests/test-cases/visibility-warning/foo_weak.c create mode 100644 FireOpal/unit-tests/test-cases/visibility-warning/foo_weak_hidden.c create mode 100644 FireOpal/unit-tests/test-cases/weak-def-ordinal/Makefile create mode 100644 FireOpal/unit-tests/test-cases/weak-def-ordinal/bar.c create mode 100644 FireOpal/unit-tests/test-cases/weak-def-ordinal/foo.c create mode 100644 FireOpal/unit-tests/test-cases/weak-def-ordinal/main.c create mode 100644 FireOpal/unit-tests/test-cases/weak_dylib/Makefile create mode 100644 FireOpal/unit-tests/test-cases/weak_dylib/bar.c create mode 100644 FireOpal/unit-tests/test-cases/weak_dylib/bar.h create mode 100644 FireOpal/unit-tests/test-cases/weak_dylib/foo.c create mode 100644 FireOpal/unit-tests/test-cases/weak_dylib/foo.h create mode 100644 FireOpal/unit-tests/test-cases/weak_dylib/main.c create mode 100644 FireOpal/unit-tests/test-cases/weak_import/Makefile create mode 100644 FireOpal/unit-tests/test-cases/weak_import/foo.c create mode 100644 FireOpal/unit-tests/test-cases/weak_import/foo.h create mode 100644 FireOpal/unit-tests/test-cases/weak_import/main.c create mode 100644 FireOpal/unit-tests/test-cases/weak_import2/Makefile.newtest create mode 100644 FireOpal/unit-tests/test-cases/weak_import2/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/weak_import2/foo.c create mode 100644 FireOpal/unit-tests/test-cases/weak_import2/foo.h create mode 100644 FireOpal/unit-tests/test-cases/weak_import2/foo1.c create mode 100644 FireOpal/unit-tests/test-cases/weak_import2/main.c create mode 100644 FireOpal/unit-tests/test-cases/weak_import3/Makefile create mode 100644 FireOpal/unit-tests/test-cases/weak_import3/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/weak_import3/foo.c create mode 100644 FireOpal/unit-tests/test-cases/weak_import3/foo.h create mode 100644 FireOpal/unit-tests/test-cases/weak_import3/foo1.c create mode 100644 FireOpal/unit-tests/test-cases/weak_import3/main.c create mode 100644 FireOpal/unit-tests/test-cases/why_live/Makefile create mode 100644 FireOpal/unit-tests/test-cases/why_live/bar.c create mode 100644 FireOpal/unit-tests/test-cases/why_live/foo.c create mode 100644 FireOpal/unit-tests/test-cases/why_live/main.c create mode 100644 FireOpal/unit-tests/test-cases/zero-fill/Makefile create mode 100644 FireOpal/unit-tests/test-cases/zero-fill/test.c create mode 100644 FireOpal/unit-tests/test-cases/zero-fill2/Makefile create mode 100644 FireOpal/unit-tests/test-cases/zero-fill2/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/zero-fill2/test.c create mode 100644 FireOpal/unit-tests/test-cases/zero-fill3/Makefile create mode 100644 FireOpal/unit-tests/test-cases/zero-fill3/comment.txt create mode 100644 FireOpal/unit-tests/test-cases/zero-fill3/test.c diff --git a/ChangeLog b/ChangeLog index c152946..1a79a07 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,55 @@ ------ Tagged ld64-85 +2008-07-10 Nick Kledzik + + * src/LTOReader.hpp: improve missing symbol error message + + +2008-07-08 Nick Kledzik + + ld: add support for mllvm LTO options + * src/Options.cpp: support -mllvm option + * src/LTOReader.hpp: call lto_codegen_debug_options() with -mllvm options + * src/ld.cpp: pass llvmOptions to optimize() + * src/Options.h: add fLLVMOptions + * src/ArchiveReader.hpp: add llvmOptions parameter to optimize() + * src/ObjectFile.h: add llvmOptions parameter to optimize() + * unit-tests/test-cases/lto-llvm-options: add test case + + +2008-06-04 Nick Kledzik + + * src/LTOReader.hpp: if lto_codegen_add_module() fails, add explanation to error message + +2008-06-04 Nick Kledzik + + * src/ObjectFile.h: add deadAtoms parameter to optimize() + * src/ld.cpp: ditto + * src/ArchiveReader.hpp: ditto + * src/MachOReaderRelocatable.hpp: handle llvm use of 0x1B pointer encodings in CIEs + * src/LTOReader.hpp: make sure libLTO.dylib knows about any llvm symbol coalesced away + * unit-tests/test-cases/lto-weak-native-override: add test case + + +2008-06-04 Nick Kledzik + + LTO : 176.gcc and 177.mesa build failure at -O4 + * src/LTOReader.hpp: make sure internal is returned by getAtoms() + * unit-tests/test-cases/lto-archive-dylib: update test case + + +2008-05-06 Nick Kledzik + + ARM ld should take W bit off of maxprot for __TEXT segment + * src/MachOWriterExecutable.hpp: for iPhone always set maxprot to be initprot in all segments + + +2008-05-06 Nick Kledzik + + encryptable images may not be signable + * src/MachOWriterExecutable.hpp: use minimum header padding when aligning __text section + + +----- Tagged ld64-85 (Xcode 3.1) 2008-04-29 Nick Kledzik diff --git a/FireOpal/APPLE_LICENSE b/FireOpal/APPLE_LICENSE new file mode 100644 index 0000000..fe81a60 --- /dev/null +++ b/FireOpal/APPLE_LICENSE @@ -0,0 +1,367 @@ +APPLE PUBLIC SOURCE LICENSE +Version 2.0 - August 6, 2003 + +Please read this License carefully before downloading this software. +By downloading or using this software, you are agreeing to be bound by +the terms of this License. If you do not or cannot agree to the terms +of this License, please do not download or use the software. + +1. General; Definitions. This License applies to any program or other +work which Apple Computer, Inc. ("Apple") makes publicly available and +which contains a notice placed by Apple identifying such program or +work as "Original Code" and stating that it is subject to the terms of +this Apple Public Source License version 2.0 ("License"). As used in +this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is +the grantor of rights, (i) claims of patents that are now or hereafter +acquired, owned by or assigned to Apple and (ii) that cover subject +matter contained in the Original Code, but only to the extent +necessary to use, reproduce and/or distribute the Original Code +without infringement; and (b) in the case where You are the grantor of +rights, (i) claims of patents that are now or hereafter acquired, +owned by or assigned to You and (ii) that cover subject matter in Your +Modifications, taken alone or in combination with Original Code. + +1.2 "Contributor" means any person or entity that creates or +contributes to the creation of Modifications. + +1.3 "Covered Code" means the Original Code, Modifications, the +combination of Original Code and any Modifications, and/or any +respective portions thereof. + +1.4 "Externally Deploy" means: (a) to sublicense, distribute or +otherwise make Covered Code available, directly or indirectly, to +anyone other than You; and/or (b) to use Covered Code, alone or as +part of a Larger Work, in any way to provide a service, including but +not limited to delivery of content, through electronic communication +with a client other than You. + +1.5 "Larger Work" means a work which combines Covered Code or portions +thereof with code not governed by the terms of this License. + +1.6 "Modifications" mean any addition to, deletion from, and/or change +to, the substance and/or structure of the Original Code, any previous +Modifications, the combination of Original Code and any previous +Modifications, and/or any respective portions thereof. When code is +released as a series of files, a Modification is: (a) any addition to +or deletion from the contents of a file containing Covered Code; +and/or (b) any new file or other representation of computer program +statements that contains any part of Covered Code. + +1.7 "Original Code" means (a) the Source Code of a program or other +work as originally made available by Apple under this License, +including the Source Code of any updates or upgrades to such programs +or works made available by Apple under this License, and that has been +expressly identified by Apple as such in the header file(s) of such +work; and (b) the object code compiled from such Source Code and +originally made available by Apple under this License. + +1.8 "Source Code" means the human readable form of a program or other +work that is suitable for making modifications to it, including all +modules it contains, plus any associated interface definition files, +scripts used to control compilation and installation of an executable +(object code). + +1.9 "You" or "Your" means an individual or a legal entity exercising +rights under this License. For legal entities, "You" or "Your" +includes any entity which controls, is controlled by, or is under +common control with, You, where "control" means (a) the power, direct +or indirect, to cause the direction or management of such entity, +whether by contract or otherwise, or (b) ownership of fifty percent +(50%) or more of the outstanding shares or beneficial ownership of +such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms +and conditions of this License, Apple hereby grants You, effective on +the date You accept this License and download the Original Code, a +world-wide, royalty-free, non-exclusive license, to the extent of +Apple's Applicable Patent Rights and copyrights covering the Original +Code, to do the following: + +2.1 Unmodified Code. You may use, reproduce, display, perform, +internally distribute within Your organization, and Externally Deploy +verbatim, unmodified copies of the Original Code, for commercial or +non-commercial purposes, provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the +copyright and other proprietary notices and disclaimers of Apple as +they appear in the Original Code, and keep intact all notices in the +Original Code that refer to this License; and + +(b) You must include a copy of this License with every copy of Source +Code of Covered Code and documentation You distribute or Externally +Deploy, and You may not offer or impose any terms on such Source Code +that alter or restrict this License or the recipients' rights +hereunder, except as permitted under Section 6. + +2.2 Modified Code. You may modify Covered Code and use, reproduce, +display, perform, internally distribute within Your organization, and +Externally Deploy Your Modifications and Covered Code, for commercial +or non-commercial purposes, provided that in each instance You also +meet all of these conditions: + +(a) You must satisfy all the conditions of Section 2.1 with respect to +the Source Code of the Covered Code; + +(b) You must duplicate, to the extent it does not already exist, the +notice in Exhibit A in each file of the Source Code of all Your +Modifications, and cause the modified files to carry prominent notices +stating that You changed the files and the date of any change; and + +(c) If You Externally Deploy Your Modifications, You must make +Source Code of all Your Externally Deployed Modifications either +available to those to whom You have Externally Deployed Your +Modifications, or publicly available. Source Code of Your Externally +Deployed Modifications must be released under the terms set forth in +this License, including the license grants set forth in Section 3 +below, for as long as you Externally Deploy the Covered Code or twelve +(12) months from the date of initial External Deployment, whichever is +longer. You should preferably distribute the Source Code of Your +Externally Deployed Modifications electronically (e.g. download from a +web site). + +2.3 Distribution of Executable Versions. In addition, if You +Externally Deploy Covered Code (Original Code and/or Modifications) in +object code, executable form only, You must include a prominent +notice, in the code itself as well as in related documentation, +stating that Source Code of the Covered Code is available under the +terms of this License with information on how and where to obtain such +Source Code. + +2.4 Third Party Rights. You expressly acknowledge and agree that +although Apple and each Contributor grants the licenses to their +respective portions of the Covered Code set forth herein, no +assurances are provided by Apple or any Contributor that the Covered +Code does not infringe the patent or other intellectual property +rights of any other entity. Apple and each Contributor disclaim any +liability to You for claims brought by any other entity based on +infringement of intellectual property rights or otherwise. As a +condition to exercising the rights and licenses granted hereunder, You +hereby assume sole responsibility to secure any other intellectual +property rights needed, if any. For example, if a third party patent +license is required to allow You to distribute the Covered Code, it is +Your responsibility to acquire that license before distributing the +Covered Code. + +3. Your Grants. In consideration of, and as a condition to, the +licenses granted to You under this License, You hereby grant to any +person or entity receiving or distributing Covered Code under this +License a non-exclusive, royalty-free, perpetual, irrevocable license, +under Your Applicable Patent Rights and other intellectual property +rights (other than patent) owned or controlled by You, to use, +reproduce, display, perform, modify, sublicense, distribute and +Externally Deploy Your Modifications of the same scope and extent as +Apple's licenses under Sections 2.1 and 2.2 above. + +4. Larger Works. You may create a Larger Work by combining Covered +Code with other code not governed by the terms of this License and +distribute the Larger Work as a single product. In each such instance, +You must make sure the requirements of this License are fulfilled for +the Covered Code or any portion thereof. + +5. Limitations on Patent License. Except as expressly stated in +Section 2, no other patent rights, express or implied, are granted by +Apple herein. Modifications and/or Larger Works may require additional +patent licenses from Apple which Apple may grant in its sole +discretion. + +6. Additional Terms. You may choose to offer, and to charge a fee for, +warranty, support, indemnity or liability obligations and/or other +rights consistent with the scope of the license granted herein +("Additional Terms") to one or more recipients of Covered Code. +However, You may do so only on Your own behalf and as Your sole +responsibility, and not on behalf of Apple or any Contributor. You +must obtain the recipient's agreement that any such Additional Terms +are offered by You alone, and You hereby agree to indemnify, defend +and hold Apple and every Contributor harmless for any liability +incurred by or claims asserted against Apple or such Contributor by +reason of any such Additional Terms. + +7. Versions of the License. Apple may publish revised and/or new +versions of this License from time to time. Each version will be given +a distinguishing version number. Once Original Code has been published +under a particular version of this License, You may continue to use it +under the terms of that version. You may also choose to use such +Original Code under the terms of any subsequent version of this +License published by Apple. No one other than Apple has the right to +modify the terms applicable to Covered Code created under this +License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in +part pre-release, untested, or not fully tested works. The Covered +Code may contain errors that could cause failures or loss of data, and +may be incomplete or contain inaccuracies. You expressly acknowledge +and agree that use of the Covered Code, or any portion thereof, is at +Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND +WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND +APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE +PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM +ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF +MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR +PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD +PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST +INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE +FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS, +THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR +ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO +ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE +AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. +You acknowledge that the Covered Code is not intended for use in the +operation of nuclear facilities, aircraft navigation, communication +systems, or air traffic control machines in which case the failure of +the Covered Code could lead to death, personal injury, or severe +physical or environmental damage. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO +EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING +TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR +ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY, +TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF +APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY +REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF +INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY +TO YOU. In no event shall Apple's total liability to You for all +damages (other than as may be required by applicable law) under this +License exceed the amount of fifty dollars ($50.00). + +10. Trademarks. This License does not grant any rights to use the +trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS", +"QuickTime", "QuickTime Streaming Server" or any other trademarks, +service marks, logos or trade names belonging to Apple (collectively +"Apple Marks") or to any trademark, service mark, logo or trade name +belonging to any Contributor. You agree not to use any Apple Marks in +or as part of the name of products derived from the Original Code or +to endorse or promote products derived from the Original Code other +than as expressly permitted by and in strict compliance at all times +with Apple's third party trademark usage guidelines which are posted +at http://www.apple.com/legal/guidelinesfor3rdparties.html. + +11. Ownership. Subject to the licenses granted under this License, +each Contributor retains all rights, title and interest in and to any +Modifications made by such Contributor. Apple retains all rights, +title and interest in and to the Original Code and any Modifications +made by or on behalf of Apple ("Apple Modifications"), and such Apple +Modifications will not be automatically subject to this License. Apple +may, at its sole discretion, choose to license such Apple +Modifications under this License, or on different terms from those +contained in this License or may choose not to license them at all. + +12. Termination. + +12.1 Termination. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Apple if You fail to comply with +any term(s) of this License and fail to cure such breach within 30 +days of becoming aware of such breach; + +(b) immediately in the event of the circumstances described in Section +13.5(b); or + +(c) automatically without notice from Apple if You, at any time during +the term of this License, commence an action for patent infringement +against Apple; provided that Apple did not first commence +an action for patent infringement against You in that instance. + +12.2 Effect of Termination. Upon termination, You agree to immediately +stop any further use, reproduction, modification, sublicensing and +distribution of the Covered Code. All sublicenses to the Covered Code +which have been properly granted prior to termination shall survive +any termination of this License. Provisions which, by their nature, +should remain in effect beyond the termination of this License shall +survive, including but not limited to Sections 3, 5, 8, 9, 10, 11, +12.2 and 13. No party will be liable to any other for compensation, +indemnity or damages of any sort solely as a result of terminating +this License in accordance with its terms, and termination of this +License will be without prejudice to any other right or remedy of +any party. + +13. Miscellaneous. + +13.1 Government End Users. The Covered Code is a "commercial item" as +defined in FAR 2.101. Government software and technical data rights in +the Covered Code include only those rights customarily provided to the +public as defined in this License. This customary commercial license +in technical data and software is provided in accordance with FAR +12.211 (Technical Data) and 12.212 (Computer Software) and, for +Department of Defense purchases, DFAR 252.227-7015 (Technical Data -- +Commercial Items) and 227.7202-3 (Rights in Commercial Computer +Software or Computer Software Documentation). Accordingly, all U.S. +Government End Users acquire Covered Code with only those rights set +forth herein. + +13.2 Relationship of Parties. This License will not be construed as +creating an agency, partnership, joint venture or any other form of +legal association between or among You, Apple or any Contributor, and +You will not represent to the contrary, whether expressly, by +implication, appearance or otherwise. + +13.3 Independent Development. Nothing in this License will impair +Apple's right to acquire, license, develop, have others develop for +it, market and/or distribute technology or products that perform the +same or similar functions as, or otherwise compete with, +Modifications, Larger Works, technology or products that You may +develop, produce, market or distribute. + +13.4 Waiver; Construction. Failure by Apple or any Contributor to +enforce any provision of this License will not be deemed a waiver of +future enforcement of that or any other provision. Any law or +regulation which provides that the language of a contract shall be +construed against the drafter will not apply to this License. + +13.5 Severability. (a) If for any reason a court of competent +jurisdiction finds any provision of this License, or portion thereof, +to be unenforceable, that provision of the License will be enforced to +the maximum extent permissible so as to effect the economic benefits +and intent of the parties, and the remainder of this License will +continue in full force and effect. (b) Notwithstanding the foregoing, +if applicable law prohibits or restricts You from fully and/or +specifically complying with Sections 2 and/or 3 or prevents the +enforceability of either of those Sections, this License will +immediately terminate and You must immediately discontinue any use of +the Covered Code and destroy all copies of it that are in your +possession or control. + +13.6 Dispute Resolution. Any litigation or other dispute resolution +between You and Apple relating to this License shall take place in the +Northern District of California, and You and Apple hereby consent to +the personal jurisdiction of, and venue in, the state and federal +courts within that District with respect to this License. The +application of the United Nations Convention on Contracts for the +International Sale of Goods is expressly excluded. + +13.7 Entire Agreement; Governing Law. This License constitutes the +entire agreement between the parties with respect to the subject +matter hereof. This License shall be governed by the laws of the +United States and the State of California, except that body of +California law concerning conflicts of law. + +Where You are located in the province of Quebec, Canada, the following +clause applies: The parties hereby confirm that they have requested +that this License and all related documents be drafted in English. Les +parties ont exige que le present contrat et tous les documents +connexes soient rediges en anglais. + +EXHIBIT A. + +"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights +Reserved. + +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." diff --git a/FireOpal/ChangeLog b/FireOpal/ChangeLog new file mode 100644 index 0000000..1a79a07 --- /dev/null +++ b/FireOpal/ChangeLog @@ -0,0 +1,542 @@ + +2008-07-10 Nick Kledzik + + * src/LTOReader.hpp: improve missing symbol error message + + +2008-07-08 Nick Kledzik + + ld: add support for mllvm LTO options + * src/Options.cpp: support -mllvm option + * src/LTOReader.hpp: call lto_codegen_debug_options() with -mllvm options + * src/ld.cpp: pass llvmOptions to optimize() + * src/Options.h: add fLLVMOptions + * src/ArchiveReader.hpp: add llvmOptions parameter to optimize() + * src/ObjectFile.h: add llvmOptions parameter to optimize() + * unit-tests/test-cases/lto-llvm-options: add test case + + +2008-06-04 Nick Kledzik + + * src/LTOReader.hpp: if lto_codegen_add_module() fails, add explanation to error message + +2008-06-04 Nick Kledzik + + * src/ObjectFile.h: add deadAtoms parameter to optimize() + * src/ld.cpp: ditto + * src/ArchiveReader.hpp: ditto + * src/MachOReaderRelocatable.hpp: handle llvm use of 0x1B pointer encodings in CIEs + * src/LTOReader.hpp: make sure libLTO.dylib knows about any llvm symbol coalesced away + * unit-tests/test-cases/lto-weak-native-override: add test case + + +2008-06-04 Nick Kledzik + + LTO : 176.gcc and 177.mesa build failure at -O4 + * src/LTOReader.hpp: make sure internal is returned by getAtoms() + * unit-tests/test-cases/lto-archive-dylib: update test case + + +2008-05-06 Nick Kledzik + + ARM ld should take W bit off of maxprot for __TEXT segment + * src/MachOWriterExecutable.hpp: for iPhone always set maxprot to be initprot in all segments + + +2008-05-06 Nick Kledzik + + encryptable images may not be signable + * src/MachOWriterExecutable.hpp: use minimum header padding when aligning __text section + + +----- Tagged ld64-85 (Xcode 3.1) + +2008-04-29 Nick Kledzik + + * ld64.xcodeproj/project.pbxproj: is moving from /usr/local/include to /Developer/usr/local/include + + +2008-04-29 Nick Kledzik + + ld doesn't honor "rightmost" -syslibroot argument + * src/Options.cpp: if last -syslibroot is /, then ignore all syslibroots + + +2008-04-29 Nick Kledzik + + GLRendererFloat has bad __eh_frame section caused by mixing llvm-gcc and gcc object files + * src/MachOReaderRelocatable.hpp: make all atoms in __eh_frame section have 1-byte alignment + * src/MachOWriterExecutable.hpp: make __eh_frame section have pointer sized alignment + + +2008-04-17 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: better cpu subtype support + + +2008-04-14 Nick Kledzik + + ld64 has bad ARM branch island check + * src/MachOWriterExecutable.hpp: in addBranchIslands() don't force large arm programs to fail + + +2008-04-10 Nick Kledzik + + * src/MachOWriterExecutable.hpp: fix stubs used with lazy dylibs + + +----- Tagged ld64-84.4 + +2008-04-10 Nick Kledzik + + SPEC2000/eon built with -mdynamic-no-pic won't run + * src/Architectures.hpp: added arm::kReadOnlyPointer + * src/MachOReaderRelocatable.hpp: generate arm::kReadOnlyPointer + * src/MachOWriterExecutable.hpp: use arm::kReadOnlyPointer + * src/machochecker.cpp: allow MH_PIE bit + * unit-tests/test-cases/switch-jump-table: added test cases + + +----- Tagged ld64-84.3 + +2008-04-09 Nick Kledzik + + -undefined dynamic_lookup busted + * src/ld.cpp: don't create proxy atom when scanning for dylib duplicates + * unit-tests/test-cases/tentative-and-archive: use -undefined dynamic_lookup + + +----- Tagged ld64-84.2 + +2008-04-04 Nick Kledzik + + * src/ld.cpp: don't add .eh symbols to symbol table in -r mode + * unit-tests/test-cases/eh-coalescing-r: update to test out of order coalescing + + +----- Tagged ld64-84.1 + +2008-03-28 Nick Kledzik + + ld should prefer architecture-specific variant over generic in fat object file + * src/Options.cpp: fully process -arch arguments into fArchitecture and fSubArchitecture + * src/ld.cpp: when -arch with a subtype is used, try to find the exact subtype from fat files + * unit-tests/test-cases/cpu-sub-types-preference: added test cases for arm and ppc + + +----- Tagged ld64-84 + +2008-03-28 Nick Kledzik + + * src/LTOReader.hpp: don't print lto version, if lto is unavailable + + +2008-03-26 Nick Kledzik + + Add LD_WARN_COMMONS to BigBear builds + * src/Options.cpp: Add support for LD_WARN_FILE which copies all warnings to a side file + + +2008-03-26 Nick Kledzik + + Need encryption tag in mach-o file + linker should adjust arm final linked images so __text is never on the same page as the load commands + * src/MachOFileAbstraction.hpp: add support for encryption_info_command + * src/Options.cpp: add support for LD_NO_ENCRYPT and -no_encryption + * src/MachOWriterExecutable.hpp: add EncryptionLoadCommandsAtom + * src/machochecker.cpp: validate LC_ENCRYPTION_INFO + + +2008-03-25 Nick Kledzik + + ld64 does not recognize LLVM bitcode archive files + * src/MachOReaderArchive.hpp: renamed to src/ArchiveReader.hpp + * src/ArchiveReader.hpp: sniff each member and instantiate correct reader + * src/ld.cpp: rename mach_o::archive::Reader to archive::Reader + * ld64.xcodeproj/project.pbxproj: rename MachOReaderArchive.hpp to ArchiveReader.hpp + * unit-tests/test-cases/llvm-integration: added test case + + +2008-03-25 Nick Kledzik + + ld64 should switch to new libLTO.dylib interface + Produce llvm bc file in 'ld -r' mode if all .o files are llvm bc + * src/LTOReader.hpp: rewrite from LLVMReader.hpp to use new lto_* C interface + * unit-tests/test-cases/llvm-integration: update and comment + * ld64.xcodeproj/project.pbxproj: update to lazy load libLTO.dylib + * src/ld.cpp: rework and simplify Linker::optimize() + * src/ObjectDump.cpp: Add -nm option + + +2008-03-25 Nick Kledzik + + * src/MachOReaderRelocatable.cpp: Fix some .objc_class_name_ off by one problem + * src/MachOWriterExecutable.cpp: Fix some .objc_class_name_ off by one problem + + +2008-03-24 Nick Kledzik + + Xcode 3.1 breaks linkage of libgcj.9.dylib from gcc 4.3.0 + * src/MachOWriterExecutable.cpp: Make sure all ivars in Writer are initialized. + + +2008-03-21 Nick Kledzik + + * src/Options.cpp: warn if -seg1addr value is not page aligned + + +2008-03-21 Nick Kledzik + + Move ARM support outside of __OPEN_SOURCE__ + * src/ld.cpp: remove __OPEN_SOURCE__ around arm support + * src/LLVMReader.hpp: remove __OPEN_SOURCE__ around arm support + * src/MachOReaderDylib.hpp: remove __OPEN_SOURCE__ around arm support + * src/ObjectFile.h: remove __OPEN_SOURCE__ around arm support + * src/MachOReaderRelocatable.hpp: remove __OPEN_SOURCE__ around arm support + * src/OpaqueSection.hpp: Cover arm support inside __OPEN_SOURCE__ macro check + * src/MachOWriterExecutable.hpp: remove __OPEN_SOURCE__ around arm support + * src/ObjectDump.cpp: remove __OPEN_SOURCE__ around arm support + * ld64.xcodeproj/project.pbxproj: remove ARM_SUPPORT from config.h + + +----- Tagged ld64-83.2 + +2008-03-15 Nick Kledzik + + ld64-83 removes OBJC_CLASS_$ symbols from projects, causes catastrophic results + * src/Options.cpp: restore "case CPU_TYPE_ARM" in switch statement for .objc_class symbols in .exp files + * unit-tests/test-cases/objc-exported_symbols_list: added test case + + +----- Tagged ld64-83.1 + +2008-03-14 Nick Kledzik + + -iphone_version_min ==> -iphoneos_version_min + * src/Options.cpp: support -iphoneos_version_min as well + + +----- Tagged ld64-83 + +2008-03-10 Nick Kledzik + + ld needs to strip iphone_version_min option if invoking ld_classic + * src/Options.cpp: suppress -iphone_version_min from being passed to ld_classic + + +2008-03-04 Nick Kledzik + + ADOBE XCODE: Linker option to lazy load frameworks (cause dyld is too slow) + * src/MachOWriterExecutable.hpp: create lazy stubs and LC_LAZY_LOAD_DYLIB for lazy load dylibs + * src/Options.cpp: support -lazy-l, -lazy_library, and -lazy_framework + * src/MachOFileAbstraction.hpp: add LC_LAZY_LOAD_DYLIB and S_LAZY_DYLIB_SYMBOL_POINTERS until in cctools + * src/MachOReaderDylib.hpp: add isLazyLoadedDylib() + * src/ld.cpp: pass lazy helper atom to writer + * doc/man/man1/ld.1: document new options + * unit-tests/test-cases/lazy-dylib-objc: add test case + * unit-tests/test-cases/lazy-dylib: add test case + + +----- Tagged ld64-82.7 + +2008-03-07 Nick Kledzik + + duplicate symbol literal-pointer@__OBJC@__message_refs@... + * src/MachOReaderRelocatable.hpp: AnonymousAtom from S_LITERAL_POINTERS section should be weak + * unit-tests/test-cases/objc-selector-coalescing: added test case + + +----- Tagged ld64-82.6 + +2008-03-04 Nick Kledzik + + ld crashes building XsanFS for Snow Leopard Builds + * src/ld.cpp: add bool dylibsOnly parameter to addJustInTimeAtoms() + * unit-tests/test-cases/tentative-and-archive: added test case + +2008-03-04 Nick Kledzik + + ld64 should not force building with gcc 4.0 + * ld64.xcodeproj/project.pbxproj: change rules to use "system" compiler instead of 4.0 + + +2008-02-29 Nick Kledzik + + Simulator frameworks are being build split-seg and not prebound + * src/Options.cpp: only splitseg if prebound + + +2008-02-29 Nick Kledzik + + Linker should not make GSYM debug note for .objc_category_* symbols + * src/ld.cpp: suppress GSYM debug notes for absolute symbols + * unit-tests/test-cases/objc-category-debug-notes: added test case + + +2008-02-29 Nick Kledzik + + non-ASCII CFString support is broken + * src/MachOReaderRelocatable.hpp: only name and coalesce cfstring constants if they use a __cstring + * unit-tests/test-cases/cfstring-utf16: add test case + + +2008-02-25 Nick Kledzik + + ld -r -x + * doc/man/man1/ld.1: update man page to explain -r -x produces auto-stripped labels + + +----- Tagged ld64-82.5 + +2008-02-12 Nick Kledzik + + x86_64: -stack_size failure when large __bss is used + * src/ld.cpp: only move section already in __DATA segment to new __huge section + * unit-tests/test-cases/stack_size_no_addr: updated test case to add large bss section + + +----- Tagged ld64-82.4 + +2008-02-06 Nick Kledzik + + comdat warnings with ld -r of C++ .o files + * unit-tests/test-cases/eh-coalescing-r: added test case + * src/ld.cpp: in ld -r mode don't warn about if .eh symbols are not static + + +2008-02-06 Devang Patel + + LTO of Bom framework with -dead_strip causes ld(1) crash + * src/LLVMReader.hpp: Check fAtom while determining LLVMReference target binding. + * unit-tests/test-cases/llvm-integration/Makefile: Add new test case. + * unit-tests/test-cases/llvm-integration/a15.c: New. + * unit-tests/test-cases/llvm-integration/b15.c: New. + * unit-tests/test-cases/llvm-integration/c15.c: New. + +2008-02-05 Nick Kledzik + + * src/ld.cpp: fix for -arch ppc -mdynamic-no-pic -pie so PPC_RELOC_HA16 reloc is used + +----- Tagged ld64-82.3 + +2008-02-04 Nick Kledzik + + ld doesn't seem to understand $ld$add$os... and $ld$hide$os... for 10.6 moves + * src/ObjectFile.h: add 10.6 + * src/Options.cpp: add 10.6 support + * src/MachOReaderDylib.hpp: recognize $os10.6$ + + +----- Tagged ld64-82.2 + +2008-01-30 Devang Patel + + Can't build 64-bit Intel binaries with LTO + ld64 fails to build with llvm-gcc-4.2 + * src/LLVMReader.hpp: Fix character count typo in strncmp call. + Use const char * to initialize temp. string. + * ld64.xcodeproj/project.pbxproj: use $(DEVELOPER_DIR) in header search construction + instead of hard coding /Developer. + +----- Tagged ld64-82.1 + +2008-01-23 Nick Kledzik + + * src/MachOReaderRelocatable.hpp: don't bus error if S_LITERAL_POINTERS is missing relocs + + +2008-01-22 Nick Kledzik + + ld uses 32-bits in some places to hold addresses when parsing 64-bit mach-o files + * src/MachOReaderRelocatable.hpp: use AddrToAtomMap type that switch address to 64-bits for 64-bit archs + * src/MachOWriterExecutable.hpp: verify BR14 does not overflow for external relocs + * unit-tests/test-cases/relocs-c: update test case to slide addresses to verify x86_64 .o files + + +----- Tagged ld64-82 + +2008-01-18 Nick Kledzik + + Bad grammar used in ld warning: cannot exported hidden symbol + * src/ld.cpp: fix typo in warning string + + +2008-01-16 Nick Kledzik + + Bundle Loader does not work anymore when loader is a bundle + ld warns of incorrect architecture when linking a bundle to a bundle + * src/MachOReaderDylib.hpp: support linking against bundles via -bundle_loader. Clean up error messages + * unit-tests/test-cases/bundle_loader: update test case + + +2008-01-16 Nick Kledzik + + ld -r -x creates debug notes (stabs) when it should not with -x (keep only global symbols) + * src/Options.cpp: in reconfigureDefaults() if -r and -x then -S + + +2008-01-16 Nick Kledzik + + if ld crashes while writing output file, it should delete the half written file + * src/MachOWriterExecutable.hpp: wrap open/write/close in try block and add signal handlers all to delete + output file on failure. + + +2008-01-16 Devang Patel + + * src/LLVMReader.hpp: Use __gnu_cxx::hash_map instead of hash supported by LLVM. + + +2008-01-16 Nick Kledzik + + GC-supported library can't be linked into GC-required executable + * src/ld.cpp: loosen constraint that all objc code must be compiled with same GC settings and + allow gc-compatible code to be linked into anything. + * unit-tests/test-cases/objc-gc-checks: update test case + + +2008-01-15 Nick Kledzik + + no debug notes for custom named data + * src/ld.cpp: in synthesizeDebugNotes() check getSymbolTableInclusion() instead of for leading underscore + * unit-tests/test-cases/dwarf-debug-notes: update test case + +----- Tagged ld64-81.5 + +2008-01-14 Devang Patel + + llvm-gcc-4.2 fails to build Sqlite 3.5.4 with -O4 + * src/LLVMReader.hpp: Resolve proxy references. Collect new unbounded references + after optimization. + * src/ld.cpp: Resolve additional unbounded references after optimization. + + +2008-01-14 Nick Kledzik + + PPC Leopard (Xcode 3.0) linker ld gets "Bus error" sometimes + * src/MachOReaderRelocatable.hpp: use same code as x86 to parse ppc and arm sect-diff relocs + * src/MachOWriterExecutable.hpp: use same code as x86 to write ppc and arm sect-diff relocs + + +2008-01-11 Nick Kledzik + + PPC Leopard (Xcode 3.0) linker ld reports "unknown scattered relocation type 4" + * src/MachOReaderRelocatable.hpp: add PPC_RELOC_HI16 to scattered reloc parsing + * unit-tests/test-cases/relocs-asm/relocs-asm.s: added tests for scattered hi/lo instructions + + +2008-01-11 Nick Kledzik + + * doc/man/man1/ld.1: add doc for -no_implicit_dylibs, -read_only_stubs, -slow_stubs, -interposable_list + + +2008-01-11 Nick Kledzik + + ld64(1) man page uses ambiguous term "suffix" + * doc/man/man1/ld.1: make meaning of "suffix" more explicit + + +2008-01-11 Nick Kledzik + + Obj-C Symbols in Leopard Can't Be Weak Linked + * src/MachOWriterExecutable.hpp: set weak and lazy attributes on dummy .objc_class_name undefines + to dylibs to support Mac OS X 10.3.x dyld + + +2008-01-11 Nick Kledzik + + Unknown error with linker (dyld: unknown external relocation type) + * src/ld.cpp: fix crash when SO stabs are not balanced + + +2008-01-11 Devang Patel + + LTO does not work if expected output is a dynamic library + * src/LLVMReader.hpp: Supply arguments describing output kind to optimizer. Communicate + visibility info. + +2000-01-10 Nick Kledzik + + __cls_refs section is losing S_LITERAL_POINTERS section type + * src/MachOWriterExecutable.hpp: special case __cls_refs section + * unit-tests/test-cases/objc-literal-pointers: add test case + + +2008-01-03 Nick Kledzik + + wrong EH information might be used + Created new kGroupSubordinate reference kind to model group comdat. The "signature" atom + has kGroupSubordinate references to the other atoms in the group. If the signature atom + is coalesced away, the linker follows kGroupSubordinate references and throws away the + other members of the group. + * unit-tests/test-cases/eh-coalescing: added test case + * src/ld.cpp: added markDead() and use propagate to subordinates + * src/Architectures.hpp: added kGroupSubordinate + * src/MachOReaderRelocatable.hpp: add kGroupSubordinate reference from a function to its .eh atom + and if used, from .eh atom to its LSDA atom. + * src/MachOWriterExecutable.hpp: handle kGroupSubordinate like kNoFixUp + +----- Tagged ld64-81.4.1 + +2007-12-19 Devang Patel + + * src/LLVMReader.hpp: Add LLVM_LTO_VERSION #ifdef check. + +2007-12-19 Devang Patel + + * src/LLVMReader.hpp: Add fOptimizer NULL check before calling printVersion(). + +2007-12-19 Devang Patel + + print LLVM LTO version number in verbose mode + * src/LLVMReader.hpp: Add printLLVMVersion() to print llvm version string in verbose mode. + * src/Options.cpp: Use printLLVMVersion() in verbose mode. + +2007-12-19 Devang Patel + + print LLVM LTO version number in verbose mode + * src/Options.h: Add verbose() method to check fVerbose flag. + * src/LLVMReader.hpp: Print LLVM version string in verbose mode. + +----- Tagged ld64-81.4 + +2007-12-18 Devang Patel + + * src/LLVMReader.hpp: Invalidate input architecture when optimizer is not available. + +----- Tagged ld64-81.3 + +2007-12-17 Nick Kledzik + + * ld64.xcodeproj/project.pbxproj: remove extraneous header search paths + + +2007-12-17 Devang Patel + + * src/LLVMReader.hpp: Do not throw exception if LLVMReader is not able to + dlopen LTO library. Instead just flag input file as an invalid LLVM bitcode file. + + +2007-12-14 Nick Kledzik + + gcc DejaGnu failure: gcc.dg/20020312-2.c (test for excess errors) (-fstack-protector-all) + * src/MachOWriterExecutable.hpp: fix Writer::generatesExternalTextReloc() to allow text relocs + * unit-tests/test-cases/read-only-relocs: updated test case to link a dynamic main executable compiled with -static + + +2007-12-14 Devang Patel + + Enable Link Time Optimization in Opal + * src/LLVMReader.hpp: Locate LLVMlto.dylib relative to ld location in Developer folder. + * ld64.xcodeproj/project.pbxproj: Add {DEVELOPER_DIR}/usr/include in header search path. + * unit-tests/run-all-unit-tests: Set DYLD_FALLBACK_LIBRARY_PATH to find LLVMlto.dylib during unit testing. + * unit-tests/testcases/llvm-integration/Makefile: Point LLVMGCC and LLVMGXX to llvm-gcc-4.2 in Developer folder during unit testing. + + +2007-12-13 Nick Kledzik + + SWB: failures due to ld: pointer in read-only segment not allowed in slidable image, used in ... + * src/MachOReaderRelocatable.hpp: in Reader::addRelocReference() handle weak pc-rel 32-bit vanilla relocs properly + +----- Tagged ld64-81.2 + diff --git a/FireOpal/doc/man/man1/ld.1 b/FireOpal/doc/man/man1/ld.1 new file mode 100644 index 0000000..a8b0188 --- /dev/null +++ b/FireOpal/doc/man/man1/ld.1 @@ -0,0 +1,676 @@ +.Dd December 8, 2006 +.Dt ld 1 +.Os Darwin +.Sh NAME +.Nm ld +.Nd "linker" +.Sh SYNOPSIS +.Nm +files... +.Op options +.Op Fl o Ar outputfile +.Sh DESCRIPTION +The +.Nm ld +command combines several object files and libraries, resolves references, and +produces an ouput file. +.Nm ld +can produce a final linked image (executable, dylib, or bundle), or with the -r +option, produce another object file. If the -o option is not used, the output +file produced is named "a.out". +.Ss Universal +The linker accepts universal (multiple-architecture) input files, but +always creates a "thin" (single-architecture), standard Mach-O output file. +The architecture for the output file is specified using the -arch option. +If this option is not used, +.Nm ld +attempts to determine the output architecture by examining the object +files in command line order. The first "thin" +architecture determines that of the output file. If no input +object file is a "thin" file, the native 32-bit architecture for the host is used. +.Pp +Usually, +.Nm ld +is not used directly. Instead the +.Xr gcc(1) +compiler driver invokes +.Nm ld. +The compiler driver can be passed multiple -arch options and it will create a +universal final linked image by invoking +.Nm ld +multiple times and then running +.Xr lipo(1) +merge the outputs into a universal file. +.Ss Layout +The object files are loaded in the order in which they are specified on the +command line. The segments and the sections in those segments will appear in +the output file in the order they are encountered in the object files being linked. +All zero fill sections will appear after all non-zero fill sections in their segments. +Sections created from files with the -sectcreate option will be laid out at after +sections from .o files. The use of the -order_file option will alter the layout +rules above, and move the symbols specified to start of their section. +.Ss Libraries +A static library (aka static archive) is a collection of .o files with a table of contents +that lists the global symbols in the .o files. +.Nm ld +will only pull .o files out of a static library if needed to resolve some symbol reference. +Unlike traditional linkers, +.Nm ld +will continually search a static library while linking. There is no need to specify a static +library multiple times on the command line. +.Pp +A dynamic library (aka dylib or framework) is a final linked image. Putting a dynamic +library on the command line causes two things: 1) The generated final linked image +will have encoded that it depends on that dynamic library. 2) Exported symbols from the +dynamic library are used to resolve references. +.Pp +Both dynamic and static libraries are searched as they appear on the command line. +.Ss Search paths +.Nm ld +maintains a list of directories to search for a library or framework to use. The default +library search path is /usr/lib then /usr/local/lib. The -L option will add a new library search +path. The default framework search path is /Library/Frameworks then /System/Library/Frameworks. +(Note: previously, /Network/Library/Frameworks was at the end of the default path. If you need +that functionality, you need to explicitly add -F/Network/Library/Frameworks). +The -F option will a new framework search path. The -Z option will remove +the standard search paths. The -syslibroot option will prepend a prefix to all search +paths. +.Ss Two-level namespace +By default all references resolved to a dynamic library record the library to which +they were resolved. At runtime, dyld uses that information to directly resolve +symobls. The alternative is to use the -flat_namespace option. With flat namespace, +the library is not recorded. At runtime, dyld will search each dynamic library in load +order when resolving symbols. This is slower, but more like how other operating systems +resolve symbols. +.Ss Indirect dynamic libraries +If the command line specifies to link against dylib A, and when dylib A was built it linked +against dylib B, then B is considered an indirect dylib. +When linking for two-level namespace, ld does not look at indirect dylibs, except when +re-exported by a direct dylibs. On the other hand when linking for flat namespace, +ld does load all indirect dylibs and uses them to resolve references. +Even though indirect dylibs are specified via a full path, +.Nm ld +first uses the specified search paths to locate each indirect dylib. If one cannot +be found using the search paths, the full path is used. +.Ss Dynamic libraries undefines +When linking for two-level namespace, +.Nm ld +does not verify that undefines in dylibs actually +exist. But when linking for flat namespace, +.Nm ld +does check that all undefines from all loaded dylibs have a matching definition. +This is sometimes used to force selected functions to be loaded from a static library. +.Sh OPTIONS +.Ss Options that control the kind of output +.Bl -tag +.It Fl execute +The default. Produce a mach-o main executable that has file type MH_EXECUTE. +.It Fl dylib +Produce a mach-o shared library that has file type MH_DYLIB. +.It Fl bundle +Produce a mach-o bundle that has file type MH_BUNDLE. +.It Fl r +Merges object files to produce another mach-o object file with file type MH_OBJECT. +.It Fl dylinker +Produce a mach-o dylinker that has file type MH_DYLINKER. Only used when building dyld. +.It Fl dynamic +The default. Implied by -dynamiclib, -bundle, or -execute +.It Fl static +Produces a mach-o file that does not use the dyld. Only used building the kernel. +.It Fl arch Ar arch_name +Specifies which architecture (e.g. ppc, ppc64, i386, x86_64) the output file should be. +.It Fl o Ar path +Specifies the name and location of the output file. If not specified, `a.out' is used. +.El +.Ss Options that control libraries +.Bl -tag +.It Fl l Ns x +This option tells the linker to search for libx.dylib or libx.a in the library search path. +If string x is of the form y.o, then that file is searched for in the same places, but without +prepending `lib' or appending `.a' or `.dylib' to the filename. +.It Fl weak-l Ns Ar x +This is the same as the -lx but forces the library and all references to it to be marked as weak imports. +That is, the library is allowed to be missing at runtime. +.It Fl weak_library Ar path_to_library +This is the same as listing a file name path to a library on the link line except that it forces the +library and all references to it to be marked as weak imports. +.It Fl reexport-l Ns Ar x +This is the same as the -lx but specifies that the all symbols in library x should be available to +clients linking to the library being created. This was previously done with a separate -sub_library option. +.It Fl reexport_library Ar path_to_library +This is the same as listing a file name path to a library on the link line and it specifies that the +all symbols in library path should be available to clients linking to the library being created. +This was previously done with a separate -sub_library option. +.It Fl lazy-l Ns Ar x +This is the same as the -lx but it is only for shared libraries and the linker +will construct glue code so that the shared library is not loaded until +the first function in it is called. +.It Fl lazy_library Ar path_to_library +This is the same as listing a file name path to a shared library on the link line +except that the linker will construct glue code so that the shared library is not +loaded until the first function in it is called. +.It Fl L Ns dir +Add +.Ar dir +to the list of directories in which to search for libraries. +Directories specified with -L are searched in the order they appear on the command line +and before the default search path. +.It Fl Z +Do not search the standard directories when searching for libraries and frameworks. +.It Fl syslibroot Ar rootdir +Prepend +.Ar rootdir +to all search paths when searching for libraries or frameworks. +.It Fl search_paths_first +By default the -lx and -weak-lx options first search for a file of the form `libx.dylib' in each directory +in the library search path, then a file of the form `libx.a' is searched for in the library search paths. +This option changes it so that in each path `libx.dylib' is searched for then `libx.a' before the +next path in the library search path is searched. +.It Fl framework Ar name[,suffix] +This option tells the linker to search for `name.framework/name' the framework search path. +If the optional suffix is specified the framework is first searched for the name with the suffix and then without +(e.g. look for `name.framework/name_suffix' first, if not there try `name.framework/name'). +.It Fl weak_framework Ar name[,suffix] +This is the same as the -framework name[,suffix] but forces the framework and all +references to it to be marked as weak imports. +.It Fl reexport_framework Ar name[,suffix] +This is the same as the -framework name[,suffix] but also specifies that the +all symbols in that framework should be available to clients linking to the library being created. +This was previously done with a separate -sub_umbrella option. +.It Fl lazy_framework Ar name[,suffix] +This is the same as the -framework name[,suffix] except that the linker will +construct glue code so that the framework is not +loaded until the first function in it is called. You cannot directly access +data or Objective-C classes in a frameworked linked this way. +.It Fl F Ns dir +Add +.Ar dir +to the list of directories in which to search for frameworks. +Directories specified with -F are searched in the order they appear on the command line +and before the default search path. +.It Fl all_load +Loads all members of static archive libraries. +.It Fl ObjC +Loads all members of static archive libraries that implement an Objective-C class or category. +.El +.Ss Options that control additional content +.Bl -tag +.It Fl sectcreate Ar segname sectname file +The section +.Ar sectname +in the segment +.Ar segname +is created from the contents of file +.Ar file. +The combination of segname and sectname must be unique Ð there cannot already be a section (segname,sectname) +from any other input. +.It Fl filelist Ar file[,dirname] +Specifies that the linker should link the files listed in +.Ar file . +This is an alternative to listing the files on the command line. +The file names are listed one per line separated only by newlines. (Spaces and tabs are assumed to be part of the file name.) +If the optional directory name, +.Ar dirname +is specified, it is prepended to each name in the list file. +.It Fl dtrace Ar file +Enables dtrace static probes when producing a final linked image. The file +.Ar file +must be a DTrace script which declares the static probes. +.El +.Ss Options that control optimizations +.Bl -tag +.It Fl dead_strip +Remove functions and data that are unreachable by the entry point or exported symbols. +.It Fl dead_strip_dylibs +Remove dylibs that are unreachable by the entry point or exported symbols. That is, +suppresses the generation of load command commands for dylibs which supplied no +symbols during the link. This option should not be used when linking against a dylib which +is required at runtime for some indirect reason such as the dylib has an important initializer. +.It Fl order_file Ar file +Alters the order in which functions and data are laid out. For each section in the output file, +any symbol in that section that are specified in the order file +.Ar file +is moved to the start of its section and laid out in the same order as in the order file +.Ar file . +Order files are text files with one symbol name per line. Lines starting with a # are comments. +A symbol name may be optionally preceded with its object file leafname and a colon (e.g. foo.o:_foo). +This is useful for static functions/data that occur in multiple files. +A symbol name may also be optionally preceded with the architecture (e.g. ppc:_foo or ppc:foo.o:_foo). +This enables you to have one order file that works for multiple architectures. +Literal c-strings may be ordered by by quoting the string (e.g. "Hello, world\\n") in the order file. +.It Fl macosx_version_min Ar version +This is set to indicate the oldest Mac OS X version that that the output is to be used on. Specifying +a later version enables the linker to assumes features of that OS in the output file. The format of +.Ar version +is a Mac OS X version number such as 10.4 or 10.5 +.It Fl image_base Ar address +Specifies the perferred load address for a dylib or bundle. The argument +.Ar address +is a hexadecimal number with an optional leading 0x. By choosing non-overlapping address for all +dylibs and bundles that a program loads, launch time can be improved because dyld will not need to +"rebase" the image (that is, adjust pointers within the image to work at the loaded address). +It is often easier to not use this option, but instead use the rebase(1) tool, and give it a list of dylibs. +It will then choose non-overlapping addresses for the list and rebase them all. +This option is also called -seg1addr for compatibility. +.It Fl no_implicit_dylibs +When creating a two-level namespace final linked image, normally the linker will hoist up public dylibs +that are implicitly linked to make the two-level namespace +encoding more efficient for dyld. For example, Cocoa re-exports AppKit and AppKit re-exports Foundation. +If you link with -framework Cocoa and use a symbol from Foundation, the linker will implicitly add a load +command to load Foundation and encode the symbol as coming from Foundation. If you use this option, +the linker will not add a load command for Foundation and encode the symbol as coming from Cocoa. Then +at runtime dyld will have to search Cocoa and AppKit before finding the symbol in Foundation. +.El +.Ss Options when creating a dynamic library (dylib) +.Bl -tag +.It Fl install_name Ar name +Sets an internal "install path" (LC_ID_DYLIB) in a dynamic library. Any clients linked against the library +will record that path as the way dyld should locate this library. If this option is not specified, then +the -o path will be used. This option is also called -dylib_install_name for compatibility. +.It Fl compatibility_version Ar number +Specifies the compatibility version number of the library. When a library is loaded by dyld, the +compatibility version is checked and if the program's version is greater that the library's version, it is an error. +The format of +.Ar number +is X[.Y[.Z]] where X must be a positive non-zero number less than or equal to 65535, +and .Y and .Z are optional and if present must be non-negative numbers less than or equal to 255. +If the compatibility version number is not specified, it has a value of 0 and no checking is done when the library is used. +This option is also called -dylib_compatibility_version for compatibility. +.It Fl current_version Ar number +Specifies the current version number of the library. The current version of the library can be obtained +programmatically by the user of the library so it can determine exactly which version of the library it is using. +The format of +.Ar number +is X[.Y[.Z]] where X must be a positive non-zero number less than or equal to 65535, +and .Y and .Z are optional and if present must be non-negative numbers less than or equal to 255. +If the version number is not specified, it has a value of 0. +This option is also called -dylib_current_version for compatibility. +.El +.Ss Options when creating a main executable +.Bl -tag +.It Fl pie +This makes a special kind of main executable that is position independent (PIE). On Mac OS X 10.5, the OS +will load a PIE at a random address each time it is executed. You cannot create a PIE from .o files compiled +with -mdynamic-no-pic. That means the codegen is less optimal, but the address randomization adds some +security. +.It Fl pagezero_size Ar size +By default the linker creates an unreadable segment starting at address zero named __PAGEZERO. Its existence +will cause a bus error if a NULL pointer is dereferenced. The argument +.Ar size +is a hexadecimal number with an optional leading 0x. If +.Ar size +is zero, the linker will not generate a page zero segment. By default on 32-bit architectures the page zero size +is 4KB. On 64-bit architectures, the default size if 4GB. The ppc64 architecture has some special cases. Since Mac +OS X 10.4 did not support 4GB page zero programs, the default page zero size for ppc64 will be 4KB unless +-macosx_version_min is 10.5 or later. Also, the -mdynamic-no-pic codegen model for ppc64 will only work if the +code is placed in the lower 2GB of the address space, so the if the linker detects any such code, the page zero +size is set to 4KB and then a new unredable trailing segment is created after the code, filling up the lower 4GB. +.It Fl stack_size Ar size +Specifies the maximum stack size for the main thread in a program. Without this option a program has a 8MB stack. +The argument +.Ar size +is a hexadecimal number with an optional leading 0x. The +.Ar size +should be an even multiple of 4KB, that is the last three hexadecimal digits should be zero. +.It Fl allow_stack_execute +Marks executable so that all stacks in the task will be given stack execution privilege. This includes pthread stacks. +.El +.Ss Options when creating a bundle +.Bl -tag +.It Fl bundle_loader Ar executable +This specifies the +.Ar executable +that will be loading the bundle output file being linked. +Undefined symbols from the bundle are checked against the specified +.Ar executable +like it was one of the +dynamic libraries the bundle was linked with. +.El +.Ss Options when creating an object file +.Bl -tag +.It Fl keep_private_externs +Don't turn private external (aka visibility=hidden) symbols into static symbols, +but rather leave them as private external in the resulting object file. +.It Fl d +Force definition of common symbols. That is, transform tentative defintions into real definitions. +.El +.Ss Options that control symbol resolution +.Bl -tag +.It Fl exported_symbols_list Ar filename +The specified +.Ar filename +contains a list of global symbol names that will remain as global symbols in the output file. +All other global symbols will be treated as if they were marked as __private_extern__ (aka visibility=hidden) +and will not be global in the output file. The symbol names listed in filename must be one per line. +Leading and trailing white space are not part of the symbol name. +Lines starting with # are ignored, as are lines with only white space. +Some wildcards (similar to shell file matching) are supported. The * matches zero or more characters. +The ? matches one character. [abc] matches one character which must be an 'a', 'b', or 'c'. [a-z] matches +any single lower case letter from 'a' to 'z'. +.It Fl exported_symbol Ar symbol +The specified +.Ar symbol +is added to the list of global symbols names that will remain as global symbols in the output file. This +option can be used multiple times. For short lists, this can be more convenient than creating a file and using +-exported_symbols_list. +.It Fl unexported_symbols_list Ar file +The specified +.Ar filename +contains a list of global symbol names that will not remain as global symbols in the output file. +The symbols will be treated as if they were marked as __private_extern__ (aka visibility=hidden) and will not be global +in the output file. The symbol names listed in filename must be one per line. +Leading and trailing white space are not part of the symbol name. +Lines starting with # are ignored, as are lines with only white space. +Some wildcards (similar to shell file matching) are supported. The * matches zero or more characters. +The ? matches one character. [abc] matches one character which must be an 'a', 'b', or 'c'. [a-z] matches +any single lower case letter from 'a' to 'z'. +.It Fl unexported_symbol Ar symbol +The specified +.Ar symbol +is added to the list of global symbols names that will not remain as global symbols in the output file. This +option can be used multiple times. For short lists, this can be more convenient than creating a file and using +-unexported_symbols_list. +.It Fl alias Ar symbol_name Ar alternate_symbol_name +Create an alias named +.Ar alternate_symbol_name +for the symbol +.Ar symbol_name . +By default the alias symbol has global visibility. This option was previous the -idef:indir option. +.It Fl alias_list Ar filename +The specified +.Ar filename +contains a list of aliases. The symbol name and its alias are on one line, separated by whitespace. +Lines starting with # are ignored. +.It Fl flat_namespace +Alters how symbols are resolved at build time and runtime. With -two_levelnamespace (the default), the linker +only searches dylibs on the command line for symbols, and records in which dylib they were found. With -flat_namespace, +the linker searches all dylibs on the command line and all dylibs those original dylibs depend on. The linker +does not record which dylib an external symbol came from, so at runtime dyld again searches all images and uses +the first definition it finds. In addition, any undefines in loaded flat_namespace dylibs must be resolvable +at build time. +.It Fl u Ar symbol_name +Specified that symbol +.Ar symbol_name +must be defined for the link to succeed. This is useful to force selected functions to be loaded +from a static library. +.It Fl U Ar symbol_name +Specified that it is ok for +.Ar symbol_name +to have no definition. With -two_levelnamespace, the resulting symbol will be marked dynamic_lookup which +means dyld will search all loaded images. +.It Fl undefined Ar treatment +Specifies how undefined symbols are to be treated. Options are: error, warning, suppress, or dynamic_lookup. The +default is error. +.It Fl rpath Ar path +Add +.Ar path +to the runpath search path list for image being created. At runtime, dyld uses the runpath when searching +for dylibs whose load path begins with @rpath/. +.It Fl commons Ar treatment +Specifies how commons (aka tentative definitions) are resolved with respect to dylibs. Options are: +ignore_dylibs, use_dylibs, error. The default is ignore_dylibs which means the linker will turn a tentative +definition in an object file into a real definition and not even check dylibs for conflicts. The dylibs +option means the linker should check linked dylibs for definitions and use them to replace tentative definitions +from object files. The error option means the linker should issu an error whenever a tentative definition in an +object file conflicts with an external symbol in a linked dylib. See also -warn_commons. +.El +.Ss Options for introspecting the linker +.Bl -tag +.It Fl why_load +Log why each object file in a static library is loaded. That is, what symbol was needed. Also called -whyload +for compatibility. +.It Fl why_live Ar symbol_name +Logs a chain of references to +.Ar symbol_name . +Only applicable with -dead_strip . +It can help debug why something that you think should be dead strip removed is not removed. +.It Fl print_statistics +Logs information about the amount of memory and time the linker used. +.It Fl t +Logs each file (object, archive, or dylib) the linker loads. Useful for debugging problems with search paths where the wrong library is loaded. +.It Fl whatsloaded +Logs just object files the linker loads. +.It Fl order_file_statistics +Logs information about the processing of a -order_file. +.It Fl map Ar map_file_path +Writes a map file to the specified path which details all symbols and their addresses in the output image. +.El +.Ss Options for controling symbol table optimizations +.Bl -tag +.It Fl S +Do not put debug information (STABS or DWARF) in the output file. +.It Fl x +Do not put non-global symbols in the output file's symbol table. Non-global symbols are useful when debugging and +getting symbol names in back traces, but are not used at runtime. If -x is used with -r +non-global symbol names are not removed, but instead replaced with a unique, duumy name +that will be automatically removed when linked into a final linked image. This +allows dead code stripping, which uses symbols to break up code and data, to +work properly and provides the security of having source symbol names removed. +.It Fl non_global_symbols_strip_list Ar filename +The specified +.Ar filename +contains a list of non-global symbol names that should be removed from the output file's symbol table. All other +non-global symbol names will remain in the output files symbol table. See -exported_symbols_list for syntax and use +of wildcards. +.It Fl non_global_symbols_no_strip_list Ar filename +The specified +.Ar filename +contains a list of non-global symbol names that should be remain in the output file's symbol table. All other +symbol names will be removed from the output file's symbol table. See -exported_symbols_list for syntax and use +of wildcards. +.El +.Ss Rarely used Options +.Bl -tag +.It Fl v +Prints the version of the linker. +.It Fl no_uuid +Do not generate an LC_UUID load command in the output file. +.It Fl root_safe +Sets the MH_ROOT_SAFE bit in the mach header of the output file. +.It Fl setuid_safe +Sets the MH_SETUID_SAFE bit in the mach header of the output file. +.It Fl interposable +Indirects access to all to exported symbols when creating a dynamic library. +.It Fl init Ar symbol_name +The specified symbol_name will be run as the first initializer. Only used when creating a dynamic library. +.It Fl sub_library Ar library_name +The specified dylib will be re-exported. For example the library_name for /usr/lib/libobjc_profile.A.dylib would be libobjc. +Only used when creating a dynamic library. +.It Fl sub_umbrella Ar framework_name +The specified framework will be re-exported. Only used when creating a dynamic library. +.It Fl allowable_client Ar name +Restricts what can link against the dynamic library being created. +.It Fl client_name Ar name +Enables a bundle to link against a dylib that was built with -allowable_client. +The name specified must match one of the -allowable_client names specified when the dylib was created. +.It Fl umbrella Ar framework_name +Specifies that the dylib being linked is re-exported through an umbrella framework of the specified name. +.It Fl headerpad Ar size +Specifies the minimum space for future expansion of the load commands. Only useful if intend to run +install_name_tool to alter the load commands later. Size is a hexadecimal number. +.It Fl headerpad_max_install_names +Automatically adds space for future expansion of load commands such that all paths could expand to MAXPATHLEN. +Only useful if intend to run install_name_tool to alter the load commands later. Size is a hexadecimal number. +.It Fl bind_at_load +Sets a bit in the mach header of the resulting binary which tells dyld to bind all symbols when the binary is loaded, rather than lazily. +.It Fl force_flat_namespace +Sets a bit in the mach header of the resulting binary which tells dyld to not only use flat namespace for the binary, +but force flat namespace binding on all dylibs and bundles loaded in the process. Can only be used when linking main executables. +.It Fl sectalign Ar segname Ar sectname Ar value +The section named sectname in the segment segname will have its alignment set to value, where value is a hexadecimal +number that must be an integral power of 2. +.It Fl stack_addr Ar address +Specifies the initial address of the stack pointer value, where value is a hexadecimal number rounded to a page boundary. +.It Fl segprot Ar segname Ar max_prot Ar init_prot +Specifies the maximum and initial virtual memory protection of the named segment, name, to be max and init ,respectively. +The values for max and init are any combination of the characters `r' (for read), `w' (for write), `x' (for execute) and `-' (no access). +.It Fl seg_addr_table Ar filename +Specifies a file containing base addresses for dynamic libraries. Each line of the file is a hexadecimal base address +followed by whitespace then the install name of the corresponding dylib. The # character denotes a comment. +.It Fl segs_read_write_addr Ar address +Allows a dynamic library to be built where the read-only and read-write segments are not contiguous. The address +specified is a hexadecimal number that indicates the base address for the read-write segments. +.It Fl segs_read_only_addr Ar address +Allows a dynamic library to be built where the read-only and read-write segments are not contiguous. The address +specified is a hexadecimal number that indicates the base address for the read-only segments. +.It Fl segaddr Ar name Ar address +Specifies the starting address of the segment named name to be address. The address must be a hexadecimal number +that is a multiple of 4K page size. +.It Fl dylib_file Ar install_name:file_name +Specifies that a dynamic shared library is in a different location than its standard location. Use this option +when you link with a library that is dependent on a dynamic library, and the dynamic library is in a location other +than its default location. install_name specifies the path where the library normally resides. file_name specifies +the path of the library you want to use instead. For example, if you link to a library that depends upon the dynamic +library libsys and you have libsys installed in a nondefault location, you would use this option: +-dylib_file /lib/libsys_s.A.dylib:/me/lib/libsys_s.A.dylib. +.It Fl prebind +The created output file will be in the prebound format. This was used in Mac OS X 10.3 and earlier to improve launch performance. +.It Fl weak_reference_mismatches Ar treatment +Specifies what to do if a symbol is weak-imported in one object file but not weak-imported in another. The valid +treatments are: error, weak, or non-weak. The default is non-weak. +.It Fl read_only_relocs Ar treatment +Enables the use of relocations which will cause dyld to modify (copy-on-write) read-only pages. The compiler will +normally never generate such code. +.It Fl force_cpusubtype_ALL +The is only applicable with -arch ppc. It tells the linker to ignore the PowerPC cpu requirements (e.g. G3, G4 or G5) encoded +in the object files and mark the resulting binary as runnable on any PowerPC cpu. +.It Fl dylinker_install_name Ar path +Only used when building dyld. +.It Fl no_arch_warnings +Suppresses warning messages about files that have the wrong architecture for the -arch flag +.It Fl arch_errors_fatal +Turns into errors, warnings about files that have the wrong architecture for the -arch flag. +.It Fl e Ar symbol_name +Specifies the entry point of a main executable. By default the entry name is "start" which is found in crt1.o which contains +the glue code need to set up and call main(). +.It Fl w +Suppress all warning messages +.It Fl final_output Ar name +Specifies the install name of a dylib if -install_name is not used. This option is used by gcc driver when it is invoked +with multiple -arch arguments. +.It Fl arch_multiple +Specifes that the linker should augment error and warning messages with the architecture name. This option is used by gcc +driver when it is invoked with multiple -arch arguments. +.It Fl twolevel_namespace_hints +Specifies that hints should be added to the resulting binary that can help speed up runtime binding by dyld as long as the +libraries being linked against have not changed. +.It Fl dot Ar path +Create a file a file at the specified path containing a graph of symbol dependencies. The .dot file can be viewed in GraphViz. +.It Fl keep_relocs +Add section based relocation records to a final linked image. These relocations are ignored at runtime by dyld. +.It Fl warn_stabs +Print a warning when the linker cannot do a BINCL/EINCL optimzation because the compiler put a bad stab symbol inside +a BINCL/EINCL range. +.It Fl warn_commons +Print a warning whenever the a tentative definition in an object file is found and a external symbol by the same name +is also found in a linked dylib. This often means that the extern keyword is missing from a variable declaration +in a header file. +.It Fl read_only_stubs +[i386 only] Makes the __IMPORT segment of a final linked images read-only. This option makes a program slightly more +secure in that the JMP instructions in the i386 fast stubs cannot be easily overwritten by malicious code. The downside +is the dyld must use mprotect() to temporily make the segment writable while it is binding the stubs. +.It Fl slow_stubs +[i386 only] Instead of using single JMP instruction stubs, the linker creates code in the __TEXT segment which +calls through a lazy pointer in the __DATA segment. +.It Fl interposable_list Ar filename +The specified +.Ar filename +contains a list of global symbol names that should always be accessed indirectly. For instance, if libSystem.dylib +is linked such that _malloc is interposable, then calls to malloc() from within libSystem will go through a dyld +stub and could potentially indirected to an alternate malloc. If libSystem.dylib were built without making _malloc +interposable then if _malloc was interposed at runtime, calls to malloc from with libSystem would be missed +(not interposed) because they would be direct calls. +.El +.Ss Obsolete Options +.Bl -tag +.It Fl segalign Ar value +All segments must be page aligned. This option is obsolete. +.It Fl seglinkedit +Object files (MH_OBJECT) with a LINKEDIT segment are no longer supported. This option is obsolete. +.It Fl noseglinkedit +This is the default. This option is obsolete. +.It Fl fvmlib +Fixed VM shared libraries (MH_FVMLIB) are no longer supported. This option is obsolete. +.It Fl preload +Preload executables (MH_PRELOAD) are no longer supported. This option is obsolete. +.It Fl sectobjectsymbols Ar segname Ar sectname +Adding a local label at a section start is no longer supported. This option is obsolete. +.It Fl nofixprebinding +The MH_NOFIXPREBINDING bit of mach_headers has been ignored since Mac OS X 10.3.9. This option is obsolete. +.It Fl noprebind_all_twolevel_modules +Multi-modules in dynamic libraries have been ignored at runtime since Mac OS X 10.4.0. This option is obsolete. +.It Fl prebind_all_twolevel_modules +Multi-modules in dynamic libraries have been ignored at runtime since Mac OS X 10.4.0. This option is obsolete. +.It Fl prebind_allow_overlap +When using -prebind, the linker allows overlapping by default, so this option is obsolete. +.It Fl noprebind +LD_PREBIND is no longer supported as a way to force on prebinding, so there no longer needs to +be a command line way to override LD_PREBIND. This option is obsolete. +.It Fl sect_diff_relocs Ar treatment +This option was an attempt to warn about linking .o files compiled without -mdynamic-no-pic into +a main executable, but the false positive rate generated too much noise to make the option useful. +This option is obsolete. +.It Fl run_init_lazily +This option was removed in Mac OS X 10.2. +.It Fl single_module +This is now the default so does not need to be specified. +.It Fl multi_module +Multi-modules in dynamic libraries have been ignored at runtime since Mac OS X 10.4.0. This option is obsolete. +.It Fl no_dead_strip_inits_and_terms +The linker never dead strips initialzation and termination routines. They are considered "roots" of the dead strip graph. +.It Fl A Ar basefile +Obsolete incremental load format. This option is obsolete. +.It Fl b +Used with -A option to strip base file's symbols. This option is obsolete. +..It Fl M +Obsolete option to produce a load map. Use -map option instead. +.It Fl Sn +Don't strip any symbols. This is the default. This option is obsolete. +.It Fl Si +Optimize stabs debug symbols to remove duplicates. This is the default. This option is obsolete. +.It Fl Sp +Write minimal stabs which causes the debugger to open and read the original .o file for full stabs. +This style of debugging is obsolete in Mac OS X 10.5. This option is obsolete. +.It Fl X +Strip local symbols that being the 'L'. This is the default. This option is obsolete. +.It Fl s +Completely strip the output, including removing the symbol table. This file format variant is no longer supported. +This option is obsolete. +.It Fl m +Don't treat multiple definitions as an error. This is no longer supported. This option is obsolete. +.It Fl y Ns symbol +Display each file in which +.Ar symbol +is used. This was previously used to debug where an undefined symbol was used, but the linker now +automatically prints out all usages. The -why_live option can also be used to display what kept +a symbol from being dead striped. This option is obsolete. +.It Fl Y Ar number +Used to control how many occurances of each symbol specifed with -y would be shown. This option is obsolete. +.It Fl nomultidefs +Only used when linking an umbrella framework. Sets the MH_NOMULTIDEFS bit in the mach_header. The MH_NOMULTIDEFS +bit has been obsolete since Mac OS X 10.4. This option is obsolete. +.It Fl multiply_defined_unused Ar treatment +Previously provided a way to warn or error if any of the symbol definitions in the output file matched any +definitions in dynamic library being linked. This option is obsolete. +.It Fl multiply_defined Ar treatment +Previously provided a way to warn or error if any of the symbols used from a dynamic library were also +available in another linked dynamic library. This option is obsolete. +.It Fl private_bundle +Previously prevented errors when -flat_namespace, -bundle, and -bundle_loader were used and the bundle +contained a definition that conflicted with a symbol in the main executable. The linker no longer +errors on such conflicts. This option is obsolete. +.It Fl noall_load +This is the default. This option is obsolete. +.It Fl seg_addr_table_filename Ar path +Use +.Ar path +instead of the install name of the library for matching an entry in the seg_addr_table. This option is obsolete. +.It Fl sectorder Ar segname sectname orderfile +Replaced by more general -order_file option. +.It Fl sectorder_detail +Produced extra logging about which entries from a sectorder entries were used. Replaced by -order_file_statistics. +This option is obsolete. +.El +.Sh SEE ALSO +as(1), ar(1), cc(1), nm(1), otool(1) lipo(1), +arch(3), dyld(3), Mach-O(5), strip(1), rebase(1) diff --git a/FireOpal/doc/man/man1/ld64.1 b/FireOpal/doc/man/man1/ld64.1 new file mode 100644 index 0000000..615b0e5 --- /dev/null +++ b/FireOpal/doc/man/man1/ld64.1 @@ -0,0 +1 @@ +.so man1/ld.1 diff --git a/FireOpal/doc/man/man1/rebase.1 b/FireOpal/doc/man/man1/rebase.1 new file mode 100644 index 0000000..6743a96 --- /dev/null +++ b/FireOpal/doc/man/man1/rebase.1 @@ -0,0 +1,39 @@ +.Dd June 6, 2006 +.Dt rebase 1 +.Os Darwin +.Sh NAME +.Nm rebase +.Nd "Changes base address of dylibs and bundles" +.Sh SYNOPSIS +.Nm +.Op Fl low_address Ar addr +.Op Fl high_address Ar addr +.Op Fl arch Ar arch +.Op Fl v +.Ar file(s) +.Sh DESCRIPTION +The base address of an image (dylib or bundle) is the preferred address for it to be loaded. By +default all images are built with a base address of zero. At runtime, if the +preferred memory range is already occupied, dyld will "slide" the image to a new address range. +There is a small cost to the slide, as dyld must do some fix ups. +The rebase tool takes a list of images and adjust their base address to be non-overlapping. If no +low or high address is specified, the a suitable address range is choosen for the architecture. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl low_address Ar addr +Force the base address for the first image to be +.Ar addr +(specified in hex). Each subsequent file gets the next available base address. +.It Fl high_address Ar addr +Force the base address for the last image to be such that when that image is loaded it occupies +memory up to +.Ar addr +(specified in hex). Each preceeding file gets the previous available base address. +.It Fl arch Ar arch +Only rebase the specified architecture. Other architectures in a universal image are left as is. +.It Fl v +Verbose. Print information about rebasing done. +.El +.Sh SEE ALSO +.Xr ld 1 diff --git a/FireOpal/ld64.xcodeproj/project.pbxproj b/FireOpal/ld64.xcodeproj/project.pbxproj new file mode 100644 index 0000000..5f8cd7f --- /dev/null +++ b/FireOpal/ld64.xcodeproj/project.pbxproj @@ -0,0 +1,788 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXAggregateTarget section */ + F96D5368094A2754008E9EE8 /* unit-tests */ = { + isa = PBXAggregateTarget; + buildConfigurationList = F96D536D094A2773008E9EE8 /* Build configuration list for PBXAggregateTarget "unit-tests" */; + buildPhases = ( + F96D5367094A2754008E9EE8 /* ShellScript */, + ); + dependencies = ( + F96D536A094A275D008E9EE8 /* PBXTargetDependency */, + F96D536C094A275F008E9EE8 /* PBXTargetDependency */, + F96904890A4333AC00B77D2A /* PBXTargetDependency */, + F9EA73970974999B008B4F1D /* PBXTargetDependency */, + ); + name = "unit-tests"; + productName = "unit-tests"; + }; + F9B1A2670A3A567B00DA8FAB /* all */ = { + isa = PBXAggregateTarget; + buildConfigurationList = F9B1A26C0A3A568700DA8FAB /* Build configuration list for PBXAggregateTarget "all" */; + buildPhases = ( + ); + dependencies = ( + F9B1A2690A3A568200DA8FAB /* PBXTargetDependency */, + F9B1A26B0A3A568400DA8FAB /* PBXTargetDependency */, + ); + name = all; + productName = all; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + F9023C4E06D5A272001BBF46 /* ld.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9023C3F06D5A254001BBF46 /* ld.cpp */; }; + F933E3D9092E855B0083EAC8 /* ObjectDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F971EED706D5AD240041D381 /* ObjectDump.cpp */; }; + F97F5029070D0BB200B9FCD7 /* ld.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = F97F5028070D0BB200B9FCD7 /* ld.1 */; }; + F9B1A2640A3A563E00DA8FAB /* rebase.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = F9B1A2580A3A448800DA8FAB /* rebase.1 */; }; + F9C0D4BD06DD28D2001C7193 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9C0D48A06DD1E1B001C7193 /* Options.cpp */; }; + F9EA72D5097454FF008B4F1D /* machochecker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9EA72D4097454FF008B4F1D /* machochecker.cpp */; }; + F9EA7584097882F3008B4F1D /* debugline.c in Sources */ = {isa = PBXBuildFile; fileRef = F9EA7582097882F3008B4F1D /* debugline.c */; }; + F9EA75BC09788857008B4F1D /* debugline.c in Sources */ = {isa = PBXBuildFile; fileRef = F9EA7582097882F3008B4F1D /* debugline.c */; }; + F9EC78060A2F8674002A3E39 /* rebase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9EC78050A2F8674002A3E39 /* rebase.cpp */; }; + F9FCC3F20A54A75600CEB866 /* ld64.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = F9FCC3F10A54A75600CEB866 /* ld64.1 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXBuildRule section */ + F9E8D4BD07FCAF2000FD5801 /* PBXBuildRule */ = { + isa = PBXBuildRule; + compilerSpec = com.apple.compilers.gcc; + fileType = sourcecode.c; + isEditable = 1; + outputFiles = ( + ); + }; + F9E8D4BE07FCAF2A00FD5801 /* PBXBuildRule */ = { + isa = PBXBuildRule; + compilerSpec = com.apple.compilers.gcc; + fileType = sourcecode.cpp; + isEditable = 1; + outputFiles = ( + ); + }; +/* End PBXBuildRule section */ + +/* Begin PBXContainerItemProxy section */ + F96904880A4333AC00B77D2A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F9023C3006D5A227001BBF46 /* Project object */; + proxyType = 1; + remoteGlobalIDString = F9EC77ED0A2F85F6002A3E39; + remoteInfo = rebase; + }; + F96D5369094A275D008E9EE8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F9023C3006D5A227001BBF46 /* Project object */; + proxyType = 1; + remoteGlobalIDString = F9023C3806D5A23E001BBF46; + remoteInfo = ld; + }; + F96D536B094A275F008E9EE8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F9023C3006D5A227001BBF46 /* Project object */; + proxyType = 1; + remoteGlobalIDString = F971EED206D5ACF60041D381; + remoteInfo = ObjectDump; + }; + F9B1A2680A3A568200DA8FAB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F9023C3006D5A227001BBF46 /* Project object */; + proxyType = 1; + remoteGlobalIDString = F9023C3806D5A23E001BBF46; + remoteInfo = ld; + }; + F9B1A26A0A3A568400DA8FAB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F9023C3006D5A227001BBF46 /* Project object */; + proxyType = 1; + remoteGlobalIDString = F9EC77ED0A2F85F6002A3E39; + remoteInfo = rebase; + }; + F9EA73960974999B008B4F1D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F9023C3006D5A227001BBF46 /* Project object */; + proxyType = 1; + remoteGlobalIDString = F9EA72CA097454A6008B4F1D; + remoteInfo = machocheck; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + F97F5025070D0B6300B9FCD7 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + F97F5029070D0BB200B9FCD7 /* ld.1 in CopyFiles */, + F9FCC3F20A54A75600CEB866 /* ld64.1 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + F9B1A25E0A3A44CB00DA8FAB /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + F9B1A2640A3A563E00DA8FAB /* rebase.1 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 3DA587190ACC53BE0015C432 /* LTOReader.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = LTOReader.hpp; path = src/LTOReader.hpp; sourceTree = ""; }; + C02A29DE0953B26E001FB8C1 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = ChangeLog; sourceTree = ""; }; + F9023C3906D5A23E001BBF46 /* ld */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ld; sourceTree = BUILT_PRODUCTS_DIR; }; + F9023C3E06D5A254001BBF46 /* ExecutableFile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ExecutableFile.h; path = src/ExecutableFile.h; sourceTree = ""; }; + F9023C3F06D5A254001BBF46 /* ld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ld.cpp; path = src/ld.cpp; sourceTree = ""; }; + F9023C4106D5A254001BBF46 /* ObjectFile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ObjectFile.h; path = src/ObjectFile.h; sourceTree = ""; }; + F933D9460929277C0083EAC8 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FileAbstraction.hpp; path = src/FileAbstraction.hpp; sourceTree = ""; }; + F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOFileAbstraction.hpp; path = src/MachOFileAbstraction.hpp; sourceTree = ""; }; + F933DC37092A82480083EAC8 /* Architectures.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Architectures.hpp; path = src/Architectures.hpp; sourceTree = ""; }; + F933E3CC092E84250083EAC8 /* MachOReaderDylib.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOReaderDylib.hpp; path = src/MachOReaderDylib.hpp; sourceTree = ""; }; + F933E3CD092E84250083EAC8 /* MachOReaderRelocatable.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOReaderRelocatable.hpp; path = src/MachOReaderRelocatable.hpp; sourceTree = ""; }; + F933E3CE092E84250083EAC8 /* MachOWriterExecutable.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOWriterExecutable.hpp; path = src/MachOWriterExecutable.hpp; sourceTree = ""; }; + F971EED306D5ACF60041D381 /* ObjectDump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ObjectDump; sourceTree = BUILT_PRODUCTS_DIR; }; + F971EED706D5AD240041D381 /* ObjectDump.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ObjectDump.cpp; path = src/ObjectDump.cpp; sourceTree = ""; }; + F97F5028070D0BB200B9FCD7 /* ld.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = ld.1; path = doc/man/man1/ld.1; sourceTree = ""; }; + F98D26850AA779BD00416316 /* OpaqueSection.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = OpaqueSection.hpp; path = src/OpaqueSection.hpp; sourceTree = ""; }; + F99F63CE0D99A291007F5394 /* ArchiveReader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ArchiveReader.hpp; path = src/ArchiveReader.hpp; sourceTree = SOURCE_ROOT; }; + F9B1A2580A3A448800DA8FAB /* rebase.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = rebase.1; path = doc/man/man1/rebase.1; sourceTree = ""; }; + F9C0D48A06DD1E1B001C7193 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Options.cpp; path = src/Options.cpp; sourceTree = ""; }; + F9C0D48B06DD1E1B001C7193 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Options.h; path = src/Options.h; sourceTree = ""; }; + F9EA72CB097454A6008B4F1D /* machocheck */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = machocheck; sourceTree = BUILT_PRODUCTS_DIR; }; + F9EA72D4097454FF008B4F1D /* machochecker.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = machochecker.cpp; path = src/machochecker.cpp; sourceTree = ""; }; + F9EA7582097882F3008B4F1D /* debugline.c */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.c; name = debugline.c; path = src/debugline.c; sourceTree = ""; tabWidth = 4; usesTabs = 1; }; + F9EA7583097882F3008B4F1D /* debugline.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = debugline.h; path = src/debugline.h; sourceTree = ""; }; + F9EC77EE0A2F85F6002A3E39 /* rebase */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rebase; sourceTree = BUILT_PRODUCTS_DIR; }; + F9EC78050A2F8674002A3E39 /* rebase.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = rebase.cpp; path = src/rebase.cpp; sourceTree = ""; }; + F9FCC3F10A54A75600CEB866 /* ld64.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = ld64.1; path = doc/man/man1/ld64.1; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + F9023C3706D5A23E001BBF46 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F971EED106D5ACF60041D381 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F9EA72C9097454A6008B4F1D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F9EC77EC0A2F85F6002A3E39 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + F9023C2C06D5A227001BBF46 = { + isa = PBXGroup; + children = ( + C02A29DE0953B26E001FB8C1 /* ChangeLog */, + F933DC37092A82480083EAC8 /* Architectures.hpp */, + F933D9460929277C0083EAC8 /* FileAbstraction.hpp */, + F99F63CE0D99A291007F5394 /* ArchiveReader.hpp */, + F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */, + F933E3CD092E84250083EAC8 /* MachOReaderRelocatable.hpp */, + F933E3CC092E84250083EAC8 /* MachOReaderDylib.hpp */, + F933E3CE092E84250083EAC8 /* MachOWriterExecutable.hpp */, + 3DA587190ACC53BE0015C432 /* LTOReader.hpp */, + F9023C3E06D5A254001BBF46 /* ExecutableFile.h */, + F9023C4106D5A254001BBF46 /* ObjectFile.h */, + F98D26850AA779BD00416316 /* OpaqueSection.hpp */, + F9023C3F06D5A254001BBF46 /* ld.cpp */, + F9C0D48A06DD1E1B001C7193 /* Options.cpp */, + F9C0D48B06DD1E1B001C7193 /* Options.h */, + F9EA7583097882F3008B4F1D /* debugline.h */, + F9EA7582097882F3008B4F1D /* debugline.c */, + F9EA72D4097454FF008B4F1D /* machochecker.cpp */, + F971EED706D5AD240041D381 /* ObjectDump.cpp */, + F9EC78050A2F8674002A3E39 /* rebase.cpp */, + F97F5028070D0BB200B9FCD7 /* ld.1 */, + F9FCC3F10A54A75600CEB866 /* ld64.1 */, + F9B1A2580A3A448800DA8FAB /* rebase.1 */, + F9023C3A06D5A23E001BBF46 /* Products */, + ); + sourceTree = ""; + }; + F9023C3A06D5A23E001BBF46 /* Products */ = { + isa = PBXGroup; + children = ( + F9023C3906D5A23E001BBF46 /* ld */, + F971EED306D5ACF60041D381 /* ObjectDump */, + F9EA72CB097454A6008B4F1D /* machocheck */, + F9EC77EE0A2F85F6002A3E39 /* rebase */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + F9023C3806D5A23E001BBF46 /* ld */ = { + isa = PBXNativeTarget; + buildConfigurationList = F933D91B09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ld" */; + buildPhases = ( + 0B12F6A50CE39466008ABCAE /* build configure.h */, + F9023C3606D5A23E001BBF46 /* Sources */, + F9023C3706D5A23E001BBF46 /* Frameworks */, + F97F5025070D0B6300B9FCD7 /* CopyFiles */, + F9FCC3EF0A54A4ED00CEB866 /* Run Script */, + ); + buildRules = ( + F9E8D4BE07FCAF2A00FD5801 /* PBXBuildRule */, + F9E8D4BD07FCAF2000FD5801 /* PBXBuildRule */, + ); + dependencies = ( + ); + name = ld; + productName = ld64; + productReference = F9023C3906D5A23E001BBF46 /* ld */; + productType = "com.apple.product-type.tool"; + }; + F971EED206D5ACF60041D381 /* ObjectDump */ = { + isa = PBXNativeTarget; + buildConfigurationList = F933D91F09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ObjectDump" */; + buildPhases = ( + F971EED006D5ACF60041D381 /* Sources */, + F971EED106D5ACF60041D381 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ObjectDump; + productName = ObjectDump; + productReference = F971EED306D5ACF60041D381 /* ObjectDump */; + productType = "com.apple.product-type.tool"; + }; + F9EA72CA097454A6008B4F1D /* machocheck */ = { + isa = PBXNativeTarget; + buildConfigurationList = F9EA72CF097454D5008B4F1D /* Build configuration list for PBXNativeTarget "machocheck" */; + buildPhases = ( + F9EA72C8097454A6008B4F1D /* Sources */, + F9EA72C9097454A6008B4F1D /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = machocheck; + productName = machocheck; + productReference = F9EA72CB097454A6008B4F1D /* machocheck */; + productType = "com.apple.product-type.tool"; + }; + F9EC77ED0A2F85F6002A3E39 /* rebase */ = { + isa = PBXNativeTarget; + buildConfigurationList = F9EC77F00A2F8616002A3E39 /* Build configuration list for PBXNativeTarget "rebase" */; + buildPhases = ( + F9EC77EB0A2F85F6002A3E39 /* Sources */, + F9EC77EC0A2F85F6002A3E39 /* Frameworks */, + F9B1A25E0A3A44CB00DA8FAB /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = rebase; + productName = rebase; + productReference = F9EC77EE0A2F85F6002A3E39 /* rebase */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + F9023C3006D5A227001BBF46 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = F933D92309291AC90083EAC8 /* Build configuration list for PBXProject "ld64" */; + compatibilityVersion = "Xcode 2.4"; + hasScannedForEncodings = 0; + mainGroup = F9023C2C06D5A227001BBF46; + productRefGroup = F9023C3A06D5A23E001BBF46 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + F9B1A2670A3A567B00DA8FAB /* all */, + F9023C3806D5A23E001BBF46 /* ld */, + F9EC77ED0A2F85F6002A3E39 /* rebase */, + F971EED206D5ACF60041D381 /* ObjectDump */, + F9EA72CA097454A6008B4F1D /* machocheck */, + F96D5368094A2754008E9EE8 /* unit-tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXShellScriptBuildPhase section */ + 0B12F6A50CE39466008ABCAE /* build configure.h */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "build configure.h"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/configure.h", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/bash; + shellScript = "if [ -f /Developer/usr/local/include/llvm-c/lto.h ]; then\n\techo \"#define LTO_SUPPORT 1\" > ${DERIVED_FILE_DIR}/configure.h\nelse\n\techo \"#undef LTO_SUPPORT\t\" > ${DERIVED_FILE_DIR}/configure.h\nfi\n"; + showEnvVarsInLog = 0; + }; + F96D5367094A2754008E9EE8 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + 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"; + showEnvVarsInLog = 0; + }; + F9FCC3EF0A54A4ED00CEB866 /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 8; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 1; + shellPath = /bin/sh; + shellScript = "cd ${DSTROOT}/usr/bin\nln -s ld ld64"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + F9023C3606D5A23E001BBF46 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F9023C4E06D5A272001BBF46 /* ld.cpp in Sources */, + F9C0D4BD06DD28D2001C7193 /* Options.cpp in Sources */, + F9EA7584097882F3008B4F1D /* debugline.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F971EED006D5ACF60041D381 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F933E3D9092E855B0083EAC8 /* ObjectDump.cpp in Sources */, + F9EA75BC09788857008B4F1D /* debugline.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F9EA72C8097454A6008B4F1D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F9EA72D5097454FF008B4F1D /* machochecker.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F9EC77EB0A2F85F6002A3E39 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F9EC78060A2F8674002A3E39 /* rebase.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + F96904890A4333AC00B77D2A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F9EC77ED0A2F85F6002A3E39 /* rebase */; + targetProxy = F96904880A4333AC00B77D2A /* PBXContainerItemProxy */; + }; + F96D536A094A275D008E9EE8 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F9023C3806D5A23E001BBF46 /* ld */; + targetProxy = F96D5369094A275D008E9EE8 /* PBXContainerItemProxy */; + }; + F96D536C094A275F008E9EE8 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F971EED206D5ACF60041D381 /* ObjectDump */; + targetProxy = F96D536B094A275F008E9EE8 /* PBXContainerItemProxy */; + }; + F9B1A2690A3A568200DA8FAB /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F9023C3806D5A23E001BBF46 /* ld */; + targetProxy = F9B1A2680A3A568200DA8FAB /* PBXContainerItemProxy */; + }; + F9B1A26B0A3A568400DA8FAB /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F9EC77ED0A2F85F6002A3E39 /* rebase */; + targetProxy = F9B1A26A0A3A568400DA8FAB /* PBXContainerItemProxy */; + }; + F9EA73970974999B008B4F1D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F9EA72CA097454A6008B4F1D /* machocheck */; + targetProxy = F9EA73960974999B008B4F1D /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + F933D91C09291AC90083EAC8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)"; + DEAD_CODE_STRIPPING = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_DYNAMIC_NO_PIC = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; + GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS = NO; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_MISSING_PARENTHESES = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = NO; + GCC_WARN_PEDANTIC = NO; + GCC_WARN_SHADOW = NO; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; + GCC_WARN_UNINITIALIZED_AUTOS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = NO; + GCC_WARN_UNUSED_VALUE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(DEVELOPER_DIR)/usr/local/include", + "$(DEVELOPER_DIR)/usr/include", + ); + INSTALL_PATH = /usr/bin; + MACOSX_DEPLOYMENT_TARGET = ""; + OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)"; + OTHER_LDFLAGS = "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib"; + PREBINDING = NO; + PRODUCT_NAME = ld; + SECTORDER_FLAGS = ""; + VERSIONING_SYSTEM = "apple-generic"; + WARNING_CFLAGS = "-Wall"; + }; + name = Debug; + }; + F933D91D09291AC90083EAC8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_DYNAMIC_NO_PIC = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = "$(GCC_PREPROCESSOR_DEFINITIONS_$(RC_RELEASE))"; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; + GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS = NO; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_MISSING_PARENTHESES = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = NO; + GCC_WARN_PEDANTIC = NO; + GCC_WARN_SHADOW = NO; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; + GCC_WARN_UNINITIALIZED_AUTOS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = NO; + GCC_WARN_UNUSED_VALUE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(DEVELOPER_DIR)/usr/local/include", + "$(DEVELOPER_DIR)/usr/include", + ); + INSTALL_PATH = /usr/bin; + OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)"; + OTHER_LDFLAGS = "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib"; + PREBINDING = NO; + PRODUCT_NAME = ld; + SECTORDER_FLAGS = ""; + VALID_ARCHS = "i386 ppc"; + VERSIONING_SYSTEM = "apple-generic"; + WARNING_CFLAGS = "-Wall"; + }; + name = Release; + }; + F933D92009291AC90083EAC8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + HEADER_SEARCH_PATHS = "$(DEVELOPER_DIR)/usr/include"; + INSTALL_PATH = "$(HOME)/bin"; + OTHER_LDFLAGS = "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib"; + OTHER_REZFLAGS = ""; + PREBINDING = NO; + PRODUCT_NAME = ObjectDump; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + }; + name = Debug; + }; + F933D92109291AC90083EAC8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = s; + INSTALL_PATH = "$(HOME)/bin"; + OTHER_LDFLAGS = "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib"; + OTHER_REZFLAGS = ""; + PREBINDING = NO; + PRODUCT_NAME = ObjectDump; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + }; + name = Release; + }; + F933D92409291AC90083EAC8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_DYNAMIC_NO_PIC = NO; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + }; + name = Debug; + }; + F933D92509291AC90083EAC8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_DYNAMIC_NO_PIC = NO; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + HEADER_SEARCH_PATHS = "$(DEVELOPER_DIR)/SDKs/Extra/usr/include"; + }; + name = Release; + }; + F96D536E094A2773008E9EE8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + PRODUCT_NAME = "unit-tests"; + }; + name = Debug; + }; + F96D536F094A2773008E9EE8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + PRODUCT_NAME = "unit-tests"; + }; + name = Release; + }; + F9B1A26D0A3A568700DA8FAB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + PRODUCT_NAME = all; + }; + name = Debug; + }; + F9B1A26E0A3A568700DA8FAB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + PRODUCT_NAME = all; + ZERO_LINK = NO; + }; + name = Release; + }; + F9EA72D0097454D5008B4F1D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = "$(HOME)/bin"; + PREBINDING = NO; + PRODUCT_NAME = machocheck; + }; + name = Debug; + }; + F9EA72D1097454D5008B4F1D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = "$(HOME)/bin"; + PREBINDING = NO; + PRODUCT_NAME = machocheck; + }; + name = Release; + }; + F9EC77F10A2F8616002A3E39 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_DYNAMIC_NO_PIC = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = "$(HOME)/bin"; + PREBINDING = NO; + PRODUCT_NAME = rebase; + }; + name = Debug; + }; + F9EC77F20A2F8616002A3E39 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_MODEL_TUNING = G5; + GCC_PREPROCESSOR_DEFINITIONS = "$(GCC_PREPROCESSOR_DEFINITIONS_$(RC_RELEASE))"; + INSTALL_PATH = /usr/bin; + PREBINDING = NO; + PRODUCT_NAME = rebase; + VALID_ARCHS = "i386 ppc"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + F933D91B09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ld" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F933D91C09291AC90083EAC8 /* Debug */, + F933D91D09291AC90083EAC8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F933D91F09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ObjectDump" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F933D92009291AC90083EAC8 /* Debug */, + F933D92109291AC90083EAC8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F933D92309291AC90083EAC8 /* Build configuration list for PBXProject "ld64" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F933D92409291AC90083EAC8 /* Debug */, + F933D92509291AC90083EAC8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F96D536D094A2773008E9EE8 /* Build configuration list for PBXAggregateTarget "unit-tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F96D536E094A2773008E9EE8 /* Debug */, + F96D536F094A2773008E9EE8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F9B1A26C0A3A568700DA8FAB /* Build configuration list for PBXAggregateTarget "all" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F9B1A26D0A3A568700DA8FAB /* Debug */, + F9B1A26E0A3A568700DA8FAB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F9EA72CF097454D5008B4F1D /* Build configuration list for PBXNativeTarget "machocheck" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F9EA72D0097454D5008B4F1D /* Debug */, + F9EA72D1097454D5008B4F1D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F9EC77F00A2F8616002A3E39 /* Build configuration list for PBXNativeTarget "rebase" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F9EC77F10A2F8616002A3E39 /* Debug */, + F9EC77F20A2F8616002A3E39 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = F9023C3006D5A227001BBF46 /* Project object */; +} diff --git a/FireOpal/src/Architectures.hpp b/FireOpal/src/Architectures.hpp new file mode 100644 index 0000000..2546bfe --- /dev/null +++ b/FireOpal/src/Architectures.hpp @@ -0,0 +1,88 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2005-2007 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 __ARCHITECTURES__ +#define __ARCHITECTURES__ + +#include "FileAbstraction.hpp" + + +// +// Architectures +// +struct ppc +{ + typedef Pointer32 P; + + enum ReferenceKinds { kNoFixUp, kFollowOn, kGroupSubordinate, kPointer, kPointerWeakImport, kPointerDiff16, kPointerDiff32, kPointerDiff64, + kBranch24, kBranch24WeakImport, kBranch14, + kPICBaseLow16, kPICBaseLow14, kPICBaseHigh16, + kAbsLow16, kAbsLow14, kAbsHigh16, kAbsHigh16AddLow, + kDtraceProbe, kDtraceProbeSite, kDtraceIsEnabledSite, kDtraceTypeReference }; +}; + +struct ppc64 +{ + typedef Pointer64 P; + + enum ReferenceKinds { kNoFixUp, kFollowOn, kGroupSubordinate, kPointer, kPointerWeakImport, kPointerDiff16, kPointerDiff32, kPointerDiff64, + kBranch24, kBranch24WeakImport, kBranch14, + kPICBaseLow16, kPICBaseLow14, kPICBaseHigh16, + kAbsLow16, kAbsLow14, kAbsHigh16, kAbsHigh16AddLow, + kDtraceProbe, kDtraceProbeSite, kDtraceIsEnabledSite, kDtraceTypeReference }; +}; + +struct x86 +{ + typedef Pointer32 P; + + enum ReferenceKinds { kNoFixUp, kFollowOn, kGroupSubordinate, kPointer, kPointerWeakImport, kPointerDiff, kPointerDiff16, + kPCRel32, kPCRel32WeakImport, kAbsolute32, kPCRel16, kPCRel8, + kDtraceProbe, kDtraceProbeSite, kDtraceIsEnabledSite, kDtraceTypeReference }; +}; + +struct x86_64 +{ + typedef Pointer64 P; + + enum ReferenceKinds { kNoFixUp, kFollowOn, kGroupSubordinate, kPointer, kPointerWeakImport, kPointerDiff, kPointerDiff32, + kPCRel32, kPCRel32_1, kPCRel32_2, kPCRel32_4, + kBranchPCRel32, kBranchPCRel32WeakImport, + kPCRel32GOTLoad, kPCRel32GOTLoadWeakImport, + kPCRel32GOT, kPCRel32GOTWeakImport, kBranchPCRel8, + kDtraceProbe, kDtraceProbeSite, kDtraceIsEnabledSite, kDtraceTypeReference }; +}; + +struct arm +{ + typedef Pointer32 P; + + enum ReferenceKinds { kNoFixUp, kFollowOn, kGroupSubordinate, kPointer, kPointerWeakImport, kPointerDiff, kReadOnlyPointer, + kBranch24, kBranch24WeakImport, kThumbBranch22, kThumbBranch22WeakImport, + kDtraceProbe, kDtraceProbeSite, kDtraceIsEnabledSite, kDtraceTypeReference }; +}; + +#endif // __ARCHITECTURES__ + + diff --git a/FireOpal/src/ArchiveReader.hpp b/FireOpal/src/ArchiveReader.hpp new file mode 100644 index 0000000..a195090 --- /dev/null +++ b/FireOpal/src/ArchiveReader.hpp @@ -0,0 +1,454 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2005-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 __OBJECT_FILE_ARCHIVE__ +#define __OBJECT_FILE_ARCHIVE__ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "MachOFileAbstraction.hpp" +#include "ObjectFile.h" +#include "MachOReaderRelocatable.hpp" +#if LTO_SUPPORT + #include "LTOReader.hpp" +#endif + +namespace archive { + +typedef const struct ranlib* ConstRanLibPtr; + +template +class Reader : public ObjectFile::Reader +{ +public: + static bool validFile(const uint8_t* fileContent, uint64_t fileLength); + Reader(const uint8_t fileContent[], uint64_t fileLength, + const char* path, time_t modTime, + const ObjectFile::ReaderOptions& options, uint32_t ordinalBase); + virtual ~Reader() {} + + virtual const char* getPath() { return fPath; } + virtual time_t getModificationTime(){ return fModTime; } + virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; } + virtual std::vector& getAtoms(); + virtual std::vector* getJustInTimeAtomsFor(const char* name); + virtual std::vector* getStabs() { return NULL; } + virtual void optimize(std::vector&, std::vector&, + std::vector&, const std::set&, + uint32_t, ObjectFile::Reader* writer, + const std::vector& llvmOptions, + bool allGlobalsAReDeadStripRoots, int okind, + bool verbose, bool saveTemps, const char* outputFilePath, + bool pie, bool allowTextRelocs); + +private: + static bool validMachOFile(const uint8_t* fileContent, uint64_t fileLength); + static bool validLTOFile(const uint8_t* fileContent, uint64_t fileLength); + static cpu_type_t architecture(); + + + class Entry : ar_hdr + { + public: + const char* getName() const; + time_t getModTime() const; + const uint8_t* getContent() const; + uint32_t getContentSize() const; + const Entry* getNext() const; + private: + bool hasLongName() const; + unsigned int getLongNameSpace() const; + + }; + + class CStringEquals + { + public: + bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } + }; + typedef __gnu_cxx::hash_map, CStringEquals> NameToEntryMap; + + typedef typename A::P P; + typedef typename A::P::E E; + + const struct ranlib* ranlibHashSearch(const char* name); + ObjectFile::Reader* makeObjectReaderForMember(const Entry* member); + void dumpTableOfContents(); + void buildHashTable(); + + const char* fPath; + time_t fModTime; + const ObjectFile::ReaderOptions& fOptions; + uint32_t fOrdinalBase; + const uint8_t* fFileContent; + uint64_t fFileLength; + const struct ranlib* fTableOfContents; + uint32_t fTableOfContentCount; + const char* fStringPool; + std::vector fAllAtoms; + std::vector fInstantiatedReaders; + std::set fInstantiatedEntries; + std::set fPossibleEntries; + NameToEntryMap fHashTable; + + static std::vector fgEmptyList; +}; + +template +std::vector Reader::fgEmptyList; + + +template +bool Reader::Entry::hasLongName() const +{ + return ( strncmp(this->ar_name, AR_EFMT1, strlen(AR_EFMT1)) == 0 ); +} + +template +unsigned int Reader::Entry::getLongNameSpace() const +{ + char* endptr; + long result = strtol(&this->ar_name[strlen(AR_EFMT1)], &endptr, 10); + return result; +} + +template +const char* Reader::Entry::getName() const +{ + if ( this->hasLongName() ) { + int len = this->getLongNameSpace(); + static char longName[256]; + strncpy(longName, ((char*)this)+sizeof(ar_hdr), len); + longName[len] = '\0'; + return longName; + } + else { + static char shortName[20]; + strncpy(shortName, this->ar_name, 16); + shortName[16] = '\0'; + char* space = strchr(shortName, ' '); + if ( space != NULL ) + *space = '\0'; + return shortName; + } +} + +template +time_t Reader::Entry::getModTime() const +{ + char temp[14]; + strncpy(temp, this->ar_date, 12); + temp[12] = '\0'; + char* endptr; + return (time_t)strtol(temp, &endptr, 10); +} + + +template +const uint8_t* Reader::Entry::getContent() const +{ + if ( this->hasLongName() ) + return ((uint8_t*)this) + sizeof(ar_hdr) + this->getLongNameSpace(); + else + return ((uint8_t*)this) + sizeof(ar_hdr); +} + + +template +uint32_t Reader::Entry::getContentSize() const +{ + char temp[12]; + strncpy(temp, this->ar_size, 10); + temp[10] = '\0'; + char* endptr; + long size = strtol(temp, &endptr, 10); + // long name is included in ar_size + if ( this->hasLongName() ) + size -= this->getLongNameSpace(); + return size; +} + + +template +const class Reader::Entry* Reader::Entry::getNext() const +{ + const uint8_t* p = this->getContent() + getContentSize(); + p = (const uint8_t*)(((uintptr_t)p+3) & (-4)); // 4-byte align + return (class Reader::Entry*)p; +} + + +template <> cpu_type_t Reader::architecture() { return CPU_TYPE_POWERPC; } +template <> cpu_type_t Reader::architecture() { return CPU_TYPE_POWERPC64; } +template <> cpu_type_t Reader::architecture() { return CPU_TYPE_I386; } +template <> cpu_type_t Reader::architecture() { return CPU_TYPE_X86_64; } +template <> cpu_type_t Reader::architecture() { return CPU_TYPE_ARM; } + + +template +bool Reader::validMachOFile(const uint8_t* fileContent, uint64_t fileLength) +{ + return mach_o::relocatable::Reader::validFile(fileContent); +} + +template +bool Reader::validLTOFile(const uint8_t* fileContent, uint64_t fileLength) +{ +#if LTO_SUPPORT + return lto::Reader::validFile(fileContent, fileLength, architecture()); +#else + return false; +#endif +} + + + +template +bool Reader::validFile(const uint8_t* fileContent, uint64_t fileLength) +{ + // must have valid archive header + if ( strncmp((const char*)fileContent, "!\n", 8) != 0 ) + return false; + + // peak at first .o file and verify it is correct architecture + const Entry* const start = (Entry*)&fileContent[8]; + const Entry* const end = (Entry*)&fileContent[fileLength]; + for (const Entry* p=start; p < end; p = p->getNext()) { + const char* memberName = p->getName(); + // skip option table-of-content member + if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) ) + continue; + // archive is valid if first .o file is valid + return (validMachOFile(p->getContent(), p->getContentSize()) || validLTOFile(p->getContent(), p->getContentSize())); + } + // empty archive + return true; +} + +template +Reader::Reader(const uint8_t fileContent[], uint64_t fileLength, const char* path, time_t modTime, + const ObjectFile::ReaderOptions& options, uint32_t ordinalBase) + : fPath(NULL), fModTime(modTime), fOptions(options), fOrdinalBase(ordinalBase), fFileContent(NULL), + fTableOfContents(NULL), fTableOfContentCount(0), fStringPool(NULL) +{ + fPath = strdup(path); + fFileContent = fileContent; + fFileLength = fileLength; + + if ( strncmp((const char*)fileContent, "!\n", 8) != 0 ) + throw "not an archive"; + + // write out path for -whatsloaded option + if ( options.fLogAllFiles ) + printf("%s\n", path); + + if ( !options.fFullyLoadArchives ) { + const Entry* const firstMember = (Entry*)&fFileContent[8]; + if ( (strcmp(firstMember->getName(), SYMDEF_SORTED) == 0) || (strcmp(firstMember->getName(), SYMDEF) == 0) ) { + const uint8_t* contents = firstMember->getContent(); + uint32_t ranlibArrayLen = E::get32(*((uint32_t*)contents)); + fTableOfContents = (const struct ranlib*)&contents[4]; + fTableOfContentCount = ranlibArrayLen / sizeof(struct ranlib); + fStringPool = (const char*)&contents[ranlibArrayLen+8]; + if ( ((uint8_t*)(&fTableOfContents[fTableOfContentCount]) > &fileContent[fileLength]) + || ((uint8_t*)fStringPool > &fileContent[fileLength]) ) + throw "malformed archive, perhaps wrong architecture"; + this->buildHashTable(); + } + else + throw "archive has no table of contents"; + } +} + + +template +ObjectFile::Reader* Reader::makeObjectReaderForMember(const Entry* member) +{ + const char* memberName = member->getName(); + char memberPath[strlen(fPath) + strlen(memberName)+4]; + strcpy(memberPath, fPath); + strcat(memberPath, "("); + strcat(memberPath, memberName); + strcat(memberPath, ")"); + //fprintf(stderr, "using %s from %s\n", memberName, fPath); + try { + // offset the ordinals in this mach-o .o file, so that atoms layout in same order as in archive + uint32_t ordinalBase = fOrdinalBase + (uint8_t*)member - fFileContent; + if ( validMachOFile(member->getContent(), member->getContentSize()) ) { + return new typename mach_o::relocatable::Reader::Reader(member->getContent(), memberPath, member->getModTime(), fOptions, ordinalBase); + } +#if LTO_SUPPORT + else if ( validLTOFile(member->getContent(), member->getContentSize()) ) { + return new typename lto::Reader(member->getContent(), member->getContentSize(), memberPath, member->getModTime(), fOptions, architecture()); + } +#endif + throw "not a valid archive member"; + } + catch (const char* msg) { + throwf("in %s, %s", memberPath, msg); + } +} + + +template +std::vector& Reader::getAtoms() +{ + if ( fOptions.fFullyLoadArchives ) { + // build vector of all atoms from all .o files in this archive + const Entry* const start = (Entry*)&fFileContent[8]; + const Entry* const end = (Entry*)&fFileContent[fFileLength]; + for (const Entry* p=start; p < end; p = p->getNext()) { + const char* memberName = p->getName(); + if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) ) + continue; + if ( fOptions.fWhyLoad ) + printf("-all_load forced load of %s(%s)\n", this->getPath(), memberName); + ObjectFile::Reader* r = this->makeObjectReaderForMember(p); + std::vector& atoms = r->getAtoms(); + fAllAtoms.insert(fAllAtoms.end(), atoms.begin(), atoms.end()); + fInstantiatedReaders.push_back(r); + } + return fAllAtoms; + } + else if ( fOptions.fLoadAllObjcObjectsFromArchives ) { + // build vector of all atoms from all .o files containing objc classes in this archive + for(class NameToEntryMap::iterator it = fHashTable.begin(); it != fHashTable.end(); ++it) { + if ( (strncmp(it->first, ".objc_c", 7) == 0) || (strncmp(it->first, "_OBJC_CLASS_$_", 14) == 0) ) { + const Entry* member = (Entry*)&fFileContent[E::get32(it->second->ran_off)]; + if ( fInstantiatedEntries.count(member) == 0 ) { + if ( fOptions.fWhyLoad ) + printf("-ObjC forced load of %s(%s)\n", this->getPath(), member->getName()); + // only return these atoms once + fInstantiatedEntries.insert(member); + ObjectFile::Reader* r = makeObjectReaderForMember(member); + std::vector& atoms = r->getAtoms(); + fAllAtoms.insert(fAllAtoms.end(), atoms.begin(), atoms.end()); + fInstantiatedReaders.push_back(r); + } + } + } + return fAllAtoms; + } + else { + // return nonthing for now, getJustInTimeAtomsFor() will return atoms as needed + return fgEmptyList; + } +} + +template +void Reader::optimize(std::vector& allAtoms, std::vector& newAtoms, + std::vector& additionalUndefines, const std::set& deadAtoms, + uint32_t nextOrdinal, ObjectFile::Reader* writer, + const std::vector& llvmOptions, + bool allGlobalsAReDeadStripRoots, int okind, + bool verbose, bool saveTemps, const char* outputFilePath, + bool pie, bool allowTextRelocs) +{ + for(std::vector::iterator it=fInstantiatedReaders.begin(); it != fInstantiatedReaders.end(); ++it) { + (*it)->optimize(allAtoms, newAtoms, additionalUndefines, deadAtoms, nextOrdinal, writer, llvmOptions, + allGlobalsAReDeadStripRoots, okind, verbose, saveTemps, outputFilePath, pie, allowTextRelocs); + } +} + + + +template +ConstRanLibPtr Reader::ranlibHashSearch(const char* name) +{ + class NameToEntryMap::iterator pos = fHashTable.find(name); + if ( pos != fHashTable.end() ) + return pos->second; + else + return NULL; +} + +template +void Reader::buildHashTable() +{ + // walk through list backwards, adding/overwriting entries + // this assures that with duplicates those earliest in the list will be found + for (int i = fTableOfContentCount-1; i >= 0; --i) { + const struct ranlib* entry = &fTableOfContents[i]; + const char* entryName = &fStringPool[E::get32(entry->ran_un.ran_strx)]; + const Entry* member = (Entry*)&fFileContent[E::get32(entry->ran_off)]; + //fprintf(stderr, "adding hash %d, %s -> %p\n", i, entryName, entry); + fHashTable[entryName] = entry; + fPossibleEntries.insert(member); + } +} + +template +void Reader::dumpTableOfContents() +{ + for (unsigned int i=0; i < fTableOfContentCount; ++i) { + const struct ranlib* e = &fTableOfContents[i]; + printf("%s in %s\n", &fStringPool[E::get32(e->ran_un.ran_strx)], ((Entry*)&fFileContent[E::get32(e->ran_off)])->getName()); + } +} + +template +std::vector* Reader::getJustInTimeAtomsFor(const char* name) +{ + if ( fOptions.fFullyLoadArchives ) { + return NULL; + } + else { + const struct ranlib* result = NULL; + // do a hash search of table of contents looking for requested symbol + result = ranlibHashSearch(name); + if ( result != NULL ) { + const Entry* member = (Entry*)&fFileContent[E::get32(result->ran_off)]; + if ( fInstantiatedEntries.count(member) == 0 ) { + if ( fOptions.fWhyLoad ) + printf("%s forced load of %s(%s)\n", name, this->getPath(), member->getName()); + // only return these atoms once + fInstantiatedEntries.insert(member); + ObjectFile::Reader* r = makeObjectReaderForMember(member); + fInstantiatedReaders.push_back(r); + return new std::vector(r->getAtoms()); + } + } + //fprintf(stderr, "%s NOT found in archive %s\n", name, fPath); + return NULL; + } +} + + + + + +}; // namespace archive + + +#endif // __OBJECT_FILE_ARCHIVE__ diff --git a/FireOpal/src/ExecutableFile.h b/FireOpal/src/ExecutableFile.h new file mode 100644 index 0000000..b0b760d --- /dev/null +++ b/FireOpal/src/ExecutableFile.h @@ -0,0 +1,70 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2005-2007 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 __EXECUTABLEFILE__ +#define __EXECUTABLEFILE__ + +#include +#include + +#include "ObjectFile.h" +#include "Options.h" + + +namespace ExecutableFile { + + struct DyLibUsed + { + ObjectFile::Reader* reader; + DynamicLibraryOptions options; + }; + + class Writer : public ObjectFile::Reader + { + public: + virtual ~Writer() {}; + + virtual const char* getPath() = 0; + virtual std::vector& getAtoms() = 0; + virtual std::vector* getJustInTimeAtomsFor(const char* name) = 0; + virtual ObjectFile::Atom& makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, + bool objcReplacementClasses) = 0; + virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name) = 0; + virtual uint64_t write(std::vector& atoms, + std::vector& stabs, + class ObjectFile::Atom* entryPointAtom, + class ObjectFile::Atom* dyldHelperAtom, + class ObjectFile::Atom* dyldLazyDylibHelperAtom, + bool createUUID, bool canScatter, + ObjectFile::Reader::CpuConstraint cpuConstraint, + bool biggerThanTwoGigs, + bool overridesDylibWeakDefines) = 0; + + protected: + Writer(std::vector&) {}; + }; + +}; + +#endif // __EXECUTABLEFILE__ diff --git a/FireOpal/src/FileAbstraction.hpp b/FireOpal/src/FileAbstraction.hpp new file mode 100644 index 0000000..1f7a629 --- /dev/null +++ b/FireOpal/src/FileAbstraction.hpp @@ -0,0 +1,145 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * 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@ + */ +#ifndef __FILE_ABSTRACTION__ +#define __FILE_ABSTRACTION__ + + +#include +#include +#include + +#ifdef __OPTIMIZE__ +#define INLINE __attribute__((always_inline)) +#else +#define INLINE +#endif + +// +// This abstraction layer is for use with file formats that have 64-bit/32-bit and Big-Endian/Little-Endian variants +// +// For example: to make a utility that handles 32-bit little enidan files use: Pointer32 +// +// +// get16() read a 16-bit number from an E endian struct +// set16() write a 16-bit number to an E endian struct +// get32() read a 32-bit number from an E endian struct +// set32() write a 32-bit number to an E endian struct +// get64() read a 64-bit number from an E endian struct +// set64() write a 64-bit number to an E endian struct +// +// getBits() read a bit field from an E endian struct (bitCount=number of bits in field, firstBit=bit index of field) +// setBits() write a bit field to an E endian struct (bitCount=number of bits in field, firstBit=bit index of field) +// +// getBitsRaw() read a bit field from a struct with native endianness +// setBitsRaw() write a bit field from a struct with native endianness +// + +class BigEndian +{ +public: + static uint16_t get16(const uint16_t& from) INLINE { return OSReadBigInt16(&from, 0); } + static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteBigInt16(&into, 0, value); } + + static uint32_t get32(const uint32_t& from) INLINE { return OSReadBigInt32(&from, 0); } + static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteBigInt32(&into, 0, value); } + + static uint64_t get64(const uint64_t& from) INLINE { return OSReadBigInt64(&from, 0); } + static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteBigInt64(&into, 0, value); } + + static uint32_t getBits(const uint32_t& from, + uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); } + static void setBits(uint32_t& into, uint32_t value, + uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); } + + static uint32_t getBitsRaw(const uint32_t& from, + uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> (32-firstBit-bitCount)) & ((1<> firstBit) & ((1< +class Pointer32 +{ +public: + typedef uint32_t uint_t; + typedef _E E; + + static uint64_t getP(const uint_t& from) INLINE { return _E::get32(from); } + static void setP(uint_t& into, uint64_t value) INLINE { _E::set32(into, value); } +}; + + +template +class Pointer64 +{ +public: + typedef uint64_t uint_t; + typedef _E E; + + static uint64_t getP(const uint_t& from) INLINE { return _E::get64(from); } + static void setP(uint_t& into, uint64_t value) INLINE { _E::set64(into, value); } +}; + + + + + +#endif // __FILE_ABSTRACTION__ + + diff --git a/FireOpal/src/LTOReader.hpp b/FireOpal/src/LTOReader.hpp new file mode 100644 index 0000000..2736f43 --- /dev/null +++ b/FireOpal/src/LTOReader.hpp @@ -0,0 +1,684 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006-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 __LTO_READER_H__ +#define __LTO_READER_H__ + +#include +#include +#include +#include +#include + +#include "MachOFileAbstraction.hpp" +#include "Architectures.hpp" +#include "ObjectFile.h" +#include "Options.h" + +#include "llvm-c/lto.h" + + +namespace lto { + + +// +// Reference handles Atom references. These references facilitate +// symbol resolution. +// + +class Reference : public ObjectFile::Reference +{ +public: + Reference(const char* name) : fTargetName(name), fTargetAtom(NULL) { } + Reference(ObjectFile::Atom& atom) : fTargetName(NULL), fTargetAtom(&atom) { } + + bool isTargetUnbound() const { return fTargetAtom == NULL; } + bool isFromTargetUnbound() const { return true; } + uint8_t getKind() const { return 0; } + uint64_t getFixUpOffset() const { return 0; } + const char * getTargetName() const { return fTargetName; } + ObjectFile::Atom& getTarget() const { return *fTargetAtom; } + uint64_t getTargetOffset() const { return 0; } + bool hasFromTarget() const { return false; } + ObjectFile::Atom& getFromTarget() const { return *((ObjectFile::Atom*)NULL); } + const char * getFromTargetName() const { return NULL; } + uint64_t getFromTargetOffset() const { return 0; } + TargetBinding getTargetBinding() const; + TargetBinding getFromTargetBinding() const { return kDontBind; } + void setTarget (ObjectFile::Atom& a, uint64_t offset) + { fTargetAtom = &a; } + void setFromTarget(ObjectFile::Atom &a) { } + const char * getDescription() const; + +private: + const char * fTargetName; + ObjectFile::Atom * fTargetAtom; +}; + + +ObjectFile::Reference::TargetBinding Reference::getTargetBinding() const +{ + if ( fTargetAtom == NULL ) + return kUnboundByName; + else if ( fTargetName == NULL ) + return kBoundDirectly; + else + return kBoundByName; +} + +const char* Reference::getDescription() const +{ + static char temp[256]; + strcpy(temp, "reference to "); + if ( fTargetName != NULL ) + strcat(temp, fTargetName); + else + strcat(temp, fTargetAtom->getDisplayName()); + return temp; +} + + +class Segment : public ObjectFile::Segment +{ +public: + Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress) + : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {} + virtual const char* getName() const { return fName; } + virtual bool isContentReadable() const { return fReadable; } + virtual bool isContentWritable() const { return fWritable; } + virtual bool isContentExecutable() const { return fExecutable; } + virtual bool hasFixedAddress() const { return fFixedAddress; } + + static Segment fgBootstrapSegment; + +private: + const char* fName; + const bool fReadable; + const bool fWritable; + const bool fExecutable; + const bool fFixedAddress; +}; + +Segment Segment:: fgBootstrapSegment("__TEMP", true, false, false, false); + + + + +// +// Atom acts as a proxy Atom for the symbols that are exported by LLVM bitcode file. Initially, +// Reader creates Atoms to allow linker proceed with usual symbol resolution phase. After +// optimization is performed, real Atoms are created for these symobls. However these real Atoms +// are not inserted into global symbol table. Atom holds real Atom and forwards appropriate +// methods to real atom. +// +class Atom : public ObjectFile::Atom +{ +public: + Atom(class Reader& owner, const char* name, Scope, DefinitionKind, uint8_t alignment, ObjectFile::Atom& internalAtom); + + ObjectFile::Reader* getFile() const { return (ObjectFile::Reader*)&fOwner; } + bool getTranslationUnitSource (const char **dir, const char **name) const + { return fRealAtom->getTranslationUnitSource(dir, name); } + const char * getName () const { return fName; } + const char * getDisplayName() const { return this->getName(); } + Scope getScope() const { return fScope; } + DefinitionKind getDefinitionKind() const { return (fRealAtom ? fRealAtom->getDefinitionKind() : fKind); } + SymbolTableInclusion getSymbolTableInclusion() const + { return fRealAtom->getSymbolTableInclusion(); } + bool dontDeadStrip() const { return false; } + bool isZeroFill() const { return (fRealAtom ? fRealAtom->isZeroFill() : false); } + bool isThumb() const { return false; } + uint64_t getSize() const { return (fRealAtom ? fRealAtom->getSize() : 0); } + std::vector& getReferences() const + { return (fRealAtom ? fRealAtom->getReferences() : (std::vector&)fReferences); } + bool mustRemainInSection() const { return fRealAtom->mustRemainInSection(); } + const char * getSectionName() const { return (fRealAtom ? fRealAtom->getSectionName() : NULL); } + // Linker::optimize() sets section for this atom, not fRealAtom. Use this Atom's fSection. + class ObjectFile::Section * getSection() const { return fSection; } + ObjectFile::Segment& getSegment() const { return (fRealAtom ? fRealAtom->getSegment() : Segment::fgBootstrapSegment); } + uint32_t getOrdinal() const { return (fRealAtom ? fRealAtom->getOrdinal() : 0); } + ObjectFile::Atom& getFollowOnAtom() const { return fRealAtom->getFollowOnAtom(); } + std::vector* getLineInfo() const { return (fRealAtom ? fRealAtom->getLineInfo() : NULL); } + ObjectFile::Alignment getAlignment() const { return (fRealAtom ? fRealAtom->getAlignment() : ObjectFile::Alignment(fAlignment)); } + void copyRawContent(uint8_t buffer[]) const + { if (fRealAtom) fRealAtom->copyRawContent(buffer); } + void setScope(Scope s) { if (fRealAtom) fRealAtom->setScope(s); else fScope = s; } + + void setRealAtom (ObjectFile::Atom *atom) + { fRealAtom = atom; } + ObjectFile::Atom * getRealAtom() { return fRealAtom; } + void addReference(ObjectFile::Reference *ref) + { fReferences.push_back(ref); } + + void setSectionOffset(uint64_t offset) { fSectionOffset = offset; if (fRealAtom) fRealAtom->setSectionOffset(offset); } + void setSection(class ObjectFile::Section* sect) { fSection = sect; if (fRealAtom) fRealAtom->setSection(sect); } + +private: + class Reader& fOwner; + const char* fName; + ObjectFile::Atom::Scope fScope; + ObjectFile::Atom::DefinitionKind fKind; + uint8_t fAlignment; + ObjectFile::Atom* fRealAtom; + std::vector fReferences; +}; + + +Atom::Atom(class Reader& owner, const char* name, Scope scope, DefinitionKind kind, uint8_t alignment, ObjectFile::Atom& internalAtom) +: fOwner(owner), fName(name), fScope(scope), fKind(kind), fAlignment(alignment), fRealAtom(NULL) +{ + // every Atom references the InternalAtom for its reader + fReferences.push_back(new Reference(internalAtom)); +} + + +// +// ld64 only tracks non-internal symbols from an llvm bitcode file. +// We model this by having an InternalAtom which represent all internal functions and data. +// All non-interal symbols from a bitcode file are represented by a Atom +// and each Atom has a reference to the InternalAtom. The InternalAtom +// also has references to each symbol external to the bitcode file. +// +class InternalAtom : public ObjectFile::Atom +{ +public: + InternalAtom(class Reader& owner) : fOwner(owner) {} + + ObjectFile::Reader * getFile() const { return (ObjectFile::Reader*)&fOwner; } + bool getTranslationUnitSource (const char **dir, const char **name) const + { return false; } + const char * getName () const { return "__llvm-internal-atom"; } + const char * getDisplayName() const { return "llvm bitcode"; } + Scope getScope() const { return scopeTranslationUnit; } + DefinitionKind getDefinitionKind() const { return kRegularDefinition; } + SymbolTableInclusion getSymbolTableInclusion() const { return kSymbolTableNotIn; } + bool dontDeadStrip() const { return false; } + bool isZeroFill() const { return false; } + bool isThumb() const { return false; } + uint64_t getSize() const { return 0; } + std::vector& getReferences() const { return (std::vector&)fReferences; } + bool mustRemainInSection() const { return false; } + const char * getSectionName() const { return NULL; } + class ObjectFile::Section * getSection() const { return NULL; } + ObjectFile::Segment& getSegment() const { return Segment::fgBootstrapSegment; } + uint32_t getOrdinal() const { return 0; } + ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); } + std::vector* getLineInfo() const { return NULL; } + ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); } + void copyRawContent(uint8_t buffer[]) const { } + void setScope(Scope s) { } + + void addReference(const char* targetName); + +private: + class Reader& fOwner; + std::vector fReferences; +}; + + +void InternalAtom::addReference(const char* name) +{ + fReferences.push_back(new Reference(name)); +} + + + + +class RemovableAtoms +{ +public: + RemovableAtoms(std::set& iAtoms) : fAtoms(iAtoms) {} + + bool operator()(ObjectFile::Atom*& atom) const { + return ( fAtoms.count(atom) != 0 ); + } + +private: + std::set& fAtoms; +}; + + + +// +// LLVM bitcode file reader +// +class Reader : public ObjectFile::Reader +{ +public: + static bool validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture); + static bool loaded() { return (::lto_get_version() != NULL); } + Reader(const uint8_t* fileContent, uint64_t fileLength, + const char* path, time_t modTime, + const ObjectFile::ReaderOptions&, cpu_type_t arch); + virtual ~Reader(); + + virtual std::vector& getAtoms() { return (std::vector&)(fAtoms); } + virtual std::vector* getJustInTimeAtomsFor(const char* name) { return NULL; } + virtual const char* getPath() { return fPath; } + virtual time_t getModificationTime() { return fModTime; } + virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return kDebugInfoNone; } + virtual std::vector* getStabs() { return NULL; } + virtual void optimize(std::vector& allAtoms, std::vector& newAtoms, + std::vector& additionalUndefines, const std::set&, + uint32_t nextInputOrdinal, + ObjectFile::Reader* writer, + const std::vector& llvmOptions, + bool allGlobalsAReDeadStripRoots, + int outputKind, bool verbose, bool saveTemps, const char* outputFilePath, + bool pie, bool allowTextRelocs); + +private: + + class CStringEquals + { + public: + bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } + }; + typedef __gnu_cxx::hash_set, CStringEquals> CStringSet; + typedef __gnu_cxx::hash_map, CStringEquals> CStringToAtom; + + ObjectFile::Reader* makeMachOReader(const uint8_t* p, size_t len, uint32_t nextInputOrdinal); + static const char* tripletPrefixForArch(cpu_type_t); + + cpu_type_t fArchitecture; + const char* fPath; + time_t fModTime; + lto_module_t fModule; + std::vector fAtoms; + InternalAtom fInternalAtom; + const ObjectFile::ReaderOptions& fReaderOptions; + static std::set fgReaders; + static bool fgOptimized; +}; + +bool Reader::fgOptimized = false; +std::set Reader::fgReaders; + + +Reader::~Reader() +{ + if ( fModule != NULL ) + ::lto_module_dispose(fModule); +} + +Reader::Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, + const ObjectFile::ReaderOptions& options, cpu_type_t arch) + : fArchitecture(arch), fPath(strdup(path)), fModTime(modTime), fInternalAtom(*this), fReaderOptions(options) +{ + fgReaders.insert(this); + + fModule = ::lto_module_create_from_memory(fileContent, fileLength); + if ( fModule == NULL ) + throwf("could not parse object file %s: %s", path, lto_get_error_message()); + + fAtoms.push_back(&fInternalAtom); + + uint32_t count = ::lto_module_get_num_symbols(fModule); + for (uint32_t i=0; i < count; ++i) { + const char* name = ::lto_module_get_symbol_name(fModule, i); + lto_symbol_attributes attr = lto_module_get_symbol_attribute(fModule, i); + + ObjectFile::Atom::DefinitionKind kind; + switch ( attr & LTO_SYMBOL_DEFINITION_MASK ) { + case LTO_SYMBOL_DEFINITION_REGULAR: + kind = ObjectFile::Atom::kRegularDefinition; + break; + case LTO_SYMBOL_DEFINITION_TENTATIVE: + kind = ObjectFile::Atom::kTentativeDefinition; + break; + case LTO_SYMBOL_DEFINITION_WEAK: + kind = ObjectFile::Atom::kWeakDefinition; + break; + case LTO_SYMBOL_DEFINITION_UNDEFINED: + kind = ObjectFile::Atom::kExternalDefinition; + break; + default: + throwf("unknown definition kind for symbol %s in bitcode file %s", name, path); + } + + // make LLVM atoms for definitions and a reference for undefines + if ( kind != ObjectFile::Atom::kExternalDefinition ) { + ObjectFile::Atom::Scope scope; + switch ( attr & LTO_SYMBOL_SCOPE_MASK) { + case LTO_SYMBOL_SCOPE_INTERNAL: + scope = ObjectFile::Atom::scopeTranslationUnit; + break; + case LTO_SYMBOL_SCOPE_HIDDEN: + scope = ObjectFile::Atom::scopeLinkageUnit; + break; + case LTO_SYMBOL_SCOPE_DEFAULT: + scope = ObjectFile::Atom::scopeGlobal; + break; + default: + throwf("unknown scope for symbol %s in bitcode file %s", name, path); + } + // only make atoms for non-internal symbols + if ( scope == ObjectFile::Atom::scopeTranslationUnit ) + continue; + uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK); + // make Atom + fAtoms.push_back(new Atom(*this, name, scope, kind, alignment, fInternalAtom)); + } + else { + // add to list of external references + fInternalAtom.addReference(name); + } + } +} + +const char* Reader::tripletPrefixForArch(cpu_type_t arch) +{ + switch (arch) { + case CPU_TYPE_POWERPC: + return "powerpc-"; + case CPU_TYPE_POWERPC64: + return "powerpc64-"; + case CPU_TYPE_I386: + return "i386-"; + case CPU_TYPE_X86_64: + return "x86_64-"; + case CPU_TYPE_ARM: + return "arm-"; + } + return ""; +} + +bool Reader::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture) +{ + return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, tripletPrefixForArch(architecture)); +} + +void Reader::optimize(std::vector& allAtoms, std::vector& newAtoms, + std::vector& additionalUndefines, const std::set& deadAtoms, + uint32_t nextInputOrdinal, ObjectFile::Reader* writer, + const std::vector& llvmOptions, + bool allGlobalsAReDeadStripRoots, + int okind, bool verbose, bool saveTemps, const char* outputFilePath, + bool pie, bool allowTextRelocs) +{ + // this method is call on all Readers. We want the first call to trigger optimization + // across all Readers and the subsequent calls to do nothing. + if ( fgOptimized ) + return; + fgOptimized = true; + + Options::OutputKind outputKind = (Options::OutputKind)okind; // HACK to work around upward dependency + + // print out LTO version string if -v was used + if ( verbose ) + fprintf(stderr, "%s\n", lto_get_version()); + + // create optimizer and add each Reader + lto_code_gen_t generator = ::lto_codegen_create(); + for (std::set::iterator it=fgReaders.begin(); it != fgReaders.end(); ++it) { + if ( ::lto_codegen_add_module(generator, (*it)->fModule) ) + throwf("lto: could not merge in %s because %s", (*it)->fPath, ::lto_get_error_message()); + } + + // add any -mllvm command line options + for (std::vector::const_iterator it=llvmOptions.begin(); it != llvmOptions.end(); ++it) { + ::lto_codegen_debug_options(generator, *it); + } + + // the linker must preserve all globals in dylibs and flat images + const bool globalsNeedPreserving = allGlobalsAReDeadStripRoots || fReaderOptions.fFlatNamespace; + + // The atom graph uses directed edges (references). Collect all references where + // originating atom is not part of any LTO Reader. This allows optimizer to optimize an + // external (i.e. not originated from same .o file) reference if all originating atoms are also + // defined in llvm bitcode file. + CStringSet nonLLVMRefs; + CStringToAtom llvmAtoms; + bool hasNonllvmAtoms = false; + for (std::vector::iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) { + ObjectFile::Atom* atom = *it; + // only look at references come from an atom that is not an llvm atom + if ( fgReaders.count((Reader*)(atom->getFile())) == 0 ) { + // remember if we've seen any atoms not from an llvm reader and not from the writer + if ( atom->getFile() != writer ) + hasNonllvmAtoms = true; + std::vector& refs = atom->getReferences(); + for (std::vector::iterator ri=refs.begin(), re=refs.end(); ri != re; ++ri) { + ObjectFile::Reference* ref = *ri; + // add target name to set if target is an llvm atom + if ( (ref->getTargetName() != NULL) && (fgReaders.count((Reader*)(ref->getTarget().getFile())) != 0) ) { + nonLLVMRefs.insert(ref->getTargetName()); + } + } + } + else { + const char* name = atom->getName(); + if ( name != NULL ) + llvmAtoms[name] = (Atom*)atom; + } + } + // deadAtoms are the atoms that the linker coalesced. For instance weak or tentative definitions + // overriden by another atom. If any of these deadAtoms are llvm atoms and they were replaced + // with a mach-o atom, we need to tell the lto engine to preserve (not optimize away) its dead + // atom so that the linker can replace it with the mach-o one later. + CStringToAtom deadllvmAtoms; + for (std::set::iterator it = deadAtoms.begin(); it != deadAtoms.end(); ++it) { + ObjectFile::Atom* atom = *it; + if ( fgReaders.count((Reader*)(atom->getFile())) != 0 ) { + const char* name = atom->getName(); + ::lto_codegen_add_must_preserve_symbol(generator, name); + deadllvmAtoms[name] = (Atom*)atom; + } + } + + + // tell code generator about symbols that must be preserved + for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) { + const char* name = it->first; + Atom* atom = it->second; + // Include llvm Symbol in export list if it meets one of following two conditions + // 1 - globals need preserving and atom scope is global (and not linkage unit). + // 2 - included in nonLLVMRefs set. + // If a symbol is not listed in exportList then LTO is free to optimize it away. + if ( globalsNeedPreserving && (atom->getScope() == ObjectFile::Atom::scopeGlobal) ) + ::lto_codegen_add_must_preserve_symbol(generator, name); + else if ( nonLLVMRefs.find(name) != nonLLVMRefs.end() ) + ::lto_codegen_add_must_preserve_symbol(generator, name); + } + + // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o) + if ( (outputKind == Options::kObjectFile) && !hasNonllvmAtoms ) { + if ( ! ::lto_codegen_write_merged_modules(generator, outputFilePath) ) { + // HACK, no good way to tell linker we are all done, so just quit + exit(0); + } + warning("could not produce merged bitcode file"); + } + + // if requested, save off merged bitcode file + if ( saveTemps ) { + char tempBitcodePath[MAXPATHLEN]; + strcpy(tempBitcodePath, outputFilePath); + strcat(tempBitcodePath, ".lto.bc"); + ::lto_codegen_write_merged_modules(generator, tempBitcodePath); + } + + // set code-gen model + lto_codegen_model model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; + switch ( outputKind ) { + case Options::kDynamicExecutable: + if ( pie ) + model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; + else + model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC; + break; + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kObjectFile: // ?? Is this appropriate ? + case Options::kDyld: + if ( allowTextRelocs ) + model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC; + else + model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; + break; + case Options::kStaticExecutable: + model = LTO_CODEGEN_PIC_MODEL_STATIC; + break; + } + if ( ::lto_codegen_set_pic_model(generator, model) ) + throwf("could not create set codegen model: %s", lto_get_error_message()); + + // run code generator + size_t machOFileLen; + const uint8_t* machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen); + if ( machOFile == NULL ) + throwf("could not do LTO codegen: %s", ::lto_get_error_message()); + + // if requested, save off temp mach-o file + if ( saveTemps ) { + char tempMachoPath[MAXPATHLEN]; + strcpy(tempMachoPath, outputFilePath); + strcat(tempMachoPath, ".lto.o"); + int fd = ::open(tempMachoPath, O_CREAT | O_WRONLY | O_TRUNC, 0666); + if ( fd != -1) { + ::write(fd, machOFile, machOFileLen); + ::close(fd); + } + } + + // parse generated mach-o file into a MachOReader + ObjectFile::Reader* machoReader = this->makeMachOReader(machOFile, machOFileLen, nextInputOrdinal); + + // sync generated mach-o atoms with existing atoms ld knows about + std::vector machoAtoms = machoReader->getAtoms(); + for (std::vector::iterator it = machoAtoms.begin(); it != machoAtoms.end(); ++it) { + ObjectFile::Atom* atom = *it; + const char* name = atom->getName(); + if ( name != NULL ) { + CStringToAtom::iterator pos = llvmAtoms.find(name); + if ( pos != llvmAtoms.end() ) { + // turn Atom into a proxy for this mach-o atom + pos->second->setRealAtom(atom); + } + else { + // an atom of this name was not in the allAtoms list the linker gave us + if ( deadllvmAtoms.find(name) != deadllvmAtoms.end() ) { + // this corresponding to an atom that the linker coalesced away. Ignore it + // Make sure there any dependent atoms are also marked dead + std::vector& refs = atom->getReferences(); + for (std::vector::iterator ri=refs.begin(), re=refs.end(); ri != re; ++ri) { + ObjectFile::Reference* ref = *ri; + if ( ref->getKind() == 2 /*kGroupSubordinate*/ ) { // FIX FIX + ObjectFile::Atom* targ = &ref->getTarget(); + deadllvmAtoms[targ->getName()] = (Atom*)atom; + } + } + } + else + { + // this is something new that lto conjured up, tell ld its new + newAtoms.push_back(atom); + } + } + } + else { + // ld only knew about named atoms, so this one must be new + newAtoms.push_back(atom); + } + std::vector& references = atom->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); ++rit) { + ObjectFile::Reference* ref = *rit; + const char* targetName = ref->getTargetName(); + CStringToAtom::iterator pos; + if (targetName != NULL) { + switch ( ref->getTargetBinding() ) { + case ObjectFile::Reference::kUnboundByName: + // accumulate unbounded references so that ld can bound them. + additionalUndefines.push_back(targetName); + break; + case ObjectFile::Reference::kBoundDirectly: + case ObjectFile::Reference::kBoundByName: + // If mach-o atom is referencing another mach-o atom then + // reference is not going through Atom proxy. Fix it here to ensure that all + // llvm symbol references always go through Atom proxy. + pos = llvmAtoms.find(targetName); + if ( pos != llvmAtoms.end() ) + ref->setTarget(*pos->second, ref->getTargetOffset()); + break; + case ObjectFile::Reference::kDontBind: + break; + } + } + } + } + + // Remove InternalAtoms from ld + std::set deletedAtoms; + for (std::set::iterator it=fgReaders.begin(); it != fgReaders.end(); ++it) { + deletedAtoms.insert(&((*it)->fInternalAtom)); + } + // Remove Atoms from ld if code generator optimized them away + for (CStringToAtom::iterator li = llvmAtoms.begin(), le = llvmAtoms.end(); li != le; ++li) { + // check if setRealAtom() called on this Atom + if ( li->second->getRealAtom() == NULL ) + deletedAtoms.insert(li->second); + } + allAtoms.erase(std::remove_if(allAtoms.begin(), allAtoms.end(), RemovableAtoms(deletedAtoms)), allAtoms.end()); +} + + +ObjectFile::Reader* Reader::makeMachOReader(const uint8_t* p, size_t len, uint32_t nextInputOrdinal) +{ + switch ( fArchitecture ) { + case CPU_TYPE_POWERPC: + if ( mach_o::relocatable::Reader::validFile(p) ) + return new mach_o::relocatable::Reader(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal); + break; + case CPU_TYPE_POWERPC64: + if ( mach_o::relocatable::Reader::validFile(p) ) + return new mach_o::relocatable::Reader(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal); + break; + case CPU_TYPE_I386: + if ( mach_o::relocatable::Reader::validFile(p) ) + return new mach_o::relocatable::Reader(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal); + break; + case CPU_TYPE_X86_64: + if ( mach_o::relocatable::Reader::validFile(p) ) + return new mach_o::relocatable::Reader(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal); + break; + case CPU_TYPE_ARM: + if ( mach_o::relocatable::Reader::validFile(p) ) + return new mach_o::relocatable::Reader(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal); + break; + } + throw "LLVM LTO, file is not of required architecture"; +} + +}; // namespace lto + + +void printLTOVersion(Options &opts) { + const char* vers = lto_get_version(); + if ( vers != NULL ) + fprintf(stderr, "%s\n", vers); +} + + +#endif + diff --git a/FireOpal/src/MachOFileAbstraction.hpp b/FireOpal/src/MachOFileAbstraction.hpp new file mode 100644 index 0000000..83a8ee1 --- /dev/null +++ b/FireOpal/src/MachOFileAbstraction.hpp @@ -0,0 +1,925 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2005-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 __MACH_O_FILE_ABSTRACTION__ +#define __MACH_O_FILE_ABSTRACTION__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FileAbstraction.hpp" +#include "Architectures.hpp" + +// stuff that will eventually go away once newer cctools headers are widespread +#ifndef LC_LAZY_LOAD_DYLIB + #define LC_LAZY_LOAD_DYLIB 0x20 +#endif +#ifndef S_LAZY_DYLIB_SYMBOL_POINTERS + #define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10 +#endif +#ifndef CPU_SUBTYPE_ARM_V5TEJ + #define CPU_SUBTYPE_ARM_V5TEJ ((cpu_subtype_t) 7) +#endif +#ifndef CPU_SUBTYPE_ARM_XSCALE + #define CPU_SUBTYPE_ARM_XSCALE ((cpu_subtype_t) 8) +#endif +#ifndef CPU_SUBTYPE_ARM_V7 + #define CPU_SUBTYPE_ARM_V7 ((cpu_subtype_t) 9) +#endif +#ifndef N_ARM_THUMB_DEF + #define N_ARM_THUMB_DEF 0x0008 +#endif +enum reloc_type_arm +{ + ARM_RELOC_VANILLA, /* generic relocation as discribed above */ + ARM_RELOC_PAIR, /* the second relocation entry of a pair */ + ARM_RELOC_SECTDIFF, /* a PAIR follows with subtract symbol value */ + ARM_RELOC_LOCAL_SECTDIFF, /* like ARM_RELOC_SECTDIFF, but the symbol + referenced was local. */ + ARM_RELOC_PB_LA_PTR,/* prebound lazy pointer */ + ARM_RELOC_BR24, /* 24 bit branch displacement (to a word address) */ + ARM_THUMB_RELOC_BR22, /* 22 bit branch displacement (to a half-word + address) */ +}; + +#ifndef LC_ENCRYPTION_INFO + #define LC_ENCRYPTION_INFO 0x21 + struct encryption_info_command { + uint32_t cmd; + uint32_t cmdsize; + uint32_t cryptoff; /* file offset of encrypted range */ + uint32_t cryptsize; /* file size of encrypted range */ + uint32_t cryptid; /* which enryption system, 0 means not-encrypted yet */ + }; +#endif + + +// +// This abstraction layer makes every mach-o file look like a 64-bit mach-o file with native endianness +// + + + +// +// mach-o file header +// +template struct macho_header_content {}; +template <> struct macho_header_content > { mach_header fields; }; +template <> struct macho_header_content > { mach_header_64 fields; }; +template <> struct macho_header_content > { mach_header fields; }; +template <> struct macho_header_content > { mach_header_64 fields; }; + +template +class macho_header { +public: + uint32_t magic() const INLINE { return E::get32(header.fields.magic); } + void set_magic(uint32_t value) INLINE { E::set32(header.fields.magic, value); } + + uint32_t cputype() const INLINE { return E::get32(header.fields.cputype); } + void set_cputype(uint32_t value) INLINE { E::set32((uint32_t&)header.fields.cputype, value); } + + uint32_t cpusubtype() const INLINE { return E::get32(header.fields.cpusubtype); } + void set_cpusubtype(uint32_t value) INLINE { E::set32((uint32_t&)header.fields.cpusubtype, value); } + + uint32_t filetype() const INLINE { return E::get32(header.fields.filetype); } + void set_filetype(uint32_t value) INLINE { E::set32(header.fields.filetype, value); } + + uint32_t ncmds() const INLINE { return E::get32(header.fields.ncmds); } + void set_ncmds(uint32_t value) INLINE { E::set32(header.fields.ncmds, value); } + + uint32_t sizeofcmds() const INLINE { return E::get32(header.fields.sizeofcmds); } + void set_sizeofcmds(uint32_t value) INLINE { E::set32(header.fields.sizeofcmds, value); } + + uint32_t flags() const INLINE { return E::get32(header.fields.flags); } + void set_flags(uint32_t value) INLINE { E::set32(header.fields.flags, value); } + + uint32_t reserved() const INLINE { return E::get32(header.fields.reserved); } + void set_reserved(uint32_t value) INLINE { E::set32(header.fields.reserved, value); } + + typedef typename P::E E; +private: + macho_header_content

header; +}; + + +// +// mach-o load command +// +template +class macho_load_command { +public: + uint32_t cmd() const INLINE { return E::get32(command.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(command.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(command.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(command.cmdsize, value); } + + typedef typename P::E E; +private: + load_command command; +}; + + +// +// mach-o segment load command +// +template struct macho_segment_content {}; +template <> struct macho_segment_content > { segment_command fields; enum { CMD = LC_SEGMENT }; }; +template <> struct macho_segment_content > { segment_command_64 fields; enum { CMD = LC_SEGMENT_64 }; }; +template <> struct macho_segment_content > { segment_command fields; enum { CMD = LC_SEGMENT }; }; +template <> struct macho_segment_content > { segment_command_64 fields; enum { CMD = LC_SEGMENT_64 }; }; + +template +class macho_segment_command { +public: + uint32_t cmd() const INLINE { return E::get32(segment.fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(segment.fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(segment.fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(segment.fields.cmdsize, value); } + + const char* segname() const INLINE { return segment.fields.segname; } + void set_segname(const char* value) INLINE { strncpy(segment.fields.segname, value, 16); } + + uint64_t vmaddr() const INLINE { return P::getP(segment.fields.vmaddr); } + void set_vmaddr(uint64_t value) INLINE { P::setP(segment.fields.vmaddr, value); } + + uint64_t vmsize() const INLINE { return P::getP(segment.fields.vmsize); } + void set_vmsize(uint64_t value) INLINE { P::setP(segment.fields.vmsize, value); } + + uint64_t fileoff() const INLINE { return P::getP(segment.fields.fileoff); } + void set_fileoff(uint64_t value) INLINE { P::setP(segment.fields.fileoff, value); } + + uint64_t filesize() const INLINE { return P::getP(segment.fields.filesize); } + void set_filesize(uint64_t value) INLINE { P::setP(segment.fields.filesize, value); } + + uint32_t maxprot() const INLINE { return E::get32(segment.fields.maxprot); } + void set_maxprot(uint32_t value) INLINE { E::set32((uint32_t&)segment.fields.maxprot, value); } + + uint32_t initprot() const INLINE { return E::get32(segment.fields.initprot); } + void set_initprot(uint32_t value) INLINE { E::set32((uint32_t&)segment.fields.initprot, value); } + + uint32_t nsects() const INLINE { return E::get32(segment.fields.nsects); } + void set_nsects(uint32_t value) INLINE { E::set32(segment.fields.nsects, value); } + + uint32_t flags() const INLINE { return E::get32(segment.fields.flags); } + void set_flags(uint32_t value) INLINE { E::set32(segment.fields.flags, value); } + + enum { + CMD = macho_segment_content

::CMD + }; + + typedef typename P::E E; +private: + macho_segment_content

segment; +}; + + +// +// mach-o section +// +template struct macho_section_content {}; +template <> struct macho_section_content > { section fields; }; +template <> struct macho_section_content > { section_64 fields; }; +template <> struct macho_section_content > { section fields; }; +template <> struct macho_section_content > { section_64 fields; }; + +template +class macho_section { +public: + const char* sectname() const INLINE { return section.fields.sectname; } + void set_sectname(const char* value) INLINE { strncpy(section.fields.sectname, value, 16); } + + const char* segname() const INLINE { return section.fields.segname; } + void set_segname(const char* value) INLINE { strncpy(section.fields.segname, value, 16); } + + uint64_t addr() const INLINE { return P::getP(section.fields.addr); } + void set_addr(uint64_t value) INLINE { P::setP(section.fields.addr, value); } + + uint64_t size() const INLINE { return P::getP(section.fields.size); } + void set_size(uint64_t value) INLINE { P::setP(section.fields.size, value); } + + uint32_t offset() const INLINE { return E::get32(section.fields.offset); } + void set_offset(uint32_t value) INLINE { E::set32(section.fields.offset, value); } + + uint32_t align() const INLINE { return E::get32(section.fields.align); } + void set_align(uint32_t value) INLINE { E::set32(section.fields.align, value); } + + uint32_t reloff() const INLINE { return E::get32(section.fields.reloff); } + void set_reloff(uint32_t value) INLINE { E::set32(section.fields.reloff, value); } + + uint32_t nreloc() const INLINE { return E::get32(section.fields.nreloc); } + void set_nreloc(uint32_t value) INLINE { E::set32(section.fields.nreloc, value); } + + uint32_t flags() const INLINE { return E::get32(section.fields.flags); } + void set_flags(uint32_t value) INLINE { E::set32(section.fields.flags, value); } + + uint32_t reserved1() const INLINE { return E::get32(section.fields.reserved1); } + void set_reserved1(uint32_t value) INLINE { E::set32(section.fields.reserved1, value); } + + uint32_t reserved2() const INLINE { return E::get32(section.fields.reserved2); } + void set_reserved2(uint32_t value) INLINE { E::set32(section.fields.reserved2, value); } + + typedef typename P::E E; +private: + macho_section_content

section; +}; + + +// +// mach-o dylib load command +// +template +class macho_dylib_command { +public: + uint32_t cmd() const INLINE { return E::get32(fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); } + + uint32_t name_offset() const INLINE { return E::get32(fields.dylib.name.offset); } + void set_name_offset(uint32_t value) INLINE { E::set32(fields.dylib.name.offset, value); } + + uint32_t timestamp() const INLINE { return E::get32(fields.dylib.timestamp); } + void set_timestamp(uint32_t value) INLINE { E::set32(fields.dylib.timestamp, value); } + + uint32_t current_version() const INLINE { return E::get32(fields.dylib.current_version); } + void set_current_version(uint32_t value) INLINE { E::set32(fields.dylib.current_version, value); } + + uint32_t compatibility_version() const INLINE { return E::get32(fields.dylib.compatibility_version); } + void set_compatibility_version(uint32_t value) INLINE { E::set32(fields.dylib.compatibility_version, value); } + + const char* name() const INLINE { return (const char*)&fields + name_offset(); } + void set_name_offset() INLINE { set_name_offset(sizeof(fields)); } + + typedef typename P::E E; +private: + dylib_command fields; +}; + + +// +// mach-o dylinker load command +// +template +class macho_dylinker_command { +public: + uint32_t cmd() const INLINE { return E::get32(fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); } + + uint32_t name_offset() const INLINE { return E::get32(fields.name.offset); } + void set_name_offset(uint32_t value) INLINE { E::set32(fields.name.offset, value); } + + const char* name() const INLINE { return (const char*)&fields + name_offset(); } + void set_name_offset() INLINE { set_name_offset(sizeof(fields)); } + + typedef typename P::E E; +private: + dylinker_command fields; +}; + + +// +// mach-o sub_framework load command +// +template +class macho_sub_framework_command { +public: + uint32_t cmd() const INLINE { return E::get32(fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); } + + uint32_t umbrella_offset() const INLINE { return E::get32(fields.umbrella.offset); } + void set_umbrella_offset(uint32_t value) INLINE { E::set32(fields.umbrella.offset, value); } + + const char* umbrella() const INLINE { return (const char*)&fields + umbrella_offset(); } + void set_umbrella_offset() INLINE { set_umbrella_offset(sizeof(fields)); } + + typedef typename P::E E; +private: + sub_framework_command fields; +}; + + +// +// mach-o sub_client load command +// +template +class macho_sub_client_command { +public: + uint32_t cmd() const INLINE { return E::get32(fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); } + + uint32_t client_offset() const INLINE { return E::get32(fields.client.offset); } + void set_client_offset(uint32_t value) INLINE { E::set32(fields.client.offset, value); } + + const char* client() const INLINE { return (const char*)&fields + client_offset(); } + void set_client_offset() INLINE { set_client_offset(sizeof(fields)); } + + typedef typename P::E E; +private: + sub_client_command fields; +}; + + +// +// mach-o sub_umbrella load command +// +template +class macho_sub_umbrella_command { +public: + uint32_t cmd() const INLINE { return E::get32(fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); } + + uint32_t sub_umbrella_offset() const INLINE { return E::get32(fields.sub_umbrella.offset); } + void set_sub_umbrella_offset(uint32_t value) INLINE { E::set32(fields.sub_umbrella.offset, value); } + + const char* sub_umbrella() const INLINE { return (const char*)&fields + sub_umbrella_offset(); } + void set_sub_umbrella_offset() INLINE { set_sub_umbrella_offset(sizeof(fields)); } + + typedef typename P::E E; +private: + sub_umbrella_command fields; +}; + + +// +// mach-o sub_library load command +// +template +class macho_sub_library_command { +public: + uint32_t cmd() const INLINE { return E::get32(fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); } + + uint32_t sub_library_offset() const INLINE { return E::get32(fields.sub_library.offset); } + void set_sub_library_offset(uint32_t value) INLINE { E::set32(fields.sub_library.offset, value); } + + const char* sub_library() const INLINE { return (const char*)&fields + sub_library_offset(); } + void set_sub_library_offset() INLINE { set_sub_library_offset(sizeof(fields)); } + + typedef typename P::E E; +private: + sub_library_command fields; +}; + + +// +// mach-o uuid load command +// +template +class macho_uuid_command { +public: + uint32_t cmd() const INLINE { return E::get32(fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); } + + const uint8_t* uuid() const INLINE { return fields.uuid; } + void set_uuid(uint8_t uuid[16]) INLINE { memcpy(&fields.uuid, uuid, 16); } + + typedef typename P::E E; +private: + uuid_command fields; +}; + + +// +// mach-o routines load command +// +template struct macho_routines_content {}; +template <> struct macho_routines_content > { routines_command fields; enum { CMD = LC_ROUTINES }; }; +template <> struct macho_routines_content > { routines_command_64 fields; enum { CMD = LC_ROUTINES_64 }; }; +template <> struct macho_routines_content > { routines_command fields; enum { CMD = LC_ROUTINES }; }; +template <> struct macho_routines_content > { routines_command_64 fields; enum { CMD = LC_ROUTINES_64 }; }; + +template +class macho_routines_command { +public: + uint32_t cmd() const INLINE { return E::get32(routines.fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(routines.fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(routines.fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(routines.fields.cmdsize, value); } + + uint64_t init_address() const INLINE { return P::getP(routines.fields.init_address); } + void set_init_address(uint64_t value) INLINE { P::setP(routines.fields.init_address, value); } + + uint64_t init_module() const INLINE { return P::getP(routines.fields.init_module); } + void set_init_module(uint64_t value) INLINE { P::setP(routines.fields.init_module, value); } + + uint64_t reserved1() const INLINE { return P::getP(routines.fields.reserved1); } + void set_reserved1(uint64_t value) INLINE { P::setP(routines.fields.reserved1, value); } + + uint64_t reserved2() const INLINE { return P::getP(routines.fields.reserved2); } + void set_reserved2(uint64_t value) INLINE { P::setP(routines.fields.reserved2, value); } + + uint64_t reserved3() const INLINE { return P::getP(routines.fields.reserved3); } + void set_reserved3(uint64_t value) INLINE { P::setP(routines.fields.reserved3, value); } + + uint64_t reserved4() const INLINE { return P::getP(routines.fields.reserved4); } + void set_reserved4(uint64_t value) INLINE { P::setP(routines.fields.reserved4, value); } + + uint64_t reserved5() const INLINE { return P::getP(routines.fields.reserved5); } + void set_reserved5(uint64_t value) INLINE { P::setP(routines.fields.reserved5, value); } + + uint64_t reserved6() const INLINE { return P::getP(routines.fields.reserved6); } + void set_reserved6(uint64_t value) INLINE { P::setP(routines.fields.reserved6, value); } + + typedef typename P::E E; + enum { + CMD = macho_routines_content

::CMD + }; +private: + macho_routines_content

routines; +}; + + +// +// mach-o symbol table load command +// +template +class macho_symtab_command { +public: + uint32_t cmd() const INLINE { return E::get32(fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); } + + uint32_t symoff() const INLINE { return E::get32(fields.symoff); } + void set_symoff(uint32_t value) INLINE { E::set32(fields.symoff, value); } + + uint32_t nsyms() const INLINE { return E::get32(fields.nsyms); } + void set_nsyms(uint32_t value) INLINE { E::set32(fields.nsyms, value); } + + uint32_t stroff() const INLINE { return E::get32(fields.stroff); } + void set_stroff(uint32_t value) INLINE { E::set32(fields.stroff, value); } + + uint32_t strsize() const INLINE { return E::get32(fields.strsize); } + void set_strsize(uint32_t value) INLINE { E::set32(fields.strsize, value); } + + + typedef typename P::E E; +private: + symtab_command fields; +}; + + +// +// mach-o dynamic symbol table load command +// +template +class macho_dysymtab_command { +public: + uint32_t cmd() const INLINE { return E::get32(fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); } + + uint32_t ilocalsym() const INLINE { return E::get32(fields.ilocalsym); } + void set_ilocalsym(uint32_t value) INLINE { E::set32(fields.ilocalsym, value); } + + uint32_t nlocalsym() const INLINE { return E::get32(fields.nlocalsym); } + void set_nlocalsym(uint32_t value) INLINE { E::set32(fields.nlocalsym, value); } + + uint32_t iextdefsym() const INLINE { return E::get32(fields.iextdefsym); } + void set_iextdefsym(uint32_t value) INLINE { E::set32(fields.iextdefsym, value); } + + uint32_t nextdefsym() const INLINE { return E::get32(fields.nextdefsym); } + void set_nextdefsym(uint32_t value) INLINE { E::set32(fields.nextdefsym, value); } + + uint32_t iundefsym() const INLINE { return E::get32(fields.iundefsym); } + void set_iundefsym(uint32_t value) INLINE { E::set32(fields.iundefsym, value); } + + uint32_t nundefsym() const INLINE { return E::get32(fields.nundefsym); } + void set_nundefsym(uint32_t value) INLINE { E::set32(fields.nundefsym, value); } + + uint32_t tocoff() const INLINE { return E::get32(fields.tocoff); } + void set_tocoff(uint32_t value) INLINE { E::set32(fields.tocoff, value); } + + uint32_t ntoc() const INLINE { return E::get32(fields.ntoc); } + void set_ntoc(uint32_t value) INLINE { E::set32(fields.ntoc, value); } + + uint32_t modtaboff() const INLINE { return E::get32(fields.modtaboff); } + void set_modtaboff(uint32_t value) INLINE { E::set32(fields.modtaboff, value); } + + uint32_t nmodtab() const INLINE { return E::get32(fields.nmodtab); } + void set_nmodtab(uint32_t value) INLINE { E::set32(fields.nmodtab, value); } + + uint32_t extrefsymoff() const INLINE { return E::get32(fields.extrefsymoff); } + void set_extrefsymoff(uint32_t value) INLINE { E::set32(fields.extrefsymoff, value); } + + uint32_t nextrefsyms() const INLINE { return E::get32(fields.nextrefsyms); } + void set_nextrefsyms(uint32_t value) INLINE { E::set32(fields.nextrefsyms, value); } + + uint32_t indirectsymoff() const INLINE { return E::get32(fields.indirectsymoff); } + void set_indirectsymoff(uint32_t value) INLINE { E::set32(fields.indirectsymoff, value); } + + uint32_t nindirectsyms() const INLINE { return E::get32(fields.nindirectsyms); } + void set_nindirectsyms(uint32_t value) INLINE { E::set32(fields.nindirectsyms, value); } + + uint32_t extreloff() const INLINE { return E::get32(fields.extreloff); } + void set_extreloff(uint32_t value) INLINE { E::set32(fields.extreloff, value); } + + uint32_t nextrel() const INLINE { return E::get32(fields.nextrel); } + void set_nextrel(uint32_t value) INLINE { E::set32(fields.nextrel, value); } + + uint32_t locreloff() const INLINE { return E::get32(fields.locreloff); } + void set_locreloff(uint32_t value) INLINE { E::set32(fields.locreloff, value); } + + uint32_t nlocrel() const INLINE { return E::get32(fields.nlocrel); } + void set_nlocrel(uint32_t value) INLINE { E::set32(fields.nlocrel, value); } + + typedef typename P::E E; +private: + dysymtab_command fields; +}; + + + + +// +// mach-o module table entry (for compatibility with old ld/dyld) +// +template struct macho_dylib_module_content {}; +template <> struct macho_dylib_module_content > { struct dylib_module fields; }; +template <> struct macho_dylib_module_content > { struct dylib_module fields; }; +template <> struct macho_dylib_module_content > { struct dylib_module_64 fields; }; +template <> struct macho_dylib_module_content > { struct dylib_module_64 fields; }; + +template +class macho_dylib_module { +public: + uint32_t module_name() const INLINE { return E::get32(module.fields.module_name); } + void set_module_name(uint32_t value) INLINE { E::set32(module.fields.module_name, value); } + + uint32_t iextdefsym() const INLINE { return E::get32(module.fields.iextdefsym); } + void set_iextdefsym(uint32_t value) INLINE { E::set32(module.fields.iextdefsym, value); } + + uint32_t nextdefsym() const INLINE { return E::get32(module.fields.nextdefsym); } + void set_nextdefsym(uint32_t value) INLINE { E::set32(module.fields.nextdefsym, value); } + + uint32_t irefsym() const INLINE { return E::get32(module.fields.irefsym); } + void set_irefsym(uint32_t value) INLINE { E::set32(module.fields.irefsym, value); } + + uint32_t nrefsym() const INLINE { return E::get32(module.fields.nrefsym); } + void set_nrefsym(uint32_t value) INLINE { E::set32(module.fields.nrefsym, value); } + + uint32_t ilocalsym() const INLINE { return E::get32(module.fields.ilocalsym); } + void set_ilocalsym(uint32_t value) INLINE { E::set32(module.fields.ilocalsym, value); } + + uint32_t nlocalsym() const INLINE { return E::get32(module.fields.nlocalsym); } + void set_nlocalsym(uint32_t value) INLINE { E::set32(module.fields.nlocalsym, value); } + + uint32_t iextrel() const INLINE { return E::get32(module.fields.iextrel); } + void set_iextrel(uint32_t value) INLINE { E::set32(module.fields.iextrel, value); } + + uint32_t nextrel() const INLINE { return E::get32(module.fields.nextrel); } + void set_nextrel(uint32_t value) INLINE { E::set32(module.fields.nextrel, value); } + + uint16_t iinit() const INLINE { return E::get32(module.fields.iinit_iterm) & 0xFFFF; } + uint16_t iterm() const INLINE { return E::get32(module.fields.iinit_iterm) > 16; } + void set_iinit_iterm(uint16_t init, uint16_t term) INLINE { E::set32(module.fields.iinit_iterm, (term<<16) | (init &0xFFFF)); } + + uint16_t ninit() const INLINE { return E::get32(module.fields.ninit_nterm) & 0xFFFF; } + uint16_t nterm() const INLINE { return E::get32(module.fields.ninit_nterm) > 16; } + void set_ninit_nterm(uint16_t init, uint16_t term) INLINE { E::set32(module.fields.ninit_nterm, (term<<16) | (init &0xFFFF)); } + + uint64_t objc_module_info_addr() const INLINE { return P::getP(module.fields.objc_module_info_addr); } + void set_objc_module_info_addr(uint64_t value) INLINE { P::setP(module.fields.objc_module_info_addr, value); } + + uint32_t objc_module_info_size() const INLINE { return E::get32(module.fields.objc_module_info_size); } + void set_objc_module_info_size(uint32_t value) INLINE { E::set32(module.fields.objc_module_info_size, value); } + + + typedef typename P::E E; +private: + macho_dylib_module_content

module; +}; + + +// +// mach-o dylib_reference entry +// +template +class macho_dylib_reference { +public: + uint32_t isym() const INLINE { return E::getBits(fields, 0, 24); } + void set_isym(uint32_t value) INLINE { E::setBits(fields, value, 0, 24); } + + uint8_t flags() const INLINE { return E::getBits(fields, 24, 8); } + void set_flags(uint8_t value) INLINE { E::setBits(fields, value, 24, 8); } + + typedef typename P::E E; +private: + uint32_t fields; +}; + + + +// +// mach-o two-level hints load command +// +template +class macho_dylib_table_of_contents { +public: + uint32_t symbol_index() const INLINE { return E::get32(fields.symbol_index); } + void set_symbol_index(uint32_t value) INLINE { E::set32(fields.symbol_index, value); } + + uint32_t module_index() const INLINE { return E::get32(fields.module_index); } + void set_module_index(uint32_t value) INLINE { E::set32(fields.module_index, value); } + + typedef typename P::E E; +private: + dylib_table_of_contents fields; +}; + + + +// +// mach-o two-level hints load command +// +template +class macho_twolevel_hints_command { +public: + uint32_t cmd() const INLINE { return E::get32(fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); } + + uint32_t offset() const INLINE { return E::get32(fields.offset); } + void set_offset(uint32_t value) INLINE { E::set32(fields.offset, value); } + + uint32_t nhints() const INLINE { return E::get32(fields.nhints); } + void set_nhints(uint32_t value) INLINE { E::set32(fields.nhints, value); } + + typedef typename P::E E; +private: + twolevel_hints_command fields; +}; + + +// +// mach-o threads load command +// +template +class macho_thread_command { +public: + uint32_t cmd() const INLINE { return E::get32(fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); } + + uint32_t flavor() const INLINE { return E::get32(fields_flavor); } + void set_flavor(uint32_t value) INLINE { E::set32(fields_flavor, value); } + + uint32_t count() const INLINE { return E::get32(fields_count); } + void set_count(uint32_t value) INLINE { E::set32(fields_count, value); } + + uint64_t thread_register(uint32_t index) const INLINE { return P::getP(thread_registers[index]); } + void set_thread_register(uint32_t index, uint64_t value) INLINE { P::setP(thread_registers[index], value); } + + typedef typename P::E E; + typedef typename P::uint_t pint_t; +private: + struct thread_command fields; + uint32_t fields_flavor; + uint32_t fields_count; + pint_t thread_registers[1]; +}; + + +// +// mach-o misc data +// +template +class macho_linkedit_data_command { +public: + uint32_t cmd() const INLINE { return E::get32(fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); } + + uint32_t dataoff() const INLINE { return E::get32(fields.dataoff); } + void set_dataoff(uint32_t value) INLINE { E::set32(fields.dataoff, value); } + + uint32_t datasize() const INLINE { return E::get32(fields.datasize); } + void set_datasize(uint32_t value)INLINE { E::set32(fields.datasize, value); } + + + typedef typename P::E E; +private: + struct linkedit_data_command fields; +}; + + +// +// mach-o rpath +// +template +class macho_rpath_command { +public: + uint32_t cmd() const INLINE { return E::get32(fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); } + + uint32_t path_offset() const INLINE { return E::get32(fields.path.offset); } + void set_path_offset(uint32_t value) INLINE { E::set32(fields.path.offset, value); } + + const char* path() const INLINE { return (const char*)&fields + path_offset(); } + void set_path_offset() INLINE { set_path_offset(sizeof(fields)); } + + + typedef typename P::E E; +private: + struct rpath_command fields; +}; + + + +// +// mach-o symbol table entry +// +template struct macho_nlist_content {}; +template <> struct macho_nlist_content > { struct nlist fields; }; +template <> struct macho_nlist_content > { struct nlist_64 fields; }; +template <> struct macho_nlist_content > { struct nlist fields; }; +template <> struct macho_nlist_content > { struct nlist_64 fields; }; + +template +class macho_nlist { +public: + uint32_t n_strx() const INLINE { return E::get32(entry.fields.n_un.n_strx); } + void set_n_strx(uint32_t value) INLINE { E::set32((uint32_t&)entry.fields.n_un.n_strx, value); } + + uint8_t n_type() const INLINE { return entry.fields.n_type; } + void set_n_type(uint8_t value) INLINE { entry.fields.n_type = value; } + + uint8_t n_sect() const INLINE { return entry.fields.n_sect; } + void set_n_sect(uint8_t value) INLINE { entry.fields.n_sect = value; } + + uint16_t n_desc() const INLINE { return E::get16(entry.fields.n_desc); } + void set_n_desc(uint16_t value) INLINE { E::set16((uint16_t&)entry.fields.n_desc, value); } + + uint64_t n_value() const INLINE { return P::getP(entry.fields.n_value); } + void set_n_value(uint64_t value) INLINE { P::setP(entry.fields.n_value, value); } + + typedef typename P::E E; +private: + macho_nlist_content

entry; +}; + + + +// +// mach-o relocation info +// +template +class macho_relocation_info { +public: + uint32_t r_address() const INLINE { return E::get32(address); } + void set_r_address(uint32_t value) INLINE { E::set32(address, value); } + + uint32_t r_symbolnum() const INLINE { return E::getBits(other, 0, 24); } + void set_r_symbolnum(uint32_t value) INLINE { E::setBits(other, value, 0, 24); } + + bool r_pcrel() const INLINE { return E::getBits(other, 24, 1); } + void set_r_pcrel(bool value) INLINE { E::setBits(other, value, 24, 1); } + + uint8_t r_length() const INLINE { return E::getBits(other, 25, 2); } + void set_r_length(uint8_t value) INLINE { E::setBits(other, value, 25, 2); } + + bool r_extern() const INLINE { return E::getBits(other, 27, 1); } + void set_r_extern(bool value) INLINE { E::setBits(other, value, 27, 1); } + + uint8_t r_type() const INLINE { return E::getBits(other, 28, 4); } + void set_r_type(uint8_t value) INLINE { E::setBits(other, value, 28, 4); } + + void set_r_length() INLINE { set_r_length((sizeof(typename P::uint_t)==8) ? 3 : 2); } + + typedef typename P::E E; +private: + uint32_t address; + uint32_t other; +}; + + +// +// mach-o scattered relocation info +// The bit fields are always in big-endian order (see mach-o/reloc.h) +// +template +class macho_scattered_relocation_info { +public: + bool r_scattered() const INLINE { return BigEndian::getBitsRaw(E::get32(other), 0, 1); } + void set_r_scattered(bool x) INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 0, 1); E::set32(other, temp); } + + bool r_pcrel() const INLINE { return BigEndian::getBitsRaw(E::get32(other), 1, 1); } + void set_r_pcrel(bool x) INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 1, 1); E::set32(other, temp); } + + uint8_t r_length() const INLINE { return BigEndian::getBitsRaw(E::get32(other), 2, 2); } + void set_r_length(uint8_t x) INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 2, 2); E::set32(other, temp); } + + uint8_t r_type() const INLINE { return BigEndian::getBitsRaw(E::get32(other), 4, 4); } + void set_r_type(uint8_t x) INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 4, 4); E::set32(other, temp); } + + uint32_t r_address() const INLINE { return BigEndian::getBitsRaw(E::get32(other), 8, 24); } + void set_r_address(uint32_t x) { if ( x > 0x00FFFFFF ) throw "scattered reloc r_address too large"; + uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 8, 24); E::set32(other, temp); } + + uint32_t r_value() const INLINE { return E::get32(value); } + void set_r_value(uint32_t x) INLINE { E::set32(value, x); } + + uint32_t r_other() const INLINE { return other; } + + void set_r_length() INLINE { set_r_length((sizeof(typename P::uint_t)==8) ? 3 : 2); } + + typedef typename P::E E; +private: + uint32_t other; + uint32_t value; +}; + + + +// +// mach-o encyrption info load command +// +template +class macho_encryption_info_command { +public: + uint32_t cmd() const INLINE { return E::get32(fields.cmd); } + void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); } + + uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); } + void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); } + + uint32_t cryptoff() const INLINE { return E::get32(fields.cryptoff); } + void set_cryptoff(uint32_t value) INLINE { E::set32(fields.cryptoff, value); } + + uint32_t cryptsize() const INLINE { return E::get32(fields.cryptsize); } + void set_cryptsize(uint32_t value) INLINE { E::set32(fields.cryptsize, value); } + + uint32_t cryptid() const INLINE { return E::get32(fields.cryptid); } + void set_cryptid(uint32_t value) INLINE { E::set32(fields.cryptid, value); } + + typedef typename P::E E; +private: + encryption_info_command fields; +}; + + + +#endif // __MACH_O_FILE_ABSTRACTION__ + + diff --git a/FireOpal/src/MachOReaderDylib.hpp b/FireOpal/src/MachOReaderDylib.hpp new file mode 100644 index 0000000..eb8e844 --- /dev/null +++ b/FireOpal/src/MachOReaderDylib.hpp @@ -0,0 +1,926 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2005-2007 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 __OBJECT_FILE_DYLIB_MACH_O__ +#define __OBJECT_FILE_DYLIB_MACH_O__ + +#include +#include +#include +#include + + +#include +#include +#include +#include + +#include "MachOFileAbstraction.hpp" +#include "ObjectFile.h" + +// +// +// To implement architecture xxx, you must write template specializations for the following method: +// Reader::validFile() +// +// + + + + +namespace mach_o { +namespace dylib { + + +// forward reference +template class Reader; + + +class Segment : public ObjectFile::Segment +{ +public: + Segment(const char* name) { fName = name; } + virtual const char* getName() const { return fName; } + virtual bool isContentReadable() const { return true; } + virtual bool isContentWritable() const { return false; } + virtual bool isContentExecutable() const { return false; } +private: + const char* fName; +}; + + +// +// An ExportAtom has no content. It exists so that the linker can track which imported +// symbols came from which dynamic libraries. +// +template +class ExportAtom : public ObjectFile::Atom +{ +public: + virtual ObjectFile::Reader* getFile() const { return &fOwner; } + virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; } + virtual const char* getName() const { return fName; } + virtual const char* getDisplayName() const { return fName; } + virtual Scope getScope() const { return ObjectFile::Atom::scopeGlobal; } + virtual DefinitionKind getDefinitionKind() const { return fWeakDefinition ? kExternalWeakDefinition : kExternalDefinition; } + virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; } + virtual bool dontDeadStrip() const { return false; } + virtual bool isZeroFill() const { return false; } + virtual bool isThumb() const { return false; } + virtual uint64_t getSize() const { return 0; } + virtual std::vector& getReferences() const { return fgEmptyReferenceList; } + virtual bool mustRemainInSection() const { return false; } + virtual const char* getSectionName() const { return "._imports"; } + virtual Segment& getSegment() const { return fgImportSegment; } + virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); } + virtual uint32_t getOrdinal() const { return fOrdinal; } + virtual std::vector* getLineInfo() const { return NULL; } + virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); } + virtual void copyRawContent(uint8_t buffer[]) const {} + + virtual void setScope(Scope) { } + +protected: + friend class Reader; + typedef typename A::P P; + + ExportAtom(ObjectFile::Reader& owner, const char* name, bool weak, uint32_t ordinal) + : fOwner(owner), fName(name), fOrdinal(ordinal), fWeakDefinition(weak) {} + virtual ~ExportAtom() {} + + ObjectFile::Reader& fOwner; + const char* fName; + uint32_t fOrdinal; + bool fWeakDefinition; + + static std::vector fgEmptyReferenceList; + static Segment fgImportSegment; +}; + +template +Segment ExportAtom::fgImportSegment("__LINKEDIT"); + +template +std::vector ExportAtom::fgEmptyReferenceList; + + + +class ImportReference : public ObjectFile::Reference +{ +public: + ImportReference(const char* name) + : fTarget(NULL), fTargetName(strdup(name)) {} + virtual ~ImportReference() {} + + + virtual ObjectFile::Reference::TargetBinding getTargetBinding() const { return (fTarget==NULL) ? ObjectFile::Reference::kUnboundByName : ObjectFile::Reference::kBoundByName; } + virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const{ return ObjectFile::Reference::kDontBind; } + virtual uint8_t getKind() const { return 0; } + virtual uint64_t getFixUpOffset() const { return 0; } + virtual const char* getTargetName() const { return fTargetName; } + virtual ObjectFile::Atom& getTarget() const { return *((ObjectFile::Atom*)fTarget); } + virtual uint64_t getTargetOffset() const { return 0; } + virtual ObjectFile::Atom& getFromTarget() const { return *((ObjectFile::Atom*)NULL); } + virtual const char* getFromTargetName() const { return NULL; } + virtual uint64_t getFromTargetOffset() const { return 0; } + virtual void setTarget(ObjectFile::Atom& atom, uint64_t offset) { fTarget = &atom; } + virtual void setFromTarget(ObjectFile::Atom&) { throw "can't set from target"; } + virtual const char* getDescription() const { return "dylib import reference"; } + +private: + const ObjectFile::Atom* fTarget; + const char* fTargetName; +}; + + +// +// An ImportAtom has no content. It exists so that when linking a main executable flat-namespace +// the imports of all flat dylibs are checked +// +template +class ImportAtom : public ObjectFile::Atom +{ +public: + virtual ObjectFile::Reader* getFile() const { return &fOwner; } + virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; } + virtual const char* getName() const { return "flat-imports"; } + virtual const char* getDisplayName() const { return "flat_namespace undefines"; } + virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; } + virtual DefinitionKind getDefinitionKind() const { return kRegularDefinition; } + virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; } + virtual bool dontDeadStrip() const { return false; } + virtual bool isZeroFill() const { return false; } + virtual bool isThumb() const { return false; } + virtual uint64_t getSize() const { return 0; } + virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } + virtual bool mustRemainInSection() const { return false; } + virtual const char* getSectionName() const { return "._imports"; } + virtual Segment& getSegment() const { return fgImportSegment; } + virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); } + virtual uint32_t getOrdinal() const { return fOrdinal; } + virtual std::vector* getLineInfo() const { return NULL; } + virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); } + virtual void copyRawContent(uint8_t buffer[]) const {} + + virtual void setScope(Scope) { } + +protected: + friend class Reader; + typedef typename A::P P; + + ImportAtom(ObjectFile::Reader& owner, uint32_t ordinal, std::vector& imports) + : fOwner(owner), fOrdinal(ordinal) { makeReferences(imports); } + virtual ~ImportAtom() {} + void makeReferences(std::vector& imports) { + for (std::vector::iterator it=imports.begin(); it != imports.end(); ++it) { + fReferences.push_back(new ImportReference(*it)); + } + } + + + ObjectFile::Reader& fOwner; + uint32_t fOrdinal; + std::vector fReferences; + + static Segment fgImportSegment; +}; + +template +Segment ImportAtom::fgImportSegment("__LINKEDIT"); + + + + +// +// The reader for a dylib extracts all exported symbols names from the memory-mapped +// dylib, builds a hash table, then unmaps the file. This is an important memory +// savings for large dylibs. +// +template +class Reader : public ObjectFile::Reader +{ +public: + static bool validFile(const uint8_t* fileContent, bool executableOrDylib); + Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path, + const DynamicLibraryOptions& dylibOptions, const ObjectFile::ReaderOptions& options, + uint32_t ordinalBase); + virtual ~Reader() {} + + virtual const char* getPath() { return fPath; } + virtual time_t getModificationTime() { return 0; } + virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; } + virtual std::vector& getAtoms(); + virtual std::vector* getJustInTimeAtomsFor(const char* name); + virtual std::vector* getStabs() { return NULL; } + virtual ObjectFile::Reader::ObjcConstraint getObjCConstraint() { return fObjcContraint; } + virtual const char* getInstallPath() { return fDylibInstallPath; } + virtual uint32_t getTimestamp() { return fDylibTimeStamp; } + virtual uint32_t getCurrentVersion() { return fDylibtCurrentVersion; } + virtual uint32_t getCompatibilityVersion() { return fDylibCompatibilityVersion; } + virtual void processIndirectLibraries(DylibHander* handler); + virtual void setExplicitlyLinked() { fExplicitlyLinked = true; } + virtual bool explicitlyLinked() { return fExplicitlyLinked; } + virtual bool implicitlyLinked() { return fImplicitlyLinked; } + virtual bool providedExportAtom() { return fProvidedAtom; } + virtual const char* parentUmbrella() { return fParentUmbrella; } + virtual std::vector* getAllowableClients(); + virtual bool hasWeakExternals() { return fHasWeakExports; } + virtual bool isLazyLoadedDylib() { return fLazyLoaded; } + + virtual void setImplicitlyLinked() { fImplicitlyLinked = true; } + +protected: + + struct ReExportChain { ReExportChain* prev; Reader* reader; }; + + void assertNoReExportCycles(ReExportChain*); + +private: + typedef typename A::P P; + typedef typename A::P::E E; + + class CStringEquals + { + public: + bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } + }; + struct AtomAndWeak { ObjectFile::Atom* atom; bool weak; uint32_t ordinal; }; + typedef __gnu_cxx::hash_map, CStringEquals> NameToAtomMap; + typedef __gnu_cxx::hash_set, CStringEquals> NameSet; + typedef typename NameToAtomMap::iterator NameToAtomMapIterator; + + struct PathAndFlag { const char* path; bool reExport; }; + + bool isPublicLocation(const char* path); + void addSymbol(const char* name, bool weak, uint32_t ordinal); + + const char* fPath; + const char* fParentUmbrella; + std::vector fAllowableClients; + const char* fDylibInstallPath; + uint32_t fDylibTimeStamp; + uint32_t fDylibtCurrentVersion; + uint32_t fDylibCompatibilityVersion; + uint32_t fReExportedOrdinal; + std::vector fDependentLibraryPaths; + NameToAtomMap fAtoms; + NameSet fIgnoreExports; + bool fNoRexports; + bool fHasWeakExports; + const bool fLinkingFlat; + const bool fLinkingMainExecutable; + bool fExplictReExportFound; + bool fExplicitlyLinked; + bool fImplicitlyLinked; + bool fProvidedAtom; + bool fImplicitlyLinkPublicDylibs; + bool fLazyLoaded; + ObjectFile::Reader::ObjcConstraint fObjcContraint; + std::vector fReExportedChildren; + const ObjectFile::ReaderOptions::VersionMin fDeploymentVersionMin; + std::vector fFlatImports; + + static bool fgLogHashtable; + static std::vector fgEmptyAtomList; +}; + +template +std::vector Reader::fgEmptyAtomList; +template +bool Reader::fgLogHashtable = false; + + +template +Reader::Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path, + const DynamicLibraryOptions& dylibOptions, + const ObjectFile::ReaderOptions& options, uint32_t ordinalBase) + : fParentUmbrella(NULL), fDylibInstallPath(NULL), fDylibTimeStamp(0), fDylibtCurrentVersion(0), + fDylibCompatibilityVersion(0), fLinkingFlat(options.fFlatNamespace), + fLinkingMainExecutable(options.fLinkingMainExecutable), fExplictReExportFound(false), + fExplicitlyLinked(false), fImplicitlyLinked(false), fProvidedAtom(false), + fImplicitlyLinkPublicDylibs(options.fImplicitlyLinkPublicDylibs), fLazyLoaded(dylibOptions.fLazyLoad), + fObjcContraint(ObjectFile::Reader::kObjcNone), + fDeploymentVersionMin(options.fVersionMin) +{ + // sanity check + if ( ! validFile(fileContent, dylibOptions.fBundleLoader) ) + throw "not a valid mach-o object file"; + + fPath = strdup(path); + + const macho_header

* header = (const macho_header

*)fileContent; + const uint32_t cmd_count = header->ncmds(); + const macho_load_command

* const cmds = (macho_load_command

*)((char*)header + sizeof(macho_header

)); + const macho_load_command

* const cmdsEnd = (macho_load_command

*)((char*)header + sizeof(macho_header

) + header->sizeofcmds()); + + // write out path for -whatsloaded option + if ( options.fLogAllFiles ) + printf("%s\n", path); + + if ( options.fRootSafe && ((header->flags() & MH_ROOT_SAFE) == 0) ) + warning("using -root_safe but linking against %s which is not root safe", path); + + if ( options.fSetuidSafe && ((header->flags() & MH_SETUID_SAFE) == 0) ) + warning("using -setuid_safe but linking against %s which is not setuid safe", path); + + // a "blank" stub has zero load commands + if ( (header->filetype() == MH_DYLIB_STUB) && (cmd_count == 0) ) { + // no further processing needed + munmap((caddr_t)fileContent, fileLength); + return; + } + + + // optimize the case where we know there is no reason to look at indirect dylibs + fNoRexports = (header->flags() & MH_NO_REEXPORTED_DYLIBS); + fHasWeakExports = (header->flags() & MH_WEAK_DEFINES); + bool trackDependentLibraries = !fNoRexports || options.fFlatNamespace; + + // pass 1 builds list of all dependent libraries + const macho_load_command

* cmd = cmds; + if ( trackDependentLibraries ) { + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd()) { + case LC_REEXPORT_DYLIB: + fExplictReExportFound = true; + // fall into next case + case LC_LOAD_DYLIB: + case LC_LOAD_WEAK_DYLIB: + PathAndFlag entry; + entry.path = strdup(((struct macho_dylib_command

*)cmd)->name()); + entry.reExport = (cmd->cmd() == LC_REEXPORT_DYLIB); + fDependentLibraryPaths.push_back(entry); + break; + } + cmd = (const macho_load_command

*)(((char*)cmd)+cmd->cmdsize()); + if ( cmd > cmdsEnd ) + throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, path); + } + } + + // pass 2 determines re-export info + const macho_dysymtab_command

* dynamicInfo = NULL; + const macho_nlist

* symbolTable = NULL; + const char* strings = NULL; + cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd()) { + case LC_SYMTAB: + { + const macho_symtab_command

* symtab = (macho_symtab_command

*)cmd; + symbolTable = (const macho_nlist

*)((char*)header + symtab->symoff()); + strings = (char*)header + symtab->stroff(); + } + break; + case LC_DYSYMTAB: + dynamicInfo = (macho_dysymtab_command

*)cmd; + break; + case LC_ID_DYLIB: + { + macho_dylib_command

* dylibID = (macho_dylib_command

*)cmd; + fDylibInstallPath = strdup(dylibID->name()); + fDylibTimeStamp = dylibID->timestamp(); + fDylibtCurrentVersion = dylibID->current_version(); + fDylibCompatibilityVersion = dylibID->compatibility_version(); + } + break; + case LC_SUB_UMBRELLA: + if ( trackDependentLibraries ) { + const char* frameworkLeafName = ((macho_sub_umbrella_command

*)cmd)->sub_umbrella(); + for (typename std::vector::iterator it = fDependentLibraryPaths.begin(); it != fDependentLibraryPaths.end(); it++) { + const char* dylibName = it->path; + const char* lastSlash = strrchr(dylibName, '/'); + if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) ) + it->reExport = true; + } + } + break; + case LC_SUB_LIBRARY: + if ( trackDependentLibraries) { + const char* dylibBaseName = ((macho_sub_library_command

*)cmd)->sub_library(); + for (typename std::vector::iterator it = fDependentLibraryPaths.begin(); it != fDependentLibraryPaths.end(); it++) { + const char* dylibName = it->path; + const char* lastSlash = strrchr(dylibName, '/'); + const char* leafStart = &lastSlash[1]; + if ( lastSlash == NULL ) + leafStart = dylibName; + const char* firstDot = strchr(leafStart, '.'); + int len = strlen(leafStart); + if ( firstDot != NULL ) + len = firstDot - leafStart; + if ( strncmp(leafStart, dylibBaseName, len) == 0 ) + it->reExport = true; + } + } + break; + case LC_SUB_FRAMEWORK: + fParentUmbrella = strdup(((macho_sub_framework_command

*)cmd)->umbrella()); + break; + case macho_segment_command

::CMD: + // check for Objective-C info + if ( strcmp(((macho_segment_command

*)cmd)->segname(), "__OBJC") == 0 ) { + const macho_segment_command

* segment = (macho_segment_command

*)cmd; + const macho_section

* const sectionsStart = (macho_section

*)((char*)segment + sizeof(macho_segment_command

)); + const macho_section

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

* sect=sectionsStart; sect < sectionsEnd; ++sect) { + if ( strcmp(sect->sectname(), "__image_info") == 0 ) { + // struct objc_image_info { + // uint32_t version; // initially 0 + // uint32_t flags; + // }; + // #define OBJC_IMAGE_SUPPORTS_GC 2 + // #define OBJC_IMAGE_GC_ONLY 4 + // + const uint32_t* contents = (uint32_t*)(&fileContent[sect->offset()]); + if ( (sect->size() >= 8) && (contents[0] == 0) ) { + uint32_t flags = E::get32(contents[1]); + if ( (flags & 4) == 4 ) + fObjcContraint = ObjectFile::Reader::kObjcGC; + else if ( (flags & 2) == 2 ) + fObjcContraint = ObjectFile::Reader::kObjcRetainReleaseOrGC; + else + fObjcContraint = ObjectFile::Reader::kObjcRetainRelease; + } + else if ( sect->size() > 0 ) { + warning("can't parse __OBJC/__image_info section in %s", fPath); + } + } + } + } + } + + cmd = (const macho_load_command

*)(((char*)cmd)+cmd->cmdsize()); + if ( cmd > cmdsEnd ) + throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, path); + } + + // Process the rest of the commands here. + cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd()) { + case LC_SUB_CLIENT: + const char *temp = strdup(((macho_sub_client_command

*)cmd)->client()); + fAllowableClients.push_back(temp); + break; + } + cmd = (const macho_load_command

*)(((char*)cmd)+cmd->cmdsize()); + } + + // validate minimal load commands + if ( (fDylibInstallPath == NULL) && ((header->filetype() == MH_DYLIB) || (header->filetype() == MH_DYLIB_STUB)) ) + throwf("dylib %s missing LC_ID_DYLIB load command", path); + if ( symbolTable == NULL ) + throw "binary missing LC_SYMTAB load command"; + if ( dynamicInfo == NULL ) + throw "binary missing LC_DYSYMTAB load command"; + + // if linking flat and this is a flat dylib, create one atom that references all imported symbols + if ( fLinkingFlat && fLinkingMainExecutable && ((header->flags() & MH_TWOLEVEL) == 0) ) { + std::vector importNames; + importNames.reserve(dynamicInfo->nundefsym()); + const macho_nlist

* start = &symbolTable[dynamicInfo->iundefsym()]; + const macho_nlist

* end = &start[dynamicInfo->nundefsym()]; + for (const macho_nlist

* sym=start; sym < end; ++sym) { + importNames.push_back(&strings[sym->n_strx()]); + } + fFlatImports.push_back(new ImportAtom(*this, ordinalBase++, importNames)); + } + + // build hash table + if ( dynamicInfo->tocoff() == 0 ) { + if ( fgLogHashtable ) fprintf(stderr, "ld: building hashtable of %u toc entries for %s\n", dynamicInfo->nextdefsym(), path); + const macho_nlist

* start = &symbolTable[dynamicInfo->iextdefsym()]; + const macho_nlist

* end = &start[dynamicInfo->nextdefsym()]; + fAtoms.resize(dynamicInfo->nextdefsym()); // set initial bucket count + uint32_t index = ordinalBase; + for (const macho_nlist

* sym=start; sym < end; ++sym, ++index) { + this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, index); + } + fReExportedOrdinal = index; + } + else { + int32_t count = dynamicInfo->ntoc(); + fAtoms.resize(count); // set initial bucket count + if ( fgLogHashtable ) fprintf(stderr, "ld: building hashtable of %u entries for %s\n", count, path); + const struct dylib_table_of_contents* toc = (dylib_table_of_contents*)((char*)header + dynamicInfo->tocoff()); + for (int32_t i = 0; i < count; ++i) { + const uint32_t index = E::get32(toc[i].symbol_index); + const macho_nlist

* sym = &symbolTable[index]; + this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, ordinalBase+i); + } + fReExportedOrdinal = ordinalBase + count; + } + + + // unmap file + munmap((caddr_t)fileContent, fileLength); +} + + + +template +void Reader::addSymbol(const char* name, bool weak, uint32_t ordinal) +{ + // symbols that start with $ld$ are meta-data to the static linker + // need way for ld and dyld to see different exported symbols in a dylib + if ( strncmp(name, "$ld$", 4) == 0 ) { + // $ld$ $ $ + const char* symAction = &name[4]; + const char* symCond = strchr(symAction, '$'); + if ( symCond != NULL ) { + ObjectFile::ReaderOptions::VersionMin symVersionCondition = ObjectFile::ReaderOptions::kMinUnset; + if ( (strncmp(symCond, "$os10.", 6) == 0) && isdigit(symCond[6]) && (symCond[7] == '$') ) { + switch ( symCond[6] - '0' ) { + case 0: + case 1: + symVersionCondition = ObjectFile::ReaderOptions::k10_1; + break; + case 2: + symVersionCondition = ObjectFile::ReaderOptions::k10_2; + break; + case 3: + symVersionCondition = ObjectFile::ReaderOptions::k10_3; + break; + case 4: + symVersionCondition = ObjectFile::ReaderOptions::k10_4; + break; + case 5: + symVersionCondition = ObjectFile::ReaderOptions::k10_5; + break; + case 6: + symVersionCondition = ObjectFile::ReaderOptions::k10_6; + break; + } + const char* symName = strchr(&symCond[1], '$'); + if ( symName != NULL ) { + ++symName; + if ( fDeploymentVersionMin == symVersionCondition ) { + if ( strncmp(symAction, "hide$", 5) == 0 ) { + if ( fgLogHashtable ) fprintf(stderr, " adding %s to ignore set for %s\n", symName, this->getPath()); + fIgnoreExports.insert(strdup(symName)); + return; + } + else if ( strncmp(symAction, "add$", 4) == 0 ) { + this->addSymbol(symName, weak, ordinal); + return; + } + else { + warning("bad symbol action: %s in dylib %s", name, this->getPath()); + } + } + } + else { + warning("bad symbol name: %s in dylib %s", name, this->getPath()); + } + } + else { + warning("bad symbol version: %s in dylib %s", name, this->getPath()); + } + } + else { + warning("bad symbol condition: %s in dylib %s", name, this->getPath()); + } + } + + // add symbol as possible export if we are not supposed to ignore it + if ( fIgnoreExports.count(name) == 0 ) { + AtomAndWeak bucket; + bucket.atom = NULL; + bucket.weak = weak; + bucket.ordinal = ordinal; + if ( fgLogHashtable ) fprintf(stderr, " adding %s to hash table for %s\n", name, this->getPath()); + fAtoms[strdup(name)] = bucket; + } +} + + +template +std::vector& Reader::getAtoms() +{ + return fFlatImports; +} + + +template +std::vector* Reader::getJustInTimeAtomsFor(const char* name) +{ + std::vector* atoms = NULL; + + NameToAtomMapIterator pos = fAtoms.find(name); + if ( pos != fAtoms.end() ) { + if ( pos->second.atom == NULL ) { + // instantiate atom and update hash table + pos->second.atom = new ExportAtom(*this, name, pos->second.weak, pos->second.ordinal); + fProvidedAtom = true; + if ( fgLogHashtable ) fprintf(stderr, "getJustInTimeAtomsFor: %s found in %s\n", name, this->getPath()); + } + // return a vector of one atom + atoms = new std::vector; + atoms->push_back(pos->second.atom); + } + else { + if ( fgLogHashtable ) fprintf(stderr, "getJustInTimeAtomsFor: %s NOT found in %s\n", name, this->getPath()); + // if not supposed to ignore this export, see if I have it + if ( fIgnoreExports.count(name) == 0 ) { + // look in children that I re-export + for (std::vector::iterator it = fReExportedChildren.begin(); it != fReExportedChildren.end(); it++) { + //fprintf(stderr, "getJustInTimeAtomsFor: %s NOT found in %s, looking in child %s\n", name, this->getPath(), (*it)->getInstallPath()); + std::vector* childAtoms = (*it)->getJustInTimeAtomsFor(name); + if ( childAtoms != NULL ) { + // make a new atom that says this reader is the owner + bool isWeakDef = (childAtoms->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition); + // return a vector of one atom + ExportAtom* newAtom = new ExportAtom(*this, name, isWeakDef, fReExportedOrdinal++); + fProvidedAtom = true; + atoms = new std::vector; + atoms->push_back(newAtom); + delete childAtoms; + return atoms; + } + } + } + } + return atoms; +} + + + +template +bool Reader::isPublicLocation(const char* path) +{ + // -no_implicit_dylibs disables this optimization + if ( ! fImplicitlyLinkPublicDylibs ) + return false; + + // /usr/lib is a public location + if ( (strncmp(path, "/usr/lib/", 9) == 0) && (strchr(&path[9], '/') == NULL) ) + return true; + + // /System/Library/Frameworks/ is a public location + if ( strncmp(path, "/System/Library/Frameworks/", 27) == 0 ) { + const char* frameworkDot = strchr(&path[27], '.'); + // but only top level framework + // /System/Library/Frameworks/Foo.framework/Versions/A/Foo ==> true + // /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib ==> false + // /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar ==> false + // /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo ==> false + if ( frameworkDot != NULL ) { + int frameworkNameLen = frameworkDot - &path[27]; + if ( strncmp(&path[strlen(path)-frameworkNameLen-1], &path[26], frameworkNameLen+1) == 0 ) + return true; + } + } + + return false; +} + +template +void Reader::processIndirectLibraries(DylibHander* handler) +{ + if ( fLinkingFlat ) { + for (typename std::vector::iterator it = fDependentLibraryPaths.begin(); it != fDependentLibraryPaths.end(); it++) { + handler->findDylib(it->path, this->getPath()); + } + } + else if ( fNoRexports ) { + // MH_NO_REEXPORTED_DYLIBS bit set, then nothing to do + } + else { + // two-level, might have re-exports + for (typename std::vector::iterator it = fDependentLibraryPaths.begin(); it != fDependentLibraryPaths.end(); it++) { + if ( it->reExport ) { + //fprintf(stderr, "processIndirectLibraries() parent=%s, child=%s\n", this->getInstallPath(), it->path); + // a LC_REEXPORT_DYLIB, LC_SUB_UMBRELLA or LC_SUB_LIBRARY says we re-export this child + ObjectFile::Reader* child = handler->findDylib(it->path, this->getPath()); + if ( isPublicLocation(child->getInstallPath()) ) { + // promote this child to be automatically added as a direct dependent if this already is + if ( this->explicitlyLinked() || this->implicitlyLinked() ) { + //fprintf(stderr, "processIndirectLibraries() implicitly linking %s\n", child->getInstallPath()); + ((Reader*)child)->setImplicitlyLinked(); + } + else + fReExportedChildren.push_back(child); + } + else { + // add all child's symbols to me + fReExportedChildren.push_back(child); + //fprintf(stderr, "processIndirectLibraries() parent=%s will re-export child=%s\n", this->getInstallPath(), it->path); + } + } + else if ( !fExplictReExportFound ) { + // see if child contains LC_SUB_FRAMEWORK with my name + ObjectFile::Reader* child = handler->findDylib(it->path, this->getPath()); + const char* parentUmbrellaName = ((Reader*)child)->parentUmbrella(); + if ( parentUmbrellaName != NULL ) { + const char* parentName = this->getPath(); + const char* lastSlash = strrchr(parentName, '/'); + if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], parentUmbrellaName) == 0) ) { + // add all child's symbols to me + fReExportedChildren.push_back(child); + //fprintf(stderr, "processIndirectLibraries() umbrella=%s will re-export child=%s\n", this->getInstallPath(), it->path); + } + } + } + } + } + + // check for re-export cycles + ReExportChain chain; + chain.prev = NULL; + chain.reader = this; + this->assertNoReExportCycles(&chain); +} + +template +void Reader::assertNoReExportCycles(ReExportChain* prev) +{ + // recursively check my re-exported dylibs + ReExportChain chain; + chain.prev = prev; + chain.reader = this; + for (std::vector::iterator it = fReExportedChildren.begin(); it != fReExportedChildren.end(); it++) { + ObjectFile::Reader* child = *it; + // check child is not already in chain + for (ReExportChain* p = prev; p != NULL; p = p->prev) { + if ( p->reader == child ) { + throwf("cycle in dylib re-exports with %s", child->getPath()); + } + } + ((Reader*)(*it))->assertNoReExportCycles(&chain); + } +} + + +template +std::vector* Reader::getAllowableClients() +{ + std::vector* result = new std::vector; + for (typename std::vector::iterator it = fAllowableClients.begin(); + it != fAllowableClients.end(); + it++) { + result->push_back(*it); + } + return (fAllowableClients.size() != 0 ? result : NULL); +} + +template <> +bool Reader::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle) +{ + const macho_header

* header = (const macho_header

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

* header = (const macho_header

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

* header = (const macho_header

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

* header = (const macho_header

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

* header = (const macho_header

*)fileContent; + if ( header->magic() != MH_MAGIC ) + return false; + if ( header->cputype() != CPU_TYPE_ARM ) + return false; + switch ( header->filetype() ) { + case MH_DYLIB: + case MH_DYLIB_STUB: + return true; + case MH_BUNDLE: + if ( executableOrDyliborBundle ) + return true; + else + throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)"; + case MH_EXECUTE: + if ( executableOrDyliborBundle ) + return true; + else + throw "can't link with a main executable"; + default: + return false; + } +} + +}; // namespace dylib +}; // namespace mach_o + + +#endif // __OBJECT_FILE_DYLIB_MACH_O__ diff --git a/FireOpal/src/MachOReaderRelocatable.hpp b/FireOpal/src/MachOReaderRelocatable.hpp new file mode 100644 index 0000000..73c58e2 --- /dev/null +++ b/FireOpal/src/MachOReaderRelocatable.hpp @@ -0,0 +1,4583 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2005-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 __OBJECT_FILE_MACH_O__ +#define __OBJECT_FILE_MACH_O__ + +#include +#include +#include +#include + +#include +#include +#include + +#include "MachOFileAbstraction.hpp" +#include "Architectures.hpp" +#include "ObjectFile.h" +#include "dwarf2.h" +#include "debugline.h" + + +// +// +// To implement architecture xxx, you must write template specializations for the following six methods: +// Reader::validFile() +// Reader::validSectionType() +// Reader::addRelocReference() +// Reference::getDescription() +// +// + + + +extern __attribute__((noreturn)) void throwf(const char* format, ...); +extern void warning(const char* format, ...); + +namespace mach_o { +namespace relocatable { + + + +class ReferenceSorter +{ +public: + bool operator()(const ObjectFile::Reference* left, const ObjectFile::Reference* right) + { + return ( left->getFixUpOffset() < right->getFixUpOffset() ); + } +}; + + +// forward reference +template class Reader; + +struct AtomAndOffset +{ + AtomAndOffset(ObjectFile::Atom* a=NULL) : atom(a), offset(0) {} + AtomAndOffset(ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {} + ObjectFile::Atom* atom; + uint32_t offset; +}; + + +template +class Reference : public ObjectFile::Reference +{ +public: + typedef typename A::P P; + typedef typename A::P::uint_t pint_t; + typedef typename A::ReferenceKinds Kinds; + + Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget); + Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget); + Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset); + + virtual ~Reference() {} + + + virtual ObjectFile::Reference::TargetBinding getTargetBinding() const; + virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const; + virtual uint8_t getKind() const { return (uint8_t)fKind; } + virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; } + virtual const char* getTargetName() const { return (fToTargetName != NULL) ? fToTargetName : fToTarget.atom->getName(); } + virtual ObjectFile::Atom& getTarget() const { return *fToTarget.atom; } + virtual uint64_t getTargetOffset() const { return (int64_t)((int32_t)fToTarget.offset); } + virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget.atom; } + virtual const char* getFromTargetName() const { return (fFromTargetName != NULL) ? fFromTargetName : fFromTarget.atom->getName(); } + virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fToTarget.atom = ⌖ fToTarget.offset = offset; } + virtual void setToTargetOffset(uint64_t offset) { fToTarget.offset = offset; } + virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget.atom = ⌖ } + virtual void setFromTargetName(const char* name) { fFromTargetName = name; } + virtual void setFromTargetOffset(uint64_t offset) { fFromTarget.offset = offset; } + virtual const char* getDescription() const; + virtual uint64_t getFromTargetOffset() const { return fFromTarget.offset; } + + static bool fgForFinalLinkedImage; + +private: + pint_t fFixUpOffsetInSrc; + AtomAndOffset fToTarget; + AtomAndOffset fFromTarget; + const char* fToTargetName; + const char* fFromTargetName; + Kinds fKind; + +}; + +template bool Reference::fgForFinalLinkedImage = true; + +template +Reference::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget) + : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fToTargetName(NULL), fFromTargetName(NULL), + fKind(kind) +{ + // make reference a by-name unless: + // - the reference type is only used with direct references + // - the target is translation unit scoped + // - the target kind is not regular (is weak or tentative) + if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate) + && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit) + && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition) + && (toTarget.atom != at.atom) ) { + fToTargetName = toTarget.atom->getName(); + //fprintf(stderr, "Reference(): changing to by-name %p %s, target scope=%d, target section=%s\n", toTarget.atom, fToTargetName, toTarget.atom->getScope(), toTarget.atom->getSectionName()); + fToTarget.atom = NULL; + } + ((class BaseAtom*)at.atom)->addReference(this); + //fprintf(stderr, "Reference(): %p fToTarget<%s, %08X>\n", this, (fToTarget.atom != NULL) ? fToTarget.atom->getDisplayName() : fToTargetName , fToTarget.offset); +} + +template +Reference::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget) + : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fFromTarget(fromTarget), + fToTargetName(NULL), fFromTargetName(NULL), fKind(kind) +{ + // make reference a by-name where needed + if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate) + && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit) + && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition) + && (toTarget.atom != at.atom) ) { + fToTargetName = toTarget.atom->getName(); + fToTarget.atom = NULL; + } + ((class BaseAtom*)at.atom)->addReference(this); + //fprintf(stderr, "Reference(): %p kind=%d, fToTarget<%s, %08X>, fromTarget<%s, %08X>\n", this, kind, + // this->getTargetName(), fToTarget.offset, this->getFromTargetName(), fromTarget.offset); +} + +template +Reference::Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset) + : fFixUpOffsetInSrc(at.offset), + fToTargetName(toName), fFromTargetName(NULL), fKind(kind) +{ + fToTarget.offset = toOffset; + ((class BaseAtom*)at.atom)->addReference(this); +} + +template +ObjectFile::Reference::TargetBinding Reference::getTargetBinding() const +{ + if ( fgForFinalLinkedImage ) { + if ( (fKind == A::kDtraceProbe) || (fKind == A::kDtraceProbeSite) || (fKind == A::kDtraceIsEnabledSite) || (fKind == A::kDtraceTypeReference) ) + return ObjectFile::Reference::kDontBind; + } + if ( fToTarget.atom == NULL ) + return ObjectFile::Reference::kUnboundByName; + if ( fToTargetName == NULL ) + return ObjectFile::Reference::kBoundDirectly; + else + return ObjectFile::Reference::kBoundByName; +} + +template +ObjectFile::Reference::TargetBinding Reference::getFromTargetBinding() const +{ + if ( fFromTarget.atom == NULL ) { + if ( fFromTargetName == NULL ) + return ObjectFile::Reference::kDontBind; + else + return ObjectFile::Reference::kUnboundByName; + } + else { + if ( fFromTargetName == NULL ) + return ObjectFile::Reference::kBoundDirectly; + else + return ObjectFile::Reference::kBoundByName; + } +} + + + +template +class Segment : public ObjectFile::Segment +{ +public: + Segment(const macho_section* sect); + virtual const char* getName() const { return fSection->segname(); } + virtual bool isContentReadable() const { return true; } + virtual bool isContentWritable() const { return fWritable; } + virtual bool isContentExecutable() const { return fExecutable; } +private: + const macho_section* fSection; + bool fWritable; + bool fExecutable; +}; + +template +Segment::Segment(const macho_section* sect) + : fSection(sect), fWritable(true), fExecutable(false) +{ + if ( strcmp(fSection->segname(), "__TEXT") == 0 ) { + fWritable = false; + fExecutable = true; + } + else if ( strcmp(fSection->segname(), "__IMPORT") == 0 ) { + fWritable = true; + fExecutable = true; + } +} + + +class DataSegment : public ObjectFile::Segment +{ +public: + virtual const char* getName() const { return "__DATA"; } + virtual bool isContentReadable() const { return true; } + virtual bool isContentWritable() const { return true; } + virtual bool isContentExecutable() const { return false; } + + static DataSegment fgSingleton; +}; + +DataSegment DataSegment::fgSingleton; + +class LinkEditSegment : public ObjectFile::Segment +{ +public: + virtual const char* getName() const { return "__LINKEDIT"; } + virtual bool isContentReadable() const { return true; } + virtual bool isContentWritable() const { return false; } + virtual bool isContentExecutable() const { return false; } + + static LinkEditSegment fgSingleton; +}; + +LinkEditSegment LinkEditSegment::fgSingleton; + +class BaseAtom : public ObjectFile::Atom +{ +public: + BaseAtom() : fStabsStartIndex(0), fStabsCount(0) {} + + virtual void setSize(uint64_t size) = 0; + virtual void addReference(ObjectFile::Reference* ref) = 0; + virtual void sortReferences() = 0; + virtual void addLineInfo(const ObjectFile::LineInfo& info) = 0; + virtual uint64_t getObjectAddress() const = 0; + virtual uint32_t getOrdinal() const { return fOrdinal; } + virtual void setOrdinal(uint32_t value) { fOrdinal = value; } + virtual const void* getSectionRecord() const = 0; + virtual bool isAlias() const { return false; } + + uint32_t fStabsStartIndex; + uint32_t fStabsCount; + uint32_t fOrdinal; +}; + +class BaseAtomSorter +{ +public: + bool operator()(const class BaseAtom* left, const class BaseAtom* right) { + if ( left == right ) + return false; + uint64_t leftAddr = left->getObjectAddress(); + uint64_t rightAddr = right->getObjectAddress(); + if ( leftAddr < rightAddr ) { + return true; + } + else if ( leftAddr > rightAddr ) { + return false; + } + else { + // if they have same address, one might be the end of a section and the other the start of the next section + const void* leftSection = left->getSectionRecord(); + const void* rightSection = right->getSectionRecord(); + if ( leftSection != rightSection ) { + return ( leftSection < rightSection ); + } + // if they have same address and section, one might be an alias + bool leftAlias = left->isAlias(); + bool rightAlias = right->isAlias(); + if ( leftAlias && rightAlias ) { + // sort multiple aliases for same address first by scope + ObjectFile::Atom::Scope leftScope = left->getScope(); + ObjectFile::Atom::Scope rightScope = right->getScope(); + if ( leftScope != rightScope ) { + return ( leftScope < rightScope ); + } + // sort multiple aliases for same address then by name + return ( strcmp(left->getName(), right->getName()) < 0 ); + } + else if ( leftAlias ) { + return true; + } + else if ( rightAlias ) { + return false; + } + else { + // they must be tentative defintions + switch ( left->getDefinitionKind() ) { + case ObjectFile::Atom::kTentativeDefinition: + // sort tentative definitions by name + return ( strcmp(left->getName(), right->getName()) < 0 ); + case ObjectFile::Atom::kAbsoluteSymbol: + // sort absolute symbols with same address by name + return ( strcmp(left->getName(), right->getName()) < 0 ); + default: + // hack for rdar://problem/5102873 + if ( !left->isZeroFill() || !right->isZeroFill() ) + warning("atom sorting error for %s and %s in %s", left->getDisplayName(), right->getDisplayName(), left->getFile()->getPath()); + break; + } + } + } + return false; + } +}; + + +// +// A SymbolAtom represents a chunk of a mach-o object file that has a symbol table entry +// pointing to it. A C function or global variable is represented by one of these atoms. +// +// +template +class SymbolAtom : public BaseAtom +{ +public: + virtual ObjectFile::Reader* getFile() const { return &fOwner; } + virtual bool getTranslationUnitSource(const char** dir, const char** name) const + { return fOwner.getTranslationUnitSource(dir, name); } + virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; } + virtual const char* getDisplayName() const { return getName(); } + virtual ObjectFile::Atom::Scope getScope() const { return fScope; } + virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ((fSymbol->n_desc() & N_WEAK_DEF) != 0) + ? ObjectFile::Atom::kWeakDefinition : ObjectFile::Atom::kRegularDefinition; } + virtual SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; } + virtual bool dontDeadStrip() const; + virtual bool isZeroFill() const { return ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL); } + virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); } + virtual uint64_t getSize() const { return fSize; } + virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } + virtual bool mustRemainInSection() const { return true; } + virtual const char* getSectionName() const; + virtual Segment& getSegment() const { return *fSegment; } + virtual ObjectFile::Atom& getFollowOnAtom() const; + virtual std::vector* getLineInfo() const { return (std::vector*)&fLineInfo; } + virtual ObjectFile::Alignment getAlignment() const { return fAlignment; } + virtual void copyRawContent(uint8_t buffer[]) const; + virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; } + virtual void setSize(uint64_t size); + virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference*)ref); } + virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); } + virtual void addLineInfo(const ObjectFile::LineInfo& info) { fLineInfo.push_back(info); } + virtual uint64_t getObjectAddress() const { return fAddress; } + virtual const void* getSectionRecord() const { return (const void*)fSection; } + +protected: + typedef typename A::P P; + typedef typename A::P::E E; + typedef typename A::P::uint_t pint_t; + typedef typename A::ReferenceKinds Kinds; + typedef typename std::vector*> ReferenceVector; + typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser + typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser + friend class Reader; + + SymbolAtom(Reader&, const macho_nlist

*, const macho_section

*); + virtual ~SymbolAtom() {} + + Reader& fOwner; + const macho_nlist

* fSymbol; + pint_t fAddress; + pint_t fSize; + const macho_section

* fSection; + Segment* fSegment; + ReferenceVector fReferences; + std::vector fLineInfo; + ObjectFile::Atom::Scope fScope; + SymbolTableInclusion fSymbolTableInclusion; + ObjectFile::Alignment fAlignment; +}; + + +template +SymbolAtom::SymbolAtom(Reader& owner, const macho_nlist

* symbol, const macho_section

* section) + : fOwner(owner), fSymbol(symbol), fAddress(0), fSize(0), fSection(section), fSegment(NULL), fAlignment(0) +{ + uint8_t type = symbol->n_type(); + if ( (type & N_EXT) == 0 ) + fScope = ObjectFile::Atom::scopeTranslationUnit; + else if ( (type & N_PEXT) != 0 ) + fScope = ObjectFile::Atom::scopeLinkageUnit; + else + fScope = ObjectFile::Atom::scopeGlobal; + if ( (type & N_TYPE) == N_SECT ) { + // real definition + fSegment = new Segment(fSection); + fAddress = fSymbol->n_value(); + pint_t sectionStartAddr = section->addr(); + pint_t sectionEndAddr = section->addr()+section->size(); + if ( (fAddress < sectionStartAddr) || (fAddress > (sectionEndAddr)) ) { + throwf("malformed .o file, symbol %s with address 0x%0llX is not with section %d (%s,%s) address range of 0x%0llX to 0x%0llX", + this->getName(), (uint64_t)fAddress, fSymbol->n_sect(), section->segname(), section->sectname(), + (uint64_t)sectionStartAddr, (uint64_t)(sectionEndAddr) ); + } + } + else { + warning("unknown symbol type: %d", type); + } + + //fprintf(stderr, "SymbolAtom(%p) %s fAddress=0x%X\n", this, this->getDisplayName(), (uint32_t)fAddress); + // support for .o files built with old ld64 + if ( (fSymbol->n_desc() & N_WEAK_DEF) && (strcmp(fSection->sectname(),"__picsymbolstub1__TEXT") == 0) ) { + const char* name = this->getName(); + const int nameLen = strlen(name); + if ( (nameLen > 6) && strcmp(&name[nameLen-5], "$stub") == 0 ) { + // switch symbol to point at name that does not have trailing $stub + char correctName[nameLen]; + strncpy(correctName, name, nameLen-5); + correctName[nameLen-5] = '\0'; + const macho_nlist

* symbolsStart = fOwner.fSymbols; + const macho_nlist

* symbolsEnd = &symbolsStart[fOwner.fSymbolCount]; + for(const macho_nlist

* s = symbolsStart; s < symbolsEnd; ++s) { + if ( strcmp(&fOwner.fStrings[s->n_strx()], correctName) == 0 ) { + fSymbol = s; + break; + } + } + } + } + // support for labeled stubs + switch ( section->flags() & SECTION_TYPE ) { + case S_SYMBOL_STUBS: + setSize(section->reserved2()); + break; + case S_LAZY_SYMBOL_POINTERS: + case S_NON_LAZY_SYMBOL_POINTERS: + setSize(sizeof(pint_t)); + break; + case S_4BYTE_LITERALS: + setSize(4); + break; + case S_8BYTE_LITERALS: + setSize(8); + break; + case S_16BYTE_LITERALS: + setSize(16); + break; + case S_CSTRING_LITERALS: + setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1); + break; + case S_REGULAR: + case S_ZEROFILL: + case S_COALESCED: + // size calculate later after next atom is found + break; + } + + // compute alignment + fAlignment = ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align())); + + // compute whether this atom needs to be in symbol table + if ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0) { + fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAndNeverStrip; + } + else if ( fOwner.fOptions.fForFinalLinkedImage + && ((section->flags() & SECTION_TYPE) == S_COALESCED) + && ((section->flags() & S_ATTR_NO_TOC) == S_ATTR_NO_TOC) + && ((section->flags() & S_ATTR_STRIP_STATIC_SYMS) == S_ATTR_STRIP_STATIC_SYMS) + && (strcmp(section->sectname(), "__eh_frame") == 0) ) { + // .eh symbols exist so the linker can associate them with functions + // removing them from final linked images is a big space savings rdar://problem/4180168 + fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn; + // FDEs and CIEs are always packed together in a final linked image, so ignore section alignment + fAlignment = ObjectFile::Alignment(0); + } + else if ( fOwner.fOptions.fForFinalLinkedImage + && ((section->flags() & SECTION_TYPE) == S_REGULAR) + && (strncmp(section->sectname(), "__gcc_except_tab", 16) == 0) + && (strncmp(this->getName(), "GCC_except_table", 16) == 0) ) { + // GCC_except_table* symbols don't need to exist in final linked image + fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn; + } + else if ( fOwner.fOptions.fForFinalLinkedImage && !fOwner.fOptions.fForStatic && (fOwner.fStrings[fSymbol->n_strx()] == 'l') ) { + // labels beginning with a lowercase ell are automatically removed in final linked images + // xnu code base uses a lot of asesembly labels that start with 'l', don't strip those (static executable) + fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn; + } + else { + fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn; + } + + // work around malformed icc generated .o files + // if section starts with a symbol and that symbol address does not match section alignment, then force it to + if ( (section->addr() == fAddress) && (fAlignment.modulus != 0) ) + fAlignment.modulus = 0; +} + +template +bool SymbolAtom::dontDeadStrip() const +{ + // the symbol can have a no-dead-strip bit + if ( (fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0 ) + return true; + // or the section can have a no-dead-strip bit + return ( fSection->flags() & S_ATTR_NO_DEAD_STRIP ); +} + + +template +const char* SymbolAtom::getSectionName() const +{ + if ( fOwner.fOptions.fForFinalLinkedImage && (strcmp(fSection->sectname(), "__textcoal_nt") == 0) ) + return "__text"; + + if ( strlen(fSection->sectname()) > 15 ) { + static char temp[18]; + strncpy(temp, fSection->sectname(), 16); + temp[17] = '\0'; + return temp; + } + return fSection->sectname(); +} + +template +ObjectFile::Atom& SymbolAtom::getFollowOnAtom() const +{ + for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) { + Reference* ref = *it; + if ( ref->getKind() == A::kFollowOn ) + return ref->getTarget(); + } + return *((ObjectFile::Atom*)NULL); +} + + +class Beyond +{ +public: + Beyond(uint64_t offset) : fOffset(offset) {} + bool operator()(ObjectFile::Reference* ref) const { + return ( ref->getFixUpOffset() >= fOffset ); + } +private: + uint64_t fOffset; +}; + + +template +void SymbolAtom::setSize(uint64_t size) +{ + // when resizing, any references beyond the new size are tossed + if ( (fSize != 0) && (fReferences.size() > 0) ) + fReferences.erase(std::remove_if(fReferences.begin(), fReferences.end(), Beyond(size)), fReferences.end()); + // set new size + fSize = size; +} + +template +void SymbolAtom::copyRawContent(uint8_t buffer[]) const +{ + // copy base bytes + if ( isZeroFill() ) + bzero(buffer, fSize); + else { + uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress; + memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize); + } +} + +// +// A SymbolAliasAtom represents an alternate name for a SymbolAtom +// +// +template +class SymbolAliasAtom : public BaseAtom +{ +public: + virtual ObjectFile::Reader* getFile() const { return fAliasOf.getFile(); } + virtual bool getTranslationUnitSource(const char** dir, const char** name) const + { return fAliasOf.getTranslationUnitSource(dir, name); } + virtual const char* getName() const { return fName; } + virtual const char* getDisplayName() const { return fName; } + virtual ObjectFile::Atom::Scope getScope() const { return fScope; } + virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return fAliasOf.getDefinitionKind(); } + virtual SymbolTableInclusion getSymbolTableInclusion() const { return fAliasOf.getSymbolTableInclusion(); } + virtual bool dontDeadStrip() const { return fDontDeadStrip; } + virtual bool isZeroFill() const { return fAliasOf.isZeroFill(); } + virtual bool isThumb() const { return fAliasOf.isThumb(); } + virtual uint64_t getSize() const { return 0; } + virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } + virtual bool mustRemainInSection() const { return true; } + virtual const char* getSectionName() const { return fAliasOf.getSectionName(); } + virtual Segment& getSegment() const { return (Segment&)fAliasOf.getSegment(); } + virtual ObjectFile::Atom& getFollowOnAtom() const { return (ObjectFile::Atom&)fAliasOf; } + virtual std::vector* getLineInfo() const { return NULL; } + virtual ObjectFile::Alignment getAlignment() const { return fAliasOf.getAlignment(); } + virtual void copyRawContent(uint8_t buffer[]) const {} + virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; } + virtual void setSize(uint64_t size) { } + virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference*)ref); } + virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); } + virtual void addLineInfo(const ObjectFile::LineInfo& info) { } + virtual uint64_t getObjectAddress() const { return fAliasOf.getObjectAddress(); } + virtual const void* getSectionRecord() const { return fAliasOf.getSectionRecord(); } + virtual bool isAlias() const { return true; } + +protected: + typedef typename A::P P; + typedef typename std::vector*> ReferenceVector; + typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser + typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser + friend class Reader; + + SymbolAliasAtom(const char* name, const macho_nlist

*, const BaseAtom& ); + virtual ~SymbolAliasAtom() {} + + const char* fName; + const BaseAtom& fAliasOf; + ObjectFile::Atom::Scope fScope; + bool fDontDeadStrip; + ReferenceVector fReferences; +}; + + +template +SymbolAliasAtom::SymbolAliasAtom(const char* name, const macho_nlist

* symbol, const BaseAtom& aliasOf) + : fName(name), fAliasOf(aliasOf) +{ + //fprintf(stderr, "SymbolAliasAtom(%p) %s\n", this, name); + if ( symbol != NULL ) { + uint8_t type = symbol->n_type(); + if ( (type & N_EXT) == 0 ) + fScope = ObjectFile::Atom::scopeTranslationUnit; + else if ( (type & N_PEXT) != 0 ) + fScope = ObjectFile::Atom::scopeLinkageUnit; + else + fScope = ObjectFile::Atom::scopeGlobal; + fDontDeadStrip = ((symbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); + } + else { + // aliases defined on the command line are initially global scope + fScope = ObjectFile::Atom::scopeGlobal; + fDontDeadStrip = false; + } + // add follow-on reference to real atom + new Reference(A::kFollowOn, AtomAndOffset(this), AtomAndOffset((ObjectFile::Atom*)&aliasOf)); +} + + +// +// A TentativeAtom represents a C "common" or "tentative" defintion of data. +// For instance, "int foo;" is neither a declaration or a definition and +// is represented by a TentativeAtom. +// +template +class TentativeAtom : public BaseAtom +{ +public: + virtual ObjectFile::Reader* getFile() const { return &fOwner; } + virtual bool getTranslationUnitSource(const char** dir, const char** name) const + { return fOwner.getTranslationUnitSource(dir, name); } + virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; } + virtual const char* getDisplayName() const { return getName(); } + virtual ObjectFile::Atom::Scope getScope() const { return fScope; } + virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kTentativeDefinition; } + virtual bool isZeroFill() const { return true; } + virtual bool isThumb() const { return false; } + virtual SymbolTableInclusion getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0) + ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; } + virtual bool dontDeadStrip() const { return ((fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); } + virtual uint64_t getSize() const { return fSymbol->n_value(); } + virtual std::vector& getReferences() const { return fgNoReferences; } + virtual bool mustRemainInSection() const { return true; } + virtual const char* getSectionName() const; + virtual ObjectFile::Segment& getSegment() const { return DataSegment::fgSingleton; } + virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; } + virtual std::vector* getLineInfo() const { return NULL; } + virtual ObjectFile::Alignment getAlignment() const; + virtual void copyRawContent(uint8_t buffer[]) const; + virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; } + virtual void setSize(uint64_t size) { } + virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; } + virtual void sortReferences() { } + virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; } + virtual uint64_t getObjectAddress() const { return ULLONG_MAX; } + virtual const void* getSectionRecord() const { return NULL; } + +protected: + typedef typename A::P P; + typedef typename A::P::E E; + typedef typename A::P::uint_t pint_t; + typedef typename A::ReferenceKinds Kinds; + friend class Reader; + + TentativeAtom(Reader&, const macho_nlist

*); + virtual ~TentativeAtom() {} + + Reader& fOwner; + const macho_nlist

* fSymbol; + ObjectFile::Atom::Scope fScope; + static std::vector fgNoReferences; +}; + +template +std::vector TentativeAtom::fgNoReferences; + +template +TentativeAtom::TentativeAtom(Reader& owner, const macho_nlist

* symbol) + : fOwner(owner), fSymbol(symbol) +{ + uint8_t type = symbol->n_type(); + if ( (type & N_EXT) == 0 ) + fScope = ObjectFile::Atom::scopeTranslationUnit; + else if ( (type & N_PEXT) != 0 ) + fScope = ObjectFile::Atom::scopeLinkageUnit; + else + fScope = ObjectFile::Atom::scopeGlobal; + if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) { + // tentative definition + } + else { + warning("unknown symbol type: %d", type); + } + //fprintf(stderr, "TentativeAtom(%p) %s\n", this, this->getDisplayName()); +} + + +template +ObjectFile::Alignment TentativeAtom::getAlignment() const +{ + uint8_t alignment = GET_COMM_ALIGN(fSymbol->n_desc()); + if ( alignment == 0 ) { + // common symbols align to their size + // that is, a 4-byte common aligns to 4-bytes + // if this size is not a power of two, + // then round up to the next power of two + uint64_t size = this->getSize(); + alignment = 63 - (uint8_t)__builtin_clzll(size); + if ( size != (1ULL << alignment) ) + ++alignment; + } + // limit alignment of extremely large commons to 2^15 bytes (8-page) + if ( alignment < 12 ) + return ObjectFile::Alignment(alignment); + else + return ObjectFile::Alignment(12); +} + +template +const char* TentativeAtom::getSectionName() const +{ + if ( fOwner.fOptions.fForFinalLinkedImage || fOwner.fOptions.fMakeTentativeDefinitionsReal ) + return "__common"; + else + return "._tentdef"; +} + + +template +void TentativeAtom::copyRawContent(uint8_t buffer[]) const +{ + bzero(buffer, getSize()); +} + + +// +// An AnonymousAtom represents compiler generated data that has no name. +// For instance, a literal C-string or a 64-bit floating point constant +// is represented by an AnonymousAtom. +// +template +class AnonymousAtom : public BaseAtom +{ +public: + virtual ObjectFile::Reader* getFile() const { return &fOwner; } + virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; } + virtual const char* getName() const { return fSynthesizedName; } + virtual const char* getDisplayName() const; + virtual ObjectFile::Atom::Scope getScope() const; + virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return fKind; } + virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; } + virtual bool dontDeadStrip() const { return fDontDeadStrip; } + virtual bool isZeroFill() const; + virtual bool isThumb() const { return false; } + virtual uint64_t getSize() const { return fSize; } + virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } + virtual bool mustRemainInSection() const { return true; } + virtual const char* getSectionName() const; + virtual Segment& getSegment() const { return *fSegment; } + virtual ObjectFile::Atom& getFollowOnAtom() const; + virtual std::vector* getLineInfo() const { return NULL; } + virtual ObjectFile::Alignment getAlignment() const; + virtual void copyRawContent(uint8_t buffer[]) const; + virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; } + virtual void setSize(uint64_t size) { fSize = size; } + virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference*)ref); } + virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); } + virtual void addLineInfo(const ObjectFile::LineInfo& info) { warning("can't add line info to anonymous symbol %s from %s", this->getDisplayName(), this->getFile()->getPath()); } + virtual uint64_t getObjectAddress() const { return fAddress; } + virtual const void* getSectionRecord() const { return (const void*)fSection; } + BaseAtom* redirectTo() { return fRedirect; } + bool isWeakImportStub() { return fWeakImportStub; } + void resolveName(); + +protected: + typedef typename A::P P; + typedef typename A::P::E E; + typedef typename A::P::uint_t pint_t; + typedef typename A::ReferenceKinds Kinds; + typedef typename std::vector*> ReferenceVector; + typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser + typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser + friend class Reader; + + AnonymousAtom(Reader&, const macho_section

*, pint_t addr, pint_t size); + virtual ~AnonymousAtom() {} + static bool cstringsHaveLabels(); + + Reader& fOwner; + const char* fSynthesizedName; + const char* fDisplayName; + const macho_section

* fSection; + pint_t fAddress; + pint_t fSize; + Segment* fSegment; + ReferenceVector fReferences; + BaseAtom* fRedirect; + bool fDontDeadStrip; + bool fWeakImportStub; + ObjectFile::Atom::SymbolTableInclusion fSymbolTableInclusion; + ObjectFile::Atom::Scope fScope; + ObjectFile::Atom::DefinitionKind fKind; +}; + +template +AnonymousAtom::AnonymousAtom(Reader& owner, const macho_section

* section, pint_t addr, pint_t size) + : fOwner(owner), fSynthesizedName(NULL), fDisplayName(NULL), fSection(section), fAddress(addr), fSize(size), + fSegment(NULL), fDontDeadStrip(true), fWeakImportStub(false), fSymbolTableInclusion(ObjectFile::Atom::kSymbolTableNotIn), + fScope(ObjectFile::Atom::scopeTranslationUnit), fKind(ObjectFile::Atom::kRegularDefinition) +{ + fSegment = new Segment(fSection); + fRedirect = this; + uint8_t type = fSection->flags() & SECTION_TYPE; + //fprintf(stderr, "AnonymousAtom(%p) addr=0x%llX in %s from %s\n", this, (long long)addr, section->sectname(), owner.getPath()); + switch ( type ) { + case S_ZEROFILL: + { + asprintf((char**)&fSynthesizedName, "zero-fill-at-0x%08X", addr); + } + break; + case S_COALESCED: + case S_REGULAR: + if ( (strcmp(section->sectname(), "__class") == 0) && (strcmp(section->segname(), "__OBJC") == 0) && owner.fAppleObjc ) { + // special case ObjC classes to synthesize .objc_class_name_* symbols, for Apple runtime only + fSynthesizedName = ".objc_class_name_PENDING"; + owner.fAtomsPendingAName.push_back(this); + owner.fSectionsWithAtomsPendingAName.insert(fSection); + if ( fOwner.fOptions.fForFinalLinkedImage ) + fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn; + else + fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAsAbsolute; + fScope = ObjectFile::Atom::scopeGlobal; + } + else if ( strcmp(fSection->sectname(), "__cstring") == 0 ) { + // handle .o files created by old ld64 -r that are missing cstring section type + const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr(); + asprintf((char**)&fSynthesizedName, "cstring=%s", str); + } + else if ((strcmp(section->sectname(), "__cfstring") == 0) && (strcmp(section->segname(), "__DATA") == 0)) { + fSynthesizedName = "cfstring-pointer-name-PENDING"; + fScope = ObjectFile::Atom::scopeLinkageUnit; + owner.fAtomsPendingAName.push_back(this); + owner.fSectionsWithAtomsPendingAName.insert(fSection); + fDontDeadStrip = false; + fKind = ObjectFile::Atom::kWeakDefinition; + } + break; + case S_CSTRING_LITERALS: + { + const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr(); + asprintf((char**)&fSynthesizedName, "cstring=%s", str); + fScope = ObjectFile::Atom::scopeLinkageUnit; + fKind = ObjectFile::Atom::kWeakDefinition; + fDontDeadStrip = false; + if ( !fOwner.fOptions.fForFinalLinkedImage && cstringsHaveLabels() ) + fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn; + } + break; + case S_4BYTE_LITERALS: + { + uint32_t value = E::get32(*(uint32_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr())); + asprintf((char**)&fSynthesizedName, "4-byte-literal=0x%08X", value); + fScope = ObjectFile::Atom::scopeLinkageUnit; + fKind = ObjectFile::Atom::kWeakDefinition; + fDontDeadStrip = false; + } + break; + case S_8BYTE_LITERALS: + { + uint64_t value = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr())); + asprintf((char**)&fSynthesizedName, "8-byte-literal=0x%016llX", value); + fScope = ObjectFile::Atom::scopeLinkageUnit; + fKind = ObjectFile::Atom::kWeakDefinition; + fDontDeadStrip = false; + } + break; + case S_16BYTE_LITERALS: + { + uint64_t value1 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr())); + uint64_t value2 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr + 8 - section->addr())); + asprintf((char**)&fSynthesizedName, "16-byte-literal=0x%016llX,%016llX", value1, value2); + fScope = ObjectFile::Atom::scopeLinkageUnit; + fKind = ObjectFile::Atom::kWeakDefinition; + fDontDeadStrip = false; + } + break; + case S_LITERAL_POINTERS: + { + //uint32_t literalNameAddr = P::getP(*(pint_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr())); + //const char* str = (char*)(owner.fHeader) + section->offset() + literalNameAddr - section->addr(); + //asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", section->segname(), section->sectname(), str); + fSynthesizedName = "literal-pointer-name-PENDING"; + fScope = ObjectFile::Atom::scopeLinkageUnit; + fKind = ObjectFile::Atom::kWeakDefinition; + fDontDeadStrip = false; + owner.fAtomsPendingAName.push_back(this); + owner.fSectionsWithAtomsPendingAName.insert(fSection); + } + break; + case S_MOD_INIT_FUNC_POINTERS: + asprintf((char**)&fSynthesizedName, "initializer$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t)); + break; + case S_MOD_TERM_FUNC_POINTERS: + asprintf((char**)&fSynthesizedName, "terminator$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t)); + break; + case S_SYMBOL_STUBS: + { + uint32_t index = (fAddress - fSection->addr()) / fSection->reserved2(); + index += fSection->reserved1(); + uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]); + const macho_nlist

* sym = &fOwner.fSymbols[symbolIndex]; + uint32_t strOffset = sym->n_strx(); + // want name to not have $stub suffix, this is what automatic stub generation expects + fSynthesizedName = &fOwner.fStrings[strOffset]; + // check for weak import + fWeakImportStub = fOwner.isWeakImportSymbol(sym); + // sometimes the compiler gets confused and generates a stub to a static function + // if so, we should redirect any call to the stub to be calls to the real static function atom + if ( ((sym->n_type() & N_TYPE) != N_UNDF) && ((sym->n_type() & N_EXT) == 0) ) { + BaseAtom* staticAtom = fOwner.findAtomByName(fSynthesizedName); + if ( staticAtom != NULL ) + fRedirect = staticAtom; + } + fKind = ObjectFile::Atom::kWeakDefinition; + // might be a spurious stub for a static function, make stub static too + if ( (sym->n_type() & N_EXT) == 0 ) + fScope = ObjectFile::Atom::scopeTranslationUnit; + else + fScope = ObjectFile::Atom::scopeLinkageUnit; + } + break; + case S_LAZY_SYMBOL_POINTERS: + case S_NON_LAZY_SYMBOL_POINTERS: + { + fDontDeadStrip = false; + fScope = ObjectFile::Atom::scopeLinkageUnit; + uint32_t index = (fAddress - fSection->addr()) / sizeof(pint_t); + index += fSection->reserved1(); + uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]); + if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) { + // Silly codegen with non-lazy pointer to a local symbol + uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress; + pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fOwner.fHeader)+fileOffset))); + // All atoms not created yet, so we need to scan symbol table + const macho_nlist

* closestSym = NULL; + const macho_nlist

* end = &fOwner.fSymbols[fOwner.fSymbolCount]; + for (const macho_nlist

* sym = fOwner.fSymbols; sym < end; ++sym) { + if ( ((sym->n_type() & N_TYPE) == N_SECT) + && ((sym->n_type() & N_STAB) == 0) ) { + if ( sym->n_value() == nonLazyPtrValue ) { + const char* name = &fOwner.fStrings[sym->n_strx()]; + char* str = new char[strlen(name)+16]; + strcpy(str, name); + strcat(str, "$non_lazy_ptr"); + fSynthesizedName = str; + // add direct reference to target later, because its atom may not be constructed yet + fOwner.fLocalNonLazys.push_back(this); + fScope = ObjectFile::Atom::scopeTranslationUnit; + return; + } + else if ( (sym->n_value() < nonLazyPtrValue) && ((closestSym == NULL) || (sym->n_value() > closestSym->n_value())) ) { + closestSym = sym; + } + } + } + // add direct reference to target later, because its atom may not be constructed yet + if ( closestSym != NULL ) { + const char* name = &fOwner.fStrings[closestSym->n_strx()]; + char* str; + asprintf(&str, "%s+%u$non_lazy_ptr", name, nonLazyPtrValue - closestSym->n_value()); + fSynthesizedName = str; + } + else { + fSynthesizedName = "$interior$non_lazy_ptr"; + } + fScope = ObjectFile::Atom::scopeTranslationUnit; + fOwner.fLocalNonLazys.push_back(this); + return; + } + const macho_nlist

* targetSymbol = &fOwner.fSymbols[symbolIndex]; + const char* name = &fOwner.fStrings[targetSymbol->n_strx()]; + char* str = new char[strlen(name)+16]; + strcpy(str, name); + if ( type == S_LAZY_SYMBOL_POINTERS ) + strcat(str, "$lazy_ptr"); + else + strcat(str, "$non_lazy_ptr"); + fSynthesizedName = str; + + // optimize __IMPORT segment out of i386 dyld or if -slow_stubs is used + if ( (fOwner.fOptions.fForDyld || fOwner.fOptions.fSlowx86Stubs) && (strcmp(fSection->segname(),"__IMPORT") == 0) ) { + macho_section

* dummySection = new macho_section

(*fSection); + dummySection->set_segname("__DATA"); + dummySection->set_sectname("__nl_symbol_ptr"); + fSection = dummySection; + fSegment = new Segment(fSection); + } + + if ( type == S_NON_LAZY_SYMBOL_POINTERS ) + fKind = ObjectFile::Atom::kWeakDefinition; + + if ( (targetSymbol->n_type() & N_EXT) == 0 ) { + // target is translation unit scoped, so add direct reference to target + //fOwner.makeReference(A::kPointer, addr, targetSymbol->n_value()); + new Reference(A::kPointer, AtomAndOffset(this), fOwner.findAtomAndOffset(targetSymbol->n_value())); + } + else { + if ( fOwner.isWeakImportSymbol(targetSymbol) ) + new Reference(A::kPointerWeakImport, AtomAndOffset(this), name, 0); + else + new Reference(A::kPointer, AtomAndOffset(this), name, 0); + } + } + break; + default: + throwf("section type %d not supported with address=0x%08X", type, addr); + } + //fprintf(stderr, "AnonymousAtom(%p) %s \n", this, this->getDisplayName()); +} + +// x86_64 uses L labels on cstrings to allow relocs with addends +template <> bool AnonymousAtom::cstringsHaveLabels() { return true; } +template bool AnonymousAtom::cstringsHaveLabels() { return false; } + + +template +void AnonymousAtom::resolveName() +{ + if ( (strcmp(fSection->sectname(), "__class") == 0) && (strcmp(fSection->segname(), "__OBJC") == 0) ) { + std::vector& references = this->getReferences(); + // references are not yet sorted, so scan the vector + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + if ( ((*rit)->getFixUpOffset() == sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) { + const char* superStr = (*rit)->getTargetName(); + if ( strncmp(superStr, "cstring=", 8) == 0 ) { + const char* superClassName; + asprintf((char**)&superClassName, ".objc_class_name_%s", &superStr[8]); + new Reference(A::kNoFixUp, AtomAndOffset(this), superClassName, 0); + } + break; + } + } + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) { + const char* classStr = (*rit)->getTargetName(); + if ( strncmp(classStr, "cstring=", 8) == 0 ) { + asprintf((char**)&fSynthesizedName, ".objc_class_name_%s", &classStr[8]); + } + break; + } + } + } + else if ( (fSection->flags() & SECTION_TYPE) == S_LITERAL_POINTERS) { + std::vector& references = this->getReferences(); + if ( references.size() < 1 ) + throwf("S_LITERAL_POINTERS section %s,%s missing relocs", fSection->segname(), fSection->sectname()); + ObjectFile::Reference* ref = references[0]; + const char* str = ref->getTargetName(); + if ( strncmp(str, "cstring=", 8) == 0 ) { + asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", fSection->segname(), fSection->sectname(), &str[8]); + } + } + else if ( (strcmp(fSection->sectname(), "__cfstring") == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) { + // references are not yet sorted, so scan the vector + std::vector& references = this->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) { + const char* superStr = (*rit)->getTargetName(); + if ( (superStr != NULL) && (strncmp(superStr, "cstring=", 8) == 0) ) { + asprintf((char**)&fSynthesizedName, "cfstring=%s", &superStr[8]); + } + else { + // compiled with -fwritable-strings or a non-ASCII string + ObjectFile::Atom& stringDataAtom = (*rit)->getTarget(); + uint8_t buffer[stringDataAtom.getSize()]; + stringDataAtom.copyRawContent(buffer); + fKind = ObjectFile::Atom::kRegularDefinition; // these are not coalescable + fScope = ObjectFile::Atom::scopeTranslationUnit; + fSynthesizedName = "cfstring-not-coalesable"; + } + break; + } + } + } +} + + +template +const char* AnonymousAtom::getDisplayName() const +{ + if ( fSynthesizedName != NULL ) + return fSynthesizedName; + + if ( fDisplayName != NULL ) + return fDisplayName; + + if ( (fSection->flags() & SECTION_TYPE) == S_CSTRING_LITERALS ) { + uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress; + asprintf((char**)&fDisplayName, "atom string literal: \"%s\"", (char*)(fOwner.fHeader)+fileOffset); + } + else { + asprintf((char**)&fDisplayName, "%s@%d", fSection->sectname(), fAddress - (uint32_t)fSection->addr() ); + } + return fDisplayName; +} + + +template +ObjectFile::Atom::Scope AnonymousAtom::getScope() const +{ + return fScope; +} + + +template +bool AnonymousAtom::isZeroFill() const +{ + return ( (fSection->flags() & SECTION_TYPE) == S_ZEROFILL ); +} + + +template +const char* AnonymousAtom::getSectionName() const +{ + if ( strlen(fSection->sectname()) > 15 ) { + static char temp[18]; + strncpy(temp, fSection->sectname(), 16); + temp[17] = '\0'; + return temp; + } + return fSection->sectname(); +} + +template +ObjectFile::Alignment AnonymousAtom::getAlignment() const +{ + switch ( fSection->flags() & SECTION_TYPE ) { + case S_4BYTE_LITERALS: + return ObjectFile::Alignment(2); + case S_8BYTE_LITERALS: + return ObjectFile::Alignment(3); + case S_16BYTE_LITERALS: + return ObjectFile::Alignment(4); + case S_NON_LAZY_SYMBOL_POINTERS: + return ObjectFile::Alignment((uint8_t)log2(sizeof(pint_t))); + case S_CSTRING_LITERALS: + if ( ! fOwner.fOptions.fForFinalLinkedImage ) + return ObjectFile::Alignment(fSection->align()); + default: + return ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align())); + } +} + + +template +ObjectFile::Atom& AnonymousAtom::getFollowOnAtom() const +{ + for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) { + Reference* ref = *it; + if ( ref->getKind() == A::kFollowOn ) + return ref->getTarget(); + } + return *((ObjectFile::Atom*)NULL); +} + +template +void AnonymousAtom::copyRawContent(uint8_t buffer[]) const +{ + // copy base bytes + if ( isZeroFill() ) + bzero(buffer, fSize); + else { + uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress; + memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize); + } +} + + +// +// An AbsoluteAtom represents an N_ABS symbol which can only be created in +// assembly language and usable by static executables such as the kernel/ +// +template +class AbsoluteAtom : public BaseAtom +{ +public: + virtual ObjectFile::Reader* getFile() const { return &fOwner; } + virtual bool getTranslationUnitSource(const char** dir, const char** name) const + { return fOwner.getTranslationUnitSource(dir, name); } + virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; } + virtual const char* getDisplayName() const { return getName(); } + virtual ObjectFile::Atom::Scope getScope() const { return fScope; } + virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kAbsoluteSymbol; } + virtual bool isZeroFill() const { return false; } + virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); } + virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableInAsAbsolute; } + virtual bool dontDeadStrip() const { return false; } + virtual uint64_t getSize() const { return 0; } + virtual std::vector& getReferences() const { return fgNoReferences; } + virtual bool mustRemainInSection() const { return true; } + virtual const char* getSectionName() const { return "._absolute"; } + virtual ObjectFile::Segment& getSegment() const { return LinkEditSegment::fgSingleton; } + virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; } + virtual std::vector* getLineInfo() const { return NULL; } + virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); } + virtual void copyRawContent(uint8_t buffer[]) const { } + virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; } + virtual void setSize(uint64_t size) { } + virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; } + virtual void sortReferences() { } + virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; } + virtual uint64_t getObjectAddress() const { return fSymbol->n_value(); } + virtual void setSectionOffset(uint64_t offset) { /* don't let fSectionOffset be altered*/ } + virtual const void* getSectionRecord() const { return NULL; } + +protected: + typedef typename A::P P; + typedef typename A::P::E E; + typedef typename A::P::uint_t pint_t; + typedef typename A::ReferenceKinds Kinds; + friend class Reader; + + AbsoluteAtom(Reader&, const macho_nlist

*); + virtual ~AbsoluteAtom() {} + + Reader& fOwner; + const macho_nlist

* fSymbol; + ObjectFile::Atom::Scope fScope; + static std::vector fgNoReferences; +}; + +template +std::vector AbsoluteAtom::fgNoReferences; + +template +AbsoluteAtom::AbsoluteAtom(Reader& owner, const macho_nlist

* symbol) + : fOwner(owner), fSymbol(symbol) +{ + // store absolute adress in fSectionOffset + fSectionOffset = symbol->n_value(); + // compute scope + uint8_t type = symbol->n_type(); + if ( (type & N_EXT) == 0 ) + fScope = ObjectFile::Atom::scopeTranslationUnit; + else if ( (type & N_PEXT) != 0 ) + fScope = ObjectFile::Atom::scopeLinkageUnit; + else + fScope = ObjectFile::Atom::scopeGlobal; + //fprintf(stderr, "AbsoluteAtom(%p) %s\n", this, this->getDisplayName()); +} + + + +template +class Reader : public ObjectFile::Reader +{ +public: + static bool validFile(const uint8_t* fileContent); + Reader(const uint8_t* fileContent, const char* path, time_t modTime, + const ObjectFile::ReaderOptions& options, uint32_t ordinalBase); + virtual ~Reader() {} + + virtual const char* getPath() { return fPath; } + virtual time_t getModificationTime() { return fModTime; } + virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return fDebugInfo; } + virtual std::vector& getAtoms() { return (std::vector&)(fAtoms); } + virtual std::vector* getJustInTimeAtomsFor(const char* name) { return NULL; } + virtual std::vector* getStabs() { return &fStabs; } + virtual ObjectFile::Reader::ObjcConstraint getObjCConstraint() { return fObjConstraint; } + virtual uint32_t updateCpuConstraint(uint32_t current); + virtual bool canScatterAtoms() { return (fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS); } + virtual bool objcReplacementClasses(){ return fReplacementClasses; } + virtual bool hasLongBranchStubs() { return fHasLongBranchStubs; } + + bool getTranslationUnitSource(const char** dir, const char** name) const; + +private: + typedef typename A::P P; + typedef typename A::P::E E; + typedef typename A::P::uint_t pint_t; + //typedef typename std::vector*> AtomVector; + //typedef typename AtomVector::iterator AtomVectorIterator; // seems to help C++ parser + typedef typename A::ReferenceKinds Kinds; + friend class AnonymousAtom; + friend class TentativeAtom; + friend class AbsoluteAtom; + friend class SymbolAtom; + typedef std::map AddrToAtomMap; + + void addReferencesForSection(const macho_section

* sect); + bool addRelocReference(const macho_section

* sect, const macho_relocation_info

* reloc); + bool addRelocReference_powerpc(const macho_section

* sect, const macho_relocation_info

* reloc); + bool read_comp_unit(const char ** name, const char ** comp_dir, uint64_t *stmt_list); + static bool isWeakImportSymbol(const macho_nlist

* sym); + static bool skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form, uint8_t addr_size, bool dwarf64); + static const char* assureFullPath(const char* path); + AtomAndOffset findAtomAndOffset(pint_t addr); + AtomAndOffset findAtomAndOffset(pint_t baseAddr, pint_t realAddr); + Reference* makeReference(Kinds kind, pint_t atAddr, pint_t toAddr); + Reference* makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr); + Reference* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr); + Reference* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr); + Reference* makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset); + Reference* makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section

* ehSect); + Reference* makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist

* toSymbol, pint_t toOffset); + void validSectionType(uint8_t type); + void addDtraceExtraInfos(uint32_t probeAddr, const char* providerName); + void setCpuConstraint(uint32_t cpusubtype); + + BaseAtom* findAtomByName(const char*); + + const char* fPath; + time_t fModTime; + uint32_t fOrdinalBase; + const ObjectFile::ReaderOptions& fOptions; + const macho_header

* fHeader; + const char* fStrings; + const macho_nlist

* fSymbols; + uint32_t fSymbolCount; + const macho_segment_command

* fSegment; + const uint32_t* fIndirectTable; + std::vector fAtoms; + AddrToAtomMap fAddrToAtom; + AddrToAtomMap fAddrToAbsoluteAtom; + std::vector*> fLocalNonLazys; + std::vector*> fAtomsPendingAName; + std::set*> fSectionsWithAtomsPendingAName; + std::vector fDtraceProviderInfo; + ObjectFile::Reader::DebugInfoKind fDebugInfo; + bool fHasUUID; + const macho_section

* fDwarfDebugInfoSect; + const macho_section

* fDwarfDebugAbbrevSect; + const macho_section

* fDwarfDebugLineSect; + const char* fDwarfTranslationUnitDir; + const char* fDwarfTranslationUnitFile; + std::map fDwarfIndexToFile; + std::vector fStabs; + bool fAppleObjc; + bool fHasDTraceProbes; + bool fHaveIndirectSymbols; + bool fReplacementClasses; + bool fHasLongBranchStubs; + ObjectFile::Reader::ObjcConstraint fObjConstraint; + uint32_t fCpuConstraint; +}; + +template +Reader::Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options, uint32_t ordinalBase) + : fPath(strdup(path)), fModTime(modTime), fOrdinalBase(ordinalBase), fOptions(options), fHeader((const macho_header

*)fileContent), + fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL), + fDebugInfo(kDebugInfoNone), fHasUUID(false), fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL), fDwarfDebugLineSect(NULL), + fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL), fAppleObjc(false), fHasDTraceProbes(false), + fHaveIndirectSymbols(false), fReplacementClasses(false), fHasLongBranchStubs(false), + fObjConstraint(ObjectFile::Reader::kObjcNone), fCpuConstraint(ObjectFile::Reader::kCpuAny) +{ + // sanity check + if ( ! validFile(fileContent) ) + throw "not a valid mach-o object file"; + + Reference::fgForFinalLinkedImage = options.fForFinalLinkedImage; + + // write out path for -t or -whatsloaded option + if ( options.fLogObjectFiles || options.fLogAllFiles ) + printf("%s\n", path); + + // cache intersting pointers + const macho_header

* header = (const macho_header

*)fileContent; + this->setCpuConstraint(header->cpusubtype()); + const uint32_t cmd_count = header->ncmds(); + const macho_load_command

* const cmds = (macho_load_command

*)((char*)header + sizeof(macho_header

)); + const macho_load_command

* const cmdsEnd = (macho_load_command

*)((char*)header + sizeof(macho_header

) + header->sizeofcmds()); + const macho_load_command

* cmd = cmds; + uint32_t undefinedStartIndex = 0; + uint32_t undefinedEndIndex = 0; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd()) { + case LC_SYMTAB: + { + const macho_symtab_command

* symtab = (macho_symtab_command

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

*)((char*)header + symtab->symoff()); + fStrings = (char*)header + symtab->stroff(); + if ( undefinedEndIndex == 0 ) { + undefinedStartIndex = 0; + undefinedEndIndex = symtab->nsyms(); + } + } + break; + case LC_DYSYMTAB: + { + const macho_dysymtab_command

* dsymtab = (struct macho_dysymtab_command

*)cmd; + fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff()); + undefinedStartIndex = dsymtab->iundefsym(); + undefinedEndIndex = undefinedStartIndex + dsymtab->nundefsym(); + } + break; + case LC_UUID: + fHasUUID = true; + break; + + default: + if ( cmd->cmd() == macho_segment_command

::CMD ) { + fSegment = (macho_segment_command

*)cmd; + } + break; + } + cmd = (const macho_load_command

*)(((char*)cmd)+cmd->cmdsize()); + if ( cmd > cmdsEnd ) + throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, path); + } + + // if there are no load commands, then this file has no content, so no atoms + if ( header->ncmds() < 1 ) + return; + + const macho_section

* const sectionsStart = (macho_section

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

)); + const macho_section

* const sectionsEnd = §ionsStart[fSegment->nsects()]; + + // inital guess for number of atoms + fAtoms.reserve(fSymbolCount); + + // add all atoms that have entries in symbol table + const macho_section

* sections = (macho_section

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

)); + for (int i=fSymbolCount-1; i >= 0 ; --i) { + // walk backwards through symbol table so globals are see before locals, otherwise a local alias would beome the reaal name + const macho_nlist

& sym = fSymbols[i]; + if ( (sym.n_type() & N_STAB) == 0 ) { + uint8_t type = (sym.n_type() & N_TYPE); + if ( type == N_SECT ) { + const macho_section

* section = §ions[sym.n_sect()-1]; + pint_t sectionEndAddr = section->addr() + section->size(); + bool suppress = false; + // ignore atoms in debugger sections + if ( (section->flags() & S_ATTR_DEBUG) == 0 ) { + if ( strncmp(&fStrings[sym.n_strx()], "__dtrace_probe$", 15) == 0 ) { + // ignore dtrace probe labels + fHasDTraceProbes = true; + } + else if ( fStrings[sym.n_strx()] == 'L' ) { + // ignore L labels, + } + else { + // ignore labels for atoms in other sections + switch ( section->flags() & SECTION_TYPE ) { + case S_REGULAR: + if ( (sym.n_desc() & N_WEAK_DEF) && strcmp(section->sectname(), "__picsymbolstub1__TEXT") == 0 ) + suppress = true; // ignore stubs in crt1.o built by old ld64 that was missing S_SYMBOL_STUBS + case S_ZEROFILL: + case S_COALESCED: + case S_4BYTE_LITERALS: + case S_8BYTE_LITERALS: + case S_16BYTE_LITERALS: + case S_CSTRING_LITERALS: + { + BaseAtom* newAtom; + typename AddrToAtomMap::iterator pos = fAddrToAtom.find(sym.n_value()); + if ( (pos != fAddrToAtom.end()) && (strcmp(pos->second->getSectionName(), section->sectname())==0) ) { + // another label to an existing address in the same section, make this an alias + newAtom = new SymbolAliasAtom(&fStrings[sym.n_strx()], &sym, *pos->second); + } + else { + // make SymbolAtom atom for this address + newAtom = new SymbolAtom(*this, &sym, section); + // don't add symbols at end of section to addr->atom map + if ( sym.n_value() != sectionEndAddr ) + fAddrToAtom[newAtom->getObjectAddress()] = newAtom; + } + if ( ! suppress ) + fAtoms.push_back(newAtom); + } + break; + case S_SYMBOL_STUBS: + case S_LAZY_SYMBOL_POINTERS: + case S_NON_LAZY_SYMBOL_POINTERS: + // ignore symboled stubs produces by old ld64 + break; + default: + warning("symbol %s found in unsupported section in %s", + &fStrings[sym.n_strx()], this->getPath()); + } + } + } + } + else if ( (type == N_UNDF) && (sym.n_value() != 0) ) { + fAtoms.push_back(new TentativeAtom(*this, &sym)); + } + else if ( type == N_ABS ) { + const char* symName = &fStrings[sym.n_strx()]; + if ( strncmp(symName, ".objc_class_name_", 17) == 0 ) { + // ignore .objc_class_name_* symbols + fAppleObjc = true; + } + else if ( strcmp(&symName[strlen(symName)-3], ".eh") == 0 ) { + // ignore empty *.eh symbols + } + else { + BaseAtom* abAtom = new AbsoluteAtom(*this, &sym); + fAtoms.push_back(abAtom); + fAddrToAbsoluteAtom[sym.n_value()] = abAtom; + } + } + else if ( type == N_INDR ) { + fHaveIndirectSymbols = true; + } + } + } + + // add all fixed size anonymous atoms from special sections + for (const macho_section

* sect=sectionsStart; sect < sectionsEnd; ++sect) { + pint_t atomSize = 0; + uint8_t type (sect->flags() & SECTION_TYPE); + validSectionType(type); + bool suppress = false; + switch ( type ) { + case S_SYMBOL_STUBS: + suppress = true; + atomSize = sect->reserved2(); + break; + case S_LAZY_SYMBOL_POINTERS: + suppress = true; + atomSize = sizeof(pint_t); + break; + case S_NON_LAZY_SYMBOL_POINTERS: + case S_LITERAL_POINTERS: + case S_MOD_INIT_FUNC_POINTERS: + case S_MOD_TERM_FUNC_POINTERS: + atomSize = sizeof(pint_t); + break; + case S_INTERPOSING: + atomSize = sizeof(pint_t)*2; + break; + case S_4BYTE_LITERALS: + atomSize = 4; + break; + case S_8BYTE_LITERALS: + atomSize = 8; + break; + case S_16BYTE_LITERALS: + atomSize = 16; + break; + case S_REGULAR: + // special case ObjC classes to synthesize .objc_class_name_* symbols + if ( (strcmp(sect->sectname(), "__class") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) && fAppleObjc ) { + // gcc sometimes over aligns class structure + uint32_t align = 1 << sect->align(); + atomSize = ((12 * sizeof(pint_t)) + align-1) & (-align); + } + // get objc Garbage Collection info + else if ( ((strcmp(sect->sectname(), "__image_info") == 0) && (strcmp(sect->segname(), "__OBJC") == 0)) + || ((strncmp(sect->sectname(), "__objc_imageinfo", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0)) ) { + // struct objc_image_info { + // uint32_t version; // initially 0 + // uint32_t flags; + // }; + // #define OBJC_IMAGE_SUPPORTS_GC 2 + // #define OBJC_IMAGE_GC_ONLY 4 + // + const uint32_t* contents = (uint32_t*)(((char*)fHeader) + sect->offset()); + if ( (sect->size() >= 8) && (contents[0] == 0) ) { + uint32_t flags = E::get32(contents[1]); + if ( (flags & 4) == 4 ) + fObjConstraint = ObjectFile::Reader::kObjcGC; + else if ( (flags & 2) == 2 ) + fObjConstraint = ObjectFile::Reader::kObjcRetainReleaseOrGC; + else + fObjConstraint = ObjectFile::Reader::kObjcRetainRelease; + if ( (flags & 1) == 1 ) + fReplacementClasses = true; + // don't make atom for this section + atomSize = sect->size(); + suppress = true; + } + else { + warning("can't parse __OBJC/__image_info section in %s", fPath); + } + } + // special case constant NS/CFString literals and make an atom out of each one + else if ((strcmp(sect->sectname(), "__cfstring") == 0) && (strcmp(sect->segname(), "__DATA") == 0)) { + atomSize = 4 * sizeof(pint_t); + } + break; + } + if ( atomSize != 0 ) { + for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += atomSize) { + pint_t atomAddr = sect->addr() + sectOffset; + // add if not already an atom at that address + if ( fAddrToAtom.find(atomAddr) == fAddrToAtom.end() ) { + AnonymousAtom* newAtom = new AnonymousAtom(*this, sect, atomAddr, atomSize); + if ( !suppress ) + fAtoms.push_back(newAtom); + fAddrToAtom[atomAddr] = newAtom->redirectTo(); + } + } + } + } + + // add all c-string anonymous atoms + for (const macho_section

* sect=sectionsStart; sect < sectionsEnd; ++sect) { + if ( ((sect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS) || strcmp(sect->sectname(), "__cstring") == 0 ) { + uint32_t stringLen; + pint_t stringAddr; + BaseAtom* mostAlignedEmptyString = NULL; + uint32_t mostAlignedEmptyStringTrailingZeros = 0; + std::vector > emptyStrings; + for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += stringLen) { + stringAddr = sect->addr() + sectOffset; + stringLen = strlen((char*)(fHeader) + sect->offset() + sectOffset) + 1; + // add if not already an atom at that address + if ( fAddrToAtom.find(stringAddr) == fAddrToAtom.end() ) { + BaseAtom* newAtom = new AnonymousAtom(*this, sect, stringAddr, stringLen); + if ( stringLen == 1 ) { + // because of padding it may look like there are lots of empty strings, keep track of all + emptyStrings.push_back(std::make_pair(stringAddr, newAtom)); + // record empty string with greatest alignment requirement + uint32_t stringAddrTrailingZeros = (stringAddr==0) ? sect->align() : __builtin_ctz(stringAddr); + if ( (mostAlignedEmptyString == NULL) + || ( stringAddrTrailingZeros > mostAlignedEmptyStringTrailingZeros) ) { + mostAlignedEmptyString = newAtom; + mostAlignedEmptyStringTrailingZeros = stringAddrTrailingZeros; + } + } + else { + fAtoms.push_back(newAtom); + fAddrToAtom[stringAddr] = newAtom; + } + } + } + // map all uses of empty strings to the most aligned one + if ( mostAlignedEmptyString != NULL ) { + // make most aligned atom a real atom + fAtoms.push_back(mostAlignedEmptyString); + // map all other empty atoms to this one + for (typename std::vector >::iterator it=emptyStrings.begin(); it != emptyStrings.end(); it++) { + fAddrToAtom[it->first] = mostAlignedEmptyString; + } + } + } + } + + // sort all atoms so far by address and section + std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter()); + + //fprintf(stderr, "sorted atoms:\n"); + //for (std::vector::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) + // fprintf(stderr, "0x%08llX %s\n", (*it)->getObjectAddress(), (*it)->getDisplayName()); + + // create atoms to cover any non-debug ranges not handled above + for (const macho_section

* sect=sectionsStart; sect < sectionsEnd; ++sect) { + pint_t sectionStartAddr = sect->addr(); + pint_t sectionEndAddr = sect->addr() + sect->size(); + const bool setFollowOnAtom = ! this->canScatterAtoms(); + if ( sect->size() != 0 ) { + // ignore dwarf sections. If ld every supports processing dwarf, this logic will need to change + if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) { + fDebugInfo = kDebugInfoDwarf; + if ( strcmp(sect->sectname(), "__debug_info") == 0 ) + fDwarfDebugInfoSect = sect; + else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 ) + fDwarfDebugAbbrevSect = sect; + else if ( strcmp(sect->sectname(), "__debug_line") == 0 ) + fDwarfDebugLineSect = sect; + } + else { + if ( strcmp(sect->segname(), "__DWARFA") == 0 ) { + throw "object file contains old DWARF debug info - rebuild with newer compiler"; + } + uint8_t type (sect->flags() & SECTION_TYPE); + switch ( type ) { + case S_REGULAR: + case S_ZEROFILL: + case S_COALESCED: + // if there is not an atom already at the start of this section, add an anonymous one + pint_t previousAtomAddr = 0; + BaseAtom* previousAtom = NULL; + if ( fAddrToAtom.find(sectionStartAddr) == fAddrToAtom.end() ) { + BaseAtom* newAtom = new AnonymousAtom(*this, sect, sect->addr(), 0); + fAddrToAtom[sect->addr()] = newAtom; + fAtoms.push_back(newAtom); + previousAtomAddr = sectionStartAddr; + previousAtom = newAtom; + std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter()); + } + // calculate size of all atoms in this section and add follow-on references + for (std::vector::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) { + BaseAtom* atom = (BaseAtom*)(*it); + pint_t atomAddr = atom->getObjectAddress(); + if ( atom->getSectionRecord() == sect ) { + //fprintf(stderr, "addr=0x%08llX, atom=%s\n", (uint64_t)atomAddr, atom->getDisplayName()); + if ( (previousAtom != NULL) && (previousAtomAddr != atomAddr) ) { + previousAtom->setSize(atomAddr - previousAtomAddr); + if ( setFollowOnAtom && (atom != previousAtom) ) + new Reference(A::kFollowOn, AtomAndOffset(previousAtom), AtomAndOffset(atom)); + } + previousAtomAddr = atomAddr; + previousAtom = atom; + } + } + if ( previousAtom != NULL ) { + // set last atom in section + previousAtom->setSize(sectionEndAddr - previousAtomAddr); + } + break; + } + } + } + } + + // check for object file that defines no objc classes, but uses objc classes + // check for dtrace provider info + for (uint32_t i=undefinedStartIndex; i < undefinedEndIndex; ++i) { + const macho_nlist

& sym = fSymbols[i]; + if ( (sym.n_type() & N_STAB) == 0 ) { + if ( (sym.n_type() & N_TYPE) == N_UNDF ) { + const char* undefinedName = &fStrings[sym.n_strx()]; + if ( !fAppleObjc && (strncmp(undefinedName, ".objc_class_name_", 17) == 0) ) { + fAppleObjc = true; + } + else if ( strncmp(undefinedName, "___dtrace_", 10) == 0 ) { + if ( strchr(undefinedName, '$') != NULL ) { + if ( (strncmp(&undefinedName[10], "probe$", 6) != 0) && (strncmp(&undefinedName[10], "isenabled$", 10) != 0) ) { + // any undefined starting with __dtrace_*$ that is not ___dtrace_probe$* or ___dtrace_isenabled$* + // is extra provider info + fDtraceProviderInfo.push_back(undefinedName); + } + } + } + } + } + } + + // add relocation based references to sections that have atoms with pending names + for (const macho_section

* sect=sectionsStart; sect < sectionsEnd; ++sect) { + if ( fSectionsWithAtomsPendingAName.count(sect) != 0 ) + addReferencesForSection(sect); + } + + // update any anonymous atoms that need references built in order to name themselves + for (typename std::vector*>::iterator it=fAtomsPendingAName.begin(); it != fAtomsPendingAName.end(); it++) { + (*it)->resolveName(); + } + + // add relocation based references to other sections + for (const macho_section

* sect=sectionsStart; sect < sectionsEnd; ++sect) { + if ( fSectionsWithAtomsPendingAName.count(sect) == 0 ) + addReferencesForSection(sect); + } + + // add objective-c references + if ( fAppleObjc ) { + for (const macho_section

* sect=sectionsStart; sect < sectionsEnd; ++sect) { + if ( (strcmp(sect->sectname(), "__cls_refs") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) { + for (uint32_t offset = 0; offset < sect->size(); offset += sizeof(pint_t)) { + AtomAndOffset ao = this->findAtomAndOffset(sect->addr()+offset); + ObjectFile::Reference* classRef = ao.atom->getReferences()[0]; + if ( classRef->getFixUpOffset() == 0 ) { + const char* classStr = classRef->getTargetName(); + if ( strncmp(classStr, "cstring=", 8) == 0 ) { + const char* className; + asprintf((char**)&className, ".objc_class_name_%s", &classStr[8]); + new Reference(A::kNoFixUp, ao, className, 0); + } + } + } + } + } + } + + // add direct references to local non-lazy-pointers, can do this now that all atoms are constructed + for (typename std::vector*>::iterator it=fLocalNonLazys.begin(); it != fLocalNonLazys.end(); it++) { + AnonymousAtom* localNonLazy = *it; + uint32_t fileOffset = localNonLazy->fSection->offset() - localNonLazy->fSection->addr() + localNonLazy->fAddress; + pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fHeader)+fileOffset))); + makeReference(A::kPointer, localNonLazy->fAddress, nonLazyPtrValue); + } + + // add implicit direct reference from each C++ function to its eh info + for (const macho_section

* sect=sectionsStart; sect < sectionsEnd; ++sect) { + if ( ((sect->flags() & SECTION_TYPE) == S_COALESCED) && (strcmp(sect->sectname(), "__eh_frame") == 0) ) { + for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) { + // note: this algorithm depens on the map iterator returning entries in address order + if ( (it->first >= sect->addr()) && (it->first < sect->addr()+sect->size()) ) { + pint_t ehAtomAddress = it->first; + BaseAtom* ehAtom = it->second; + const char* ehName = ehAtom->getName(); + if ( (ehName != NULL) && (strcmp(&ehName[strlen(ehName)-3], ".eh") == 0) ) { + makeReferenceToEH(ehName, ehAtomAddress, sect); + // make EH symbol static so linker does not try to coalesce + if ( fOptions.fForFinalLinkedImage ) + ehAtom->setScope(ObjectFile::Atom::scopeTranslationUnit); + // if it has a reference to a LSDA, add a group reference + std::vector& ehrefs = ehAtom->getReferences(); + // all FDE's have at least 2 references (to CIE and to function) + if ( ehrefs.size() > 2 ) { + // a third reference means there is a LSDA + ObjectFile::Atom* lsdaAtom = NULL; + for (std::vector::iterator rit=ehrefs.begin(); rit != ehrefs.end(); rit++) { + ObjectFile::Reference* ref = *rit; + switch ( ref->getFixUpOffset() ) { + case 4: + case 8: + // these are CIE and function references + break; + default: + // this is LSDA reference + lsdaAtom = &ref->getTarget(); + } + } + if ( lsdaAtom != NULL ) { + new Reference(A::kGroupSubordinate, AtomAndOffset(ehAtom), AtomAndOffset(lsdaAtom)); + } + } + } + } + } + } + } + + // add command line aliases + for(std::vector::const_iterator it = fOptions.fAliases.begin(); it != fOptions.fAliases.end(); ++it) { + BaseAtom* target = this->findAtomByName(it->realName); + if ( (target != NULL) && target->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn ) + fAtoms.push_back(new SymbolAliasAtom(it->alias, NULL, *target)); + } + + // add dtrace probe locations + if ( fHasDTraceProbes ) { + for (uint32_t i=0; i < fSymbolCount; ++i) { + const macho_nlist

& sym = fSymbols[i]; + if ( (sym.n_type() & N_STAB) == 0 ) { + if ( (sym.n_type() & N_TYPE) == N_SECT ) { + const char* symbolName = &fStrings[sym.n_strx()]; + if ( strncmp(symbolName, "__dtrace_probe$", 15) == 0 ) { + //fprintf(stderr, "adding dtrace probe at 0x%08llX %s\n", sym.n_value(), symbolName); + makeByNameReference(A::kDtraceProbe, sym.n_value(), symbolName, 0); + } + } + } + } + } + + // turn indirect symbols int SymbolAliasAtom + if ( fHaveIndirectSymbols ) { + for (uint32_t i=0; i < fSymbolCount; ++i) { + const macho_nlist

& sym = fSymbols[i]; + if ( (sym.n_type() & N_STAB) == 0 ) { + if ( (sym.n_type() & N_TYPE) == N_INDR ) { + const char* aliasName = &fStrings[sym.n_strx()]; + const char* targetName = &fStrings[sym.n_value()]; + //fprintf(stderr, "found alias %s for %s\n", aliasName, targetName); + BaseAtom* target = this->findAtomByName(targetName); + // only currently support N_INDR based aliases to something in the same .o file + if ( target != NULL ) { + fAtoms.push_back(new SymbolAliasAtom(aliasName, &sym, *target)); + //fprintf(stderr, "creating alias %s for %s\n", aliasName, targetName); + } + } + } + } + } + + //for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) { + // fprintf(stderr, "[0x%0X -> 0x%0llX) : %s\n", it->first, it->first+it->second->getSize(), it->second->getDisplayName()); + //} + + // add translation unit info from dwarf + uint64_t stmtList; + if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) { + // compiler sometimes emits emtpty dwarf sections when there is no debug info, skip those + if ( (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) { + if ( !read_comp_unit(&fDwarfTranslationUnitFile, &fDwarfTranslationUnitDir, &stmtList) ) { + // if can't parse dwarf, warn and give up + fDwarfTranslationUnitFile = NULL; + fDwarfTranslationUnitDir = NULL; + warning("can't parse dwarf compilation unit info in %s", this->getPath()); + fDebugInfo = kDebugInfoNone; + } + } + } + + // add line number info to atoms from dwarf + if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) { + // file with just data will have no __debug_line info + if ( (fDwarfDebugLineSect != NULL) && (fDwarfDebugLineSect->size() != 0) && (fAddrToAtom.size() != 0) + && (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) { + // validate stmt_list + if ( (stmtList != (uint64_t)-1) && (stmtList < fDwarfDebugLineSect->size()) ) { + const uint8_t* debug_line = (uint8_t*)(fHeader) + fDwarfDebugLineSect->offset(); + if ( debug_line != NULL ) { + struct line_reader_data* lines = line_open(&debug_line[stmtList], + fDwarfDebugLineSect->size() - stmtList, E::little_endian); + struct line_info result; + ObjectFile::Atom* curAtom = NULL; + uint32_t curAtomOffset = 0; + uint32_t curAtomAddress = 0; + uint32_t curAtomSize = 0; + while ( line_next (lines, &result, line_stop_pc) ) { + //fprintf(stderr, "curAtom=%p, result.pc=0x%llX, result.line=%llu, result.end_of_sequence=%d, curAtomAddress=0x%X, curAtomSize=0x%X\n", + // curAtom, result.pc, result.line, result.end_of_sequence, curAtomAddress, curAtomSize); + // work around weird debug line table compiler generates if no functions in __text section + if ( (curAtom == NULL) && (result.pc == 0) && result.end_of_sequence && (result.file == 1)) + continue; + // for performance, see if in next pc is in current atom + if ( (curAtom != NULL) && (curAtomAddress <= result.pc) && (result.pc < (curAtomAddress+curAtomSize)) ) { + curAtomOffset = result.pc - curAtomAddress; + } + // or pc at end of current atom + else if ( result.end_of_sequence && (curAtom != NULL) && (result.pc == (curAtomAddress+curAtomSize)) ) { + curAtomOffset = result.pc - curAtomAddress; + } + else { + // do slow look up of atom by address + AtomAndOffset ao = this->findAtomAndOffset(result.pc); + curAtom = ao.atom; + if ( curAtom == NULL ) + break; // file has line info but no functions + if ( result.end_of_sequence && (curAtomAddress+curAtomSize < result.pc) ) { + // a one line function can be returned by line_next() as one entry with pc at end of blob + // look for alt atom starting at end of previous atom + uint32_t previousEnd = curAtomAddress+curAtomSize; + AtomAndOffset alt = this->findAtomAndOffset(previousEnd); + if ( result.pc <= previousEnd - alt.offset + alt.atom->getSize() ) { + curAtom = alt.atom; + curAtomOffset = alt.offset; + curAtomAddress = previousEnd - alt.offset; + curAtomSize = curAtom->getSize(); + } + else { + curAtomOffset = ao.offset; + curAtomAddress = result.pc - ao.offset; + curAtomSize = curAtom->getSize(); + } + } + else { + curAtomOffset = ao.offset; + curAtomAddress = result.pc - ao.offset; + curAtomSize = curAtom->getSize(); + } + } + const char* filename; + std::map::iterator pos = fDwarfIndexToFile.find(result.file); + if ( pos == fDwarfIndexToFile.end() ) { + filename = line_file(lines, result.file); + fDwarfIndexToFile[result.file] = filename; + } + else { + filename = pos->second; + } + ObjectFile::LineInfo info; + info.atomOffset = curAtomOffset; + info.fileName = filename; + info.lineNumber = result.line; + //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s, atom=%s, atom.size=0x%X, end=%d\n", + // result.pc, result.line, filename, curAtom->getDisplayName(), curAtomSize, result.end_of_sequence); + ((BaseAtom*)curAtom)->addLineInfo(info); + if ( result.end_of_sequence ) { + curAtom = NULL; + } + } + line_free(lines); + } + else { + warning("could not parse dwarf line number info in %s", this->getPath()); + } + } + } + } + + // if no dwarf, try processing stabs debugging info + if ( (fDebugInfo == kDebugInfoNone) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) { + // scan symbol table for stabs entries + fStabs.reserve(fSymbolCount); // reduce re-allocations + BaseAtom* currentAtom = NULL; + pint_t currentAtomAddress = 0; + enum { start, inBeginEnd, inFun } state = start; + for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) { + const macho_nlist

* sym = &fSymbols[symbolIndex]; + bool useStab = true; + uint8_t type = sym->n_type(); + const char* symString = (sym->n_strx() != 0) ? &fStrings[sym->n_strx()] : NULL; + if ( (type & N_STAB) != 0 ) { + fDebugInfo = (fHasUUID ? kDebugInfoStabsUUID : kDebugInfoStabs); + Stab stab; + stab.atom = NULL; + stab.type = type; + stab.other = sym->n_sect(); + stab.desc = sym->n_desc(); + stab.value = sym->n_value(); + stab.string = NULL; + switch (state) { + case start: + switch (type) { + case N_BNSYM: + // beginning of function block + state = inBeginEnd; + // fall into case to lookup atom by addresss + case N_LCSYM: + case N_STSYM: + currentAtomAddress = sym->n_value(); + currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom; + if ( currentAtom != NULL ) { + stab.atom = currentAtom; + stab.string = symString; + } + else { + fprintf(stderr, "can't find atom for stabs BNSYM at %08llX in %s", + (uint64_t)sym->n_value(), path); + } + break; + case N_SO: + case N_OSO: + case N_OPT: + case N_LSYM: + case N_RSYM: + case N_PSYM: + // not associated with an atom, just copy + stab.string = symString; + break; + case N_GSYM: + { + // n_value field is NOT atom address ;-( + // need to find atom by name match + const char* colon = strchr(symString, ':'); + if ( colon != NULL ) { + // build underscore leading name + int nameLen = colon - symString; + char symName[nameLen+2]; + strlcpy(&symName[1], symString, nameLen+1); + symName[0] = '_'; + symName[nameLen+1] = '\0'; + currentAtom = findAtomByName(symName); + if ( currentAtom != NULL ) { + stab.atom = currentAtom; + stab.string = symString; + } + } + else { + // might be a debug-note without trailing :G() + currentAtom = findAtomByName(symString); + if ( currentAtom != NULL ) { + stab.atom = currentAtom; + stab.string = symString; + } + } + if ( stab.atom == NULL ) { + warning("can't find atom for N_GSYM stabs %s in %s", symString, path); + useStab = false; + } + break; + } + case N_FUN: + // old style stabs without BNSYM + state = inFun; + currentAtomAddress = sym->n_value(); + currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom; + if ( currentAtom != NULL ) { + stab.atom = currentAtom; + stab.string = symString; + } + else { + warning("can't find atom for stabs FUN at %08llX in %s", + (uint64_t)currentAtomAddress, path); + } + break; + case N_SOL: + case N_SLINE: + stab.string = symString; + // old stabs + break; + case N_BINCL: + case N_EINCL: + case N_EXCL: + stab.string = symString; + // -gfull built .o file + break; + default: + warning("unknown stabs type 0x%X in %s", type, path); + } + break; + case inBeginEnd: + stab.atom = currentAtom; + switch (type) { + case N_ENSYM: + state = start; + currentAtom = NULL; + break; + case N_LCSYM: + case N_STSYM: + { + BaseAtom* nestedAtom = (BaseAtom*)this->findAtomAndOffset(sym->n_value()).atom; + if ( nestedAtom != NULL ) { + stab.atom = nestedAtom; + stab.string = symString; + } + else { + warning("can't find atom for stabs 0x%X at %08llX in %s", + type, (uint64_t)sym->n_value(), path); + } + break; + } + case N_LBRAC: + case N_RBRAC: + case N_SLINE: + // adjust value to be offset in atom + stab.value -= currentAtomAddress; + default: + stab.string = symString; + break; + } + break; + case inFun: + switch (type) { + case N_FUN: + if ( sym->n_sect() != 0 ) { + // found another start stab, must be really old stabs... + currentAtomAddress = sym->n_value(); + currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom; + if ( currentAtom != NULL ) { + stab.atom = currentAtom; + stab.string = symString; + } + else { + warning("can't find atom for stabs FUN at %08llX in %s", + (uint64_t)currentAtomAddress, path); + } + } + else { + // found ending stab, switch back to start state + stab.string = symString; + stab.atom = currentAtom; + state = start; + currentAtom = NULL; + } + break; + case N_LBRAC: + case N_RBRAC: + case N_SLINE: + // adjust value to be offset in atom + stab.value -= currentAtomAddress; + stab.atom = currentAtom; + break; + case N_SO: + stab.string = symString; + state = start; + break; + default: + stab.atom = currentAtom; + stab.string = symString; + break; + } + break; + } + // add to list of stabs for this .o file + if ( useStab ) + fStabs.push_back(stab); + } + } + } + +#if 0 + // special case precompiled header .o file (which has no content) to have one empty atom + if ( fAtoms.size() == 0 ) { + int pathLen = strlen(path); + if ( (pathLen > 6) && (strcmp(&path[pathLen-6], ".gch.o")==0) ) { + ObjectFile::Atom* phony = new AnonymousAtom(*this, (uint32_t)0); + //phony->fSynthesizedName = ".gch.o"; + fAtoms.push_back(phony); + } + } +#endif + + // sort all atoms by address + std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter()); + + // set ordinal and sort references in each atom + uint32_t index = fOrdinalBase; + for (std::vector::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) { + BaseAtom* atom = (BaseAtom*)(*it); + atom->setOrdinal(index++); + atom->sortReferences(); + } + +} + + +template <> +void Reader::setCpuConstraint(uint32_t cpusubtype) +{ + switch (cpusubtype) { + case CPU_SUBTYPE_POWERPC_ALL: + case CPU_SUBTYPE_POWERPC_750: + case CPU_SUBTYPE_POWERPC_7400: + case CPU_SUBTYPE_POWERPC_7450: + case CPU_SUBTYPE_POWERPC_970: + fCpuConstraint = cpusubtype; + break; + default: + warning("unknown ppc subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath); + fCpuConstraint = CPU_SUBTYPE_POWERPC_ALL; + break; + } +} + +template <> +void Reader::setCpuConstraint(uint32_t cpusubtype) +{ + switch (cpusubtype) { + case CPU_SUBTYPE_ARM_ALL: + case CPU_SUBTYPE_ARM_V4T: + case CPU_SUBTYPE_ARM_V5TEJ: + case CPU_SUBTYPE_ARM_V6: + case CPU_SUBTYPE_ARM_XSCALE: + case CPU_SUBTYPE_ARM_V7: + fCpuConstraint = cpusubtype; + break; + default: + warning("unknown arm subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath); + fCpuConstraint = CPU_SUBTYPE_ARM_ALL; + break; + } +} + +template +void Reader::setCpuConstraint(uint32_t cpusubtype) +{ + // no cpu sub types for this architecture +} + +template <> +uint32_t Reader::updateCpuConstraint(uint32_t previous) +{ + switch ( previous ) { + case CPU_SUBTYPE_POWERPC_ALL: + return fCpuConstraint; + break; + case CPU_SUBTYPE_POWERPC_750: + if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_7400 || + fCpuConstraint == CPU_SUBTYPE_POWERPC_7450 || + fCpuConstraint == CPU_SUBTYPE_POWERPC_970 ) + return fCpuConstraint; + break; + case CPU_SUBTYPE_POWERPC_7400: + case CPU_SUBTYPE_POWERPC_7450: + if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_970 ) + return fCpuConstraint; + break; + case CPU_SUBTYPE_POWERPC_970: + // G5 can run everything + break; + default: + throw "Unhandled PPC cpu subtype!"; + break; + } + return previous; +} + + + +template <> +uint32_t Reader::updateCpuConstraint(uint32_t previous) +{ + switch (previous) { + case CPU_SUBTYPE_ARM_ALL: + return fCpuConstraint; + break; + case CPU_SUBTYPE_ARM_V5TEJ: + // v6, v7, and xscale are more constrained than previous file (v5), so use it + if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V6) + || (fCpuConstraint == CPU_SUBTYPE_ARM_V7) + || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) ) + return fCpuConstraint; + break; + case CPU_SUBTYPE_ARM_V4T: + // v5, v6, v7, and xscale are more constrained than previous file (v4t), so use it + if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V7) + || (fCpuConstraint == CPU_SUBTYPE_ARM_V6) + || (fCpuConstraint == CPU_SUBTYPE_ARM_V5TEJ) + || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) ) + return fCpuConstraint; + break; + case CPU_SUBTYPE_ARM_V6: + // v6 can run everything except xscale and v7 + if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE ) + throw "can't mix xscale and v6 code"; + if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 ) + return fCpuConstraint; + break; + case CPU_SUBTYPE_ARM_XSCALE: + // xscale can run everything except v6 and v7 + if ( fCpuConstraint == CPU_SUBTYPE_ARM_V6 ) + throw "can't mix xscale and v6 code"; + if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 ) + throw "can't mix xscale and v7 code"; + break; + case CPU_SUBTYPE_ARM_V7: + // v7 can run everything except xscale + if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE ) + throw "can't mix xscale and v7 code"; + break; + default: + throw "Unhandled ARM cpu subtype!"; + } + return previous; +} + +template +uint32_t Reader::updateCpuConstraint(uint32_t current) +{ + // no cpu sub types for this architecture + return current; +} + +template +void Reader::addDtraceExtraInfos(uint32_t probeAddr, const char* providerName) +{ + // for every ___dtrace_stability$* and ___dtrace_typedefs$* undefine with + // a matching provider name, add a by-name kDtraceTypeReference at probe site + const char* dollar = strchr(providerName, '$'); + if ( dollar != NULL ) { + int providerNameLen = dollar-providerName+1; + for ( std::vector::iterator it = fDtraceProviderInfo.begin(); it != fDtraceProviderInfo.end(); ++it) { + const char* typeDollar = strchr(*it, '$'); + if ( typeDollar != NULL ) { + if ( strncmp(typeDollar+1, providerName, providerNameLen) == 0 ) { + makeByNameReference(A::kDtraceTypeReference, probeAddr, *it, 0); + } + } + } + } +} + + +template <> +void Reader::validSectionType(uint8_t type) +{ + switch ( type ) { + case S_SYMBOL_STUBS: + throw "symbol_stub sections not valid in x86_64 object files"; + case S_LAZY_SYMBOL_POINTERS: + throw "lazy pointer sections not valid in x86_64 object files"; + case S_NON_LAZY_SYMBOL_POINTERS: + throw "non lazy pointer sections not valid in x86_64 object files"; + } +} + +template +void Reader::validSectionType(uint8_t type) +{ +} + +template +bool Reader::getTranslationUnitSource(const char** dir, const char** name) const +{ + if ( fDebugInfo == kDebugInfoDwarf ) { + *dir = fDwarfTranslationUnitDir; + *name = fDwarfTranslationUnitFile; + return (fDwarfTranslationUnitFile != NULL); + } + return false; +} + +template +BaseAtom* Reader::findAtomByName(const char* name) +{ + // first search the more important atoms + for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) { + const char* atomName = it->second->getName(); + if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) { + return it->second; + } + } + // try all atoms, because this might have been a tentative definition + for (std::vector::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) { + BaseAtom* atom = (BaseAtom*)(*it); + const char* atomName = atom->getName(); + if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) { + return atom; + } + } + return NULL; +} + +template +Reference* Reader::makeReference(Kinds kind, pint_t atAddr, pint_t toAddr) +{ + return new Reference(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toAddr)); +} + +template +Reference* Reader::makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr) +{ + return new Reference(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toAddr)); +} + +template +Reference* Reader::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr) +{ + return new Reference(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toBaseAddr, toAddr)); +} + +template +Reference* Reader::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr) +{ + return new Reference(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toBaseAddr, toAddr)); +} + +template +Reference* Reader::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset) +{ + return new Reference(kind, findAtomAndOffset(atAddr), toName, toOffset); +} + +template +Reference* Reader::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section

* ehSect) +{ + // add a direct reference from function atom to its eh frame atom + const uint8_t* ehContent = (const uint8_t*)(fHeader) + ehAtomAddress - ehSect->addr() + ehSect->offset(); + int32_t deltaMinus8 = P::getP(*(pint_t*)(&ehContent[8])); // offset 8 in eh info is delta to function + pint_t funcAddr = ehAtomAddress + deltaMinus8 + 8; + return makeReference(A::kGroupSubordinate, funcAddr, ehAtomAddress); +} + + +template <> +Reference* Reader::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset) +{ + // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references + // instead check scope of target + BaseAtom* target = findAtomByName(toName); + if ( (target != NULL) && (target->getScope() == ObjectFile::Atom::scopeTranslationUnit) ) + return new Reference(kind, findAtomAndOffset(atAddr), AtomAndOffset(target, toOffset)); + else + return new Reference(kind, findAtomAndOffset(atAddr), toName, toOffset); +} + +template <> +Reference* Reader::makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist

* toSymbol, pint_t toOffset) +{ + // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references + // instead check scope of target + const char* symbolName = &fStrings[toSymbol->n_strx()]; + if ( ((toSymbol->n_type() & N_TYPE) == N_SECT) && (((toSymbol->n_type() & N_EXT) == 0) || (symbolName[0] == 'L')) ) + return new Reference(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toSymbol->n_value(), toSymbol->n_value()+toOffset)); + else + return new Reference(kind, findAtomAndOffset(atAddr), symbolName, toOffset); +} + + +template <> +Reference* Reader::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section

* ehSect) +{ + // add a direct reference from function atom to its eh frame atom + // for x86_64 the __eh_frame section contains the addends, so need to use relocs to find target + uint32_t ehAtomDeltaSectionOffset = ehAtomAddress + 8 - ehSect->addr(); // offset 8 in eh info is delta to function + const macho_relocation_info

* relocs = (macho_relocation_info

*)((char*)(fHeader) + ehSect->reloff()); + const macho_relocation_info

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

* reloc = relocs; reloc < relocsEnd; ++reloc) { + if ( (reloc->r_address() == ehAtomDeltaSectionOffset) && (reloc->r_type() == X86_64_RELOC_UNSIGNED) ) { + pint_t funcAddr = fSymbols[reloc->r_symbolnum()].n_value(); + return makeReference(x86_64::kGroupSubordinate, funcAddr, ehAtomAddress); + } + } + warning("can't find matching function for eh symbol %s", ehName); + return NULL; +} + + +template +AtomAndOffset Reader::findAtomAndOffset(pint_t addr) +{ + // STL has no built-in for "find largest key that is same or less than" + typename AddrToAtomMap::iterator it = fAddrToAtom.upper_bound(addr); + // if no atoms up to this address return none found + if ( it == fAddrToAtom.begin() ) + return AtomAndOffset(NULL); + // otherwise upper_bound gets us next key, so we back up one + --it; + AtomAndOffset result; + result.atom = it->second; + result.offset = addr - it->first; + //fprintf(stderr, "findAtomAndOffset(0x%0llX) ==> %s (0x%0llX -> 0x%0llX)\n", + // (uint64_t)addr, result.atom->getDisplayName(), (uint64_t)it->first, it->first+result.atom->getSize()); + return result; +} + +// "scattered" relocations enable you to offset into an atom past the end of it +// baseAddr is the address of the target atom, +// realAddr is the points into it +template +AtomAndOffset Reader::findAtomAndOffset(pint_t baseAddr, pint_t realAddr) +{ + typename AddrToAtomMap::iterator it = fAddrToAtom.find(baseAddr); + if ( it != fAddrToAtom.end() ) { + AtomAndOffset result; + result.atom = it->second; + result.offset = realAddr - it->first; + //fprintf(stderr, "findAtomAndOffset(0x%08X, 0x%08X) => %s + 0x%08X\n", baseAddr, realAddr, result.atom->getDisplayName(), result.offset); + return result; + } + // getting here means we have a scattered relocation to an address without a label + // we should never get here... + // one case we do get here is because sometimes the compiler generates non-lazy pointers in the __data section + return findAtomAndOffset(realAddr); +} + + +/* Skip over a LEB128 value (signed or unsigned). */ +static void +skip_leb128 (const uint8_t ** offset, const uint8_t * end) +{ + while (*offset != end && **offset >= 0x80) + (*offset)++; + if (*offset != end) + (*offset)++; +} + +/* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow + or error. On overflow, skip past the rest of the uleb128. */ +static uint64_t +read_uleb128 (const uint8_t ** offset, const uint8_t * end) +{ + uint64_t result = 0; + int bit = 0; + + do { + uint64_t b; + + if (*offset == end) + return (uint64_t) -1; + + b = **offset & 0x7f; + + if (bit >= 64 || b << bit >> bit != b) + result = (uint64_t) -1; + else + result |= b << bit, bit += 7; + } while (*(*offset)++ >= 0x80); + return result; +} + + +/* Skip over a DWARF attribute of form FORM. */ +template +bool Reader::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form, + uint8_t addr_size, bool dwarf64) +{ + int64_t sz=0; + + switch (form) + { + case DW_FORM_addr: + sz = addr_size; + break; + + case DW_FORM_block2: + if (end - *offset < 2) + return false; + sz = 2 + A::P::E::get16(*(uint16_t*)offset); + break; + + case DW_FORM_block4: + if (end - *offset < 4) + return false; + sz = 2 + A::P::E::get32(*(uint32_t*)offset); + break; + + case DW_FORM_data2: + case DW_FORM_ref2: + sz = 2; + break; + + case DW_FORM_data4: + case DW_FORM_ref4: + sz = 4; + break; + + case DW_FORM_data8: + case DW_FORM_ref8: + sz = 8; + break; + + case DW_FORM_string: + while (*offset != end && **offset) + ++*offset; + case DW_FORM_data1: + case DW_FORM_flag: + case DW_FORM_ref1: + sz = 1; + break; + + case DW_FORM_block: + sz = read_uleb128 (offset, end); + break; + + case DW_FORM_block1: + if (*offset == end) + return false; + sz = 1 + **offset; + break; + + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_ref_udata: + skip_leb128 (offset, end); + return true; + + case DW_FORM_strp: + case DW_FORM_ref_addr: + sz = dwarf64 ? 8 : 4; + break; + + default: + return false; + } + if (end - *offset < sz) + return false; + *offset += sz; + return true; +} + +// Look at the compilation unit DIE and determine +// its NAME, compilation directory (in COMP_DIR) and its +// line number information offset (in STMT_LIST). NAME and COMP_DIR +// may be NULL (especially COMP_DIR) if they are not in the .o file; +// STMT_LIST will be (uint64_t) -1. +// +// At present this assumes that there's only one compilation unit DIE. +// +template +bool Reader::read_comp_unit(const char ** name, const char ** comp_dir, + uint64_t *stmt_list) +{ + const uint8_t * debug_info; + const uint8_t * debug_abbrev; + const uint8_t * di; + const uint8_t * da; + const uint8_t * end; + const uint8_t * enda; + uint64_t sz; + uint16_t vers; + uint64_t abbrev_base; + uint64_t abbrev; + uint8_t address_size; + bool dwarf64; + + *name = NULL; + *comp_dir = NULL; + *stmt_list = (uint64_t) -1; + + if ( (fDwarfDebugInfoSect == NULL) || (fDwarfDebugAbbrevSect == NULL) ) + return false; + + debug_info = (uint8_t*)(fHeader) + fDwarfDebugInfoSect->offset(); + debug_abbrev = (uint8_t*)(fHeader) + fDwarfDebugAbbrevSect->offset(); + di = debug_info; + + if (fDwarfDebugInfoSect->size() < 12) + /* Too small to be a real debug_info section. */ + return false; + sz = A::P::E::get32(*(uint32_t*)di); + di += 4; + dwarf64 = sz == 0xffffffff; + if (dwarf64) + sz = A::P::E::get64(*(uint64_t*)di), di += 8; + else if (sz > 0xffffff00) + /* Unknown dwarf format. */ + return false; + + /* Verify claimed size. */ + if (sz + (di - debug_info) > fDwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11)) + return false; + + vers = A::P::E::get16(*(uint16_t*)di); + if (vers < 2 || vers > 3) + /* DWARF version wrong for this code. + Chances are we could continue anyway, but we don't know for sure. */ + return false; + di += 2; + + /* Find the debug_abbrev section. */ + abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di); + di += dwarf64 ? 8 : 4; + + if (abbrev_base > fDwarfDebugAbbrevSect->size()) + return false; + da = debug_abbrev + abbrev_base; + enda = debug_abbrev + fDwarfDebugAbbrevSect->size(); + + address_size = *di++; + + /* Find the abbrev number we're looking for. */ + end = di + sz; + abbrev = read_uleb128 (&di, end); + if (abbrev == (uint64_t) -1) + return false; + + /* Skip through the debug_abbrev section looking for that abbrev. */ + for (;;) + { + uint64_t this_abbrev = read_uleb128 (&da, enda); + uint64_t attr; + + if (this_abbrev == abbrev) + /* This is almost always taken. */ + break; + skip_leb128 (&da, enda); /* Skip the tag. */ + if (da == enda) + return false; + da++; /* Skip the DW_CHILDREN_* value. */ + + do { + attr = read_uleb128 (&da, enda); + skip_leb128 (&da, enda); + } while (attr != 0 && attr != (uint64_t) -1); + if (attr != 0) + return false; + } + + /* Check that the abbrev is one for a DW_TAG_compile_unit. */ + if (read_uleb128 (&da, enda) != DW_TAG_compile_unit) + return false; + if (da == enda) + return false; + da++; /* Skip the DW_CHILDREN_* value. */ + + /* Now, go through the DIE looking for DW_AT_name, + DW_AT_comp_dir, and DW_AT_stmt_list. */ + for (;;) + { + uint64_t attr = read_uleb128 (&da, enda); + uint64_t form = read_uleb128 (&da, enda); + + if (attr == (uint64_t) -1) + return false; + else if (attr == 0) + return true; + + if (form == DW_FORM_indirect) + form = read_uleb128 (&di, end); + + if (attr == DW_AT_name && form == DW_FORM_string) + *name = (const char *) di; + else if (attr == DW_AT_comp_dir && form == DW_FORM_string) + *comp_dir = (const char *) di; + /* Really we should support DW_FORM_strp here, too, but + there's usually no reason for the producer to use that form + for the DW_AT_name and DW_AT_comp_dir attributes. */ + else if (attr == DW_AT_stmt_list && form == DW_FORM_data4) + *stmt_list = A::P::E::get32(*(uint32_t*)di); + else if (attr == DW_AT_stmt_list && form == DW_FORM_data8) + *stmt_list = A::P::E::get64(*(uint64_t*)di); + if (! skip_form (&di, end, form, address_size, dwarf64)) + return false; + } +} + +template +const char* Reader::assureFullPath(const char* path) +{ + if ( path[0] == '/' ) + return path; + char cwdbuff[MAXPATHLEN]; + if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) { + char* result; + asprintf(&result, "%s/%s", cwdbuff, path); + if ( result != NULL ) + return result; + } + return path; +} + + +// +// +// To implement architecture xxx, you must write template specializations for the following six methods: +// Reader::validFile() +// Reader::addRelocReference() +// Reference::getDescription() +// +// + + +template <> +bool Reader::validFile(const uint8_t* fileContent) +{ + const macho_header

* header = (const macho_header

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

* header = (const macho_header

*)fileContent; + if ( header->magic() != MH_MAGIC_64 ) + return false; + if ( header->cputype() != CPU_TYPE_POWERPC64 ) + return false; + if ( header->filetype() != MH_OBJECT ) + return false; + return true; +} + +template <> +bool Reader::validFile(const uint8_t* fileContent) +{ + const macho_header

* header = (const macho_header

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

* header = (const macho_header

*)fileContent; + if ( header->magic() != MH_MAGIC_64 ) + return false; + if ( header->cputype() != CPU_TYPE_X86_64 ) + return false; + if ( header->filetype() != MH_OBJECT ) + return false; + return true; +} + +template <> +bool Reader::validFile(const uint8_t* fileContent) +{ + const macho_header

* header = (const macho_header

*)fileContent; + if ( header->magic() != MH_MAGIC ) + return false; + if ( header->cputype() != CPU_TYPE_ARM ) + return false; + if ( header->filetype() != MH_OBJECT ) + return false; + return true; +} + +template +bool Reader::isWeakImportSymbol(const macho_nlist

* sym) +{ + return ( ((sym->n_type() & N_TYPE) == N_UNDF) && ((sym->n_desc() & N_WEAK_REF) != 0) ); +} + +template <> +bool Reader::addRelocReference(const macho_section* sect, const macho_relocation_info* reloc) +{ + return addRelocReference_powerpc(sect, reloc); +} + +template <> +bool Reader::addRelocReference(const macho_section* sect, const macho_relocation_info* reloc) +{ + return addRelocReference_powerpc(sect, reloc); +} + + +// +// ppc and ppc64 both use the same relocations, so process them in one common routine +// +template +bool Reader::addRelocReference_powerpc(const macho_section* sect, + const macho_relocation_info* reloc) +{ + uint32_t srcAddr; + uint32_t dstAddr; + uint32_t* fixUpPtr; + int32_t displacement = 0; + uint32_t instruction = 0; + uint32_t offsetInTarget; + int16_t lowBits; + bool result = false; + if ( (reloc->r_address() & R_SCATTERED) == 0 ) { + const macho_relocation_info

* nextReloc = &reloc[1]; + const char* targetName = NULL; + bool weakImport = false; + fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address()); + if ( reloc->r_type() != PPC_RELOC_PAIR ) + instruction = BigEndian::get32(*fixUpPtr); + srcAddr = sect->addr() + reloc->r_address(); + if ( reloc->r_extern() ) { + const macho_nlist

* targetSymbol = &fSymbols[reloc->r_symbolnum()]; + targetName = &fStrings[targetSymbol->n_strx()]; + weakImport = this->isWeakImportSymbol(targetSymbol); + } + switch ( reloc->r_type() ) { + case PPC_RELOC_BR24: + { + if ( (instruction & 0x4C000000) == 0x48000000 ) { + displacement = (instruction & 0x03FFFFFC); + if ( (displacement & 0x02000000) != 0 ) + displacement |= 0xFC000000; + } + else { + printf("bad instruction for BR24 reloc"); + } + if ( reloc->r_extern() ) { + offsetInTarget = srcAddr + displacement; + if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) { + makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[16]); + } + else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) { + makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[20]); + } + else if ( weakImport ) + makeByNameReference(A::kBranch24WeakImport, srcAddr, targetName, offsetInTarget); + else + makeByNameReference(A::kBranch24, srcAddr, targetName, offsetInTarget); + } + else { + dstAddr = srcAddr + displacement; + // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol + ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom; + targetName = atom->getName(); + if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) { + makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[16]); + } + else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) { + makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[20]); + } + else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn) + && ((AnonymousAtom*)atom)->isWeakImportStub() ) + makeReference(A::kBranch24WeakImport, srcAddr, dstAddr); + else + makeReference(A::kBranch24, srcAddr, dstAddr); + } + } + break; + case PPC_RELOC_BR14: + { + displacement = (instruction & 0x0000FFFC); + if ( (displacement & 0x00008000) != 0 ) + displacement |= 0xFFFF0000; + if ( reloc->r_extern() ) { + offsetInTarget = srcAddr + displacement; + makeByNameReference(A::kBranch14, srcAddr, targetName, offsetInTarget); + } + else { + dstAddr = srcAddr + displacement; + makeReference(A::kBranch14, srcAddr, dstAddr); + } + } + break; + case PPC_RELOC_PAIR: + // skip, processed by a previous look ahead + break; + case PPC_RELOC_LO16: + { + if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { + warning("PPC_RELOC_LO16 missing following pair"); + break; + } + result = true; + lowBits = (instruction & 0xFFFF); + if ( reloc->r_extern() ) { + offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF); + makeByNameReference(A::kAbsLow16, srcAddr, targetName, offsetInTarget); + } + else { + dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF); + if ( reloc->r_symbolnum() == R_ABS ) { + // find absolute symbol that corresponds to pointerValue + typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr); + if ( pos != fAddrToAbsoluteAtom.end() ) + makeByNameReference(A::kAbsLow16, srcAddr, pos->second->getName(), 0); + else + makeReference(A::kAbsLow16, srcAddr, dstAddr); + } + else { + makeReference(A::kAbsLow16, srcAddr, dstAddr); + } + } + } + break; + case PPC_RELOC_LO14: + { + if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { + warning("PPC_RELOC_LO14 missing following pair"); + break; + } + result = true; + lowBits = (instruction & 0xFFFC); + if ( reloc->r_extern() ) { + offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF); + makeByNameReference(A::kAbsLow14, srcAddr, targetName, offsetInTarget); + } + else { + dstAddr = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF); + if ( reloc->r_symbolnum() == R_ABS ) { + // find absolute symbol that corresponds to pointerValue + typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr); + if ( pos != fAddrToAbsoluteAtom.end() ) + makeByNameReference(A::kAbsLow14, srcAddr, pos->second->getName(), 0); + else + makeReference(A::kAbsLow14, srcAddr, dstAddr); + } + else { + makeReference(A::kAbsLow14, srcAddr, dstAddr); + } + } + } + break; + case PPC_RELOC_HI16: + { + if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { + warning("PPC_RELOC_HI16 missing following pair"); + break; + } + result = true; + if ( reloc->r_extern() ) { + offsetInTarget = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF); + makeByNameReference(A::kAbsHigh16, srcAddr, targetName, offsetInTarget); + } + else { + dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF); + if ( reloc->r_symbolnum() == R_ABS ) { + // find absolute symbol that corresponds to pointerValue + typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr); + if ( pos != fAddrToAbsoluteAtom.end() ) + makeByNameReference(A::kAbsHigh16, srcAddr, pos->second->getName(), 0); + else + makeReference(A::kAbsHigh16, srcAddr, dstAddr); + } + else { + makeReference(A::kAbsHigh16, srcAddr, dstAddr); + } + } + } + break; + case PPC_RELOC_HA16: + { + if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { + warning("PPC_RELOC_HA16 missing following pair"); + break; + } + result = true; + lowBits = (nextReloc->r_address() & 0x0000FFFF); + if ( reloc->r_extern() ) { + offsetInTarget = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits; + makeByNameReference(A::kAbsHigh16AddLow, srcAddr, targetName, offsetInTarget); + } + else { + dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits; + if ( reloc->r_symbolnum() == R_ABS ) { + // find absolute symbol that corresponds to pointerValue + typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr); + if ( pos != fAddrToAbsoluteAtom.end() ) + makeByNameReference(A::kAbsHigh16AddLow, srcAddr, pos->second->getName(), 0); + else + makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr); + } + else { + makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr); + } + } + } + break; + case PPC_RELOC_VANILLA: + { + pint_t pointerValue = P::getP(*((pint_t*)fixUpPtr)); + if ( reloc->r_extern() ) { + if ( weakImport ) + makeByNameReference(A::kPointerWeakImport, srcAddr, targetName, pointerValue); + else + makeByNameReference(A::kPointer, srcAddr, targetName, pointerValue); + } + else { + makeReference(A::kPointer, srcAddr, pointerValue); + } + } + break; + case PPC_RELOC_JBSR: + // this is from -mlong-branch codegen. We ignore the jump island and make reference to the real target + if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { + warning("PPC_RELOC_JBSR missing following pair"); + break; + } + fHasLongBranchStubs = true; + result = true; + makeReference(A::kBranch24, srcAddr, nextReloc->r_address()); + if ( (instruction & 0x4C000000) == 0x48000000 ) { + displacement = (instruction & 0x03FFFFFC); + if ( (displacement & 0x02000000) != 0 ) + displacement |= 0xFC000000; + } + else { + fprintf(stderr, "bad instruction for BR24 reloc"); + } + if ( reloc->r_extern() ) { + fprintf(stderr, "PPC_RELOC_JBSR should not be using an external relocation"); + } + break; + default: + warning("unknown relocation type %d", reloc->r_type()); + } + } + else { + const macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; + srcAddr = sect->addr() + sreloc->r_address(); + dstAddr = sreloc->r_value(); + uint32_t betterDstAddr; + fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address()); + const macho_scattered_relocation_info

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

* nextReloc = &reloc[1]; + // file format allows pair to be scattered or not + bool nextRelocIsPair = false; + uint32_t nextRelocAddress = 0; + uint32_t nextRelocValue = 0; + if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) { + if ( nextReloc->r_type() == PPC_RELOC_PAIR ) { + nextRelocIsPair = true; + nextRelocAddress = nextReloc->r_address(); + result = true; + } + } + else { + if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) { + nextRelocIsPair = true; + nextRelocAddress = nextSReloc->r_address(); + nextRelocValue = nextSReloc->r_value(); + result = true; + } + } + switch (sreloc->r_type()) { + case PPC_RELOC_VANILLA: + { + betterDstAddr = P::getP(*(pint_t*)fixUpPtr); + //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr); + // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr) + makeReferenceWithToBase(A::kPointer, srcAddr, betterDstAddr, dstAddr); + } + break; + case PPC_RELOC_BR14: + { + instruction = BigEndian::get32(*fixUpPtr); + displacement = (instruction & 0x0000FFFC); + if ( (displacement & 0x00008000) != 0 ) + displacement |= 0xFFFF0000; + betterDstAddr = srcAddr+displacement; + //fprintf(stderr, "betterDstAddr=0x%08X, srcAddr=0x%08X, displacement=0x%08X\n", betterDstAddr, srcAddr, displacement); + makeReferenceWithToBase(A::kBranch14, srcAddr, betterDstAddr, dstAddr); + } + break; + case PPC_RELOC_BR24: + { + instruction = BigEndian::get32(*fixUpPtr); + if ( (instruction & 0x4C000000) == 0x48000000 ) { + displacement = (instruction & 0x03FFFFFC); + if ( (displacement & 0x02000000) != 0 ) + displacement |= 0xFC000000; + betterDstAddr = srcAddr+displacement; + makeReferenceWithToBase(A::kBranch24, srcAddr, betterDstAddr, dstAddr); + } + } + break; + case PPC_RELOC_LO16_SECTDIFF: + { + if ( ! nextRelocIsPair ) { + warning("PPC_RELOC_LO16_SECTDIFF missing following PAIR"); + break; + } + instruction = BigEndian::get32(*fixUpPtr); + lowBits = (instruction & 0xFFFF); + displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF); + makeReferenceWithToBase(A::kPICBaseLow16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr); + } + break; + case PPC_RELOC_LO14_SECTDIFF: + { + if ( ! nextRelocIsPair ) { + warning("PPC_RELOC_LO14_SECTDIFF missing following PAIR"); + break; + } + instruction = BigEndian::get32(*fixUpPtr); + lowBits = (instruction & 0xFFFC); + displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF); + makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr); + } + break; + case PPC_RELOC_HA16_SECTDIFF: + { + if ( ! nextRelocIsPair ) { + warning("PPC_RELOC_HA16_SECTDIFF missing following PAIR"); + break; + } + instruction = BigEndian::get32(*fixUpPtr); + lowBits = (nextRelocAddress & 0x0000FFFF); + displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits; + makeReferenceWithToBase(A::kPICBaseHigh16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr); + } + break; + case PPC_RELOC_LO14: + { + if ( ! nextRelocIsPair ) { + warning("PPC_RELOC_LO14 missing following PAIR"); + break; + } + instruction = BigEndian::get32(*fixUpPtr); + lowBits = (instruction & 0xFFFC); + betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF); + makeReferenceWithToBase(A::kAbsLow14, srcAddr, betterDstAddr, dstAddr); + } + break; + case PPC_RELOC_LO16: + { + if ( ! nextRelocIsPair ) { + warning("PPC_RELOC_LO16 missing following PAIR"); + break; + } + instruction = BigEndian::get32(*fixUpPtr); + lowBits = (instruction & 0xFFFF); + betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF); + makeReferenceWithToBase(A::kAbsLow16, srcAddr, betterDstAddr, dstAddr); + } + break; + case PPC_RELOC_HA16: + { + if ( ! nextRelocIsPair ) { + warning("PPC_RELOC_HA16 missing following PAIR"); + break; + } + instruction = BigEndian::get32(*fixUpPtr); + lowBits = (nextRelocAddress & 0xFFFF); + betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits; + makeReferenceWithToBase(A::kAbsHigh16AddLow, srcAddr, betterDstAddr, dstAddr); + } + break; + case PPC_RELOC_HI16: + { + if ( ! nextRelocIsPair ) { + warning("PPC_RELOC_HI16 missing following PAIR"); + break; + } + instruction = BigEndian::get32(*fixUpPtr); + lowBits = (nextRelocAddress & 0xFFFF); + betterDstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF); + makeReferenceWithToBase(A::kAbsHigh16, srcAddr, betterDstAddr, dstAddr); + } + break; + case PPC_RELOC_SECTDIFF: + case PPC_RELOC_LOCAL_SECTDIFF: + { + if ( ! nextRelocIsPair ) { + warning("PPC_RELOC_SECTDIFF missing following pair"); + break; + } + Kinds kind = A::kPointerDiff32;; + uint32_t contentAddr = 0; + switch ( sreloc->r_length() ) { + case 0: + throw "bad diff relocations r_length (0) for ppc architecture"; + case 1: + kind = A::kPointerDiff16; + contentAddr = BigEndian::get16(*((uint16_t*)fixUpPtr)); + break; + case 2: + kind = A::kPointerDiff32; + contentAddr = BigEndian::get32(*fixUpPtr); + break; + case 3: + kind = A::kPointerDiff64; + contentAddr = BigEndian::get64(*((uint64_t*)fixUpPtr)); + break; + } + AtomAndOffset srcao = findAtomAndOffset(srcAddr); + AtomAndOffset fromao = findAtomAndOffset(nextRelocValue); + AtomAndOffset toao = findAtomAndOffset(dstAddr); + // check for addend encoded in the section content + //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n", + // dstAddr, nextRelocValue, contentAddr); + if ( (dstAddr - nextRelocValue) != contentAddr ) { + if ( toao.atom == srcao.atom ) + toao.offset += (contentAddr + nextRelocValue) - dstAddr; + else if ( fromao.atom == srcao.atom ) + toao.offset += (contentAddr + nextRelocValue) - dstAddr; + else + fromao.offset += (dstAddr - contentAddr) - nextRelocValue; + } + //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n", + // srcao.atom->getDisplayName(), srcao.offset, + // fromao.atom->getDisplayName(), fromao.offset, + // toao.atom->getDisplayName(), toao.offset); + new Reference(kind, srcao, fromao, toao); + } + break; + case PPC_RELOC_PAIR: + break; + case PPC_RELOC_HI16_SECTDIFF: + warning("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF"); + break; + default: + warning("unknown scattered relocation type %d", sreloc->r_type()); + } + } + return result; +} + + +template <> +bool Reader::addRelocReference(const macho_section* sect, const macho_relocation_info* reloc) +{ + uint32_t srcAddr; + uint32_t dstAddr; + uint32_t* fixUpPtr; + bool result = false; + if ( (reloc->r_address() & R_SCATTERED) == 0 ) { + srcAddr = sect->addr() + reloc->r_address(); + fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address()); + switch ( reloc->r_type() ) { + case GENERIC_RELOC_VANILLA: + { + x86::ReferenceKinds kind = x86::kPointer; + uint32_t pointerValue = E::get32(*fixUpPtr); + if ( reloc->r_pcrel() ) { + switch( reloc->r_length() ) { + case 0: + kind = x86::kPCRel8; + pointerValue = srcAddr + *((int8_t*)fixUpPtr) + sizeof(int8_t); + break; + case 1: + kind = x86::kPCRel16; + pointerValue = srcAddr + (int16_t)E::get16(*((uint16_t*)fixUpPtr)) + sizeof(uint16_t); + break; + case 2: + kind = x86::kPCRel32; + pointerValue += srcAddr + sizeof(uint32_t); + break; + case 3: + throw "bad pc-rel vanilla relocation length"; + } + } + else if ( strcmp(sect->segname(), "__TEXT") == 0 ) { + kind = x86::kAbsolute32; + if ( reloc->r_length() != 2 ) + throw "bad vanilla relocation length"; + } + else { + kind = x86::kPointer; + if ( reloc->r_length() != 2 ) + throw "bad vanilla relocation length"; + } + if ( reloc->r_extern() ) { + const macho_nlist

* targetSymbol = &fSymbols[reloc->r_symbolnum()]; + if ( this->isWeakImportSymbol(targetSymbol) ) { + if ( reloc->r_pcrel() ) + kind = x86::kPCRel32WeakImport; + else + kind = x86::kPointerWeakImport; + } + const char* targetName = &fStrings[targetSymbol->n_strx()]; + if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) { + makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[16]); + } + else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) { + makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[20]); + } + else + makeByNameReference(kind, srcAddr, targetName, pointerValue); + } + else { + // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol + ObjectFile::Atom* atom = findAtomAndOffset(pointerValue).atom; + const char* targetName = atom->getName(); + if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) { + makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[16]); + } + else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) { + makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[20]); + } + else if ( reloc->r_pcrel() && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn) + && ((AnonymousAtom*)atom)->isWeakImportStub() ) + makeReference(x86::kPCRel32WeakImport, srcAddr, pointerValue); + else if ( reloc->r_symbolnum() != R_ABS ) + makeReference(kind, srcAddr, pointerValue); + else { + // find absolute symbol that corresponds to pointerValue + AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(pointerValue); + if ( pos != fAddrToAbsoluteAtom.end() ) + makeByNameReference(kind, srcAddr, pos->second->getName(), 0); + else + throwf("R_ABS reloc but no absolute symbol at target address"); + } + } + } + break; + default: + warning("unknown relocation type %d", reloc->r_type()); + } + } + else { + const macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; + srcAddr = sect->addr() + sreloc->r_address(); + dstAddr = sreloc->r_value(); + fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address()); + const macho_scattered_relocation_info

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

* nextReloc = &reloc[1]; + pint_t betterDstAddr; + // file format allows pair to be scattered or not + bool nextRelocIsPair = false; + uint32_t nextRelocAddress = 0; + uint32_t nextRelocValue = 0; + if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) { + if ( nextReloc->r_type() == GENERIC_RELOC_PAIR ) { + nextRelocIsPair = true; + nextRelocAddress = nextReloc->r_address(); + result = true; + } + } + else { + if ( nextSReloc->r_type() == GENERIC_RELOC_PAIR ) { + nextRelocIsPair = true; + nextRelocAddress = nextSReloc->r_address(); + nextRelocValue = nextSReloc->r_value(); + } + } + switch (sreloc->r_type()) { + case GENERIC_RELOC_VANILLA: + betterDstAddr = LittleEndian::get32(*fixUpPtr); + //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr); + // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr) + if ( sreloc->r_pcrel() ) { + betterDstAddr += srcAddr + 4; + makeReferenceWithToBase(x86::kPCRel32, srcAddr, betterDstAddr, dstAddr); + } + else { + if ( strcmp(sect->segname(), "__TEXT") == 0 ) + makeReferenceWithToBase(x86::kAbsolute32, srcAddr, betterDstAddr, dstAddr); + else + makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr); + } + break; + case GENERIC_RELOC_SECTDIFF: + case GENERIC_RELOC_LOCAL_SECTDIFF: + { + if ( !nextRelocIsPair ) { + warning("GENERIC_RELOC_SECTDIFF missing following pair"); + break; + } + x86::ReferenceKinds kind = x86::kPointerDiff; + uint32_t contentAddr = 0; + switch ( sreloc->r_length() ) { + case 0: + case 3: + throw "bad length for GENERIC_RELOC_SECTDIFF"; + case 1: + kind = x86::kPointerDiff16; + contentAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr)); + break; + case 2: + kind = x86::kPointerDiff; + contentAddr = LittleEndian::get32(*fixUpPtr); + break; + } + AtomAndOffset srcao = findAtomAndOffset(srcAddr); + AtomAndOffset fromao = findAtomAndOffset(nextRelocValue); + AtomAndOffset toao = findAtomAndOffset(dstAddr); + // check for addend encoded in the section content + //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n", + // dstAddr, nextRelocValue, contentAddr); + if ( (dstAddr - nextRelocValue) != contentAddr ) { + if ( toao.atom == srcao.atom ) + toao.offset += (contentAddr + nextRelocValue) - dstAddr; + else if ( fromao.atom == srcao.atom ) + toao.offset += (contentAddr + nextRelocValue) - dstAddr; + else + fromao.offset += (dstAddr - contentAddr) - nextRelocValue; + } + //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n", + // srcao.atom->getDisplayName(), srcao.offset, + // fromao.atom->getDisplayName(), fromao.offset, + // toao.atom->getDisplayName(), toao.offset); + new Reference(kind, srcao, fromao, toao); + } + break; + case GENERIC_RELOC_PAIR: + // do nothing, already used via a look ahead + break; + default: + warning("unknown scattered relocation type %d", sreloc->r_type()); + } + } + return result; +} + +template <> +bool Reader::addRelocReference(const macho_section* sect, const macho_relocation_info* reloc) +{ + uint64_t srcAddr; + uint64_t dstAddr = 0; + uint64_t addend; + uint32_t* fixUpPtr; + x86_64::ReferenceKinds kind = x86_64::kNoFixUp; + bool result = false; + const macho_nlist

* targetSymbol = NULL; + const char* targetName = NULL; + srcAddr = sect->addr() + reloc->r_address(); + fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address()); + //fprintf(stderr, "addReloc type=%d\n", reloc->r_type()); + if ( reloc->r_extern() ) { + targetSymbol = &fSymbols[reloc->r_symbolnum()]; + targetName = &fStrings[targetSymbol->n_strx()]; + } + switch ( reloc->r_type() ) { + case X86_64_RELOC_UNSIGNED: + if ( reloc->r_pcrel() ) + throw "pcrel and X86_64_RELOC_UNSIGNED not supported"; + if ( reloc->r_length() != 3 ) + throw "length < 3 and X86_64_RELOC_UNSIGNED not supported"; + dstAddr = E::get64(*((uint64_t*)fixUpPtr)); + if ( reloc->r_extern() ) { + makeReferenceToSymbol(x86_64::kPointer, srcAddr, targetSymbol, dstAddr); + } + else { + makeReference(x86_64::kPointer, srcAddr, dstAddr); + // verify that dstAddr is in the section being targeted + int sectNum = reloc->r_symbolnum(); + const macho_section

* const sectionsStart = (macho_section

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

)); + const macho_section

* const targetSection = §ionsStart[sectNum-1]; + if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) { + throwf("local relocation for address 0x%08llX in section %s does not target section %s", + srcAddr, sect->sectname(), targetSection->sectname()); + } + } + break; + case X86_64_RELOC_SIGNED: + case X86_64_RELOC_SIGNED_1: + case X86_64_RELOC_SIGNED_2: + case X86_64_RELOC_SIGNED_4: + if ( ! reloc->r_pcrel() ) + throw "not pcrel and X86_64_RELOC_SIGNED* not supported"; + if ( reloc->r_length() != 2 ) + throw "length != 2 and X86_64_RELOC_SIGNED* not supported"; + addend = (int64_t)((int32_t)(E::get32(*fixUpPtr))); + if ( reloc->r_extern() ) { + switch ( reloc->r_type() ) { + case X86_64_RELOC_SIGNED: + kind = x86_64::kPCRel32; + // begin support for old .o files before X86_64_RELOC_SIGNED_1 was created + if ( addend == (uint64_t)(-1) ) { + addend = 0; + kind = x86_64::kPCRel32_1; + } + else if ( addend == (uint64_t)(-2) ) { + addend = 0; + kind = x86_64::kPCRel32_2; + } + else if ( addend == (uint64_t)(-4) ) { + addend = 0; + kind = x86_64::kPCRel32_4; + } + break; + // end support for old .o files before X86_64_RELOC_SIGNED_1 was created + case X86_64_RELOC_SIGNED_1: + kind = x86_64::kPCRel32_1; + addend += 1; + break; + case X86_64_RELOC_SIGNED_2: + kind = x86_64::kPCRel32_2; + addend += 2; + break; + case X86_64_RELOC_SIGNED_4: + kind = x86_64::kPCRel32_4; + addend += 4; + break; + } + makeReferenceToSymbol(kind, srcAddr, targetSymbol, addend); + } + else { + uint64_t ripRelativeOffset = addend; + switch ( reloc->r_type() ) { + case X86_64_RELOC_SIGNED: + dstAddr = srcAddr + 4 + ripRelativeOffset; + kind = x86_64::kPCRel32; + break; + case X86_64_RELOC_SIGNED_1: + dstAddr = srcAddr + 5 + ripRelativeOffset; + kind = x86_64::kPCRel32_1; + break; + case X86_64_RELOC_SIGNED_2: + dstAddr = srcAddr + 6 + ripRelativeOffset; + kind = x86_64::kPCRel32_2; + break; + case X86_64_RELOC_SIGNED_4: + dstAddr = srcAddr + 8 + ripRelativeOffset; + kind = x86_64::kPCRel32_4; + break; + } + makeReference(kind, srcAddr, dstAddr); + // verify that dstAddr is in the section being targeted + int sectNum = reloc->r_symbolnum(); + const macho_section

* const sectionsStart = (macho_section

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

)); + const macho_section

* const targetSection = §ionsStart[sectNum-1]; + if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) { + throwf("local relocation for address 0x%08llX in section %s does not target section %s", + srcAddr, sect->sectname(), targetSection->sectname()); + } + } + break; + case X86_64_RELOC_BRANCH: + if ( ! reloc->r_pcrel() ) + throw "not pcrel and X86_64_RELOC_BRANCH not supported"; + if ( reloc->r_length() == 2 ) { + dstAddr = (int64_t)((int32_t)(E::get32(*fixUpPtr))); + if ( reloc->r_extern() ) { + if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) { + makeByNameReference(x86_64::kDtraceProbeSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[16]); + } + else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) { + makeByNameReference(x86_64::kDtraceIsEnabledSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[16]); + } + else if ( isWeakImportSymbol(targetSymbol) ) + makeReferenceToSymbol(x86_64::kBranchPCRel32WeakImport, srcAddr, targetSymbol, dstAddr); + else + makeReferenceToSymbol(x86_64::kBranchPCRel32, srcAddr, targetSymbol, dstAddr); + } + else { + makeReference(x86_64::kBranchPCRel32, srcAddr, srcAddr+4+dstAddr); + } + } + else if ( reloc->r_length() == 0 ) { + dstAddr = *((int8_t*)fixUpPtr); + if ( reloc->r_extern() ) { + makeReferenceToSymbol(x86_64::kBranchPCRel8, srcAddr, targetSymbol, dstAddr); + } + else { + makeReference(x86_64::kBranchPCRel8, srcAddr, srcAddr+1+dstAddr); + } + } + else { + throwf("length=%d and X86_64_RELOC_BRANCH not supported", reloc->r_length());; + } + break; + case X86_64_RELOC_GOT: + if ( ! reloc->r_extern() ) + throw "not extern and X86_64_RELOC_GOT not supported"; + if ( ! reloc->r_pcrel() ) + throw "not pcrel and X86_64_RELOC_GOT not supported"; + if ( reloc->r_length() != 2 ) + throw "length != 2 and X86_64_RELOC_GOT not supported"; + addend = (int64_t)((int32_t)(E::get32(*fixUpPtr))); + if ( isWeakImportSymbol(targetSymbol) ) + makeReferenceToSymbol(x86_64::kPCRel32GOTWeakImport, srcAddr, targetSymbol, addend); + else + makeReferenceToSymbol(x86_64::kPCRel32GOT, srcAddr, targetSymbol, addend); + break; + case X86_64_RELOC_GOT_LOAD: + if ( ! reloc->r_extern() ) + throw "not extern and X86_64_RELOC_GOT_LOAD not supported"; + if ( ! reloc->r_pcrel() ) + throw "not pcrel and X86_64_RELOC_GOT_LOAD not supported"; + if ( reloc->r_length() != 2 ) + throw "length != 2 and X86_64_RELOC_GOT_LOAD not supported"; + addend = (int64_t)((int32_t)(E::get32(*fixUpPtr))); + if ( isWeakImportSymbol(targetSymbol) ) + makeReferenceToSymbol(x86_64::kPCRel32GOTLoadWeakImport, srcAddr, targetSymbol, addend); + else + makeReferenceToSymbol(x86_64::kPCRel32GOTLoad, srcAddr, targetSymbol, addend); + break; + case X86_64_RELOC_SUBTRACTOR: + { + if ( reloc->r_pcrel() ) + throw "X86_64_RELOC_SUBTRACTOR cannot be pc-relative"; + if ( reloc->r_length() < 2 ) + throw "X86_64_RELOC_SUBTRACTOR must have r_length of 2 or 3"; + if ( !reloc->r_extern() ) + throw "X86_64_RELOC_SUBTRACTOR must have r_extern=1"; + const macho_relocation_info* nextReloc = &reloc[1]; + if ( nextReloc->r_type() != X86_64_RELOC_UNSIGNED ) + throw "X86_64_RELOC_SUBTRACTOR must be followed by X86_64_RELOC_UNSIGNED"; + result = true; + if ( nextReloc->r_pcrel() ) + throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR cannot be pc-relative"; + if ( nextReloc->r_length() != reloc->r_length() ) + throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR must have same r_length"; + Reference* ref; + bool negativeAddend; + if ( reloc->r_length() == 2 ) { + kind = x86_64::kPointerDiff32; + dstAddr = E::get32(*fixUpPtr); // addend is in content + negativeAddend = ((dstAddr & 0x80000000) != 0); + } + else { + kind = x86_64::kPointerDiff; + dstAddr = E::get64(*((uint64_t*)fixUpPtr)); // addend is in content + negativeAddend = ((dstAddr & 0x8000000000000000ULL) != 0); + } + ObjectFile::Atom* inAtom = this->findAtomAndOffset(srcAddr).atom; + // create reference with "to" target + if ( nextReloc->r_extern() ) { + const macho_nlist

* targetSymbol = &fSymbols[nextReloc->r_symbolnum()]; + const char* targetName = &fStrings[targetSymbol->n_strx()]; + ref = makeReferenceToSymbol(kind, srcAddr, targetSymbol, 0); + // if "to" is in this atom, change by-name to a direct reference + if ( strcmp(targetName, inAtom->getName()) == 0 ) + ref->setTarget(*inAtom, 0); + } + else { + ref = makeReference(kind, srcAddr, dstAddr); + } + // add in "from" target + if ( reloc->r_extern() ) { + const macho_nlist

* targetFromSymbol = &fSymbols[reloc->r_symbolnum()]; + const char* fromTargetName = &fStrings[targetFromSymbol->n_strx()]; + if ( (targetFromSymbol->n_type() & N_EXT) == 0 ) { + // from target is translation unit scoped, so use a direct reference + ref->setFromTarget(*(findAtomAndOffset(targetSymbol->n_value()).atom)); + } + else if ( strcmp(fromTargetName, inAtom->getName()) == 0 ) { + // if "from" is in this atom, change by-name to a direct reference + ref->setFromTarget(*inAtom); + } + else { + // some non-static other atom + ref->setFromTargetName(fromTargetName); + } + } + // addend goes in from side iff negative + if ( negativeAddend ) + ref->setFromTargetOffset(-dstAddr); + else + ref->setToTargetOffset(dstAddr); + break; + } + default: + warning("unknown relocation type %d", reloc->r_type()); + } + return result; +} + + +/// Reader::addRelocReference - +/// turns arm relocation entries into references. Returns true if the next +/// relocation should be skipped, false otherwise. +template <> +bool Reader::addRelocReference(const macho_section* sect, + const macho_relocation_info* reloc) +{ + uint32_t * fixUpPtr; + int32_t displacement; + uint32_t instruction = 0; + bool result = false; + uint32_t srcAddr; + uint32_t dstAddr; + uint32_t pointerValue; + + if ( (reloc->r_address() & R_SCATTERED) == 0 ) { + // non-scattered relocation + const char* targetName = NULL; + bool weakImport = false; + + srcAddr = sect->addr() + reloc->r_address(); + fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address()); + if ( reloc->r_type() != ARM_RELOC_PAIR ) + instruction = LittleEndian::get32(*fixUpPtr); + + if ( reloc->r_extern() ) { + const macho_nlist

* targetSymbol = &fSymbols[reloc->r_symbolnum()]; + targetName = &fStrings[targetSymbol->n_strx()]; + weakImport = this->isWeakImportSymbol(targetSymbol); + } + + switch ( reloc->r_type() ) { + case ARM_RELOC_BR24: + // Sign-extend displacement + displacement = (instruction & 0x00FFFFFF) << 2; + if ( (displacement & 0x02000000) != 0 ) + displacement |= 0xFC000000; + // The pc added will be +8 from the pc + displacement += 8; + // If this is BLX add H << 1 + if ((instruction & 0xFE000000) == 0xFA000000) + displacement += ((instruction & 0x01000000) >> 23); + + if ( reloc->r_extern() ) { + uint32_t offsetInTarget = srcAddr + displacement; + if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) { + makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[16]); + } + else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) { + makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[20]); + } + else if ( weakImport ) + makeByNameReference(arm::kBranch24WeakImport, srcAddr, targetName, offsetInTarget); + else + makeByNameReference(arm::kBranch24, srcAddr, targetName, offsetInTarget); + } + else { + dstAddr = srcAddr + displacement; + ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom; + // check for dtrace probes and weak_import stubs + const char* targetName = atom->getName(); + if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) { + makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[16]); + } + else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) { + makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[20]); + } + else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn) + && ((AnonymousAtom*)atom)->isWeakImportStub() ) + makeReference(arm::kBranch24WeakImport, srcAddr, dstAddr); + else if ( reloc->r_symbolnum() != R_ABS ) + makeReference(arm::kBranch24, srcAddr, dstAddr); + else { + // find absolute symbol that corresponds to pointerValue + AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr); + if ( pos != fAddrToAbsoluteAtom.end() ) + makeByNameReference(arm::kBranch24, srcAddr, pos->second->getName(), 0); + else + throwf("R_ABS reloc but no absolute symbol at target address"); + } + } + break; + + case ARM_THUMB_RELOC_BR22: + // First instruction has upper 11 bits of the displacement. + displacement = (instruction & 0x7FF) << 12; + if ( (displacement & 0x400000) != 0 ) + displacement |= 0xFF800000; + // Second instruction has lower eleven bits of the displacement. + displacement += ((instruction >> 16) & 0x7FF) << 1; + // The pc added will be +4 from the pc + displacement += 4; + // If the instruction was blx, force the low 2 bits to be clear + dstAddr = srcAddr + displacement; + if ((instruction & 0xF8000000) == 0xE8000000) + dstAddr &= 0xFFFFFFFC; + + if ( reloc->r_extern() ) { + uint32_t offsetInTarget = dstAddr; + if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) { + makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[16]); + } + else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) { + makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[20]); + } + else if ( weakImport ) + makeByNameReference(arm::kThumbBranch22WeakImport, srcAddr, targetName, offsetInTarget); + else + makeByNameReference(arm::kThumbBranch22, srcAddr, targetName, offsetInTarget); + } + else { + ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom; + // check for dtrace probes and weak_import stubs + const char* targetName = atom->getName(); + if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) { + makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[16]); + } + else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) { + makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0); + addDtraceExtraInfos(srcAddr, &targetName[20]); + } + else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn) + && ((AnonymousAtom*)atom)->isWeakImportStub() ) + makeReference(arm::kThumbBranch22WeakImport, srcAddr, dstAddr); + else if ( reloc->r_symbolnum() != R_ABS ) + makeReference(arm::kThumbBranch22, srcAddr, dstAddr); + else { + // find absolute symbol that corresponds to pointerValue + AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr); + if ( pos != fAddrToAbsoluteAtom.end() ) + makeByNameReference(arm::kThumbBranch22, srcAddr, pos->second->getName(), 0); + else + throwf("R_ABS reloc but no absolute symbol at target address"); + } + } + break; + + case ARM_RELOC_VANILLA: + if ( reloc->r_length() != 2 ) + throw "bad length for ARM_RELOC_VANILLA"; + + pointerValue = instruction; + if ( reloc->r_extern() ) { + if ( weakImport ) + makeByNameReference(arm::kPointerWeakImport, srcAddr, targetName, pointerValue); + else if ( strcmp(sect->segname(), "__TEXT") == 0 ) + makeByNameReference(arm::kReadOnlyPointer, srcAddr, targetName, pointerValue); + else + makeByNameReference(arm::kPointer, srcAddr, targetName, pointerValue); + } + else { + if ( strcmp(sect->segname(), "__TEXT") == 0 ) + makeReference(arm::kReadOnlyPointer, srcAddr, pointerValue); + else + makeReference(arm::kPointer, srcAddr, pointerValue); + } + break; + + default: + warning("unexpected relocation type %u", reloc->r_type()); + break; + } + } + else { + const macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; + const macho_scattered_relocation_info

* nextSReloc = &sreloc[1]; + srcAddr = sect->addr() + sreloc->r_address(); + dstAddr = sreloc->r_value(); + uint32_t betterDstAddr; + fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address()); + instruction = LittleEndian::get32(*fixUpPtr); + + // A ARM_RELOC_PAIR only follows ARM_RELOC_{SECTDIFF,LOCAL_SECTDIFF} + // relocation types, and it is an error to see one otherwise. + bool nextRelocIsPair = false; + uint32_t nextRelocAddress = 0; + uint32_t nextRelocValue = 0; + if ( nextSReloc->r_type() == ARM_RELOC_PAIR ) { + nextRelocIsPair = true; + nextRelocAddress = nextSReloc->r_address(); + nextRelocValue = nextSReloc->r_value(); + result = true; + } + + switch (sreloc->r_type()) { + case ARM_RELOC_VANILLA: + if ( sreloc->r_length() != 2 ) + throw "bad length for ARM_RELOC_VANILLA"; + + betterDstAddr = LittleEndian::get32(*fixUpPtr); + //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr); + // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr) + if ( strcmp(sect->segname(), "__TEXT") == 0 ) + makeReferenceWithToBase(arm::kReadOnlyPointer, srcAddr, betterDstAddr, dstAddr); + else + makeReferenceWithToBase(arm::kPointer, srcAddr, betterDstAddr, dstAddr); + break; + + case ARM_RELOC_BR24: + // Sign-extend displacement + displacement = (instruction & 0x00FFFFFF) << 2; + if ( (displacement & 0x02000000) != 0 ) + displacement |= 0xFC000000; + // The pc added will be +8 from the pc + displacement += 8; + // If this is BLX add H << 1 + if ((instruction & 0xFE000000) == 0xFA000000) + displacement += ((instruction & 0x01000000) >> 23); + betterDstAddr = srcAddr+displacement; + makeReferenceWithToBase(arm::kBranch24, srcAddr, betterDstAddr, dstAddr); + break; + + case ARM_THUMB_RELOC_BR22: + // First instruction has upper 11 bits of the displacement. + displacement = (instruction & 0x7FF) << 12; + if ( (displacement & 0x400000) != 0 ) + displacement |= 0xFF800000; + // Second instruction has lower eleven bits of the displacement. + displacement += ((instruction >> 16) & 0x7FF) << 1; + // The pc added will be +4 from the pc + displacement += 4; + betterDstAddr = srcAddr+displacement; + // If the instruction was blx, force the low 2 bits to be clear + if ((instruction & 0xF8000000) == 0xE8000000) + betterDstAddr &= 0xFFFFFFFC; + makeReferenceWithToBase(arm::kThumbBranch22, srcAddr, betterDstAddr, dstAddr); + break; + + case ARM_RELOC_SECTDIFF: + case ARM_RELOC_LOCAL_SECTDIFF: + if ( !nextRelocIsPair ) { + warning("ARM_RELOC_SECTDIFF missing following pair"); + break; + } + if ( sreloc->r_length() != 2 ) + throw "bad length for ARM_RELOC_SECTDIFF"; + { + AtomAndOffset srcao = findAtomAndOffset(srcAddr); + AtomAndOffset fromao = findAtomAndOffset(nextRelocValue); + AtomAndOffset toao = findAtomAndOffset(dstAddr); + // check for addend encoded in the section content + pointerValue = LittleEndian::get32(*fixUpPtr); + if ( (dstAddr - nextRelocValue) != pointerValue ) { + if ( toao.atom == srcao.atom ) + toao.offset += (pointerValue + nextRelocValue) - dstAddr; + else if ( fromao.atom == srcao.atom ) + toao.offset += (pointerValue + nextRelocValue) - dstAddr; + else + fromao.offset += (dstAddr - pointerValue) - nextRelocValue; + } + new Reference(arm::kPointerDiff, srcao, fromao, toao); + } + break; + + default: + warning("unexpected srelocation type %u", sreloc->r_type()); + break; + } + } + return result; +} + +template +void Reader::addReferencesForSection(const macho_section

* sect) +{ + // ignore dwarf sections. If ld ever supports processing dwarf, this logic will need to change + if ( (sect->flags() & S_ATTR_DEBUG) == 0 ) { + switch ( sect->flags() & SECTION_TYPE ) { + case S_SYMBOL_STUBS: + case S_LAZY_SYMBOL_POINTERS: + // we ignore compiler generated stubs, so ignore those relocs too + break; + default: + const macho_relocation_info

* relocs = (macho_relocation_info

*)((char*)(fHeader) + sect->reloff()); + const uint32_t relocCount = sect->nreloc(); + //fprintf(stderr, "relocCount = %d in section %s\n", relocCount, sect->sectname()); + for (uint32_t r = 0; r < relocCount; ++r) { + try { + if ( addRelocReference(sect, &relocs[r]) ) + ++r; // skip next + } + catch (const char* msg) { + throwf("in section %s,%s reloc %u: %s", sect->segname(), sect->sectname(), r, msg); + } + } + } + } +} + + +template <> +const char* Reference::getDescription() const +{ + static char temp[2048]; + switch( fKind ) { + case x86::kNoFixUp: + sprintf(temp, "reference to "); + break; + case x86::kFollowOn: + sprintf(temp, "followed by "); + break; + case x86::kGroupSubordinate: + sprintf(temp, "group subordinate "); + break; + case x86::kPointerWeakImport: + sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc); + break; + case x86::kPointer: + sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc); + break; + case x86::kPointerDiff: + { + // by-name references have quoted names + const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; + const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; + sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)", + fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset, + fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset ); + return temp; + } + break; + case x86::kPointerDiff16: + { + // by-name references have quoted names + const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; + const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; + sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)", + fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset, + fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset ); + return temp; + } + break; + case x86::kPCRel32WeakImport: + sprintf(temp, "offset 0x%04X, rel32 reference to weak imported ", fFixUpOffsetInSrc); + break; + case x86::kPCRel32: + sprintf(temp, "offset 0x%04X, rel32 reference to ", fFixUpOffsetInSrc); + break; + case x86::kPCRel16: + sprintf(temp, "offset 0x%04X, rel16 reference to ", fFixUpOffsetInSrc); + break; + case x86::kPCRel8: + sprintf(temp, "offset 0x%04X, rel8 reference to ", fFixUpOffsetInSrc); + break; + case x86::kAbsolute32: + sprintf(temp, "offset 0x%04X, absolute32 reference to ", fFixUpOffsetInSrc); + break; + case x86::kDtraceProbe: + sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc); + break; + case x86::kDtraceProbeSite: + sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc); + break; + case x86::kDtraceIsEnabledSite: + sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc); + break; + case x86::kDtraceTypeReference: + sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc); + break; + } + // always quote by-name references + if ( fToTargetName != NULL ) { + strcat(temp, "\""); + strcat(temp, fToTargetName); + strcat(temp, "\""); + } + else if ( fToTarget.atom != NULL ) { + strcat(temp, fToTarget.atom->getDisplayName()); + } + else { + strcat(temp, "NULL target"); + } + if ( fToTarget.offset != 0 ) + sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset); + + return temp; +} + + +template <> +const char* Reference::getDescription() const +{ + static char temp[2048]; + switch( fKind ) { + case ppc::kNoFixUp: + sprintf(temp, "reference to "); + break; + case ppc::kFollowOn: + sprintf(temp, "followed by "); + break; + case ppc::kGroupSubordinate: + sprintf(temp, "group subordinate "); + break; + case ppc::kPointerWeakImport: + sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc); + break; + case ppc::kPointer: + sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc); + break; + case ppc::kPointerDiff16: + { + // by-name references have quoted names + const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; + const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; + sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)", + fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset, + fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset ); + return temp; + } + case ppc::kPointerDiff32: + { + // by-name references have quoted names + const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; + const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; + sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)", + fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset, + fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset ); + return temp; + } + case ppc::kPointerDiff64: + throw "unsupported refrence kind"; + break; + case ppc::kBranch24WeakImport: + sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc); + break; + case ppc::kBranch24: + case ppc::kBranch14: + sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc); + break; + case ppc::kPICBaseLow16: + sprintf(temp, "offset 0x%04X, low 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset); + break; + case ppc::kPICBaseLow14: + sprintf(temp, "offset 0x%04X, low 14 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset); + break; + case ppc::kPICBaseHigh16: + sprintf(temp, "offset 0x%04X, high 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset); + break; + case ppc::kAbsLow16: + sprintf(temp, "offset 0x%04X, low 16 fixup to absolute address of ", fFixUpOffsetInSrc); + break; + case ppc::kAbsLow14: + sprintf(temp, "offset 0x%04X, low 14 fixup to absolute address of ", fFixUpOffsetInSrc); + break; + case ppc::kAbsHigh16: + sprintf(temp, "offset 0x%04X, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc); + break; + case ppc::kAbsHigh16AddLow: + sprintf(temp, "offset 0x%04X, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc); + break; + case ppc::kDtraceProbe: + sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc); + break; + case ppc::kDtraceProbeSite: + sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc); + break; + case ppc::kDtraceIsEnabledSite: + sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc); + break; + case ppc::kDtraceTypeReference: + sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc); + break; + } + // always quote by-name references + if ( fToTargetName != NULL ) { + strcat(temp, "\""); + strcat(temp, fToTargetName); + strcat(temp, "\""); + } + else if ( fToTarget.atom != NULL ) { + strcat(temp, fToTarget.atom->getDisplayName()); + } + else { + strcat(temp, "NULL target"); + } + if ( fToTarget.offset != 0 ) + sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset); + + return temp; +} + +template <> +const char* Reference::getDescription() const +{ + static char temp[2048]; + switch( fKind ) { + case ppc64::kNoFixUp: + sprintf(temp, "reference to "); + break; + case ppc64::kFollowOn: + sprintf(temp, "followed by "); + break; + case ppc64::kGroupSubordinate: + sprintf(temp, "group subordinate "); + break; + case ppc64::kPointerWeakImport: + sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc); + break; + case ppc64::kPointer: + sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc); + break; + case ppc64::kPointerDiff64: + { + // by-name references have quoted names + const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; + const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; + sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)", + fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset, + fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset ); + return temp; + } + case ppc64::kPointerDiff32: + { + // by-name references have quoted names + const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; + const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; + sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)", + fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset, + fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset ); + return temp; + } + case ppc64::kPointerDiff16: + { + // by-name references have quoted names + const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; + const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; + sprintf(temp, "offset 0x%04llX, 16-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)", + fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset, + fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset ); + return temp; + } + case ppc64::kBranch24WeakImport: + sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc); + break; + case ppc64::kBranch24: + case ppc64::kBranch14: + sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to ", fFixUpOffsetInSrc); + break; + case ppc64::kPICBaseLow16: + sprintf(temp, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset); + break; + case ppc64::kPICBaseLow14: + sprintf(temp, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset); + break; + case ppc64::kPICBaseHigh16: + sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset); + break; + case ppc64::kAbsLow16: + sprintf(temp, "offset 0x%04llX, low 16 fixup to absolute address of ", fFixUpOffsetInSrc); + break; + case ppc64::kAbsLow14: + sprintf(temp, "offset 0x%04llX, low 14 fixup to absolute address of ", fFixUpOffsetInSrc); + break; + case ppc64::kAbsHigh16: + sprintf(temp, "offset 0x%04llX, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc); + break; + case ppc64::kAbsHigh16AddLow: + sprintf(temp, "offset 0x%04llX, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc); + break; + case ppc64::kDtraceProbe: + sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc); + break; + case ppc64::kDtraceProbeSite: + sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc); + break; + case ppc64::kDtraceIsEnabledSite: + sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc); + break; + case ppc64::kDtraceTypeReference: + sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc); + break; + } + // always quote by-name references + if ( fToTargetName != NULL ) { + strcat(temp, "\""); + strcat(temp, fToTargetName); + strcat(temp, "\""); + } + else if ( fToTarget.atom != NULL ) { + strcat(temp, fToTarget.atom->getDisplayName()); + } + else { + strcat(temp, "NULL target"); + } + if ( fToTarget.offset != 0 ) + sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset()); + + return temp; +} + + +template <> +const char* Reference::getDescription() const +{ + static char temp[2048]; + switch( fKind ) { + case x86_64::kNoFixUp: + sprintf(temp, "reference to "); + break; + case x86_64::kFollowOn: + sprintf(temp, "followed by "); + break; + case x86_64::kGroupSubordinate: + sprintf(temp, "group subordinate "); + break; + case x86_64::kPointerWeakImport: + sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc); + break; + case x86_64::kPointer: + sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc); + break; + case x86_64::kPointerDiff32: + case x86_64::kPointerDiff: + { + // by-name references have quoted names + const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; + const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; + const char* size = (fKind == x86_64::kPointerDiff32) ? "32-bit" : "64-bit"; + sprintf(temp, "offset 0x%04llX, %s pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)", + fFixUpOffsetInSrc, size, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset, + fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset ); + return temp; + } + break; + case x86_64::kPCRel32: + sprintf(temp, "offset 0x%04llX, rel32 reference to ", fFixUpOffsetInSrc); + break; + case x86_64::kPCRel32_1: + sprintf(temp, "offset 0x%04llX, rel32-1 reference to ", fFixUpOffsetInSrc); + break; + case x86_64::kPCRel32_2: + sprintf(temp, "offset 0x%04llX, rel32-2 reference to ", fFixUpOffsetInSrc); + break; + case x86_64::kPCRel32_4: + sprintf(temp, "offset 0x%04llX, rel32-4 reference to ", fFixUpOffsetInSrc); + break; + case x86_64::kBranchPCRel32: + sprintf(temp, "offset 0x%04llX, branch rel32 reference to ", fFixUpOffsetInSrc); + break; + case x86_64::kBranchPCRel32WeakImport: + sprintf(temp, "offset 0x%04llX, branch rel32 reference to weak imported ", fFixUpOffsetInSrc); + break; + case x86_64::kPCRel32GOT: + sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc); + break; + case x86_64::kPCRel32GOTWeakImport: + sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc); + break; + case x86_64::kPCRel32GOTLoad: + sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc); + break; + case x86_64::kPCRel32GOTLoadWeakImport: + sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc); + break; + case x86_64::kBranchPCRel8: + sprintf(temp, "offset 0x%04llX, branch rel8 reference to ", fFixUpOffsetInSrc); + break; + case x86_64::kDtraceProbe: + sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc); + break; + case x86_64::kDtraceProbeSite: + sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc); + break; + case x86_64::kDtraceIsEnabledSite: + sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc); + break; + case x86_64::kDtraceTypeReference: + sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc); + break; + } + // always quote by-name references + if ( fToTargetName != NULL ) { + strcat(temp, "\""); + strcat(temp, fToTargetName); + strcat(temp, "\""); + } + else if ( fToTarget.atom != NULL ) { + strcat(temp, fToTarget.atom->getDisplayName()); + } + else { + strcat(temp, "NULL target"); + } + if ( fToTarget.offset != 0 ) + sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset()); + + return temp; +} + +template <> +const char* Reference::getDescription() const +{ + static char temp[2048]; + switch( fKind ) { + case arm::kNoFixUp: + sprintf(temp, "reference to "); + break; + case arm::kFollowOn: + sprintf(temp, "followed by "); + break; + case arm::kGroupSubordinate: + sprintf(temp, "group subordinate "); + break; + case arm::kPointer: + sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc); + break; + case arm::kPointerWeakImport: + sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc); + break; + case arm::kPointerDiff: + { + // by-name references have quoted names + const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; + const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; + sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)", + fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset, + fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset ); + return temp; + } + case arm::kReadOnlyPointer: + sprintf(temp, "offset 0x%04X, read-only pointer to ", fFixUpOffsetInSrc); + break; + case arm::kBranch24: + case arm::kThumbBranch22: + sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc); + break; + case arm::kBranch24WeakImport: + case arm::kThumbBranch22WeakImport: + sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc); + break; + case arm::kDtraceProbe: + sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc); + break; + case arm::kDtraceProbeSite: + sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc); + break; + case arm::kDtraceIsEnabledSite: + sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc); + break; + case arm::kDtraceTypeReference: + sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc); + break; + } + // always quote by-name references + if ( fToTargetName != NULL ) { + strcat(temp, "\""); + strcat(temp, fToTargetName); + strcat(temp, "\""); + } + else if ( fToTarget.atom != NULL ) { + strcat(temp, fToTarget.atom->getDisplayName()); + } + else { + strcat(temp, "NULL target"); + } + if ( fToTarget.offset != 0 ) + sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset); + + return temp; +} + +}; // namespace relocatable +}; // namespace mach_o + +#endif // __OBJECT_FILE_MACH_O__ diff --git a/FireOpal/src/MachOWriterExecutable.hpp b/FireOpal/src/MachOWriterExecutable.hpp new file mode 100644 index 0000000..8667ae4 --- /dev/null +++ b/FireOpal/src/MachOWriterExecutable.hpp @@ -0,0 +1,8579 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2005-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 __EXECUTABLE_MACH_O__ +#define __EXECUTABLE_MACH_O__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ObjectFile.h" +#include "ExecutableFile.h" +#include "Options.h" + +#include "MachOFileAbstraction.hpp" + + +// +// +// To implement architecture xxx, you must write template specializations for the following methods: +// MachHeaderAtom::setHeaderInfo() +// ThreadsLoadCommandsAtom::getSize() +// ThreadsLoadCommandsAtom::copyRawContent() +// Writer::addObjectRelocs() +// Writer::fixUpReferenceRelocatable() +// Writer::fixUpReferenceFinal() +// Writer::stubableReference() +// Writer::weakImportReferenceKind() +// Writer::GOTReferenceKind() +// + + +namespace mach_o { +namespace executable { + +// forward references +template class WriterAtom; +template class PageZeroAtom; +template class CustomStackAtom; +template class MachHeaderAtom; +template class SegmentLoadCommandsAtom; +template class EncryptionLoadCommandsAtom; +template class SymbolTableLoadCommandsAtom; +template class ThreadsLoadCommandsAtom; +template class DylibIDLoadCommandsAtom; +template class RoutinesLoadCommandsAtom; +template class DyldLoadCommandsAtom; +template class UUIDLoadCommandAtom; +template class LinkEditAtom; +template class SectionRelocationsLinkEditAtom; +template class LocalRelocationsLinkEditAtom; +template class ExternalRelocationsLinkEditAtom; +template class SymbolTableLinkEditAtom; +template class SegmentSplitInfoLoadCommandsAtom; +template class SegmentSplitInfoContentAtom; +template class IndirectTableLinkEditAtom; +template class ModuleInfoLinkEditAtom; +template class StringsLinkEditAtom; +template class LoadCommandsPaddingAtom; +template class StubAtom; +template class StubHelperAtom; +template class LazyPointerAtom; +template class NonLazyPointerAtom; +template class DylibLoadCommandsAtom; + + +// SectionInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes +class SectionInfo : public ObjectFile::Section { +public: + SectionInfo() : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0), + fIndirectSymbolOffset(0), fAlignment(0), fAllLazyPointers(false), + fAllLazyDylibPointers(false),fAllNonLazyPointers(false), fAllStubs(false), + fAllSelfModifyingStubs(false), fAllZeroFill(false), fVirtualSection(false), + fHasTextLocalRelocs(false), fHasTextExternalRelocs(false) + { fSegmentName[0] = '\0'; fSectionName[0] = '\0'; } + void setIndex(unsigned int index) { fIndex=index; } + std::vector fAtoms; + char fSegmentName[20]; + char fSectionName[20]; + uint64_t fFileOffset; + uint64_t fSize; + uint32_t fRelocCount; + uint32_t fRelocOffset; + uint32_t fIndirectSymbolOffset; + uint8_t fAlignment; + bool fAllLazyPointers; + bool fAllLazyDylibPointers; + bool fAllNonLazyPointers; + bool fAllStubs; + bool fAllSelfModifyingStubs; + bool fAllZeroFill; + bool fVirtualSection; + bool fHasTextLocalRelocs; + bool fHasTextExternalRelocs; +}; + +// SegmentInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes +class SegmentInfo +{ +public: + SegmentInfo() : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0), + fBaseAddress(0), fSize(0), fFixedAddress(false), + fIndependentAddress(false) { fName[0] = '\0'; } + std::vector fSections; + char fName[20]; + uint32_t fInitProtection; + uint32_t fMaxProtection; + uint64_t fFileOffset; + uint64_t fFileSize; + uint64_t fBaseAddress; + uint64_t fSize; + bool fFixedAddress; + bool fIndependentAddress; +}; + +template +class Writer : public ExecutableFile::Writer +{ +public: + Writer(const char* path, Options& options, std::vector& dynamicLibraries); + virtual ~Writer(); + + virtual const char* getPath() { return fFilePath; } + virtual time_t getModificationTime() { return 0; } + virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; } + virtual std::vector& getAtoms() { return fWriterSynthesizedAtoms; } + virtual std::vector* getJustInTimeAtomsFor(const char* name) { return NULL; } + virtual std::vector* getStabs() { return NULL; } + + virtual ObjectFile::Atom& makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, + bool objcReplacementClasses); + virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name); + virtual uint64_t write(std::vector& atoms, + std::vector& stabs, + class ObjectFile::Atom* entryPointAtom, + class ObjectFile::Atom* dyldHelperAtom, + class ObjectFile::Atom* dyldLazyDylibHelperAtom, + bool createUUID, bool canScatter, + ObjectFile::Reader::CpuConstraint cpuConstraint, + bool biggerThanTwoGigs, bool overridesDylibWeakDefines); + +private: + typedef typename A::P P; + typedef typename A::P::uint_t pint_t; + + enum RelocKind { kRelocNone, kRelocInternal, kRelocExternal }; + + void assignFileOffsets(); + void synthesizeStubs(); + void insertDummyStubs(); + void partitionIntoSections(); + bool addBranchIslands(); + bool addPPCBranchIslands(); + bool isBranch24Reference(uint8_t kind); + void adjustLoadCommandsAndPadding(); + void createDynamicLinkerCommand(); + void createDylibCommands(); + void buildLinkEdit(); + const char* getArchString(); + void writeMap(); + uint64_t writeAtoms(); + void writeNoOps(int fd, uint32_t from, uint32_t to); + void copyNoOps(uint8_t* from, uint8_t* to); + bool segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to); + void addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref); + void collectExportedAndImportedAndLocalAtoms(); + void setNlistRange(std::vector& atoms, uint32_t startIndex, uint32_t count); + void addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name); + void addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name); + void buildSymbolTable(); + const char* symbolTableName(const ObjectFile::Atom* atom); + void setExportNlist(const ObjectFile::Atom* atom, macho_nlist

* entry); + void setImportNlist(const ObjectFile::Atom* atom, macho_nlist

* entry); + void setLocalNlist(const ObjectFile::Atom* atom, macho_nlist

* entry); + void copyNlistRange(const std::vector >& entries, uint32_t startIndex); + uint64_t getAtomLoadAddress(const ObjectFile::Atom* atom); + uint8_t ordinalForLibrary(ObjectFile::Reader* file); + bool shouldExport(const ObjectFile::Atom& atom) const; + void buildFixups(); + void adjustLinkEditSections(); + void buildObjectFileFixups(); + void buildExecutableFixups(); + bool preboundLazyPointerType(uint8_t* type); + uint64_t relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const; + void fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const; + void fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const; + void fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, + uint8_t buffer[], bool finalLinkedImage) const; + uint32_t symbolIndex(ObjectFile::Atom& atom); + bool makesExternalRelocatableReference(ObjectFile::Atom& target) const; + uint32_t addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref); + uint32_t addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref); + uint8_t getRelocPointerSize(); + uint64_t maxAddress(); + bool stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref); + bool GOTReferenceKind(uint8_t kind); + bool optimizableGOTReferenceKind(uint8_t kind); + bool weakImportReferenceKind(uint8_t kind); + unsigned int collectStabs(); + uint64_t valueForStab(const ObjectFile::Reader::Stab& stab); + uint32_t stringOffsetForStab(const ObjectFile::Reader::Stab& stab); + uint8_t sectionIndexForStab(const ObjectFile::Reader::Stab& stab); + void addStabs(uint32_t startIndex); + RelocKind relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const; + bool illegalRelocInFinalLinkedImage(const ObjectFile::Reference&); + bool generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection); + bool generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection); + bool mightNeedPadSegment(); + void scanForAbsoluteReferences(); + bool needsModuleTable(); + void optimizeDylibReferences(); + bool indirectSymbolIsLocal(const ObjectFile::Reference* ref) const; + + struct DirectLibrary { + class ObjectFile::Reader* fLibrary; + bool fWeak; + bool fReExport; + }; + + friend class WriterAtom; + friend class PageZeroAtom; + friend class CustomStackAtom; + friend class MachHeaderAtom; + friend class SegmentLoadCommandsAtom; + friend class EncryptionLoadCommandsAtom; + friend class SymbolTableLoadCommandsAtom; + friend class ThreadsLoadCommandsAtom; + friend class DylibIDLoadCommandsAtom; + friend class RoutinesLoadCommandsAtom; + friend class DyldLoadCommandsAtom; + friend class UUIDLoadCommandAtom; + friend class LinkEditAtom; + friend class SectionRelocationsLinkEditAtom; + friend class LocalRelocationsLinkEditAtom; + friend class ExternalRelocationsLinkEditAtom; + friend class SymbolTableLinkEditAtom; + friend class SegmentSplitInfoLoadCommandsAtom; + friend class SegmentSplitInfoContentAtom; +// friend class IndirectTableLinkEditAtom; + friend class ModuleInfoLinkEditAtom; + friend class StringsLinkEditAtom; + friend class LoadCommandsPaddingAtom; + friend class StubAtom; + friend class StubHelperAtom; + friend class LazyPointerAtom; + friend class NonLazyPointerAtom; + friend class DylibLoadCommandsAtom; + + const char* fFilePath; + Options& fOptions; + std::vector* fAllAtoms; + std::vector* fStabs; + class SectionInfo* fLoadCommandsSection; + class SegmentInfo* fLoadCommandsSegment; + class EncryptionLoadCommandsAtom* fEncryptionLoadCommand; + class SegmentLoadCommandsAtom* fSegmentCommands; + class SymbolTableLoadCommandsAtom* fSymbolTableCommands; + class LoadCommandsPaddingAtom* fHeaderPadding; + class UUIDLoadCommandAtom* fUUIDAtom; + std::vector fWriterSynthesizedAtoms; + std::vector fSegmentInfos; + class SegmentInfo* fPadSegmentInfo; + class ObjectFile::Atom* fEntryPoint; + class ObjectFile::Atom* fDyldHelper; + class ObjectFile::Atom* fDyldLazyDylibHelper; + std::map*> fLibraryToLoadCommand; + std::map fLibraryToOrdinal; + std::map fLibraryAliases; + std::vector fExportedAtoms; + std::vector fImportedAtoms; + std::vector fLocalSymbolAtoms; + std::vector > fLocalExtraLabels; + std::vector > fGlobalExtraLabels; + class SectionRelocationsLinkEditAtom* fSectionRelocationsAtom; + class LocalRelocationsLinkEditAtom* fLocalRelocationsAtom; + class ExternalRelocationsLinkEditAtom* fExternalRelocationsAtom; + class SymbolTableLinkEditAtom* fSymbolTableAtom; + class SegmentSplitInfoContentAtom* fSplitCodeToDataContentAtom; + class IndirectTableLinkEditAtom* fIndirectTableAtom; + class ModuleInfoLinkEditAtom* fModuleInfoAtom; + class StringsLinkEditAtom* fStringsAtom; + class PageZeroAtom* fPageZeroAtom; + macho_nlist

* fSymbolTable; + std::vector > fSectionRelocs; + std::vector > fInternalRelocs; + std::vector > fExternalRelocs; + std::map fStubsMap; + std::map fGOTMap; + std::vector*> fAllSynthesizedStubs; + std::vector fAllSynthesizedStubHelpers; + std::vector*> fAllSynthesizedLazyPointers; + std::vector*> fAllSynthesizedLazyDylibPointers; + std::vector*> fAllSynthesizedNonLazyPointers; + uint32_t fSymbolTableCount; + uint32_t fSymbolTableStabsCount; + uint32_t fSymbolTableStabsStartIndex; + uint32_t fSymbolTableLocalCount; + uint32_t fSymbolTableLocalStartIndex; + uint32_t fSymbolTableExportCount; + uint32_t fSymbolTableExportStartIndex; + uint32_t fSymbolTableImportCount; + uint32_t fSymbolTableImportStartIndex; + uint32_t fLargestAtomSize; + bool fEmitVirtualSections; + bool fHasWeakExports; + bool fReferencesWeakImports; + bool fCanScatter; + bool fWritableSegmentPastFirst4GB; + bool fNoReExportedDylibs; + bool fBiggerThanTwoGigs; + bool fSlideable; + std::map fWeakImportMap; + std::set fDylibReadersWithNonWeakImports; + std::set fDylibReadersWithWeakImports; + SegmentInfo* fFirstWritableSegment; + ObjectFile::Reader::CpuConstraint fCpuConstraint; + uint32_t fAnonNameIndex; +}; + + +class Segment : public ObjectFile::Segment +{ +public: + Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress) + : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {} + virtual const char* getName() const { return fName; } + virtual bool isContentReadable() const { return fReadable; } + virtual bool isContentWritable() const { return fWritable; } + virtual bool isContentExecutable() const { return fExecutable; } + virtual bool hasFixedAddress() const { return fFixedAddress; } + + static Segment fgTextSegment; + static Segment fgPageZeroSegment; + static Segment fgLinkEditSegment; + static Segment fgStackSegment; + static Segment fgImportSegment; + static Segment fgROImportSegment; + static Segment fgDataSegment; + static Segment fgObjCSegment; + + +private: + const char* fName; + const bool fReadable; + const bool fWritable; + const bool fExecutable; + const bool fFixedAddress; +}; + +Segment Segment::fgPageZeroSegment("__PAGEZERO", false, false, false, true); +Segment Segment::fgTextSegment("__TEXT", true, false, true, false); +Segment Segment::fgLinkEditSegment("__LINKEDIT", true, false, false, false); +Segment Segment::fgStackSegment("__UNIXSTACK", true, true, false, true); +Segment Segment::fgImportSegment("__IMPORT", true, true, true, false); +Segment Segment::fgROImportSegment("__IMPORT", true, false, true, false); +Segment Segment::fgDataSegment("__DATA", true, true, false, false); +Segment Segment::fgObjCSegment("__OBJC", true, true, false, false); + + +template +class WriterAtom : public ObjectFile::Atom +{ +public: + enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy }; + WriterAtom(Writer& writer, Segment& segment) : fWriter(writer), fSegment(segment) { } + + virtual ObjectFile::Reader* getFile() const { return &fWriter; } + virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; } + virtual const char* getName() const { return NULL; } + virtual const char* getDisplayName() const { return this->getName(); } + virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; } + virtual DefinitionKind getDefinitionKind() const { return kRegularDefinition; } + virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; } + virtual bool dontDeadStrip() const { return true; } + virtual bool isZeroFill() const { return false; } + virtual bool isThumb() const { return false; } + virtual std::vector& getReferences() const { return fgEmptyReferenceList; } + virtual bool mustRemainInSection() const { return true; } + virtual ObjectFile::Segment& getSegment() const { return fSegment; } + virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); } + virtual uint32_t getOrdinal() const { return 0; } + virtual std::vector* getLineInfo() const { return NULL; } + virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(2); } + virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; } + virtual void setScope(Scope) { } + + +protected: + virtual ~WriterAtom() {} + typedef typename A::P P; + typedef typename A::P::E E; + + static std::vector fgEmptyReferenceList; + + Writer& fWriter; + Segment& fSegment; +}; + +template std::vector WriterAtom::fgEmptyReferenceList; + + +template +class PageZeroAtom : public WriterAtom +{ +public: + PageZeroAtom(Writer& writer) : WriterAtom(writer, Segment::fgPageZeroSegment), + fSize(fWriter.fOptions.zeroPageSize()) {} + virtual const char* getDisplayName() const { return "page zero content"; } + virtual bool isZeroFill() const { return true; } + virtual uint64_t getSize() const { return fSize; } + virtual const char* getSectionName() const { return "._zeropage"; } + virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); } + void setSize(uint64_t size) { fSize = size; } +private: + using WriterAtom::fWriter; + typedef typename A::P P; + uint64_t fSize; +}; + + +template +class DsoHandleAtom : public WriterAtom +{ +public: + DsoHandleAtom(Writer& writer) : WriterAtom(writer, Segment::fgTextSegment) {} + virtual const char* getName() const { return "___dso_handle"; } + virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } + virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; } + virtual uint64_t getSize() const { return 0; } + virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); } + virtual const char* getSectionName() const { return "._mach_header"; } + virtual void copyRawContent(uint8_t buffer[]) const {} +}; + + +template +class MachHeaderAtom : public WriterAtom +{ +public: + MachHeaderAtom(Writer& writer) : WriterAtom(writer, Segment::fgTextSegment) {} + virtual const char* getName() const; + virtual const char* getDisplayName() const; + virtual ObjectFile::Atom::Scope getScope() const; + virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const; + virtual uint64_t getSize() const { return sizeof(macho_header); } + virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); } + virtual const char* getSectionName() const { return "._mach_header"; } + virtual uint32_t getOrdinal() const { return 1; } + virtual void copyRawContent(uint8_t buffer[]) const; +private: + using WriterAtom::fWriter; + typedef typename A::P P; + void setHeaderInfo(macho_header& header) const; +}; + +template +class CustomStackAtom : public WriterAtom +{ +public: + CustomStackAtom(Writer& writer); + virtual const char* getDisplayName() const { return "custom stack content"; } + virtual bool isZeroFill() const { return true; } + virtual uint64_t getSize() const { return fWriter.fOptions.customStackSize(); } + virtual const char* getSectionName() const { return "._stack"; } + virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); } +private: + using WriterAtom::fWriter; + typedef typename A::P P; + static bool stackGrowsDown(); +}; + +template +class LoadCommandAtom : public WriterAtom +{ +protected: + LoadCommandAtom(Writer& writer, Segment& segment) : WriterAtom(writer, segment), fOrdinal(fgCurrentOrdinal++) {} + virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); } + virtual const char* getSectionName() const { return "._load_commands"; } + virtual uint32_t getOrdinal() const { return fOrdinal; } + static uint64_t alignedSize(uint64_t size); +protected: + uint32_t fOrdinal; + static uint32_t fgCurrentOrdinal; +}; + +template uint32_t LoadCommandAtom::fgCurrentOrdinal = 0; + +template +class SegmentLoadCommandsAtom : public LoadCommandAtom +{ +public: + SegmentLoadCommandsAtom(Writer& writer) + : LoadCommandAtom(writer, Segment::fgTextSegment), fCommandCount(0), fSize(0) + { writer.fSegmentCommands = this; } + virtual const char* getDisplayName() const { return "segment load commands"; } + virtual uint64_t getSize() const { return fSize; } + virtual void copyRawContent(uint8_t buffer[]) const; + + void computeSize(); + void setup(); + unsigned int commandCount() { return fCommandCount; } +private: + using WriterAtom::fWriter; + typedef typename A::P P; + unsigned int fCommandCount; + uint32_t fSize; +}; + + +template +class SymbolTableLoadCommandsAtom : public LoadCommandAtom +{ +public: + SymbolTableLoadCommandsAtom(Writer&); + virtual const char* getDisplayName() const { return "symbol table load commands"; } + virtual uint64_t getSize() const; + virtual void copyRawContent(uint8_t buffer[]) const; + unsigned int commandCount(); + void needDynamicTable(); +private: + using WriterAtom::fWriter; + typedef typename A::P P; + bool fNeedsDynamicSymbolTable; + macho_symtab_command fSymbolTable; + macho_dysymtab_command fDynamicSymbolTable; +}; + +template +class ThreadsLoadCommandsAtom : public LoadCommandAtom +{ +public: + ThreadsLoadCommandsAtom(Writer& writer) + : LoadCommandAtom(writer, Segment::fgTextSegment) {} + virtual const char* getDisplayName() const { return "thread load commands"; } + virtual uint64_t getSize() const; + virtual void copyRawContent(uint8_t buffer[]) const; +private: + using WriterAtom::fWriter; + typedef typename A::P P; + uint8_t* fBuffer; + uint32_t fBufferSize; +}; + +template +class DyldLoadCommandsAtom : public LoadCommandAtom +{ +public: + DyldLoadCommandsAtom(Writer& writer) : LoadCommandAtom(writer, Segment::fgTextSegment) {} + virtual const char* getDisplayName() const { return "dyld load command"; } + virtual uint64_t getSize() const; + virtual void copyRawContent(uint8_t buffer[]) const; +private: + using WriterAtom::fWriter; + typedef typename A::P P; +}; + +template +class SegmentSplitInfoLoadCommandsAtom : public LoadCommandAtom +{ +public: + SegmentSplitInfoLoadCommandsAtom(Writer& writer) : LoadCommandAtom(writer, Segment::fgTextSegment) {} + virtual const char* getDisplayName() const { return "segment split info load command"; } + virtual uint64_t getSize() const; + virtual void copyRawContent(uint8_t buffer[]) const; +private: + using WriterAtom::fWriter; + typedef typename A::P P; +}; + +template +class AllowableClientLoadCommandsAtom : public LoadCommandAtom +{ +public: + AllowableClientLoadCommandsAtom(Writer& writer, const char* client) : + LoadCommandAtom(writer, Segment::fgTextSegment), clientString(client) {} + virtual const char* getDisplayName() const { return "allowable_client load command"; } + virtual uint64_t getSize() const; + virtual void copyRawContent(uint8_t buffer[]) const; +private: + using WriterAtom::fWriter; + typedef typename A::P P; + const char* clientString; +}; + +template +class DylibLoadCommandsAtom : public LoadCommandAtom +{ +public: + DylibLoadCommandsAtom(Writer& writer, ExecutableFile::DyLibUsed& info) + : LoadCommandAtom(writer, Segment::fgTextSegment), fInfo(info), + fOptimizedAway(false) { if (fInfo.options.fLazyLoad) this->fOrdinal += 256; } + virtual const char* getDisplayName() const { return "dylib load command"; } + virtual uint64_t getSize() const; + virtual void copyRawContent(uint8_t buffer[]) const; + virtual void optimizeAway() { fOptimizedAway = true; } + bool linkedWeak() { return fInfo.options.fWeakImport; } +private: + using WriterAtom::fWriter; + typedef typename A::P P; + ExecutableFile::DyLibUsed fInfo; + bool fOptimizedAway; +}; + +template +class DylibIDLoadCommandsAtom : public LoadCommandAtom +{ +public: + DylibIDLoadCommandsAtom(Writer& writer) : LoadCommandAtom(writer, Segment::fgTextSegment) {} + virtual const char* getDisplayName() const { return "dylib ID load command"; } + virtual uint64_t getSize() const; + virtual void copyRawContent(uint8_t buffer[]) const; +private: + using WriterAtom::fWriter; + typedef typename A::P P; +}; + +template +class RoutinesLoadCommandsAtom : public LoadCommandAtom +{ +public: + RoutinesLoadCommandsAtom(Writer& writer) : LoadCommandAtom(writer, Segment::fgTextSegment) {} + virtual const char* getDisplayName() const { return "routines load command"; } + virtual uint64_t getSize() const { return sizeof(macho_routines_command); } + virtual void copyRawContent(uint8_t buffer[]) const; +private: + using WriterAtom::fWriter; + typedef typename A::P P; +}; + +template +class SubUmbrellaLoadCommandsAtom : public LoadCommandAtom +{ +public: + SubUmbrellaLoadCommandsAtom(Writer& writer, const char* name) + : LoadCommandAtom(writer, Segment::fgTextSegment), fName(name) {} + virtual const char* getDisplayName() const { return "sub-umbrella load command"; } + virtual uint64_t getSize() const; + virtual void copyRawContent(uint8_t buffer[]) const; +private: + typedef typename A::P P; + const char* fName; +}; + +template +class SubLibraryLoadCommandsAtom : public LoadCommandAtom +{ +public: + SubLibraryLoadCommandsAtom(Writer& writer, const char* nameStart, int nameLen) + : LoadCommandAtom(writer, Segment::fgTextSegment), fNameStart(nameStart), fNameLength(nameLen) {} + virtual const char* getDisplayName() const { return "sub-library load command"; } + virtual uint64_t getSize() const; + virtual void copyRawContent(uint8_t buffer[]) const; +private: + using WriterAtom::fWriter; + typedef typename A::P P; + const char* fNameStart; + int fNameLength; +}; + +template +class UmbrellaLoadCommandsAtom : public LoadCommandAtom +{ +public: + UmbrellaLoadCommandsAtom(Writer& writer, const char* name) + : LoadCommandAtom(writer, Segment::fgTextSegment), fName(name) {} + virtual const char* getDisplayName() const { return "umbrella load command"; } + virtual uint64_t getSize() const; + virtual void copyRawContent(uint8_t buffer[]) const; +private: + using WriterAtom::fWriter; + typedef typename A::P P; + const char* fName; +}; + +template +class UUIDLoadCommandAtom : public LoadCommandAtom +{ +public: + UUIDLoadCommandAtom(Writer& writer) + : LoadCommandAtom(writer, Segment::fgTextSegment), fEmit(false) {} + virtual const char* getDisplayName() const { return "uuid load command"; } + virtual uint64_t getSize() const { return fEmit ? sizeof(macho_uuid_command) : 0; } + virtual void copyRawContent(uint8_t buffer[]) const; + virtual void generate(); + void setContent(const uint8_t uuid[16]); + const uint8_t* getUUID() { return fUUID; } +private: + using WriterAtom::fWriter; + typedef typename A::P P; + uuid_t fUUID; + bool fEmit; +}; + + +template +class RPathLoadCommandsAtom : public LoadCommandAtom +{ +public: + RPathLoadCommandsAtom(Writer& writer, const char* path) + : LoadCommandAtom(writer, Segment::fgTextSegment), fPath(path) {} + virtual const char* getDisplayName() const { return "rpath load command"; } + virtual uint64_t getSize() const; + virtual void copyRawContent(uint8_t buffer[]) const; +private: + using WriterAtom::fWriter; + typedef typename A::P P; + const char* fPath; +}; + +template +class EncryptionLoadCommandsAtom : public LoadCommandAtom +{ +public: + EncryptionLoadCommandsAtom(Writer& writer) + : LoadCommandAtom(writer, Segment::fgTextSegment), fStartOffset(0), + fEndOffset(0) {} + virtual const char* getDisplayName() const { return "encryption info load command"; } + virtual uint64_t getSize() const { return sizeof(macho_encryption_info_command); } + virtual void copyRawContent(uint8_t buffer[]) const; + void setStartEncryptionOffset(uint32_t off) { fStartOffset = off; } + void setEndEncryptionOffset(uint32_t off) { fEndOffset = off; } +private: + using WriterAtom::fWriter; + typedef typename A::P P; + uint32_t fStartOffset; + uint32_t fEndOffset; +}; + +template +class LoadCommandsPaddingAtom : public WriterAtom +{ +public: + LoadCommandsPaddingAtom(Writer& writer) + : WriterAtom(writer, Segment::fgTextSegment), fSize(0) {} + virtual const char* getDisplayName() const { return "header padding"; } + virtual uint64_t getSize() const { return fSize; } + virtual const char* getSectionName() const { return "._load_cmds_pad"; } + virtual void copyRawContent(uint8_t buffer[]) const; + + void setSize(uint64_t newSize); +private: + using WriterAtom::fWriter; + typedef typename A::P P; + uint64_t fSize; +}; + +template +class LinkEditAtom : public WriterAtom +{ +public: + LinkEditAtom(Writer& writer) : WriterAtom(writer, Segment::fgLinkEditSegment), fOrdinal(fgCurrentOrdinal++) {} + uint64_t getFileOffset() const; + virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); } + virtual uint32_t getOrdinal() const { return fOrdinal; } +private: + uint32_t fOrdinal; + static uint32_t fgCurrentOrdinal; +private: + typedef typename A::P P; +}; + +template uint32_t LinkEditAtom::fgCurrentOrdinal = 0; + +template +class SectionRelocationsLinkEditAtom : public LinkEditAtom +{ +public: + SectionRelocationsLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { } + virtual const char* getDisplayName() const { return "section relocations"; } + virtual uint64_t getSize() const; + virtual const char* getSectionName() const { return "._section_relocs"; } + virtual void copyRawContent(uint8_t buffer[]) const; +private: + using WriterAtom::fWriter; + typedef typename A::P P; +}; + +template +class LocalRelocationsLinkEditAtom : public LinkEditAtom +{ +public: + LocalRelocationsLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { } + virtual const char* getDisplayName() const { return "local relocations"; } + virtual uint64_t getSize() const; + virtual const char* getSectionName() const { return "._local_relocs"; } + virtual void copyRawContent(uint8_t buffer[]) const; +private: + using WriterAtom::fWriter; + typedef typename A::P P; +}; + +template +class SymbolTableLinkEditAtom : public LinkEditAtom +{ +public: + SymbolTableLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { } + virtual const char* getDisplayName() const { return "symbol table"; } + virtual uint64_t getSize() const; + virtual const char* getSectionName() const { return "._symbol_table"; } + virtual void copyRawContent(uint8_t buffer[]) const; +private: + using WriterAtom::fWriter; + typedef typename A::P P; +}; + +template +class ExternalRelocationsLinkEditAtom : public LinkEditAtom +{ +public: + ExternalRelocationsLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { } + virtual const char* getDisplayName() const { return "external relocations"; } + virtual uint64_t getSize() const; + virtual const char* getSectionName() const { return "._extern_relocs"; } + virtual void copyRawContent(uint8_t buffer[]) const; +private: + using WriterAtom::fWriter; + typedef typename A::P P; +}; + +struct IndirectEntry { + uint32_t indirectIndex; + uint32_t symbolIndex; +}; + + +template +class SegmentSplitInfoContentAtom : public LinkEditAtom +{ +public: + SegmentSplitInfoContentAtom(Writer& writer) : LinkEditAtom(writer), fCantEncode(false) { } + virtual const char* getDisplayName() const { return "split segment info"; } + virtual uint64_t getSize() const; + virtual const char* getSectionName() const { return "._split_info"; } + virtual void copyRawContent(uint8_t buffer[]) const; + bool canEncode() { return !fCantEncode; } + void setCantEncode() { fCantEncode = true; } + void add32bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind1Locations.push_back(AtomAndOffset(atom, offset)); } + void add64bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind2Locations.push_back(AtomAndOffset(atom, offset)); } + void addPPCHi16Location(const ObjectFile::Atom* atom, uint32_t offset) { fKind3Locations.push_back(AtomAndOffset(atom, offset)); } + void add32bitImportLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind4Locations.push_back(AtomAndOffset(atom, offset)); } + void encode(); + +private: + using WriterAtom::fWriter; + typedef typename A::P P; + typedef typename A::P::uint_t pint_t; + struct AtomAndOffset { + AtomAndOffset(const ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {} + const ObjectFile::Atom* atom; + uint32_t offset; + }; + void uleb128EncodeAddresses(const std::vector& locations); + + std::vector fKind1Locations; + std::vector fKind2Locations; + std::vector fKind3Locations; + std::vector fKind4Locations; + std::vector fEncodedData; + bool fCantEncode; +}; + +template +class IndirectTableLinkEditAtom : public LinkEditAtom +{ +public: + IndirectTableLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { } + virtual const char* getDisplayName() const { return "indirect symbol table"; } + virtual uint64_t getSize() const; + virtual const char* getSectionName() const { return "._indirect_syms"; } + virtual void copyRawContent(uint8_t buffer[]) const; + + std::vector fTable; + +private: + using WriterAtom::fWriter; + typedef typename A::P P; +}; + +template +class ModuleInfoLinkEditAtom : public LinkEditAtom +{ +public: + ModuleInfoLinkEditAtom(Writer& writer) : LinkEditAtom(writer), fModuleNameOffset(0) { } + virtual const char* getDisplayName() const { return "module table"; } + virtual uint64_t getSize() const; + virtual const char* getSectionName() const { return "._module_info"; } + virtual void copyRawContent(uint8_t buffer[]) const; + + void setName() { fModuleNameOffset = fWriter.fStringsAtom->add("single module"); } + uint32_t getTableOfContentsFileOffset() const; + uint32_t getModuleTableFileOffset() const; + uint32_t getReferencesFileOffset() const; + uint32_t getReferencesCount() const; + +private: + using WriterAtom::fWriter; + typedef typename A::P P; + uint32_t fModuleNameOffset; +}; + + +class CStringEquals +{ +public: + bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } +}; + +template +class StringsLinkEditAtom : public LinkEditAtom +{ +public: + StringsLinkEditAtom(Writer& writer); + virtual const char* getDisplayName() const { return "string pool"; } + virtual uint64_t getSize() const; + virtual const char* getSectionName() const { return "._string_pool"; } + virtual void copyRawContent(uint8_t buffer[]) const; + + int32_t add(const char* name); + int32_t addUnique(const char* name); + int32_t emptyString() { return 1; } + const char* stringForIndex(int32_t) const; + +private: + using WriterAtom::fWriter; + typedef typename A::P P; + enum { kBufferSize = 0x01000000 }; + typedef __gnu_cxx::hash_map, CStringEquals> StringToOffset; + + std::vector fFullBuffers; + char* fCurrentBuffer; + uint32_t fCurrentBufferUsed; + StringToOffset fUniqueStrings; +}; + + + +template +class UndefinedSymbolProxyAtom : public WriterAtom +{ +public: + UndefinedSymbolProxyAtom(Writer& writer, const char* name) : WriterAtom(writer, Segment::fgLinkEditSegment), fName(name) {} + virtual const char* getName() const { return fName; } + virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeGlobal; } + virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kExternalDefinition; } + virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; } + virtual uint64_t getSize() const { return 0; } + virtual const char* getSectionName() const { return "._imports"; } +private: + using WriterAtom::fWriter; + typedef typename A::P P; + const char* fName; +}; + +template +class BranchIslandAtom : public WriterAtom +{ +public: + BranchIslandAtom(Writer& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset); + virtual const char* getName() const { return fName; } + virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } + virtual uint64_t getSize() const; + virtual const char* getSectionName() const { return "__text"; } + virtual void copyRawContent(uint8_t buffer[]) const; +private: + using WriterAtom::fWriter; + const char* fName; + ObjectFile::Atom& fTarget; + uint32_t fTargetOffset; +}; + +template +class StubAtom : public WriterAtom +{ +public: + StubAtom(Writer& writer, ObjectFile::Atom& target, bool forLazyDylib); + virtual const char* getName() const { return fName; } + virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } + virtual uint64_t getSize() const; + virtual ObjectFile::Alignment getAlignment() const; + virtual const char* getSectionName() const { return "__symbol_stub1"; } + virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } + virtual void copyRawContent(uint8_t buffer[]) const; + ObjectFile::Atom* getTarget() { return &fTarget; } +private: + static const char* stubName(const char* importName); + bool pic() const { return fWriter.fSlideable; } + using WriterAtom::fWriter; + const char* fName; + ObjectFile::Atom& fTarget; + std::vector fReferences; + bool fForLazyDylib; +}; + +template +class StubHelperAtom : public WriterAtom +{ +public: + StubHelperAtom(Writer& writer, ObjectFile::Atom& target, ObjectFile::Atom& lazyPointer, bool forLazyDylib); + virtual const char* getName() const { return fName; } + virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } + virtual uint64_t getSize() const; + virtual const char* getSectionName() const { return "__stub_helper"; } + virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } + virtual void copyRawContent(uint8_t buffer[]) const; + ObjectFile::Atom* getTarget() { return &fTarget; } +private: + static const char* stubName(const char* importName); + using WriterAtom::fWriter; + const char* fName; + ObjectFile::Atom& fTarget; + std::vector fReferences; +}; + +template +class LazyPointerAtom : public WriterAtom +{ +public: + LazyPointerAtom(Writer& writer, ObjectFile::Atom& target, + StubAtom& stub, bool forLazyDylib); + virtual const char* getName() const { return fName; } + virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } + virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); } + virtual const char* getSectionName() const { return fForLazyDylib ? "__ld_symbol_ptr" : "__la_symbol_ptr"; } + virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } + virtual void copyRawContent(uint8_t buffer[]) const; + ObjectFile::Atom* getTarget() { return &fExternalTarget; } +private: + using WriterAtom::fWriter; + static const char* lazyPointerName(const char* importName); + const char* fName; + ObjectFile::Atom& fTarget; + ObjectFile::Atom& fExternalTarget; + std::vector fReferences; + bool fForLazyDylib; +}; + + +template +class NonLazyPointerAtom : public WriterAtom +{ +public: + NonLazyPointerAtom(Writer& writer, ObjectFile::Atom& target); + virtual const char* getName() const { return fName; } + virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } + virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); } + virtual const char* getSectionName() const { return "__nl_symbol_ptr"; } + virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } + virtual void copyRawContent(uint8_t buffer[]) const; + ObjectFile::Atom* getTarget() { return &fTarget; } +private: + using WriterAtom::fWriter; + static const char* nonlazyPointerName(const char* importName); + const char* fName; + ObjectFile::Atom& fTarget; + std::vector fReferences; +}; + + +template +class ObjCInfoAtom : public WriterAtom +{ +public: + ObjCInfoAtom(Writer& writer, ObjectFile::Reader::ObjcConstraint objcContraint, + bool objcReplacementClasses); + virtual const char* getName() const { return "objc$info"; } + virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } + virtual uint64_t getSize() const { return 8; } + virtual const char* getSectionName() const; + virtual void copyRawContent(uint8_t buffer[]) const; +private: + Segment& getInfoSegment() const; + uint32_t fContent[2]; +}; + + +template +class WriterReference : public ObjectFile::Reference +{ +public: + typedef typename A::ReferenceKinds Kinds; + + WriterReference(uint32_t offset, Kinds kind, ObjectFile::Atom* target, + uint32_t toOffset=0, ObjectFile::Atom* fromTarget=NULL, uint32_t fromOffset=0) + : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(target), + fTargetOffset(toOffset), fFromTarget(fromTarget), fFromTargetOffset(fromOffset) {} + + virtual ~WriterReference() {} + + virtual ObjectFile::Reference::TargetBinding getTargetBinding() const { return ObjectFile::Reference::kBoundDirectly; } + virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const { return (fFromTarget != NULL) ? ObjectFile::Reference::kBoundDirectly : ObjectFile::Reference::kDontBind; } + virtual uint8_t getKind() const { return (uint8_t)fKind; } + virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; } + virtual const char* getTargetName() const { return fTarget->getName(); } + virtual ObjectFile::Atom& getTarget() const { return *fTarget; } + virtual uint64_t getTargetOffset() const { return fTargetOffset; } + virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget; } + virtual const char* getFromTargetName() const { return fFromTarget->getName(); } + virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fTarget = ⌖ fTargetOffset = offset; } + virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget = ⌖ } + virtual void setFromTargetName(const char* name) { } + virtual void setFromTargetOffset(uint64_t offset) { fFromTargetOffset = offset; } + virtual const char* getDescription() const { return "writer reference"; } + virtual uint64_t getFromTargetOffset() const { return fFromTargetOffset; } + +private: + Kinds fKind; + uint32_t fFixUpOffsetInSrc; + ObjectFile::Atom* fTarget; + uint32_t fTargetOffset; + ObjectFile::Atom* fFromTarget; + uint32_t fFromTargetOffset; +}; + + + +template <> +StubHelperAtom::StubHelperAtom(Writer& writer, ObjectFile::Atom& target, + ObjectFile::Atom& lazyPointer, bool forLazyDylib) + : WriterAtom(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target) +{ + writer.fAllSynthesizedStubHelpers.push_back(this); + + fReferences.push_back(new WriterReference(3, x86_64::kPCRel32, &lazyPointer)); + if ( forLazyDylib ) { + if ( writer.fDyldLazyDylibHelper == NULL ) + throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)"; + fReferences.push_back(new WriterReference(8, x86_64::kPCRel32, writer.fDyldLazyDylibHelper)); + } + else { + if ( writer.fDyldHelper == NULL ) + throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)"; + fReferences.push_back(new WriterReference(8, x86_64::kPCRel32, writer.fDyldHelper)); + } +} + +template <> +uint64_t StubHelperAtom::getSize() const +{ + return 12; +} + +template <> +void StubHelperAtom::copyRawContent(uint8_t buffer[]) const +{ + buffer[0] = 0x4C; // lea foo$lazy_ptr(%rip),%r11 + buffer[1] = 0x8D; + buffer[2] = 0x1D; + buffer[3] = 0x00; + buffer[4] = 0x00; + buffer[5] = 0x00; + buffer[6] = 0x00; + buffer[7] = 0xE9; // jmp dyld_stub_binding_helper + buffer[8] = 0x00; + buffer[9] = 0x00; + buffer[10] = 0x00; + buffer[11] = 0x00; +} + + +template +const char* StubHelperAtom::stubName(const char* name) +{ + char* buf; + asprintf(&buf, "%s$stubHelper", name); + return buf; +} + + +// specialize lazy pointer for x86_64 to initially pointer to stub helper +template <> +LazyPointerAtom::LazyPointerAtom(Writer& writer, ObjectFile::Atom& target, StubAtom& stub, bool forLazyDylib) + : WriterAtom(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target), + fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib) +{ + if ( forLazyDylib ) + writer.fAllSynthesizedLazyDylibPointers.push_back(this); + else + writer.fAllSynthesizedLazyPointers.push_back(this); + + StubHelperAtom* helper = new StubHelperAtom(writer, target, *this, forLazyDylib); + fReferences.push_back(new WriterReference(0, x86_64::kPointer, helper)); +} + +// specialize lazy pointer for x86 to initially pointer to second half of stub +template <> +LazyPointerAtom::LazyPointerAtom(Writer& writer, ObjectFile::Atom& target, StubAtom& stub, bool forLazyDylib) + : WriterAtom(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target), + fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib) +{ + if ( forLazyDylib ) + writer.fAllSynthesizedLazyDylibPointers.push_back(this); + else + writer.fAllSynthesizedLazyPointers.push_back(this); + + // helper part of stub is 14 or 6 bytes into stub + fReferences.push_back(new WriterReference(0, x86::kPointer, &stub, writer.fSlideable ? 14 : 6)); +} + +template +LazyPointerAtom::LazyPointerAtom(Writer& writer, ObjectFile::Atom& target, StubAtom& stub, bool forLazyDylib) + : WriterAtom(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target), + fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib) +{ + if ( forLazyDylib ) + writer.fAllSynthesizedLazyDylibPointers.push_back(this); + else + writer.fAllSynthesizedLazyPointers.push_back(this); + + fReferences.push_back(new WriterReference(0, A::kPointer, &target)); +} + + + +template +const char* LazyPointerAtom::lazyPointerName(const char* name) +{ + char* buf; + asprintf(&buf, "%s$lazy_pointer", name); + return buf; +} + +template +void LazyPointerAtom::copyRawContent(uint8_t buffer[]) const +{ + bzero(buffer, getSize()); +} + + +template +NonLazyPointerAtom::NonLazyPointerAtom(Writer& writer, ObjectFile::Atom& target) + : WriterAtom(writer, Segment::fgDataSegment), fName(nonlazyPointerName(target.getName())), fTarget(target) +{ + writer.fAllSynthesizedNonLazyPointers.push_back(this); + + fReferences.push_back(new WriterReference(0, A::kPointer, &target)); +} + +template +const char* NonLazyPointerAtom::nonlazyPointerName(const char* name) +{ + char* buf; + asprintf(&buf, "%s$non_lazy_pointer", name); + return buf; +} + +template +void NonLazyPointerAtom::copyRawContent(uint8_t buffer[]) const +{ + bzero(buffer, getSize()); +} + + + +template <> +bool StubAtom::pic() const +{ + // no-pic stubs for ppc64 don't work if lazy pointer is above low 2GB. + // Usually that only happens if page zero is very large + return ( fWriter.fSlideable || ((fWriter.fPageZeroAtom != NULL) && (fWriter.fPageZeroAtom->getSize() > 4096)) ); +} + + +template <> +bool StubAtom::pic() const +{ + return fWriter.fSlideable; +} + +template <> +ObjectFile::Alignment StubAtom::getAlignment() const +{ + return 2; +} + +template <> +ObjectFile::Alignment StubAtom::getAlignment() const +{ + return 2; +} + +template <> +ObjectFile::Alignment StubAtom::getAlignment() const +{ + return 2; +} + +template <> +StubAtom::StubAtom(Writer& writer, ObjectFile::Atom& target, bool forLazyDylib) + : WriterAtom(writer, Segment::fgTextSegment), fName(stubName(target.getName())), + fTarget(target), fForLazyDylib(forLazyDylib) +{ + writer.fAllSynthesizedStubs.push_back(this); + LazyPointerAtom* lp; + if ( fWriter.fOptions.prebind() ) { + // for prebound ppc, lazy pointer starts out pointing to target symbol's address + // if target is a weak definition within this linkage unit or zero if in some dylib + lp = new LazyPointerAtom(writer, target, *this, forLazyDylib); + } + else { + // for non-prebound ppc, lazy pointer starts out pointing to dyld_stub_binding_helper glue code + if ( forLazyDylib ) { + if ( writer.fDyldLazyDylibHelper == NULL ) + throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)"; + lp = new LazyPointerAtom(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib); + } + else { + if ( writer.fDyldHelper == NULL ) + throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)"; + lp = new LazyPointerAtom(writer, *writer.fDyldHelper, *this, forLazyDylib); + } + } + if ( pic() ) { + // picbase is 8 bytes into atom + fReferences.push_back(new WriterReference(12, ppc::kPICBaseHigh16, lp, 0, this, 8)); + fReferences.push_back(new WriterReference(20, ppc::kPICBaseLow16, lp, 0, this, 8)); + } + else { + fReferences.push_back(new WriterReference(0, ppc::kAbsHigh16AddLow, lp)); + fReferences.push_back(new WriterReference(4, ppc::kAbsLow16, lp)); + } +} + +template <> +StubAtom::StubAtom(Writer& writer, ObjectFile::Atom& target, bool forLazyDylib) + : WriterAtom(writer, Segment::fgTextSegment), fName(stubName(target.getName())), + fTarget(target), fForLazyDylib(forLazyDylib) +{ + writer.fAllSynthesizedStubs.push_back(this); + + LazyPointerAtom* lp; + if ( forLazyDylib ) { + if ( writer.fDyldLazyDylibHelper == NULL ) + throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)"; + lp = new LazyPointerAtom(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib); + } + else { + if ( writer.fDyldHelper == NULL ) + throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)"; + lp = new LazyPointerAtom(writer, *writer.fDyldHelper, *this, forLazyDylib); + } + if ( pic() ) { + // picbase is 8 bytes into atom + fReferences.push_back(new WriterReference(12, ppc64::kPICBaseHigh16, lp, 0, this, 8)); + fReferences.push_back(new WriterReference(20, ppc64::kPICBaseLow14, lp, 0, this, 8)); + } + else { + fReferences.push_back(new WriterReference(0, ppc64::kAbsHigh16AddLow, lp)); + fReferences.push_back(new WriterReference(4, ppc64::kAbsLow14, lp)); + } +} + +// specialize to put x86 fast stub in __IMPORT segment with no lazy pointer +template <> +StubAtom::StubAtom(Writer& writer, ObjectFile::Atom& target, bool forLazyDylib) + : WriterAtom(writer, (writer.fOptions.slowx86Stubs() || forLazyDylib) ? Segment::fgTextSegment : + ( writer.fOptions.readOnlyx86Stubs() ? Segment::fgROImportSegment : Segment::fgImportSegment)), + fTarget(target), fForLazyDylib(forLazyDylib) +{ + if ( writer.fOptions.slowx86Stubs() || forLazyDylib ) { + fName = stubName(target.getName()); + writer.fAllSynthesizedStubs.push_back(this); + LazyPointerAtom* lp = new LazyPointerAtom(writer, target, *this, forLazyDylib); + ObjectFile::Atom* helper; + if ( forLazyDylib ) { + if ( writer.fDyldLazyDylibHelper == NULL ) + throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)"; + helper = writer.fDyldLazyDylibHelper; + } + else { + if ( writer.fDyldHelper == NULL ) + throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)"; + helper = writer.fDyldHelper; + } + if ( pic() ) { + // picbase is 5 bytes into atom + fReferences.push_back(new WriterReference(8, x86::kPointerDiff, lp, 0, this, 5)); + fReferences.push_back(new WriterReference(16, x86::kPCRel32, helper)); + } + else { + fReferences.push_back(new WriterReference(2, x86::kAbsolute32, lp)); + fReferences.push_back(new WriterReference(7, x86::kAbsolute32, lp)); + fReferences.push_back(new WriterReference(12, x86::kPCRel32, helper)); + } + } + else { + if ( &target == NULL ) + fName = "cache-line-crossing-stub"; + else { + fName = stubName(target.getName()); + writer.fAllSynthesizedStubs.push_back(this); + } + } +} + +template <> +StubAtom::StubAtom(Writer& writer, ObjectFile::Atom& target, bool forLazyDylib) + : WriterAtom(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target) +{ + writer.fAllSynthesizedStubs.push_back(this); + + LazyPointerAtom* lp = new LazyPointerAtom(writer, target, *this, forLazyDylib); + fReferences.push_back(new WriterReference(2, x86_64::kPCRel32, lp)); +} + +template <> +StubAtom::StubAtom(Writer& writer, ObjectFile::Atom& target, bool forLazyDylib) + : WriterAtom(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target) +{ + writer.fAllSynthesizedStubs.push_back(this); + + LazyPointerAtom* lp; + if ( fWriter.fOptions.prebind() && !forLazyDylib ) { + // for prebound arm, lazy pointer starts out pointing to target symbol's address + // if target is a weak definition within this linkage unit or zero if in some dylib + lp = new LazyPointerAtom(writer, target, *this, forLazyDylib); + } + else { + // for non-prebound arm, lazy pointer starts out pointing to dyld_stub_binding_helper glue code + ObjectFile::Atom* helper; + if ( forLazyDylib ) { + if ( writer.fDyldLazyDylibHelper == NULL ) + throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)"; + helper = writer.fDyldLazyDylibHelper; + } + else { + if ( writer.fDyldHelper == NULL ) + throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)"; + helper = writer.fDyldHelper; + } + lp = new LazyPointerAtom(writer, *helper, *this, forLazyDylib); + } + if ( pic() ) + fReferences.push_back(new WriterReference(12, arm::kPointerDiff, lp, 0, this, 12)); + else + fReferences.push_back(new WriterReference(8, arm::kPointer, lp)); +} + +template +const char* StubAtom::stubName(const char* name) +{ + char* buf; + asprintf(&buf, "%s$stub", name); + return buf; +} + +template <> +uint64_t StubAtom::getSize() const +{ + return ( pic() ? 32 : 16 ); +} + +template <> +uint64_t StubAtom::getSize() const +{ + return ( pic() ? 32 : 16 ); +} + + +template <> +uint64_t StubAtom::getSize() const +{ + return ( pic() ? 16 : 12 ); +} + +template <> +uint64_t StubAtom::getSize() const +{ + if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib ) { + if ( pic() ) + return 20; + else + return 16; + } + return 5; +} + +template <> +uint64_t StubAtom::getSize() const +{ + return 6; +} + +template <> +ObjectFile::Alignment StubAtom::getAlignment() const +{ + if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib ) + return 2; + else + return 0; // special case x86 fast stubs to be byte aligned +} + +template <> +void StubAtom::copyRawContent(uint8_t buffer[]) const +{ + if ( pic() ) { + OSWriteBigInt32(&buffer [0], 0, 0x7c0802a6); // mflr r0 + OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase + OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11 + OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase) + OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0 + OSWriteBigInt32(&buffer[20], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11) + OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12 + OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr + } + else { + OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr) + OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr)(r11) + OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12 + OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr + } +} + +template <> +void StubAtom::copyRawContent(uint8_t buffer[]) const +{ + if ( pic() ) { + OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6); // mflr r0 + OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase + OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11 + OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase) + OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0 + OSWriteBigInt32(&buffer[20], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11) + OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12 + OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr + } + else { + OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr) + OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr)(r11) + OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12 + OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr + } +} + +template <> +void StubAtom::copyRawContent(uint8_t buffer[]) const +{ + if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib ) { + if ( pic() ) { + buffer[0] = 0xE8; // call picbase + buffer[1] = 0x00; + buffer[2] = 0x00; + buffer[3] = 0x00; + buffer[4] = 0x00; + buffer[5] = 0x58; // pop eax + buffer[6] = 0x8D; // lea foo$lazy_pointer-picbase(eax),eax + buffer[7] = 0x80; + buffer[8] = 0x00; + buffer[9] = 0x00; + buffer[10] = 0x00; + buffer[11] = 0x00; + buffer[12] = 0xFF; // jmp *(eax) + buffer[13] = 0x20; + buffer[14] = 0x50; // push eax + buffer[15] = 0xE9; // jump dyld_stub_binding_helper + buffer[16] = 0x00; + buffer[17] = 0x00; + buffer[18] = 0x00; + buffer[19] = 0x00; + } + else { + buffer[0] = 0xFF; // jmp *foo$lazy_pointer + buffer[1] = 0x25; + buffer[2] = 0x00; + buffer[3] = 0x00; + buffer[4] = 0x00; + buffer[5] = 0x00; + buffer[6] = 0x68; // pushl $foo$lazy_pointer + buffer[7] = 0x00; + buffer[8] = 0x00; + buffer[9] = 0x00; + buffer[10] = 0x00; + buffer[11] = 0xE9; // jump dyld_stub_binding_helper + buffer[12] = 0x00; + buffer[13] = 0x00; + buffer[14] = 0x00; + buffer[15] = 0x00; + } + } + else { + if ( fWriter.fOptions.prebind() ) { + uint32_t address = this->getAddress(); + int32_t rel32 = 0 - (address+5); + buffer[0] = 0xE9; + buffer[1] = rel32 & 0xFF; + buffer[2] = (rel32 >> 8) & 0xFF; + buffer[3] = (rel32 >> 16) & 0xFF; + buffer[4] = (rel32 >> 24) & 0xFF; + } + else { + buffer[0] = 0xF4; + buffer[1] = 0xF4; + buffer[2] = 0xF4; + buffer[3] = 0xF4; + buffer[4] = 0xF4; + } + } +} + +template <> +void StubAtom::copyRawContent(uint8_t buffer[]) const +{ + buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip) + buffer[1] = 0x25; + buffer[2] = 0x00; + buffer[3] = 0x00; + buffer[4] = 0x00; + buffer[5] = 0x00; +} + +template <> +void StubAtom::copyRawContent(uint8_t buffer[]) const +{ + if ( pic() ) { + OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 12 + OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip + OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); // ldr pc, [ip] + OSWriteLittleInt32(&buffer[12], 0, 0x00000000); // .long L_foo$lazy_ptr - (L1$scv + 8) + } + else { + OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); // ldr ip, [pc, #0] + OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); // ldr pc, [ip] + OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); // .long L_foo$lazy_ptr + } +} + +// x86_64 stubs are 7 bytes and need no alignment +template <> +ObjectFile::Alignment StubAtom::getAlignment() const +{ + return 0; +} + +template <> +const char* StubAtom::getSectionName() const +{ + return ( pic() ? "__picsymbolstub1" : "__symbol_stub1"); +} + +template <> +const char* StubAtom::getSectionName() const +{ + return ( pic() ? "__picsymbolstub1" : "__symbol_stub1"); +} + +template <> +const char* StubAtom::getSectionName() const +{ + return ( pic() ? "__picsymbolstub4" : "__symbol_stub4"); +} + +template <> +const char* StubAtom::getSectionName() const +{ + if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib ) { + if ( pic() ) + return "__picsymbol_stub"; + else + return "__symbol_stub"; + } + return "__jump_table"; +} + + + + +struct AtomByNameSorter +{ + bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right) + { + return (strcmp(left->getName(), right->getName()) < 0); + } +}; + +template +struct ExternalRelocSorter +{ + bool operator()(const macho_relocation_info

& left, const macho_relocation_info

& right) + { + // sort first by symbol number + if ( left.r_symbolnum() != right.r_symbolnum() ) + return (left.r_symbolnum() < right.r_symbolnum()); + // then sort all uses of the same symbol by address + return (left.r_address() < right.r_address()); + } +}; + + +template +Writer::Writer(const char* path, Options& options, std::vector& dynamicLibraries) + : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options), + fAllAtoms(NULL), fStabs(NULL), fLoadCommandsSection(NULL), + fLoadCommandsSegment(NULL), fEncryptionLoadCommand(NULL), fSegmentCommands(NULL), + fSymbolTableCommands(NULL), fHeaderPadding(NULL), + fUUIDAtom(NULL), fPadSegmentInfo(NULL), fEntryPoint( NULL), fDyldHelper(NULL), fDyldLazyDylibHelper(NULL), + fSectionRelocationsAtom(NULL), fLocalRelocationsAtom(NULL), fExternalRelocationsAtom(NULL), + fSymbolTableAtom(NULL), fSplitCodeToDataContentAtom(NULL), fIndirectTableAtom(NULL), fModuleInfoAtom(NULL), + fStringsAtom(NULL), fPageZeroAtom(NULL), fSymbolTable(NULL), fSymbolTableCount(0), fSymbolTableStabsCount(0), + fSymbolTableLocalCount(0), fSymbolTableExportCount(0), fSymbolTableImportCount(0), + fLargestAtomSize(1), + fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false), + fCanScatter(false), fWritableSegmentPastFirst4GB(false), fNoReExportedDylibs(false), + fBiggerThanTwoGigs(false), fSlideable(false), + fFirstWritableSegment(NULL), fAnonNameIndex(1000) +{ + switch ( fOptions.outputKind() ) { + case Options::kDynamicExecutable: + case Options::kStaticExecutable: + if ( fOptions.zeroPageSize() != 0 ) + fWriterSynthesizedAtoms.push_back(fPageZeroAtom = new PageZeroAtom(*this)); + if ( fOptions.outputKind() == Options::kDynamicExecutable ) + fWriterSynthesizedAtoms.push_back(new DsoHandleAtom(*this)); + fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this)); + fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this)); + fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this)); + if ( fOptions.outputKind() == Options::kDynamicExecutable ) + fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom(*this)); + fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom(*this)); + fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom(*this)); + if ( fOptions.hasCustomStack() ) + fWriterSynthesizedAtoms.push_back(new CustomStackAtom(*this)); + fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this)); + fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom(*this)); + fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this)); + fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this)); + fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this)); + fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this)); + fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this)); + break; + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + fWriterSynthesizedAtoms.push_back(new DsoHandleAtom(*this)); + // fall through + case Options::kObjectFile: + fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this)); + fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this)); + if ( fOptions.outputKind() == Options::kDynamicLibrary ) { + fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom(*this)); + if ( fOptions.initFunctionName() != NULL ) + fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom(*this)); + } + fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom(*this)); + fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this)); + if ( fOptions.sharedRegionEligible() ) + fWriterSynthesizedAtoms.push_back(new SegmentSplitInfoLoadCommandsAtom(*this)); + fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this)); + fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom(*this)); + fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this)); + if ( fOptions.sharedRegionEligible() ) { + fWriterSynthesizedAtoms.push_back(fSplitCodeToDataContentAtom = new SegmentSplitInfoContentAtom(*this)); + } + fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this)); + fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this)); + fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this)); + if ( this->needsModuleTable() ) + fWriterSynthesizedAtoms.push_back(fModuleInfoAtom = new ModuleInfoLinkEditAtom(*this)); + fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this)); + break; + case Options::kDyld: + fWriterSynthesizedAtoms.push_back(new DsoHandleAtom(*this)); + fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this)); + fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this)); + fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this)); + fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom(*this)); + fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom(*this)); + fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom(*this)); + fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this)); + fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this)); + fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this)); + fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this)); + fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this)); + fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this)); + break; + } + + // add extra commmands + bool hasReExports = false; + uint32_t ordinal = 1; + switch ( fOptions.outputKind() ) { + case Options::kDynamicExecutable: + if ( fOptions.makeEncryptable() ) { + fEncryptionLoadCommand = new EncryptionLoadCommandsAtom(*this); + fWriterSynthesizedAtoms.push_back(fEncryptionLoadCommand); + } + // fall through + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + { + // add dylib load command atoms for all dynamic libraries + const unsigned int libCount = dynamicLibraries.size(); + for (unsigned int i=0; i < libCount; ++i) { + ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i]; + //fprintf(stderr, "dynamicLibraries[%d]: reader=%p, %s, install=%s\n", i, dylibInfo.reader, dylibInfo.reader->getPath(), dylibInfo.reader->getInstallPath() ); + + if ( dylibInfo.options.fReExport ) { + hasReExports = true; + } + else { + const char* parentUmbrella = dylibInfo.reader->parentUmbrella(); + if ( (parentUmbrella != NULL) && (fOptions.outputKind() == Options::kDynamicLibrary) ) { + const char* thisIDLastSlash = strrchr(fOptions.installPath(), '/'); + if ( (thisIDLastSlash != NULL) && (strcmp(&thisIDLastSlash[1], parentUmbrella) == 0) ) + hasReExports = true; + } + } + + if ( dylibInfo.options.fBundleLoader ) { + fLibraryToOrdinal[dylibInfo.reader] = EXECUTABLE_ORDINAL; + } + else { + // see if a DylibLoadCommandsAtom has already been created for this install path + bool newDylib = true; + const char* dylibInstallPath = dylibInfo.reader->getInstallPath(); + for (unsigned int seenLib=0; seenLib < i; ++seenLib) { + ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib]; + if ( !seenDylibInfo.options.fBundleLoader ) { + const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath(); + if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) { + fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader]; + fLibraryToLoadCommand[dylibInfo.reader] = fLibraryToLoadCommand[seenDylibInfo.reader]; + fLibraryAliases[dylibInfo.reader] = seenDylibInfo.reader; + newDylib = false; + break; + } + } + } + + if ( newDylib ) { + // assign new ordinal and check for other paired load commands + fLibraryToOrdinal[dylibInfo.reader] = ordinal++; + DylibLoadCommandsAtom* dyliblc = new DylibLoadCommandsAtom(*this, dylibInfo); + fLibraryToLoadCommand[dylibInfo.reader] = dyliblc; + fWriterSynthesizedAtoms.push_back(dyliblc); + if ( dylibInfo.options.fReExport + && (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5) + && (fOptions.outputKind() == Options::kDynamicLibrary) ) { + // see if child has sub-framework that is this + bool isSubFramework = false; + const char* childInUmbrella = dylibInfo.reader->parentUmbrella(); + if ( childInUmbrella != NULL ) { + const char* myLeaf = strrchr(fOptions.installPath(), '/'); + if ( myLeaf != NULL ) { + if ( strcmp(childInUmbrella, &myLeaf[1]) == 0 ) + isSubFramework = true; + } + } + // LC_SUB_FRAMEWORK is in child, so do nothing in parent + if ( ! isSubFramework ) { + // this dylib also needs a sub_x load command + bool isFrameworkReExport = false; + const char* lastSlash = strrchr(dylibInstallPath, '/'); + if ( lastSlash != NULL ) { + char frameworkName[strlen(lastSlash)+20]; + sprintf(frameworkName, "/%s.framework/", &lastSlash[1]); + isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL); + } + if ( isFrameworkReExport ) { + // needs a LC_SUB_UMBRELLA command + fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom(*this, &lastSlash[1])); + } + else { + // needs a LC_SUB_LIBRARY command + const char* nameStart = &lastSlash[1]; + if ( lastSlash == NULL ) + nameStart = dylibInstallPath; + int len = strlen(nameStart); + const char* dot = strchr(nameStart, '.'); + if ( dot != NULL ) + len = dot - nameStart; + fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom(*this, nameStart, len)); + } + } + } + } + } + } + // add umbrella command if needed + if ( fOptions.umbrellaName() != NULL ) { + fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom(*this, fOptions.umbrellaName())); + } + // add allowable client commands if used + std::vector& allowableClients = fOptions.allowableClients(); + for (std::vector::iterator it=allowableClients.begin(); it != allowableClients.end(); ++it) + fWriterSynthesizedAtoms.push_back(new AllowableClientLoadCommandsAtom(*this, *it)); + } + break; + case Options::kStaticExecutable: + case Options::kObjectFile: + case Options::kDyld: + break; + } + fNoReExportedDylibs = !hasReExports; + + // add any rpath load commands + for(std::vector::const_iterator it=fOptions.rpaths().begin(); it != fOptions.rpaths().end(); ++it) { + fWriterSynthesizedAtoms.push_back(new RPathLoadCommandsAtom(*this, *it)); + } + + // set up fSlideable + switch ( fOptions.outputKind() ) { + case Options::kObjectFile: + case Options::kStaticExecutable: + fSlideable = false; + break; + case Options::kDynamicExecutable: + fSlideable = fOptions.positionIndependentExecutable(); + break; + case Options::kDyld: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + fSlideable = true; + break; + } + + //fprintf(stderr, "ordinals table:\n"); + //for (std::map::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) { + // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath()); + //} +} + +template +Writer::~Writer() +{ + if ( fFilePath != NULL ) + free((void*)fFilePath); + if ( fSymbolTable != NULL ) + delete [] fSymbolTable; +} + + +// for ppc64, -mdynamic-no-pic only works in low 2GB, so we might need to split the zeropage into two segments +template <>bool Writer::mightNeedPadSegment() { return (fOptions.zeroPageSize() >= 0x80000000ULL); } +template bool Writer::mightNeedPadSegment() { return false; } + + +template +ObjectFile::Atom* Writer::getUndefinedProxyAtom(const char* name) +{ + if ( fOptions.outputKind() == Options::kObjectFile ) { + // when doing -r -exported_symbols_list, don't creat proxy for a symbol + // that is supposed to be exported. We want an error instead + // ld does not report error when -r is used and exported symbols are not defined. + if ( fOptions.hasExportRestrictList() && fOptions.shouldExport(name) ) + return NULL; + else + return new UndefinedSymbolProxyAtom(*this, name); + } + else if ( (fOptions.undefinedTreatment() != Options::kUndefinedError) || fOptions.allowedUndefined(name) ) + return new UndefinedSymbolProxyAtom(*this, name); + else + return NULL; +} + +template +uint8_t Writer::ordinalForLibrary(ObjectFile::Reader* lib) +{ + // flat namespace images use zero for all ordinals + if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace ) + return 0; + + // is an UndefinedSymbolProxyAtom + if ( lib == this ) + if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) + return DYNAMIC_LOOKUP_ORDINAL; + + std::map::iterator pos = fLibraryToOrdinal.find(lib); + if ( pos != fLibraryToOrdinal.end() ) + return pos->second; + + throw "can't find ordinal for imported symbol"; +} + +template +ObjectFile::Atom& Writer::makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, bool objcReplacementClasses) +{ + return *(new ObjCInfoAtom(*this, objcContraint, objcReplacementClasses)); +} + + +template +uint64_t Writer::write(std::vector& atoms, + std::vector& stabs, + class ObjectFile::Atom* entryPointAtom, class ObjectFile::Atom* dyldHelperAtom, + class ObjectFile::Atom* dyldLazyDylibHelperAtom, + bool createUUID, bool canScatter, ObjectFile::Reader::CpuConstraint cpuConstraint, + bool biggerThanTwoGigs, bool overridesDylibWeakDefines) +{ + fAllAtoms = &atoms; + fStabs = &stabs; + fEntryPoint = entryPointAtom; + fDyldHelper = dyldHelperAtom; + fDyldLazyDylibHelper = dyldLazyDylibHelperAtom; + fCanScatter = canScatter; + fCpuConstraint = cpuConstraint; + fBiggerThanTwoGigs = biggerThanTwoGigs; + fHasWeakExports = overridesDylibWeakDefines; // dyld needs to search this image as if it had weak exports + + try { + // Set for create UUID + if (createUUID) + fUUIDAtom->generate(); + + // remove uneeded dylib load commands + optimizeDylibReferences(); + + // check for mdynamic-no-pic codegen + scanForAbsoluteReferences(); + + // create inter-library stubs + synthesizeStubs(); + + // create SegmentInfo and SectionInfo objects and assign all atoms to a section + partitionIntoSections(); + + // segment load command can now be sized and padding can be set + adjustLoadCommandsAndPadding(); + + // assign each section a file offset + assignFileOffsets(); + + // if need to add branch islands, reassign file offsets + if ( addBranchIslands() ) + assignFileOffsets(); + + // build symbol table and relocations + buildLinkEdit(); + + // write map file if requested + writeMap(); + + // write everything + return writeAtoms(); + } catch (...) { + // clean up if any errors + (void)unlink(fFilePath); + throw; + } +} + +template +void Writer::buildLinkEdit() +{ + this->collectExportedAndImportedAndLocalAtoms(); + this->buildSymbolTable(); + this->buildFixups(); + this->adjustLinkEditSections(); +} + + + +template +uint64_t Writer::getAtomLoadAddress(const ObjectFile::Atom* atom) +{ + return atom->getAddress(); +// SectionInfo* info = (SectionInfo*)atom->getSection(); +// return info->getBaseAddress() + atom->getSectionOffset(); +} + + +template <> +const char* Writer::symbolTableName(const ObjectFile::Atom* atom) +{ + static unsigned int counter = 0; + const char* name = atom->getName(); + if ( strncmp(name, "cstring=", 8) == 0 ) + asprintf((char**)&name, "LC%u", counter++); + return name; +} + +template +const char* Writer::symbolTableName(const ObjectFile::Atom* atom) +{ + return atom->getName(); +} + +template +void Writer::setExportNlist(const ObjectFile::Atom* atom, macho_nlist

* entry) +{ + // set n_strx + entry->set_n_strx(this->fStringsAtom->add(this->symbolTableName(atom))); + + // set n_type + if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute ) { + entry->set_n_type(N_EXT | N_ABS); + } + else { + entry->set_n_type(N_EXT | N_SECT); + if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && (fOptions.outputKind() == Options::kObjectFile) ) { + if ( fOptions.keepPrivateExterns() ) + entry->set_n_type(N_EXT | N_SECT | N_PEXT); + } + } + + // set n_sect (section number of implementation ) + uint8_t sectionIndex = atom->getSection()->getIndex(); + entry->set_n_sect(sectionIndex); + + // the __mh_execute_header is magic and must be an absolute symbol + if ( (sectionIndex==0) + && (fOptions.outputKind() == Options::kDynamicExecutable) + && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )) + entry->set_n_type(N_EXT | N_ABS); + + // set n_desc + uint16_t desc = 0; + if ( atom->isThumb() ) + desc |= N_ARM_THUMB_DEF; + if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ) + desc |= REFERENCED_DYNAMICALLY; + if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) { + desc |= N_WEAK_DEF; + fHasWeakExports = true; + } + entry->set_n_desc(desc); + + // set n_value ( address this symbol will be at if this executable is loaded at it preferred address ) + if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol ) + entry->set_n_value(atom->getSectionOffset()); + else + entry->set_n_value(this->getAtomLoadAddress(atom)); +} + +template +void Writer::setImportNlist(const ObjectFile::Atom* atom, macho_nlist

* entry) +{ + // set n_strx + entry->set_n_strx(this->fStringsAtom->add(atom->getName())); + + // set n_type + if ( (fOptions.outputKind() == Options::kObjectFile) + && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) + && (atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition) ) + entry->set_n_type(N_UNDF | N_EXT | N_PEXT); + else if ( fOptions.prebind() ) + entry->set_n_type(N_PBUD | N_EXT); + else + entry->set_n_type(N_UNDF | N_EXT); + + // set n_sect + entry->set_n_sect(0); + + uint16_t desc = 0; + if ( fOptions.outputKind() != Options::kObjectFile ) { + // set n_desc ( high byte is library ordinal, low byte is reference type ) + std::map::iterator pos = fStubsMap.find(atom); + if ( pos != fStubsMap.end() || ( strncmp(atom->getName(), ".objc_class_name_", 17) == 0) ) + desc = REFERENCE_FLAG_UNDEFINED_LAZY; + else + desc = REFERENCE_FLAG_UNDEFINED_NON_LAZY; + try { + uint8_t ordinal = this->ordinalForLibrary(atom->getFile()); + //fprintf(stderr, "ordinal=%u from reader=%p for symbol=%s\n", ordinal, atom->getFile(), atom->getName()); + SET_LIBRARY_ORDINAL(desc, ordinal); + } + catch (const char* msg) { + throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath()); + } + } + else if ( atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition ) { + uint8_t align = atom->getAlignment().powerOf2; + // always record custom alignment of common symbols to match what compiler does + SET_COMM_ALIGN(desc, align); + } + if ( atom->isThumb() ) + desc |= N_ARM_THUMB_DEF; + if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ) + desc |= REFERENCED_DYNAMICALLY; + if ( ( fOptions.outputKind() != Options::kObjectFile) && (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) { + desc |= N_REF_TO_WEAK; + fReferencesWeakImports = true; + } + // set weak_import attribute + if ( fWeakImportMap[atom] ) + desc |= N_WEAK_REF; + entry->set_n_desc(desc); + + // set n_value, zero for import proxy and size for tentative definition + entry->set_n_value(atom->getSize()); +} + + +template +void Writer::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist

* entry) +{ + // set n_strx + const char* symbolName = this->symbolTableName(atom); + char anonName[32]; + if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.keepLocalSymbol(symbolName) ) { + sprintf(anonName, "l%u", fAnonNameIndex++); + symbolName = anonName; + } + entry->set_n_strx(this->fStringsAtom->add(symbolName)); + + // set n_type + uint8_t type = N_SECT; + if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol ) + type = N_ABS; + if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit ) + type |= N_PEXT; + entry->set_n_type(type); + + // set n_sect (section number of implementation ) + uint8_t sectIndex = atom->getSection()->getIndex(); + if ( sectIndex == 0 ) { + // see synthesized lable for mach_header needs special section number... + if ( strcmp(atom->getSectionName(), "._mach_header") == 0 ) + sectIndex = 1; + } + entry->set_n_sect(sectIndex); + + // set n_desc + uint16_t desc = 0; + if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) + desc |= N_WEAK_DEF; + if ( atom->isThumb() ) + desc |= N_ARM_THUMB_DEF; + entry->set_n_desc(desc); + + // set n_value ( address this symbol will be at if this executable is loaded at it preferred address ) + if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol ) + entry->set_n_value(atom->getSectionOffset()); + else + entry->set_n_value(this->getAtomLoadAddress(atom)); +} + + +template +void Writer::addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name) +{ + macho_nlist

entry; + + // set n_strx + entry.set_n_strx(fStringsAtom->add(name)); + + // set n_type + entry.set_n_type(N_SECT); + + // set n_sect (section number of implementation ) + entry.set_n_sect(atom.getSection()->getIndex()); + + // set n_desc + entry.set_n_desc(0); + + // set n_value ( address this symbol will be at if this executable is loaded at it preferred address ) + entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom); + + // add + fLocalExtraLabels.push_back(entry); +} + + + +template +void Writer::addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name) +{ + macho_nlist

entry; + + // set n_strx + entry.set_n_strx(fStringsAtom->add(name)); + + // set n_type + entry.set_n_type(N_SECT|N_EXT); + + // set n_sect (section number of implementation ) + entry.set_n_sect(atom.getSection()->getIndex()); + + // set n_desc + entry.set_n_desc(0); + + // set n_value ( address this symbol will be at if this executable is loaded at it preferred address ) + entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom); + + // add + fGlobalExtraLabels.push_back(entry); +} + +template +void Writer::setNlistRange(std::vector& atoms, uint32_t startIndex, uint32_t count) +{ + macho_nlist

* entry = &fSymbolTable[startIndex]; + for (uint32_t i=0; i < count; ++i, ++entry) { + ObjectFile::Atom* atom = atoms[i]; + if ( &atoms == &fExportedAtoms ) { + this->setExportNlist(atom, entry); + } + else if ( &atoms == &fImportedAtoms ) { + this->setImportNlist(atom, entry); + } + else { + this->setLocalNlist(atom, entry); + } + } +} + +template +void Writer::copyNlistRange(const std::vector >& entries, uint32_t startIndex) +{ + for ( typename std::vector >::const_iterator it = entries.begin(); it != entries.end(); ++it) + fSymbolTable[startIndex++] = *it; +} + + +template +struct NListNameSorter +{ + NListNameSorter(StringsLinkEditAtom* pool) : fStringPool(pool) {} + + bool operator()(const macho_nlist& left, const macho_nlist& right) + { + return (strcmp(fStringPool->stringForIndex(left.n_strx()), fStringPool->stringForIndex(right.n_strx())) < 0); + } +private: + StringsLinkEditAtom* fStringPool; +}; + + +template +void Writer::buildSymbolTable() +{ + fSymbolTableStabsStartIndex = 0; + fSymbolTableStabsCount = fStabs->size(); + fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount; + fSymbolTableLocalCount = fLocalSymbolAtoms.size() + fLocalExtraLabels.size(); + fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount; + fSymbolTableExportCount = fExportedAtoms.size() + fGlobalExtraLabels.size(); + fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount; + fSymbolTableImportCount = fImportedAtoms.size(); + + // allocate symbol table + fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount; + fSymbolTable = new macho_nlist

[fSymbolTableCount]; + + // fill in symbol table and string pool (do stabs last so strings are at end of pool) + setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex, fLocalSymbolAtoms.size()); + if ( fLocalExtraLabels.size() != 0 ) + copyNlistRange(fLocalExtraLabels, fSymbolTableLocalStartIndex+fLocalSymbolAtoms.size()); + setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fExportedAtoms.size()); + if ( fGlobalExtraLabels.size() != 0 ) { + copyNlistRange(fGlobalExtraLabels, fSymbolTableExportStartIndex+fExportedAtoms.size()); + // re-sort combined range + std::sort( &fSymbolTable[fSymbolTableExportStartIndex], + &fSymbolTable[fSymbolTableExportStartIndex+fSymbolTableExportCount], + NListNameSorter(fStringsAtom) ); + } + setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount); + addStabs(fSymbolTableStabsStartIndex); + + // set up module table + if ( fModuleInfoAtom != NULL ) + fModuleInfoAtom->setName(); +} + + + +template +bool Writer::shouldExport(const ObjectFile::Atom& atom) const +{ + switch ( atom.getSymbolTableInclusion() ) { + case ObjectFile::Atom::kSymbolTableNotIn: + return false; + case ObjectFile::Atom::kSymbolTableInAndNeverStrip: + return true; + case ObjectFile::Atom::kSymbolTableInAsAbsolute: + case ObjectFile::Atom::kSymbolTableIn: + switch ( atom.getScope() ) { + case ObjectFile::Atom::scopeGlobal: + return true; + case ObjectFile::Atom::scopeLinkageUnit: + return ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() ); + default: + return false; + } + break; + } + return false; +} + +template +void Writer::collectExportedAndImportedAndLocalAtoms() +{ + const int atomCount = fAllAtoms->size(); + // guess at sizes of each bucket to minimize re-allocations + fImportedAtoms.reserve(100); + fExportedAtoms.reserve(atomCount/2); + fLocalSymbolAtoms.reserve(atomCount); + for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { + ObjectFile::Atom* atom = *it; + // only named atoms go in symbol table + if ( atom->getName() != NULL ) { + // put atom into correct bucket: imports, exports, locals + //fprintf(stderr, "collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName()); + switch ( atom->getDefinitionKind() ) { + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + fImportedAtoms.push_back(atom); + break; + case ObjectFile::Atom::kTentativeDefinition: + if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fMakeTentativeDefinitionsReal ) { + fImportedAtoms.push_back(atom); + break; + } + // else fall into + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + case ObjectFile::Atom::kAbsoluteSymbol: + if ( this->shouldExport(*atom) ) + fExportedAtoms.push_back(atom); + else if ( (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) + && ((fOptions.outputKind() == Options::kObjectFile) || fOptions.keepLocalSymbol(atom->getName())) ) + fLocalSymbolAtoms.push_back(atom); + break; + } + } + // when geneating a .o file, dtrace static probes become local labels + if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fForStatic ) { + std::vector& references = atom->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + ObjectFile::Reference* ref = *rit; + if ( ref->getKind() == A::kDtraceProbe ) { + // dtrace probe points to be add back into generated .o file + this->addLocalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName()); + } + } + } + // when linking kernel, old style dtrace static probes become global labels + else if ( fOptions.readerOptions().fForStatic ) { + std::vector& references = atom->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + ObjectFile::Reference* ref = *rit; + if ( ref->getKind() == A::kDtraceProbe ) { + // dtrace probe points to be add back into generated .o file + this->addGlobalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName()); + } + } + } + } + + // sort exported atoms by name + std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), AtomByNameSorter()); + // sort imported atoms by name (not required by runtime, but helps make generated files binary diffable) + std::sort(fImportedAtoms.begin(), fImportedAtoms.end(), AtomByNameSorter()); +} + + +template +uint64_t Writer::valueForStab(const ObjectFile::Reader::Stab& stab) +{ + switch ( stab.type ) { + case N_FUN: + if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) { + // end of function N_FUN has size + return stab.atom->getSize(); + } + else { + // start of function N_FUN has address + return getAtomLoadAddress(stab.atom); + } + case N_LBRAC: + case N_RBRAC: + case N_SLINE: + if ( stab.atom == NULL ) + // some weird assembly files have slines not associated with a function + return stab.value; + else + // all these stab types need their value changed from an offset in the atom to an address + return getAtomLoadAddress(stab.atom) + stab.value; + case N_STSYM: + case N_LCSYM: + case N_BNSYM: + // all these need address of atom + return getAtomLoadAddress(stab.atom);; + case N_ENSYM: + return stab.atom->getSize(); + case N_SO: + if ( stab.atom == NULL ) { + return 0; + } + else { + if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) { + // end of translation unit N_SO has address of end of last atom + return getAtomLoadAddress(stab.atom) + stab.atom->getSize(); + } + else { + // start of translation unit N_SO has address of end of first atom + return getAtomLoadAddress(stab.atom); + } + } + break; + default: + return stab.value; + } +} + +template +uint32_t Writer::stringOffsetForStab(const ObjectFile::Reader::Stab& stab) +{ + switch (stab.type) { + case N_SO: + if ( (stab.string == NULL) || stab.string[0] == '\0' ) { + return this->fStringsAtom->emptyString(); + break; + } + // fall into uniquing case + case N_SOL: + case N_BINCL: + case N_EXCL: + return this->fStringsAtom->addUnique(stab.string); + break; + default: + if ( stab.string == NULL ) + return 0; + else if ( stab.string[0] == '\0' ) + return this->fStringsAtom->emptyString(); + else + return this->fStringsAtom->add(stab.string); + } + return 0; +} + +template +uint8_t Writer::sectionIndexForStab(const ObjectFile::Reader::Stab& stab) +{ + // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN + if ( stab.type == N_FUN ) + return stab.other; + else if ( stab.atom != NULL ) + return stab.atom->getSection()->getIndex(); + else + return stab.other; +} + +template +void Writer::addStabs(uint32_t startIndex) +{ + macho_nlist

* entry = &fSymbolTable[startIndex]; + for(std::vector::iterator it = fStabs->begin(); it != fStabs->end(); ++it, ++entry) { + const ObjectFile::Reader::Stab& stab = *it; + entry->set_n_type(stab.type); + entry->set_n_sect(sectionIndexForStab(stab)); + entry->set_n_desc(stab.desc); + entry->set_n_value(valueForStab(stab)); + entry->set_n_strx(stringOffsetForStab(stab)); + } +} + + + +template +uint32_t Writer::symbolIndex(ObjectFile::Atom& atom) +{ + // search imports + int i = 0; + for(std::vector::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) { + if ( &atom == *it ) + return i + fSymbolTableImportStartIndex; + ++i; + } + + // search locals + i = 0; + for(std::vector::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) { + if ( &atom == *it ) + return i + fSymbolTableLocalStartIndex; + ++i; + } + + // search exports + i = 0; + for(std::vector::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) { + if ( &atom == *it ) + return i + fSymbolTableExportStartIndex; + ++i; + } + + throwf("atom not found in symbolIndex(%s) for %s", atom.getDisplayName(), atom.getFile()->getPath()); +} + + +template <> +bool Writer::makesExternalRelocatableReference(ObjectFile::Atom& target) const +{ + switch ( target.getSymbolTableInclusion() ) { + case ObjectFile::Atom::kSymbolTableNotIn: + return false; + case ObjectFile::Atom::kSymbolTableInAsAbsolute: + case ObjectFile::Atom::kSymbolTableIn: + case ObjectFile::Atom::kSymbolTableInAndNeverStrip: + return true; + }; + return false; +} + +template +bool Writer::makesExternalRelocatableReference(ObjectFile::Atom& target) const +{ + switch ( target.getDefinitionKind() ) { + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + case ObjectFile::Atom::kAbsoluteSymbol: + return false; + case ObjectFile::Atom::kTentativeDefinition: + if ( fOptions.readerOptions().fMakeTentativeDefinitionsReal ) + return false; + else + return (target.getScope() != ObjectFile::Atom::scopeTranslationUnit); + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + return shouldExport(target); + } + return false; +} + +template +void Writer::buildFixups() +{ + if ( fOptions.outputKind() == Options::kObjectFile ) { + this->buildObjectFileFixups(); + } + else { + if ( fOptions.keepRelocations() ) + this->buildObjectFileFixups(); + this->buildExecutableFixups(); + } +} + +template <> +uint32_t Writer::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref) +{ + ObjectFile::Atom& target = ref->getTarget(); + bool external = this->makesExternalRelocatableReference(target); + uint32_t symbolIndex = external ? this->symbolIndex(target) : target.getSection()->getIndex(); + uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset(); + macho_relocation_info

reloc1; + macho_relocation_info

reloc2; + x86_64::ReferenceKinds kind = (x86_64::ReferenceKinds)ref->getKind(); + + switch ( kind ) { + case x86_64::kNoFixUp: + case x86_64::kFollowOn: + case x86_64::kGroupSubordinate: + return 0; + + case x86_64::kPointer: + case x86_64::kPointerWeakImport: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolIndex); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(3); + reloc1.set_r_extern(external); + reloc1.set_r_type(X86_64_RELOC_UNSIGNED); + fSectionRelocs.push_back(reloc1); + return 1; + + case x86_64::kPointerDiff32: + case x86_64::kPointerDiff: + { + ObjectFile::Atom& fromTarget = ref->getFromTarget(); + bool fromExternal = (fromTarget.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn); + uint32_t fromSymbolIndex = fromExternal ? this->symbolIndex(fromTarget) : fromTarget.getSection()->getIndex(); + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolIndex); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3); + reloc1.set_r_extern(external); + reloc1.set_r_type(X86_64_RELOC_UNSIGNED); + reloc2.set_r_address(address); + reloc2.set_r_symbolnum(fromSymbolIndex); + reloc2.set_r_pcrel(false); + reloc2.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3); + reloc2.set_r_extern(fromExternal); + reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR); + fSectionRelocs.push_back(reloc1); + fSectionRelocs.push_back(reloc2); + return 2; + } + + case x86_64::kBranchPCRel32: + case x86_64::kBranchPCRel32WeakImport: + case x86_64::kDtraceProbeSite: + case x86_64::kDtraceIsEnabledSite: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolIndex); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(X86_64_RELOC_BRANCH); + fSectionRelocs.push_back(reloc1); + return 1; + + case x86_64::kPCRel32: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolIndex); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(X86_64_RELOC_SIGNED); + fSectionRelocs.push_back(reloc1); + return 1; + + case x86_64::kPCRel32_1: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolIndex); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(X86_64_RELOC_SIGNED_1); + fSectionRelocs.push_back(reloc1); + return 1; + + case x86_64::kPCRel32_2: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolIndex); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(X86_64_RELOC_SIGNED_2); + fSectionRelocs.push_back(reloc1); + return 1; + + case x86_64::kPCRel32_4: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolIndex); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(X86_64_RELOC_SIGNED_4); + fSectionRelocs.push_back(reloc1); + return 1; + + case x86_64::kBranchPCRel8: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolIndex); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(0); + reloc1.set_r_extern(external); + reloc1.set_r_type(X86_64_RELOC_BRANCH); + fSectionRelocs.push_back(reloc1); + return 1; + + case x86_64::kPCRel32GOT: + case x86_64::kPCRel32GOTWeakImport: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolIndex); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(X86_64_RELOC_GOT); + fSectionRelocs.push_back(reloc1); + return 1; + + case x86_64::kPCRel32GOTLoad: + case x86_64::kPCRel32GOTLoadWeakImport: + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(symbolIndex); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_extern(external); + reloc1.set_r_type(X86_64_RELOC_GOT_LOAD); + fSectionRelocs.push_back(reloc1); + return 1; + + case x86_64::kDtraceTypeReference: + case x86_64::kDtraceProbe: + // generates no relocs + return 0; + } + return 0; +} + + +template <> +uint32_t Writer::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref) +{ + ObjectFile::Atom& target = ref->getTarget(); + bool isExtern = this->makesExternalRelocatableReference(target); + uint32_t symbolIndex = 0; + if ( isExtern ) + symbolIndex = this->symbolIndex(target); + uint32_t sectionNum = target.getSection()->getIndex(); + uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset(); + macho_relocation_info

reloc1; + macho_relocation_info

reloc2; + macho_scattered_relocation_info

* sreloc1 = (macho_scattered_relocation_info

*)&reloc1; + macho_scattered_relocation_info

* sreloc2 = (macho_scattered_relocation_info

*)&reloc2; + x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind(); + + if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) ) + warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s", + target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath()); + + + switch ( kind ) { + case x86::kNoFixUp: + case x86::kFollowOn: + case x86::kGroupSubordinate: + return 0; + + case x86::kPointer: + case x86::kPointerWeakImport: + case x86::kAbsolute32: + if ( !isExtern && (ref->getTargetOffset() != 0) ) { + // use scattered reloc is target offset is non-zero + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(false); + sreloc1->set_r_length(2); + sreloc1->set_r_type(GENERIC_RELOC_VANILLA); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + } + else { + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(2); + reloc1.set_r_extern(isExtern); + reloc1.set_r_type(GENERIC_RELOC_VANILLA); + } + fSectionRelocs.push_back(reloc1); + return 1; + + case x86::kPointerDiff16: + case x86::kPointerDiff: + { + //pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset(); + //fprintf(stderr, "addObjectRelocs(): refFromTarget=%s, refTarget=%s, refFromTargetAddr=0x%llX, refFromTargetOffset=0x%llX\n", + // ref->getFromTarget().getDisplayName(), ref->getTarget().getDisplayName(), + // ref->getFromTarget().getAddress(), ref->getFromTargetOffset()); + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(false); + sreloc1->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 ); + if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit ) + sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF); + else + sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + sreloc2->set_r_scattered(true); + sreloc2->set_r_pcrel(false); + sreloc2->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 ); + sreloc2->set_r_type(GENERIC_RELOC_PAIR); + sreloc2->set_r_address(0); + sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset()); + fSectionRelocs.push_back(reloc2); + fSectionRelocs.push_back(reloc1); + return 2; + } + + case x86::kPCRel32WeakImport: + case x86::kPCRel32: + case x86::kPCRel16: + case x86::kPCRel8: + case x86::kDtraceProbeSite: + case x86::kDtraceIsEnabledSite: + if ( !isExtern && (ref->getTargetOffset() != 0) ) { + // use scattered reloc is target offset is non-zero + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(true); + sreloc1->set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) ); + sreloc1->set_r_type(GENERIC_RELOC_VANILLA); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + } + else { + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum); + reloc1.set_r_pcrel(true); + reloc1.set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) ); + reloc1.set_r_extern(isExtern); + reloc1.set_r_type(GENERIC_RELOC_VANILLA); + } + fSectionRelocs.push_back(reloc1); + return 1; + + case x86::kDtraceTypeReference: + case x86::kDtraceProbe: + // generates no relocs + return 0; + + } + return 0; +} + +template <> +uint32_t Writer::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref) +{ + ObjectFile::Atom& target = ref->getTarget(); + bool isExtern = this->makesExternalRelocatableReference(target); + uint32_t symbolIndex = 0; + if ( isExtern ) + symbolIndex = this->symbolIndex(target); + uint32_t sectionNum = target.getSection()->getIndex(); + uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset(); + macho_relocation_info

reloc1; + macho_relocation_info

reloc2; + macho_scattered_relocation_info

* sreloc1 = (macho_scattered_relocation_info

*)&reloc1; + macho_scattered_relocation_info

* sreloc2 = (macho_scattered_relocation_info

*)&reloc2; + arm::ReferenceKinds kind = (arm::ReferenceKinds)ref->getKind(); + + if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) ) + warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s", + target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath()); + + + switch ( kind ) { + case arm::kNoFixUp: + case arm::kFollowOn: + case arm::kGroupSubordinate: + return 0; + + case arm::kPointer: + case arm::kReadOnlyPointer: + case arm::kPointerWeakImport: + if ( !isExtern && (ref->getTargetOffset() != 0) ) { + // use scattered reloc is target offset is non-zero + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(false); + sreloc1->set_r_length(2); + sreloc1->set_r_type(ARM_RELOC_VANILLA); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + } + else { + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(2); + reloc1.set_r_extern(isExtern); + reloc1.set_r_type(ARM_RELOC_VANILLA); + } + fSectionRelocs.push_back(reloc1); + return 1; + + case arm::kPointerDiff: + { + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(false); + sreloc1->set_r_length(2); + if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit ) + sreloc1->set_r_type(ARM_RELOC_LOCAL_SECTDIFF); + else + sreloc1->set_r_type(ARM_RELOC_SECTDIFF); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + sreloc2->set_r_scattered(true); + sreloc2->set_r_pcrel(false); + sreloc2->set_r_length(2); + sreloc2->set_r_type(ARM_RELOC_PAIR); + sreloc2->set_r_address(0); + sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset()); + fSectionRelocs.push_back(reloc2); + fSectionRelocs.push_back(reloc1); + return 2; + } + + case arm::kBranch24WeakImport: + case arm::kBranch24: + case arm::kDtraceProbeSite: + case arm::kDtraceIsEnabledSite: + if ( !isExtern && (ref->getTargetOffset() != 0) ) { + // use scattered reloc is target offset is non-zero + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(true); + sreloc1->set_r_length(2); + sreloc1->set_r_type(ARM_RELOC_BR24); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + } + else { + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_extern(isExtern); + reloc1.set_r_type(ARM_RELOC_BR24); + } + fSectionRelocs.push_back(reloc1); + return 1; + + case arm::kThumbBranch22WeakImport: + case arm::kThumbBranch22: + if ( !isExtern && (ref->getTargetOffset() != 0) ) { + // use scattered reloc is target offset is non-zero + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(true); + sreloc1->set_r_length(2); + sreloc1->set_r_type(ARM_THUMB_RELOC_BR22); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + } + else { + reloc1.set_r_address(address); + reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_extern(isExtern); + reloc1.set_r_type(ARM_THUMB_RELOC_BR22); + } + fSectionRelocs.push_back(reloc1); + return 1; + + case arm::kDtraceTypeReference: + case arm::kDtraceProbe: + // generates no relocs + return 0; + + } + return 0; +} + +template <> uint64_t Writer::maxAddress() { return 0xFFFFFFFFULL; } +template <> uint64_t Writer::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; } +template <> uint64_t Writer::maxAddress() { return 0xFFFFFFFFULL; } +template <> uint64_t Writer::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; } +template <> uint64_t Writer::maxAddress() { return 0xFFFFFFFFULL; } + +template <> +uint8_t Writer::getRelocPointerSize() +{ + return 2; +} + +template <> +uint8_t Writer::getRelocPointerSize() +{ + return 3; +} + +template <> +uint32_t Writer::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref) +{ + return addObjectRelocs_powerpc(atom, ref); +} + +template <> +uint32_t Writer::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref) +{ + return addObjectRelocs_powerpc(atom, ref); +} + +// +// addObjectRelocs and addObjectRelocs are almost exactly the same, so +// they use a common addObjectRelocs_powerpc() method. +// +template +uint32_t Writer::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref) +{ + ObjectFile::Atom& target = ref->getTarget(); + bool isExtern = this->makesExternalRelocatableReference(target); + uint32_t symbolIndex = 0; + if ( isExtern ) + symbolIndex = this->symbolIndex(target); + uint32_t sectionNum = target.getSection()->getIndex(); + uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset(); + macho_relocation_info

reloc1; + macho_relocation_info

reloc2; + macho_scattered_relocation_info

* sreloc1 = (macho_scattered_relocation_info

*)&reloc1; + macho_scattered_relocation_info

* sreloc2 = (macho_scattered_relocation_info

*)&reloc2; + typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind(); + + switch ( kind ) { + case A::kNoFixUp: + case A::kFollowOn: + case A::kGroupSubordinate: + return 0; + + case A::kPointer: + case A::kPointerWeakImport: + if ( !isExtern && (ref->getTargetOffset() >= target.getSize()) ) { + // use scattered reloc is target offset is outside target + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(false); + sreloc1->set_r_length(getRelocPointerSize()); + sreloc1->set_r_type(GENERIC_RELOC_VANILLA); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + } + else { + reloc1.set_r_address(address); + if ( isExtern ) + reloc1.set_r_symbolnum(symbolIndex); + else + reloc1.set_r_symbolnum(sectionNum); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(getRelocPointerSize()); + reloc1.set_r_extern(isExtern); + reloc1.set_r_type(GENERIC_RELOC_VANILLA); + } + fSectionRelocs.push_back(reloc1); + return 1; + + case A::kPointerDiff16: + case A::kPointerDiff32: + case A::kPointerDiff64: + { + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(false); + sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : ((kind == A::kPointerDiff64) ? 3 : 1)); + if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit ) + sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF); + else + sreloc1->set_r_type(PPC_RELOC_SECTDIFF); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + sreloc2->set_r_scattered(true); + sreloc2->set_r_pcrel(false); + sreloc2->set_r_length(sreloc1->r_length()); + sreloc2->set_r_type(PPC_RELOC_PAIR); + sreloc2->set_r_address(0); + sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset()); + fSectionRelocs.push_back(reloc2); + fSectionRelocs.push_back(reloc1); + return 2; + } + + case A::kBranch24WeakImport: + case A::kBranch24: + case A::kDtraceProbeSite: + case A::kDtraceIsEnabledSite: + if ( (ref->getTargetOffset() == 0) || isExtern ) { + reloc1.set_r_address(address); + if ( isExtern ) + reloc1.set_r_symbolnum(symbolIndex); + else + reloc1.set_r_symbolnum(sectionNum); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_type(PPC_RELOC_BR24); + reloc1.set_r_extern(isExtern); + } + else { + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(true); + sreloc1->set_r_length(2); + sreloc1->set_r_type(PPC_RELOC_BR24); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + } + fSectionRelocs.push_back(reloc1); + return 1; + + case A::kBranch14: + if ( (ref->getTargetOffset() == 0) || isExtern ) { + reloc1.set_r_address(address); + if ( isExtern ) + reloc1.set_r_symbolnum(symbolIndex); + else + reloc1.set_r_symbolnum(sectionNum); + reloc1.set_r_pcrel(true); + reloc1.set_r_length(2); + reloc1.set_r_type(PPC_RELOC_BR14); + reloc1.set_r_extern(isExtern); + } + else { + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(true); + sreloc1->set_r_length(2); + sreloc1->set_r_type(PPC_RELOC_BR14); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + } + fSectionRelocs.push_back(reloc1); + return 1; + + case A::kPICBaseLow16: + case A::kPICBaseLow14: + { + pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset(); + pint_t toAddr = target.getAddress() + ref->getTargetOffset(); + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(false); + sreloc1->set_r_length(2); + sreloc1->set_r_type(kind == A::kPICBaseLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + sreloc2->set_r_scattered(true); + sreloc2->set_r_pcrel(false); + sreloc2->set_r_length(2); + sreloc2->set_r_type(PPC_RELOC_PAIR); + sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF); + sreloc2->set_r_value(fromAddr); + fSectionRelocs.push_back(reloc2); + fSectionRelocs.push_back(reloc1); + return 2; + } + + case A::kPICBaseHigh16: + { + pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset(); + pint_t toAddr = target.getAddress() + ref->getTargetOffset(); + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(false); + sreloc1->set_r_length(2); + sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + sreloc2->set_r_scattered(true); + sreloc2->set_r_pcrel(false); + sreloc2->set_r_length(2); + sreloc2->set_r_type(PPC_RELOC_PAIR); + sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF); + sreloc2->set_r_value(fromAddr); + fSectionRelocs.push_back(reloc2); + fSectionRelocs.push_back(reloc1); + return 2; + } + + case A::kAbsLow14: + case A::kAbsLow16: + { + pint_t toAddr = target.getAddress() + ref->getTargetOffset(); + if ( (ref->getTargetOffset() == 0) || isExtern ) { + reloc1.set_r_address(address); + if ( isExtern ) + reloc1.set_r_symbolnum(symbolIndex); + else + reloc1.set_r_symbolnum(sectionNum); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(2); + reloc1.set_r_extern(isExtern); + reloc1.set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14); + } + else { + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(false); + sreloc1->set_r_length(2); + sreloc1->set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + } + if ( isExtern ) + reloc2.set_r_address(ref->getTargetOffset() >> 16); + else + reloc2.set_r_address(toAddr >> 16); + reloc2.set_r_symbolnum(0); + reloc2.set_r_pcrel(false); + reloc2.set_r_length(2); + reloc2.set_r_extern(false); + reloc2.set_r_type(PPC_RELOC_PAIR); + fSectionRelocs.push_back(reloc2); + fSectionRelocs.push_back(reloc1); + return 2; + } + + case A::kAbsHigh16: + { + pint_t toAddr = target.getAddress() + ref->getTargetOffset(); + if ( (ref->getTargetOffset() == 0) || isExtern ) { + reloc1.set_r_address(address); + if ( isExtern ) + reloc1.set_r_symbolnum(symbolIndex); + else + reloc1.set_r_symbolnum(sectionNum); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(2); + reloc1.set_r_extern(isExtern); + reloc1.set_r_type(PPC_RELOC_HI16); + } + else { + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(false); + sreloc1->set_r_length(2); + sreloc1->set_r_type(PPC_RELOC_HI16); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + } + if ( isExtern ) + reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF); + else + reloc2.set_r_address(toAddr & 0xFFFF); + reloc2.set_r_symbolnum(0); + reloc2.set_r_pcrel(false); + reloc2.set_r_length(2); + reloc2.set_r_extern(false); + reloc2.set_r_type(PPC_RELOC_PAIR); + fSectionRelocs.push_back(reloc2); + fSectionRelocs.push_back(reloc1); + return 2; + } + + case A::kAbsHigh16AddLow: + { + pint_t toAddr = target.getAddress() + ref->getTargetOffset(); + uint32_t overflow = 0; + if ( (toAddr & 0x00008000) != 0 ) + overflow = 0x10000; + if ( (ref->getTargetOffset() == 0) || isExtern ) { + reloc1.set_r_address(address); + if ( isExtern ) + reloc1.set_r_symbolnum(symbolIndex); + else + reloc1.set_r_symbolnum(sectionNum); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(2); + reloc1.set_r_extern(isExtern); + reloc1.set_r_type(PPC_RELOC_HA16); + } + else { + sreloc1->set_r_scattered(true); + sreloc1->set_r_pcrel(false); + sreloc1->set_r_length(2); + sreloc1->set_r_type(PPC_RELOC_HA16); + sreloc1->set_r_address(address); + sreloc1->set_r_value(target.getAddress()); + } + if ( isExtern ) + reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF); + else + reloc2.set_r_address(toAddr & 0xFFFF); + reloc2.set_r_symbolnum(0); + reloc2.set_r_pcrel(false); + reloc2.set_r_length(2); + reloc2.set_r_extern(false); + reloc2.set_r_type(PPC_RELOC_PAIR); + fSectionRelocs.push_back(reloc2); + fSectionRelocs.push_back(reloc1); + return 2; + } + + case A::kDtraceTypeReference: + case A::kDtraceProbe: + // generates no relocs + return 0; + } + return 0; +} + + + +// +// There are cases when an entry in the indirect symbol table is the magic value +// INDIRECT_SYMBOL_LOCAL instead of being a symbol index. When that happens +// the content of the corresponding part of the __nl_symbol_pointer section +// must also change. +// +template +bool Writer::indirectSymbolIsLocal(const ObjectFile::Reference* ref) const +{ + // use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend + return ( !this->shouldExport(ref->getTarget()) || (ref->getTargetOffset() != 0) ); +} + + +template +void Writer::buildObjectFileFixups() +{ + uint32_t relocIndex = 0; + std::vector& segmentInfos = fSegmentInfos; + const int segCount = segmentInfos.size(); + for(int i=0; i < segCount; ++i) { + SegmentInfo* curSegment = segmentInfos[i]; + std::vector& sectionInfos = curSegment->fSections; + const int sectionCount = sectionInfos.size(); + for(int j=0; j < sectionCount; ++j) { + SectionInfo* curSection = sectionInfos[j]; + //fprintf(stderr, "buildObjectFileFixups(): starting section %s\n", curSection->fSectionName); + std::vector& sectionAtoms = curSection->fAtoms; + if ( ! curSection->fAllZeroFill ) { + if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers + || curSection->fAllLazyDylibPointers || curSection->fAllStubs ) + curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size(); + curSection->fRelocOffset = relocIndex; + const int atomCount = sectionAtoms.size(); + for (int k=0; k < atomCount; ++k) { + ObjectFile::Atom* atom = sectionAtoms[k]; + //fprintf(stderr, "buildObjectFileFixups(): atom %s\n", atom->getDisplayName()); + std::vector& refs = atom->getReferences(); + const int refCount = refs.size(); + for (int l=0; l < refCount; ++l) { + ObjectFile::Reference* ref = refs[l]; + if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers + || curSection->fAllLazyDylibPointers || curSection->fAllStubs ) { + uint32_t offsetInSection = atom->getSectionOffset(); + uint32_t indexInSection = offsetInSection / atom->getSize(); + uint32_t undefinedSymbolIndex; + if ( curSection->fAllStubs ) { + ObjectFile::Atom& stubTarget =ref->getTarget(); + ObjectFile::Atom& stubTargetTarget = stubTarget.getReferences()[0]->getTarget(); + undefinedSymbolIndex = this->symbolIndex(stubTargetTarget); + //fprintf(stderr, "stub %s ==> %s ==> %s ==> index:%u\n", atom->getDisplayName(), stubTarget.getDisplayName(), stubTargetTarget.getDisplayName(), undefinedSymbolIndex); + } + else if ( curSection->fAllNonLazyPointers) { + // only use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend + if ( this->indirectSymbolIsLocal(ref) ) + undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL; + else + undefinedSymbolIndex = this->symbolIndex(ref->getTarget()); + } + else { + // should never get here, fAllLazyPointers not used in generated .o files + undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL; + } + uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset; + IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex }; + //printf("fIndirectTableAtom->fTable.add(sectionIndex=%u, indirectTableIndex=%u => %u), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, atom->getSize()); + fIndirectTableAtom->fTable.push_back(entry); + if ( curSection->fAllLazyPointers ) { + ObjectFile::Atom& target = ref->getTarget(); + ObjectFile::Atom& fromTarget = ref->getFromTarget(); + if ( &fromTarget == NULL ) { + warning("lazy pointer %s missing initial binding", atom->getDisplayName()); + } + else { + bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition) + || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition)) + && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) ); + macho_relocation_info

reloc1; + reloc1.set_r_address(atom->getSectionOffset()); + reloc1.set_r_symbolnum(isExtern ? this->symbolIndex(target) : target.getSection()->getIndex()); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(); + reloc1.set_r_extern(isExtern); + reloc1.set_r_type(GENERIC_RELOC_VANILLA); + fSectionRelocs.push_back(reloc1); + ++relocIndex; + } + } + else if ( curSection->fAllStubs ) { + relocIndex += this->addObjectRelocs(atom, ref); + } + } + else if ( (ref->getKind() != A::kNoFixUp) && (ref->getTargetBinding() != ObjectFile::Reference::kDontBind) ) { + relocIndex += this->addObjectRelocs(atom, ref); + } + } + } + curSection->fRelocCount = relocIndex - curSection->fRelocOffset; + } + } + } + + // reverse the relocs + std::reverse(fSectionRelocs.begin(), fSectionRelocs.end()); + + // now reverse section reloc offsets + for(int i=0; i < segCount; ++i) { + SegmentInfo* curSegment = segmentInfos[i]; + std::vector& sectionInfos = curSegment->fSections; + const int sectionCount = sectionInfos.size(); + for(int j=0; j < sectionCount; ++j) { + SectionInfo* curSection = sectionInfos[j]; + curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount; + } + } + +} + +template <> +bool Writer::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref) +{ + switch ( ref.getKind() ) { + case ppc::kAbsLow16: + case ppc::kAbsLow14: + case ppc::kAbsHigh16: + case ppc::kAbsHigh16AddLow: + if ( fSlideable ) + return true; + } + return false; +} + + +template <> +bool Writer::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref) +{ + switch ( ref.getKind() ) { + case ppc::kAbsLow16: + case ppc::kAbsLow14: + case ppc::kAbsHigh16: + case ppc::kAbsHigh16AddLow: + if ( fSlideable ) + return true; + } + return false; +} + +template <> +bool Writer::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref) +{ + if ( ref.getKind() == x86::kAbsolute32 ) { + switch ( ref.getTarget().getDefinitionKind() ) { + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + // illegal in dylibs/bundles, until we support TEXT relocs + return fSlideable; + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + // illegal until we support TEXT relocs + return true; + case ObjectFile::Atom::kAbsoluteSymbol: + // absolute symbbols only allowed in static executables + return ( fOptions.outputKind() != Options::kStaticExecutable); + } + } + return false; +} + +template <> +bool Writer::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref) +{ + return false; +} + +template <> +bool Writer::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref) +{ + if ( ref.getKind() == arm::kReadOnlyPointer ) { + switch ( ref.getTarget().getDefinitionKind() ) { + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + // illegal in dylibs/bundles, until we support TEXT relocs + return fSlideable; + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + // illegal until we support TEXT relocs + return true; + case ObjectFile::Atom::kAbsoluteSymbol: + // absolute symbbols only allowed in static executables + return ( fOptions.outputKind() != Options::kStaticExecutable); + } + } + return false; +} + +template <> +bool Writer::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection) +{ + if ( ref.getKind() == x86::kAbsolute32 ) { + switch ( ref.getTarget().getDefinitionKind() ) { + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + // a reference to the absolute address of something in this same linkage unit can be + // encoded as a local text reloc in a dylib or bundle + if ( fSlideable ) { + macho_relocation_info

reloc; + SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection()); + reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom)); + reloc.set_r_symbolnum(sectInfo->getIndex()); + reloc.set_r_pcrel(false); + reloc.set_r_length(); + reloc.set_r_extern(false); + reloc.set_r_type(GENERIC_RELOC_VANILLA); + fInternalRelocs.push_back(reloc); + atomSection->fHasTextLocalRelocs = true; + return true; + } + return false; + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + case ObjectFile::Atom::kAbsoluteSymbol: + return false; + } + } + return false; +} + +template <> +bool Writer::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection) +{ + macho_relocation_info

reloc1; + macho_relocation_info

reloc2; + switch ( ref.getTarget().getDefinitionKind() ) { + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + switch ( ref.getKind() ) { + case ppc::kAbsLow16: + case ppc::kAbsLow14: + // a reference to the absolute address of something in this same linkage unit can be + // encoded as a local text reloc in a dylib or bundle + if ( fSlideable ) { + SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection()); + uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset(); + reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom)); + reloc1.set_r_symbolnum(sectInfo->getIndex()); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(2); + reloc1.set_r_extern(false); + reloc1.set_r_type(ref.getKind()==ppc::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14); + reloc2.set_r_address(targetAddr >> 16); + reloc2.set_r_symbolnum(0); + reloc2.set_r_pcrel(false); + reloc2.set_r_length(2); + reloc2.set_r_extern(false); + reloc2.set_r_type(PPC_RELOC_PAIR); + fInternalRelocs.push_back(reloc1); + fInternalRelocs.push_back(reloc2); + atomSection->fHasTextLocalRelocs = true; + return true; + } + break; + case ppc::kAbsHigh16: + case ppc::kAbsHigh16AddLow: + if ( fSlideable ) { + SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection()); + uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset(); + reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom)); + reloc1.set_r_symbolnum(sectInfo->getIndex()); + reloc1.set_r_pcrel(false); + reloc1.set_r_length(2); + reloc1.set_r_extern(false); + reloc1.set_r_type(ref.getKind()==ppc::kAbsHigh16AddLow ? PPC_RELOC_HA16 : PPC_RELOC_HI16); + reloc2.set_r_address(targetAddr & 0xFFFF); + reloc2.set_r_symbolnum(0); + reloc2.set_r_pcrel(false); + reloc2.set_r_length(2); + reloc2.set_r_extern(false); + reloc2.set_r_type(PPC_RELOC_PAIR); + fInternalRelocs.push_back(reloc1); + fInternalRelocs.push_back(reloc2); + atomSection->fHasTextLocalRelocs = true; + return true; + } + } + break; + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + case ObjectFile::Atom::kAbsoluteSymbol: + return false; + } + return false; +} + +template <> +bool Writer::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection) +{ + if ( ref.getKind() == arm::kReadOnlyPointer ) { + switch ( ref.getTarget().getDefinitionKind() ) { + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + // a reference to the absolute address of something in this same linkage unit can be + // encoded as a local text reloc in a dylib or bundle + if ( fSlideable ) { + macho_relocation_info

reloc; + SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection()); + reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom)); + reloc.set_r_symbolnum(sectInfo->getIndex()); + reloc.set_r_pcrel(false); + reloc.set_r_length(); + reloc.set_r_extern(false); + reloc.set_r_type(GENERIC_RELOC_VANILLA); + fInternalRelocs.push_back(reloc); + atomSection->fHasTextLocalRelocs = true; + return true; + } + return false; + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + case ObjectFile::Atom::kAbsoluteSymbol: + return false; + } + } + return false; +} + + +template <> +bool Writer::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection) +{ + // text relocs not supported (usually never needed because of RIP addressing) + return false; +} + +template <> +bool Writer::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection) +{ + // text relocs not supported + return false; +} + +template <> +bool Writer::generatesExternalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection) +{ + if ( ref.getKind() == x86::kAbsolute32 ) { + macho_relocation_info

reloc; + switch ( ref.getTarget().getDefinitionKind() ) { + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + return false; + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + // a reference to the absolute address of something in another linkage unit can be + // encoded as an external text reloc in a dylib or bundle + reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom)); + reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget())); + reloc.set_r_pcrel(false); + reloc.set_r_length(); + reloc.set_r_extern(true); + reloc.set_r_type(GENERIC_RELOC_VANILLA); + fExternalRelocs.push_back(reloc); + atomSection->fHasTextExternalRelocs = true; + return true; + case ObjectFile::Atom::kAbsoluteSymbol: + return false; + } + } + return false; +} + +template +bool Writer::generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection) +{ + return false; +} + + + + +template +typename Writer::RelocKind Writer::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const +{ + switch ( target.getDefinitionKind() ) { + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + // in main executables, the only way regular symbols are indirected is if -interposable is used + if ( fOptions.outputKind() == Options::kDynamicExecutable ) { + if ( this->shouldExport(target) && fOptions.interposable(target.getName()) ) + return kRelocExternal; + else if ( fSlideable ) + return kRelocInternal; + else + return kRelocNone; + } + // for flat-namespace or interposable two-level-namespace + // all references to exported symbols get indirected + else if ( this->shouldExport(target) && + ((fOptions.nameSpace() == Options::kFlatNameSpace) + || (fOptions.nameSpace() == Options::kForceFlatNameSpace) + || fOptions.interposable(target.getName())) + && (target.getName() != NULL) + && (strncmp(target.getName(), ".objc_class_", 12) != 0) ) // + return kRelocExternal; + else if ( fSlideable ) + return kRelocInternal; + else + return kRelocNone; + case ObjectFile::Atom::kWeakDefinition: + // all calls to global weak definitions get indirected + if ( this->shouldExport(target) ) + return kRelocExternal; + else if ( fSlideable ) + return kRelocInternal; + else + return kRelocNone; + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + return kRelocExternal; + case ObjectFile::Atom::kAbsoluteSymbol: + return kRelocNone; + } + return kRelocNone; +} + +template +uint64_t Writer::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const +{ + // for 32-bit architectures, the r_address field in relocs + // for final linked images is the offset from the first segment + uint64_t result = address - fSegmentInfos[0]->fBaseAddress; + // or the offset from the first writable segment if built split-seg + if ( fOptions.splitSeg() ) + result = address - fFirstWritableSegment->fBaseAddress; + if ( result > 0x7FFFFFFF ) { + throwf("image too large: address can't fit in 31-bit r_address field in %s from %s", + atom->getDisplayName(), atom->getFile()->getPath()); + } + return result; +} + +template <> +uint64_t Writer::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const +{ + // for x86_64, the r_address field in relocs for final linked images + // is the offset from the start address of the first writable segment + uint64_t result = address - fFirstWritableSegment->fBaseAddress; + if ( result > 0xFFFFFFFF ) { + throwf("image too large: address can't fit in 32-bit r_address field in %s from %s", + atom->getDisplayName(), atom->getFile()->getPath()); + } + return result; +} + +template <> +uint64_t Writer::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const +{ + // for ppc64, the Mac OS X 10.4 dyld assumes r_address is always the offset from the base address. + // the 10.5 dyld, iterprets the r_address as: + // 1) an offset from the base address, iff there are no writable segments with a address > 4GB from base address, otherwise + // 2) an offset from the base address of the first writable segment + // For dyld, r_address is always the offset from the base address + uint64_t result; + bool badFor10_4 = false; + if ( fWritableSegmentPastFirst4GB ) { + if ( fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5 ) + badFor10_4 = true; + result = address - fFirstWritableSegment->fBaseAddress; + if ( result > 0xFFFFFFFF ) { + throwf("image too large: address can't fit in 32-bit r_address field in %s from %s", + atom->getDisplayName(), atom->getFile()->getPath()); + } + } + else { + result = address - fSegmentInfos[0]->fBaseAddress; + if ( (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5) && (result > 0x7FFFFFFF) ) + badFor10_4 = true; + } + if ( badFor10_4 ) { + throwf("image or pagezero_size too large for Mac OS X 10.4: address can't fit in 31-bit r_address field for %s from %s", + atom->getDisplayName(), atom->getFile()->getPath()); + } + return result; +} + + +template <> bool Writer::preboundLazyPointerType(uint8_t* type) { *type = PPC_RELOC_PB_LA_PTR; return true; } +template <> bool Writer::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; } +template <> bool Writer::preboundLazyPointerType(uint8_t* type) { *type = GENERIC_RELOC_PB_LA_PTR; return true; } +template <> bool Writer::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; } +template <> bool Writer::preboundLazyPointerType(uint8_t* type) { *type = ARM_RELOC_PB_LA_PTR; return true; } + +template +void Writer::buildExecutableFixups() +{ + fIndirectTableAtom->fTable.reserve(50); // minimize reallocations + std::vector& segmentInfos = fSegmentInfos; + const int segCount = segmentInfos.size(); + for(int i=0; i < segCount; ++i) { + SegmentInfo* curSegment = segmentInfos[i]; + std::vector& sectionInfos = curSegment->fSections; + const int sectionCount = sectionInfos.size(); + for(int j=0; j < sectionCount; ++j) { + SectionInfo* curSection = sectionInfos[j]; + //fprintf(stderr, "starting section %s\n", curSection->fSectionName); + std::vector& sectionAtoms = curSection->fAtoms; + if ( ! curSection->fAllZeroFill ) { + if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers + || curSection->fAllStubs || curSection->fAllSelfModifyingStubs ) + curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size(); + const int atomCount = sectionAtoms.size(); + for (int k=0; k < atomCount; ++k) { + ObjectFile::Atom* atom = sectionAtoms[k]; + std::vector& refs = atom->getReferences(); + const int refCount = refs.size(); + //fprintf(stderr, "atom %s has %d references in section %s, %p\n", atom->getDisplayName(), refCount, curSection->fSectionName, atom->getSection()); + for (int l=0; l < refCount; ++l) { + ObjectFile::Reference* ref = refs[l]; + if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) { + // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol + if ( atom->getSize() != sizeof(pint_t) ) { + warning("wrong size pointer atom %s from file %s", atom->getDisplayName(), atom->getFile()->getPath()); + } + ObjectFile::Atom* pointerTarget = &(ref->getTarget()); + if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) { + pointerTarget = ((LazyPointerAtom*)atom)->getTarget(); + } + uint32_t offsetInSection = atom->getSectionOffset(); + uint32_t indexInSection = offsetInSection / sizeof(pint_t); + uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL; + if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal ) + undefinedSymbolIndex = this->symbolIndex(*pointerTarget); + uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset; + IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex }; + //fprintf(stderr,"fIndirectTableAtom->fTable.push_back(tableIndex=%d, symIndex=0x%X), pointerTarget=%s\n", + // indirectTableIndex, undefinedSymbolIndex, pointerTarget->getDisplayName()); + fIndirectTableAtom->fTable.push_back(entry); + if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) { + uint8_t preboundLazyType; + if ( fOptions.prebind() && (fDyldHelper != NULL) + && curSection->fAllLazyPointers && preboundLazyPointerType(&preboundLazyType) ) { + // this is a prebound image, need special relocs for dyld to reset lazy pointers if prebinding is invalid + macho_scattered_relocation_info

pblaReloc; + pblaReloc.set_r_scattered(true); + pblaReloc.set_r_pcrel(false); + pblaReloc.set_r_length(); + pblaReloc.set_r_type(preboundLazyType); + pblaReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom)); + pblaReloc.set_r_value(fDyldHelper->getAddress()); + fInternalRelocs.push_back(*((macho_relocation_info

*)&pblaReloc)); + } + else if ( fSlideable ) { + // this is a non-prebound dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides + macho_relocation_info

dyldHelperReloc; + uint32_t sectionNum = 1; + if ( fDyldHelper != NULL ) + sectionNum = ((SectionInfo*)(fDyldHelper->getSection()))->getIndex(); + //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName); + dyldHelperReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom)); + dyldHelperReloc.set_r_symbolnum(sectionNum); + dyldHelperReloc.set_r_pcrel(false); + dyldHelperReloc.set_r_length(); + dyldHelperReloc.set_r_extern(false); + dyldHelperReloc.set_r_type(GENERIC_RELOC_VANILLA); + fInternalRelocs.push_back(dyldHelperReloc); + } + } + } + else if ( (ref->getKind() == A::kPointer) || (ref->getKind() == A::kPointerWeakImport) ) { + if ( fSlideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) { + throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s", + atom->getDisplayName(), atom->getFile()->getPath()); + } + switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) { + case kRelocNone: + // no reloc needed + break; + case kRelocInternal: + { + macho_relocation_info

internalReloc; + SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection(); + uint32_t sectionNum = sectInfo->getIndex(); + // special case _mh_dylib_header and friends which are not in any real section + if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) ) + sectionNum = 1; + internalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom)); + internalReloc.set_r_symbolnum(sectionNum); + internalReloc.set_r_pcrel(false); + internalReloc.set_r_length(); + internalReloc.set_r_extern(false); + internalReloc.set_r_type(GENERIC_RELOC_VANILLA); + fInternalRelocs.push_back(internalReloc); + } + break; + case kRelocExternal: + { + macho_relocation_info

externalReloc; + externalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom)); + externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget())); + externalReloc.set_r_pcrel(false); + externalReloc.set_r_length(); + externalReloc.set_r_extern(true); + externalReloc.set_r_type(GENERIC_RELOC_VANILLA); + fExternalRelocs.push_back(externalReloc); + } + break; + } + } + else if ( this->illegalRelocInFinalLinkedImage(*ref) ) { + if ( fOptions.allowTextRelocs() && !atom->getSegment().isContentWritable() ) { + if ( fOptions.warnAboutTextRelocs() ) + warning("text reloc in %s to %s", atom->getDisplayName(), ref->getTargetName()); + if ( this->generatesLocalTextReloc(*ref, *atom, curSection) ) { + // relocs added to fInternalRelocs + } + else if ( this->generatesExternalTextReloc(*ref, *atom, curSection) ) { + // relocs added to fExternalRelocs + } + else { + throwf("relocation used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath()); + } + } + else { + throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image. " + "Use '-read_only_relocs suppress' to enable text relocs", atom->getDisplayName(), atom->getFile()->getPath()); + } + } + } + if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) { + ObjectFile::Atom* stubTarget = ((StubAtom*)atom)->getTarget(); + uint32_t undefinedSymbolIndex = (stubTarget != NULL) ? this->symbolIndex(*stubTarget) : INDIRECT_SYMBOL_ABS; + uint32_t offsetInSection = atom->getSectionOffset(); + uint32_t indexInSection = offsetInSection / atom->getSize(); + uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset; + IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex }; + //fprintf(stderr,"for stub: fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, stubTarget->getName(), atom->getSize()); + fIndirectTableAtom->fTable.push_back(entry); + } + } + } + } + } + if ( fSplitCodeToDataContentAtom != NULL ) + fSplitCodeToDataContentAtom->encode(); +} + + +template <> +void Writer::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref) +{ + switch ( (ppc::ReferenceKinds)ref->getKind() ) { + case ppc::kPICBaseHigh16: + fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset()); + break; + case ppc::kPointerDiff32: + fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset()); + break; + case ppc::kPointerDiff64: + fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset()); + break; + case ppc::kNoFixUp: + case ppc::kGroupSubordinate: + case ppc::kPointer: + case ppc::kPointerWeakImport: + case ppc::kPICBaseLow16: + case ppc::kPICBaseLow14: + // ignore + break; + default: + warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName()); + fSplitCodeToDataContentAtom->setCantEncode(); + } +} + +template <> +void Writer::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref) +{ + switch ( (ppc64::ReferenceKinds)ref->getKind() ) { + case ppc64::kPICBaseHigh16: + fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset()); + break; + case ppc64::kPointerDiff32: + fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset()); + break; + case ppc64::kPointerDiff64: + fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset()); + break; + case ppc64::kNoFixUp: + case ppc64::kGroupSubordinate: + case ppc64::kPointer: + case ppc64::kPointerWeakImport: + case ppc64::kPICBaseLow16: + case ppc64::kPICBaseLow14: + // ignore + break; + default: + warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName()); + fSplitCodeToDataContentAtom->setCantEncode(); + } +} + +template <> +void Writer::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref) +{ + switch ( (x86::ReferenceKinds)ref->getKind() ) { + case x86::kPointerDiff: + if ( strcmp(ref->getTarget().getSegment().getName(), "__IMPORT") == 0 ) + fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset()); + else + fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset()); + break; + case x86::kNoFixUp: + case x86::kGroupSubordinate: + case x86::kPointer: + case x86::kPointerWeakImport: + // ignore + break; + case x86::kPCRel32: + case x86::kPCRel32WeakImport: + if ( (&(ref->getTarget().getSegment()) == &Segment::fgImportSegment) + || (&(ref->getTarget().getSegment()) == &Segment::fgROImportSegment) ) { + fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset()); + break; + } + // fall into warning case + default: + warning("codegen in %s (offset 0x%08llX) prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getFixUpOffset()); + fSplitCodeToDataContentAtom->setCantEncode(); + } +} + +template <> +void Writer::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref) +{ + switch ( (x86_64::ReferenceKinds)ref->getKind() ) { + case x86_64::kPCRel32: + case x86_64::kPCRel32_1: + case x86_64::kPCRel32_2: + case x86_64::kPCRel32_4: + case x86_64::kPCRel32GOTLoad: + case x86_64::kPCRel32GOTLoadWeakImport: + case x86_64::kPCRel32GOT: + case x86_64::kPCRel32GOTWeakImport: + case x86_64::kPointerDiff32: + fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset()); + break; + case x86_64::kPointerDiff: + fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset()); + break; + case x86_64::kNoFixUp: + case x86_64::kGroupSubordinate: + case x86_64::kPointer: + // ignore + break; + default: + warning("codegen in %s with kind %d prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getKind()); + fSplitCodeToDataContentAtom->setCantEncode(); + } +} + +template <> +void Writer::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref) +{ + switch ( (arm::ReferenceKinds)ref->getKind() ) { + case arm::kPointerDiff: + fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset()); + break; + case arm::kNoFixUp: + case arm::kGroupSubordinate: + case arm::kPointer: + case arm::kPointerWeakImport: + case arm::kReadOnlyPointer: + // ignore + break; + default: + warning("codegen in %s prevents image from loading in dyld shared cache", atom->getDisplayName()); + fSplitCodeToDataContentAtom->setCantEncode(); + } +} + +template +bool Writer::segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to) +{ + switch ( to.getDefinitionKind() ) { + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + case ObjectFile::Atom::kAbsoluteSymbol: + return false; + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + case ObjectFile::Atom::kTentativeDefinition: + // segments with same permissions slide together + return ( (from.getSegment().isContentExecutable() != to.getSegment().isContentExecutable()) + || (from.getSegment().isContentWritable() != to.getSegment().isContentWritable()) ); + } + throw "ld64 internal error"; +} + + +template <> +void Writer::writeNoOps(int fd, uint32_t from, uint32_t to) +{ + uint32_t ppcNop; + OSWriteBigInt32(&ppcNop, 0, 0x60000000); + for (uint32_t p=from; p < to; p += 4) + ::pwrite(fd, &ppcNop, 4, p); +} + +template <> +void Writer::writeNoOps(int fd, uint32_t from, uint32_t to) +{ + uint32_t ppcNop; + OSWriteBigInt32(&ppcNop, 0, 0x60000000); + for (uint32_t p=from; p < to; p += 4) + ::pwrite(fd, &ppcNop, 4, p); +} + +template <> +void Writer::writeNoOps(int fd, uint32_t from, uint32_t to) +{ + uint8_t x86Nop = 0x90; + for (uint32_t p=from; p < to; ++p) + ::pwrite(fd, &x86Nop, 1, p); +} + +template <> +void Writer::writeNoOps(int fd, uint32_t from, uint32_t to) +{ + uint8_t x86Nop = 0x90; + for (uint32_t p=from; p < to; ++p) + ::pwrite(fd, &x86Nop, 1, p); +} + +template <> +void Writer::writeNoOps(int fd, uint32_t from, uint32_t to) +{ + // FIXME: need thumb nop? + uint32_t armNop; + OSWriteLittleInt32(&armNop, 0, 0xe1a00000); + for (uint32_t p=from; p < to; p += 4) + ::pwrite(fd, &armNop, 4, p); +} + +template <> +void Writer::copyNoOps(uint8_t* from, uint8_t* to) +{ + for (uint8_t* p=from; p < to; p += 4) + OSWriteBigInt32((uint32_t*)p, 0, 0x60000000); +} + +template <> +void Writer::copyNoOps(uint8_t* from, uint8_t* to) +{ + for (uint8_t* p=from; p < to; p += 4) + OSWriteBigInt32((uint32_t*)p, 0, 0x60000000); +} + +template <> +void Writer::copyNoOps(uint8_t* from, uint8_t* to) +{ + for (uint8_t* p=from; p < to; ++p) + *p = 0x90; +} + +template <> +void Writer::copyNoOps(uint8_t* from, uint8_t* to) +{ + for (uint8_t* p=from; p < to; ++p) + *p = 0x90; +} + +template <> +void Writer::copyNoOps(uint8_t* from, uint8_t* to) +{ + // fixme: need thumb nop? + for (uint8_t* p=from; p < to; p += 4) + OSWriteBigInt32((uint32_t*)p, 0, 0xe1a00000); +} + +static const char* stringName(const char* str) +{ + if ( strncmp(str, "cstring=", 8) == 0) { + static char buffer[1024]; + char* t = buffer; + *t++ = '\"'; + for(const char*s = &str[8]; *s != '\0'; ++s) { + switch(*s) { + case '\n': + *t++ = '\\'; + *t++ = 'n'; + break; + case '\t': + *t++ = '\\'; + *t++ = 't'; + break; + default: + *t++ = *s; + break; + } + if ( t > &buffer[1020] ) { + *t++= '\"'; + *t++= '.'; + *t++= '.'; + *t++= '.'; + *t++= '\0'; + return buffer; + } + } + *t++= '\"'; + *t++= '\0'; + return buffer; + } + else { + return str; + } +} + + +template <> const char* Writer::getArchString() { return "ppc"; } +template <> const char* Writer::getArchString() { return "ppc64"; } +template <> const char* Writer::getArchString() { return "i386"; } +template <> const char* Writer::getArchString() { return "x86_64"; } +template <> const char* Writer::getArchString() { return "arm"; } + +template +void Writer::writeMap() +{ + if ( fOptions.generatedMapPath() != NULL ) { + FILE* mapFile = fopen(fOptions.generatedMapPath(), "w"); + if ( mapFile != NULL ) { + // write output path + fprintf(mapFile, "# Path: %s\n", fFilePath); + // write output architecure + fprintf(mapFile, "# Arch: %s\n", getArchString()); + // write UUID + if ( fUUIDAtom != NULL ) { + const uint8_t* uuid = fUUIDAtom->getUUID(); + fprintf(mapFile, "# UUID: %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X \n", + uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]); + } + // write table of object files + std::map readerToOrdinal; + std::map ordinalToReader; + std::map readerToFileOrdinal; + for (std::vector::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) { + std::vector& sectionInfos = (*segit)->fSections; + for (std::vector::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) { + if ( ! (*secit)->fVirtualSection ) { + std::vector& sectionAtoms = (*secit)->fAtoms; + for (std::vector::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) { + ObjectFile::Reader* reader = (*ait)->getFile(); + uint32_t readerOrdinal = (*ait)->getOrdinal(); + std::map::iterator pos = readerToOrdinal.find(reader); + if ( pos == readerToOrdinal.end() ) { + readerToOrdinal[reader] = readerOrdinal; + ordinalToReader[readerOrdinal] = reader; + } + } + } + } + } + fprintf(mapFile, "# Object files:\n"); + fprintf(mapFile, "[%3u] %s\n", 0, "linker synthesized"); + uint32_t fileIndex = 0; + readerToFileOrdinal[this] = fileIndex++; + for(std::map::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) { + if ( it->first != 0 ) { + fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->getPath()); + readerToFileOrdinal[it->second] = fileIndex++; + } + } + // write table of sections + fprintf(mapFile, "# Sections:\n"); + fprintf(mapFile, "# Address\tSize \tSegment\tSection\n"); + for (std::vector::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) { + std::vector& sectionInfos = (*segit)->fSections; + for (std::vector::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) { + if ( ! (*secit)->fVirtualSection ) { + SectionInfo* sect = *secit; + fprintf(mapFile, "0x%08llX\t0x%08llX\t%s\t%s\n", sect->getBaseAddress(), sect->fSize, + (*segit)->fName, sect->fSectionName); + } + } + } + // write table of symbols + fprintf(mapFile, "# Symbols:\n"); + fprintf(mapFile, "# Address\tSize \tFile Name\n"); + for (std::vector::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) { + std::vector& sectionInfos = (*segit)->fSections; + for (std::vector::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) { + if ( ! (*secit)->fVirtualSection ) { + std::vector& sectionAtoms = (*secit)->fAtoms; + bool isCstring = (strcmp((*secit)->fSectionName, "__cstring") == 0); + for (std::vector::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) { + ObjectFile::Atom* atom = *ait; + fprintf(mapFile, "0x%08llX\t0x%08llX\t[%3u] %s\n", atom->getAddress(), atom->getSize(), + readerToFileOrdinal[atom->getFile()], isCstring ? stringName(atom->getDisplayName()): atom->getDisplayName()); + } + } + } + } + fclose(mapFile); + } + else { + warning("could not write map file: %s\n", fOptions.generatedMapPath()); + } + } +} + +static const char* sCleanupFile = NULL; +static void cleanup(int sig) +{ + ::signal(sig, SIG_DFL); + if ( sCleanupFile != NULL ) { + ::unlink(sCleanupFile); + } + if ( sig == SIGINT ) + ::exit(1); +} + + +template +uint64_t Writer::writeAtoms() +{ + // for UNIX conformance, error if file exists and is not writable + if ( (access(fFilePath, F_OK) == 0) && (access(fFilePath, W_OK) == -1) ) + throwf("can't write output file: %s", fFilePath); + + int permissions = 0777; + if ( fOptions.outputKind() == Options::kObjectFile ) + permissions = 0666; + // Calling unlink first assures the file is gone so that open creates it with correct permissions + // It also handles the case where fFilePath file is not writable but its directory is + // And it means we don't have to truncate the file when done writing (in case new is smaller than old) + (void)unlink(fFilePath); + + // try to allocate buffer for entire output file content + int fd = -1; + SectionInfo* lastSection = fSegmentInfos.back()->fSections.back(); + uint64_t fileBufferSize = (lastSection->fFileOffset + lastSection->fSize + 4095) & (-4096); + uint8_t* wholeBuffer = (uint8_t*)calloc(fileBufferSize, 1); + uint8_t* atomBuffer = NULL; + bool streaming = false; + if ( wholeBuffer == NULL ) { + fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions); + if ( fd == -1 ) + throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno); + atomBuffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)]; + streaming = true; + // install signal handlers to delete output file if program is killed + sCleanupFile = fFilePath; + ::signal(SIGINT, cleanup); + ::signal(SIGBUS, cleanup); + ::signal(SIGSEGV, cleanup); + } + uint32_t size = 0; + uint32_t end = 0; + try { + for (std::vector::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) { + SegmentInfo* curSegment = *segit; + bool isTextSeg = (strcmp(curSegment->fName, "__TEXT") == 0); + std::vector& sectionInfos = curSegment->fSections; + for (std::vector::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) { + SectionInfo* curSection = *secit; + std::vector& sectionAtoms = curSection->fAtoms; + //printf("writing with max atom size 0x%X\n", fLargestAtomSize); + //fprintf(stderr, "writing %lu atoms for section %s\n", sectionAtoms.size(), curSection->fSectionName); + if ( ! curSection->fAllZeroFill ) { + end = curSection->fFileOffset; + bool needsNops = isTextSeg && (strcmp(curSection->fSectionName, "__cstring") != 0); + for (std::vector::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) { + ObjectFile::Atom* atom = *ait; + if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition) + && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition) + && (atom->getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) ) { + uint32_t fileOffset = curSection->fFileOffset + atom->getSectionOffset(); + if ( fileOffset != end ) { + if ( needsNops ) { + // fill gaps with no-ops + if ( streaming ) + writeNoOps(fd, end, fileOffset); + else + copyNoOps(&wholeBuffer[end], &wholeBuffer[fileOffset]); + } + else if ( streaming ) { + // zero fill gaps + if ( (fileOffset-end) == 4 ) { + uint32_t zero = 0; + ::pwrite(fd, &zero, 4, end); + } + else { + uint8_t zero = 0x00; + for (uint32_t p=end; p < fileOffset; ++p) + ::pwrite(fd, &zero, 1, p); + } + } + } + uint64_t atomSize = atom->getSize(); + if ( streaming ) { + if ( atomSize > fLargestAtomSize ) + throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX", + atom->getDisplayName(), atomSize, fLargestAtomSize); + } + else { + if ( fileOffset > fileBufferSize ) + throwf("ld64 internal error: atom \"%s\" has file offset greater thatn expceted 0x%X > 0x%llX", + atom->getDisplayName(), fileOffset, fileBufferSize); + } + uint8_t* buffer = streaming ? atomBuffer : &wholeBuffer[fileOffset]; + end = fileOffset+atomSize; + // copy raw bytes + atom->copyRawContent(buffer); + // apply any fix-ups + try { + std::vector& references = atom->getReferences(); + for (std::vector::iterator it=references.begin(); it != references.end(); it++) { + ObjectFile::Reference* ref = *it; + if ( fOptions.outputKind() == Options::kObjectFile ) { + // doing ld -r + // skip fix-ups for undefined targets + if ( &(ref->getTarget()) != NULL ) + this->fixUpReferenceRelocatable(ref, atom, buffer); + } + else { + // producing final linked image + this->fixUpReferenceFinal(ref, atom, buffer); + } + } + } + catch (const char* msg) { + throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath()); + } + //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %s from %s\n", + // fileOffset, end, atom->getAddress(), atom->getSize(), atom->getDisplayName(), atom->getFile()->getPath()); + if ( streaming ) { + // write out + ::pwrite(fd, buffer, atomSize, fileOffset); + } + else { + if ( (fileOffset + atomSize) > size ) + size = fileOffset + atomSize; + } + } + } + } + } + } + + // update content based UUID + if ( fOptions.getUUIDMode() == Options::kUUIDContent ) { + uint8_t digest[CC_MD5_DIGEST_LENGTH]; + if ( streaming ) { + // if output file file did not fit in memory, re-read file to generate md5 hash + uint32_t kMD5BufferSize = 16*1024; + uint8_t* md5Buffer = (uint8_t*)::malloc(kMD5BufferSize); + if ( md5Buffer != NULL ) { + CC_MD5_CTX md5State; + CC_MD5_Init(&md5State); + ::lseek(fd, 0, SEEK_SET); + ssize_t len; + while ( (len = ::read(fd, md5Buffer, kMD5BufferSize)) > 0 ) + CC_MD5_Update(&md5State, md5Buffer, len); + CC_MD5_Final(digest, &md5State); + ::free(md5Buffer); + } + else { + // if malloc fails, fall back to random uuid + ::uuid_generate_random(digest); + } + fUUIDAtom->setContent(digest); + uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset(); + fUUIDAtom->copyRawContent(atomBuffer); + ::pwrite(fd, atomBuffer, fUUIDAtom->getSize(), uuidOffset); + } + else { + // if output file fit in memory, just genrate an md5 hash in memory + #if 1 + // temp hack for building on Tiger + CC_MD5_CTX md5State; + CC_MD5_Init(&md5State); + CC_MD5_Update(&md5State, wholeBuffer, size); + CC_MD5_Final(digest, &md5State); + #else + CC_MD5(wholeBuffer, size, digest); + #endif + fUUIDAtom->setContent(digest); + uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset(); + fUUIDAtom->copyRawContent(&wholeBuffer[uuidOffset]); + } + } + } + catch (...) { + if ( sCleanupFile != NULL ) + ::unlink(sCleanupFile); + throw; + } + + // finish up + if ( streaming ) { + delete [] atomBuffer; + close(fd); + // restore default signal handlers + sCleanupFile = NULL; + ::signal(SIGINT, SIG_DFL); + ::signal(SIGBUS, SIG_DFL); + ::signal(SIGSEGV, SIG_DFL); + } + else { + // write whole output file in one chunk + fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions); + if ( fd == -1 ) + throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno); + ::pwrite(fd, wholeBuffer, size, 0); + close(fd); + delete [] wholeBuffer; + } + + return end; +} + +template <> +void Writer::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const +{ + int64_t displacement; + int64_t baseAddr; + uint32_t instruction; + uint32_t newInstruction; + uint64_t targetAddr = 0; + uint32_t firstDisp; + uint32_t nextDisp; + uint32_t opcode; + bool relocateableExternal = false; + bool is_bl; + bool is_blx; + bool targetIsThumb; + + if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) { + targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset(); + relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal); + } + + uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()]; + switch ( (arm::ReferenceKinds)(ref->getKind()) ) { + case arm::kNoFixUp: + case arm::kFollowOn: + case arm::kGroupSubordinate: + // do nothing + break; + case arm::kPointerWeakImport: + case arm::kPointer: + // If this is the lazy pointers section, then set all lazy pointers to + // point to the dyld stub binding helper. + if ( ((SectionInfo*)inAtom->getSection())->fAllLazyPointers + || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers ) { + switch (ref->getTarget().getDefinitionKind()) { + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + // prebound lazy pointer to another dylib ==> pointer contains zero + LittleEndian::set32(*fixUp, 0); + break; + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + case ObjectFile::Atom::kAbsoluteSymbol: + // prebound lazy pointer to withing this dylib ==> pointer contains address + if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) ) + targetAddr |= 1; + LittleEndian::set32(*fixUp, targetAddr); + break; + } + } + else if ( relocateableExternal ) { + if ( fOptions.prebind() ) { + switch (ref->getTarget().getDefinitionKind()) { + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + // prebound external relocation ==> pointer contains addend + LittleEndian::set32(*fixUp, ref->getTargetOffset()); + break; + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + // prebound external relocation to internal atom ==> pointer contains target address + addend + if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) ) + targetAddr |= 1; + LittleEndian::set32(*fixUp, targetAddr); + break; + case ObjectFile::Atom::kAbsoluteSymbol: + break; + } + } + else { + // external relocation ==> pointer contains addend + LittleEndian::set32(*fixUp, ref->getTargetOffset()); + } + } + else { + // pointer contains target address + if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0)) + targetAddr |= 1; + LittleEndian::set32(*fixUp, targetAddr); + } + break; + case arm::kPointerDiff: + LittleEndian::set32(*fixUp, + (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) ); + break; + case arm::kReadOnlyPointer: + switch ( ref->getTarget().getDefinitionKind() ) { + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + case ObjectFile::Atom::kTentativeDefinition: + // pointer contains target address + LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset()); + break; + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + // external relocation ==> pointer contains addend + LittleEndian::set32(*fixUp, ref->getTargetOffset()); + break; + case ObjectFile::Atom::kAbsoluteSymbol: + // pointer contains target address + LittleEndian::set32(*fixUp, ref->getTarget().getSectionOffset() + ref->getTargetOffset()); + break; + } + break; + case arm::kBranch24WeakImport: + case arm::kBranch24: + displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset()); + // The pc added will be +8 from the pc + displacement -= 8; + // fprintf(stderr, "bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement); + // max positive displacement is 0x007FFFFF << 2 + // max negative displacement is 0xFF800000 << 2 + if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) { + throwf("b/bl/blx out of range (%lld max is +/-32M) from %s in %s to %s in %s", + displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(), + ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath()); + } + instruction = LittleEndian::get32(*fixUp); + // Make sure we are calling arm with bl, thumb with blx + is_bl = ((instruction & 0xFF000000) == 0xEB000000); + is_blx = ((instruction & 0xFE000000) == 0xFA000000); + if ( is_bl && ref->getTarget().isThumb() ) { + uint32_t opcode = 0xFA000000; + uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF; + uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000; + newInstruction = opcode | h_bit | disp; + } + else if ( is_blx && !ref->getTarget().isThumb() ) { + uint32_t opcode = 0xEB000000; + uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF; + newInstruction = opcode | disp; + } + else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) { + throwf("don't know how to convert instruction %x referencing %s to thumb", + instruction, ref->getTarget().getDisplayName()); + } + else { + newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF); + } + LittleEndian::set32(*fixUp, newInstruction); + break; + case arm::kThumbBranch22WeakImport: + case arm::kThumbBranch22: + instruction = LittleEndian::get32(*fixUp); + is_bl = ((instruction & 0xF8000000) == 0xF8000000); + is_blx = ((instruction & 0xF8000000) == 0xE8000000); + targetIsThumb = ref->getTarget().isThumb(); + + // The pc added will be +4 from the pc + baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4; + // If the target is not thumb, we will be generating a blx instruction + // 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 ( !targetIsThumb ) { + targetAddr &= -3ULL; + targetAddr |= (baseAddr & 2LL); + } + displacement = targetAddr - baseAddr; + + // max positive displacement is 0x003FFFFE + // max negative displacement is 0xFFC00000 + if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) { + throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s", + displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(), + ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath()); + } + // The instruction is really two instructions: + // The lower 16 bits are the first instruction, which contains the first + // 11 bits of the displacement. + // The upper 16 bits are the second instruction, which contains the next + // 11 bits of the displacement, as well as differentiating bl and blx. + { + firstDisp = (uint32_t)(displacement >> 12) & 0x7FF; + nextDisp = (uint32_t)(displacement >> 1) & 0x7FF; + if ( is_bl && !targetIsThumb ) { + opcode = 0xE800F000; + } + else if ( is_blx && targetIsThumb ) { + opcode = 0xF800F000; + } + else if ( !is_bl && !is_blx && !targetIsThumb ) { + throwf("don't know how to convert instruction %x referencing %s to arm", + instruction, ref->getTarget().getDisplayName()); + } + else { + opcode = instruction & 0xF800F800; + } + newInstruction = opcode | (nextDisp << 16) | firstDisp; + LittleEndian::set32(*fixUp, newInstruction); + } + break; + case arm::kDtraceProbeSite: + case arm::kDtraceIsEnabledSite: + if ( inAtom->isThumb() ) { + // change 32-bit blx call site to two thumb NOPs + LittleEndian::set32(*fixUp, 0x46C046C0); + } + else { + // change call site to a NOP + LittleEndian::set32(*fixUp, 0xE1A00000); + } + break; + case arm::kDtraceTypeReference: + case arm::kDtraceProbe: + // nothing to fix up + break; + default: + throw "boom shaka laka"; + } +} + +template <> +void Writer::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const +{ + int64_t displacement; + uint32_t instruction; + uint32_t newInstruction; + uint64_t targetAddr = 0; + int64_t baseAddr; + uint32_t firstDisp; + uint32_t nextDisp; + uint32_t opcode; + bool relocateableExternal = false; + bool is_bl; + bool is_blx; + bool targetIsThumb; + + if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) { + targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset(); + relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget()); + } + + uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()]; + switch ( (arm::ReferenceKinds)(ref->getKind()) ) { + case arm::kNoFixUp: + case arm::kFollowOn: + case arm::kGroupSubordinate: + // do nothing + break; + case arm::kPointer: + case arm::kReadOnlyPointer: + case arm::kPointerWeakImport: + { + if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) { + // indirect symbol table has INDIRECT_SYMBOL_LOCAL, so we must put address in content + if ( this->indirectSymbolIsLocal(ref) ) + LittleEndian::set32(*fixUp, targetAddr); + else + LittleEndian::set32(*fixUp, 0); + } + else if ( relocateableExternal ) { + if ( fOptions.prebind() ) { + switch (ref->getTarget().getDefinitionKind()) { + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + // prebound external relocation ==> pointer contains addend + LittleEndian::set32(*fixUp, ref->getTargetOffset()); + break; + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + // prebound external relocation to internal atom ==> pointer contains target address + addend + LittleEndian::set32(*fixUp, targetAddr); + break; + case ObjectFile::Atom::kAbsoluteSymbol: + break; + } + } + } + else { + // internal relocation + if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) { + // pointer contains target address + if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0)) + targetAddr |= 1; + LittleEndian::set32(*fixUp, targetAddr); + } + else { + // pointer contains addend + LittleEndian::set32(*fixUp, ref->getTargetOffset()); + } + } + } + break; + case arm::kPointerDiff: + LittleEndian::set32(*fixUp, + (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) ); + break; + case arm::kDtraceProbeSite: + case arm::kDtraceIsEnabledSite: + case arm::kBranch24WeakImport: + case arm::kBranch24: + displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset()); + // The pc added will be +8 from the pc + displacement -= 8; + // fprintf(stderr, "b/bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement); + if ( relocateableExternal ) { + // doing "ld -r" to an external symbol + // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target + displacement -= ref->getTarget().getAddress(); + } + else { + // max positive displacement is 0x007FFFFF << 2 + // max negative displacement is 0xFF800000 << 2 + if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) { + throwf("arm b/bl/blx out of range (%lld max is +/-32M) from %s in %s to %s in %s", + displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(), + ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath()); + } + } + instruction = LittleEndian::get32(*fixUp); + // Make sure we are calling arm with bl, thumb with blx + is_bl = ((instruction & 0xFF000000) == 0xEB000000); + is_blx = ((instruction & 0xFE000000) == 0xFA000000); + if ( is_bl && ref->getTarget().isThumb() ) { + uint32_t opcode = 0xFA000000; + uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF; + uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000; + newInstruction = opcode | h_bit | disp; + } + else if ( is_blx && !ref->getTarget().isThumb() ) { + uint32_t opcode = 0xEB000000; + uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF; + newInstruction = opcode | disp; + } + else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) { + throwf("don't know how to convert instruction %x referencing %s to thumb", + instruction, ref->getTarget().getDisplayName()); + } + else { + newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF); + } + LittleEndian::set32(*fixUp, newInstruction); + break; + case arm::kThumbBranch22WeakImport: + case arm::kThumbBranch22: + instruction = LittleEndian::get32(*fixUp); + is_bl = ((instruction & 0xF8000000) == 0xF8000000); + is_blx = ((instruction & 0xF8000000) == 0xE8000000); + targetIsThumb = ref->getTarget().isThumb(); + + // The pc added will be +4 from the pc + baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4; + // If the target is not thumb, we will be generating a blx instruction + // 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 (!targetIsThumb) { + targetAddr &= -3ULL; + targetAddr |= (baseAddr & 2LL); + } + displacement = targetAddr - baseAddr; + + //fprintf(stderr, "thumb %s fixup to %s at 0x%08llX, baseAddr = 0x%08llX, displacement = 0x%08llX, %d\n", is_blx ? "blx" : "bl", ref->getTarget().getDisplayName(), targetAddr, baseAddr, displacement, targetIsThumb); + if ( relocateableExternal ) { + // doing "ld -r" to an external symbol + // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target + displacement -= ref->getTarget().getAddress(); + } + else { + // max positive displacement is 0x003FFFFE + // max negative displacement is 0xFFC00000 + if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) { + throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s", + displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(), + ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath()); + } + } + // The instruction is really two instructions: + // The lower 16 bits are the first instruction, which contains the first + // 11 bits of the displacement. + // The upper 16 bits are the second instruction, which contains the next + // 11 bits of the displacement, as well as differentiating bl and blx. + firstDisp = (uint32_t)(displacement >> 12) & 0x7FF; + nextDisp = (uint32_t)(displacement >> 1) & 0x7FF; + if ( is_bl && !targetIsThumb ) { + opcode = 0xE800F000; + } + else if ( is_blx && targetIsThumb ) { + opcode = 0xF800F000; + } + else if ( !is_bl && !is_blx && !targetIsThumb ) { + throwf("don't know how to convert instruction %x referencing %s to arm", + instruction, ref->getTarget().getDisplayName()); + } + else { + opcode = instruction & 0xF800F800; + } + newInstruction = opcode | (nextDisp << 16) | firstDisp; + LittleEndian::set32(*fixUp, newInstruction); + break; + case arm::kDtraceProbe: + case arm::kDtraceTypeReference: + // nothing to fix up + break; + } +} + +template <> +void Writer::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const +{ + uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()]; + uint8_t* dtraceProbeSite; + const int64_t kTwoGigLimit = 0x7FFFFFFF; + const int64_t kSixtyFourKiloLimit = 0x7FFF; + const int64_t kOneTwentyEightLimit = 0x7F; + int64_t displacement; + x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind()); + switch ( kind ) { + case x86::kNoFixUp: + case x86::kFollowOn: + case x86::kGroupSubordinate: + // do nothing + break; + case x86::kPointerWeakImport: + case x86::kPointer: + { + if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) { + if ( fOptions.prebind() ) { + switch (ref->getTarget().getDefinitionKind()) { + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + // prebound external relocation ==> pointer contains addend + LittleEndian::set32(*fixUp, ref->getTargetOffset()); + break; + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + // prebound external relocation to internal atom ==> pointer contains target address + addend + LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset()); + break; + case ObjectFile::Atom::kAbsoluteSymbol: + break; + } + } + else { + // external relocation ==> pointer contains addend + LittleEndian::set32(*fixUp, ref->getTargetOffset()); + } + } + else { + // pointer contains target address + //printf("Atom::fixUpReferenceFinal() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress()); + LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset()); + } + } + break; + case x86::kPointerDiff: + displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()); + LittleEndian::set32(*fixUp, (uint32_t)displacement); + break; + case x86::kPointerDiff16: + displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()); + if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) + throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName()); + LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement); + break; + case x86::kDtraceProbeSite: + // change call site to a NOP + dtraceProbeSite = (uint8_t*)fixUp; + dtraceProbeSite[-1] = 0x90; // 1-byte nop + dtraceProbeSite[0] = 0x0F; // 4-byte nop + dtraceProbeSite[1] = 0x1F; + dtraceProbeSite[2] = 0x40; + dtraceProbeSite[3] = 0x00; + break; + case x86::kDtraceIsEnabledSite: + // change call site to a clear eax + dtraceProbeSite = (uint8_t*)fixUp; + dtraceProbeSite[-1] = 0x33; // xorl eax,eax + dtraceProbeSite[0] = 0xC0; + dtraceProbeSite[1] = 0x90; // 1-byte nop + dtraceProbeSite[2] = 0x90; // 1-byte nop + dtraceProbeSite[3] = 0x90; // 1-byte nop + break; + case x86::kPCRel32WeakImport: + case x86::kPCRel32: + case x86::kPCRel16: + case x86::kPCRel8: + displacement = 0; + switch ( ref->getTarget().getDefinitionKind() ) { + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4); + break; + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + throw "codegen problem, can't use rel32 to external symbol"; + case ObjectFile::Atom::kTentativeDefinition: + displacement = 0; + break; + case ObjectFile::Atom::kAbsoluteSymbol: + displacement = (ref->getTarget().getSectionOffset() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4); + break; + } + if ( kind == x86::kPCRel8 ) { + if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) { + //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath()); + throwf("rel8 out of range in %s", inAtom->getDisplayName()); + } + *(int8_t*)fixUp = (int8_t)displacement; + } + else if ( kind == x86::kPCRel16 ) { + if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) { + //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath()); + throwf("rel16 out of range in %s", inAtom->getDisplayName()); + } + LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement); + } + else { + if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) { + //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath()); + throwf("rel32 out of range in %s", inAtom->getDisplayName()); + } + LittleEndian::set32(*fixUp, (int32_t)displacement); + } + break; + case x86::kAbsolute32: + switch ( ref->getTarget().getDefinitionKind() ) { + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + case ObjectFile::Atom::kTentativeDefinition: + // pointer contains target address + LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset()); + break; + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + // external relocation ==> pointer contains addend + LittleEndian::set32(*fixUp, ref->getTargetOffset()); + break; + case ObjectFile::Atom::kAbsoluteSymbol: + // pointer contains target address + LittleEndian::set32(*fixUp, ref->getTarget().getSectionOffset() + ref->getTargetOffset()); + break; + } + break; + case x86::kDtraceTypeReference: + case x86::kDtraceProbe: + // nothing to fix up + break; + } +} + + + +template <> +void Writer::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const +{ + const int64_t kTwoGigLimit = 0x7FFFFFFF; + const int64_t kSixtyFourKiloLimit = 0x7FFF; + const int64_t kOneTwentyEightLimit = 0x7F; + uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()]; + bool isExtern = this->makesExternalRelocatableReference(ref->getTarget()); + int64_t displacement; + x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind()); + switch ( kind ) { + case x86::kNoFixUp: + case x86::kFollowOn: + case x86::kGroupSubordinate: + // do nothing + break; + case x86::kPointer: + case x86::kPointerWeakImport: + case x86::kAbsolute32: + { + if ( isExtern ) { + // external relocation ==> pointer contains addend + LittleEndian::set32(*fixUp, ref->getTargetOffset()); + } + else if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) { + // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero + if ( this->indirectSymbolIsLocal(ref) ) + LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset()); + else + LittleEndian::set32(*fixUp, 0); + } + else if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) { + // internal relocation => pointer contains target address + LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset()); + } + else { + // internal relocation to tentative ==> pointer contains addend + LittleEndian::set32(*fixUp, ref->getTargetOffset()); + } + } + break; + case x86::kPointerDiff: + displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()); + LittleEndian::set32(*fixUp, (uint32_t)displacement); + break; + case x86::kPointerDiff16: + displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()); + if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) + throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName()); + LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement); + break; + case x86::kPCRel8: + case x86::kPCRel16: + case x86::kPCRel32: + case x86::kPCRel32WeakImport: + case x86::kDtraceProbeSite: + case x86::kDtraceIsEnabledSite: + { + if ( isExtern ) + displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4); + else + displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4); + if ( kind == x86::kPCRel8 ) { + displacement += 3; + if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) { + //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath()); + throwf("rel8 out of range (%lld)in %s", displacement, inAtom->getDisplayName()); + } + int8_t byte = (int8_t)displacement; + *((int8_t*)fixUp) = byte; + } + else if ( kind == x86::kPCRel16 ) { + displacement += 2; + if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) { + //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath()); + throwf("rel16 out of range in %s", inAtom->getDisplayName()); + } + int16_t word = (int16_t)displacement; + LittleEndian::set16(*((uint16_t*)fixUp), word); + } + else { + if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) { + //fprintf(stderr, "call out of range, displacement=ox%llX, from %s in %s to %s in %s\n", displacement, + // inAtom->getDisplayName(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath()); + throwf("rel32 out of range in %s", inAtom->getDisplayName()); + } + LittleEndian::set32(*fixUp, (int32_t)displacement); + } + } + break; + case x86::kDtraceProbe: + case x86::kDtraceTypeReference: + // nothing to fix up + break; + } +} + +template <> +void Writer::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const +{ + const int64_t twoGigLimit = 0x7FFFFFFF; + uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()]; + uint8_t* dtraceProbeSite; + int64_t displacement = 0; + switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) { + case x86_64::kNoFixUp: + case x86_64::kFollowOn: + case x86_64::kGroupSubordinate: + // do nothing + break; + case x86_64::kPointerWeakImport: + case x86_64::kPointer: + { + //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName()); + if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) { + // external relocation ==> pointer contains addend + LittleEndian::set64(*fixUp, ref->getTargetOffset()); + } + else { + // internal relocation + // pointer contains target address + //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress()); + LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset()); + } + } + break; + case x86_64::kPointerDiff32: + displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()); + if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) + throw "32-bit pointer difference out of range"; + LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement); + break; + case x86_64::kPointerDiff: + LittleEndian::set64(*fixUp, + (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) ); + break; + case x86_64::kPCRel32GOTLoad: + case x86_64::kPCRel32GOTLoadWeakImport: + // if GOT entry was optimized away, change movq instruction to a leaq + if ( std::find(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), &(ref->getTarget())) == fAllSynthesizedNonLazyPointers.end() ) { + //fprintf(stderr, "GOT for %s optimized away\n", ref->getTarget().getDisplayName()); + uint8_t* opcodes = (uint8_t*)fixUp; + if ( opcodes[-2] != 0x8B ) + throw "GOT load reloc does not point to a movq instruction"; + opcodes[-2] = 0x8D; + } + // fall into general rel32 case + case x86_64::kBranchPCRel32WeakImport: + case x86_64::kBranchPCRel32: + case x86_64::kBranchPCRel8: + case x86_64::kPCRel32: + case x86_64::kPCRel32_1: + case x86_64::kPCRel32_2: + case x86_64::kPCRel32_4: + case x86_64::kPCRel32GOT: + case x86_64::kPCRel32GOTWeakImport: + switch ( ref->getTarget().getDefinitionKind() ) { + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + case ObjectFile::Atom::kTentativeDefinition: + displacement = (ref->getTarget().getAddress() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4); + break; + case ObjectFile::Atom::kAbsoluteSymbol: + displacement = (ref->getTarget().getSectionOffset() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4); + break; + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + throw "codegen problem, can't use rel32 to external symbol"; + break; + } + switch ( ref->getKind() ) { + case x86_64::kPCRel32_1: + displacement -= 1; + break; + case x86_64::kPCRel32_2: + displacement -= 2; + break; + case x86_64::kPCRel32_4: + displacement -= 4; + break; + case x86_64::kBranchPCRel8: + displacement += 3; + break; + } + if ( ref->getKind() == x86_64::kBranchPCRel8 ) { + if ( (displacement > 127) || (displacement < (-128)) ) { + fprintf(stderr, "branch out of range from %s (%llX) in %s to %s (%llX) in %s\n", + inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath()); + throw "rel8 out of range"; + } + *((int8_t*)fixUp) = (int8_t)displacement; + } + else { + if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) { + fprintf(stderr, "call out of range from %s (%llX) in %s to %s (%llX) in %s\n", + inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath()); + throw "rel32 out of range"; + } + LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement); + } + break; + case x86_64::kDtraceProbeSite: + // change call site to a NOP + dtraceProbeSite = (uint8_t*)fixUp; + dtraceProbeSite[-1] = 0x90; // 1-byte nop + dtraceProbeSite[0] = 0x0F; // 4-byte nop + dtraceProbeSite[1] = 0x1F; + dtraceProbeSite[2] = 0x40; + dtraceProbeSite[3] = 0x00; + break; + case x86_64::kDtraceIsEnabledSite: + // change call site to a clear eax + dtraceProbeSite = (uint8_t*)fixUp; + dtraceProbeSite[-1] = 0x48; // xorq eax,eax + dtraceProbeSite[0] = 0x33; + dtraceProbeSite[1] = 0xC0; + dtraceProbeSite[2] = 0x90; // 1-byte nop + dtraceProbeSite[3] = 0x90; // 1-byte nop + break; + case x86_64::kDtraceTypeReference: + case x86_64::kDtraceProbe: + // nothing to fix up + break; + } +} + +template <> +void Writer::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const +{ + const int64_t twoGigLimit = 0x7FFFFFFF; + bool external = this->makesExternalRelocatableReference(ref->getTarget()); + uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()]; + int64_t displacement = 0; + int32_t temp32; + switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) { + case x86_64::kNoFixUp: + case x86_64::kFollowOn: + case x86_64::kGroupSubordinate: + // do nothing + break; + case x86_64::kPointer: + case x86_64::kPointerWeakImport: + { + if ( external ) { + // external relocation ==> pointer contains addend + LittleEndian::set64(*fixUp, ref->getTargetOffset()); + } + else { + // internal relocation ==> pointer contains target address + LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset()); + } + } + break; + case x86_64::kPointerDiff32: + // addend in content + LittleEndian::set32(*((uint32_t*)fixUp), ref->getTargetOffset() - ref->getFromTargetOffset() ); + break; + case x86_64::kPointerDiff: + // addend in content + LittleEndian::set64(*fixUp, ref->getTargetOffset() - ref->getFromTargetOffset() ); + break; + case x86_64::kBranchPCRel32: + case x86_64::kBranchPCRel32WeakImport: + case x86_64::kDtraceProbeSite: + case x86_64::kDtraceIsEnabledSite: + case x86_64::kPCRel32: + case x86_64::kPCRel32_1: + case x86_64::kPCRel32_2: + case x86_64::kPCRel32_4: + // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had + temp32 = ref->getTargetOffset(); + if ( external ) { + // extern relocation contains addend + displacement = temp32; + } + else { + // internal relocations contain delta to target address + displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 4); + } + switch ( ref->getKind() ) { + case x86_64::kPCRel32_1: + displacement -= 1; + break; + case x86_64::kPCRel32_2: + displacement -= 2; + break; + case x86_64::kPCRel32_4: + displacement -= 4; + break; + } + if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) { + //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath()); + throw "rel32 out of range"; + } + LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement); + break; + case x86_64::kBranchPCRel8: + // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had + temp32 = ref->getTargetOffset(); + if ( external ) { + // extern relocation contains addend + displacement = temp32; + } + else { + // internal relocations contain delta to target address + displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 1); + } + if ( (displacement > 127) || (displacement < (-128)) ) { + //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath()); + throw "rel8 out of range"; + } + *((int8_t*)fixUp) = (int8_t)displacement; + break; + case x86_64::kPCRel32GOT: + case x86_64::kPCRel32GOTLoad: + case x86_64::kPCRel32GOTWeakImport: + case x86_64::kPCRel32GOTLoadWeakImport: + // contains addend (usually zero) + LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)(ref->getTargetOffset())); + break; + case x86_64::kDtraceTypeReference: + case x86_64::kDtraceProbe: + // nothing to fix up + break; + } +} + +template <> +void Writer::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const +{ + fixUpReference_powerpc(ref, inAtom, buffer, true); +} + +template <> +void Writer::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const +{ + fixUpReference_powerpc(ref, inAtom, buffer, true); +} + +template <> +void Writer::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const +{ + fixUpReference_powerpc(ref, inAtom, buffer, false); +} + +template <> +void Writer::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const +{ + fixUpReference_powerpc(ref, inAtom, buffer, false); +} + +// +// ppc and ppc64 are mostly the same, so they share a template specialzation +// +template +void Writer::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const +{ + uint32_t instruction; + uint32_t newInstruction; + int64_t displacement; + uint64_t targetAddr = 0; + uint64_t picBaseAddr; + uint16_t instructionLowHalf; + uint16_t instructionHighHalf; + uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()]; + pint_t* fixUpPointer = (pint_t*)&buffer[ref->getFixUpOffset()]; + bool relocateableExternal = false; + const int64_t picbase_twoGigLimit = 0x80000000; + + if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) { + targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset(); + if ( finalLinkedImage ) + relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal); + else + relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget()); + } + + switch ( (typename A::ReferenceKinds)(ref->getKind()) ) { + case A::kNoFixUp: + case A::kFollowOn: + case A::kGroupSubordinate: + // do nothing + break; + case A::kPointerWeakImport: + case A::kPointer: + { + //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName()); + if ( finalLinkedImage && (((SectionInfo*)inAtom->getSection())->fAllLazyPointers + || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers) ) { + switch (ref->getTarget().getDefinitionKind()) { + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + // prebound lazy pointer to another dylib ==> pointer contains zero + P::setP(*fixUpPointer, 0); + break; + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + case ObjectFile::Atom::kAbsoluteSymbol: + // prebound lazy pointer to withing this dylib ==> pointer contains address + P::setP(*fixUpPointer, targetAddr); + break; + } + } + else if ( !finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) { + // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero + if ( this->indirectSymbolIsLocal(ref) ) + P::setP(*fixUpPointer, targetAddr); + else + P::setP(*fixUpPointer, 0); + } + else if ( relocateableExternal ) { + if ( fOptions.prebind() ) { + switch (ref->getTarget().getDefinitionKind()) { + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + // prebound external relocation ==> pointer contains addend + P::setP(*fixUpPointer, ref->getTargetOffset()); + break; + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + // prebound external relocation to internal atom ==> pointer contains target address + addend + P::setP(*fixUpPointer, targetAddr); + break; + case ObjectFile::Atom::kAbsoluteSymbol: + break; + } + } + else { + // external relocation ==> pointer contains addend + P::setP(*fixUpPointer, ref->getTargetOffset()); + } + } + else { + // internal relocation + if ( finalLinkedImage || (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition) ) { + // pointer contains target address + //printf("Atom::fixUpReference_powerpc() target.name=%s, target.address=0x%08llX\n", ref->getTarget().getDisplayName(), targetAddr); + P::setP(*fixUpPointer, targetAddr); + } + else { + // pointer contains addend + P::setP(*fixUpPointer, ref->getTargetOffset()); + } + } + } + break; + case A::kPointerDiff64: + P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) ); + break; + case A::kPointerDiff32: + P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) ); + break; + case A::kPointerDiff16: + P::E::set16(*((uint16_t*)fixUp), targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) ); + break; + case A::kDtraceProbeSite: + if ( finalLinkedImage ) { + // change call site to a NOP + BigEndian::set32(*fixUp, 0x60000000); + } + else { + // set bl instuction to branch to address zero in .o file + int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset()); + instruction = BigEndian::get32(*fixUp); + newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC); + BigEndian::set32(*fixUp, newInstruction); + } + break; + case A::kDtraceIsEnabledSite: + if ( finalLinkedImage ) { + // change call site to a li r3,0 + BigEndian::set32(*fixUp, 0x38600000); + } + else { + // set bl instuction to branch to address zero in .o file + int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset()); + instruction = BigEndian::get32(*fixUp); + newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC); + BigEndian::set32(*fixUp, newInstruction); + } + break; + case A::kBranch24WeakImport: + case A::kBranch24: + { + //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress()); + int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset()); + if ( relocateableExternal ) { + // doing "ld -r" to an external symbol + // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target + displacement -= ref->getTarget().getAddress(); + } + else { + const int64_t bl_eightMegLimit = 0x00FFFFFF; + if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) { + //fprintf(stderr, "bl out of range (%lld max is +/-16M) from %s in %s to %s in %s\n", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath()); + throwf("bl out of range (%lld max is +/-16M) from %s at 0x%08llX in %s of %s to %s at 0x%08llX in %s of %s", + displacement, inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getSectionName(), inAtom->getFile()->getPath(), + ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getSectionName(), ref->getTarget().getFile()->getPath()); + } + } + instruction = BigEndian::get32(*fixUp); + newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC); + //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction); + BigEndian::set32(*fixUp, newInstruction); + } + break; + case A::kBranch14: + { + int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset()); + if ( relocateableExternal ) { + // doing "ld -r" to an external symbol + // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target + displacement -= ref->getTarget().getAddress(); + } + const int64_t b_sixtyFourKiloLimit = 0x0000FFFF; + if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) { + //fprintf(stderr, "bl out of range (%lld max is +/-16M) from %s in %s to %s in %s\n", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath()); + throwf("bcc out of range (%lld max is +/-64K) from %s in %s to %s in %s", + displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(), + ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath()); + } + + //fprintf(stderr, "bcc fixup displacement=0x%08llX, atom.addr=0x%08llX, atom.offset=0x%08X\n", displacement, inAtom->getAddress(), (uint32_t)ref->getFixUpOffset()); + instruction = BigEndian::get32(*fixUp); + newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)displacement & 0x0000FFFC); + //fprintf(stderr, "bc fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction); + BigEndian::set32(*fixUp, newInstruction); + } + break; + case A::kPICBaseLow16: + picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset(); + displacement = targetAddr - picBaseAddr; + if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) ) + throw "32-bit pic-base out of range"; + instructionLowHalf = (displacement & 0xFFFF); + instruction = BigEndian::get32(*fixUp); + newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf; + BigEndian::set32(*fixUp, newInstruction); + break; + case A::kPICBaseLow14: + picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset(); + displacement = targetAddr - picBaseAddr; + if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) ) + throw "32-bit pic-base out of range"; + if ( (displacement & 0x3) != 0 ) + throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)displacement); + instructionLowHalf = (displacement & 0xFFFC); + instruction = BigEndian::get32(*fixUp); + newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf; + BigEndian::set32(*fixUp, newInstruction); + break; + case A::kPICBaseHigh16: + picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset(); + displacement = targetAddr - picBaseAddr; + if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) ) + throw "32-bit pic-base out of range"; + instructionLowHalf = displacement >> 16; + if ( (displacement & 0x00008000) != 0 ) + ++instructionLowHalf; + instruction = BigEndian::get32(*fixUp); + newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf; + BigEndian::set32(*fixUp, newInstruction); + break; + case A::kAbsLow16: + if ( relocateableExternal && !finalLinkedImage ) + targetAddr -= ref->getTarget().getAddress(); + instructionLowHalf = (targetAddr & 0xFFFF); + instruction = BigEndian::get32(*fixUp); + newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf; + BigEndian::set32(*fixUp, newInstruction); + break; + case A::kAbsLow14: + if ( relocateableExternal && !finalLinkedImage ) + targetAddr -= ref->getTarget().getAddress(); + if ( (targetAddr & 0x3) != 0 ) + throw "bad address for absolute lo14 instruction fix-up"; + instructionLowHalf = (targetAddr & 0xFFFF); + instruction = BigEndian::get32(*fixUp); + newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf; + BigEndian::set32(*fixUp, newInstruction); + break; + case A::kAbsHigh16: + if ( relocateableExternal ) { + if ( finalLinkedImage ) { + switch (ref->getTarget().getDefinitionKind()) { + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName()); + break; + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + // use target address + break; + case ObjectFile::Atom::kAbsoluteSymbol: + targetAddr = ref->getTarget().getSectionOffset(); + break; + } + } + else { + targetAddr -= ref->getTarget().getAddress(); + } + } + instructionHighHalf = (targetAddr >> 16); + instruction = BigEndian::get32(*fixUp); + newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf; + BigEndian::set32(*fixUp, newInstruction); + break; + case A::kAbsHigh16AddLow: + if ( relocateableExternal ) { + if ( finalLinkedImage ) { + switch (ref->getTarget().getDefinitionKind()) { + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName()); + break; + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + // use target address + break; + case ObjectFile::Atom::kAbsoluteSymbol: + targetAddr = ref->getTarget().getSectionOffset(); + break; + } + } + else { + targetAddr -= ref->getTarget().getAddress(); + } + } + if ( targetAddr & 0x00008000 ) + targetAddr += 0x00010000; + instruction = BigEndian::get32(*fixUp); + newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16); + BigEndian::set32(*fixUp, newInstruction); + break; + case A::kDtraceTypeReference: + case A::kDtraceProbe: + // nothing to fix up + break; + } +} + +template <> +bool Writer::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref) +{ + uint8_t kind = ref->getKind(); + switch ( (ppc::ReferenceKinds)kind ) { + case ppc::kNoFixUp: + case ppc::kFollowOn: + case ppc::kGroupSubordinate: + case ppc::kPointer: + case ppc::kPointerWeakImport: + case ppc::kPointerDiff16: + case ppc::kPointerDiff32: + case ppc::kPointerDiff64: + case ppc::kDtraceProbe: + case ppc::kDtraceProbeSite: + case ppc::kDtraceIsEnabledSite: + case ppc::kDtraceTypeReference: + // these are never used to call external functions + return false; + case ppc::kBranch24: + case ppc::kBranch24WeakImport: + case ppc::kBranch14: + // these are used to call external functions + return true; + case ppc::kPICBaseLow16: + case ppc::kPICBaseLow14: + case ppc::kPICBaseHigh16: + case ppc::kAbsLow16: + case ppc::kAbsLow14: + case ppc::kAbsHigh16: + case ppc::kAbsHigh16AddLow: + // these are only used to call external functions + // in -mlong-branch stubs + switch ( ref->getTarget().getDefinitionKind() ) { + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + // if the .o file this atom came from has long-branch stubs, + // then assume these instructions in a stub. + // Otherwise, these are a direct reference to something (maybe a runtime text reloc) + return ( inAtom->getFile()->hasLongBranchStubs() ); + case ObjectFile::Atom::kTentativeDefinition: + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + case ObjectFile::Atom::kAbsoluteSymbol: + return false; + } + break; + } + return false; +} + +template <> +bool Writer::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref) +{ + uint8_t kind = ref->getKind(); + switch ( (arm::ReferenceKinds)kind ) { + case arm::kBranch24: + case arm::kBranch24WeakImport: + case arm::kThumbBranch22: + case arm::kThumbBranch22WeakImport: + return true; + case arm::kNoFixUp: + case arm::kFollowOn: + case arm::kGroupSubordinate: + case arm::kPointer: + case arm::kReadOnlyPointer: + case arm::kPointerWeakImport: + case arm::kPointerDiff: + case arm::kDtraceProbe: + case arm::kDtraceProbeSite: + case arm::kDtraceIsEnabledSite: + case arm::kDtraceTypeReference: + return false; + } + return false; +} + +template <> +bool Writer::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref) +{ + uint8_t kind = ref->getKind(); + switch ( (ppc64::ReferenceKinds)kind ) { + case ppc::kNoFixUp: + case ppc::kFollowOn: + case ppc::kGroupSubordinate: + case ppc::kPointer: + case ppc::kPointerWeakImport: + case ppc::kPointerDiff16: + case ppc::kPointerDiff32: + case ppc::kPointerDiff64: + case ppc::kPICBaseLow16: + case ppc::kPICBaseLow14: + case ppc::kPICBaseHigh16: + case ppc::kAbsLow16: + case ppc::kAbsLow14: + case ppc::kAbsHigh16: + case ppc::kAbsHigh16AddLow: + case ppc::kDtraceProbe: + case ppc::kDtraceProbeSite: + case ppc::kDtraceIsEnabledSite: + case ppc::kDtraceTypeReference: + // these are never used to call external functions + return false; + case ppc::kBranch24: + case ppc::kBranch24WeakImport: + case ppc::kBranch14: + // these are used to call external functions + return true; + } + return false; +} + +template <> +bool Writer::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref) +{ + uint8_t kind = ref->getKind(); + return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport); +} + +template <> +bool Writer::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref) +{ + uint8_t kind = ref->getKind(); + return (kind == x86_64::kBranchPCRel32 || kind == x86_64::kBranchPCRel32WeakImport); +} + + +template <> +bool Writer::weakImportReferenceKind(uint8_t kind) +{ + return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport); +} + +template <> +bool Writer::weakImportReferenceKind(uint8_t kind) +{ + return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport); +} + +template <> +bool Writer::weakImportReferenceKind(uint8_t kind) +{ + return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport); +} + +template <> +bool Writer::weakImportReferenceKind(uint8_t kind) +{ + switch ( kind ) { + case x86_64::kPointerWeakImport: + case x86_64::kBranchPCRel32WeakImport: + case x86_64::kPCRel32GOTWeakImport: + case x86_64::kPCRel32GOTLoadWeakImport: + return true; + } + return false; +} + +template <> +bool Writer::weakImportReferenceKind(uint8_t kind) +{ + return (kind == arm::kBranch24WeakImport || kind == arm::kThumbBranch22WeakImport || + kind == arm::kPointerWeakImport); +} + +template <> +bool Writer::GOTReferenceKind(uint8_t kind) +{ + return false; +} + +template <> +bool Writer::GOTReferenceKind(uint8_t kind) +{ + return false; +} + +template <> +bool Writer::GOTReferenceKind(uint8_t kind) +{ + return false; +} + +template <> +bool Writer::GOTReferenceKind(uint8_t kind) +{ + switch ( kind ) { + case x86_64::kPCRel32GOT: + case x86_64::kPCRel32GOTWeakImport: + case x86_64::kPCRel32GOTLoad: + case x86_64::kPCRel32GOTLoadWeakImport: + return true; + } + return false; +} + +template <> +bool Writer::GOTReferenceKind(uint8_t kind) +{ + return false; +} + +template <> +bool Writer::optimizableGOTReferenceKind(uint8_t kind) +{ + return false; +} + +template <> +bool Writer::optimizableGOTReferenceKind(uint8_t kind) +{ + return false; +} + +template <> +bool Writer::optimizableGOTReferenceKind(uint8_t kind) +{ + return false; +} + +template <> +bool Writer::optimizableGOTReferenceKind(uint8_t kind) +{ + switch ( kind ) { + case x86_64::kPCRel32GOTLoad: + case x86_64::kPCRel32GOTLoadWeakImport: + return true; + } + return false; +} + +template <> +bool Writer::optimizableGOTReferenceKind(uint8_t kind) +{ + return false; +} + +// 64-bit architectures never need module table, 32-bit sometimes do for backwards compatiblity +template bool Writer::needsModuleTable() {return fOptions.needsModuleTable(); } +template <> bool Writer::needsModuleTable() { return false; } +template <> bool Writer::needsModuleTable() { return false; } + + +template +void Writer::optimizeDylibReferences() +{ + //fprintf(stderr, "original ordinals table:\n"); + //for (std::map::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) { + // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath()); + //} + // find unused dylibs that can be removed + std::map ordinalToReader; + std::map readerAliases; + for (std::map::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) { + ObjectFile::Reader* reader = it->first; + std::map::iterator aliasPos = fLibraryAliases.find(reader); + if ( aliasPos != fLibraryAliases.end() ) { + // already noticed that this reader has same install name as another reader + readerAliases[reader] = aliasPos->second; + } + else if ( !reader->providedExportAtom() && (reader->implicitlyLinked() || fOptions.deadStripDylibs()) ) { + // this reader can be optimized away + it->second = 0xFFFFFFFF; + typename std::map* >::iterator pos = fLibraryToLoadCommand.find(reader); + if ( pos != fLibraryToLoadCommand.end() ) + pos->second->optimizeAway(); + } + else { + // mark this reader as using it ordinal + std::map::iterator pos = ordinalToReader.find(it->second); + if ( pos == ordinalToReader.end() ) + ordinalToReader[it->second] = reader; + else + readerAliases[reader] = pos->second; + } + } + // renumber ordinals (depends on iterator walking in ordinal order) + // all LC_LAZY_LOAD_DYLIB load commands must have highest ordinals + uint32_t newOrdinal = 0; + for (std::map::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) { + if ( it->first <= fLibraryToOrdinal.size() ) { + if ( ! it->second->isLazyLoadedDylib() ) + fLibraryToOrdinal[it->second] = ++newOrdinal; + } + } + for (std::map::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) { + if ( it->first <= fLibraryToOrdinal.size() ) { + if ( it->second->isLazyLoadedDylib() ) { + fLibraryToOrdinal[it->second] = ++newOrdinal; + } + } + } + + // linker does not error when dylib ordinal exceeds 250 + if ( (newOrdinal >= MAX_LIBRARY_ORDINAL) && (fOptions.nameSpace() == Options::kTwoLevelNameSpace) ) + throwf("two level namespace mach-o files can link with at most %d dylibs, this link would use %d dylibs", MAX_LIBRARY_ORDINAL, newOrdinal); + + // add aliases (e.g. -lm points to libSystem.dylib) + for (std::map::iterator it = readerAliases.begin(); it != readerAliases.end(); ++it) { + fLibraryToOrdinal[it->first] = fLibraryToOrdinal[it->second]; + } + + //fprintf(stderr, "new ordinals table:\n"); + //for (std::map::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) { + // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath()); + //} +} + + +template <> +void Writer::scanForAbsoluteReferences() +{ + // arm codegen never has absolute references. FIXME: Is this correct? +} + +template <> +void Writer::scanForAbsoluteReferences() +{ + // x86_64 codegen never has absolute references +} + +template <> +void Writer::scanForAbsoluteReferences() +{ + // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used + if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) { + for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { + ObjectFile::Atom* atom = *it; + std::vector& references = atom->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + ObjectFile::Reference* ref = *rit; + switch (ref->getKind()) { + case x86::kAbsolute32: + throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath()); + return; + } + } + } + } +} + +template <> +void Writer::scanForAbsoluteReferences() +{ + // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used + if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) { + for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { + ObjectFile::Atom* atom = *it; + std::vector& references = atom->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + ObjectFile::Reference* ref = *rit; + switch (ref->getKind()) { + case ppc::kAbsLow16: + case ppc::kAbsLow14: + case ppc::kAbsHigh16: + case ppc::kAbsHigh16AddLow: + throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath()); + return; + } + } + } + } +} + + +// for ppc64 look for any -mdynamic-no-pic codegen +template <> +void Writer::scanForAbsoluteReferences() +{ + // only do this for main executable + if ( mightNeedPadSegment() && (fPageZeroAtom != NULL) ) { + for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { + ObjectFile::Atom* atom = *it; + std::vector& references = atom->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + ObjectFile::Reference* ref = *rit; + switch (ref->getKind()) { + case ppc64::kAbsLow16: + case ppc64::kAbsLow14: + case ppc64::kAbsHigh16: + case ppc64::kAbsHigh16AddLow: + //fprintf(stderr, "found -mdynamic-no-pic codegen in %s in %s\n", atom->getDisplayName(), atom->getFile()->getPath()); + // shrink page-zero and add pad segment to compensate + fPadSegmentInfo = new SegmentInfo(); + strcpy(fPadSegmentInfo->fName, "__4GBFILL"); + fPageZeroAtom->setSize(0x1000); + return; + } + } + } + } +} + + +template +void Writer::insertDummyStubs() +{ + // only needed for x86 +} + +template <> +void Writer::insertDummyStubs() +{ + // any 5-byte stubs that cross a 32-byte cache line may update incorrectly + std::vector*> betterStubs; + for (std::vector*>::iterator it=fAllSynthesizedStubs.begin(); it != fAllSynthesizedStubs.end(); it++) { + switch (betterStubs.size() % 64 ) { + case 12:// stub would occupy 0x3C->0x41 + case 25:// stub would occupy 0x7D->0x82 + case 38:// stub would occupy 0xBE->0xC3 + case 51:// stub would occupy 0xFF->0x04 + betterStubs.push_back(new StubAtom(*this, *((ObjectFile::Atom*)NULL), false)); //pad with dummy stub + break; + } + betterStubs.push_back(*it); + } + // replace + fAllSynthesizedStubs.clear(); + fAllSynthesizedStubs.insert(fAllSynthesizedStubs.begin(), betterStubs.begin(), betterStubs.end()); +} + +template +void Writer::synthesizeStubs() +{ + switch ( fOptions.outputKind() ) { + case Options::kObjectFile: + // these output kinds never have stubs + return; + case Options::kStaticExecutable: + case Options::kDyld: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kDynamicExecutable: + // try to synthesize stubs for these + break; + } + + // walk every atom and reference + for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { + ObjectFile::Atom* atom = *it; + std::vector& references = atom->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + ObjectFile::Reference* ref = *rit; + switch ( ref->getTargetBinding()) { + case ObjectFile::Reference::kUnboundByName: + case ObjectFile::Reference::kDontBind: + break; + case ObjectFile::Reference::kBoundByName: + case ObjectFile::Reference::kBoundDirectly: + ObjectFile::Atom& target = ref->getTarget(); + // build map of which symbols need weak importing + if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition) + || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) { + bool weakImport = this->weakImportReferenceKind(ref->getKind()); + // Obj-C Symbols in Leopard Can't Be Weak Linked + // dyld in Mac OS X 10.3 and earlier need N_WEAK_REF bit set on undefines to objc symbols + // in dylibs that are weakly linked. + if ( (ref->getKind() == A::kNoFixUp) && (strncmp(target.getName(), ".objc_class_name_", 17) == 0) ) { + typename std::map* >::iterator pos; + pos = fLibraryToLoadCommand.find(target.getFile()); + if ( pos != fLibraryToLoadCommand.end() ) { + if ( pos->second->linkedWeak() ) + weakImport = true; + } + } + std::map::iterator pos = fWeakImportMap.find(&target); + if ( pos == fWeakImportMap.end() ) { + // target not in fWeakImportMap, so add + fWeakImportMap[&target] = weakImport; + } + else { + // target in fWeakImportMap, check for weakness mismatch + if ( pos->second != weakImport ) { + // found mismatch + switch ( fOptions.weakReferenceMismatchTreatment() ) { + case Options::kWeakReferenceMismatchError: + throwf("mismatching weak references for symbol: %s", target.getName()); + case Options::kWeakReferenceMismatchWeak: + pos->second = true; + break; + case Options::kWeakReferenceMismatchNonWeak: + pos->second = false; + break; + } + } + } + // update if we use a weak_import or a strong import from this dylib + if ( fWeakImportMap[&target] ) + fDylibReadersWithWeakImports.insert(target.getFile()); + else + fDylibReadersWithNonWeakImports.insert(target.getFile()); + } + // create stubs as needed + if ( this->stubableReference(atom, ref) + && (ref->getTargetOffset() == 0) + && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) { + ObjectFile::Atom* stub = NULL; + std::map::iterator pos = fStubsMap.find(&target); + if ( pos == fStubsMap.end() ) { + bool forLazyDylib = false; + switch ( target.getDefinitionKind() ) { + case ObjectFile::Atom::kRegularDefinition: + case ObjectFile::Atom::kWeakDefinition: + case ObjectFile::Atom::kAbsoluteSymbol: + case ObjectFile::Atom::kTentativeDefinition: + break; + case ObjectFile::Atom::kExternalDefinition: + case ObjectFile::Atom::kExternalWeakDefinition: + if ( target.getFile()->isLazyLoadedDylib() ) + forLazyDylib = true; + break; + } + stub = new StubAtom(*this, target, forLazyDylib); + fStubsMap[&target] = stub; + } + else { + stub = pos->second; + } + // alter reference to use stub instead + ref->setTarget(*stub, 0); + } + else if ( fOptions.usingLazyDylibLinking() && target.getFile()->isLazyLoadedDylib() ) { + throwf("illegal reference to %s in lazy loaded dylib from %s in %s", + target.getDisplayName(), atom->getDisplayName(), + atom->getFile()->getPath()); + } + // create GOT slots (non-lazy pointers) as needed + else if ( this->GOTReferenceKind(ref->getKind()) ) { + // + bool mustUseGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ); + bool useGOT; + if ( fBiggerThanTwoGigs ) { + // in big images use GOT for all zero fill atoms + // this is just a heuristic and may need to be re-examined + useGOT = mustUseGOT || ref->getTarget().isZeroFill(); + } + else { + // < 2GB image so remove all GOT entries that we can + useGOT = mustUseGOT; + } + // if this GOT usage cannot be optimized away then make a GOT enry + if ( ! this->optimizableGOTReferenceKind(ref->getKind()) ) + useGOT = true; + if ( useGOT ) { + ObjectFile::Atom* nlp = NULL; + std::map::iterator pos = fGOTMap.find(&target); + if ( pos == fGOTMap.end() ) { + nlp = new NonLazyPointerAtom(*this, target); + fGOTMap[&target] = nlp; + } + else { + nlp = pos->second; + } + // alter reference to use non lazy pointer instead + ref->setTarget(*nlp, ref->getTargetOffset()); + } + } + } + } + } + + // sort stubs + std::sort(fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end(), AtomByNameSorter()); + + // add dummy fast stubs (x86 only) + if ( !fOptions.slowx86Stubs() ) + this->insertDummyStubs(); + + // sort lazy pointers + std::sort(fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end(), AtomByNameSorter()); + std::sort(fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end(), AtomByNameSorter()); + + + // add stubs to fAllAtoms + if ( fAllSynthesizedStubs.size() != 0 ) { + std::vector textStubs; + std::vector importStubs; + for (typename std::vector*>::iterator sit=fAllSynthesizedStubs.begin(); sit != fAllSynthesizedStubs.end(); ++sit) { + ObjectFile::Atom* stubAtom = *sit; + if ( strcmp(stubAtom->getSegment().getName(), "__TEXT") == 0 ) + textStubs.push_back(stubAtom); + else + importStubs.push_back(stubAtom); + } + // any helper stubs go right after regular stubs + if ( fAllSynthesizedStubHelpers.size() != 0 ) + textStubs.insert(textStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end()); + // insert text stubs right after __text section + ObjectFile::Section* curSection = NULL; + ObjectFile::Atom* prevAtom = NULL; + for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { + ObjectFile::Atom* atom = *it; + ObjectFile::Section* nextSection = atom->getSection(); + if ( nextSection != curSection ) { + if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) { + // found end of __text section, insert stubs here + fAllAtoms->insert(it, textStubs.begin(), textStubs.end()); + break; + } + curSection = nextSection; + } + prevAtom = atom; + } + if ( importStubs.size() != 0 ) { + // insert __IMPORTS stubs right before __LINKEDIT + for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { + ObjectFile::Atom* atom = *it; + ObjectFile::Section* nextSection = atom->getSection(); + if ( nextSection != curSection ) { + // for i386 where stubs are not in __TEXT segment + if ( ((prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__IMPORT") == 0)) + || (strcmp(atom->getSegment().getName(), "__LINKEDIT") == 0) ) { + // insert stubs at end of __IMPORT segment, or before __LINKEDIT + fAllAtoms->insert(it, importStubs.begin(), importStubs.end()); + break; + } + curSection = nextSection; + } + prevAtom = atom; + } + } + } + + + // add lazy dylib pointers to fAllAtoms + if ( fAllSynthesizedLazyDylibPointers.size() != 0 ) { + ObjectFile::Section* curSection = NULL; + ObjectFile::Atom* prevAtom = NULL; + bool inserted = false; + for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { + ObjectFile::Atom* atom = *it; + ObjectFile::Section* nextSection = atom->getSection(); + if ( nextSection != curSection ) { + if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) { + // found end of __dyld section, insert lazy pointers here + fAllAtoms->insert(it, fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end()); + inserted = true; + break; + } + curSection = nextSection; + } + prevAtom = atom; + } + if ( !inserted ) { + throw "can't insert lazy pointers, __dyld section not found"; + } + } + + // add lazy pointers to fAllAtoms + if ( fAllSynthesizedLazyPointers.size() != 0 ) { + ObjectFile::Section* curSection = NULL; + ObjectFile::Atom* prevAtom = NULL; + bool inserted = false; + for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { + ObjectFile::Atom* atom = *it; + ObjectFile::Section* nextSection = atom->getSection(); + if ( nextSection != curSection ) { + if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) { + // found end of __dyld section, insert lazy pointers here + fAllAtoms->insert(it, fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end()); + inserted = true; + break; + } + curSection = nextSection; + } + prevAtom = atom; + } + if ( !inserted ) { + throw "can't insert lazy pointers, __dyld section not found"; + } + } + + // add non-lazy pointers to fAllAtoms + if ( fAllSynthesizedNonLazyPointers.size() != 0 ) { + ObjectFile::Section* curSection = NULL; + ObjectFile::Atom* prevAtom = NULL; + bool inserted = false; + for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { + ObjectFile::Atom* atom = *it; + ObjectFile::Section* nextSection = atom->getSection(); + if ( nextSection != curSection ) { + if ( (prevAtom != NULL) + && ((strcmp(prevAtom->getSectionName(), "__dyld") == 0) + || ((strcmp(prevAtom->getSectionName(), "__data") == 0) && + ((fOptions.outputKind() == Options::kDyld) || (fOptions.outputKind() == Options::kStaticExecutable))) ) ) { + // found end of __dyld section, insert lazy pointers here + fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end()); + inserted = true; + break; + } + curSection = nextSection; + } + prevAtom = atom; + } + if ( !inserted ) { + throw "can't insert non-lazy pointers, __dyld section not found"; + } + } + + // build LC_SEGMENT_SPLIT_INFO content now that all atoms exist + if ( fSplitCodeToDataContentAtom != NULL ) { + for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { + ObjectFile::Atom* atom = *it; + std::vector& references = atom->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + ObjectFile::Reference* ref = *rit; + switch ( ref->getTargetBinding()) { + case ObjectFile::Reference::kUnboundByName: + case ObjectFile::Reference::kDontBind: + break; + case ObjectFile::Reference::kBoundByName: + case ObjectFile::Reference::kBoundDirectly: + if ( this->segmentsCanSplitApart(*atom, ref->getTarget()) ) { + this->addCrossSegmentRef(atom, ref); + } + break; + } + } + } + } + +} + + +template +void Writer::partitionIntoSections() +{ + const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile); + + // for every atom, set its sectionInfo object and section offset + // build up fSegmentInfos along the way + ObjectFile::Section* curSection = NULL; + SectionInfo* currentSectionInfo = NULL; + SegmentInfo* currentSegmentInfo = NULL; + SectionInfo* cstringSectionInfo = NULL; + unsigned int sectionIndex = 1; + fSegmentInfos.reserve(8); + for (unsigned int i=0; i < fAllAtoms->size(); ++i) { + ObjectFile::Atom* atom = (*fAllAtoms)[i]; + if ( (atom->getSection() != curSection) || ((curSection==NULL) && (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0)) ) { + if ( oneSegmentCommand ) { + if ( currentSegmentInfo == NULL ) { + currentSegmentInfo = new SegmentInfo(); + currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; + currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; + this->fSegmentInfos.push_back(currentSegmentInfo); + } + currentSectionInfo = new SectionInfo(); + strcpy(currentSectionInfo->fSectionName, atom->getSectionName()); + strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName()); + currentSectionInfo->fAlignment = atom->getAlignment().powerOf2; + currentSectionInfo->fAllZeroFill = atom->isZeroFill(); + currentSectionInfo->fVirtualSection = (currentSectionInfo->fSectionName[0] == '.'); + if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections ) + currentSectionInfo->setIndex(sectionIndex++); + currentSegmentInfo->fSections.push_back(currentSectionInfo); + if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__cstring") == 0) ) + cstringSectionInfo = currentSectionInfo; + } + else { + if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) { + currentSegmentInfo = new SegmentInfo(); + strcpy(currentSegmentInfo->fName, atom->getSegment().getName()); + uint32_t initprot = 0; + if ( atom->getSegment().isContentReadable() ) + initprot |= VM_PROT_READ; + if ( atom->getSegment().isContentWritable() ) + initprot |= VM_PROT_WRITE; + if ( atom->getSegment().isContentExecutable() ) + initprot |= VM_PROT_EXECUTE; + if ( fOptions.readOnlyx86Stubs() && (strcmp(atom->getSegment().getName(), "__IMPORT") == 0) ) + initprot &= ~VM_PROT_WRITE; // hack until i386 __pointers section is synthesized by linker + currentSegmentInfo->fInitProtection = initprot; + if ( initprot == 0 ) + currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0 + else if ( fOptions.architecture() == CPU_TYPE_ARM ) + currentSegmentInfo->fMaxProtection = currentSegmentInfo->fInitProtection; // iPhoneOS wants max==init + else + currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; + std::vector& customSegProtections = fOptions.customSegmentProtections(); + for(std::vector::iterator it = customSegProtections.begin(); it != customSegProtections.end(); ++it) { + if ( strcmp(it->name, currentSegmentInfo->fName) == 0 ) { + currentSegmentInfo->fInitProtection = it->init; + currentSegmentInfo->fMaxProtection = it->max; + } + } + currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress(); + currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress(); + if ( currentSegmentInfo->fFixedAddress && (&(atom->getSegment()) == &Segment::fgStackSegment) ) + currentSegmentInfo->fIndependentAddress = true; + this->fSegmentInfos.push_back(currentSegmentInfo); + } + currentSectionInfo = new SectionInfo(); + currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large + strcpy(currentSectionInfo->fSectionName, atom->getSectionName()); + strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName()); + currentSectionInfo->fAlignment = atom->getAlignment().powerOf2; + // check for -sectalign override + std::vector& alignmentOverrides = fOptions.sectionAlignments(); + for(std::vector::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) { + if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) ) + currentSectionInfo->fAlignment = it->alignment; + } + currentSectionInfo->fAllZeroFill = atom->isZeroFill(); + currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.'); + if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections ) + currentSectionInfo->setIndex(sectionIndex++); + currentSegmentInfo->fSections.push_back(currentSectionInfo); + } + if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) { + fLoadCommandsSection = currentSectionInfo; + fLoadCommandsSegment = currentSegmentInfo; + } + if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) ) + currentSectionInfo->fAllLazyPointers = true; + if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) ) + currentSectionInfo->fAllLazyPointers = true; + if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__ld_symbol_ptr") == 0) ) + currentSectionInfo->fAllLazyDylibPointers = true; + if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) ) + currentSectionInfo->fAllNonLazyPointers = true; + if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) ) + currentSectionInfo->fAllNonLazyPointers = true; + if ( (fOptions.outputKind() == Options::kDyld) && (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) ) + currentSectionInfo->fAllNonLazyPointers = true; + if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) ) + currentSectionInfo->fAllStubs = true; + if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) ) + currentSectionInfo->fAllStubs = true; + if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) ) + currentSectionInfo->fAllStubs = true; + if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) ) + currentSectionInfo->fAllStubs = true; + if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub4") == 0) ) + currentSectionInfo->fAllStubs = true; + if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub4") == 0) ) + currentSectionInfo->fAllStubs = true; + if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) ) { + currentSectionInfo->fAllSelfModifyingStubs = true; + currentSectionInfo->fAlignment = 6; // force x86 fast stubs to start on 64-byte boundary + } + if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__eh_frame") == 0) ) + currentSectionInfo->fAlignment = __builtin_ctz(sizeof(pint_t)); // always start CFI info pointer aligned + curSection = atom->getSection(); + if ( currentSectionInfo->fAllNonLazyPointers || currentSectionInfo->fAllLazyPointers || currentSectionInfo->fAllLazyDylibPointers + || currentSectionInfo->fAllStubs || currentSectionInfo->fAllSelfModifyingStubs ) { + fSymbolTableCommands->needDynamicTable(); + } + } + // any non-zero fill atoms make whole section marked not-zero-fill + if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() ) + currentSectionInfo->fAllZeroFill = false; + // change section object to be Writer's SectionInfo object + atom->setSection(currentSectionInfo); + // section alignment is that of a contained atom with the greatest alignment + uint8_t atomAlign = atom->getAlignment().powerOf2; + if ( currentSectionInfo->fAlignment < atomAlign ) + currentSectionInfo->fAlignment = atomAlign; + // calculate section offset for this atom + uint64_t offset = currentSectionInfo->fSize; + uint64_t alignment = 1 << atomAlign; + uint64_t currentModulus = (offset % alignment); + uint64_t requiredModulus = atom->getAlignment().modulus; + if ( currentModulus != requiredModulus ) { + if ( requiredModulus > currentModulus ) + offset += requiredModulus-currentModulus; + else + offset += requiredModulus+alignment-currentModulus; + } + atom->setSectionOffset(offset); + uint64_t curAtomSize = atom->getSize(); + currentSectionInfo->fSize = offset + curAtomSize; + // add atom to section vector + currentSectionInfo->fAtoms.push_back(atom); + // update largest size + if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) ) + fLargestAtomSize = curAtomSize; + } + if ( (cstringSectionInfo != NULL) && (cstringSectionInfo->fAlignment > 0) ) { + // when merging cstring sections in .o files, all strings need to use the max alignment + uint64_t offset = 0; + uint64_t cstringAlignment = 1 << cstringSectionInfo->fAlignment; + for (std::vector::iterator it=cstringSectionInfo->fAtoms.begin(); it != cstringSectionInfo->fAtoms.end(); it++) { + offset = (offset + (cstringAlignment-1)) & (-cstringAlignment); + ObjectFile::Atom* atom = *it; + atom->setSectionOffset(offset); + offset += atom->getSize(); + } + cstringSectionInfo->fSize = offset; + } +} + + +struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; }; +class TargetAndOffsetComparor +{ +public: + bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const + { + if ( left.atom != right.atom ) + return ( left.atom < right.atom ); + return ( left.offset < right.offset ); + } +}; + +template <> +bool Writer::addBranchIslands() +{ + return this->addPPCBranchIslands(); +} + +template <> +bool Writer::addBranchIslands() +{ + return this->addPPCBranchIslands(); +} + +template <> +bool Writer::addBranchIslands() +{ + // x86 branches can reach entire 4G address space, so no need for branch islands + return false; +} + +template <> +bool Writer::addBranchIslands() +{ + // x86 branches can reach entire 4G size of largest image + return false; +} + +template <> +bool Writer::addBranchIslands() +{ + // arm branch islands not (yet) supported + // you can instead compile with -mlong-call + return false; +} + +template <> +bool Writer::isBranch24Reference(uint8_t kind) +{ + switch (kind) { + case ppc::kBranch24: + case ppc::kBranch24WeakImport: + return true; + } + return false; +} + +template <> +bool Writer::isBranch24Reference(uint8_t kind) +{ + switch (kind) { + case ppc64::kBranch24: + case ppc64::kBranch24WeakImport: + return true; + } + return false; +} + +// +// PowerPC can do PC relative branches as far as +/-16MB. +// If a branch target is >16MB then we insert one or more +// "branch islands" between the branch and its target that +// allows island hoping to the target. +// +// Branch Island Algorithm +// +// If the __TEXT segment < 16MB, then no branch islands needed +// Otherwise, every 15MB into the __TEXT segment is region is +// added which can contain branch islands. Every out of range +// bl instruction is checked. If it crosses a region, an island +// is added to that region with the same target and the bl is +// adjusted to target the island instead. +// +// In theory, if too many islands are added to one region, it +// could grow the __TEXT enough that other previously in-range +// bl branches could be pushed out of range. We reduce the +// probability this could happen by placing the ranges every +// 15MB which means the region would have to be 1MB (256K islands) +// before any branches could be pushed out of range. +// +template +bool Writer::addPPCBranchIslands() +{ + bool log = false; + bool result = false; + // Can only possibly need branch islands if __TEXT segment > 16M + if ( fLoadCommandsSegment->fSize > 16000000 ) { + if ( log) fprintf(stderr, "ld: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize); + const uint32_t kBetweenRegions = 15*1024*1024; // place regions of islands every 15MB in __text section + SectionInfo* textSection = NULL; + for (std::vector::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) { + if ( strcmp((*it)->fSectionName, "__text") == 0 ) { + textSection = *it; + if ( log) fprintf(stderr, "ld: checking for branch islands, __text section size=%llu\n", textSection->fSize); + break; + } + } + const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions; + typedef std::map AtomToIsland; + AtomToIsland regionsMap[kIslandRegionsCount]; + std::vector regionsIslands[kIslandRegionsCount]; + unsigned int islandCount = 0; + if ( log) fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount); + + // create islands for branch references that are out of range + for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { + ObjectFile::Atom* atom = *it; + std::vector& references = atom->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + ObjectFile::Reference* ref = *rit; + if ( this->isBranch24Reference(ref->getKind()) ) { + ObjectFile::Atom& target = ref->getTarget(); + int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset(); + int64_t dstAddr = target.getAddress() + ref->getTargetOffset(); + int64_t displacement = dstAddr - srcAddr; + TargetAndOffset finalTargetAndOffset = { &target, ref->getTargetOffset() }; + const int64_t kFifteenMegLimit = kBetweenRegions; + if ( displacement > kFifteenMegLimit ) { + // create forward branch chain + ObjectFile::Atom* nextTarget = ⌖ + uint64_t nextTargetOffset = ref->getTargetOffset(); + for (int i=kIslandRegionsCount-1; i >=0 ; --i) { + AtomToIsland* region = ®ionsMap[i]; + int64_t islandRegionAddr = kBetweenRegions * (i+1) + textSection->getBaseAddress(); + if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) { + AtomToIsland::iterator pos = region->find(finalTargetAndOffset); + if ( pos == region->end() ) { + BranchIslandAtom* island = new BranchIslandAtom(*this, target.getDisplayName(), i, *nextTarget, nextTargetOffset); + island->setSection(textSection); + (*region)[finalTargetAndOffset] = island; + if (log) fprintf(stderr, "added island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName()); + regionsIslands[i].push_back(island); + ++islandCount; + nextTarget = island; + nextTargetOffset = 0; + } + else { + nextTarget = pos->second; + nextTargetOffset = 0; + } + } + } + if (log) fprintf(stderr, "using island %s for branch to %s from %s\n", nextTarget->getDisplayName(), target.getDisplayName(), atom->getDisplayName()); + ref->setTarget(*nextTarget, nextTargetOffset); + } + else if ( displacement < (-kFifteenMegLimit) ) { + // create back branching chain + ObjectFile::Atom* prevTarget = ⌖ + uint64_t prevTargetOffset = ref->getTargetOffset(); + for (int i=0; i < kIslandRegionsCount ; ++i) { + AtomToIsland* region = ®ionsMap[i]; + int64_t islandRegionAddr = kBetweenRegions * (i+1); + if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) { + AtomToIsland::iterator pos = region->find(finalTargetAndOffset); + if ( pos == region->end() ) { + BranchIslandAtom* island = new BranchIslandAtom(*this, target.getDisplayName(), i, *prevTarget, prevTargetOffset); + island->setSection(textSection); + (*region)[finalTargetAndOffset] = island; + if (log) fprintf(stderr, "added back island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName()); + regionsIslands[i].push_back(island); + ++islandCount; + prevTarget = island; + prevTargetOffset = 0; + } + else { + prevTarget = pos->second; + prevTargetOffset = 0; + } + } + } + if (log) fprintf(stderr, "using back island %s for %s\n", prevTarget->getDisplayName(), atom->getDisplayName()); + ref->setTarget(*prevTarget, prevTargetOffset); + } + } + } + } + + // insert islands into __text section and adjust section offsets + if ( islandCount > 0 ) { + if ( log ) fprintf(stderr, "ld: %u branch islands required in %u regions\n", islandCount, kIslandRegionsCount); + std::vector newAtomList; + newAtomList.reserve(textSection->fAtoms.size()+islandCount); + uint64_t islandRegionAddr = kBetweenRegions + textSection->getBaseAddress(); + uint64_t textSectionAlignment = (1 << textSection->fAlignment); + int regionIndex = 0; + uint64_t atomSlide = 0; + uint64_t sectionOffset = 0; + for (std::vector::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) { + ObjectFile::Atom* atom = *it; + if ( atom->getAddress() > islandRegionAddr ) { + uint64_t islandStartOffset = atom->getSectionOffset() + atomSlide; + sectionOffset = islandStartOffset; + std::vector* regionIslands = ®ionsIslands[regionIndex]; + for (std::vector::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) { + ObjectFile::Atom* islandAtom = *rit; + newAtomList.push_back(islandAtom); + uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2); + sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) ); + islandAtom->setSectionOffset(sectionOffset); + sectionOffset += islandAtom->getSize(); + } + ++regionIndex; + islandRegionAddr += kBetweenRegions; + uint64_t islandRegionAlignmentBlocks = (sectionOffset - islandStartOffset + textSectionAlignment - 1) / textSectionAlignment; + atomSlide += (islandRegionAlignmentBlocks * textSectionAlignment); + } + newAtomList.push_back(atom); + if ( atomSlide != 0 ) + atom->setSectionOffset(atom->getSectionOffset()+atomSlide); + } + sectionOffset = textSection->fSize+atomSlide; + // put any remaining islands at end of __text section + if ( regionIndex < kIslandRegionsCount ) { + std::vector* regionIslands = ®ionsIslands[regionIndex]; + for (std::vector::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) { + ObjectFile::Atom* islandAtom = *rit; + newAtomList.push_back(islandAtom); + uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2); + sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) ); + islandAtom->setSectionOffset(sectionOffset); + sectionOffset += islandAtom->getSize(); + } + } + + textSection->fAtoms = newAtomList; + textSection->fSize = sectionOffset; + result = true; + } + + } + return result; +} + + +template +void Writer::adjustLoadCommandsAndPadding() +{ + fSegmentCommands->computeSize(); + + // recompute load command section offsets + uint64_t offset = 0; + std::vector& loadCommandAtoms = fLoadCommandsSection->fAtoms; + const unsigned int atomCount = loadCommandAtoms.size(); + for (unsigned int i=0; i < atomCount; ++i) { + ObjectFile::Atom* atom = loadCommandAtoms[i]; + uint64_t alignment = 1 << atom->getAlignment().powerOf2; + offset = ( (offset+alignment-1) & (-alignment) ); + atom->setSectionOffset(offset); + uint32_t atomSize = atom->getSize(); + if ( atomSize > fLargestAtomSize ) + fLargestAtomSize = atomSize; + offset += atomSize; + fLoadCommandsSection->fSize = offset; + } + + std::vector& sectionInfos = fLoadCommandsSegment->fSections; + const int sectionCount = sectionInfos.size(); + uint32_t totalSizeOfHeaderAndLoadCommands = 0; + for(int j=0; j < sectionCount; ++j) { + SectionInfo* curSection = sectionInfos[j]; + totalSizeOfHeaderAndLoadCommands += curSection->fSize; + if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) + break; + } + uint64_t paddingSize = 0; + if ( fOptions.outputKind() == Options::kDyld ) { + // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address + paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096); + } + else if ( fOptions.outputKind() == Options::kObjectFile ) { + // mach-o .o files need no padding between load commands and first section + paddingSize = 0; + } + else if ( fOptions.makeEncryptable() ) { + // want load commands to end on a page boundary, so __text starts on page boundary + paddingSize = 4096 - ((totalSizeOfHeaderAndLoadCommands+fOptions.minimumHeaderPad()) % 4096) + fOptions.minimumHeaderPad(); + fEncryptionLoadCommand->setStartEncryptionOffset(totalSizeOfHeaderAndLoadCommands+paddingSize); + } + else { + // work backwards from end of segment and lay out sections so that extra room goes to padding atom + uint64_t addr = 0; + for(int j=sectionCount-1; j >=0; --j) { + SectionInfo* curSection = sectionInfos[j]; + addr -= curSection->fSize; + addr = addr & (0 - (1 << curSection->fAlignment)); + if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) { + addr -= totalSizeOfHeaderAndLoadCommands; + paddingSize = addr % 4096; + break; + } + } + + // if command line requires more padding than this + uint32_t minPad = fOptions.minimumHeaderPad(); + if ( fOptions.maxMminimumHeaderPad() ) { + // -headerpad_max_install_names means there should be room for every path load command to grow to 1204 bytes + uint32_t altMin = fLibraryToOrdinal.size() * MAXPATHLEN; + if ( fOptions.outputKind() == Options::kDynamicLibrary ) + altMin += MAXPATHLEN; + if ( altMin > minPad ) + minPad = altMin; + } + if ( paddingSize < minPad ) { + int extraPages = (minPad - paddingSize + 4095)/4096; + paddingSize += extraPages * 4096; + } + } + + // adjust atom size and update section size + fHeaderPadding->setSize(paddingSize); + for(int j=0; j < sectionCount; ++j) { + SectionInfo* curSection = sectionInfos[j]; + if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) + curSection->fSize = paddingSize; + } +} + +// assign file offsets and logical address to all segments +template +void Writer::assignFileOffsets() +{ + bool finalLinkedImage = (fOptions.outputKind() != Options::kObjectFile); + bool haveFixedSegments = false; + uint64_t fileOffset = 0; + uint64_t nextContiguousAddress = fOptions.baseAddress(); + uint64_t nextReadOnlyAddress = fOptions.baseAddress(); + uint64_t nextWritableAddress = fOptions.baseWritableAddress(); + + // process segments with fixed addresses (-segaddr) + for (std::vector::iterator it = fOptions.customSegmentAddresses().begin(); it != fOptions.customSegmentAddresses().end(); ++it) { + for (std::vector::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) { + SegmentInfo* curSegment = *segit; + if ( strcmp(curSegment->fName, it->name) == 0 ) { + curSegment->fBaseAddress = it->address; + curSegment->fFixedAddress = true; + break; + } + } + } + + // Run through the segments and each segment's sections to assign addresses + for (std::vector::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) { + SegmentInfo* curSegment = *segit; + + if ( fOptions.splitSeg() ) { + if ( curSegment->fInitProtection & VM_PROT_WRITE ) + nextContiguousAddress = nextWritableAddress; + else + nextContiguousAddress = nextReadOnlyAddress; + } + + fileOffset = (fileOffset+4095) & (-4096); + curSegment->fFileOffset = fileOffset; + + // Set the segment base address + if ( curSegment->fFixedAddress ) + haveFixedSegments = true; + else + curSegment->fBaseAddress = nextContiguousAddress; + + // We've set the segment address, now run through each section. + uint64_t address = curSegment->fBaseAddress; + SectionInfo* firstZeroFillSection = NULL; + SectionInfo* prevSection = NULL; + + std::vector& sectionInfos = curSegment->fSections; + + for (std::vector::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) { + SectionInfo* curSection = *it; + + // adjust section address based on alignment + uint64_t alignment = 1 << curSection->fAlignment; + address = ( (address+alignment-1) & (-alignment) ); + + // adjust file offset to match address + if ( prevSection != NULL ) { + if ( finalLinkedImage || !prevSection->fVirtualSection ) + fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset; + else + fileOffset = ( (fileOffset+alignment-1) & (-alignment) ); + } + + // update section info + curSection->fFileOffset = fileOffset; + curSection->setBaseAddress(address); + //fprintf(stderr, "%s %s %llX\n", curSegment->fName, curSection->fSectionName, address); + + // keep track of trailing zero fill sections + if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) ) + firstZeroFillSection = curSection; + if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && finalLinkedImage ) + throwf("zero-fill section %s not at end of segment", curSection->fSectionName); + + // update running pointers + if ( finalLinkedImage || !curSection->fVirtualSection ) + address += curSection->fSize; + fileOffset += curSection->fSize; + + // sanity check size of 32-bit binaries + if ( address > maxAddress() ) + throwf("section %s exceeds 4GB limit", curSection->fSectionName); + + // update segment info + curSegment->fFileSize = fileOffset - curSegment->fFileOffset; + curSegment->fSize = curSegment->fFileSize; + prevSection = curSection; + } + + if ( fOptions.outputKind() == Options::kObjectFile ) { + // don't page align .o files + } + else { + // optimize trailing zero-fill sections to not occupy disk space + if ( firstZeroFillSection != NULL ) { + curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset; + fileOffset = firstZeroFillSection->fFileOffset; + } + // page align segment size + curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096); + curSegment->fSize = (curSegment->fSize+4095) & (-4096); + if ( !curSegment->fIndependentAddress && (curSegment->fBaseAddress >= nextContiguousAddress) ) { + nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096); + if ( curSegment->fInitProtection & VM_PROT_WRITE ) + nextWritableAddress = nextContiguousAddress; + else + nextReadOnlyAddress = nextContiguousAddress; + } + } + } + + // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK) + if ( haveFixedSegments ) { + int segCount = fSegmentInfos.size(); + for(int i=0; i < segCount; ++i) { + SegmentInfo* segment1 = fSegmentInfos[i]; + + for(int j=0; j < segCount; ++j) { + if ( i != j ) { + SegmentInfo* segment2 = fSegmentInfos[j]; + + if ( segment1->fBaseAddress < segment2->fBaseAddress ) { + if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress ) + throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)", + segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize); + } + else if ( segment1->fBaseAddress > segment2->fBaseAddress ) { + if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress ) + throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)", + segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize); + } + else if ( (segment1->fSize != 0) && (segment2->fSize != 0) ) { + throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)", + segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize); + } + } + } + } + } + + // set up fFirstWritableSegment and fWritableSegmentPastFirst4GB + for (std::vector::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) { + SegmentInfo* curSegment = *segit; + if ( (curSegment->fInitProtection & VM_PROT_WRITE) != 0 ) { + if ( fFirstWritableSegment == NULL ) + fFirstWritableSegment = curSegment; + if ( (curSegment->fBaseAddress + curSegment->fSize - fOptions.baseAddress()) >= 0x100000000LL ) + fWritableSegmentPastFirst4GB = true; + } + } + + // record size of encrypted part of __TEXT segment + if ( fOptions.makeEncryptable() ) { + for (std::vector::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) { + SegmentInfo* curSegment = *segit; + if ( strcmp(curSegment->fName, "__TEXT") == 0 ) { + fEncryptionLoadCommand->setEndEncryptionOffset(curSegment->fFileSize); + break; + } + } + } + +} + +template +void Writer::adjustLinkEditSections() +{ + // link edit content is always in last segment + SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1]; + unsigned int firstLinkEditSectionIndex = 0; + while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 ) + ++firstLinkEditSectionIndex; + + const unsigned int linkEditSectionCount = lastSeg->fSections.size(); + uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset; + uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress(); + if ( fPadSegmentInfo != NULL ) { + // insert __4GBFILL segment into segments vector before LINKEDIT + for(std::vector::iterator it = fSegmentInfos.begin(); it != fSegmentInfos.end(); ++it) { + if ( *it == lastSeg ) { + fSegmentInfos.insert(it, fPadSegmentInfo); + break; + } + } + // adjust __4GBFILL segment to span from end of last segment to zeroPageSize + fPadSegmentInfo->fSize = fOptions.zeroPageSize() - address; + fPadSegmentInfo->fBaseAddress = address; + // adjust LINKEDIT to start at zeroPageSize + address = fOptions.zeroPageSize(); + lastSeg->fBaseAddress = fOptions.zeroPageSize(); + } + for (unsigned int i=firstLinkEditSectionIndex; i < linkEditSectionCount; ++i) { + std::vector& atoms = lastSeg->fSections[i]->fAtoms; + // adjust section address based on alignment + uint64_t sectionAlignment = 1 << lastSeg->fSections[i]->fAlignment; + uint64_t pad = ((address+sectionAlignment-1) & (-sectionAlignment)) - address; + address += pad; + fileOffset += pad; // adjust file offset to match address + lastSeg->fSections[i]->setBaseAddress(address); + if ( strcmp(lastSeg->fSections[i]->fSectionName, "._absolute") == 0 ) + lastSeg->fSections[i]->setBaseAddress(0); + lastSeg->fSections[i]->fFileOffset = fileOffset; + uint64_t sectionOffset = 0; + for (unsigned int j=0; j < atoms.size(); ++j) { + ObjectFile::Atom* atom = atoms[j]; + uint64_t alignment = 1 << atom->getAlignment().powerOf2; + sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) ); + atom->setSectionOffset(sectionOffset); + uint64_t size = atom->getSize(); + sectionOffset += size; + if ( size > fLargestAtomSize ) + fLargestAtomSize = size; + } + //fprintf(stderr, "setting: lastSeg->fSections[%d]->fSize = 0x%08llX\n", i, sectionOffset); + lastSeg->fSections[i]->fSize = sectionOffset; + fileOffset += sectionOffset; + address += sectionOffset; + } + if ( fOptions.outputKind() == Options::kObjectFile ) { + //lastSeg->fBaseAddress = 0; + //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]-> + //lastSeg->fFileOffset = 0; + //lastSeg->fFileSize = + } + else { + lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset; + lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096); + } +} + + +template +ObjectFile::Atom::Scope MachHeaderAtom::getScope() const +{ + switch ( fWriter.fOptions.outputKind() ) { + case Options::kDynamicExecutable: + case Options::kStaticExecutable: + return ObjectFile::Atom::scopeGlobal; + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kDyld: + case Options::kObjectFile: + return ObjectFile::Atom::scopeLinkageUnit; + } + throw "unknown header type"; +} + +template +ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom::getSymbolTableInclusion() const +{ + switch ( fWriter.fOptions.outputKind() ) { + case Options::kDynamicExecutable: + return ObjectFile::Atom::kSymbolTableInAndNeverStrip; + case Options::kStaticExecutable: + return ObjectFile::Atom::kSymbolTableInAsAbsolute; + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kDyld: + return ObjectFile::Atom::kSymbolTableIn; + case Options::kObjectFile: + return ObjectFile::Atom::kSymbolTableNotIn; + } + throw "unknown header type"; +} + +template +const char* MachHeaderAtom::getName() const +{ + switch ( fWriter.fOptions.outputKind() ) { + case Options::kDynamicExecutable: + case Options::kStaticExecutable: + return "__mh_execute_header"; + case Options::kDynamicLibrary: + return "__mh_dylib_header"; + case Options::kDynamicBundle: + return "__mh_bundle_header"; + case Options::kObjectFile: + return NULL; + case Options::kDyld: + return "__mh_dylinker_header"; + } + throw "unknown header type"; +} + +template +const char* MachHeaderAtom::getDisplayName() const +{ + switch ( fWriter.fOptions.outputKind() ) { + case Options::kDynamicExecutable: + case Options::kStaticExecutable: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kDyld: + return this->getName(); + case Options::kObjectFile: + return "mach header"; + } + throw "unknown header type"; +} + +template +void MachHeaderAtom::copyRawContent(uint8_t buffer[]) const +{ + // get file type + uint32_t fileType = 0; + switch ( fWriter.fOptions.outputKind() ) { + case Options::kDynamicExecutable: + case Options::kStaticExecutable: + fileType = MH_EXECUTE; + break; + case Options::kDynamicLibrary: + fileType = MH_DYLIB; + break; + case Options::kDynamicBundle: + fileType = MH_BUNDLE; + break; + case Options::kObjectFile: + fileType = MH_OBJECT; + break; + case Options::kDyld: + fileType = MH_DYLINKER; + break; + } + + // get flags + uint32_t flags = 0; + if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) { + if ( fWriter.fCanScatter ) + flags = MH_SUBSECTIONS_VIA_SYMBOLS; + } + else { + if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) { + flags |= MH_NOUNDEFS; + } + else { + flags = MH_DYLDLINK; + if ( fWriter.fOptions.bindAtLoad() ) + flags |= MH_BINDATLOAD; + switch ( fWriter.fOptions.nameSpace() ) { + case Options::kTwoLevelNameSpace: + flags |= MH_TWOLEVEL | MH_NOUNDEFS; + break; + case Options::kFlatNameSpace: + break; + case Options::kForceFlatNameSpace: + flags |= MH_FORCE_FLAT; + break; + } + if ( fWriter.fHasWeakExports ) + flags |= MH_WEAK_DEFINES; + if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports ) + flags |= MH_BINDS_TO_WEAK; + if ( fWriter.fOptions.prebind() ) + flags |= MH_PREBOUND; + if ( fWriter.fOptions.splitSeg() ) + flags |= MH_SPLIT_SEGS; + if ( (fWriter.fOptions.outputKind() == Options::kDynamicLibrary) && fWriter.fNoReExportedDylibs ) + flags |= MH_NO_REEXPORTED_DYLIBS; + if ( fWriter.fOptions.positionIndependentExecutable() ) + flags |= MH_PIE; + } + if ( fWriter.fOptions.hasExecutableStack() ) + flags |= MH_ALLOW_STACK_EXECUTION; + if ( fWriter.fOptions.readerOptions().fRootSafe ) + flags |= MH_ROOT_SAFE; + if ( fWriter.fOptions.readerOptions().fSetuidSafe ) + flags |= MH_SETUID_SAFE; + } + + // get commands info + uint32_t commandsSize = 0; + uint32_t commandsCount = 0; + + std::vector& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms; + for (std::vector::iterator it=loadCommandAtoms.begin(); it != loadCommandAtoms.end(); it++) { + ObjectFile::Atom* atom = *it; + commandsSize += atom->getSize(); + // segment and symbol table atoms can contain more than one load command + if ( atom == fWriter.fSegmentCommands ) + commandsCount += fWriter.fSegmentCommands->commandCount(); + else if ( atom == fWriter.fSymbolTableCommands ) + commandsCount += fWriter.fSymbolTableCommands->commandCount(); + else if ( atom->getSize() != 0 ) + ++commandsCount; + } + + // fill out mach_header + macho_header* mh = (macho_header*)buffer; + setHeaderInfo(*mh); + mh->set_filetype(fileType); + mh->set_ncmds(commandsCount); + mh->set_sizeofcmds(commandsSize); + mh->set_flags(flags); +} + +template <> +void MachHeaderAtom::setHeaderInfo(macho_header& header) const +{ + header.set_magic(MH_MAGIC); + header.set_cputype(CPU_TYPE_POWERPC); + header.set_cpusubtype(fWriter.fCpuConstraint); +} + +template <> +void MachHeaderAtom::setHeaderInfo(macho_header& header) const +{ + header.set_magic(MH_MAGIC_64); + header.set_cputype(CPU_TYPE_POWERPC64); + if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) ) + header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL | 0x80000000); + else + header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL); + header.set_reserved(0); +} + +template <> +void MachHeaderAtom::setHeaderInfo(macho_header& header) const +{ + header.set_magic(MH_MAGIC); + header.set_cputype(CPU_TYPE_I386); + header.set_cpusubtype(CPU_SUBTYPE_I386_ALL); +} + +template <> +void MachHeaderAtom::setHeaderInfo(macho_header& header) const +{ + header.set_magic(MH_MAGIC_64); + header.set_cputype(CPU_TYPE_X86_64); + if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) ) + header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL | 0x80000000); + else + header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL); + header.set_reserved(0); +} + +template <> +void MachHeaderAtom::setHeaderInfo(macho_header& header) const +{ + header.set_magic(MH_MAGIC); + header.set_cputype(CPU_TYPE_ARM); + header.set_cpusubtype(fWriter.fCpuConstraint); +} + +template +CustomStackAtom::CustomStackAtom(Writer& writer) + : WriterAtom(writer, Segment::fgStackSegment) +{ + if ( stackGrowsDown() ) + Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize()); + else + Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr()); +} + + +template <> bool CustomStackAtom::stackGrowsDown() { return true; } +template <> bool CustomStackAtom::stackGrowsDown() { return true; } +template <> bool CustomStackAtom::stackGrowsDown() { return true; } +template <> bool CustomStackAtom::stackGrowsDown() { return true; } +template <> bool CustomStackAtom::stackGrowsDown() { return true; } + +template +void SegmentLoadCommandsAtom::computeSize() +{ + uint64_t size = 0; + std::vector& segmentInfos = fWriter.fSegmentInfos; + const int segCount = segmentInfos.size(); + for(int i=0; i < segCount; ++i) { + size += sizeof(macho_segment_command

); + std::vector& sectionInfos = segmentInfos[i]->fSections; + const int sectionCount = sectionInfos.size(); + for(int j=0; j < sectionCount; ++j) { + if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection ) + size += sizeof(macho_section

); + } + } + fSize = size; + fCommandCount = segCount; + if ( fWriter.fPadSegmentInfo != NULL ) { + ++fCommandCount; + fSize += sizeof(macho_segment_command

); + } +} + +template <> +uint64_t LoadCommandAtom::alignedSize(uint64_t size) +{ + return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o +} + +template <> +uint64_t LoadCommandAtom::alignedSize(uint64_t size) +{ + return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o +} + +template <> +uint64_t LoadCommandAtom::alignedSize(uint64_t size) +{ + return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o +} + +template <> +uint64_t LoadCommandAtom::alignedSize(uint64_t size) +{ + return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o +} + +template <> +uint64_t LoadCommandAtom::alignedSize(uint64_t size) +{ + return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o +} + +template +void SegmentLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile ); + bzero(buffer, size); + uint8_t* p = buffer; + typename std::vector& segmentInfos = fWriter.fSegmentInfos; + const int segCount = segmentInfos.size(); + for(int i=0; i < segCount; ++i) { + SegmentInfo* segInfo = segmentInfos[i]; + const int sectionCount = segInfo->fSections.size(); + macho_segment_command

* cmd = (macho_segment_command

*)p; + cmd->set_cmd(macho_segment_command

::CMD); + cmd->set_segname(segInfo->fName); + cmd->set_vmaddr(segInfo->fBaseAddress); + cmd->set_vmsize(segInfo->fSize); + cmd->set_fileoff(segInfo->fFileOffset); + cmd->set_filesize(segInfo->fFileSize); + cmd->set_maxprot(segInfo->fMaxProtection); + cmd->set_initprot(segInfo->fInitProtection); + // add sections array + macho_section

* const sections = (macho_section

*)&p[sizeof(macho_segment_command

)]; + unsigned int sectionsEmitted = 0; + for (int j=0; j < sectionCount; ++j) { + SectionInfo* sectInfo = segInfo->fSections[j]; + if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) { + macho_section

* sect = §ions[sectionsEmitted++]; + if ( oneSegment ) { + // .o file segment does not cover load commands, so recalc at first real section + if ( sectionsEmitted == 1 ) { + cmd->set_vmaddr(sectInfo->getBaseAddress()); + cmd->set_fileoff(sectInfo->fFileOffset); + } + cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff()); + cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize); + } + sect->set_sectname(sectInfo->fSectionName); + sect->set_segname(sectInfo->fSegmentName); + sect->set_addr(sectInfo->getBaseAddress()); + sect->set_size(sectInfo->fSize); + sect->set_offset(sectInfo->fFileOffset); + sect->set_align(sectInfo->fAlignment); + if ( sectInfo->fRelocCount != 0 ) { + sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info

) + fWriter.fSectionRelocationsAtom->getFileOffset()); + sect->set_nreloc(sectInfo->fRelocCount); + } + if ( sectInfo->fAllZeroFill ) { + sect->set_flags(S_ZEROFILL); + sect->set_offset(0); + } + else if ( sectInfo->fAllLazyPointers ) { + sect->set_flags(S_LAZY_SYMBOL_POINTERS); + sect->set_reserved1(sectInfo->fIndirectSymbolOffset); + } + else if ( sectInfo->fAllLazyDylibPointers ) { + sect->set_flags(S_LAZY_DYLIB_SYMBOL_POINTERS); + sect->set_reserved1(sectInfo->fIndirectSymbolOffset); + } + else if ( sectInfo->fAllNonLazyPointers ) { + sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS); + sect->set_reserved1(sectInfo->fIndirectSymbolOffset); + } + else if ( sectInfo->fAllStubs ) { + sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS); + sect->set_reserved1(sectInfo->fIndirectSymbolOffset); + sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size()); + } + else if ( sectInfo->fAllSelfModifyingStubs ) { + sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE); + sect->set_reserved1(sectInfo->fIndirectSymbolOffset); + sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size()); + } + else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) { + sect->set_flags(S_MOD_INIT_FUNC_POINTERS); + } + else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) { + sect->set_flags(S_MOD_TERM_FUNC_POINTERS); + } + else if ( (strcmp(sectInfo->fSectionName, "__eh_frame") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) { + sect->set_flags(S_COALESCED | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS); + } + else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) { + sect->set_flags(S_COALESCED); + } + else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) { + sect->set_flags(S_COALESCED); + } + else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) { + sect->set_flags(S_INTERPOSING); + } + else if ( (strcmp(sectInfo->fSectionName, "__cstring") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) { + sect->set_flags(S_CSTRING_LITERALS); + } + else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) { + sect->set_flags(S_4BYTE_LITERALS); + } + else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) { + sect->set_flags(S_8BYTE_LITERALS); + } + else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) { + sect->set_flags(S_16BYTE_LITERALS); + } + else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) { + sect->set_flags(S_LITERAL_POINTERS); + } + else if ( (strcmp(sectInfo->fSectionName, "__cls_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) { + sect->set_flags(S_LITERAL_POINTERS); + } + else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) { + sect->set_flags(S_DTRACE_DOF); + } + else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) { + sect->set_flags(S_DTRACE_DOF); + } + else if ( (strncmp(sectInfo->fSectionName, "__text", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) { + sect->set_flags(S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS); + if ( sectInfo->fHasTextLocalRelocs ) + sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC); + if ( sectInfo->fHasTextExternalRelocs ) + sect->set_flags(sect->flags() | S_ATTR_EXT_RELOC); + } + } + } + p = &p[sizeof(macho_segment_command

) + sectionsEmitted*sizeof(macho_section

)]; + cmd->set_cmdsize(sizeof(macho_segment_command

) + sectionsEmitted*sizeof(macho_section

)); + cmd->set_nsects(sectionsEmitted); + } +} + + +template +SymbolTableLoadCommandsAtom::SymbolTableLoadCommandsAtom(Writer& writer) + : LoadCommandAtom(writer, Segment::fgTextSegment) +{ + bzero(&fSymbolTable, sizeof(macho_symtab_command

)); + bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command

)); + switch ( fWriter.fOptions.outputKind() ) { + case Options::kDynamicExecutable: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kDyld: + fNeedsDynamicSymbolTable = true; + break; + case Options::kObjectFile: + case Options::kStaticExecutable: + fNeedsDynamicSymbolTable = false; + break; + } + writer.fSymbolTableCommands = this; +} + + + +template +void SymbolTableLoadCommandsAtom::needDynamicTable() +{ + fNeedsDynamicSymbolTable = true; +} + + +template +uint64_t SymbolTableLoadCommandsAtom::getSize() const +{ + if ( fNeedsDynamicSymbolTable ) + return this->alignedSize(sizeof(macho_symtab_command

) + sizeof(macho_dysymtab_command

)); + else + return this->alignedSize(sizeof(macho_symtab_command

)); +} + +template +void SymbolTableLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + // build LC_DYSYMTAB command + macho_symtab_command

* symbolTableCmd = (macho_symtab_command

*)buffer; + bzero(symbolTableCmd, sizeof(macho_symtab_command

)); + symbolTableCmd->set_cmd(LC_SYMTAB); + symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command

)); + symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount); + symbolTableCmd->set_symoff(fWriter.fSymbolTableAtom->getFileOffset()); + symbolTableCmd->set_stroff(fWriter.fStringsAtom->getFileOffset()); + symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize()); + + // build LC_DYSYMTAB command + if ( fNeedsDynamicSymbolTable ) { + macho_dysymtab_command

* dynamicSymbolTableCmd = (macho_dysymtab_command

*)&buffer[sizeof(macho_symtab_command

)]; + bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command

)); + dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB); + dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command

)); + dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex); + dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount); + dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex); + dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount); + dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex); + dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount); + if ( fWriter.fModuleInfoAtom != NULL ) { + dynamicSymbolTableCmd->set_tocoff(fWriter.fModuleInfoAtom->getTableOfContentsFileOffset()); + dynamicSymbolTableCmd->set_ntoc(fWriter.fSymbolTableExportCount); + dynamicSymbolTableCmd->set_modtaboff(fWriter.fModuleInfoAtom->getModuleTableFileOffset()); + dynamicSymbolTableCmd->set_nmodtab(1); + dynamicSymbolTableCmd->set_extrefsymoff(fWriter.fModuleInfoAtom->getReferencesFileOffset()); + dynamicSymbolTableCmd->set_nextrefsyms(fWriter.fModuleInfoAtom->getReferencesCount()); + } + dynamicSymbolTableCmd->set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset()); + dynamicSymbolTableCmd->set_nindirectsyms(fWriter.fIndirectTableAtom->fTable.size()); + if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) { + dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset()); + dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size()); + dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset()); + dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size()); + } + } +} + + +template +unsigned int SymbolTableLoadCommandsAtom::commandCount() +{ + return fNeedsDynamicSymbolTable ? 2 : 1; +} + +template +uint64_t DyldLoadCommandsAtom::getSize() const +{ + return this->alignedSize(sizeof(macho_dylinker_command

) + strlen("/usr/lib/dyld") + 1); +} + +template +void DyldLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + bzero(buffer, size); + macho_dylinker_command

* cmd = (macho_dylinker_command

*)buffer; + if ( fWriter.fOptions.outputKind() == Options::kDyld ) + cmd->set_cmd(LC_ID_DYLINKER); + else + cmd->set_cmd(LC_LOAD_DYLINKER); + cmd->set_cmdsize(this->getSize()); + cmd->set_name_offset(); + strcpy((char*)&buffer[sizeof(macho_dylinker_command

)], "/usr/lib/dyld"); +} + +template +uint64_t AllowableClientLoadCommandsAtom::getSize() const +{ + return this->alignedSize(sizeof(macho_sub_client_command

) + strlen(this->clientString) + 1); +} + +template +void AllowableClientLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + + bzero(buffer, size); + macho_sub_client_command

* cmd = (macho_sub_client_command

*)buffer; + cmd->set_cmd(LC_SUB_CLIENT); + cmd->set_cmdsize(size); + cmd->set_client_offset(); + strcpy((char*)&buffer[sizeof(macho_sub_client_command

)], this->clientString); + +} + +template +uint64_t DylibLoadCommandsAtom::getSize() const +{ + if ( fOptimizedAway ) { + return 0; + } + else { + const char* path = fInfo.reader->getInstallPath(); + return this->alignedSize(sizeof(macho_dylib_command

) + strlen(path) + 1); + } +} + +template +void DylibLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + if ( fOptimizedAway ) + return; + uint64_t size = this->getSize(); + bzero(buffer, size); + const char* path = fInfo.reader->getInstallPath(); + macho_dylib_command

* cmd = (macho_dylib_command

*)buffer; + // If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB + bool autoWeakLoadDylib = ( (fWriter.fDylibReadersWithWeakImports.count(fInfo.reader) > 0) + && (fWriter.fDylibReadersWithNonWeakImports.count(fInfo.reader) == 0) ); + if ( fInfo.options.fLazyLoad ) + cmd->set_cmd(LC_LAZY_LOAD_DYLIB); + else if ( fInfo.options.fWeakImport || autoWeakLoadDylib ) + cmd->set_cmd(LC_LOAD_WEAK_DYLIB); + else if ( fInfo.options.fReExport && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) ) + cmd->set_cmd(LC_REEXPORT_DYLIB); + else + cmd->set_cmd(LC_LOAD_DYLIB); + cmd->set_cmdsize(this->getSize()); + cmd->set_timestamp(2); // needs to be some constant value that is different than DylibIDLoadCommandsAtom uses + cmd->set_current_version(fInfo.reader->getCurrentVersion()); + cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion()); + cmd->set_name_offset(); + strcpy((char*)&buffer[sizeof(macho_dylib_command

)], path); +} + + + +template +uint64_t DylibIDLoadCommandsAtom::getSize() const +{ + return this->alignedSize(sizeof(macho_dylib_command

) + strlen(fWriter.fOptions.installPath()) + 1); +} + +template +void DylibIDLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + bzero(buffer, size); + macho_dylib_command

* cmd = (macho_dylib_command

*)buffer; + cmd->set_cmd(LC_ID_DYLIB); + cmd->set_cmdsize(this->getSize()); + cmd->set_name_offset(); + cmd->set_timestamp(1); // needs to be some constant value that is different than DylibLoadCommandsAtom uses + cmd->set_current_version(fWriter.fOptions.currentVersion()); + cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion()); + strcpy((char*)&buffer[sizeof(macho_dylib_command

)], fWriter.fOptions.installPath()); +} + + +template +void RoutinesLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint); + if (fWriter.fEntryPoint->isThumb()) + initAddr |= 1ULL; + bzero(buffer, sizeof(macho_routines_command

)); + macho_routines_command

* cmd = (macho_routines_command

*)buffer; + cmd->set_cmd(macho_routines_command

::CMD); + cmd->set_cmdsize(this->getSize()); + cmd->set_init_address(initAddr); +} + + +template +uint64_t SubUmbrellaLoadCommandsAtom::getSize() const +{ + return this->alignedSize(sizeof(macho_sub_umbrella_command

) + strlen(fName) + 1); +} + +template +void SubUmbrellaLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + bzero(buffer, size); + macho_sub_umbrella_command

* cmd = (macho_sub_umbrella_command

*)buffer; + cmd->set_cmd(LC_SUB_UMBRELLA); + cmd->set_cmdsize(this->getSize()); + cmd->set_sub_umbrella_offset(); + strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command

)], fName); +} + +template +void UUIDLoadCommandAtom::generate() +{ + switch ( fWriter.fOptions.getUUIDMode() ) { + case Options::kUUIDNone: + fEmit = false; + break; + case Options::kUUIDRandom: + ::uuid_generate_random(fUUID); + fEmit = true; + break; + case Options::kUUIDContent: + bzero(fUUID, 16); + fEmit = true; + break; + } +} + +template +void UUIDLoadCommandAtom::setContent(const uint8_t uuid[16]) +{ + memcpy(fUUID, uuid, 16); +} + +template +void UUIDLoadCommandAtom::copyRawContent(uint8_t buffer[]) const +{ + if (fEmit) { + uint64_t size = this->getSize(); + bzero(buffer, size); + macho_uuid_command

* cmd = (macho_uuid_command

*)buffer; + cmd->set_cmd(LC_UUID); + cmd->set_cmdsize(this->getSize()); + cmd->set_uuid((uint8_t*)fUUID); + } +} + + +template +uint64_t SubLibraryLoadCommandsAtom::getSize() const +{ + return this->alignedSize(sizeof(macho_sub_library_command

) + fNameLength + 1); +} + +template +void SubLibraryLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + bzero(buffer, size); + macho_sub_library_command

* cmd = (macho_sub_library_command

*)buffer; + cmd->set_cmd(LC_SUB_LIBRARY); + cmd->set_cmdsize(this->getSize()); + cmd->set_sub_library_offset(); + strncpy((char*)&buffer[sizeof(macho_sub_library_command

)], fNameStart, fNameLength); + buffer[sizeof(macho_sub_library_command

)+fNameLength] = '\0'; +} + +template +uint64_t UmbrellaLoadCommandsAtom::getSize() const +{ + return this->alignedSize(sizeof(macho_sub_framework_command

) + strlen(fName) + 1); +} + +template +void UmbrellaLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + bzero(buffer, size); + macho_sub_framework_command

* cmd = (macho_sub_framework_command

*)buffer; + cmd->set_cmd(LC_SUB_FRAMEWORK); + cmd->set_cmdsize(this->getSize()); + cmd->set_umbrella_offset(); + strcpy((char*)&buffer[sizeof(macho_sub_framework_command

)], fName); +} + +template <> +uint64_t ThreadsLoadCommandsAtom::getSize() const +{ + return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4 +} + +template <> +uint64_t ThreadsLoadCommandsAtom::getSize() const +{ + return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4 +} + +template <> +uint64_t ThreadsLoadCommandsAtom::getSize() const +{ + return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4 +} + +template <> +uint64_t ThreadsLoadCommandsAtom::getSize() const +{ + return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4); +} + +// We should be picking it up from a header +template <> +uint64_t ThreadsLoadCommandsAtom::getSize() const +{ + return this->alignedSize(16 + 17 * 4); // base size + ARM_THREAD_STATE_COUNT * 4 +} + +template <> +void ThreadsLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint); + bzero(buffer, size); + macho_thread_command* cmd = (macho_thread_command*)buffer; + cmd->set_cmd(LC_UNIXTHREAD); + cmd->set_cmdsize(size); + cmd->set_flavor(1); // PPC_THREAD_STATE + cmd->set_count(40); // PPC_THREAD_STATE_COUNT; + cmd->set_thread_register(0, start); + if ( fWriter.fOptions.hasCustomStack() ) + cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1 +} + + +template <> +void ThreadsLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint); + bzero(buffer, size); + macho_thread_command* cmd = (macho_thread_command*)buffer; + cmd->set_cmd(LC_UNIXTHREAD); + cmd->set_cmdsize(size); + cmd->set_flavor(5); // PPC_THREAD_STATE64 + cmd->set_count(76); // PPC_THREAD_STATE64_COUNT; + cmd->set_thread_register(0, start); + if ( fWriter.fOptions.hasCustomStack() ) + cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1 +} + +template <> +void ThreadsLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint); + bzero(buffer, size); + macho_thread_command* cmd = (macho_thread_command*)buffer; + cmd->set_cmd(LC_UNIXTHREAD); + cmd->set_cmdsize(size); + cmd->set_flavor(1); // i386_THREAD_STATE + cmd->set_count(16); // i386_THREAD_STATE_COUNT; + cmd->set_thread_register(10, start); + if ( fWriter.fOptions.hasCustomStack() ) + cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // esp +} + +template <> +void ThreadsLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint); + bzero(buffer, size); + macho_thread_command* cmd = (macho_thread_command*)buffer; + cmd->set_cmd(LC_UNIXTHREAD); + cmd->set_cmdsize(size); + cmd->set_flavor(x86_THREAD_STATE64); + cmd->set_count(x86_THREAD_STATE64_COUNT); + cmd->set_thread_register(16, start); // rip + if ( fWriter.fOptions.hasCustomStack() ) + cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // uesp +} + +template <> +void ThreadsLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint); + bzero(buffer, size); + macho_thread_command* cmd = (macho_thread_command*)buffer; + cmd->set_cmd(LC_UNIXTHREAD); + cmd->set_cmdsize(size); + cmd->set_flavor(1); + cmd->set_count(17); + cmd->set_thread_register(15, start); // pc + if ( fWriter.fOptions.hasCustomStack() ) + cmd->set_thread_register(13, fWriter.fOptions.customStackAddr()); // FIXME: sp? +} + +template +uint64_t RPathLoadCommandsAtom::getSize() const +{ + return this->alignedSize(sizeof(macho_rpath_command

) + strlen(fPath) + 1); +} + +template +void RPathLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + bzero(buffer, size); + macho_rpath_command

* cmd = (macho_rpath_command

*)buffer; + cmd->set_cmd(LC_RPATH); + cmd->set_cmdsize(this->getSize()); + cmd->set_path_offset(); + strcpy((char*)&buffer[sizeof(macho_rpath_command

)], fPath); +} + + + +template +void EncryptionLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + bzero(buffer, size); + macho_encryption_info_command

* cmd = (macho_encryption_info_command

*)buffer; + cmd->set_cmd(LC_ENCRYPTION_INFO); + cmd->set_cmdsize(this->getSize()); + cmd->set_cryptoff(fStartOffset); + cmd->set_cryptsize(fEndOffset-fStartOffset); + cmd->set_cryptid(0); +} + + + +template +void LoadCommandsPaddingAtom::copyRawContent(uint8_t buffer[]) const +{ + bzero(buffer, fSize); +} + +template +void LoadCommandsPaddingAtom::setSize(uint64_t newSize) +{ + fSize = newSize; + // this resizing by-passes the way fLargestAtomSize is set, so re-check here + if ( fWriter.fLargestAtomSize < newSize ) + fWriter.fLargestAtomSize = newSize; +} + +template +uint64_t LinkEditAtom::getFileOffset() const +{ + return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset(); +} + + +template +uint64_t SectionRelocationsLinkEditAtom::getSize() const +{ + return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info

); +} + +template +void SectionRelocationsLinkEditAtom::copyRawContent(uint8_t buffer[]) const +{ + memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize()); +} + + +template +uint64_t LocalRelocationsLinkEditAtom::getSize() const +{ + return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info

); +} + +template +void LocalRelocationsLinkEditAtom::copyRawContent(uint8_t buffer[]) const +{ + memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize()); +} + + + +template +uint64_t SymbolTableLinkEditAtom::getSize() const +{ + return fWriter.fSymbolTableCount * sizeof(macho_nlist

); +} + +template +void SymbolTableLinkEditAtom::copyRawContent(uint8_t buffer[]) const +{ + memcpy(buffer, fWriter.fSymbolTable, this->getSize()); +} + +template +uint64_t ExternalRelocationsLinkEditAtom::getSize() const +{ + return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info

); +} + +template +void ExternalRelocationsLinkEditAtom::copyRawContent(uint8_t buffer[]) const +{ + std::sort(fWriter.fExternalRelocs.begin(), fWriter.fExternalRelocs.end(), ExternalRelocSorter

()); + memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize()); +} + + + +template +uint64_t IndirectTableLinkEditAtom::getSize() const +{ + return fTable.size() * sizeof(uint32_t); +} + +template +void IndirectTableLinkEditAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + bzero(buffer, size); + const uint32_t indirectTableSize = fTable.size(); + uint32_t* indirectTable = (uint32_t*)buffer; + for(std::vector::const_iterator it = fTable.begin(); it != fTable.end(); ++it) { + if ( it->indirectIndex < indirectTableSize ) { + A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex); + } + else { + throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex); + } + } +} + + + +template +uint64_t ModuleInfoLinkEditAtom::getSize() const +{ + return fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents

) + + sizeof(macho_dylib_module

) + + this->getReferencesCount()*sizeof(uint32_t); +} + +template +uint32_t ModuleInfoLinkEditAtom::getTableOfContentsFileOffset() const +{ + return this->getFileOffset(); +} + +template +uint32_t ModuleInfoLinkEditAtom::getModuleTableFileOffset() const +{ + return this->getFileOffset() + fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents

); +} + +template +uint32_t ModuleInfoLinkEditAtom::getReferencesFileOffset() const +{ + return this->getModuleTableFileOffset() + sizeof(macho_dylib_module

); +} + +template +uint32_t ModuleInfoLinkEditAtom::getReferencesCount() const +{ + return fWriter.fSymbolTableExportCount + fWriter.fSymbolTableImportCount; +} + +template +void ModuleInfoLinkEditAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + bzero(buffer, size); + // create toc. The symbols are already sorted, they are all in the smae module + macho_dylib_table_of_contents

* p = (macho_dylib_table_of_contents

*)buffer; + for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++p) { + p->set_symbol_index(fWriter.fSymbolTableExportStartIndex+i); + p->set_module_index(0); + } + // create module table (one entry) + uint16_t numInits = 0; + uint16_t numTerms = 0; + std::vector& segmentInfos = fWriter.fSegmentInfos; + for (std::vector::iterator segit = segmentInfos.begin(); segit != segmentInfos.end(); ++segit) { + if ( strcmp((*segit)->fName, "__DATA") == 0 ) { + std::vector& sectionInfos = (*segit)->fSections; + for (std::vector::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) { + if ( strcmp((*sectit)->fSectionName, "__mod_init_func") == 0 ) + numInits = (*sectit)->fSize / sizeof(typename A::P::uint_t); + else if ( strcmp((*sectit)->fSectionName, "__mod_term_func") == 0 ) + numTerms = (*sectit)->fSize / sizeof(typename A::P::uint_t); + } + } + } + macho_dylib_module

* module = (macho_dylib_module

*)&buffer[fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents

)]; + module->set_module_name(fModuleNameOffset); + module->set_iextdefsym(fWriter.fSymbolTableExportStartIndex); + module->set_nextdefsym(fWriter.fSymbolTableExportCount); + module->set_irefsym(0); + module->set_nrefsym(this->getReferencesCount()); + module->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex); + module->set_nlocalsym(fWriter.fSymbolTableStabsCount+fWriter.fSymbolTableLocalCount); + module->set_iextrel(0); + module->set_nextrel(fWriter.fExternalRelocs.size()); + module->set_iinit_iterm(0,0); + module->set_ninit_nterm(numInits,numTerms); + module->set_objc_module_info_addr(0); // Not used by ld_classic, and not used by objc runtime for many years + module->set_objc_module_info_size(0); // Not used by ld_classic, and not used by objc runtime for many years + // create reference table + macho_dylib_reference

* ref = (macho_dylib_reference

*)((uint8_t*)module + sizeof(macho_dylib_module

)); + for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++ref) { + ref->set_isym(fWriter.fSymbolTableExportStartIndex+i); + ref->set_flags(REFERENCE_FLAG_DEFINED); + } + for(uint32_t i=0; i < fWriter.fSymbolTableImportCount; ++i, ++ref) { + ref->set_isym(fWriter.fSymbolTableImportStartIndex+i); + std::map::iterator pos = fWriter.fStubsMap.find(fWriter.fImportedAtoms[i]); + if ( pos != fWriter.fStubsMap.end() ) + ref->set_flags(REFERENCE_FLAG_UNDEFINED_LAZY); + else + ref->set_flags(REFERENCE_FLAG_UNDEFINED_NON_LAZY); + } +} + + + +template +StringsLinkEditAtom::StringsLinkEditAtom(Writer& writer) + : LinkEditAtom(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0) +{ + fCurrentBuffer = new char[kBufferSize]; + // burn first byte of string pool (so zero is never a valid string offset) + fCurrentBuffer[fCurrentBufferUsed++] = ' '; + // make offset 1 always point to an empty string + fCurrentBuffer[fCurrentBufferUsed++] = '\0'; +} + +template +uint64_t StringsLinkEditAtom::getSize() const +{ + // align size + return (kBufferSize * fFullBuffers.size() + fCurrentBufferUsed + sizeof(typename A::P::uint_t) - 1) & (-sizeof(typename A::P::uint_t)); +} + +template +void StringsLinkEditAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t offset = 0; + for (unsigned int i=0; i < fFullBuffers.size(); ++i) { + memcpy(&buffer[offset], fFullBuffers[i], kBufferSize); + offset += kBufferSize; + } + memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed); + // zero fill end to align + offset += fCurrentBufferUsed; + while ( (offset % sizeof(typename A::P::uint_t)) != 0 ) + buffer[offset++] = 0; +} + +template +int32_t StringsLinkEditAtom::add(const char* name) +{ + int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed; + int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1; + if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) { + fCurrentBufferUsed += lenNeeded; + } + else { + int copied = kBufferSize-fCurrentBufferUsed-1; + // change trailing '\0' that strlcpy added to real char + fCurrentBuffer[kBufferSize-1] = name[copied]; + // alloc next buffer + fFullBuffers.push_back(fCurrentBuffer); + fCurrentBuffer = new char[kBufferSize]; + fCurrentBufferUsed = 0; + // append rest of string + this->add(&name[copied+1]); + } + return offset; +} + + +template +int32_t StringsLinkEditAtom::addUnique(const char* name) +{ + StringToOffset::iterator pos = fUniqueStrings.find(name); + if ( pos != fUniqueStrings.end() ) { + return pos->second; + } + else { + int32_t offset = this->add(name); + fUniqueStrings[name] = offset; + return offset; + } +} + + +template +const char* StringsLinkEditAtom::stringForIndex(int32_t index) const +{ + int32_t currentBufferStartIndex = kBufferSize * fFullBuffers.size(); + int32_t maxIndex = currentBufferStartIndex + fCurrentBufferUsed; + // check for out of bounds + if ( index > maxIndex ) + return ""; + // check for index in fCurrentBuffer + if ( index > currentBufferStartIndex ) + return &fCurrentBuffer[index-currentBufferStartIndex]; + // otherwise index is in a full buffer + uint32_t fullBufferIndex = index/kBufferSize; + return &fFullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)]; +} + + + +template +BranchIslandAtom::BranchIslandAtom(Writer& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset) + : WriterAtom(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset) +{ + char* buf = new char[strlen(name)+32]; + if ( targetOffset == 0 ) { + if ( islandRegion == 0 ) + sprintf(buf, "%s$island", name); + else + sprintf(buf, "%s$island_%d", name, islandRegion); + } + else { + sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion); + } + fName = buf; +} + + +template <> +void BranchIslandAtom::copyRawContent(uint8_t buffer[]) const +{ + int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress(); + int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC); + OSWriteBigInt32(buffer, 0, branchInstruction); +} + +template <> +void BranchIslandAtom::copyRawContent(uint8_t buffer[]) const +{ + int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress(); + int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC); + OSWriteBigInt32(buffer, 0, branchInstruction); +} + +template <> +uint64_t BranchIslandAtom::getSize() const +{ + return 4; +} + +template <> +uint64_t BranchIslandAtom::getSize() const +{ + return 4; +} + + + +template +uint64_t SegmentSplitInfoLoadCommandsAtom::getSize() const +{ + if ( fWriter.fSplitCodeToDataContentAtom->canEncode() ) + return this->alignedSize(sizeof(macho_linkedit_data_command

)); + else + return 0; // a zero size causes the load command to be suppressed +} + +template +void SegmentSplitInfoLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + uint64_t size = this->getSize(); + bzero(buffer, size); + macho_linkedit_data_command

* cmd = (macho_linkedit_data_command

*)buffer; + cmd->set_cmd(LC_SEGMENT_SPLIT_INFO); + cmd->set_cmdsize(size); + cmd->set_dataoff(fWriter.fSplitCodeToDataContentAtom->getFileOffset()); + cmd->set_datasize(fWriter.fSplitCodeToDataContentAtom->getSize()); +} + + +template +uint64_t SegmentSplitInfoContentAtom::getSize() const +{ + return fEncodedData.size(); +} + +template +void SegmentSplitInfoContentAtom::copyRawContent(uint8_t buffer[]) const +{ + memcpy(buffer, &fEncodedData[0], fEncodedData.size()); +} + + +template +void SegmentSplitInfoContentAtom::uleb128EncodeAddresses(const std::vector::AtomAndOffset>& locations) +{ + pint_t addr = fWriter.fOptions.baseAddress(); + for(typename std::vector::const_iterator it = locations.begin(); it != locations.end(); ++it) { + pint_t nextAddr = it->atom->getAddress() + it->offset; + //fprintf(stderr, "\t0x%0llX\n", (uint64_t)nextAddr); + uint64_t delta = nextAddr - addr; + if ( delta == 0 ) + throw "double split seg info for same address"; + // uleb128 encode + uint8_t byte; + do { + byte = delta & 0x7F; + delta &= ~0x7F; + if ( delta != 0 ) + byte |= 0x80; + fEncodedData.push_back(byte); + delta = delta >> 7; + } + while( byte >= 0x80 ); + addr = nextAddr; + } +} + +template +void SegmentSplitInfoContentAtom::encode() +{ + if ( ! fCantEncode ) { + fEncodedData.reserve(8192); + + if ( fKind1Locations.size() != 0 ) { + fEncodedData.push_back(1); + //fprintf(stderr, "type 1:\n"); + this->uleb128EncodeAddresses(fKind1Locations); + fEncodedData.push_back(0); + } + + if ( fKind2Locations.size() != 0 ) { + fEncodedData.push_back(2); + //fprintf(stderr, "type 2:\n"); + this->uleb128EncodeAddresses(fKind2Locations); + fEncodedData.push_back(0); + } + + if ( fKind3Locations.size() != 0 ) { + fEncodedData.push_back(3); + //fprintf(stderr, "type 3:\n"); + this->uleb128EncodeAddresses(fKind3Locations); + fEncodedData.push_back(0); + } + + if ( fKind4Locations.size() != 0 ) { + fEncodedData.push_back(4); + //fprintf(stderr, "type 4:\n"); + this->uleb128EncodeAddresses(fKind4Locations); + fEncodedData.push_back(0); + } + + // always add zero byte to mark end + fEncodedData.push_back(0); + + // add zeros to end to align size + while ( (fEncodedData.size() % sizeof(pint_t)) != 0 ) + fEncodedData.push_back(0); + } +} + + +template +ObjCInfoAtom::ObjCInfoAtom(Writer& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, bool objcReplacementClasses) + : WriterAtom(writer, getInfoSegment()) +{ + fContent[0] = 0; + uint32_t value = 0; + // struct objc_image_info { + // uint32_t version; // initially 0 + // uint32_t flags; + // }; + // #define OBJC_IMAGE_SUPPORTS_GC 2 + // #define OBJC_IMAGE_GC_ONLY 4 + // + if ( objcReplacementClasses ) + value = 1; + switch ( objcConstraint ) { + case ObjectFile::Reader::kObjcNone: + case ObjectFile::Reader::kObjcRetainRelease: + break; + case ObjectFile::Reader::kObjcRetainReleaseOrGC: + value |= 2; + break; + case ObjectFile::Reader::kObjcGC: + value |= 6; + break; + } + A::P::E::set32(fContent[1], value); +} + +template +void ObjCInfoAtom::copyRawContent(uint8_t buffer[]) const +{ + memcpy(buffer, &fContent[0], 8); +} + + +// objc info section is in a different segment and section for 32 vs 64 bit runtimes +template <> const char* ObjCInfoAtom::getSectionName() const { return "__image_info"; } +template <> const char* ObjCInfoAtom::getSectionName() const { return "__image_info"; } +template <> const char* ObjCInfoAtom::getSectionName() const { return "__objc_imageinfo"; } +template <> const char* ObjCInfoAtom::getSectionName() const { return "__objc_imageinfo"; } +template <> const char* ObjCInfoAtom::getSectionName() const { return "__objc_imageinfo"; } + +template <> Segment& ObjCInfoAtom::getInfoSegment() const { return Segment::fgObjCSegment; } +template <> Segment& ObjCInfoAtom::getInfoSegment() const { return Segment::fgObjCSegment; } +template <> Segment& ObjCInfoAtom::getInfoSegment() const { return Segment::fgDataSegment; } +template <> Segment& ObjCInfoAtom::getInfoSegment() const { return Segment::fgDataSegment; } +template <> Segment& ObjCInfoAtom::getInfoSegment() const { return Segment::fgDataSegment; } + + +}; // namespace executable +}; // namespace mach_o + + +#endif // __EXECUTABLE_MACH_O__ diff --git a/FireOpal/src/ObjectDump.cpp b/FireOpal/src/ObjectDump.cpp new file mode 100644 index 0000000..a06c7a2 --- /dev/null +++ b/FireOpal/src/ObjectDump.cpp @@ -0,0 +1,497 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2005-2006 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@ + */ + +#include +#include +#include +#include +#include + +#include "MachOReaderRelocatable.hpp" + +#define LTO_SUPPORT 0 + +#if LTO_SUPPORT + #include "LTOReader.hpp" +#endif + +static bool sDumpContent= true; +static bool sDumpStabs = false; +static bool sSort = true; +static bool sNMmode = false; +static cpu_type_t sPreferredArch = CPU_TYPE_POWERPC64; +static const char* sMatchName; +static int sPrintRestrict; +static int sPrintAlign; +static int sPrintName; + + + __attribute__((noreturn)) +void throwf(const char* format, ...) +{ + va_list list; + char* p; + va_start(list, format); + vasprintf(&p, format, list); + va_end(list); + + const char* t = p; + throw t; +} + +void warning(const char* format, ...) +{ + va_list list; + fprintf(stderr, "warning: "); + va_start(list, format); + vfprintf(stderr, format, list); + va_end(list); + fprintf(stderr, "\n"); +} + +static void dumpStabs(std::vector* stabs) +{ + // debug info + printf("stabs: (%lu)\n", stabs->size()); + for (std::vector::iterator it = stabs->begin(); it != stabs->end(); ++it ) { + ObjectFile::Reader::Stab& stab = *it; + const char* code = "?????"; + switch (stab.type) { + case N_GSYM: + code = " GSYM"; + break; + case N_FNAME: + code = "FNAME"; + break; + case N_FUN: + code = " FUN"; + break; + case N_STSYM: + code = "STSYM"; + break; + case N_LCSYM: + code = "LCSYM"; + break; + case N_BNSYM: + code = "BNSYM"; + break; + case N_OPT: + code = " OPT"; + break; + case N_RSYM: + code = " RSYM"; + break; + case N_SLINE: + code = "SLINE"; + break; + case N_ENSYM: + code = "ENSYM"; + break; + case N_SSYM: + code = " SSYM"; + break; + case N_SO: + code = " SO"; + break; + case N_OSO: + code = " OSO"; + break; + case N_LSYM: + code = " LSYM"; + break; + case N_BINCL: + code = "BINCL"; + break; + case N_SOL: + code = " SOL"; + break; + case N_PARAMS: + code = "PARMS"; + break; + case N_VERSION: + code = " VERS"; + break; + case N_OLEVEL: + code = "OLEVL"; + break; + case N_PSYM: + code = " PSYM"; + break; + case N_EINCL: + code = "EINCL"; + break; + case N_ENTRY: + code = "ENTRY"; + break; + case N_LBRAC: + code = "LBRAC"; + break; + case N_EXCL: + code = " EXCL"; + break; + case N_RBRAC: + code = "RBRAC"; + break; + case N_BCOMM: + code = "BCOMM"; + break; + case N_ECOMM: + code = "ECOMM"; + break; + case N_LENG: + code = "LENG"; + break; + } + printf(" [atom=%20s] %02X %04X %s %s\n", ((stab.atom != NULL) ? stab.atom->getDisplayName() : ""), stab.other, stab.desc, code, stab.string); + } +} + + +static void dumpAtomLikeNM(ObjectFile::Atom* atom) +{ + uint32_t size = atom->getSize(); + + const char* visibility; + switch ( atom->getScope() ) { + case ObjectFile::Atom::scopeTranslationUnit: + visibility = "internal"; + break; + case ObjectFile::Atom::scopeLinkageUnit: + visibility = "hidden "; + break; + case ObjectFile::Atom::scopeGlobal: + visibility = "global "; + break; + default: + visibility = " "; + break; + } + + const char* kind; + switch ( atom->getDefinitionKind() ) { + case ObjectFile::Atom::kRegularDefinition: + kind = "regular "; + break; + case ObjectFile::Atom::kTentativeDefinition: + kind = "tentative"; + break; + case ObjectFile::Atom::kWeakDefinition: + kind = "weak "; + break; + case ObjectFile::Atom::kAbsoluteSymbol: + kind = "absolute "; + break; + default: + kind = " "; + break; + } + + printf("0x%08X %s %s %s\n", size, visibility, kind, atom->getDisplayName()); +} + + +static void dumpAtom(ObjectFile::Atom* atom) +{ + if(sMatchName && strcmp(sMatchName, atom->getDisplayName())) + return; + + //printf("atom: %p\n", atom); + + // name + if(!sPrintRestrict || sPrintName) + printf("name: %s\n", atom->getDisplayName()); + + // scope + if(!sPrintRestrict) + switch ( atom->getScope() ) { + case ObjectFile::Atom::scopeTranslationUnit: + printf("scope: translation unit\n"); + break; + case ObjectFile::Atom::scopeLinkageUnit: + printf("scope: linkage unit\n"); + break; + case ObjectFile::Atom::scopeGlobal: + printf("scope: global\n"); + break; + default: + printf("scope: unknown\n"); + } + + // kind + if(!sPrintRestrict) + switch ( atom->getDefinitionKind() ) { + case ObjectFile::Atom::kRegularDefinition: + printf("kind: regular\n"); + break; + case ObjectFile::Atom::kWeakDefinition: + printf("kind: weak\n"); + break; + case ObjectFile::Atom::kTentativeDefinition: + printf("kind: tentative\n"); + break; + case ObjectFile::Atom::kExternalDefinition: + printf("kind: import\n"); + break; + case ObjectFile::Atom::kExternalWeakDefinition: + printf("kind: weak import\n"); + break; + case ObjectFile::Atom::kAbsoluteSymbol: + printf("kind: absolute symbol\n"); + break; + default: + printf("kind: unknown\n"); + } + + // segment and section + if(!sPrintRestrict && (atom->getSectionName() != NULL) ) + printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName()); + + // attributes + if(!sPrintRestrict) { + printf("attrs: "); + if ( atom->dontDeadStrip() ) + printf("dont-dead-strip "); + if ( atom->isZeroFill() ) + printf("zero-fill "); + if ( atom->isThumb() ) + printf("thumb "); + printf("\n"); + } + + // size + if(!sPrintRestrict) + printf("size: 0x%012llX\n", atom->getSize()); + + // alignment + if(!sPrintRestrict || sPrintAlign) + printf("align: %u mod %u\n", atom->getAlignment().modulus, (1 << atom->getAlignment().powerOf2) ); + + // content + if (!sPrintRestrict && sDumpContent ) { + uint64_t size = atom->getSize(); + if ( size < 4096 ) { + uint8_t content[size]; + atom->copyRawContent(content); + printf("content: "); + if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) { + printf("\""); + for (unsigned int i=0; i < size; ++i) { + if(content[i]<'!' || content[i]>=127) + printf("\\%o", content[i]); + else + printf("%c", content[i]); + } + printf("\""); + } + else { + for (unsigned int i=0; i < size; ++i) + printf("%02X ", content[i]); + } + } + printf("\n"); + } + + // references + if(!sPrintRestrict) { + std::vector& references = atom->getReferences(); + const int refCount = references.size(); + printf("references: (%u)\n", refCount); + for (int i=0; i < refCount; ++i) { + ObjectFile::Reference* ref = references[i]; + printf(" %s\n", ref->getDescription()); + } + } + + // line info + if(!sPrintRestrict) { + std::vector* lineInfo = atom->getLineInfo(); + if ( (lineInfo != NULL) && (lineInfo->size() > 0) ) { + printf("line info: (%lu)\n", lineInfo->size()); + for (std::vector::iterator it = lineInfo->begin(); it != lineInfo->end(); ++it) { + printf(" offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName); + } + } + } + + if(!sPrintRestrict) + printf("\n"); +} + +struct AtomSorter +{ + bool operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right) + { + if ( left == right ) + return false; + return (strcmp(left->getDisplayName(), right->getDisplayName()) < 0); + } +}; + + +static void dumpFile(ObjectFile::Reader* reader) +{ + // stabs debug info + if ( sDumpStabs && (reader->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoStabs) ) { + std::vector* stabs = reader->getStabs(); + if ( stabs != NULL ) + dumpStabs(stabs); + } + + // get all atoms + std::vector atoms = reader->getAtoms(); + + // make copy of vector and sort (so output is canonical) + std::vector sortedAtoms(atoms); + if ( sSort ) + std::sort(sortedAtoms.begin(), sortedAtoms.end(), AtomSorter()); + + for(std::vector::iterator it=sortedAtoms.begin(); it != sortedAtoms.end(); ++it) { + if ( sNMmode ) + dumpAtomLikeNM(*it); + else + dumpAtom(*it); + } +} + + +static ObjectFile::Reader* createReader(const char* path, const ObjectFile::ReaderOptions& options) +{ + struct stat stat_buf; + + int fd = ::open(path, O_RDONLY, 0); + if ( fd == -1 ) + throwf("cannot open file: %s", path); + ::fstat(fd, &stat_buf); + uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); + ::close(fd); + const mach_header* mh = (mach_header*)p; + 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 ) { + p = p + OSSwapBigToHostInt32(archs[i].offset); + mh = (struct mach_header*)p; + } + } + } + if ( mach_o::relocatable::Reader::validFile(p) ) + return new mach_o::relocatable::Reader::Reader(p, path, 0, options, 0); + else if ( mach_o::relocatable::Reader::validFile(p) ) + return new mach_o::relocatable::Reader::Reader(p, path, 0, options, 0); + else if ( mach_o::relocatable::Reader::validFile(p) ) + return new mach_o::relocatable::Reader::Reader(p, path, 0, options, 0); + else if ( mach_o::relocatable::Reader::validFile(p) ) + return new mach_o::relocatable::Reader::Reader(p, path, 0, options, 0); + else if ( mach_o::relocatable::Reader::validFile(p) ) + return new mach_o::relocatable::Reader::Reader(p, path, 0, options, 0); +#if LTO_SUPPORT + if ( lto::Reader::validFile(p, stat_buf.st_size, 0) ) { + return new lto::Reader(p, stat_buf.st_size, path, 0, options, 0); + } +#endif + + throwf("not a mach-o object file: %s", path); +} + +static +void +usage() +{ + fprintf(stderr, "ObjectDump options:\n" + "\t-no_content\tdon't dump contents\n" + "\t-stabs\t\tdump stabs\n" + "\t-arch aaa\tonly dump info about arch aaa\n" + "\t-only sym\tonly dump info about sym\n" + "\t-align\t\tonly print alignment info\n" + "\t-name\t\tonly print symbol names\n" + ); +} + +int main(int argc, const char* argv[]) +{ + if(argc<2) { + usage(); + return 0; + } + + ObjectFile::ReaderOptions options; + try { + for(int i=1; i < argc; ++i) { + const char* arg = argv[i]; + if ( arg[0] == '-' ) { + if ( strcmp(arg, "-no_content") == 0 ) { + sDumpContent = false; + } + else if ( strcmp(arg, "-nm") == 0 ) { + sNMmode = true; + } + else if ( strcmp(arg, "-stabs") == 0 ) { + sDumpStabs = true; + } + else if ( strcmp(arg, "-no_sort") == 0 ) { + sSort = false; + } + else if ( strcmp(arg, "-arch") == 0 ) { + const char* arch = ++i +#include +#include +#include + + + +// +// These classes represent the abstract Atoms and References that are the basis of the linker. +// An Atom and a Reference correspond to a Node and Edge in graph theory. +// +// A Reader is a class which parses an object file and presents it as Atoms and References. +// All linking operations are done on Atoms and References. This makes the linker file +// format independent. +// +// A Writer takes a vector of Atoms with all References resolved and produces an executable file. +// +// + + + +namespace ObjectFile { + + +struct LineInfo +{ + uint32_t atomOffset; + const char* fileName; + uint32_t lineNumber; +}; + + +class ReaderOptions +{ +public: + ReaderOptions() : fFullyLoadArchives(false), fLoadAllObjcObjectsFromArchives(false), fFlatNamespace(false), + fLinkingMainExecutable(false), fSlowx86Stubs(false), + fForFinalLinkedImage(false), fForStatic(false), fForDyld(false), fMakeTentativeDefinitionsReal(false), + fWhyLoad(false), fRootSafe(false), fSetuidSafe(false),fDebugInfoStripping(kDebugInfoFull), + fImplicitlyLinkPublicDylibs(true), fLogObjectFiles(false), fLogAllFiles(false), + fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false), + fTraceOutputFile(NULL), fVersionMin(kMinUnset) {} + enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull }; + enum VersionMin { kMinUnset, k10_1, k10_2, k10_3, k10_4, k10_5, k10_6 }; + + struct AliasPair { + const char* realName; + const char* alias; + }; + + bool fFullyLoadArchives; + bool fLoadAllObjcObjectsFromArchives; + bool fFlatNamespace; + bool fLinkingMainExecutable; + bool fSlowx86Stubs; + bool fForFinalLinkedImage; + bool fForStatic; + bool fForDyld; + bool fMakeTentativeDefinitionsReal; + bool fWhyLoad; + bool fRootSafe; + bool fSetuidSafe; + DebugInfoStripping fDebugInfoStripping; + bool fImplicitlyLinkPublicDylibs; + bool fLogObjectFiles; + bool fLogAllFiles; + bool fTraceDylibs; + bool fTraceIndirectDylibs; + bool fTraceArchives; + const char* fTraceOutputFile; + VersionMin fVersionMin; + std::vector fAliases; +}; + + +class Reader +{ +public: + enum DebugInfoKind { kDebugInfoNone=0, kDebugInfoStabs=1, kDebugInfoDwarf=2, kDebugInfoStabsUUID=3 }; + struct Stab + { + class Atom* atom; + uint8_t type; + uint8_t other; + uint16_t desc; + uint32_t value; + const char* string; + }; + enum ObjcConstraint { kObjcNone, kObjcRetainRelease, kObjcRetainReleaseOrGC, kObjcGC }; + enum CpuConstraint { kCpuAny = 0 }; + + class DylibHander + { + public: + virtual ~DylibHander() {} + virtual Reader* findDylib(const char* installPath, const char* fromPath) = 0; + }; + + + static Reader* createReader(const char* path, const ReaderOptions& options); + + virtual const char* getPath() = 0; + virtual time_t getModificationTime() = 0; + virtual DebugInfoKind getDebugInfoKind() = 0; + virtual std::vector& getAtoms() = 0; + virtual std::vector* getJustInTimeAtomsFor(const char* name) = 0; + virtual std::vector* getStabs() = 0; + virtual ObjcConstraint getObjCConstraint() { return kObjcNone; } + virtual uint32_t updateCpuConstraint(uint32_t current) { return current; } + virtual bool objcReplacementClasses() { return false; } + + // For relocatable object files only + virtual bool canScatterAtoms() { return true; } + virtual void optimize(std::vector&, std::vector&, + std::vector&, const std::set&, + uint32_t, ObjectFile::Reader* writer, + const std::vector& llvmOptions, + bool allGlobalsAReDeadStripRoots, int okind, + bool verbose, bool saveTemps, const char* outputFilePath, + bool pie, bool allowTextRelocs) { } + virtual bool hasLongBranchStubs() { return false; } + + // For Dynamic Libraries only + virtual const char* getInstallPath() { return NULL; } + virtual uint32_t getTimestamp() { return 0; } + virtual uint32_t getCurrentVersion() { return 0; } + virtual uint32_t getCompatibilityVersion() { return 0; } + virtual void processIndirectLibraries(DylibHander* handler) { } + virtual void setExplicitlyLinked() { } + virtual bool explicitlyLinked() { return false; } + virtual bool implicitlyLinked() { return false; } + virtual bool providedExportAtom() { return false; } + virtual const char* parentUmbrella() { return NULL; } + virtual std::vector* getAllowableClients() { return NULL; } + virtual bool hasWeakExternals() { return false; } + virtual bool isLazyLoadedDylib() { return false; } + +protected: + Reader() {} + virtual ~Reader() {} +}; + +class Segment +{ +public: + virtual const char* getName() const = 0; + virtual bool isContentReadable() const = 0; + virtual bool isContentWritable() const = 0; + virtual bool isContentExecutable() const = 0; + + uint64_t getBaseAddress() const { return fBaseAddress; } + void setBaseAddress(uint64_t addr) { fBaseAddress = addr; } + virtual bool hasFixedAddress() const { return false; } + +protected: + Segment() : fBaseAddress(0) {} + virtual ~Segment() {} + uint64_t fBaseAddress; +}; + +class Reference; + +class Section +{ +public: + unsigned int getIndex() { return fIndex; } + uint64_t getBaseAddress() { return fBaseAddress; } + void setBaseAddress(uint64_t addr) { fBaseAddress = addr; } + void* fOther; + +protected: + Section() : fOther(NULL), fBaseAddress(0), fIndex(0) {} + uint64_t fBaseAddress; + unsigned int fIndex; +}; + + +struct Alignment +{ + Alignment(int p2, int m=0) : powerOf2(p2), modulus(m) {} + uint8_t trailingZeros() const { return (modulus==0) ? powerOf2 : __builtin_ctz(modulus); } + uint16_t powerOf2; + uint16_t modulus; +}; + +// +// An atom is the fundamental unit of linking. A C function or global variable is an atom. +// An atom has content and some attributes. The content of a function atom is the instructions +// that implement the function. The content of a global variable atom is its initial bits. +// +// Name: +// The name of an atom is the label name generated by the compiler. A C compiler names foo() +// as _foo. A C++ compiler names foo() as __Z3foov. +// The name refers to the first byte of the content. An atom cannot have multiple entry points. +// Such code is modeled as multiple atoms, each having a "follow on" reference to the next. +// A "follow on" reference is a contraint to the linker to the atoms must be laid out contiguously. +// +// Scope: +// An atom is in one of three scopes: translation-unit, linkage-unit, or global. These correspond +// to the C visibility of static, hidden, default. +// +// DefinitionKind: +// An atom is one of five defintion kinds: +// regular Most atoms. +// weak C++ compiler makes some functions weak if there might be multiple copies +// that the linker needs to coalesce. +// tentative A straggler from ancient C when the extern did not exist. "int foo;" is ambiguous. +// It could be a prototype or it could be a definition. +// external This is a "proxy" atom produced by a dylib reader. It has no content. It exists +// so that all References can be resolved. +// external-weak Same as external, but the definition in the dylib is weak. +// +// SymbolTableInclusion: +// An atom may or may not be in the symbol table in an object file. +// in Most atoms for functions or global data +// not-in Anonymous atoms such literal c-strings, or other compiler generated data +// in-never-strip Atom whose name the strip tool should never remove (e.g. REFERENCED_DYNAMICALLY in mach-o) +// +// Ordinal: +// When a reader is created it is given a base ordinal number. All atoms created by the reader +// should return a contiguous range of ordinal values that start at the base ordinal. The ordinal +// values are used by the linker to sort the atom graph when producing the output file. +// +class Atom +{ +public: + enum Scope { scopeTranslationUnit, scopeLinkageUnit, scopeGlobal }; + enum DefinitionKind { kRegularDefinition, kWeakDefinition, kTentativeDefinition, kExternalDefinition, kExternalWeakDefinition, kAbsoluteSymbol }; + enum SymbolTableInclusion { kSymbolTableNotIn, kSymbolTableIn, kSymbolTableInAndNeverStrip, kSymbolTableInAsAbsolute }; + + virtual Reader* getFile() const = 0; + virtual bool getTranslationUnitSource(const char** dir, const char** name) const = 0; + virtual const char* getName() const = 0; + virtual const char* getDisplayName() const = 0; + virtual Scope getScope() const = 0; + virtual DefinitionKind getDefinitionKind() const = 0; + virtual SymbolTableInclusion getSymbolTableInclusion() const = 0; + virtual bool dontDeadStrip() const = 0; + virtual bool isZeroFill() const = 0; + virtual bool isThumb() const = 0; + virtual uint64_t getSize() const = 0; + virtual std::vector& getReferences() const = 0; + virtual bool mustRemainInSection() const = 0; + virtual const char* getSectionName() const = 0; + virtual Segment& getSegment() const = 0; + virtual Atom& getFollowOnAtom() const = 0; + virtual uint32_t getOrdinal() const = 0; + virtual std::vector* getLineInfo() const = 0; + virtual Alignment getAlignment() const = 0; + virtual void copyRawContent(uint8_t buffer[]) const = 0; + virtual void setScope(Scope) = 0; + + + uint64_t getSectionOffset() const { return fSectionOffset; } + uint64_t getAddress() const { return fSection->getBaseAddress() + fSectionOffset; } + class Section* getSection() const { return fSection; } + + virtual void setSectionOffset(uint64_t offset) { fSectionOffset = offset; } + virtual void setSection(class Section* sect) { fSection = sect; } + +protected: + Atom() : fSectionOffset(0), fSection(NULL) {} + virtual ~Atom() {} + + uint64_t fSectionOffset; + class Section* fSection; +}; + + +// +// A Reference is a directed edge to another Atom. When an instruction in +// the content of an Atom refers to another Atom, that is represented by a +// Reference. +// +// There are two kinds of references: direct and by-name. With a direct Reference, +// the target is bound by the Reader that created it. For instance a reference to a +// static would produce a direct reference. A by-name reference requires the linker +// to find the target Atom with the required name in order to be bound. +// +// For a link to succeed all References must be bound. +// +// A Reference has an optional "from" target. This is used when the content to fix-up +// is the difference of two Atom address. For instance, if a pointer sized data Atom +// is to contain A - B, then the Atom would have on Reference with a target of "A" and +// a from-target of "B". +// +// A Reference also has a fix-up-offset. This is the offset into the content of the +// Atom holding the reference where the fix-up (relocation) will be applied. +// +// +// +class Reference +{ +public: + enum TargetBinding { kUnboundByName, kBoundDirectly, kBoundByName, kDontBind }; + + virtual TargetBinding getTargetBinding() const = 0; + virtual TargetBinding getFromTargetBinding() const = 0; + virtual uint8_t getKind() const = 0; + virtual uint64_t getFixUpOffset() const = 0; + virtual const char* getTargetName() const = 0; + virtual Atom& getTarget() const = 0; + virtual uint64_t getTargetOffset() const = 0; + virtual Atom& getFromTarget() const = 0; + virtual const char* getFromTargetName() const = 0; + virtual uint64_t getFromTargetOffset() const = 0; + + virtual void setTarget(Atom&, uint64_t offset) = 0; + virtual void setFromTarget(Atom&) = 0; + virtual const char* getDescription() const = 0; + +protected: + Reference() {} + virtual ~Reference() {} +}; + + +}; // namespace ObjectFile + + +#endif // __OBJECTFILE__ diff --git a/FireOpal/src/OpaqueSection.hpp b/FireOpal/src/OpaqueSection.hpp new file mode 100644 index 0000000..cddd45c --- /dev/null +++ b/FireOpal/src/OpaqueSection.hpp @@ -0,0 +1,199 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2005-2006 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@ + */ + +#ifndef __OPAQUE_SECTION__ +#define __OPAQUE_SECTION__ + + +#include + +#include "ObjectFile.h" + +namespace opaque_section { + + +class Segment : public ObjectFile::Segment +{ +public: + Segment(const char* name) { fName = name; } + virtual const char* getName() const { return fName; } + virtual bool isContentReadable() const { return true; } + virtual bool isContentWritable() const { return false; } + virtual bool isContentExecutable() const { return (strcmp(fName, "__TEXT") == 0); } +private: + const char* fName; +}; + + +class Reader : public ObjectFile::Reader +{ +public: + Reader(const char* segmentName, const char* sectionName, const char* path, + const uint8_t fileContent[], uint64_t fileLength, uint32_t ordinal, const char* symbolName=NULL); + virtual ~Reader(); + + void addSectionReference(uint8_t kind, uint64_t offsetInSection, const ObjectFile::Atom* targetAtom, + uint64_t offsetInTarget, const ObjectFile::Atom* fromTargetAtom=NULL, uint64_t offsetInFromTarget=0); + + virtual const char* getPath() { return fPath; } + virtual time_t getModificationTime() { return 0; } + virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; } + virtual std::vector& getAtoms() { return fAtoms; } + virtual std::vector* getJustInTimeAtomsFor(const char* name) { return NULL; } + virtual std::vector* getStabs() { return NULL; } + +private: + const char* fPath; + std::vector fAtoms; +}; + +class Reference : public ObjectFile::Reference +{ +public: + Reference(uint8_t kind, uint64_t fixupOffset, const ObjectFile::Atom* target, uint64_t targetOffset, + const ObjectFile::Atom* fromTarget=NULL, uint64_t fromTargetOffset=0) + : fFixUpOffset(fixupOffset), fTarget(target), fTargetOffset(targetOffset), fKind(kind), + fFromTarget(fromTarget), fFromTargetOffset(fromTargetOffset) {} + virtual ~Reference() {} + + + virtual ObjectFile::Reference::TargetBinding getTargetBinding() const { return ObjectFile::Reference::kBoundDirectly; } + virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const{ return ObjectFile::Reference::kDontBind; } + virtual uint8_t getKind() const { return fKind; } + virtual uint64_t getFixUpOffset() const { return fFixUpOffset; } + virtual const char* getTargetName() const { return fTarget->getName(); } + virtual ObjectFile::Atom& getTarget() const { return *((ObjectFile::Atom*)fTarget); } + virtual uint64_t getTargetOffset() const { return fTargetOffset; } + virtual ObjectFile::Atom& getFromTarget() const { return *((ObjectFile::Atom*)fFromTarget); } + virtual const char* getFromTargetName() const { return fFromTarget->getName(); } + virtual uint64_t getFromTargetOffset() const { return fFromTargetOffset; } + virtual void setTarget(ObjectFile::Atom&, uint64_t offset) { throw "can't set target"; } + virtual void setFromTarget(ObjectFile::Atom&) { throw "can't set from target"; } + virtual const char* getDescription() const { return "opaque section reference"; } + +private: + uint64_t fFixUpOffset; + const ObjectFile::Atom* fTarget; + uint64_t fTargetOffset; + uint8_t fKind; + const ObjectFile::Atom* fFromTarget; + uint64_t fFromTargetOffset; +}; + + +class Atom : public ObjectFile::Atom { +public: + virtual ObjectFile::Reader* getFile() const { return &fOwner; } + virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; } + virtual const char* getName() const { return fName; } + virtual const char* getDisplayName() const; + virtual Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } + virtual DefinitionKind getDefinitionKind() const { return kRegularDefinition; } + virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; } + virtual bool dontDeadStrip() const { return true; } + virtual bool isZeroFill() const { return false; } + virtual bool isThumb() const { return false; } + virtual uint64_t getSize() const { return fFileLength; } + virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } + virtual bool mustRemainInSection() const { return false; } + virtual const char* getSectionName() const { return fSectionName; } + virtual Segment& getSegment() const { return fSegment; } + virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); } + virtual uint32_t getOrdinal() const { return fOrdinal; } + virtual std::vector* getLineInfo() const { return NULL; } + virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(4); } + virtual void copyRawContent(uint8_t buffer[]) const; + + virtual void setScope(Scope) { } + +protected: + friend class Reader; + + Atom(Reader& owner, Segment& segment, const char* sectionName, + const uint8_t fileContent[], uint64_t fileLength, uint32_t ordinal, const char* symbolName); + virtual ~Atom() {} + + Reader& fOwner; + Segment& fSegment; + const char* fName; + const char* fSectionName; + const uint8_t* fFileContent; + uint32_t fOrdinal; + uint64_t fFileLength; + std::vector fReferences; +}; + + + +Atom::Atom(Reader& owner, Segment& segment, const char* sectionName, const uint8_t fileContent[], uint64_t fileLength, uint32_t ordinal, const char* symbolName) + : fOwner(owner), fSegment(segment), fSectionName(sectionName), fFileContent(fileContent), fOrdinal(ordinal), fFileLength(fileLength) +{ + if ( symbolName != NULL ) + fName = strdup(symbolName); + else + asprintf((char**)&fName, "__section$%s%s", segment.getName(), sectionName); +} + + +Reader::Reader(const char* segmentName, const char* sectionName, const char* path, const uint8_t fileContent[], + uint64_t fileLength, uint32_t ordinal, const char* symbolName) + : fPath(path) +{ + fAtoms.push_back(new Atom(*this, *(new Segment(segmentName)), strdup(sectionName), fileContent, fileLength, ordinal, symbolName)); +} + +Reader::~Reader() +{ +} + +void Reader::addSectionReference(uint8_t kind, uint64_t offsetInSection, const ObjectFile::Atom* targetAtom, + uint64_t offsetInTarget, const ObjectFile::Atom* fromTargetAtom, uint64_t offsetInFromTarget) +{ + fAtoms[0]->getReferences().push_back(new Reference(kind, offsetInSection, targetAtom, offsetInTarget, fromTargetAtom, offsetInFromTarget)); +} + + +const char* Atom::getDisplayName() const +{ + static char name[64]; + sprintf(name, "opaque section %s %s", fSegment.getName(), fSectionName); + return name; +} + + +void Atom::copyRawContent(uint8_t buffer[]) const +{ + memcpy(buffer, fFileContent, fFileLength); +} + + + +}; + + + +#endif // __OPAQUE_SECTION__ + + + diff --git a/FireOpal/src/Options.cpp b/FireOpal/src/Options.cpp new file mode 100644 index 0000000..eb244ed --- /dev/null +++ b/FireOpal/src/Options.cpp @@ -0,0 +1,3150 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2005-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@ + */ + + +#include +#include +#include +#include +#include + +#include "configure.h" +#include "Options.h" +#include "Architectures.hpp" +#include "MachOFileAbstraction.hpp" + +extern void printLTOVersion(Options &opts); + + +static bool sEmitWarnings = true; +static const char* sWarningsSideFilePath = NULL; +static FILE* sWarningsSideFile = NULL; + +void warning(const char* format, ...) +{ + if ( sEmitWarnings ) { + va_list list; + if ( sWarningsSideFilePath != NULL ) { + if ( sWarningsSideFile == NULL ) + sWarningsSideFile = fopen(sWarningsSideFilePath, "a"); + } + va_start(list, format); + fprintf(stderr, "ld warning: "); + vfprintf(stderr, format, list); + fprintf(stderr, "\n"); + if ( sWarningsSideFile != NULL ) { + fprintf(sWarningsSideFile, "ld warning: "); + vfprintf(sWarningsSideFile, format, list); + fprintf(sWarningsSideFile, "\n"); + fflush(sWarningsSideFile); + } + va_end(list); + } +} + +void throwf(const char* format, ...) +{ + va_list list; + char* p; + va_start(list, format); + vasprintf(&p, format, list); + va_end(list); + + const char* t = p; + throw t; +} + +Options::Options(int argc, const char* argv[]) + : fOutputFile("a.out"), fArchitecture(0), fSubArchitecture(0), fOutputKind(kDynamicExecutable), + fHasPreferredSubType(false), fPrebind(false), fBindAtLoad(false), fKeepPrivateExterns(false), + fNeedsModuleTable(false), fIgnoreOtherArchFiles(false), fForceSubtypeAll(false), + fInterposeMode(kInterposeNone), fDeadStrip(kDeadStripOff), fNameSpace(kTwoLevelNameSpace), + fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fFinalName(NULL), fEntryName("start"), fBaseAddress(0), + fBaseWritableAddress(0), fSplitSegs(false), + fExportMode(kExportDefault), fLibrarySearchMode(kSearchAllDirsForDylibsThenAllDirsForArchives), + fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(false), + fWeakReferenceMismatchTreatment(kWeakReferenceMismatchNonWeak), + fClientName(NULL), + fUmbrellaName(NULL), fInitFunctionName(NULL), fDotOutputFile(NULL), fExecutablePath(NULL), + fBundleLoader(NULL), fDtraceScriptName(NULL), fSegAddrTablePath(NULL), fMapPath(NULL), + fZeroPageSize(ULLONG_MAX), fStackSize(0), fStackAddr(0), fExecutableStack(false), fMinimumHeaderPad(32), + fCommonsMode(kCommonsIgnoreDylibs), fUUIDMode(kUUIDContent), fLocalSymbolHandling(kLocalSymbolsAll), fWarnCommons(false), + fVerbose(false), fKeepRelocations(false), fWarnStabs(false), + fTraceDylibSearching(false), fPause(false), fStatistics(false), fPrintOptions(false), + fSharedRegionEligible(false), fPrintOrderFileStatistics(false), + fReadOnlyx86Stubs(false), fPositionIndependentExecutable(false), fMaxMinimumHeaderPad(false), + fDeadStripDylibs(false), fAllowTextRelocs(false), fWarnTextRelocs(false), + fUsingLazyDylibLinking(false), fEncryptable(true), fSaveTempFiles(false) +{ + this->checkForClassic(argc, argv); + this->parsePreCommandLineEnvironmentSettings(); + this->parse(argc, argv); + this->parsePostCommandLineEnvironmentSettings(); + this->reconfigureDefaults(); + this->checkIllegalOptionCombinations(); +} + +Options::~Options() +{ +} + +const ObjectFile::ReaderOptions& Options::readerOptions() +{ + return fReaderOptions; +} + + +const char* Options::getOutputFilePath() +{ + return fOutputFile; +} + +std::vector& Options::getInputFiles() +{ + return fInputFiles; +} + +Options::OutputKind Options::outputKind() +{ + return fOutputKind; +} + +bool Options::bindAtLoad() +{ + return fBindAtLoad; +} + +bool Options::prebind() +{ + return fPrebind; +} + +bool Options::fullyLoadArchives() +{ + return fReaderOptions.fFullyLoadArchives; +} + +Options::NameSpace Options::nameSpace() +{ + return fNameSpace; +} + +const char* Options::installPath() +{ + if ( fDylibInstallName != NULL ) + return fDylibInstallName; + else if ( fFinalName != NULL ) + return fFinalName; + else + return fOutputFile; +} + +uint32_t Options::currentVersion() +{ + return fDylibCurrentVersion; +} + +uint32_t Options::compatibilityVersion() +{ + return fDylibCompatVersion; +} + +const char* Options::entryName() +{ + return fEntryName; +} + +uint64_t Options::baseAddress() +{ + return fBaseAddress; +} + +bool Options::keepPrivateExterns() +{ + return fKeepPrivateExterns; +} + +bool Options::interposable(const char* name) +{ + switch ( fInterposeMode ) { + case kInterposeNone: + return false; + case kInterposeAllExternal: + return true; + case kInterposeSome: + return fInterposeList.contains(name); + } + throw "internal error"; +} + +bool Options::needsModuleTable() +{ + return fNeedsModuleTable; +} + +bool Options::ignoreOtherArchInputFiles() +{ + return fIgnoreOtherArchFiles; +} + +bool Options::forceCpuSubtypeAll() +{ + return fForceSubtypeAll; +} + +bool Options::traceDylibs() +{ + return fReaderOptions.fTraceDylibs; +} + +bool Options::traceArchives() +{ + return fReaderOptions.fTraceArchives; +} + +Options::UndefinedTreatment Options::undefinedTreatment() +{ + return fUndefinedTreatment; +} + +ObjectFile::ReaderOptions::VersionMin Options::macosxVersionMin() +{ + return fReaderOptions.fVersionMin; +} + +Options::WeakReferenceMismatchTreatment Options::weakReferenceMismatchTreatment() +{ + return fWeakReferenceMismatchTreatment; +} + +const char* Options::umbrellaName() +{ + return fUmbrellaName; +} + +std::vector& Options::allowableClients() +{ + return fAllowableClients; +} + +const char* Options::clientName() +{ + return fClientName; +} + +uint64_t Options::zeroPageSize() +{ + return fZeroPageSize; +} + +bool Options::hasCustomStack() +{ + return (fStackSize != 0); +} + +uint64_t Options::customStackSize() +{ + return fStackSize; +} + +uint64_t Options::customStackAddr() +{ + return fStackAddr; +} + +bool Options::hasExecutableStack() +{ + return fExecutableStack; +} + +std::vector& Options::initialUndefines() +{ + return fInitialUndefines; +} + +bool Options::printWhyLive(const char* symbolName) +{ + return ( fWhyLive.find(symbolName) != fWhyLive.end() ); +} + + +const char* Options::initFunctionName() +{ + return fInitFunctionName; +} + +const char* Options::dotOutputFile() +{ + return fDotOutputFile; +} + +bool Options::hasExportRestrictList() +{ + return (fExportMode != kExportDefault); +} + +bool Options::hasExportMaskList() +{ + return (fExportMode == kExportSome); +} + + +bool Options::hasWildCardExportRestrictList() +{ + // has -exported_symbols_list which contains some wildcards + return ((fExportMode == kExportSome) && fExportSymbols.hasWildCards()); +} + + +bool Options::allGlobalsAreDeadStripRoots() +{ + // -exported_symbols_list means globals are not exported by default + if ( fExportMode == kExportSome ) + return false; + // + switch ( fOutputKind ) { + case Options::kDynamicExecutable: + case Options::kStaticExecutable: + // by default unused globals in a main executable are stripped + return false; + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kObjectFile: + case Options::kDyld: + return true; + } + return false; +} + +uint32_t Options::minimumHeaderPad() +{ + return fMinimumHeaderPad; +} + +std::vector& Options::extraSections() +{ + return fExtraSections; +} + +std::vector& Options::sectionAlignments() +{ + return fSectionAlignments; +} + +Options::CommonsMode Options::commonsMode() +{ + return fCommonsMode; +} + +bool Options::warnCommons() +{ + return fWarnCommons; +} + +bool Options::keepRelocations() +{ + return fKeepRelocations; +} + +bool Options::warnStabs() +{ + return fWarnStabs; +} + +const char* Options::executablePath() +{ + return fExecutablePath; +} + +Options::DeadStripMode Options::deadStrip() +{ + return fDeadStrip; +} + +bool Options::shouldExport(const char* symbolName) +{ + switch (fExportMode) { + case kExportSome: + return fExportSymbols.contains(symbolName); + case kDontExportSome: + return ! fDontExportSymbols.contains(symbolName); + case kExportDefault: + return true; + } + throw "internal error"; +} + +bool Options::keepLocalSymbol(const char* symbolName) +{ + switch (fLocalSymbolHandling) { + case kLocalSymbolsAll: + return true; + case kLocalSymbolsNone: + return false; + case kLocalSymbolsSelectiveInclude: + return fLocalSymbolsIncluded.contains(symbolName); + case kLocalSymbolsSelectiveExclude: + return ! fLocalSymbolsExcluded.contains(symbolName); + } + throw "internal error"; +} + +void Options::parseArch(const char* architecture) +{ + if ( architecture == NULL ) + throw "-arch must be followed by an architecture string"; + if ( strcmp(architecture, "ppc") == 0 ) { + fArchitecture = CPU_TYPE_POWERPC; + fSubArchitecture = CPU_SUBTYPE_POWERPC_ALL; + } + else if ( strcmp(architecture, "ppc64") == 0 ) { + fArchitecture = CPU_TYPE_POWERPC64; + fSubArchitecture = CPU_SUBTYPE_POWERPC_ALL; + } + else if ( strcmp(architecture, "i386") == 0 ) { + fArchitecture = CPU_TYPE_I386; + fSubArchitecture = CPU_SUBTYPE_I386_ALL; + } + else if ( strcmp(architecture, "x86_64") == 0 ) { + fArchitecture = CPU_TYPE_X86_64; + fSubArchitecture = CPU_SUBTYPE_X86_64_ALL; + } + else if ( strcmp(architecture, "arm") == 0 ) { + fArchitecture = CPU_TYPE_ARM; + fSubArchitecture = CPU_SUBTYPE_ARM_ALL; + } + // compatibility support for cpu-sub-types + else if ( strcmp(architecture, "ppc750") == 0 ) { + fArchitecture = CPU_TYPE_POWERPC; + fSubArchitecture = CPU_SUBTYPE_POWERPC_750; + fHasPreferredSubType = true; + } + else if ( strcmp(architecture, "ppc7400") == 0 ) { + fArchitecture = CPU_TYPE_POWERPC; + fSubArchitecture = CPU_SUBTYPE_POWERPC_7400; + fHasPreferredSubType = true; + } + else if ( strcmp(architecture, "ppc7450") == 0 ) { + fArchitecture = CPU_TYPE_POWERPC; + fSubArchitecture = CPU_SUBTYPE_POWERPC_7450; + fHasPreferredSubType = true; + } + else if ( strcmp(architecture, "ppc970") == 0 ) { + fArchitecture = CPU_TYPE_POWERPC; + fSubArchitecture = CPU_SUBTYPE_POWERPC_970; + fHasPreferredSubType = true; + } + else if ( strcmp(architecture, "armv6") == 0 ) { + fArchitecture = CPU_TYPE_ARM; + fSubArchitecture = CPU_SUBTYPE_ARM_V6; + fHasPreferredSubType = true; + } + else if ( strcmp(architecture, "armv5") == 0 ) { + fArchitecture = CPU_TYPE_ARM; + fSubArchitecture = CPU_SUBTYPE_ARM_V5TEJ; + fHasPreferredSubType = true; + } + else if ( strcmp(architecture, "armv4t") == 0 ) { + fArchitecture = CPU_TYPE_ARM; + fSubArchitecture = CPU_SUBTYPE_ARM_V4T; + fHasPreferredSubType = true; + } + else if ( strcmp(architecture, "xscale") == 0 ) { + fArchitecture = CPU_TYPE_ARM; + fSubArchitecture = CPU_SUBTYPE_ARM_XSCALE; + fHasPreferredSubType = true; + } + else if ( strcmp(architecture, "armv7") == 0 ) { + fArchitecture = CPU_TYPE_ARM; + fSubArchitecture = CPU_SUBTYPE_ARM_V7; + fHasPreferredSubType = true; + } + else + throwf("unknown/unsupported architecture name for: -arch %s", architecture); +} + +bool Options::checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result) +{ + struct stat statBuffer; + char possiblePath[strlen(dir)+strlen(rootName)+strlen(format)+8]; + sprintf(possiblePath, format, dir, rootName); + bool found = (stat(possiblePath, &statBuffer) == 0); + if ( fTraceDylibSearching ) + printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), possiblePath); + if ( found ) { + result.path = strdup(possiblePath); + result.fileLen = statBuffer.st_size; + result.modTime = statBuffer.st_mtime; + return true; + } + return false; +} + + +Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly) +{ + FileInfo result; + const int rootNameLen = strlen(rootName); + // if rootName ends in .o there is no .a vs .dylib choice + if ( (rootNameLen > 3) && (strcmp(&rootName[rootNameLen-2], ".o") == 0) ) { + for (std::vector::iterator it = fLibrarySearchPaths.begin(); + it != fLibrarySearchPaths.end(); + it++) { + const char* dir = *it; + if ( checkForFile("%s/%s", dir, rootName, result) ) + return result; + } + } + else { + bool lookForDylibs = ( fOutputKind != Options::kDyld); + switch ( fLibrarySearchMode ) { + case kSearchAllDirsForDylibsThenAllDirsForArchives: + // first look in all directories for just for dylibs + if ( lookForDylibs ) { + for (std::vector::iterator it = fLibrarySearchPaths.begin(); + it != fLibrarySearchPaths.end(); + it++) { + const char* dir = *it; + if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) ) + return result; + } + for (std::vector::iterator it = fLibrarySearchPaths.begin(); + it != fLibrarySearchPaths.end(); + it++) { + const char* dir = *it; + if ( checkForFile("%s/lib%s.so", dir, rootName, result) ) + return result; + } + } + // next look in all directories for just for archives + if ( !dylibsOnly ) { + for (std::vector::iterator it = fLibrarySearchPaths.begin(); + it != fLibrarySearchPaths.end(); + it++) { + const char* dir = *it; + if ( checkForFile("%s/lib%s.a", dir, rootName, result) ) + return result; + } + } + break; + + case kSearchDylibAndArchiveInEachDir: + // look in each directory for just for a dylib then for an archive + for (std::vector::iterator it = fLibrarySearchPaths.begin(); + it != fLibrarySearchPaths.end(); + it++) { + const char* dir = *it; + if ( lookForDylibs && checkForFile("%s/lib%s.dylib", dir, rootName, result) ) + return result; + if ( lookForDylibs && checkForFile("%s/lib%s.so", dir, rootName, result) ) + return result; + if ( !dylibsOnly && checkForFile("%s/lib%s.a", dir, rootName, result) ) + return result; + } + break; + } + } + throwf("library not found for -l%s", rootName); +} + +Options::FileInfo Options::findFramework(const char* frameworkName) +{ + if ( frameworkName == NULL ) + throw "-framework missing next argument"; + char temp[strlen(frameworkName)+1]; + strcpy(temp, frameworkName); + const char* name = temp; + const char* suffix = NULL; + char* comma = strchr(temp, ','); + if ( comma != NULL ) { + *comma = '\0'; + suffix = &comma[1]; + } + return findFramework(name, suffix); +} + +Options::FileInfo Options::findFramework(const char* rootName, const char* suffix) +{ + struct stat statBuffer; + for (std::vector::iterator it = fFrameworkSearchPaths.begin(); + it != fFrameworkSearchPaths.end(); + it++) { + // ??? Shouldn't we be using String here and just initializing it? + // ??? Use str.c_str () to pull out the string for the stat call. + const char* dir = *it; + char possiblePath[PATH_MAX]; + strcpy(possiblePath, dir); + strcat(possiblePath, "/"); + strcat(possiblePath, rootName); + strcat(possiblePath, ".framework/"); + strcat(possiblePath, rootName); + if ( suffix != NULL ) { + char realPath[PATH_MAX]; + // no symlink in framework to suffix variants, so follow main symlink + if ( realpath(possiblePath, realPath) != NULL ) { + strcpy(possiblePath, realPath); + strcat(possiblePath, suffix); + } + } + bool found = (stat(possiblePath, &statBuffer) == 0); + if ( fTraceDylibSearching ) + printf("[Logging for XBS]%sfound framework: '%s'\n", + (found ? " " : " not "), possiblePath); + if ( found ) { + FileInfo result; + result.path = strdup(possiblePath); + result.fileLen = statBuffer.st_size; + result.modTime = statBuffer.st_mtime; + return result; + } + } + // try without suffix + if ( suffix != NULL ) + return findFramework(rootName, NULL); + else + throwf("framework not found %s", rootName); +} + +Options::FileInfo Options::findFile(const char* path) +{ + FileInfo result; + struct stat statBuffer; + + // if absolute path and not a .o file, the use SDK prefix + if ( (path[0] == '/') && (strcmp(&path[strlen(path)-2], ".o") != 0) ) { + const int pathLen = strlen(path); + for (std::vector::iterator it = fSDKPaths.begin(); it != fSDKPaths.end(); it++) { + // ??? Shouldn't we be using String here? + const char* sdkPathDir = *it; + const int sdkPathDirLen = strlen(sdkPathDir); + char possiblePath[sdkPathDirLen+pathLen+4]; + strcpy(possiblePath, sdkPathDir); + if ( possiblePath[sdkPathDirLen-1] == '/' ) + possiblePath[sdkPathDirLen-1] = '\0'; + strcat(possiblePath, path); + if ( stat(possiblePath, &statBuffer) == 0 ) { + result.path = strdup(possiblePath); + result.fileLen = statBuffer.st_size; + result.modTime = statBuffer.st_mtime; + return result; + } + } + } + // try raw path + if ( stat(path, &statBuffer) == 0 ) { + result.path = strdup(path); + result.fileLen = statBuffer.st_size; + result.modTime = statBuffer.st_mtime; + return result; + } + + // try @executable_path substitution + if ( (strncmp(path, "@executable_path/", 17) == 0) && (fExecutablePath != NULL) ) { + char newPath[strlen(fExecutablePath) + strlen(path)]; + strcpy(newPath, fExecutablePath); + char* addPoint = strrchr(newPath,'/'); + if ( addPoint != NULL ) + strcpy(&addPoint[1], &path[17]); + else + strcpy(newPath, &path[17]); + if ( stat(newPath, &statBuffer) == 0 ) { + result.path = strdup(newPath); + result.fileLen = statBuffer.st_size; + result.modTime = statBuffer.st_mtime; + return result; + } + } + + // not found + throwf("file not found: %s", path); +} + +Options::FileInfo Options::findFileUsingPaths(const char* path) +{ + FileInfo result; + + const char* lastSlash = strrchr(path, '/'); + const char* leafName = (lastSlash == NULL) ? path : &lastSlash[1]; + + // Is this in a framework? + // /path/Foo.framework/Foo ==> true (Foo) + // /path/Foo.framework/Frameworks/Bar.framework/Bar ==> true (Bar) + // /path/Foo.framework/Resources/Bar ==> false + bool isFramework = false; + if ( lastSlash != NULL ) { + char frameworkDir[strlen(leafName) + 20]; + strcpy(frameworkDir, "/"); + strcat(frameworkDir, leafName); + strcat(frameworkDir, ".framework/"); + if ( strstr(path, frameworkDir) != NULL ) + isFramework = true; + } + + // These are abbreviated versions of the routines findFramework and findLibrary above + // because we already know the final name of the file that we're looking for and so + // don't need to try variations, just paths. We do need to add the additional bits + // onto the framework path though. + if ( isFramework ) { + for (std::vector::iterator it = fFrameworkSearchPaths.begin(); + it != fFrameworkSearchPaths.end(); + it++) { + const char* dir = *it; + char possiblePath[PATH_MAX]; + strcpy(possiblePath, dir); + strcat(possiblePath, "/"); + strcat(possiblePath, leafName); + strcat(possiblePath, ".framework"); + + //fprintf(stderr,"Finding Framework: %s/%s, leafName=%s\n", possiblePath, leafName, leafName); + if ( checkForFile("%s/%s", possiblePath, leafName, result) ) + return result; + } + } + else { + // if this is a .dylib inside a framework, do not search -L paths + // ld64's re-export cycle detection logic prevents use of X11 libGL on Leopard + int leafLen = strlen(leafName); + bool embeddedDylib = ( (leafLen > 6) + && (strcmp(&leafName[leafLen-6], ".dylib") == 0) + && (strstr(path, ".framework/") != NULL) ); + if ( !embeddedDylib ) { + for (std::vector::iterator it = fLibrarySearchPaths.begin(); + it != fLibrarySearchPaths.end(); + it++) { + const char* dir = *it; + //fprintf(stderr,"Finding Library: %s/%s\n", dir, leafName); + if ( checkForFile("%s/%s", dir, leafName, result) ) + return result; + } + } + } + + // If we didn't find it fall back to findFile. + return findFile(path); +} + + +void Options::parseSegAddrTable(const char* segAddrPath, const char* installPath) +{ + FILE* file = fopen(segAddrPath, "r"); + if ( file == NULL ) { + warning("-seg_addr_table file cannot be read: %s", segAddrPath); + return; + } + + char path[PATH_MAX]; + uint64_t firstColumAddress = 0; + uint64_t secondColumAddress = 0; + bool hasSecondColumn = false; + while ( fgets(path, PATH_MAX, file) != NULL ) { + path[PATH_MAX-1] = '\0'; + char* eol = strchr(path, '\n'); + if ( eol != NULL ) + *eol = '\0'; + // ignore lines not starting with 0x number + if ( (path[0] == '0') && (path[1] == 'x') ) { + char* p; + firstColumAddress = strtoull(path, &p, 16); + while ( isspace(*p) ) + ++p; + // see if second column is a number + if ( (p[0] == '0') && (p[1] == 'x') ) { + secondColumAddress = strtoull(p, &p, 16); + hasSecondColumn = true; + while ( isspace(*p) ) + ++p; + } + while ( isspace(*p) ) + ++p; + if ( p[0] == '/' ) { + // remove any trailing whitespace + for(char* end = eol-1; (end > p) && isspace(*end); --end) + *end = '\0'; + // see if this line is for the dylib being linked + if ( strcmp(p, installPath) == 0 ) { + fBaseAddress = firstColumAddress; + if ( hasSecondColumn ) { + fBaseWritableAddress = secondColumAddress; + fSplitSegs = true; + } + break; // out of while loop + } + } + } + } + + fclose(file); +} + +void Options::loadFileList(const char* fileOfPaths) +{ + FILE* file; + const char* comma = strrchr(fileOfPaths, ','); + const char* prefix = NULL; + if ( comma != NULL ) { + prefix = comma+1; + int realFileOfPathsLen = comma-fileOfPaths; + char realFileOfPaths[realFileOfPathsLen+1]; + strncpy(realFileOfPaths,fileOfPaths, realFileOfPathsLen); + realFileOfPaths[realFileOfPathsLen] = '\0'; + file = fopen(realFileOfPaths, "r"); + if ( file == NULL ) + throwf("-filelist file not found: %s\n", realFileOfPaths); + } + else { + file = fopen(fileOfPaths, "r"); + if ( file == NULL ) + throwf("-filelist file not found: %s\n", fileOfPaths); + } + + char path[PATH_MAX]; + while ( fgets(path, PATH_MAX, file) != NULL ) { + path[PATH_MAX-1] = '\0'; + char* eol = strchr(path, '\n'); + if ( eol != NULL ) + *eol = '\0'; + if ( prefix != NULL ) { + char builtPath[strlen(prefix)+strlen(path)+2]; + strcpy(builtPath, prefix); + strcat(builtPath, "/"); + strcat(builtPath, path); + fInputFiles.push_back(findFile(builtPath)); + } + else { + fInputFiles.push_back(findFile(path)); + } + } + fclose(file); +} + +bool Options::SetWithWildcards::hasWildCards(const char* symbol) +{ + // an exported symbol name containing *, ?, or [ requires wildcard matching + return ( strpbrk(symbol, "*?[") != NULL ); +} + +void Options::SetWithWildcards::insert(const char* symbol) +{ + if ( hasWildCards(symbol) ) + fWildCard.push_back(symbol); + else + fRegular.insert(symbol); +} + +bool Options::SetWithWildcards::contains(const char* symbol) +{ + // first look at hash table on non-wildcard symbols + if ( fRegular.find(symbol) != fRegular.end() ) + return true; + // next walk list of wild card symbols looking for a match + for(std::vector::iterator it = fWildCard.begin(); it != fWildCard.end(); ++it) { + if ( wildCardMatch(*it, symbol) ) + return true; + } + return false; +} + + +bool Options::SetWithWildcards::inCharRange(const char*& p, unsigned char c) +{ + ++p; // find end + const char* b = p; + while ( *p != '\0' ) { + if ( *p == ']') { + const char* e = p; + // found beginining [ and ending ] + unsigned char last = '\0'; + for ( const char* s = b; s < e; ++s ) { + if ( *s == '-' ) { + unsigned char next = *(++s); + if ( (last <= c) && (c <= next) ) + return true; + ++s; + } + else { + if ( *s == c ) + return true; + last = *s; + } + } + return false; + } + ++p; + } + return false; +} + +bool Options::SetWithWildcards::wildCardMatch(const char* pattern, const char* symbol) +{ + const char* s = symbol; + for (const char* p = pattern; *p != '\0'; ++p) { + switch ( *p ) { + case '*': + if ( p[1] == '\0' ) + return true; + for (const char* t = s; *t != '\0'; ++t) { + if ( wildCardMatch(&p[1], t) ) + return true; + } + return false; + case '?': + if ( *s == '\0' ) + return false; + ++s; + break; + case '[': + if ( ! inCharRange(p, *s) ) + return false; + ++s; + break; + default: + if ( *s != *p ) + return false; + ++s; + } + } + return (*s == '\0'); +} + + +void Options::loadExportFile(const char* fileOfExports, const char* option, SetWithWildcards& set) +{ + // read in whole file + int fd = ::open(fileOfExports, O_RDONLY, 0); + if ( fd == -1 ) + throwf("can't open %s file: %s", option, fileOfExports); + struct stat stat_buf; + ::fstat(fd, &stat_buf); + char* p = (char*)malloc(stat_buf.st_size); + if ( p == NULL ) + throwf("can't process %s file: %s", option, fileOfExports); + + if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size ) + throwf("can't read %s file: %s", option, fileOfExports); + + ::close(fd); + + // parse into symbols and add to hash_set + char * const end = &p[stat_buf.st_size]; + enum { lineStart, inSymbol, inComment } state = lineStart; + char* symbolStart = NULL; + for (char* s = p; s < end; ++s ) { + switch ( state ) { + case lineStart: + if ( *s =='#' ) { + state = inComment; + } + else if ( !isspace(*s) ) { + state = inSymbol; + symbolStart = s; + } + break; + case inSymbol: + if ( (*s == '\n') || (*s == '\r') ) { + *s = '\0'; + // removing any trailing spaces + char* last = s-1; + while ( isspace(*last) ) { + *last = '\0'; + --last; + } + set.insert(symbolStart); + symbolStart = NULL; + state = lineStart; + } + break; + case inComment: + if ( (*s == '\n') || (*s == '\r') ) + state = lineStart; + break; + } + } + if ( state == inSymbol ) { + warning("missing line-end at end of file \"%s\"", fileOfExports); + int len = end-symbolStart+1; + char* temp = new char[len]; + strlcpy(temp, symbolStart, len); + + // remove any trailing spaces + char* last = &temp[len-2]; + while ( isspace(*last) ) { + *last = '\0'; + --last; + } + set.insert(temp); + } + + // Note: we do not free() the malloc buffer, because the strings are used by the export-set hash table +} + +void Options::parseAliasFile(const char* fileOfAliases) +{ + // read in whole file + int fd = ::open(fileOfAliases, O_RDONLY, 0); + if ( fd == -1 ) + throwf("can't open alias file: %s", fileOfAliases); + struct stat stat_buf; + ::fstat(fd, &stat_buf); + char* p = (char*)malloc(stat_buf.st_size+1); + if ( p == NULL ) + throwf("can't process alias file: %s", fileOfAliases); + + if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size ) + throwf("can't read alias file: %s", fileOfAliases); + p[stat_buf.st_size] = '\n'; + ::close(fd); + + // parse into symbols and add to fAliases + ObjectFile::ReaderOptions::AliasPair pair; + char * const end = &p[stat_buf.st_size+1]; + enum { lineStart, inRealName, inBetween, inAliasName, inComment } state = lineStart; + int lineNumber = 1; + for (char* s = p; s < end; ++s ) { + switch ( state ) { + case lineStart: + if ( *s =='#' ) { + state = inComment; + } + else if ( !isspace(*s) ) { + state = inRealName; + pair.realName = s; + } + break; + case inRealName: + if ( *s == '\n' ) { + warning("line needs two symbols but has only one at line #%d in \"%s\"", lineNumber, fileOfAliases); + ++lineNumber; + state = lineStart; + } + else if ( isspace(*s) ) { + *s = '\0'; + state = inBetween; + } + break; + case inBetween: + if ( *s == '\n' ) { + warning("line needs two symbols but has only one at line #%d in \"%s\"", lineNumber, fileOfAliases); + ++lineNumber; + state = lineStart; + } + else if ( ! isspace(*s) ) { + state = inAliasName; + pair.alias = s; + } + break; + case inAliasName: + if ( *s =='#' ) { + *s = '\0'; + // removing any trailing spaces + char* last = s-1; + while ( isspace(*last) ) { + *last = '\0'; + --last; + } + fReaderOptions.fAliases.push_back(pair); + state = inComment; + } + else if ( *s == '\n' ) { + *s = '\0'; + // removing any trailing spaces + char* last = s-1; + while ( isspace(*last) ) { + *last = '\0'; + --last; + } + fReaderOptions.fAliases.push_back(pair); + state = lineStart; + } + break; + case inComment: + if ( *s == '\n' ) + state = lineStart; + break; + } + } + + // Note: we do not free() the malloc buffer, because the strings therein are used by fAliases +} + + + +void Options::setUndefinedTreatment(const char* treatment) +{ + if ( treatment == NULL ) + throw "-undefined missing [ warning | error | suppress | dynamic_lookup ]"; + + if ( strcmp(treatment, "warning") == 0 ) + fUndefinedTreatment = kUndefinedWarning; + else if ( strcmp(treatment, "error") == 0 ) + fUndefinedTreatment = kUndefinedError; + else if ( strcmp(treatment, "suppress") == 0 ) + fUndefinedTreatment = kUndefinedSuppress; + else if ( strcmp(treatment, "dynamic_lookup") == 0 ) + fUndefinedTreatment = kUndefinedDynamicLookup; + else + throw "invalid option to -undefined [ warning | error | suppress | dynamic_lookup ]"; +} + +Options::Treatment Options::parseTreatment(const char* treatment) +{ + if ( treatment == NULL ) + return kNULL; + + if ( strcmp(treatment, "warning") == 0 ) + return kWarning; + else if ( strcmp(treatment, "error") == 0 ) + return kError; + else if ( strcmp(treatment, "suppress") == 0 ) + return kSuppress; + else + return kInvalid; +} + +void Options::setMacOSXVersionMin(const char* version) +{ + if ( version == NULL ) + throw "-macosx_version_min argument missing"; + + if ( (strncmp(version, "10.", 3) == 0) && isdigit(version[3]) ) { + int num = version[3] - '0'; + switch ( num ) { + case 0: + case 1: + fReaderOptions.fVersionMin = ObjectFile::ReaderOptions::k10_1; + break; + case 2: + fReaderOptions.fVersionMin = ObjectFile::ReaderOptions::k10_2; + break; + case 3: + fReaderOptions.fVersionMin = ObjectFile::ReaderOptions::k10_3; + break; + case 4: + fReaderOptions.fVersionMin = ObjectFile::ReaderOptions::k10_4; + break; + case 5: + fReaderOptions.fVersionMin = ObjectFile::ReaderOptions::k10_5; + break; + case 6: + fReaderOptions.fVersionMin = ObjectFile::ReaderOptions::k10_6; + break; + default: + fReaderOptions.fVersionMin = ObjectFile::ReaderOptions::k10_6; + break; + } + } + else { + warning("unknown option to -macosx_version_min, not 10.x"); + } +} + +void Options::setIPhoneVersionMin(const char* version) +{ + if ( version == NULL ) + throw "-iphoneos_version_min argument missing"; + + if ( ((strncmp(version, "1.", 2) == 0) || (strncmp(version, "2.", 2) == 0)) && isdigit(version[2]) ) { + int num = version[2] - '0'; + switch ( num ) { + case 2: + // TODO: store deployment version + break; + default: + break; + } + } + else { + warning("unknown option to -iphoneos_version_min, not 1.x or 2.x"); + } +} + +void Options::setWeakReferenceMismatchTreatment(const char* treatment) +{ + if ( treatment == NULL ) + throw "-weak_reference_mismatches missing [ error | weak | non-weak ]"; + + if ( strcmp(treatment, "error") == 0 ) + fWeakReferenceMismatchTreatment = kWeakReferenceMismatchError; + else if ( strcmp(treatment, "weak") == 0 ) + fWeakReferenceMismatchTreatment = kWeakReferenceMismatchWeak; + else if ( strcmp(treatment, "non-weak") == 0 ) + fWeakReferenceMismatchTreatment = kWeakReferenceMismatchNonWeak; + else + throw "invalid option to -weak_reference_mismatches [ error | weak | non-weak ]"; +} + +Options::CommonsMode Options::parseCommonsTreatment(const char* mode) +{ + if ( mode == NULL ) + throw "-commons missing [ ignore_dylibs | use_dylibs | error ]"; + + if ( strcmp(mode, "ignore_dylibs") == 0 ) + return kCommonsIgnoreDylibs; + else if ( strcmp(mode, "use_dylibs") == 0 ) + return kCommonsOverriddenByDylibs; + else if ( strcmp(mode, "error") == 0 ) + return kCommonsConflictsDylibsError; + else + throw "invalid option to -commons [ ignore_dylibs | use_dylibs | error ]"; +} + +void Options::addDylibOverride(const char* paths) +{ + if ( paths == NULL ) + throw "-dylib_file must followed by two colon separated paths"; + const char* colon = strchr(paths, ':'); + if ( colon == NULL ) + throw "-dylib_file must followed by two colon separated paths"; + int len = colon-paths; + char* target = new char[len+2]; + strncpy(target, paths, len); + target[len] = '\0'; + DylibOverride entry; + entry.installName = target; + entry.useInstead = &colon[1]; + fDylibOverrides.push_back(entry); +} + +uint64_t Options::parseAddress(const char* addr) +{ + char* endptr; + uint64_t result = strtoull(addr, &endptr, 16); + return result; +} + +uint32_t Options::parseProtection(const char* prot) +{ + uint32_t result = 0; + for(const char* p = prot; *p != '\0'; ++p) { + switch(tolower(*p)) { + case 'r': + result |= VM_PROT_READ; + break; + case 'w': + result |= VM_PROT_WRITE; + break; + case 'x': + result |= VM_PROT_EXECUTE; + break; + case '-': + break; + default: + throwf("unknown -segprot lettter in %s", prot); + } + } + return result; +} + + + +// +// Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz +// +// +uint32_t Options::parseVersionNumber(const char* versionString) +{ + unsigned long x = 0; + unsigned long y = 0; + unsigned long z = 0; + char* end; + x = strtoul(versionString, &end, 10); + if ( *end == '.' ) { + y = strtoul(&end[1], &end, 10); + if ( *end == '.' ) { + z = strtoul(&end[1], &end, 10); + } + } + if ( (*end != '\0') || (x > 0xffff) || (y > 0xff) || (z > 0xff) ) + throwf("malformed version number: %s", versionString); + + return (x << 16) | ( y << 8 ) | z; +} + +static const char* cstringSymbolName(const char* orderFileString) +{ + char* result; + asprintf(&result, "cstring=%s", orderFileString); + // convert escaped characters + char* d = result; + for(const char* s=result; *s != '\0'; ++s, ++d) { + if ( *s == '\\' ) { + ++s; + switch ( *s ) { + case 'n': + *d = '\n'; + break; + case 't': + *d = '\t'; + break; + case 'v': + *d = '\v'; + break; + case 'b': + *d = '\b'; + break; + case 'r': + *d = '\r'; + break; + case 'f': + *d = '\f'; + break; + case 'a': + *d = '\a'; + break; + case '\\': + *d = '\\'; + break; + case '?': + *d = '\?'; + break; + case '\'': + *d = '\r'; + break; + case '\"': + *d = '\"'; + break; + case 'x': + // hexadecimal value of char + { + ++s; + char value = 0; + while ( isxdigit(*s) ) { + value *= 16; + if ( isdigit(*s) ) + value += (*s-'0'); + else + value += ((toupper(*s)-'A') + 10); + ++s; + } + *d = value; + } + break; + default: + if ( isdigit(*s) ) { + // octal value of char + char value = 0; + while ( isdigit(*s) ) { + value = (value << 3) + (*s-'0'); + ++s; + } + *d = value; + } + } + } + else { + *d = *s; + } + } + *d = '\0'; + return result; +} + +void Options::parseOrderFile(const char* path, bool cstring) +{ + // read in whole file + int fd = ::open(path, O_RDONLY, 0); + if ( fd == -1 ) + throwf("can't open order file: %s", path); + struct stat stat_buf; + ::fstat(fd, &stat_buf); + char* p = (char*)malloc(stat_buf.st_size+1); + if ( p == NULL ) + throwf("can't process order file: %s", path); + if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size ) + throwf("can't read order file: %s", path); + ::close(fd); + p[stat_buf.st_size] = '\n'; + + // parse into vector of pairs + char * const end = &p[stat_buf.st_size+1]; + enum { lineStart, inSymbol, inComment } state = lineStart; + char* symbolStart = NULL; + for (char* s = p; s < end; ++s ) { + switch ( state ) { + case lineStart: + if ( *s =='#' ) { + state = inComment; + } + else if ( !isspace(*s) || cstring ) { + state = inSymbol; + symbolStart = s; + } + break; + case inSymbol: + if ( (*s == '\n') || (!cstring && (*s == '#')) ) { + bool wasComment = (*s == '#'); + *s = '\0'; + // removing any trailing spaces + char* last = s-1; + while ( isspace(*last) ) { + *last = '\0'; + --last; + } + if ( strncmp(symbolStart, "ppc:", 4) == 0 ) { + if ( fArchitecture == CPU_TYPE_POWERPC ) + symbolStart = &symbolStart[4]; + else + symbolStart = NULL; + } + // if there is an architecture prefix, only use this symbol it if matches current arch + else if ( strncmp(symbolStart, "ppc64:", 6) == 0 ) { + if ( fArchitecture == CPU_TYPE_POWERPC64 ) + symbolStart = &symbolStart[6]; + else + symbolStart = NULL; + } + else if ( strncmp(symbolStart, "i386:", 5) == 0 ) { + if ( fArchitecture == CPU_TYPE_I386 ) + symbolStart = &symbolStart[5]; + else + symbolStart = NULL; + } + else if ( strncmp(symbolStart, "x86_64:", 7) == 0 ) { + if ( fArchitecture == CPU_TYPE_X86_64 ) + symbolStart = &symbolStart[7]; + else + symbolStart = NULL; + } + else if ( strncmp(symbolStart, "arm:", 4) == 0 ) { + if ( fArchitecture == CPU_TYPE_ARM ) + symbolStart = &symbolStart[4]; + else + symbolStart = NULL; + } + if ( symbolStart != NULL ) { + char* objFileName = NULL; + char* colon = strstr(symbolStart, ".o:"); + if ( colon != NULL ) { + colon[2] = '\0'; + objFileName = symbolStart; + symbolStart = &colon[3]; + } + // trim leading spaces + while ( isspace(*symbolStart) ) + ++symbolStart; + Options::OrderedSymbol pair; + if ( cstring ) + pair.symbolName = cstringSymbolName(symbolStart); + else + pair.symbolName = symbolStart; + pair.objectFileName = objFileName; + fOrderedSymbols.push_back(pair); + } + symbolStart = NULL; + if ( wasComment ) + state = inComment; + else + state = lineStart; + } + break; + case inComment: + if ( *s == '\n' ) + state = lineStart; + break; + } + } + // Note: we do not free() the malloc buffer, because the strings are used by the fOrderedSymbols +} + +void Options::parseSectionOrderFile(const char* segment, const char* section, const char* path) +{ + if ( (strcmp(section, "__cstring") == 0) && (strcmp(segment, "__TEXT") == 0) ) { + parseOrderFile(path, true); + } + else if ( (strncmp(section, "__literal",9) == 0) && (strcmp(segment, "__TEXT") == 0) ) { + warning("sorting of __literal[4,8,16] sections not supported"); + } + else { + // ignore section information and append all symbol names to global order file + parseOrderFile(path, false); + } +} + +void Options::addSection(const char* segment, const char* section, const char* path) +{ + if ( strlen(segment) > 16 ) + throw "-seccreate segment name max 16 chars"; + if ( strlen(section) > 16 ) { + char* tmp = strdup(section); + tmp[16] = '\0'; + warning("-seccreate section name (%s) truncated to 16 chars (%s)\n", section, tmp); + section = tmp; + } + + // read in whole file + int fd = ::open(path, O_RDONLY, 0); + if ( fd == -1 ) + throwf("can't open -sectcreate file: %s", path); + struct stat stat_buf; + ::fstat(fd, &stat_buf); + char* p = (char*)malloc(stat_buf.st_size); + if ( p == NULL ) + throwf("can't process -sectcreate file: %s", path); + if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size ) + throwf("can't read -sectcreate file: %s", path); + ::close(fd); + + // record section to create + ExtraSection info = { segment, section, path, (uint8_t*)p, stat_buf.st_size }; + fExtraSections.push_back(info); +} + +void Options::addSectionAlignment(const char* segment, const char* section, const char* alignmentStr) +{ + if ( strlen(segment) > 16 ) + throw "-sectalign segment name max 16 chars"; + if ( strlen(section) > 16 ) + throw "-sectalign section name max 16 chars"; + + // argument to -sectalign is a hexadecimal number + char* endptr; + unsigned long value = strtoul(alignmentStr, &endptr, 16); + if ( *endptr != '\0') + throw "argument for -sectalign is not a hexadecimal number"; + if ( value > 0x8000 ) + throw "argument for -sectalign must be less than or equal to 0x8000"; + if ( value == 0 ) { + warning("zero is not a valid -sectalign"); + value = 1; + } + + // alignment is power of 2 (e.g. page alignment = 12) + uint8_t alignment = (uint8_t)__builtin_ctz(value); + if ( (unsigned long)(1 << alignment) != value ) { + warning("alignment for -sectalign %s %s is not a power of two, using 0x%X", + segment, section, 1 << alignment); + } + + SectionAlignment info = { segment, section, alignment }; + fSectionAlignments.push_back(info); +} + +void Options::addLibrary(const FileInfo& info) +{ + // if this library has already been added, don't add again (archives are automatically repeatedly searched) + for (std::vector::iterator fit = fInputFiles.begin(); fit != fInputFiles.end(); fit++) { + if ( strcmp(info.path, fit->path) == 0 ) { + // if dylib is specified again but weak, record that it should be weak + if ( info.options.fWeakImport ) + fit->options.fWeakImport = true; + return; + } + } + // add to list + fInputFiles.push_back(info); +} + +void Options::warnObsolete(const char* arg) +{ + warning("option %s is obsolete and being ignored", arg); +} + + + + +// +// Process all command line arguments. +// +// The only error checking done here is that each option is valid and if it has arguments +// that they too are valid. +// +// The general rule is "last option wins", i.e. if both -bundle and -dylib are specified, +// whichever was last on the command line is used. +// +// Error check for invalid combinations of options is done in checkIllegalOptionCombinations() +// +void Options::parse(int argc, const char* argv[]) +{ + // pass one builds search list from -L and -F options + this->buildSearchPaths(argc, argv); + + // reduce re-allocations + fInputFiles.reserve(32); + + // pass two parse all other options + for(int i=1; i < argc; ++i) { + const char* arg = argv[i]; + + if ( arg[0] == '-' ) { + + // Since we don't care about the files passed, just the option names, we do this here. + if (fPrintOptions) + fprintf (stderr, "[Logging ld64 options]\t%s\n", arg); + + if ( (arg[1] == 'L') || (arg[1] == 'F') ) { + // previously handled by buildSearchPaths() + } + // The one gnu style option we have to keep compatibility + // with gcc. Might as well have the single hyphen one as well. + else if ( (strcmp(arg, "--help") == 0) + || (strcmp(arg, "-help") == 0)) { + fprintf (stdout, "ld64: For information on command line options please use 'man ld'.\n"); + exit (0); + } + else if ( strcmp(arg, "-arch") == 0 ) { + parseArch(argv[++i]); + } + else if ( strcmp(arg, "-dynamic") == 0 ) { + // default + } + else if ( strcmp(arg, "-static") == 0 ) { + if ( fOutputKind != kObjectFile ) + fOutputKind = kStaticExecutable; + fReaderOptions.fForStatic = true; + } + else if ( strcmp(arg, "-dylib") == 0 ) { + fOutputKind = kDynamicLibrary; + } + else if ( strcmp(arg, "-bundle") == 0 ) { + fOutputKind = kDynamicBundle; + } + else if ( strcmp(arg, "-dylinker") == 0 ) { + fOutputKind = kDyld; + } + else if ( strcmp(arg, "-execute") == 0 ) { + if ( fOutputKind != kStaticExecutable ) + fOutputKind = kDynamicExecutable; + } + else if ( strcmp(arg, "-r") == 0 ) { + fOutputKind = kObjectFile; + } + else if ( strcmp(arg, "-o") == 0 ) { + fOutputFile = argv[++i]; + } + else if ( (arg[1] == 'l') && (strncmp(arg,"-lazy_",6) !=0) ) { + addLibrary(findLibrary(&arg[2])); + } + // This causes a dylib to be weakly bound at + // link time. This corresponds to weak_import. + else if ( strncmp(arg, "-weak-l", 7) == 0 ) { + FileInfo info = findLibrary(&arg[7]); + info.options.fWeakImport = true; + addLibrary(info); + } + else if ( strncmp(arg, "-lazy-l", 7) == 0 ) { + FileInfo info = findLibrary(&arg[7], true); + info.options.fLazyLoad = true; + addLibrary(info); + fUsingLazyDylibLinking = true; + } + // Avoid lazy binding. + // ??? Deprecate. + else if ( strcmp(arg, "-bind_at_load") == 0 ) { + fBindAtLoad = true; + } + else if ( strcmp(arg, "-twolevel_namespace") == 0 ) { + fNameSpace = kTwoLevelNameSpace; + } + else if ( strcmp(arg, "-flat_namespace") == 0 ) { + fNameSpace = kFlatNameSpace; + } + // Also sets a bit to ensure dyld causes everything + // in the namespace to be flat. + // ??? Deprecate + else if ( strcmp(arg, "-force_flat_namespace") == 0 ) { + fNameSpace = kForceFlatNameSpace; + } + // Similar to --whole-archive. + else if ( strcmp(arg, "-all_load") == 0 ) { + fReaderOptions.fFullyLoadArchives = true; + } + else if ( strcmp(arg, "-noall_load") == 0) { + warnObsolete(arg); + } + // Similar to -all_load + else if ( strcmp(arg, "-ObjC") == 0 ) { + fReaderOptions.fLoadAllObjcObjectsFromArchives = true; + } + // Library versioning. + else if ( (strcmp(arg, "-dylib_compatibility_version") == 0) + || (strcmp(arg, "-compatibility_version") == 0)) { + const char* vers = argv[++i]; + if ( vers == NULL ) + throw "-dylib_compatibility_version missing "; + fDylibCompatVersion = parseVersionNumber(vers); + } + else if ( (strcmp(arg, "-dylib_current_version") == 0) + || (strcmp(arg, "-current_version") == 0)) { + const char* vers = argv[++i]; + if ( vers == NULL ) + throw "-dylib_current_version missing "; + fDylibCurrentVersion = parseVersionNumber(vers); + } + else if ( strcmp(arg, "-sectorder") == 0 ) { + if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) ) + throw "-sectorder missing

"; + parseSectionOrderFile(argv[i+1], argv[i+2], argv[i+3]); + i += 3; + } + else if ( strcmp(arg, "-order_file") == 0 ) { + parseOrderFile(argv[++i], false); + } + else if ( strcmp(arg, "-order_file_statistics") == 0 ) { + fPrintOrderFileStatistics = true; + } + // ??? Deprecate segcreate. + // -sectcreate puts whole files into a section in the output. + else if ( (strcmp(arg, "-sectcreate") == 0) || (strcmp(arg, "-segcreate") == 0) ) { + if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) ) + throw "-sectcreate missing
"; + addSection(argv[i+1], argv[i+2], argv[i+3]); + i += 3; + } + // Since we have a full path in binary/library names we need to be able to override it. + else if ( (strcmp(arg, "-dylib_install_name") == 0) + || (strcmp(arg, "-dylinker_install_name") == 0) + || (strcmp(arg, "-install_name") == 0)) { + fDylibInstallName = argv[++i]; + if ( fDylibInstallName == NULL ) + throw "-install_name missing "; + } + // Sets the base address of the output. + else if ( (strcmp(arg, "-seg1addr") == 0) || (strcmp(arg, "-image_base") == 0) ) { + const char* address = argv[++i]; + if ( address == NULL ) + throwf("%s missing
", arg); + fBaseAddress = parseAddress(address); + uint64_t temp = (fBaseAddress+4095) & (-4096); // page align + if ( fBaseAddress != temp ) { + warning("-seg1addr not page aligned, rounding up"); + fBaseAddress = temp; + } + } + else if ( strcmp(arg, "-e") == 0 ) { + fEntryName = argv[++i]; + } + // Same as -@ from the FSF linker. + else if ( strcmp(arg, "-filelist") == 0 ) { + const char* path = argv[++i]; + if ( (path == NULL) || (path[0] == '-') ) + throw "-filelist missing "; + loadFileList(path); + } + else if ( strcmp(arg, "-keep_private_externs") == 0 ) { + fKeepPrivateExterns = true; + } + else if ( strcmp(arg, "-final_output") == 0 ) { + fFinalName = argv[++i]; + } + // Ensure that all calls to exported symbols go through lazy pointers. Multi-module + // just ensures that this happens for cross object file boundaries. + else if ( (strcmp(arg, "-interposable") == 0) || (strcmp(arg, "-multi_module") == 0)) { + switch ( fInterposeMode ) { + case kInterposeNone: + case kInterposeAllExternal: + fInterposeMode = kInterposeAllExternal; + break; + case kInterposeSome: + // do nothing, -interposable_list overrides -interposable" + break; + } + } + else if ( strcmp(arg, "-interposable_list") == 0 ) { + fInterposeMode = kInterposeSome; + loadExportFile(argv[++i], "-interposable_list", fInterposeList); + } + // Default for -interposable/-multi_module/-single_module. + else if ( strcmp(arg, "-single_module") == 0 ) { + fInterposeMode = kInterposeNone; + } + else if ( strcmp(arg, "-exported_symbols_list") == 0 ) { + if ( fExportMode == kDontExportSome ) + throw "can't use -exported_symbols_list and -unexported_symbols_list"; + fExportMode = kExportSome; + loadExportFile(argv[++i], "-exported_symbols_list", fExportSymbols); + } + else if ( strcmp(arg, "-unexported_symbols_list") == 0 ) { + if ( fExportMode == kExportSome ) + throw "can't use -unexported_symbols_list and -exported_symbols_list"; + fExportMode = kDontExportSome; + loadExportFile(argv[++i], "-unexported_symbols_list", fDontExportSymbols); + } + else if ( strcmp(arg, "-exported_symbol") == 0 ) { + if ( fExportMode == kDontExportSome ) + throw "can't use -exported_symbol and -unexported_symbols"; + fExportMode = kExportSome; + fExportSymbols.insert(argv[++i]); + } + else if ( strcmp(arg, "-unexported_symbol") == 0 ) { + if ( fExportMode == kExportSome ) + throw "can't use -unexported_symbol and -exported_symbol"; + fExportMode = kDontExportSome; + fDontExportSymbols.insert(argv[++i]); + } + else if ( strcmp(arg, "-non_global_symbols_no_strip_list") == 0 ) { + if ( fLocalSymbolHandling == kLocalSymbolsSelectiveExclude ) + throw "can't use -non_global_symbols_no_strip_list and -non_global_symbols_strip_list"; + fLocalSymbolHandling = kLocalSymbolsSelectiveInclude; + loadExportFile(argv[++i], "-non_global_symbols_no_strip_list", fLocalSymbolsIncluded); + } + else if ( strcmp(arg, "-non_global_symbols_strip_list") == 0 ) { + if ( fLocalSymbolHandling == kLocalSymbolsSelectiveInclude ) + throw "can't use -non_global_symbols_no_strip_list and -non_global_symbols_strip_list"; + fLocalSymbolHandling = kLocalSymbolsSelectiveExclude; + loadExportFile(argv[++i], "-non_global_symbols_strip_list", fLocalSymbolsExcluded); + } + // ??? Deprecate + else if ( strcmp(arg, "-no_arch_warnings") == 0 ) { + fIgnoreOtherArchFiles = true; + } + else if ( strcmp(arg, "-force_cpusubtype_ALL") == 0 ) { + fForceSubtypeAll = true; + } + // Similar to -weak-l but uses the absolute path name to the library. + else if ( strcmp(arg, "-weak_library") == 0 ) { + FileInfo info = findFile(argv[++i]); + info.options.fWeakImport = true; + addLibrary(info); + } + else if ( strcmp(arg, "-lazy_library") == 0 ) { + FileInfo info = findFile(argv[++i]); + info.options.fLazyLoad = true; + addLibrary(info); + fUsingLazyDylibLinking = true; + } + else if ( strcmp(arg, "-framework") == 0 ) { + addLibrary(findFramework(argv[++i])); + } + else if ( strcmp(arg, "-weak_framework") == 0 ) { + FileInfo info = findFramework(argv[++i]); + info.options.fWeakImport = true; + addLibrary(info); + } + else if ( strcmp(arg, "-lazy_framework") == 0 ) { + FileInfo info = findFramework(argv[++i]); + info.options.fLazyLoad = true; + addLibrary(info); + fUsingLazyDylibLinking = true; + } + else if ( strcmp(arg, "-search_paths_first") == 0 ) { + // previously handled by buildSearchPaths() + } + else if ( strcmp(arg, "-undefined") == 0 ) { + setUndefinedTreatment(argv[++i]); + } + // Debugging output flag. + else if ( strcmp(arg, "-arch_multiple") == 0 ) { + fMessagesPrefixedWithArchitecture = true; + } + // Specify what to do with relocations in read only + // sections like .text. Could be errors, warnings, + // or suppressed. Currently we do nothing with the + // flag. + else if ( strcmp(arg, "-read_only_relocs") == 0 ) { + switch ( parseTreatment(argv[++i]) ) { + case kNULL: + case kInvalid: + throw "-read_only_relocs missing [ warning | error | suppress ]"; + case kWarning: + fWarnTextRelocs = true; + fAllowTextRelocs = true; + break; + case kSuppress: + fWarnTextRelocs = false; + fAllowTextRelocs = true; + break; + case kError: + fWarnTextRelocs = false; + fAllowTextRelocs = false; + break; + } + } + else if ( strcmp(arg, "-sect_diff_relocs") == 0 ) { + warnObsolete(arg); + ++i; + } + // Warn, error or make strong a mismatch between weak + // and non-weak references. + else if ( strcmp(arg, "-weak_reference_mismatches") == 0 ) { + setWeakReferenceMismatchTreatment(argv[++i]); + } + // For a deployment target of 10.3 and earlier ld64 will + // prebind an executable with 0s in all addresses that + // are prebound. This can then be fixed up by update_prebinding + // later. Prebinding is less useful on 10.4 and greater. + else if ( strcmp(arg, "-prebind") == 0 ) { + fPrebind = true; + } + else if ( strcmp(arg, "-noprebind") == 0 ) { + warnObsolete(arg); + fPrebind = false; + } + else if ( strcmp(arg, "-prebind_allow_overlap") == 0 ) { + warnObsolete(arg); + } + else if ( strcmp(arg, "-prebind_all_twolevel_modules") == 0 ) { + warnObsolete(arg); + } + else if ( strcmp(arg, "-noprebind_all_twolevel_modules") == 0 ) { + warnObsolete(arg); + } + else if ( strcmp(arg, "-nofixprebinding") == 0 ) { + warnObsolete(arg); + } + // This should probably be deprecated when we respect -L and -F + // when searching for libraries. + else if ( strcmp(arg, "-dylib_file") == 0 ) { + addDylibOverride(argv[++i]); + } + // What to expand @executable_path to if found in dependent dylibs + else if ( strcmp(arg, "-executable_path") == 0 ) { + fExecutablePath = argv[++i]; + if ( (fExecutablePath == NULL) || (fExecutablePath[0] == '-') ) + throw "-executable_path missing "; + // if a directory was passed, add / to end + // ld64 can't find @executable _path relative dylibs from our umbrella frameworks + struct stat statBuffer; + if ( stat(fExecutablePath, &statBuffer) == 0 ) { + if ( (statBuffer.st_mode & S_IFMT) == S_IFDIR ) { + char* pathWithSlash = new char[strlen(fExecutablePath)+2]; + strcpy(pathWithSlash, fExecutablePath); + strcat(pathWithSlash, "/"); + fExecutablePath = pathWithSlash; + } + } + } + // Aligns all segments to the power of 2 boundary specified. + else if ( strcmp(arg, "-segalign") == 0 ) { + warnObsolete(arg); + ++i; + } + // Puts a specified segment at a particular address that must + // be a multiple of the segment alignment. + else if ( strcmp(arg, "-segaddr") == 0 ) { + SegmentStart seg; + seg.name = argv[++i]; + if ( (seg.name == NULL) || (argv[i+1] == NULL) ) + throw "-segaddr missing segName Adddress"; + seg.address = parseAddress(argv[++i]); + uint64_t temp = seg.address & (-4096); // page align + if ( (seg.address != temp) ) + warning("-segaddr %s not page aligned, rounding down", seg.name); + fCustomSegmentAddresses.push_back(seg); + } + // ??? Deprecate when we deprecate split-seg. + else if ( strcmp(arg, "-segs_read_only_addr") == 0 ) { + fBaseAddress = parseAddress(argv[++i]); + } + // ??? Deprecate when we deprecate split-seg. + else if ( strcmp(arg, "-segs_read_write_addr") == 0 ) { + fBaseWritableAddress = parseAddress(argv[++i]); + fSplitSegs = true; + } + // ??? Deprecate when we get rid of basing at build time. + else if ( strcmp(arg, "-seg_addr_table") == 0 ) { + const char* name = argv[++i]; + if ( name == NULL ) + throw "-seg_addr_table missing argument"; + fSegAddrTablePath = name; + } + else if ( strcmp(arg, "-seg_addr_table_filename") == 0 ) { + warnObsolete(arg); + ++i; + } + else if ( strcmp(arg, "-segprot") == 0 ) { + SegmentProtect seg; + seg.name = argv[++i]; + if ( (seg.name == NULL) || (argv[i+1] == NULL) || (argv[i+2] == NULL) ) + throw "-segprot missing segName max-prot init-prot"; + seg.max = parseProtection(argv[++i]); + seg.init = parseProtection(argv[++i]); + fCustomSegmentProtections.push_back(seg); + } + else if ( strcmp(arg, "-pagezero_size") == 0 ) { + const char* size = argv[++i]; + if ( size == NULL ) + throw "-pagezero_size missing "; + fZeroPageSize = parseAddress(size); + uint64_t temp = fZeroPageSize & (-4096); // page align + if ( (fZeroPageSize != temp) ) + warning("-pagezero_size not page aligned, rounding down"); + fZeroPageSize = temp; + } + else if ( strcmp(arg, "-stack_addr") == 0 ) { + const char* address = argv[++i]; + if ( address == NULL ) + throw "-stack_addr missing
"; + fStackAddr = parseAddress(address); + } + else if ( strcmp(arg, "-stack_size") == 0 ) { + const char* size = argv[++i]; + if ( size == NULL ) + throw "-stack_size missing
"; + fStackSize = parseAddress(size); + uint64_t temp = fStackSize & (-4096); // page align + if ( (fStackSize != temp) ) + warning("-stack_size not page aligned, rounding down"); + } + else if ( strcmp(arg, "-allow_stack_execute") == 0 ) { + fExecutableStack = true; + } + else if ( strcmp(arg, "-sectalign") == 0 ) { + if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) ) + throw "-sectalign missing
"; + addSectionAlignment(argv[i+1], argv[i+2], argv[i+3]); + i += 3; + } + else if ( strcmp(arg, "-sectorder_detail") == 0 ) { + warnObsolete(arg); + } + else if ( strcmp(arg, "-sectobjectsymbols") == 0 ) { + warnObsolete(arg); + i += 2; + } + else if ( strcmp(arg, "-bundle_loader") == 0 ) { + fBundleLoader = argv[++i]; + if ( (fBundleLoader == NULL) || (fBundleLoader[0] == '-') ) + throw "-bundle_loader missing "; + FileInfo info = findFile(fBundleLoader); + info.options.fBundleLoader = true; + fInputFiles.push_back(info); + } + else if ( strcmp(arg, "-private_bundle") == 0 ) { + warnObsolete(arg); + } + else if ( strcmp(arg, "-twolevel_namespace_hints") == 0 ) { + // FIX FIX + } + // Use this flag to set default behavior for deployement targets. + else if ( strcmp(arg, "-macosx_version_min") == 0 ) { + setMacOSXVersionMin(argv[++i]); + } + else if ( (strcmp(arg, "-aspen_version_min") == 0) || (strcmp(arg, "-iphone_version_min") == 0) || (strcmp(arg, "-iphoneos_version_min") == 0) ) { + setIPhoneVersionMin(argv[++i]); + } + else if ( strcmp(arg, "-multiply_defined") == 0 ) { + //warnObsolete(arg); + ++i; + } + else if ( strcmp(arg, "-multiply_defined_unused") == 0 ) { + warnObsolete(arg); + ++i; + } + else if ( strcmp(arg, "-nomultidefs") == 0 ) { + warnObsolete(arg); + } + // Display each file in which the argument symbol appears and whether + // the file defines or references it. This option takes an argument + // as -y note that there is no space. + else if ( strncmp(arg, "-y", 2) == 0 ) { + warnObsolete("-y"); + } + // Same output as -y, but output number of undefined symbols only. + else if ( strcmp(arg, "-Y") == 0 ) { + //warnObsolete(arg); + ++i; + } + // This option affects all objects linked into the final result. + else if ( strcmp(arg, "-m") == 0 ) { + warnObsolete(arg); + } + else if ( (strcmp(arg, "-why_load") == 0) || (strcmp(arg, "-whyload") == 0) ) { + fReaderOptions.fWhyLoad = true; + } + else if ( strcmp(arg, "-why_live") == 0 ) { + const char* name = argv[++i]; + if ( name == NULL ) + throw "-why_live missing symbol name argument"; + fWhyLive.insert(name); + } + else if ( strcmp(arg, "-u") == 0 ) { + const char* name = argv[++i]; + if ( name == NULL ) + throw "-u missing argument"; + fInitialUndefines.push_back(name); + } + else if ( strcmp(arg, "-U") == 0 ) { + const char* name = argv[++i]; + if ( name == NULL ) + throw "-U missing argument"; + fAllowedUndefined.insert(name); + } + else if ( strcmp(arg, "-s") == 0 ) { + warnObsolete(arg); + fLocalSymbolHandling = kLocalSymbolsNone; + fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoNone; + } + else if ( strcmp(arg, "-x") == 0 ) { + fLocalSymbolHandling = kLocalSymbolsNone; + } + else if ( strcmp(arg, "-S") == 0 ) { + fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoNone; + } + else if ( strcmp(arg, "-X") == 0 ) { + warnObsolete(arg); + } + else if ( strcmp(arg, "-Si") == 0 ) { + warnObsolete(arg); + fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoFull; + } + else if ( strcmp(arg, "-b") == 0 ) { + warnObsolete(arg); + } + else if ( strcmp(arg, "-Sn") == 0 ) { + warnObsolete(arg); + fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoFull; + } + else if ( strcmp(arg, "-Sp") == 0 ) { + warnObsolete(arg); + } + else if ( strcmp(arg, "-dead_strip") == 0 ) { + fDeadStrip = kDeadStripOnPlusUnusedInits; + } + else if ( strcmp(arg, "-no_dead_strip_inits_and_terms") == 0 ) { + fDeadStrip = kDeadStripOn; + } + else if ( strcmp(arg, "-w") == 0 ) { + // previously handled by buildSearchPaths() + } + else if ( strcmp(arg, "-arch_errors_fatal") == 0 ) { + // FIX FIX + } + else if ( strcmp(arg, "-M") == 0 ) { + // FIX FIX + } + else if ( strcmp(arg, "-headerpad") == 0 ) { + const char* size = argv[++i]; + if ( size == NULL ) + throw "-headerpad missing argument"; + fMinimumHeaderPad = parseAddress(size); + } + else if ( strcmp(arg, "-headerpad_max_install_names") == 0 ) { + fMaxMinimumHeaderPad = true; + } + else if ( strcmp(arg, "-t") == 0 ) { + fReaderOptions.fLogAllFiles = true; + } + else if ( strcmp(arg, "-whatsloaded") == 0 ) { + fReaderOptions.fLogObjectFiles = true; + } + else if ( strcmp(arg, "-A") == 0 ) { + warnObsolete(arg); + ++i; + } + else if ( strcmp(arg, "-umbrella") == 0 ) { + const char* name = argv[++i]; + if ( name == NULL ) + throw "-umbrella missing argument"; + fUmbrellaName = name; + } + else if ( strcmp(arg, "-allowable_client") == 0 ) { + const char* name = argv[++i]; + + if ( name == NULL ) + throw "-allowable_client missing argument"; + + fAllowableClients.push_back(name); + } + else if ( strcmp(arg, "-client_name") == 0 ) { + const char* name = argv[++i]; + + if ( name == NULL ) + throw "-client_name missing argument"; + + fClientName = name; + } + else if ( strcmp(arg, "-sub_umbrella") == 0 ) { + const char* name = argv[++i]; + if ( name == NULL ) + throw "-sub_umbrella missing argument"; + fSubUmbellas.push_back(name); + } + else if ( strcmp(arg, "-sub_library") == 0 ) { + const char* name = argv[++i]; + if ( name == NULL ) + throw "-sub_library missing argument"; + fSubLibraries.push_back(name); + } + else if ( strcmp(arg, "-init") == 0 ) { + const char* name = argv[++i]; + if ( name == NULL ) + throw "-init missing argument"; + fInitFunctionName = name; + } + else if ( strcmp(arg, "-dot") == 0 ) { + const char* name = argv[++i]; + if ( name == NULL ) + throw "-dot missing argument"; + fDotOutputFile = name; + } + else if ( strcmp(arg, "-warn_commons") == 0 ) { + fWarnCommons = true; + } + else if ( strcmp(arg, "-commons") == 0 ) { + fCommonsMode = parseCommonsTreatment(argv[++i]); + } + else if ( strcmp(arg, "-keep_relocs") == 0 ) { + fKeepRelocations = true; + } + else if ( strcmp(arg, "-warn_stabs") == 0 ) { + fWarnStabs = true; + } + else if ( strcmp(arg, "-pause") == 0 ) { + fPause = true; + } + else if ( strcmp(arg, "-print_statistics") == 0 ) { + fStatistics = true; + } + else if ( strcmp(arg, "-d") == 0 ) { + fReaderOptions.fMakeTentativeDefinitionsReal = true; + } + else if ( strcmp(arg, "-v") == 0 ) { + // previously handled by buildSearchPaths() + } + else if ( strcmp(arg, "-Z") == 0 ) { + // previously handled by buildSearchPaths() + } + else if ( strcmp(arg, "-syslibroot") == 0 ) { + ++i; + // previously handled by buildSearchPaths() + } + else if ( strcmp(arg, "-no_uuid") == 0 ) { + fUUIDMode = kUUIDNone; + } + else if ( strcmp(arg, "-random_uuid") == 0 ) { + fUUIDMode = kUUIDRandom; + } + else if ( strcmp(arg, "-dtrace") == 0 ) { + const char* name = argv[++i]; + if ( name == NULL ) + throw "-dtrace missing argument"; + fDtraceScriptName = name; + } + else if ( strcmp(arg, "-root_safe") == 0 ) { + fReaderOptions.fRootSafe = true; + } + else if ( strcmp(arg, "-setuid_safe") == 0 ) { + fReaderOptions.fSetuidSafe = true; + } + else if ( strcmp(arg, "-alias") == 0 ) { + ObjectFile::ReaderOptions::AliasPair pair; + pair.realName = argv[++i]; + if ( pair.realName == NULL ) + throw "missing argument to -alias"; + pair.alias = argv[++i]; + if ( pair.alias == NULL ) + throw "missing argument to -alias"; + fReaderOptions.fAliases.push_back(pair); + } + else if ( strcmp(arg, "-alias_list") == 0 ) { + parseAliasFile(argv[++i]); + } + // put this last so that it does not interfer with other options starting with 'i' + else if ( strncmp(arg, "-i", 2) == 0 ) { + const char* colon = strchr(arg, ':'); + if ( colon == NULL ) + throwf("unknown option: %s", arg); + ObjectFile::ReaderOptions::AliasPair pair; + char* temp = new char[colon-arg]; + strlcpy(temp, &arg[2], colon-arg-1); + pair.realName = &colon[1]; + pair.alias = temp; + fReaderOptions.fAliases.push_back(pair); + } + else if ( strcmp(arg, "-save-temps") == 0 ) { + fSaveTempFiles = true; + } + else if ( strcmp(arg, "-rpath") == 0 ) { + const char* path = argv[++i]; + if ( path == NULL ) + throw "missing argument to -rpath"; + fRPaths.push_back(path); + } + else if ( strcmp(arg, "-read_only_stubs") == 0 ) { + fReadOnlyx86Stubs = true; + } + else if ( strcmp(arg, "-slow_stubs") == 0 ) { + fReaderOptions.fSlowx86Stubs = true; + } + else if ( strcmp(arg, "-map") == 0 ) { + fMapPath = argv[++i]; + if ( fMapPath == NULL ) + throw "missing argument to -map"; + } + else if ( strcmp(arg, "-pie") == 0 ) { + fPositionIndependentExecutable = true; + } + else if ( strncmp(arg, "-reexport-l", 11) == 0 ) { + FileInfo info = findLibrary(&arg[11], true); + info.options.fReExport = true; + addLibrary(info); + } + else if ( strcmp(arg, "-reexport_library") == 0 ) { + FileInfo info = findFile(argv[++i]); + info.options.fReExport = true; + addLibrary(info); + } + else if ( strcmp(arg, "-reexport_framework") == 0 ) { + FileInfo info = findFramework(argv[++i]); + info.options.fReExport = true; + addLibrary(info); + } + else if ( strcmp(arg, "-dead_strip_dylibs") == 0 ) { + fDeadStripDylibs = true; + } + else if ( strcmp(arg, "-no_implicit_dylibs") == 0 ) { + fReaderOptions.fImplicitlyLinkPublicDylibs = false; + } + else if ( strcmp(arg, "-new_linker") == 0 ) { + // ignore + } + else if ( strcmp(arg, "-no_encryption") == 0 ) { + fEncryptable = false; + } + else if ( strcmp(arg, "-mllvm") == 0 ) { + const char* opts = argv[++i]; + if ( opts == NULL ) + throw "missing argument to -mllvm"; + fLLVMOptions.push_back(opts); + } + else { + throwf("unknown option: %s", arg); + } + } + else { + FileInfo info = findFile(arg); + if ( strcmp(&info.path[strlen(info.path)-2], ".a") == 0 ) + addLibrary(info); + else + fInputFiles.push_back(info); + } + } + + // if a -lazy option was used, implicitly link in lazydylib1.o + if ( fUsingLazyDylibLinking ) { + addLibrary(findLibrary("lazydylib1.o")); + } +} + + + +// +// -syslibroot is used for SDK support. +// The rule is that all search paths (both explicit and default) are +// checked to see if they exist in the SDK. If so, that path is +// replaced with the sdk prefixed path. If not, that search path +// is used as is. If multiple -syslibroot options are specified +// their directory structures are logically overlayed and files +// from sdks specified earlier on the command line used before later ones. + +void Options::buildSearchPaths(int argc, const char* argv[]) +{ + bool addStandardLibraryDirectories = true; + std::vector libraryPaths; + std::vector frameworkPaths; + libraryPaths.reserve(10); + frameworkPaths.reserve(10); + // scan through argv looking for -L, -F, -Z, and -syslibroot options + for(int i=0; i < argc; ++i) { + if ( (argv[i][0] == '-') && (argv[i][1] == 'L') ) + libraryPaths.push_back(&argv[i][2]); + else if ( (argv[i][0] == '-') && (argv[i][1] == 'F') ) + frameworkPaths.push_back(&argv[i][2]); + else if ( strcmp(argv[i], "-Z") == 0 ) + addStandardLibraryDirectories = false; + else if ( strcmp(argv[i], "-v") == 0 ) { + fVerbose = true; + extern const char ldVersionString[]; + fprintf(stderr, "%s", ldVersionString); + // if only -v specified, exit cleanly + if ( argc == 2 ) { +#if LTO_SUPPORT + printLTOVersion(*this); +#endif + exit(0); + } + } + else if ( strcmp(argv[i], "-syslibroot") == 0 ) { + const char* path = argv[++i]; + if ( path == NULL ) + throw "-syslibroot missing argument"; + fSDKPaths.push_back(path); + } + else if ( strcmp(argv[i], "-search_paths_first") == 0 ) { + // ??? Deprecate when we get -Bstatic/-Bdynamic. + fLibrarySearchMode = kSearchDylibAndArchiveInEachDir; + } + else if ( strcmp(argv[i], "-w") == 0 ) { + sEmitWarnings = false; + } + } + if ( addStandardLibraryDirectories ) { + libraryPaths.push_back("/usr/lib"); + libraryPaths.push_back("/usr/local/lib"); + + frameworkPaths.push_back("/Library/Frameworks/"); + frameworkPaths.push_back("/System/Library/Frameworks/"); + // remove /Network from default search path + //frameworkPaths.push_back("/Network/Library/Frameworks/"); + } + + // Support for configure based hacks + // if last -syslibroot is /, then ignore all syslibroots + if ( fSDKPaths.size() > 0 ) { + if ( strcmp(fSDKPaths.back(), "/") == 0 ) { + fSDKPaths.clear(); + } + } + + // now merge sdk and library paths to make real search paths + fLibrarySearchPaths.reserve(libraryPaths.size()*(fSDKPaths.size()+1)); + for (std::vector::iterator it = libraryPaths.begin(); it != libraryPaths.end(); it++) { + const char* libDir = *it; + bool sdkOverride = false; + if ( libDir[0] == '/' ) { + char betterLibDir[PATH_MAX]; + if ( strstr(libDir, "/..") != NULL ) { + if ( realpath(libDir, betterLibDir) != NULL ) + libDir = strdup(betterLibDir); + } + const int libDirLen = strlen(libDir); + for (std::vector::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) { + // ??? Should be using string here. + const char* sdkDir = *sdkit; + const int sdkDirLen = strlen(sdkDir); + char newPath[libDirLen + sdkDirLen+4]; + strcpy(newPath, sdkDir); + if ( newPath[sdkDirLen-1] == '/' ) + newPath[sdkDirLen-1] = '\0'; + strcat(newPath, libDir); + struct stat statBuffer; + if ( stat(newPath, &statBuffer) == 0 ) { + fLibrarySearchPaths.push_back(strdup(newPath)); + sdkOverride = true; + } + } + } + if ( !sdkOverride ) + fLibrarySearchPaths.push_back(libDir); + } + + // now merge sdk and framework paths to make real search paths + fFrameworkSearchPaths.reserve(frameworkPaths.size()*(fSDKPaths.size()+1)); + for (std::vector::iterator it = frameworkPaths.begin(); it != frameworkPaths.end(); it++) { + const char* frameworkDir = *it; + bool sdkOverride = false; + if ( frameworkDir[0] == '/' ) { + char betterFrameworkDir[PATH_MAX]; + if ( strstr(frameworkDir, "/..") != NULL ) { + if ( realpath(frameworkDir, betterFrameworkDir) != NULL ) + frameworkDir = strdup(betterFrameworkDir); + } + const int frameworkDirLen = strlen(frameworkDir); + for (std::vector::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) { + // ??? Should be using string here + const char* sdkDir = *sdkit; + const int sdkDirLen = strlen(sdkDir); + char newPath[frameworkDirLen + sdkDirLen+4]; + strcpy(newPath, sdkDir); + if ( newPath[sdkDirLen-1] == '/' ) + newPath[sdkDirLen-1] = '\0'; + strcat(newPath, frameworkDir); + struct stat statBuffer; + if ( stat(newPath, &statBuffer) == 0 ) { + fFrameworkSearchPaths.push_back(strdup(newPath)); + sdkOverride = true; + } + } + } + if ( !sdkOverride ) + fFrameworkSearchPaths.push_back(frameworkDir); + } + + if ( fVerbose ) { + fprintf(stderr,"Library search paths:\n"); + for (std::vector::iterator it = fLibrarySearchPaths.begin(); + it != fLibrarySearchPaths.end(); + it++) + fprintf(stderr,"\t%s\n", *it); + fprintf(stderr,"Framework search paths:\n"); + for (std::vector::iterator it = fFrameworkSearchPaths.begin(); + it != fFrameworkSearchPaths.end(); + it++) + fprintf(stderr,"\t%s\n", *it); + } +} + +// this is run before the command line is parsed +void Options::parsePreCommandLineEnvironmentSettings() +{ + if ((getenv("LD_TRACE_ARCHIVES") != NULL) + || (getenv("RC_TRACE_ARCHIVES") != NULL)) + fReaderOptions.fTraceArchives = true; + + if ((getenv("LD_TRACE_DYLIBS") != NULL) + || (getenv("RC_TRACE_DYLIBS") != NULL)) { + fReaderOptions.fTraceDylibs = true; + fReaderOptions.fTraceIndirectDylibs = true; + } + + if (getenv("RC_TRACE_DYLIB_SEARCHING") != NULL) { + fTraceDylibSearching = true; + } + + if (getenv("LD_PRINT_OPTIONS") != NULL) + fPrintOptions = true; + + if (fReaderOptions.fTraceDylibs || fReaderOptions.fTraceArchives) + fReaderOptions.fTraceOutputFile = getenv("LD_TRACE_FILE"); + + if (getenv("LD_PRINT_ORDER_FILE_STATISTICS") != NULL) + fPrintOrderFileStatistics = true; + + if (getenv("LD_SPLITSEGS_NEW_LIBRARIES") != NULL) + fSplitSegs = true; + + if (getenv("LD_NO_ENCRYPT") != NULL) + fEncryptable = false; + + sWarningsSideFilePath = getenv("LD_WARN_FILE"); +} + + +// this is run after the command line is parsed +void Options::parsePostCommandLineEnvironmentSettings() +{ + // when building a dynamic main executable, default any use of @executable_path to output path + if ( fExecutablePath == NULL && (fOutputKind == kDynamicExecutable) ) { + fExecutablePath = fOutputFile; + } + + // allow build system to set default seg_addr_table + if ( fSegAddrTablePath == NULL ) + fSegAddrTablePath = getenv("LD_SEG_ADDR_TABLE"); + + // allow build system to turn on prebinding + if ( !fPrebind ) { + fPrebind = ( getenv("LD_PREBIND") != NULL ); + } + + // allow build system to force on dead-code-stripping + if ( fDeadStrip == kDeadStripOff ) { + if ( getenv("LD_DEAD_STRIP") != NULL ) { + switch (fOutputKind) { + case Options::kDynamicLibrary: + case Options::kDynamicExecutable: + case Options::kDynamicBundle: + fDeadStrip = kDeadStripOn; + break; + case Options::kObjectFile: + case Options::kDyld: + case Options::kStaticExecutable: + break; + } + } + } + + // allow build system to force on -warn_commons + if ( getenv("LD_WARN_COMMONS") != NULL ) + fWarnCommons = true; +} + +void Options::reconfigureDefaults() +{ + // sync reader options + switch ( fOutputKind ) { + case Options::kObjectFile: + fReaderOptions.fForFinalLinkedImage = false; + break; + case Options::kDyld: + fReaderOptions.fForDyld = true; + fReaderOptions.fForFinalLinkedImage = true; + break; + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + fReaderOptions.fForFinalLinkedImage = true; + break; + case Options::kDynamicExecutable: + case Options::kStaticExecutable: + fReaderOptions.fLinkingMainExecutable = true; + fReaderOptions.fForFinalLinkedImage = true; + break; + } + + // set default min OS version + if ( fReaderOptions.fVersionMin == ObjectFile::ReaderOptions::kMinUnset ) { + // if -macosx_version_min not used, try environment variable + const char* envVers = getenv("MACOSX_DEPLOYMENT_TARGET"); + if ( envVers != NULL ) + setMacOSXVersionMin(envVers); + // if -macosx_version_min and environment variable not used assume current OS version + if ( fReaderOptions.fVersionMin == ObjectFile::ReaderOptions::kMinUnset ) + fReaderOptions.fVersionMin = ObjectFile::ReaderOptions::k10_5; // FIX FIX, this really should be a check of the OS version the linker is running on + } + + // adjust min based on architecture + switch ( fArchitecture ) { + case CPU_TYPE_I386: + if ( fReaderOptions.fVersionMin < ObjectFile::ReaderOptions::k10_4 ) { + //warning("-macosx_version_min should be 10.4 or later for i386"); + fReaderOptions.fVersionMin = ObjectFile::ReaderOptions::k10_4; + } + break; + case CPU_TYPE_POWERPC64: + if ( fReaderOptions.fVersionMin < ObjectFile::ReaderOptions::k10_4 ) { + //warning("-macosx_version_min should be 10.4 or later for ppc64"); + fReaderOptions.fVersionMin = ObjectFile::ReaderOptions::k10_4; + } + break; + case CPU_TYPE_X86_64: + if ( fReaderOptions.fVersionMin < ObjectFile::ReaderOptions::k10_4 ) { + //warning("-macosx_version_min should be 10.4 or later for x86_64"); + fReaderOptions.fVersionMin = ObjectFile::ReaderOptions::k10_4; + } + break; + } + + // disable implicit dylibs when targetting 10.3 + // add option to disable implicit load commands for indirectly used public dylibs + if ( fReaderOptions.fVersionMin <= ObjectFile::ReaderOptions::k10_3 ) + fReaderOptions.fImplicitlyLinkPublicDylibs = false; + + + // determine if info for shared region should be added + if ( fOutputKind == Options::kDynamicLibrary ) { + if ( fReaderOptions.fVersionMin >= ObjectFile::ReaderOptions::k10_5 ) + if ( fArchitecture != CPU_TYPE_ARM ) + fSharedRegionEligible = true; + } + + // allow build system to force linker to ignore seg_addr_table + if ( getenv("LD_FORCE_NO_SEG_ADDR_TABLE") != NULL ) + fSegAddrTablePath = NULL; + + // check for base address specified externally + if ( (fSegAddrTablePath != NULL) && (fOutputKind == Options::kDynamicLibrary) ) { + parseSegAddrTable(fSegAddrTablePath, this->installPath()); + // HACK to support seg_addr_table entries that are physical paths instead of install paths + if ( fBaseAddress == 0 ) { + if ( strcmp(this->installPath(), "/usr/lib/libstdc++.6.dylib") == 0 ) + parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libstdc++.6.0.4.dylib"); + + else if ( strcmp(this->installPath(), "/usr/lib/libz.1.dylib") == 0 ) + parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libz.1.2.3.dylib"); + + else if ( strcmp(this->installPath(), "/usr/lib/libutil.dylib") == 0 ) + parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libutil1.0.dylib"); + } + } + + // split segs only allowed for dylibs + if ( fSplitSegs ) { + // split seg only supported for ppc, i386, and arm. + switch ( fArchitecture ) { + case CPU_TYPE_POWERPC: + case CPU_TYPE_I386: + if ( fOutputKind != Options::kDynamicLibrary ) + fSplitSegs = false; + // make sure read and write segments are proper distance apart + if ( fSplitSegs && (fBaseWritableAddress-fBaseAddress != 0x10000000) ) + fBaseWritableAddress = fBaseAddress + 0x10000000; + break; + case CPU_TYPE_ARM: + if ( fOutputKind != Options::kDynamicLibrary ) { + fSplitSegs = false; + } + else { + // make sure read and write segments are proper distance apart + if ( fSplitSegs && (fBaseWritableAddress-fBaseAddress != 0x08000000) ) + fBaseWritableAddress = fBaseAddress + 0x08000000; + } + break; + default: + fSplitSegs = false; + fBaseAddress = 0; + fBaseWritableAddress = 0; + } + } + + // disable prebinding depending on arch and min OS version + if ( fPrebind ) { + switch ( fArchitecture ) { + case CPU_TYPE_POWERPC: + case CPU_TYPE_I386: + if ( fReaderOptions.fVersionMin == ObjectFile::ReaderOptions::k10_4 ) { + // in 10.4 only split seg dylibs are prebound + if ( (fOutputKind != Options::kDynamicLibrary) || ! fSplitSegs ) + fPrebind = false; + } + else if ( fReaderOptions.fVersionMin >= ObjectFile::ReaderOptions::k10_5 ) { + // in 10.5 nothing is prebound + fPrebind = false; + } + else { + // in 10.3 and earlier only dylibs and main executables could be prebound + switch ( fOutputKind ) { + case Options::kDynamicExecutable: + case Options::kDynamicLibrary: + // only main executables and dylibs can be prebound + break; + case Options::kStaticExecutable: + case Options::kDynamicBundle: + case Options::kObjectFile: + case Options::kDyld: + // disable prebinding for everything else + fPrebind = false; + break; + } + } + break; + case CPU_TYPE_POWERPC64: + case CPU_TYPE_X86_64: + fPrebind = false; + break; + case CPU_TYPE_ARM: + switch ( fOutputKind ) { + case Options::kDynamicExecutable: + case Options::kDynamicLibrary: + // only main executables and dylibs can be prebound + break; + case Options::kStaticExecutable: + case Options::kDynamicBundle: + case Options::kObjectFile: + case Options::kDyld: + // disable prebinding for everything else + fPrebind = false; + break; + } + break; + } + } + + // only prebound images can be split-seg + if ( fSplitSegs && !fPrebind ) + fSplitSegs = false; + + // figure out if module table is needed for compatibility with old ld/dyld + if ( fOutputKind == Options::kDynamicLibrary ) { + switch ( fArchitecture ) { + 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 ( fReaderOptions.fVersionMin <= ObjectFile::ReaderOptions::k10_5 ) + fNeedsModuleTable = true; + break; + case CPU_TYPE_ARM: + fNeedsModuleTable = true; // redo_prebinding requires a module table + break; + } + } + + // -r -x implies -S + if ( (fOutputKind == Options::kObjectFile) && (fLocalSymbolHandling == kLocalSymbolsNone) ) + fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoNone; + + // only ARM main executables can be encrypted + if ( fOutputKind != Options::kDynamicExecutable ) + fEncryptable = false; + if ( fArchitecture != CPU_TYPE_ARM ) + fEncryptable = false; +} + +void Options::checkIllegalOptionCombinations() +{ + // check -undefined setting + switch ( fUndefinedTreatment ) { + case kUndefinedError: + case kUndefinedDynamicLookup: + // always legal + break; + case kUndefinedWarning: + case kUndefinedSuppress: + // requires flat namespace + if ( fNameSpace == kTwoLevelNameSpace ) + throw "can't use -undefined warning or suppress with -twolevel_namespace"; + break; + } + + // unify -sub_umbrella with dylibs + for (std::vector::iterator it = fSubUmbellas.begin(); it != fSubUmbellas.end(); it++) { + const char* subUmbrella = *it; + bool found = false; + for (std::vector::iterator fit = fInputFiles.begin(); fit != fInputFiles.end(); fit++) { + Options::FileInfo& info = *fit; + const char* lastSlash = strrchr(info.path, '/'); + if ( lastSlash == NULL ) + lastSlash = info.path - 1; + if ( strcmp(&lastSlash[1], subUmbrella) == 0 ) { + info.options.fReExport = true; + found = true; + break; + } + } + if ( ! found ) + warning("-sub_umbrella %s does not match a supplied dylib", subUmbrella); + } + + // unify -sub_library with dylibs + for (std::vector::iterator it = fSubLibraries.begin(); it != fSubLibraries.end(); it++) { + const char* subLibrary = *it; + bool found = false; + for (std::vector::iterator fit = fInputFiles.begin(); fit != fInputFiles.end(); fit++) { + Options::FileInfo& info = *fit; + const char* lastSlash = strrchr(info.path, '/'); + if ( lastSlash == NULL ) + lastSlash = info.path - 1; + const char* dot = strchr(&lastSlash[1], '.'); + if ( dot == NULL ) + dot = &lastSlash[strlen(lastSlash)]; + if ( strncmp(&lastSlash[1], subLibrary, dot-lastSlash-1) == 0 ) { + info.options.fReExport = true; + found = true; + break; + } + } + if ( ! found ) + warning("-sub_library %s does not match a supplied dylib", subLibrary); + } + + // sync reader options + if ( fNameSpace != kTwoLevelNameSpace ) + fReaderOptions.fFlatNamespace = true; + + // check -stack_addr + if ( fStackAddr != 0 ) { + switch (fArchitecture) { + case CPU_TYPE_I386: + case CPU_TYPE_POWERPC: + case CPU_TYPE_ARM: + if ( fStackAddr > 0xFFFFFFFF ) + throw "-stack_addr must be < 4G for 32-bit processes"; + break; + case CPU_TYPE_POWERPC64: + case CPU_TYPE_X86_64: + break; + } + if ( (fStackAddr & -4096) != fStackAddr ) + throw "-stack_addr must be multiples of 4K"; + if ( fStackSize == 0 ) + throw "-stack_addr must be used with -stack_size"; + } + + // check -stack_size + if ( fStackSize != 0 ) { + switch (fArchitecture) { + case CPU_TYPE_I386: + case CPU_TYPE_POWERPC: + if ( fStackSize > 0xFFFFFFFF ) + throw "-stack_size must be < 4G for 32-bit processes"; + if ( fStackAddr == 0 ) { + fStackAddr = 0xC0000000; + } + if ( (fStackAddr > 0xB0000000) && ((fStackAddr-fStackSize) < 0xB0000000) ) + warning("custom stack placement overlaps and will disable shared region"); + break; + case CPU_TYPE_ARM: + if ( fStackSize > 0xFFFFFFFF ) + throw "-stack_size must be < 4G for 32-bit processes"; + if ( fStackAddr == 0 ) + fStackAddr = 0x30000000; + if ( fStackAddr > 0x40000000) + throw "-stack_addr must be < 1G for arm"; + case CPU_TYPE_POWERPC64: + case CPU_TYPE_X86_64: + if ( fStackAddr == 0 ) { + fStackAddr = 0x00007FFF5C000000LL; + } + break; + } + if ( (fStackSize & -4096) != fStackSize ) + throw "-stack_size must be multiples of 4K"; + switch ( fOutputKind ) { + case Options::kDynamicExecutable: + case Options::kStaticExecutable: + // custom stack size only legal when building main executable + break; + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kObjectFile: + case Options::kDyld: + throw "-stack_size option can only be used when linking a main executable"; + } + } + + // check that -allow_stack_execute is only used with main executables + if ( fExecutableStack ) { + switch ( fOutputKind ) { + case Options::kDynamicExecutable: + case Options::kStaticExecutable: + // -allow_stack_execute size only legal when building main executable + break; + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kObjectFile: + case Options::kDyld: + throw "-allow_stack_execute option can only be used when linking a main executable"; + } + } + + // check -client_name is only used when making a bundle or main executable + if ( fClientName != NULL ) { + switch ( fOutputKind ) { + case Options::kDynamicExecutable: + case Options::kDynamicBundle: + break; + case Options::kStaticExecutable: + case Options::kDynamicLibrary: + case Options::kObjectFile: + case Options::kDyld: + throw "-client_name can only be used with -bundle"; + } + } + + // check -init is only used when building a dylib + if ( (fInitFunctionName != NULL) && (fOutputKind != Options::kDynamicLibrary) ) + throw "-init can only be used with -dynamiclib"; + + // check -bundle_loader only used with -bundle + if ( (fBundleLoader != NULL) && (fOutputKind != Options::kDynamicBundle) ) + throw "-bundle_loader can only be used with -bundle"; + + // check -dtrace not used with -r + if ( (fDtraceScriptName != NULL) && (fOutputKind == Options::kObjectFile) ) + throw "-dtrace can only be used when creating final linked images"; + + // check -d can only be used with -r + if ( fReaderOptions.fMakeTentativeDefinitionsReal && (fOutputKind != Options::kObjectFile) ) + throw "-d can only be used with -r"; + + // check that -root_safe is not used with -r + if ( fReaderOptions.fRootSafe && (fOutputKind == Options::kObjectFile) ) + throw "-root_safe cannot be used with -r"; + + // check that -setuid_safe is not used with -r + if ( fReaderOptions.fSetuidSafe && (fOutputKind == Options::kObjectFile) ) + throw "-setuid_safe cannot be used with -r"; + + // make sure all required exported symbols exist + std::vector impliedExports; + for (NameSet::iterator it=fExportSymbols.regularBegin(); it != fExportSymbols.regularEnd(); it++) { + const char* name = *it; + // never export .eh symbols + const int len = strlen(name); + if ( (strcmp(&name[len-3], ".eh") == 0) || (strncmp(name, ".objc_category_name_", 20) == 0) ) + warning("ignoring %s in export list", name); + else + fInitialUndefines.push_back(name); + if ( strncmp(name, ".objc_class_name_", 17) == 0 ) { + // rdar://problem/4718189 map ObjC class names to new runtime names + switch (fArchitecture) { + case CPU_TYPE_POWERPC64: + case CPU_TYPE_X86_64: + case CPU_TYPE_ARM: + char* temp; + asprintf(&temp, "_OBJC_CLASS_$_%s", &name[17]); + impliedExports.push_back(temp); + asprintf(&temp, "_OBJC_METACLASS_$_%s", &name[17]); + impliedExports.push_back(temp); + break; + } + } + } + for (std::vector::iterator it=impliedExports.begin(); it != impliedExports.end(); it++) { + const char* name = *it; + fExportSymbols.insert(name); + fInitialUndefines.push_back(name); + } + + // make sure that -init symbol exist + if ( fInitFunctionName != NULL ) + fInitialUndefines.push_back(fInitFunctionName); + + // check custom segments + if ( fCustomSegmentAddresses.size() != 0 ) { + // verify no segment is in zero page + if ( fZeroPageSize != ULLONG_MAX ) { + for (std::vector::iterator it = fCustomSegmentAddresses.begin(); it != fCustomSegmentAddresses.end(); ++it) { + if ( (it->address >= 0) && (it->address < fZeroPageSize) ) + throwf("-segaddr %s 0x%X conflicts with -pagezero_size", it->name, it->address); + } + } + // verify no duplicates + for (std::vector::iterator it = fCustomSegmentAddresses.begin(); it != fCustomSegmentAddresses.end(); ++it) { + for (std::vector::iterator it2 = fCustomSegmentAddresses.begin(); it2 != fCustomSegmentAddresses.end(); ++it2) { + if ( (it->address == it2->address) && (it != it2) ) + throwf("duplicate -segaddr addresses for %s and %s", it->name, it2->name); + } + // a custom segment address of zero will disable the use of a zero page + if ( it->address == 0 ) + fZeroPageSize = 0; + } + } + + if ( fZeroPageSize == ULLONG_MAX ) { + // zero page size not specified on command line, set default + switch (fArchitecture) { + case CPU_TYPE_I386: + case CPU_TYPE_POWERPC: + case CPU_TYPE_ARM: + // first 4KB for 32-bit architectures + fZeroPageSize = 0x1000; + break; + case CPU_TYPE_POWERPC64: + // first 4GB for ppc64 on 10.5 + if ( fReaderOptions.fVersionMin >= ObjectFile::ReaderOptions::k10_5 ) + fZeroPageSize = 0x100000000ULL; + else + fZeroPageSize = 0x1000; // 10.4 dyld may not be able to handle >4GB zero page + break; + case CPU_TYPE_X86_64: + // first 4GB for x86_64 on all OS's + fZeroPageSize = 0x100000000ULL; + break; + default: + // if -arch not used, default to 4K zero-page + fZeroPageSize = 0x1000; + } + } + else { + switch ( fOutputKind ) { + case Options::kDynamicExecutable: + case Options::kStaticExecutable: + // -pagezero_size size only legal when building main executable + break; + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kObjectFile: + case Options::kDyld: + if ( fZeroPageSize != 0 ) + throw "-pagezero_size option can only be used when linking a main executable"; + } + } + + // -dead_strip and -r are incompatible + if ( (fDeadStrip != kDeadStripOff) && (fOutputKind == Options::kObjectFile) ) + throw "-r and -dead_strip cannot be used together"; + + // can't use -rpath unless targeting 10.5 or later + if ( fRPaths.size() > 0 ) { + if ( fReaderOptions.fVersionMin < ObjectFile::ReaderOptions::k10_5 ) + throw "-rpath can only be used when targeting Mac OS X 10.5 or later"; + switch ( fOutputKind ) { + case Options::kDynamicExecutable: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + break; + case Options::kStaticExecutable: + case Options::kObjectFile: + case Options::kDyld: + throw "-rpath can only be used when creating a dynamic final linked image"; + } + } + + // check -pie is only used when building a dynamic main executable for 10.5 + if ( fPositionIndependentExecutable ) { + if ( fOutputKind != Options::kDynamicExecutable ) + throw "-pie can only be used when linking a main executable"; + if ( fReaderOptions.fVersionMin < ObjectFile::ReaderOptions::k10_5 ) + throw "-pie can only be used when targeting Mac OS X 10.5 or later"; + } +} + + + +void Options::checkForClassic(int argc, const char* argv[]) +{ + // scan options + bool archFound = false; + bool staticFound = false; + bool dtraceFound = false; + bool rFound = false; + bool creatingMachKernel = false; + bool newLinker = false; + + for(int i=0; i < argc; ++i) { + const char* arg = argv[i]; + if ( arg[0] == '-' ) { + if ( strcmp(arg, "-arch") == 0 ) { + parseArch(argv[++i]); + archFound = true; + } + else if ( strcmp(arg, "-static") == 0 ) { + staticFound = true; + } + else if ( strcmp(arg, "-dtrace") == 0 ) { + dtraceFound = true; + } + else if ( strcmp(arg, "-r") == 0 ) { + rFound = true; + } + else if ( strcmp(arg, "-new_linker") == 0 ) { + newLinker = true; + } + else if ( strcmp(arg, "-classic_linker") == 0 ) { + // ld_classic does not understand this option, so remove it + for(int j=i; j < argc; ++j) + argv[j] = argv[j+1]; + this->gotoClassicLinker(argc-1, argv); + } + else if ( strcmp(arg, "-o") == 0 ) { + const char* outfile = argv[++i]; + if ( (outfile != NULL) && (strstr(outfile, "/mach_kernel") != NULL) ) + creatingMachKernel = true; + } + } + } + + // -dtrace only supported by new linker + if( dtraceFound ) + return; + + if( archFound ) { + switch ( fArchitecture ) { + case CPU_TYPE_POWERPC: + case CPU_TYPE_I386: + case CPU_TYPE_ARM: +// if ( staticFound && (rFound || !creatingMachKernel) ) { + if ( staticFound && !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 -aspen_version_min, so change + for(int j=0; j < argc; ++j) { + if ( (strcmp(argv[j], "-aspen_version_min") == 0) + || (strcmp(argv[j], "-iphone_version_min") == 0) + || (strcmp(argv[j], "-iphoneos_version_min") == 0) ) { + argv[j] = "-macosx_version_min"; + if ( j < argc-1 ) + argv[j+1] = "10.5"; + break; + } + } + this->gotoClassicLinker(argc, argv); + } + } + break; + } + } + else { + // work around for VSPTool + if ( staticFound ) + this->gotoClassicLinker(argc, argv); + } + +} + +void Options::gotoClassicLinker(int argc, const char* argv[]) +{ + argv[0] = "ld_classic"; + execvp(argv[0], (char**)argv); + fprintf(stderr, "can't exec ld_classic\n"); + exit(1); +} diff --git a/FireOpal/src/Options.h b/FireOpal/src/Options.h new file mode 100644 index 0000000..4bbcffe --- /dev/null +++ b/FireOpal/src/Options.h @@ -0,0 +1,368 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2005-2007 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 __OPTIONS__ +#define __OPTIONS__ + + +#include +#include + +#include +#include + +#include "ObjectFile.h" + +extern void throwf (const char* format, ...) __attribute__ ((noreturn)); +extern void warning(const char* format, ...); + +class DynamicLibraryOptions +{ +public: + DynamicLibraryOptions() : fWeakImport(false), fReExport(false), fBundleLoader(false), fLazyLoad(false) {} + + bool fWeakImport; + bool fReExport; + bool fBundleLoader; + bool fLazyLoad; +}; + +// +// The public interface to the Options class is the abstract representation of what work the linker +// should do. +// +// This abstraction layer will make it easier to support a future where the linker is a shared library +// invoked directly from Xcode. The target settings in Xcode would be used to directly construct an Options +// object (without building a command line which is then parsed). +// +// +class Options +{ +public: + Options(int argc, const char* argv[]); + ~Options(); + + enum OutputKind { kDynamicExecutable, kStaticExecutable, kDynamicLibrary, kDynamicBundle, kObjectFile, kDyld }; + enum NameSpace { kTwoLevelNameSpace, kFlatNameSpace, kForceFlatNameSpace }; + // Standard treatment for many options. + enum Treatment { kError, kWarning, kSuppress, kNULL, kInvalid }; + enum UndefinedTreatment { kUndefinedError, kUndefinedWarning, kUndefinedSuppress, kUndefinedDynamicLookup }; + enum WeakReferenceMismatchTreatment { kWeakReferenceMismatchError, kWeakReferenceMismatchWeak, + kWeakReferenceMismatchNonWeak }; + enum CommonsMode { kCommonsIgnoreDylibs, kCommonsOverriddenByDylibs, kCommonsConflictsDylibsError }; + enum DeadStripMode { kDeadStripOff, kDeadStripOn, kDeadStripOnPlusUnusedInits }; + enum UUIDMode { kUUIDNone, kUUIDRandom, kUUIDContent }; + enum LocalSymbolHandling { kLocalSymbolsAll, kLocalSymbolsNone, kLocalSymbolsSelectiveInclude, kLocalSymbolsSelectiveExclude }; + + struct FileInfo { + const char* path; + uint64_t fileLen; + time_t modTime; + DynamicLibraryOptions options; + }; + + struct ExtraSection { + const char* segmentName; + const char* sectionName; + const char* path; + const uint8_t* data; + uint64_t dataLen; + }; + + struct SectionAlignment { + const char* segmentName; + const char* sectionName; + uint8_t alignment; + }; + + struct OrderedSymbol { + const char* symbolName; + const char* objectFileName; + }; + + struct SegmentStart { + const char* name; + uint64_t address; + }; + + struct SegmentProtect { + const char* name; + uint32_t max; + uint32_t init; + }; + + struct DylibOverride { + const char* installName; + const char* useInstead; + }; + + + const ObjectFile::ReaderOptions& readerOptions(); + const char* getOutputFilePath(); + std::vector& getInputFiles(); + + cpu_type_t architecture() { return fArchitecture; } + bool preferSubArchitecture() { return fHasPreferredSubType; } + cpu_subtype_t subArchitecture() { return fSubArchitecture; } + OutputKind outputKind(); + bool prebind(); + bool bindAtLoad(); + bool fullyLoadArchives(); + NameSpace nameSpace(); + const char* installPath(); // only for kDynamicLibrary + uint32_t currentVersion(); // only for kDynamicLibrary + uint32_t compatibilityVersion(); // only for kDynamicLibrary + const char* entryName(); // only for kDynamicExecutable or kStaticExecutable + const char* executablePath(); + uint64_t baseAddress(); + bool keepPrivateExterns(); // only for kObjectFile + bool needsModuleTable(); // only for kDynamicLibrary + bool interposable(const char* name); + bool hasExportRestrictList(); + bool hasExportMaskList(); + bool hasWildCardExportRestrictList(); + bool allGlobalsAreDeadStripRoots(); + bool shouldExport(const char*); + bool ignoreOtherArchInputFiles(); + bool forceCpuSubtypeAll(); + bool traceDylibs(); + bool traceArchives(); + DeadStripMode deadStrip(); + UndefinedTreatment undefinedTreatment(); + ObjectFile::ReaderOptions::VersionMin macosxVersionMin(); + bool messagesPrefixedWithArchitecture(); + Treatment picTreatment(); + WeakReferenceMismatchTreatment weakReferenceMismatchTreatment(); + const char* umbrellaName(); + std::vector& allowableClients(); + const char* clientName(); + const char* initFunctionName(); // only for kDynamicLibrary + const char* dotOutputFile(); + uint64_t zeroPageSize(); + bool hasCustomStack(); + uint64_t customStackSize(); + uint64_t customStackAddr(); + bool hasExecutableStack(); + std::vector& initialUndefines(); + bool printWhyLive(const char* name); + uint32_t minimumHeaderPad(); + bool maxMminimumHeaderPad() { return fMaxMinimumHeaderPad; } + std::vector& extraSections(); + std::vector& sectionAlignments(); + CommonsMode commonsMode(); + bool warnCommons(); + bool keepRelocations(); + FileInfo findFile(const char* path); + UUIDMode getUUIDMode() { return fUUIDMode; } + bool warnStabs(); + bool pauseAtEnd() { return fPause; } + bool printStatistics() { return fStatistics; } + bool printArchPrefix() { return fMessagesPrefixedWithArchitecture; } + void gotoClassicLinker(int argc, const char* argv[]); + bool sharedRegionEligible() { return fSharedRegionEligible; } + bool printOrderFileStatistics() { return fPrintOrderFileStatistics; } + const char* dTraceScriptName() { return fDtraceScriptName; } + bool dTrace() { return (fDtraceScriptName != NULL); } + std::vector& orderedSymbols() { return fOrderedSymbols; } + bool splitSeg() { return fSplitSegs; } + uint64_t baseWritableAddress() { return fBaseWritableAddress; } + std::vector& customSegmentAddresses() { return fCustomSegmentAddresses; } + std::vector& customSegmentProtections() { return fCustomSegmentProtections; } + bool saveTempFiles() { return fSaveTempFiles; } + const std::vector& rpaths() { return fRPaths; } + bool readOnlyx86Stubs() { return fReadOnlyx86Stubs; } + bool slowx86Stubs() { return fReaderOptions.fSlowx86Stubs; } + std::vector& dylibOverrides() { return fDylibOverrides; } + const char* generatedMapPath() { return fMapPath; } + bool positionIndependentExecutable() { return fPositionIndependentExecutable; } + Options::FileInfo findFileUsingPaths(const char* path); + bool deadStripDylibs() { return fDeadStripDylibs; } + bool allowedUndefined(const char* name) { return ( fAllowedUndefined.find(name) != fAllowedUndefined.end() ); } + bool someAllowedUndefines() { return (fAllowedUndefined.size() != 0); } + LocalSymbolHandling localSymbolHandling() { return fLocalSymbolHandling; } + bool keepLocalSymbol(const char* symbolName); + bool allowTextRelocs() { return fAllowTextRelocs; } + bool warnAboutTextRelocs() { return fWarnTextRelocs; } + bool usingLazyDylibLinking() { return fUsingLazyDylibLinking; } + bool verbose() { return fVerbose; } + bool makeEncryptable() { return fEncryptable; } + std::vector& llvmOptions() { return fLLVMOptions; } + +private: + class CStringEquals + { + public: + bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } + }; + + typedef __gnu_cxx::hash_set, CStringEquals> NameSet; + enum ExportMode { kExportDefault, kExportSome, kDontExportSome }; + enum LibrarySearchMode { kSearchDylibAndArchiveInEachDir, kSearchAllDirsForDylibsThenAllDirsForArchives }; + enum InterposeMode { kInterposeNone, kInterposeAllExternal, kInterposeSome }; + + class SetWithWildcards { + public: + void insert(const char*); + bool contains(const char*); + bool hasWildCards() { return !fWildCard.empty(); } + NameSet::iterator regularBegin() { return fRegular.begin(); } + NameSet::iterator regularEnd() { return fRegular.end(); } + private: + static bool hasWildCards(const char*); + bool wildCardMatch(const char* pattern, const char* candidate); + bool inCharRange(const char*& range, unsigned char c); + + NameSet fRegular; + std::vector fWildCard; + }; + + + void parse(int argc, const char* argv[]); + void checkIllegalOptionCombinations(); + void buildSearchPaths(int argc, const char* argv[]); + void parseArch(const char* architecture); + FileInfo findLibrary(const char* rootName, bool dylibsOnly=false); + FileInfo findFramework(const char* frameworkName); + FileInfo findFramework(const char* rootName, const char* suffix); + bool checkForFile(const char* format, const char* dir, const char* rootName, + FileInfo& result); + uint32_t parseVersionNumber(const char*); + void parseSectionOrderFile(const char* segment, const char* section, const char* path); + void parseOrderFile(const char* path, bool cstring); + void addSection(const char* segment, const char* section, const char* path); + void addSubLibrary(const char* name); + void loadFileList(const char* fileOfPaths); + uint64_t parseAddress(const char* addr); + void loadExportFile(const char* fileOfExports, const char* option, SetWithWildcards& set); + void parseAliasFile(const char* fileOfAliases); + void parsePreCommandLineEnvironmentSettings(); + void parsePostCommandLineEnvironmentSettings(); + void setUndefinedTreatment(const char* treatment); + void setMacOSXVersionMin(const char* version); + void setIPhoneVersionMin(const char* version); + void setWeakReferenceMismatchTreatment(const char* treatment); + void addDylibOverride(const char* paths); + void addSectionAlignment(const char* segment, const char* section, const char* alignment); + CommonsMode parseCommonsTreatment(const char* mode); + Treatment parseTreatment(const char* treatment); + void reconfigureDefaults(); + void checkForClassic(int argc, const char* argv[]); + void parseSegAddrTable(const char* segAddrPath, const char* installPath); + void addLibrary(const FileInfo& info); + void warnObsolete(const char* arg); + uint32_t parseProtection(const char* prot); + + + ObjectFile::ReaderOptions fReaderOptions; + const char* fOutputFile; + std::vector fInputFiles; + cpu_type_t fArchitecture; + cpu_subtype_t fSubArchitecture; + OutputKind fOutputKind; + bool fHasPreferredSubType; + bool fPrebind; + bool fBindAtLoad; + bool fKeepPrivateExterns; + bool fNeedsModuleTable; + bool fIgnoreOtherArchFiles; + bool fForceSubtypeAll; + InterposeMode fInterposeMode; + DeadStripMode fDeadStrip; + NameSpace fNameSpace; + uint32_t fDylibCompatVersion; + uint32_t fDylibCurrentVersion; + const char* fDylibInstallName; + const char* fFinalName; + const char* fEntryName; + uint64_t fBaseAddress; + uint64_t fBaseWritableAddress; + bool fSplitSegs; + SetWithWildcards fExportSymbols; + SetWithWildcards fDontExportSymbols; + SetWithWildcards fInterposeList; + ExportMode fExportMode; + LibrarySearchMode fLibrarySearchMode; + UndefinedTreatment fUndefinedTreatment; + bool fMessagesPrefixedWithArchitecture; + WeakReferenceMismatchTreatment fWeakReferenceMismatchTreatment; + std::vector fSubUmbellas; + std::vector fSubLibraries; + std::vector fAllowableClients; + std::vector fRPaths; + const char* fClientName; + const char* fUmbrellaName; + const char* fInitFunctionName; + const char* fDotOutputFile; + const char* fExecutablePath; + const char* fBundleLoader; + const char* fDtraceScriptName; + const char* fSegAddrTablePath; + const char* fMapPath; + uint64_t fZeroPageSize; + uint64_t fStackSize; + uint64_t fStackAddr; + bool fExecutableStack; + uint32_t fMinimumHeaderPad; + CommonsMode fCommonsMode; + UUIDMode fUUIDMode; + SetWithWildcards fLocalSymbolsIncluded; + SetWithWildcards fLocalSymbolsExcluded; + LocalSymbolHandling fLocalSymbolHandling; + bool fWarnCommons; + bool fVerbose; + bool fKeepRelocations; + bool fWarnStabs; + bool fTraceDylibSearching; + bool fPause; + bool fStatistics; + bool fPrintOptions; + bool fSharedRegionEligible; + bool fPrintOrderFileStatistics; + bool fReadOnlyx86Stubs; + bool fPositionIndependentExecutable; + bool fMaxMinimumHeaderPad; + bool fDeadStripDylibs; + bool fAllowTextRelocs; + bool fWarnTextRelocs; + bool fUsingLazyDylibLinking; + bool fEncryptable; + std::vector fInitialUndefines; + NameSet fAllowedUndefined; + NameSet fWhyLive; + std::vector fExtraSections; + std::vector fSectionAlignments; + std::vector fOrderedSymbols; + std::vector fCustomSegmentAddresses; + std::vector fCustomSegmentProtections; + std::vector fDylibOverrides; + std::vector fLLVMOptions; + std::vector fLibrarySearchPaths; + std::vector fFrameworkSearchPaths; + std::vector fSDKPaths; + bool fSaveTempFiles; +}; + + + +#endif // __OPTIONS__ diff --git a/FireOpal/src/SectCreate.h b/FireOpal/src/SectCreate.h new file mode 100644 index 0000000..d5c7f4e --- /dev/null +++ b/FireOpal/src/SectCreate.h @@ -0,0 +1,43 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * 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@ + */ + + +#ifndef __SECTCREATE__ +#define __SECTCREATE__ + + +#include "ObjectFile.h" + +namespace SectCreate { + + extern ObjectFile::Reader* MakeReader(const char* segmentName, const char* sectionName, const char* path, const uint8_t fileContent[], uint64_t fileLength); + +}; + + +#endif + + + + diff --git a/FireOpal/src/debugline.c b/FireOpal/src/debugline.c new file mode 100644 index 0000000..ff0e1d9 --- /dev/null +++ b/FireOpal/src/debugline.c @@ -0,0 +1,546 @@ +/* + * Copyright (c) 2005-2006 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@ + */ +#ifndef KLD +#include +#include +#include +#include +#include "dwarf2.h" +#include "debugline.h" + +struct line_reader_data +{ + bool little_endian; + + /* From the line number information header. */ + uint8_t minimum_instruction_length; + int8_t line_base; + uint8_t line_range; + uint8_t opcode_base; + const uint8_t * standard_opcode_lengths; + size_t numdir; + const uint8_t * * dirnames; + size_t numfile_orig; + size_t numfile; /* As updated during execution of the table. */ + const uint8_t * * filenames; + + /* Current position in the line table. */ + const uint8_t * cpos; + /* End of this part of the line table. */ + const uint8_t * end; + /* Start of the line table. */ + const uint8_t * init; + + struct line_info cur; +}; + +/* Read in a word of fixed size, which may be unaligned, in the + appropriate endianness. */ +#define read_16(p) (lnd->little_endian \ + ? ((p)[1] << 8 | (p)[0]) \ + : ((p)[0] << 8 | (p)[1])) +#define read_32(p) (lnd->little_endian \ + ? ((p)[3] << 24 | (p)[2] << 16 | (p)[1] << 8 | (p)[0]) \ + : ((p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3])) +#define read_64(p) (lnd->little_endian \ + ? ((uint64_t) (p)[7] << 56 | (uint64_t) (p)[6] << 48 \ + | (uint64_t) (p)[5] << 40 | (uint64_t) (p)[4] << 32 \ + | (uint64_t) (p)[3] << 24 | (uint64_t) (p)[2] << 16u \ + | (uint64_t) (p)[1] << 8 | (uint64_t) (p)[0]) \ + : ((uint64_t) (p)[0] << 56 | (uint64_t) (p)[1] << 48 \ + | (uint64_t) (p)[2] << 40 | (uint64_t) (p)[3] << 32 \ + | (uint64_t) (p)[4] << 24 | (uint64_t) (p)[5] << 16u \ + | (uint64_t) (p)[6] << 8 | (uint64_t) (p)[7])) + +/* Skip over a LEB128 value (signed or unsigned). */ +static void +skip_leb128 (struct line_reader_data * leb) +{ + while (leb->cpos != leb->end && *leb->cpos >= 0x80) + leb->cpos++; + if (leb->cpos != leb->end) + leb->cpos++; +} + +/* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow + or error. On overflow, skip past the rest of the uleb128. */ +static uint64_t +read_uleb128 (struct line_reader_data * leb) +{ + uint64_t result = 0; + int bit = 0; + + do { + uint64_t b; + + if (leb->cpos == leb->end) + return (uint64_t) -1; + + b = *leb->cpos & 0x7f; + + if (bit >= 64 || b << bit >> bit != b) + result = (uint64_t) -1; + else + result |= b << bit, bit += 7; + } while (*leb->cpos++ >= 0x80); + return result; +} + + +/* Read a SLEB128 into a 64-bit word. Return 0 on overflow or error + (which is not very helpful). On overflow, skip past the rest of + the SLEB128. For negative numbers, this actually overflows when + under -2^62, but since this is used for line numbers that ought to + be OK... */ +static int64_t +read_sleb128 (struct line_reader_data * leb) +{ + const uint8_t * start_pos = leb->cpos; + uint64_t v = read_uleb128 (leb); + uint64_t signbit; + + if (v >= 1ull << 63) + return 0; + if (leb->cpos - start_pos > 9) + return v; + + signbit = 1ull << ((leb->cpos - start_pos) * 7 - 1); + + return v | -(v & signbit); +} + +/* Free a line_reader_data structure. */ +void +line_free (struct line_reader_data * lnd) +{ + if (! lnd) + return; + if (lnd->dirnames) + free (lnd->dirnames); + if (lnd->filenames) + free (lnd->filenames); + free (lnd); +} + +/* Return the pathname of the file in S, or NULL on error. + The result will have been allocated with malloc. */ + +char * +line_file (struct line_reader_data *lnd, uint64_t n) +{ + const uint8_t * prev_pos = lnd->cpos; + size_t filelen, dirlen; + uint64_t dir; + char * result; + + /* I'm not sure if this is actually an error. */ + if (n == 0 + || n > lnd->numfile) + return NULL; + + filelen = strlen ((const char *)lnd->filenames[n - 1]); + lnd->cpos = lnd->filenames[n - 1] + filelen + 1; + dir = read_uleb128 (lnd); + lnd->cpos = prev_pos; + if (dir == 0 + || lnd->filenames[n - 1][0] == '/') + return strdup ((const char *)lnd->filenames[n - 1]); + else if (dir > lnd->numdir) + return NULL; + + dirlen = strlen ((const char *) lnd->dirnames[dir - 1]); + result = malloc (dirlen + filelen + 2); + memcpy (result, lnd->dirnames[dir - 1], dirlen); + result[dirlen] = '/'; + memcpy (result + dirlen + 1, lnd->filenames[n - 1], filelen); + result[dirlen + 1 + filelen] = '\0'; + return result; +} + +/* Initialize a state S. Return FALSE on error. */ + +static void +init_state (struct line_info *s) +{ + s->file = 1; + s->line = 1; + s->col = 0; + s->pc = 0; + s->end_of_sequence = false; +} + +/* Read a debug_line section. */ + +struct line_reader_data * +line_open (const uint8_t * debug_line, size_t debug_line_size, + int little_endian) +{ + struct line_reader_data * lnd = NULL; + bool dwarf_size_64; + + uint64_t lnd_length, header_length; + const uint8_t * table_start; + + if (debug_line_size < 12) + return NULL; + + lnd = malloc (sizeof (struct line_reader_data)); + if (! lnd) + goto error; + + lnd->little_endian = little_endian; + lnd->cpos = debug_line; + + lnd_length = read_32 (lnd->cpos); + lnd->cpos += 4; + if (lnd_length == 0xffffffff) + { + lnd_length = read_64 (lnd->cpos); + lnd->cpos += 8; + dwarf_size_64 = true; + } + else if (lnd_length > 0xfffffff0) + /* Not a format we understand. */ + goto error; + else + dwarf_size_64 = false; + + if (debug_line_size < lnd_length + (dwarf_size_64 ? 12 : 4) + || lnd_length < (dwarf_size_64 ? 15 : 11)) + /* Too small. */ + goto error; + + if (read_16 (lnd->cpos) != 2) + /* Unknown line number format. */ + goto error; + lnd->cpos += 2; + + header_length = dwarf_size_64 ? (uint64_t)read_64(lnd->cpos) : (uint64_t)read_32(lnd->cpos); + lnd->cpos += dwarf_size_64 ? 8 : 4; + if (lnd_length < header_length + (lnd->cpos - debug_line) + || header_length < 7) + goto error; + + lnd->minimum_instruction_length = lnd->cpos[0]; + /* Ignore default_is_stmt. */ + lnd->line_base = lnd->cpos[2]; + lnd->line_range = lnd->cpos[3]; + lnd->opcode_base = lnd->cpos[4]; + + if (lnd->opcode_base == 0) + /* Every valid line number program must use at least opcode 0 + for DW_LNE_end_sequence. */ + goto error; + + lnd->standard_opcode_lengths = lnd->cpos + 5; + if (header_length < (uint64_t)(5 + (lnd->opcode_base - 1))) + /* Header not long enough. */ + goto error; + lnd->cpos += 5 + lnd->opcode_base - 1; + lnd->end = debug_line + header_length + (dwarf_size_64 ? 22 : 10); + + /* Make table of offsets to directory names. */ + table_start = lnd->cpos; + lnd->numdir = 0; + while (lnd->cpos != lnd->end && *lnd->cpos) + { + lnd->cpos = memchr (lnd->cpos, 0, lnd->end - lnd->cpos); + if (! lnd->cpos) + goto error; + lnd->cpos++; + lnd->numdir++; + } + if (lnd->cpos == lnd->end) + goto error; + lnd->dirnames = malloc (lnd->numdir * sizeof (const uint8_t *)); + if (! lnd->dirnames) + goto error; + lnd->numdir = 0; + lnd->cpos = table_start; + while (*lnd->cpos) + { + lnd->dirnames[lnd->numdir++] = lnd->cpos; + lnd->cpos = memchr (lnd->cpos, 0, lnd->end - lnd->cpos) + 1; + } + lnd->cpos++; + + /* Make table of offsets to file entries. */ + table_start = lnd->cpos; + lnd->numfile = 0; + while (lnd->cpos != lnd->end && *lnd->cpos) + { + lnd->cpos = memchr (lnd->cpos, 0, lnd->end - lnd->cpos); + if (! lnd->cpos) + goto error; + lnd->cpos++; + skip_leb128 (lnd); + skip_leb128 (lnd); + skip_leb128 (lnd); + lnd->numfile++; + } + if (lnd->cpos == lnd->end) + goto error; + lnd->filenames = malloc (lnd->numfile * sizeof (const uint8_t *)); + if (! lnd->filenames) + goto error; + lnd->numfile = 0; + lnd->cpos = table_start; + while (*lnd->cpos) + { + lnd->filenames[lnd->numfile++] = lnd->cpos; + lnd->cpos = memchr (lnd->cpos, 0, lnd->end - lnd->cpos) + 1; + skip_leb128 (lnd); + skip_leb128 (lnd); + skip_leb128 (lnd); + } + lnd->cpos++; + + lnd->numfile_orig = lnd->numfile; + lnd->cpos = lnd->init = lnd->end; + lnd->end = debug_line + lnd_length + (dwarf_size_64 ? 12 : 4); + + init_state (&lnd->cur); + + return lnd; + + error: + line_free (lnd); + return NULL; +} + +/* Reset back to the beginning. */ +void +line_reset (struct line_reader_data * lnd) +{ + lnd->cpos = lnd->init; + lnd->numfile = lnd->numfile_orig; + init_state (&lnd->cur); +} + +/* Is there no more line data available? */ +int +line_at_eof (struct line_reader_data * lnd) +{ + return lnd->cpos == lnd->end; +} + +static bool +next_state (struct line_reader_data *lnd) +{ + if (lnd->cur.end_of_sequence) + init_state (&lnd->cur); + + for (;;) + { + uint8_t op; + uint64_t tmp; + + if (lnd->cpos == lnd->end) + return false; + op = *lnd->cpos++; + if (op >= lnd->opcode_base) + { + op -= lnd->opcode_base; + + lnd->cur.line += op % lnd->line_range + lnd->line_base; + lnd->cur.pc += (op / lnd->line_range + * lnd->minimum_instruction_length); + return true; + } + else switch (op) + { + case DW_LNS_extended_op: + { + uint64_t sz = read_uleb128 (lnd); + const uint8_t * op = lnd->cpos; + + if ((uint64_t)(lnd->end - op) < sz || sz == 0) + return false; + lnd->cpos += sz; + switch (*op++) + { + case DW_LNE_end_sequence: + lnd->cur.end_of_sequence = true; + return true; + + case DW_LNE_set_address: + if (sz == 9) + lnd->cur.pc = read_64 (op); + else if (sz == 5) + lnd->cur.pc = read_32 (op); + else + return false; + break; + + case DW_LNE_define_file: + { + const uint8_t * * filenames; + filenames = realloc + (lnd->filenames, + (lnd->numfile + 1) * sizeof (const uint8_t *)); + if (! filenames) + return false; + /* Check for zero-termination. */ + if (! memchr (op, 0, lnd->cpos - op)) + return false; + filenames[lnd->numfile++] = op; + lnd->filenames = filenames; + + /* There's other data here, like file sizes and modification + times, but we don't need to read it so skip it. */ + } + break; + + default: + /* Don't understand it, so skip it. */ + break; + } + break; + } + + case DW_LNS_copy: + //fprintf(stderr, "DW_LNS_copy\n"); + return true; + case DW_LNS_advance_pc: + //fprintf(stderr, "DW_LNS_advance_pc\n"); + tmp = read_uleb128 (lnd); + if (tmp == (uint64_t) -1) + return false; + lnd->cur.pc += tmp * lnd->minimum_instruction_length; + break; + case DW_LNS_advance_line: + //fprintf(stderr, "DW_LNS_advance_line\n"); + lnd->cur.line += read_sleb128 (lnd); + break; + case DW_LNS_set_file: + //fprintf(stderr, "DW_LNS_set_file\n"); + lnd->cur.file = read_uleb128 (lnd); + break; + case DW_LNS_set_column: + //fprintf(stderr, "DW_LNS_set_column\n"); + lnd->cur.col = read_uleb128 (lnd); + break; + case DW_LNS_const_add_pc: + //fprintf(stderr, "DW_LNS_const_add_pc\n"); + lnd->cur.pc += ((255 - lnd->opcode_base) / lnd->line_range + * lnd->minimum_instruction_length); + break; + case DW_LNS_fixed_advance_pc: + //fprintf(stderr, "DW_LNS_fixed_advance_pc\n"); + if (lnd->end - lnd->cpos < 2) + return false; + lnd->cur.pc += read_16 (lnd->cpos); + lnd->cpos += 2; + break; + default: + { + /* Don't know what it is, so skip it. */ + int i; + for (i = 0; i < lnd->standard_opcode_lengths[op - 1]; i++) + skip_leb128 (lnd); + break; + } + } + } +} + + +/* Set RESULT to the next 'interesting' line state, as indicated + by STOP, or return FALSE on error. The final (end-of-sequence) + line state is always considered interesting. */ +int +line_next (struct line_reader_data * lnd, + struct line_info * result, + enum line_stop_constants stop) +{ + for (;;) + { + struct line_info prev = lnd->cur; + + if (! next_state (lnd)) + return false; + + if (lnd->cur.end_of_sequence) + break; + if (stop == line_stop_always) + break; + if ((stop & line_stop_pc) && lnd->cur.pc != prev.pc) + break; + if ((stop & line_stop_pos_mask) && lnd->cur.file != prev.file) + break; + if ((stop & line_stop_pos_mask) >= line_stop_line + && lnd->cur.line != prev.line) + break; + if ((stop & line_stop_pos_mask) >= line_stop_col + && lnd->cur.col != prev.col) + break; + } + *result = lnd->cur; + return true; +} + +/* Find the region (START->pc through END->pc) in the debug_line + information which contains PC. This routine starts searching at + the current position (which is returned as END), and will go all + the way around the debug_line information. It will return false if + an error occurs or if there is no matching region; these may be + distinguished by looking at START->end_of_sequence, which will be + false on error and true if there was no matching region. + You could write this routine using line_next, but this version + will be slightly more efficient, and of course more convenient. */ + +int +line_find_addr (struct line_reader_data * lnd, + struct line_info * start, + struct line_info * end, + uint64_t pc) +{ + const uint8_t * startpos; + struct line_info prev; + + if (lnd->cur.end_of_sequence && lnd->cpos == lnd->end) + line_reset (lnd); + + startpos = lnd->cpos; + + do { + prev = lnd->cur; + if (! next_state (lnd)) + { + start->end_of_sequence = false; + return false; + } + if (lnd->cur.end_of_sequence && lnd->cpos == lnd->end) + line_reset (lnd); + if (lnd->cpos == startpos) + { + start->end_of_sequence = true; + return false; + } + } while (lnd->cur.pc <= pc || prev.pc > pc || prev.end_of_sequence); + *start = prev; + *end = lnd->cur; + return true; +} +#endif /* ! KLD */ + diff --git a/FireOpal/src/debugline.h b/FireOpal/src/debugline.h new file mode 100644 index 0000000..51d585e --- /dev/null +++ b/FireOpal/src/debugline.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2006 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@ + */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Information about a line. + DIRECTORY is to be ignored if FILENAME is absolute. + PC will be relative to the file the debug_line section is in. */ +struct line_info +{ + uint64_t file; + int64_t line; + uint64_t col; + uint64_t pc; + int end_of_sequence; +}; + +/* Opaque status structure for the line readers. */ +struct line_reader_data; + +/* Create a line_reader_data, given address and size of the debug_line section. + SIZE may be (size_t)-1 if unknown, although this suppresses checking + for an incorrectly large size in the debug_line section. + LITTLE_ENDIAN is set if the debug_line section is for a little-endian + machine. + Returns NULL on error. */ +struct line_reader_data * line_open (const uint8_t * debug_line, + size_t debug_line_size, + int little_endian); + +/* The STOP parameter to line_next is one of line_stop_{file,line,col}, + perhaps ORed with line_stop_pc; or line_stop_atend, or line_stop_always. */ +enum line_stop_constants { + line_stop_atend = 0, /* Stop only at the end of a sequence. */ + line_stop_file = 1, /* Stop if DIRECTORY or FILENAME change. */ + line_stop_line = 2, /* Stop if LINE, DIRECTORY, or FILENAME change. */ + line_stop_col = 3, /* Stop if COL, LINE, DIRECTORY, or FILENAME change. */ + line_stop_pos_mask = 3, + line_stop_pc = 4, /* Stop if PC changes. */ + line_stop_always = 8 /* Stop always. */ +}; + +/* Either return FALSE on an error, in which case the line_reader_data + may be invalid and should be passed immediately to line_free; or + fill RESULT with the first 'interesting' line, as determined by STOP. + The last line data in a sequence is always considered 'interesting'. */ +int line_next (struct line_reader_data * lnd, + struct line_info * result, + enum line_stop_constants stop); + +/* Find the region (START->pc through END->pc) in the debug_line + information which contains PC. This routine starts searching at + the current position (which is returned as END), and will go all + the way around the debug_line information. It will return false if + an error occurs or if there is no matching region; these may be + distinguished by looking at START->end_of_sequence, which will be + false on error and true if there was no matching region. + You could write this routine using line_next, but this version + will be slightly more efficient, and of course more convenient. */ + +int line_find_addr (struct line_reader_data * lnd, + struct line_info * start, + struct line_info * end, + uint64_t pc); + +/* Return TRUE if there is more line data to be fetched. + If line_next has not been called or it has been called but did not + set END_OF_SEQUENCE, you can assume there is more line data, + but it's safe to call this routine anyway. */ +int line_at_eof (struct line_reader_data * lnd); + +/* Return the pathname of the file in S, or NULL on error. + The result will have been allocated with malloc. */ +char * line_file (struct line_reader_data *lnd, uint64_t file); + +/* Reset the line_reader_data: go back to the beginning. */ +void line_reset (struct line_reader_data * lnd); + +/* Free a line_reader_data structure. */ +void line_free (struct line_reader_data * lnd); + +#ifdef __cplusplus +} +#endif + diff --git a/FireOpal/src/dwarf2.h b/FireOpal/src/dwarf2.h new file mode 100644 index 0000000..530b465 --- /dev/null +++ b/FireOpal/src/dwarf2.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2006 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@ + */ +/* These constants were taken from version 3 of the DWARF standard, + which is Copyright (c) 2005 Free Standards Group, and + Copyright (c) 1992, 1993 UNIX International, Inc. */ + +/* This is not a complete list. */ +enum { + DW_TAG_compile_unit = 17, + DW_TAG_partial_unit = 60 +}; + +/* This is not a complete list. */ +enum { + DW_AT_sibling = 1, + DW_AT_name = 3, + DW_AT_stmt_list = 16, + DW_AT_comp_dir = 27 +}; + +enum { + DW_FORM_addr = 1, + DW_FORM_block2 = 3, + DW_FORM_block4, + DW_FORM_data2, + DW_FORM_data4, + DW_FORM_data8, + DW_FORM_string, + DW_FORM_block, + DW_FORM_block1, + DW_FORM_data1, + DW_FORM_flag, + DW_FORM_sdata, + DW_FORM_strp, + DW_FORM_udata, + DW_FORM_ref_addr, + DW_FORM_ref1, + DW_FORM_ref2, + DW_FORM_ref4, + DW_FORM_ref8, + DW_FORM_ref_udata, + DW_FORM_indirect /* 22 */ +}; + +enum { + DW_LNS_extended_op = 0, + DW_LNS_copy, + DW_LNS_advance_pc, + DW_LNS_advance_line, + DW_LNS_set_file, + DW_LNS_set_column, + DW_LNS_negate_stmt, + DW_LNS_set_basic_block, + DW_LNS_const_add_pc, + DW_LNS_fixed_advance_pc, + DW_LNS_set_prologue_end, + DW_LNS_set_epilogue_begin, + DW_LNS_set_isa +}; + +enum { + DW_LNE_end_sequence = 1, + DW_LNE_set_address, + DW_LNE_define_file +}; diff --git a/FireOpal/src/ld.cpp b/FireOpal/src/ld.cpp new file mode 100644 index 0000000..acd18c8 --- /dev/null +++ b/FireOpal/src/ld.cpp @@ -0,0 +1,3778 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-* + * Copyright (c) 2005-2007 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@ + */ + +// start temp HACK for cross builds +extern "C" double log2 ( double ); +#define __MATH__ +// end temp HACK for cross builds + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "configure.h" +#include "Options.h" + +#include "ObjectFile.h" + +#include "MachOReaderRelocatable.hpp" +#include "ArchiveReader.hpp" +#include "MachOReaderDylib.hpp" +#include "MachOWriterExecutable.hpp" + + +#if LTO_SUPPORT +#include "LTOReader.hpp" +#endif + + +#include "OpaqueSection.hpp" + + +class CStringComparor +{ +public: + bool operator()(const char* left, const char* right) const { return (strcmp(left, right) < 0); } +}; + +class CStringEquals +{ +public: + bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } +}; + +class Section : public ObjectFile::Section +{ +public: + static Section* find(const char* sectionName, const char* segmentName, bool zeroFill); + static void assignIndexes(); + const char* getName() { return fSectionName; } +private: + Section(const char* sectionName, const char* segmentName, bool zeroFill); + + struct Sorter { + static int segmentOrdinal(const char* segName); + bool operator()(Section* left, Section* right); + }; + + typedef __gnu_cxx::hash_map, CStringEquals> NameToOrdinal; + typedef __gnu_cxx::hash_map, CStringEquals> NameToSection; + //typedef std::map NameToSection; + + const char* fSectionName; + const char* fSegmentName; + bool fZeroFill; + + static NameToSection fgMapping; + static std::vector fgSections; + static NameToOrdinal fgSegmentDiscoverOrder; +}; + +Section::NameToSection Section::fgMapping; +std::vector Section::fgSections; +Section::NameToOrdinal Section::fgSegmentDiscoverOrder; + +Section::Section(const char* sectionName, const char* segmentName, bool zeroFill) + : fSectionName(sectionName), fSegmentName(segmentName), fZeroFill(zeroFill) +{ + this->fIndex = fgSections.size(); + //fprintf(stderr, "new Section(%s, %s) => %p, %u\n", sectionName, segmentName, this, this->getIndex()); +} + +Section* Section::find(const char* sectionName, const char* segmentName, bool zeroFill) +{ + NameToSection::iterator pos = fgMapping.find(sectionName); + if ( pos != fgMapping.end() ) { + if ( strcmp(pos->second->fSegmentName, segmentName) == 0 ) + return pos->second; + // otherwise same section name is used in different segments, look slow way + for (std::vector::iterator it=fgSections.begin(); it != fgSections.end(); it++) { + if ( (strcmp((*it)->fSectionName, sectionName) == 0) && (strcmp((*it)->fSegmentName, segmentName) == 0) ) + return *it; + } + } + + // does not exist, so make a new one + Section* sect = new Section(sectionName, segmentName, zeroFill); + fgMapping[sectionName] = sect; + fgSections.push_back(sect); + + if ( (strcmp(sectionName, "__text") == 0) && (strcmp(segmentName, "__TEXT") == 0) ) { + // special case __textcoal_nt to be right after __text + find("__textcoal_nt", "__TEXT", false); + } + + // remember segment discovery order + if ( fgSegmentDiscoverOrder.find(segmentName) == fgSegmentDiscoverOrder.end() ) + fgSegmentDiscoverOrder[segmentName] = fgSegmentDiscoverOrder.size(); + + return sect; +} + +int Section::Sorter::segmentOrdinal(const char* segName) +{ + if ( strcmp(segName, "__PAGEZERO") == 0 ) + return 1; + if ( strcmp(segName, "__TEXT") == 0 ) + return 2; + if ( strcmp(segName, "__DATA") == 0 ) + return 3; + if ( strcmp(segName, "__OBJC") == 0 ) + return 4; + if ( strcmp(segName, "__OBJC2") == 0 ) + return 5; + if ( strcmp(segName, "__LINKEDIT") == 0 ) + return INT_MAX; // linkedit segment should always sort last + else + return fgSegmentDiscoverOrder[segName]+6; +} + + +bool Section::Sorter::operator()(Section* left, Section* right) +{ + // Segment is primary sort key + int leftSegOrdinal = segmentOrdinal(left->fSegmentName); + int rightSegOrdinal = segmentOrdinal(right->fSegmentName); + if ( leftSegOrdinal < rightSegOrdinal ) + return true; + if ( leftSegOrdinal > rightSegOrdinal ) + return false; + + // zerofill section sort to the end + if ( !left->fZeroFill && right->fZeroFill ) + return true; + if ( left->fZeroFill && !right->fZeroFill ) + return false; + + // section discovery order is last sort key + return left->fIndex < right->fIndex; +} + +void Section::assignIndexes() +{ + //printf("unsorted sections:\n"); + //for (std::vector::iterator it=fgSections.begin(); it != fgSections.end(); it++) { + // printf("section: name=%s, segment: name=%s, discovery order=%d\n", (*it)->fSectionName, (*it)->fSegmentName, (*it)->fIndex); + //} + + // sort it + std::sort(fgSections.begin(), fgSections.end(), Section::Sorter()); + + // assign correct section ordering to each Section object + unsigned int newOrder = 1; + for (std::vector::iterator it=fgSections.begin(); it != fgSections.end(); it++) + (*it)->fIndex = newOrder++; + + //printf("sorted sections:\n"); + //for (std::vector::iterator it=fgSections.begin(); it != fgSections.end(); it++) { + // printf("section: index=%d, obj=%p, name=%s\n", (*it)->fIndex, (*it), (*it)->fSectionName); + //} +} + +class Linker : public ObjectFile::Reader::DylibHander { +public: + Linker(int argc, const char* argv[]); + + const char* getArchPrefix(); + const char* architectureName(); + bool showArchitectureInErrors(); + bool isInferredArchitecture(); + void createReaders(); + void createWriter(); + void addInputFile(ObjectFile::Reader* reader, const Options::FileInfo& ); + void setOutputFile(ExecutableFile::Writer* writer); + void link(); + void optimize(); + + // implemenation from ObjectFile::Reader::DylibHander + virtual ObjectFile::Reader* findDylib(const char* installPath, const char* fromPath); + +private: + struct WhyLiveBackChain + { + WhyLiveBackChain* previous; + const char* name; + }; + + ObjectFile::Reader* createReader(const Options::FileInfo&); + void addAtom(ObjectFile::Atom& atom); + void addAtoms(std::vector& atoms); + void buildAtomList(); + void processDylibs(); + void markDead(ObjectFile::Atom* atom); + void updateConstraints(ObjectFile::Reader* reader); + void loadAndResolve(); + void processDTrace(); + void checkObjC(); + void loadUndefines(); + void checkUndefines(); + void addWeakAtomOverrides(); + void resolveReferences(); + void deadStripResolve(); + void addLiveRoot(const char* name); + ObjectFile::Atom* findAtom(const Options::OrderedSymbol& pair); + void logArchive(ObjectFile::Reader* reader); + void sortSections(); + void sortAtoms(); + void tweakLayout(); + void writeDotOutput(); + static bool minimizeStab(ObjectFile::Reader::Stab& stab); + static const char* truncateStabString(const char* str); + void collectDebugInfo(); + void writeOutput(); + ObjectFile::Atom* entryPoint(bool orInit); + ObjectFile::Atom* dyldHelper(); + ObjectFile::Atom* dyldLazyLibraryHelper(); + const char* assureFullPath(const char* path); + void markLive(ObjectFile::Atom& atom, Linker::WhyLiveBackChain* previous); + void collectStabs(ObjectFile::Reader* reader, std::map& atomOrdinals); + void synthesizeDebugNotes(std::vector& allAtomsByReader); + void printStatistics(); + void printTime(const char* msg, uint64_t partTime, uint64_t totalTime); + char* commatize(uint64_t in, char* out); + void getVMInfo(vm_statistics_data_t& info); + cpu_type_t inferArchitecture(); + void addDtraceProbe(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* probeName); + void checkDylibClientRestrictions(ObjectFile::Reader* reader); + void logDylib(ObjectFile::Reader* reader, bool indirect); + + void resolve(ObjectFile::Reference* reference); + void resolveFrom(ObjectFile::Reference* reference); + std::vector* addJustInTimeAtoms(const char* name, bool dylibsOnly=false); + void addJustInTimeAtomsAndMarkLive(const char* name); + + ObjectFile::Reader* addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen); + ObjectFile::Reader* addObject(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen); + ObjectFile::Reader* addArchive(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen); + + void logTraceInfo(const char* format, ...); + + + class SymbolTable + { + public: + typedef __gnu_cxx::hash_map, CStringEquals> Mapper; + + SymbolTable(Linker&); + void require(const char* name); + bool add(ObjectFile::Atom& atom); + ObjectFile::Atom* find(const char* name); + unsigned int getRequireCount() { return fRequireCount; } + void getNeededNames(bool andWeakDefintions, std::vector& undefines); + bool hasExternalTentativeDefinitions() { return fHasExternalTentativeDefinitions; } + bool hasExternalWeakDefinitions() { return fHasExternalWeakDefinitions; } + void setHasExternalWeakDefinitions() { fHasExternalWeakDefinitions = true; } + Mapper::iterator begin() { return fTable.begin(); } + Mapper::iterator end() { return fTable.end(); } + + private: + Linker& fOwner; + Mapper fTable; + unsigned int fRequireCount; + bool fHasExternalTentativeDefinitions; + bool fHasExternalWeakDefinitions; + }; + + class AtomSorter + { + public: + AtomSorter(std::map* map) : fOverriddenOrdinalMap(map) {} + bool operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right); + private: + std::map* fOverriddenOrdinalMap; + }; + + typedef std::map SectionOrder; + + struct DTraceProbeInfo { + DTraceProbeInfo(const ObjectFile::Atom* a, uint32_t o, const char* n) : atom(a), offset(o), probeName(n) {} + const ObjectFile::Atom* atom; + uint32_t offset; + const char* probeName; + }; + typedef __gnu_cxx::hash_map, __gnu_cxx::hash, CStringEquals> ProviderToProbes; + typedef __gnu_cxx::hash_set, CStringEquals> CStringSet; + typedef __gnu_cxx::hash_map, CStringEquals> InstallNameToReader; + + struct IndirectLibrary { + const char* path; + uint64_t fileLen; + ObjectFile::Reader* reader; + std::set parents; + ObjectFile::Reader* reExportedViaDirectLibrary; + }; + + ObjectFile::Reader* findDirectLibraryWhichReExports(struct IndirectLibrary& indirectLib); + + Options fOptions; + SymbolTable fGlobalSymbolTable; + uint32_t fNextInputOrdinal; + std::vector fInputFiles; + ExecutableFile::Writer* fOutputFile; + InstallNameToReader fDylibMap; + std::map fDylibOptionsMap; + std::set fDylibsProcessed; + ObjectFile::Reader* fBundleLoaderReader; + std::vector fReadersThatHaveSuppliedAtoms; + std::vector fAllAtoms; + std::set fArchiveReaders; + std::set fArchiveReadersLogged; + std::set fDeadAtoms; + std::set fLiveAtoms; + std::set fLiveRootAtoms; + std::vector fStabs; + std::vector fAtomsWithUnresolvedReferences; + std::vector fDtraceProbes; + std::vector fDtraceProbeSites; + std::vector fDtraceIsEnabledSites; + std::map fDtraceAtomToTypes; + bool fCreateUUID; + bool fCanScatter; + SectionOrder fSectionOrder; + cpu_type_t fArchitecture; + const char* fArchitectureName; + bool fArchitectureInferred; + bool fDirectLibrariesComplete; + bool fBiggerThanTwoGigOutput; + uint64_t fOutputFileSize; + uint64_t fTotalZeroFillSize; + uint64_t fTotalSize; + uint64_t fStartTime; + uint64_t fStartCreateReadersTime; + uint64_t fStartCreateWriterTime; + uint64_t fStartBuildAtomsTime; + uint64_t fStartLoadAndResolveTime; + uint64_t fStartSortTime; + uint64_t fStartDebugTime; + uint64_t fStartWriteTime; + uint64_t fEndTime; + uint64_t fTotalObjectSize; + uint64_t fTotalArchiveSize; + uint32_t fTotalObjectLoaded; + uint32_t fTotalArchivesLoaded; + uint32_t fTotalDylibsLoaded; + vm_statistics_data_t fStartVMInfo; + ObjectFile::Reader::ObjcConstraint fCurrentObjCConstraint; + ObjectFile::Reader::CpuConstraint fCurrentCpuConstraint; + bool fObjcReplacmentClasses; + bool fAllDirectDylibsLoaded; +}; + + +Linker::Linker(int argc, const char* argv[]) + : fOptions(argc, argv), fGlobalSymbolTable(*this), fNextInputOrdinal(1), fOutputFile(NULL), fBundleLoaderReader(NULL), + fCreateUUID(fOptions.outputKind() != Options::kObjectFile), fCanScatter(true), + fArchitecture(0), fArchitectureInferred(false), fDirectLibrariesComplete(false), fBiggerThanTwoGigOutput(false), + fOutputFileSize(0), fTotalZeroFillSize(0), fTotalSize(0), fTotalObjectSize(0), + fTotalArchiveSize(0), fTotalObjectLoaded(0), fTotalArchivesLoaded(0), fTotalDylibsLoaded(0), + fCurrentObjCConstraint(ObjectFile::Reader::kObjcNone), fCurrentCpuConstraint(ObjectFile::Reader::kCpuAny), + fObjcReplacmentClasses(false), fAllDirectDylibsLoaded(false) +{ + fStartTime = mach_absolute_time(); + if ( fOptions.printStatistics() ) + getVMInfo(fStartVMInfo); + + fArchitecture = fOptions.architecture(); + if ( fArchitecture == 0 ) { + // -arch not specified, scan .o files to figure out what it should be + fArchitecture = inferArchitecture(); + fArchitectureInferred = true; + } + switch (fArchitecture) { + case CPU_TYPE_POWERPC: + fArchitectureName = "ppc"; + break; + case CPU_TYPE_POWERPC64: + fArchitectureName = "ppc64"; + break; + case CPU_TYPE_I386: + fArchitectureName = "i386"; + break; + case CPU_TYPE_X86_64: + fArchitectureName = "x86_64"; + break; + case CPU_TYPE_ARM: + fArchitectureName = "arm"; + break; + default: + fArchitectureName = "unknown architecture"; + break; + } +} + +const char* Linker::architectureName() +{ + return fArchitectureName; +} + +bool Linker::showArchitectureInErrors() +{ + return fOptions.printArchPrefix(); +} + +bool Linker::isInferredArchitecture() +{ + return fArchitectureInferred; +} + +cpu_type_t Linker::inferArchitecture() +{ + // scan all input files, looking for a thin .o file. + // the first one found is presumably the architecture to link + uint8_t buffer[sizeof(mach_header_64)]; + std::vector& files = fOptions.getInputFiles(); + for (std::vector::iterator it = files.begin(); it != files.end(); ++it) { + int fd = ::open(it->path, O_RDONLY, 0); + if ( fd != -1 ) { + ssize_t amount = read(fd, buffer, sizeof(buffer)); + ::close(fd); + if ( amount >= (ssize_t)sizeof(buffer) ) { + if ( mach_o::relocatable::Reader::validFile(buffer) ) { + //warning("-arch not used, infering -arch ppc based on %s", it->path); + return CPU_TYPE_POWERPC; + } + else if ( mach_o::relocatable::Reader::validFile(buffer) ) { + //warning("-arch not used, infering -arch ppc64 based on %s", it->path); + return CPU_TYPE_POWERPC64; + } + else if ( mach_o::relocatable::Reader::validFile(buffer) ) { + //warning("-arch not used, infering -arch i386 based on %s", it->path); + return CPU_TYPE_I386; + } + else if ( mach_o::relocatable::Reader::validFile(buffer) ) { + //warning("-arch not used, infering -arch x86_64 based on %s", it->path); + return CPU_TYPE_X86_64; + } + else if ( mach_o::relocatable::Reader::validFile(buffer) ) { + //warning("-arch not used, infering -arch arm based on %s", it->path); + return CPU_TYPE_ARM; + } + } + } + } + + // no thin .o files found, so default to same architecture this was built as + warning("-arch not specified"); +#if __ppc__ + return CPU_TYPE_POWERPC; +#elif __i386__ + return CPU_TYPE_I386; +#elif __ppc64__ + return CPU_TYPE_POWERPC64; +#elif __x86_64__ + return CPU_TYPE_X86_64; +#elif __arm__ + return CPU_TYPE_ARM; +#else + #error unknown default architecture +#endif +} + + +void Linker::addInputFile(ObjectFile::Reader* reader, const Options::FileInfo& info) +{ + fInputFiles.push_back(reader); + fDylibOptionsMap[reader] = info.options; +} + +void Linker::setOutputFile(ExecutableFile::Writer* writer) +{ + fOutputFile = writer; +} + +class InSet +{ +public: + InSet(std::set& deadAtoms) : fDeadAtoms(deadAtoms) {} + + bool operator()(ObjectFile::Atom*& atom) const { + return ( fDeadAtoms.count(atom) != 0 ); + } + +private: + std::set& fDeadAtoms; +}; + +void Linker::loadAndResolve() +{ + fStartLoadAndResolveTime = mach_absolute_time(); + if ( fOptions.deadStrip() == Options::kDeadStripOff ) { + // without dead-code-stripping: + // find atoms to resolve all undefines + this->loadUndefines(); + // verify nothing is missing + this->checkUndefines(); + // once all undefines fulfill, then bind all references + this->resolveReferences(); + // remove atoms weak atoms that have been overridden + fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), InSet(fDeadAtoms)), fAllAtoms.end()); + } + else { + // with dead code stripping: + // start binding references from roots, + this->deadStripResolve(); + // verify nothing is missing + this->checkUndefines(); + } +} + +void Linker::optimize() +{ + // give each reader a chance to do any optimizations + std::vector newAtoms; + std::vector additionalUndefines; + for (std::vector::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) { + (*it)->optimize(fAllAtoms, newAtoms, additionalUndefines, fDeadAtoms, fNextInputOrdinal, fOutputFile, + fOptions.llvmOptions(), + fOptions.allGlobalsAreDeadStripRoots(), (int)fOptions.outputKind(), fOptions.verbose(), + fOptions.saveTempFiles(), fOptions.getOutputFilePath(), fOptions.positionIndependentExecutable(), + fOptions.allowTextRelocs()); + } + + // add all newly created atoms to fAllAtoms and update symbol table + this->addAtoms(newAtoms); + + // Make sure all atoms have a section. Atoms that were not originally in a mach-o file could + // not have their section set until now. + for(std::vector::iterator itr = fAllAtoms.begin(); itr != fAllAtoms.end(); ++itr) { + ObjectFile::Atom *atom = *itr; + if ( atom->getSection() == NULL ) + atom->setSection(Section::find(atom->getSectionName(), atom->getSegment().getName(), atom->isZeroFill())); + } + + // resolve new undefines + for(std::vector::iterator riter = additionalUndefines.begin(); riter != additionalUndefines.end(); ++riter) { + const char *targetName = *riter; + //fprintf(stderr, "LTO additional undefine: %s\n", targetName); + ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName); + if ( target == NULL) { + // mark that this symbol is needed + fGlobalSymbolTable.require(targetName); + // try to find it in some library + this->addJustInTimeAtoms(targetName); + } + } + + if ( fOptions.deadStrip() != Options::kDeadStripOff ) { + fLiveAtoms.clear(); + this->deadStripResolve(); + } + else { + this->checkUndefines(); + this->resolveReferences(); + } +} + +void Linker::link() +{ + this->buildAtomList(); + this->loadAndResolve(); + this->optimize(); + this->checkObjC(); + this->processDTrace(); + this->tweakLayout(); + this->sortSections(); + this->sortAtoms(); + this->writeDotOutput(); + this->collectDebugInfo(); + this->writeOutput(); + this->printStatistics(); + + if ( fOptions.pauseAtEnd() ) + sleep(10); +} + +void Linker::printTime(const char* msg, uint64_t partTime, uint64_t totalTime) +{ + static uint64_t sUnitsPerSecond = 0; + if ( sUnitsPerSecond == 0 ) { + struct mach_timebase_info timeBaseInfo; + if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) { + sUnitsPerSecond = 1000000000ULL * timeBaseInfo.denom / timeBaseInfo.numer; + //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond); + } + } + if ( partTime < sUnitsPerSecond ) { + uint32_t milliSecondsTimeTen = (partTime*10000)/sUnitsPerSecond; + uint32_t milliSeconds = milliSecondsTimeTen/10; + uint32_t percentTimesTen = (partTime*1000)/totalTime; + uint32_t percent = percentTimesTen/10; + fprintf(stderr, "%s: %u.%u milliseconds (%u.%u%%)\n", msg, milliSeconds, milliSecondsTimeTen-milliSeconds*10, percent, percentTimesTen-percent*10); + } + else { + uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond; + uint32_t seconds = secondsTimeTen/10; + uint32_t percentTimesTen = (partTime*1000)/totalTime; + uint32_t percent = percentTimesTen/10; + fprintf(stderr, "%s: %u.%u seconds (%u.%u%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10); + } +} + +char* Linker::commatize(uint64_t in, char* out) +{ + char* result = out; + char rawNum[30]; + sprintf(rawNum, "%llu", in); + const int rawNumLen = strlen(rawNum); + for(int i=0; i < rawNumLen-1; ++i) { + *out++ = rawNum[i]; + if ( ((rawNumLen-i) % 3) == 1 ) + *out++ = ','; + } + *out++ = rawNum[rawNumLen-1]; + *out = '\0'; + return result; +} + +void Linker::getVMInfo(vm_statistics_data_t& info) +{ + mach_msg_type_number_t count = sizeof(vm_statistics_data_t) / sizeof(natural_t); + kern_return_t error = host_statistics(mach_host_self(), HOST_VM_INFO, + (host_info_t)&info, &count); + if (error != KERN_SUCCESS) { + bzero(&info, sizeof(vm_statistics_data_t)); + } +} + +void Linker::printStatistics() +{ + fEndTime = mach_absolute_time(); + if ( fOptions.printStatistics() ) { + vm_statistics_data_t endVMInfo; + getVMInfo(endVMInfo); + + uint64_t totalTime = fEndTime - fStartTime; + printTime("ld total time", totalTime, totalTime); + printTime(" option parsing time", fStartCreateReadersTime - fStartTime, totalTime); + printTime(" object file processing",fStartCreateWriterTime - fStartCreateReadersTime, totalTime); + printTime(" output file setup", fStartBuildAtomsTime - fStartCreateWriterTime, totalTime); + printTime(" build atom list", fStartLoadAndResolveTime - fStartBuildAtomsTime, totalTime); + printTime(" resolve references", fStartSortTime - fStartLoadAndResolveTime, totalTime); + printTime(" sort output", fStartDebugTime - fStartSortTime, totalTime); + printTime(" process debug info", fStartWriteTime - fStartDebugTime, totalTime); + printTime(" write output", fEndTime - fStartWriteTime, totalTime); + fprintf(stderr, "pageins=%u, pageouts=%u, faults=%u\n", endVMInfo.pageins-fStartVMInfo.pageins, + endVMInfo.pageouts-fStartVMInfo.pageouts, endVMInfo.faults-fStartVMInfo.faults); + char temp[40]; + fprintf(stderr, "processed %3u object files, totaling %15s bytes\n", fTotalObjectLoaded, commatize(fTotalObjectSize, temp)); + fprintf(stderr, "processed %3u archive files, totaling %15s bytes\n", fTotalArchivesLoaded, commatize(fTotalArchiveSize, temp)); + fprintf(stderr, "processed %3u dylib files\n", fTotalDylibsLoaded); + fprintf(stderr, "wrote output file totaling %15s bytes\n", commatize(fOutputFileSize, temp)); + } +} + +inline void Linker::addAtom(ObjectFile::Atom& atom) +{ + // add to list of all atoms + fAllAtoms.push_back(&atom); + + if ( fOptions.deadStrip() == Options::kDeadStripOff ) { + // not dead-stripping code, so add atom's references's names to symbol table as to-be-resolved-later + std::vector& references = atom.getReferences(); + for (std::vector::iterator it=references.begin(); it != references.end(); it++) { + ObjectFile::Reference* reference = *it; + if ( reference->getTargetBinding() == ObjectFile::Reference::kUnboundByName ) + fGlobalSymbolTable.require(reference->getTargetName()); + if ( reference->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName ) + fGlobalSymbolTable.require(reference->getFromTargetName()); + if ( reference->getTargetBinding() == ObjectFile::Reference::kDontBind ) + addDtraceProbe(atom, reference->getFixUpOffset(), reference->getTargetName()); + } + // update total size info (except for __ZEROPAGE atom) + if ( atom.getSegment().isContentReadable() ) { + fTotalSize += atom.getSize(); + if ( atom.isZeroFill() ) + fTotalZeroFillSize += atom.getSize(); + } + } + else { + if ( atom.dontDeadStrip() ) + fLiveRootAtoms.insert(&atom); + } + + // if in global namespace, add atom itself to symbol table + ObjectFile::Atom::Scope scope = atom.getScope(); + const char* name = atom.getName(); + if ( (scope != ObjectFile::Atom::scopeTranslationUnit) && (name != NULL) ) { + // update scope based on export list + if ( fOptions.hasExportRestrictList() ) { + if ( scope == ObjectFile::Atom::scopeGlobal ) { + // check for globals that are downgraded to hidden + bool doExport = fOptions.shouldExport(name); + if ( !doExport ) { + atom.setScope(ObjectFile::Atom::scopeLinkageUnit); + } + } + else if ( scope == ObjectFile::Atom::scopeLinkageUnit ) { + // check for hiddens that were requested to be exported + if ( fOptions.hasExportMaskList() && fOptions.shouldExport(name) ) { + warning("cannot export hidden symbol %s from %s", name, atom.getFile()->getPath()); + } + } + } + // add to symbol table + if ( fOptions.outputKind() == Options::kObjectFile ) { + // in ld -r mode don't add .eh symbols to symbol table + // instead kGroupSubordinate references will keep them paired + // with their functions. + const char* sectionName = atom.getSectionName(); + if ( (sectionName != NULL) && (strcmp(sectionName, "__eh_frame") != 0) ) + fGlobalSymbolTable.add(atom); + } + else { + fGlobalSymbolTable.add(atom); + } + } + + // record section orders so output file can have same order + if (atom.getSectionName()) + atom.setSection(Section::find(atom.getSectionName(), atom.getSegment().getName(), atom.isZeroFill())); +} + + +void Linker::markDead(ObjectFile::Atom* atom) +{ + fDeadAtoms.insert(atom); + // + // The kGroupSubordinate reference kind is used to model group comdat. + // The "signature" atom in the group has a kGroupSubordinate reference to + // all other members of the group. So, if the signature atom is + // coalesced away, all other atoms in the group should also be removed. + // + std::vector& references = atom->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + ObjectFile::Reference* ref = *rit; + if ( ref->getKind() == 2 /*kGroupSubordinate*/ ) { // FIX FIX + ObjectFile::Atom* targetAtom = &(ref->getTarget()); + if ( targetAtom == NULL ) { + warning("%s has a group reference to %s but is not bound", atom->getDisplayName(), ref->getTargetName()); + } + else { + if ( targetAtom->getScope() != ObjectFile::Atom::scopeTranslationUnit ) { + // ok for .eh symbols to be not static in -r mode + if ( (fOptions.outputKind() != Options::kObjectFile) || (strcmp(targetAtom->getSectionName(), "__eh_frame") != 0) ) + warning("%s is in a comdat group but its scope is not static", targetAtom->getDisplayName()); + } + this->markDead(targetAtom); + } + } + } +} + +void Linker::updateConstraints(ObjectFile::Reader* reader) +{ + // check objc objects were compiled compatibly + ObjectFile::Reader::ObjcConstraint objcAddition = reader->getObjCConstraint(); + if ( reader->getInstallPath() == NULL ) { + // adding a .o file + switch ( objcAddition ) { + case ObjectFile::Reader::kObjcNone: + break; + case ObjectFile::Reader::kObjcRetainRelease: + if ( fCurrentObjCConstraint == ObjectFile::Reader::kObjcGC ) + throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", reader->getPath()); + fCurrentObjCConstraint = ObjectFile::Reader::kObjcRetainRelease; + break; + case ObjectFile::Reader::kObjcRetainReleaseOrGC: + if ( fCurrentObjCConstraint == ObjectFile::Reader::kObjcNone ) + fCurrentObjCConstraint = ObjectFile::Reader::kObjcRetainReleaseOrGC; + break; + case ObjectFile::Reader::kObjcGC: + if ( fCurrentObjCConstraint == ObjectFile::Reader::kObjcRetainRelease ) + throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", reader->getPath()); + fCurrentObjCConstraint = ObjectFile::Reader::kObjcGC; + break; + } + } + if ( reader->objcReplacementClasses() ) + fObjcReplacmentClasses = true; + + // check cpu sub-types for stricter sub-type + fCurrentCpuConstraint = (ObjectFile::Reader::CpuConstraint)reader->updateCpuConstraint(fCurrentCpuConstraint); +} + +inline void Linker::addAtoms(std::vector& atoms) +{ + bool scanAll = fOptions.readerOptions().fFullyLoadArchives || fOptions.readerOptions().fLoadAllObjcObjectsFromArchives; + bool first = true; + for (std::vector::iterator it=atoms.begin(); it != atoms.end(); it++) { + // usually we only need to get the first atom's reader, but + // with -all_load all atoms from all .o files come come back together + // so we need to scan all atoms + if ( first || scanAll ) { + // update fReadersThatHaveSuppliedAtoms + ObjectFile::Reader* reader = (*it)->getFile(); + if ( std::find(fReadersThatHaveSuppliedAtoms.begin(), fReadersThatHaveSuppliedAtoms.end(), reader) + == fReadersThatHaveSuppliedAtoms.end() ) { + fReadersThatHaveSuppliedAtoms.push_back(reader); + updateConstraints(reader); + } + } + this->addAtom(**it); + first = false; + } +} + +void Linker::logArchive(ObjectFile::Reader* reader) +{ + if ( (fArchiveReaders.count(reader) != 0) && (fArchiveReadersLogged.count(reader) == 0) ) { + fArchiveReadersLogged.insert(reader); + const char* fullPath = reader->getPath(); + char realName[MAXPATHLEN]; + if ( realpath(fullPath, realName) != NULL ) + fullPath = realName; + logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath); + } +} + + +void Linker::buildAtomList() +{ + fStartBuildAtomsTime = mach_absolute_time(); + // add initial undefines from -u option + std::vector& initialUndefines = fOptions.initialUndefines(); + for (std::vector::iterator it=initialUndefines.begin(); it != initialUndefines.end(); it++) { + fGlobalSymbolTable.require(*it); + } + + // writer can contribute atoms + this->addAtoms(fOutputFile->getAtoms()); + + // each reader contributes atoms + for (std::vector::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) { + ObjectFile::Reader* reader = *it; + std::vector& atoms = reader->getAtoms(); + this->addAtoms(atoms); + if ( fOptions.readerOptions().fTraceArchives && (atoms.size() != 0) ) + logArchive(reader); + } + + // extra command line section always at end + std::vector& extraSections = fOptions.extraSections(); + for( std::vector::iterator it=extraSections.begin(); it != extraSections.end(); ++it) { + this->addAtoms((new opaque_section::Reader(it->segmentName, it->sectionName, it->path, it->data, it->dataLen, fNextInputOrdinal))->getAtoms()); + fNextInputOrdinal += it->dataLen; + } +} + +static const char* pathLeafName(const char* path) +{ + const char* shortPath = strrchr(path, '/'); + if ( shortPath == NULL ) + return path; + else + return &shortPath[1]; +} + +void Linker::loadUndefines() +{ + // keep looping until no more undefines were added in last loop + unsigned int undefineCount = 0xFFFFFFFF; + while ( undefineCount != fGlobalSymbolTable.getRequireCount() ) { + undefineCount = fGlobalSymbolTable.getRequireCount(); + std::vector undefineNames; + fGlobalSymbolTable.getNeededNames(false, undefineNames); + for(std::vector::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) { + const char* name = *it; + ObjectFile::Atom* possibleAtom = fGlobalSymbolTable.find(name); + if ( (possibleAtom == NULL) + || ((possibleAtom->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition) + && (fOptions.outputKind() != Options::kObjectFile) + && (possibleAtom->getScope() == ObjectFile::Atom::scopeGlobal)) ) { + std::vector* atoms = this->addJustInTimeAtoms(name); + if ( atoms != NULL ) + delete atoms; + } + } + } +} + +// temp hack for rdar://problem/4718189 map ObjC class names to new runtime names +class ExportedObjcClass +{ +public: + ExportedObjcClass(Options& opt) : fOptions(opt) {} + + bool operator()(const char* name) const { + if ( fOptions.shouldExport(name) ) { + if ( strncmp(name, ".objc_class_name_", 17) == 0 ) + return true; + if ( strncmp(name, "_OBJC_CLASS_$_", 14) == 0 ) + return true; + if ( strncmp(name, "_OBJC_METACLASS_$_", 18) == 0 ) + return true; + } + //fprintf(stderr, "%s is not exported\n", name); + return false; + } +private: + Options& fOptions; +}; + + +void Linker::checkUndefines() +{ + // error out on any remaining undefines + bool doPrint = true; + bool doError = true; + switch ( fOptions.undefinedTreatment() ) { + case Options::kUndefinedError: + break; + case Options::kUndefinedDynamicLookup: + doError = false; + break; + case Options::kUndefinedWarning: + doError = false; + break; + case Options::kUndefinedSuppress: + doError = false; + doPrint = false; + break; + } + std::vector unresolvableUndefines; + fGlobalSymbolTable.getNeededNames(false, unresolvableUndefines); + + // temp hack for rdar://problem/4718189 map ObjC class names to new runtime names + // ignore unresolved references to Objc class names that are listed in -exported_symbols_list + if ( fOptions.hasExportRestrictList() ) + unresolvableUndefines.erase(std::remove_if(unresolvableUndefines.begin(), unresolvableUndefines.end(), ExportedObjcClass(fOptions)), unresolvableUndefines.end()); + + const int unresolvableCount = unresolvableUndefines.size(); + int unresolvableExportsCount = 0; + if ( unresolvableCount != 0 ) { + if ( doPrint ) { + if ( fOptions.printArchPrefix() ) + fprintf(stderr, "Undefined symbols for architecture %s:\n", fArchitectureName); + else + fprintf(stderr, "Undefined symbols:\n"); + for (int i=0; i < unresolvableCount; ++i) { + const char* name = unresolvableUndefines[i]; + fprintf(stderr, " \"%s\", referenced from:\n", name); + // scan all atoms for references + bool foundAtomReference = false; + for (std::vector::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) { + ObjectFile::Atom* atom = *it; + std::vector& references = atom->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + ObjectFile::Reference* reference = *rit; + if ( reference->getTargetBinding() == ObjectFile::Reference::kUnboundByName ) { + if ( strcmp(reference->getTargetName(), name) == 0 ) { + fprintf(stderr, " %s in %s\n", atom->getDisplayName(), pathLeafName(atom->getFile()->getPath())); + foundAtomReference = true; + } + } + if ( reference->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName ) { + if ( strcmp(reference->getFromTargetName(), name) == 0 ) { + fprintf(stderr, " %s in %s\n", atom->getDisplayName(), pathLeafName(atom->getFile()->getPath())); + foundAtomReference = true; + } + } + } + } + // scan command line options + if ( !foundAtomReference && fOptions.hasExportRestrictList() && fOptions.shouldExport(name) ) { + fprintf(stderr, " -exported_symbols_list command line option\n"); + ++unresolvableExportsCount; + } + } + } + if ( doError ) + throw "symbol(s) not found"; + } + + // for each tentative definition in symbol table look for dylib that exports same symbol name + if ( fGlobalSymbolTable.hasExternalTentativeDefinitions() ) { + for (SymbolTable::Mapper::iterator it=fGlobalSymbolTable.begin(); it != fGlobalSymbolTable.end(); ++it) { + ObjectFile::Atom* atom = it->second; + if ( (atom != NULL) && (atom->getDefinitionKind()==ObjectFile::Atom::kTentativeDefinition) + && (atom->getScope() == ObjectFile::Atom::scopeGlobal) ) { + // look for dylibs that export same name as used by global tentative definition + addJustInTimeAtoms(atom->getName(), true); + } + } + } + + // if we have no weak symbols, see if we override some weak symbol in some dylib + if ( !fGlobalSymbolTable.hasExternalWeakDefinitions() ) { + bool done = false; + for (SymbolTable::Mapper::iterator it=fGlobalSymbolTable.begin(); !done && (it != fGlobalSymbolTable.end()); ++it) { + ObjectFile::Atom* atom = it->second; + if ( (atom != NULL) && (atom->getDefinitionKind()==ObjectFile::Atom::kRegularDefinition) + && (atom->getScope() == ObjectFile::Atom::scopeGlobal) ) { + const char* name = atom->getName(); + //fprintf(stderr, "looking for dylibs with a weak %s\n", name); + // look for dylibs with weak exports of the same name + for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) { + ObjectFile::Reader* reader = it->second; + if ( reader->hasWeakExternals() ) { + std::vector* atoms = reader->getJustInTimeAtomsFor(name); + if ( atoms != NULL ) { + //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() ); + // if this is a weak definition in a dylib + if ( (atoms->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) { + fGlobalSymbolTable.setHasExternalWeakDefinitions(); + done = true; + break; + } + } + } + } + } + } + } + +} + + + +std::vector* Linker::addJustInTimeAtoms(const char* name, bool dylibsOnly) +{ + // when creating final linked image, writer gets first chance + if ( fOptions.outputKind() != Options::kObjectFile ) { + std::vector* atoms = fOutputFile->getJustInTimeAtomsFor(name); + if ( atoms != NULL ) { + this->addAtoms(*atoms); + //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fOutputFile->getPath() ); + return atoms; // found a definition, no need to search anymore + } + } + + // give readers a chance + for (std::vector::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) { + ObjectFile::Reader* reader = *it; + if ( reader != NULL ) { + // 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. + //fprintf(stderr, "addJustInTimeAtoms(%s), looking in reader %s\n", name, reader->getPath() ); + bool isDylibReader = (reader->getInstallPath() != NULL); + if ( !dylibsOnly || isDylibReader ) { + std::vector* atoms = reader->getJustInTimeAtomsFor(name); + if ( atoms != NULL ) { + this->addAtoms(*atoms); + //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() ); + if ( !isDylibReader && fOptions.readerOptions().fTraceArchives ) { + logArchive(reader); + } + // if this is a weak definition in a dylib + if ( isDylibReader && (atoms->size() == 1) && (atoms->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) { + // keep looking for a non-weak definition + } + else { + // found a definition, no need to search anymore + return atoms; + } + } + } + } + } + + // for two level namesapce, give all implicitly link dylibs a chance + if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) { + for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) { + if ( it->second->implicitlyLinked() ) { + //fprintf(stderr, "addJustInTimeAtoms(%s), looking in implicitly linked %s\n", name, it->second->getPath() ); + std::vector* atoms = it->second->getJustInTimeAtomsFor(name); + if ( atoms != NULL ) { + this->addAtoms(*atoms); + //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() ); + // if this is a weak definition in a dylib + if ( (atoms->size() == 1) && (atoms->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) { + // keep looking for a non-weak definition + } + else { + // found a definition, no need to search anymore + return atoms; + } + } + } + } + } + + // for flat namespace, give indirect dylibs + if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace ) { + for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) { + if ( ! it->second->explicitlyLinked() ) { + std::vector* atoms = it->second->getJustInTimeAtomsFor(name); + if ( atoms != NULL ) { + this->addAtoms(*atoms); + //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() ); + return atoms; // found a definition, no need to search anymore + } + } + } + } + + // writer creates a proxy in two cases: + // 1) ld -r is being used to create a .o file + // 2) -undefined dynamic_lookup is being used + // 3) -U _foo is being used + if ( (fOptions.outputKind() == Options::kObjectFile) + || ((fOptions.undefinedTreatment() != Options::kUndefinedError) && !dylibsOnly) + || (fOptions.someAllowedUndefines() && !dylibsOnly) ) { + ObjectFile::Atom* atom = fOutputFile->getUndefinedProxyAtom(name); + if ( atom != NULL ) { + this->addAtom(*atom); + return NULL; + } + } + //fprintf(stderr, "addJustInTimeAtoms(%s) => not found\n", name); + return NULL; +} + +void Linker::resolve(ObjectFile::Reference* reference) +{ + // look in global symbol table + const char* targetName = reference->getTargetName(); + ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName); + if ( target == NULL ) { + fprintf(stderr, "Undefined symbol: %s\n", targetName); + } + reference->setTarget(*target, reference->getTargetOffset()); +} + +void Linker::resolveFrom(ObjectFile::Reference* reference) +{ + // handle references that have two (from and to) targets + const char* fromTargetName = reference->getFromTargetName(); + ObjectFile::Atom* fromTarget = fGlobalSymbolTable.find(fromTargetName); + if ( fromTarget == NULL ) { + fprintf(stderr, "Undefined symbol: %s\n", fromTargetName); + } + reference->setFromTarget(*fromTarget); +} + + +void Linker::resolveReferences() +{ + // note: the atom list may grow during this loop as libraries supply needed atoms + for (unsigned int j=0; j < fAllAtoms.size(); ++j) { + ObjectFile::Atom* atom = fAllAtoms[j]; + std::vector& references = atom->getReferences(); + for (std::vector::iterator it=references.begin(); it != references.end(); it++) { + ObjectFile::Reference* reference = *it; + if ( reference->getTargetBinding() == ObjectFile::Reference::kUnboundByName ) + this->resolve(reference); + if ( reference->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName ) + this->resolveFrom(reference); + } + } +} + + +// used to remove stabs associated with atoms that won't be in output file +class NotInSet +{ +public: + NotInSet(std::set& theSet) : fSet(theSet) {} + + bool operator()(const ObjectFile::Reader::Stab& stab) const { + if ( stab.atom == NULL ) + return false; // leave stabs that are not associated with any atome + else + return ( fSet.count(stab.atom) == 0 ); + } + +private: + std::set& fSet; +}; + + +class NotLive +{ +public: + NotLive(std::set& set) : fLiveAtoms(set) {} + + bool operator()(ObjectFile::Atom*& atom) const { + //if ( fLiveAtoms.count(atom) == 0 ) + // fprintf(stderr, "dead strip %s\n", atom->getDisplayName()); + return ( fLiveAtoms.count(atom) == 0 ); + } +private: + std::set& fLiveAtoms; +}; + + +void Linker::addJustInTimeAtomsAndMarkLive(const char* name) +{ + std::vector* atoms = this->addJustInTimeAtoms(name); + if ( atoms != NULL ) { + if ( fOptions.allGlobalsAreDeadStripRoots() ) { + for (std::vector::iterator it=atoms->begin(); it != atoms->end(); it++) { + ObjectFile::Atom* atom = *it; + if ( atom->getScope() == ObjectFile::Atom::scopeGlobal ) { + WhyLiveBackChain rootChain; + rootChain.previous = NULL; + rootChain.name = atom->getDisplayName(); + this->markLive(*atom, &rootChain); + } + } + } + delete atoms; + } +} + +void Linker::markLive(ObjectFile::Atom& atom, struct Linker::WhyLiveBackChain* previous) +{ + if ( fLiveAtoms.count(&atom) == 0 ) { + // if -whylive cares about this symbol, then dump chain + if ( (previous->name != NULL) && fOptions.printWhyLive(previous->name) ) { + int depth = 0; + for(WhyLiveBackChain* p = previous; p != NULL; p = p->previous, ++depth) { + for(int i=depth; i > 0; --i) + fprintf(stderr, " "); + fprintf(stderr, "%s\n", p->name); + } + } + // set up next chain + WhyLiveBackChain thisChain; + thisChain.previous = previous; + // this atom is live + fLiveAtoms.insert(&atom); + // update total size info (except for __ZEROPAGE atom) + if ( atom.getSegment().isContentReadable() ) { + fTotalSize += atom.getSize(); + if ( atom.isZeroFill() ) + fTotalZeroFillSize += atom.getSize(); + } + // and all atoms it references + std::vector& references = atom.getReferences(); + for (std::vector::iterator it=references.begin(); it != references.end(); it++) { + ObjectFile::Reference* reference = *it; + if ( reference->getTargetBinding() == ObjectFile::Reference::kUnboundByName ) { + // look in global symbol table + const char* targetName = reference->getTargetName(); + ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName); + if ( target == NULL ) { + // load archives or dylibs + this->addJustInTimeAtomsAndMarkLive(targetName); + } + // look again + target = fGlobalSymbolTable.find(targetName); + if ( target != NULL ) { + reference->setTarget(*target, reference->getTargetOffset()); + } + else { + // mark as undefined, for later error processing + fAtomsWithUnresolvedReferences.push_back(&atom); + fGlobalSymbolTable.require(targetName); + } + } + switch ( reference->getTargetBinding() ) { + case ObjectFile::Reference::kBoundDirectly: + case ObjectFile::Reference::kBoundByName: + thisChain.name = reference->getTargetName(); + markLive(reference->getTarget(), &thisChain); + break; + case ObjectFile::Reference::kDontBind: + addDtraceProbe(atom, reference->getFixUpOffset(), reference->getTargetName()); + break; + case ObjectFile::Reference::kUnboundByName: + // do nothing + break; + } + // do the same as above, for "from target" + if ( reference->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName ) { + // look in global symbol table + const char* targetName = reference->getFromTargetName(); + ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName); + if ( target == NULL ) { + // load archives or dylibs + this->addJustInTimeAtomsAndMarkLive(targetName); + } + // look again + target = fGlobalSymbolTable.find(targetName); + if ( target != NULL ) { + reference->setFromTarget(*target); + } + else { + // mark as undefined, for later error processing + fGlobalSymbolTable.require(targetName); + } + } + switch ( reference->getFromTargetBinding() ) { + case ObjectFile::Reference::kBoundDirectly: + case ObjectFile::Reference::kBoundByName: + thisChain.name = reference->getFromTargetName(); + markLive(reference->getFromTarget(), &thisChain); + break; + case ObjectFile::Reference::kUnboundByName: + case ObjectFile::Reference::kDontBind: + // do nothing + break; + } + } + } +} + + +void Linker::addLiveRoot(const char* name) +{ + ObjectFile::Atom* target = fGlobalSymbolTable.find(name); + if ( target == NULL ) { + this->addJustInTimeAtomsAndMarkLive(name); + target = fGlobalSymbolTable.find(name); + } + if ( target != NULL ) + fLiveRootAtoms.insert(target); +} + + +void Linker::deadStripResolve() +{ + // add main() to live roots + ObjectFile::Atom* entryPoint = this->entryPoint(false); + if ( entryPoint != NULL ) + fLiveRootAtoms.insert(entryPoint); + + // add dyld_stub_binding_helper() to live roots + ObjectFile::Atom* dyldHelper = this->dyldHelper(); + if ( dyldHelper != NULL ) + fLiveRootAtoms.insert(dyldHelper); + + // if using lazy dylib loading, add dyld_lazy_dylib_stub_binding_helper() to live roots + if ( fOptions.usingLazyDylibLinking() ) { + ObjectFile::Atom* dyldLazyDylibHelper = this->dyldLazyLibraryHelper(); + if ( dyldLazyDylibHelper != NULL ) + fLiveRootAtoms.insert(dyldLazyDylibHelper); + } + + // add -exported_symbols_list, -init, and -u entries to live roots + std::vector& initialUndefines = fOptions.initialUndefines(); + for (std::vector::iterator it=initialUndefines.begin(); it != initialUndefines.end(); it++) + addLiveRoot(*it); + + // if -exported_symbols_list that has wildcards, we need to find all matches and make them the roots + // + if ( fOptions.hasWildCardExportRestrictList() ) { + for (std::vector::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) { + ObjectFile::Atom* atom = *it; + if ( (atom->getScope() == ObjectFile::Atom::scopeGlobal) + && (fDeadAtoms.count(atom) == 0) + && fOptions.shouldExport(atom->getName()) ) + fLiveRootAtoms.insert(atom); + } + } + + // in some cases, every global scope atom in initial .o files is a root + if ( fOptions.allGlobalsAreDeadStripRoots() ) { + for (std::vector::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) { + ObjectFile::Atom* atom = *it; + if ( (atom->getScope() == ObjectFile::Atom::scopeGlobal) && (fDeadAtoms.count(atom) == 0) ) + fLiveRootAtoms.insert(atom); + } + } + + // mark all roots as live, and all atoms they reference + for (std::set::iterator it=fLiveRootAtoms.begin(); it != fLiveRootAtoms.end(); it++) { + WhyLiveBackChain rootChain; + rootChain.previous = NULL; + rootChain.name = (*it)->getDisplayName(); + markLive(**it, &rootChain); + } + + // it is possible that there are unresolved references that can be resolved now + // this can happen if the first reference to a common symbol in an archive. + // common symbols are not in the archive TOC, but the .o could have been pulled in later. + // ld64 while linking cc1 [ when dead_strip is ON] + for (std::vector::iterator it=fAtomsWithUnresolvedReferences.begin(); it != fAtomsWithUnresolvedReferences.end(); it++) { + std::vector& references = (*it)->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + ObjectFile::Reference* reference = *rit; + if ( reference->getTargetBinding() == ObjectFile::Reference::kUnboundByName ) { + ObjectFile::Atom* target = fGlobalSymbolTable.find(reference->getTargetName()); + if ( target != NULL ) { + reference->setTarget(*target, reference->getTargetOffset()); + fLiveAtoms.insert(target); + // by just adding this atom to fLiveAtoms set, we are assuming it has no + // references, which is true for commons. + if ( target->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) + warning("internal error %s is not a tentative definition", target->getDisplayName()); + } + } + if ( reference->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName ) { + ObjectFile::Atom* target = fGlobalSymbolTable.find(reference->getFromTargetName()); + if ( target != NULL ) { + reference->setFromTarget(*target); + fLiveAtoms.insert(target); + // by just adding this atom to fLiveAtoms set, we are assuming it has no + // references, which is true for commons. + if ( target->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) + warning("internal error %s is not a tentative definition", target->getDisplayName()); + } + } + } + } + + // now remove all non-live atoms from fAllAtoms + fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), NotLive(fLiveAtoms)), fAllAtoms.end()); +} + +void Linker::checkObjC() +{ + // check dylibs + switch ( fCurrentObjCConstraint ) { + case ObjectFile::Reader::kObjcNone: + // can link against any dylib + break; + case ObjectFile::Reader::kObjcRetainRelease: + // cannot link against GC-only dylibs + for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) { + if ( it->second->explicitlyLinked() ) { + if ( it->second->getObjCConstraint() == ObjectFile::Reader::kObjcGC ) + throwf("this linkage unit uses Retain/Release. It cannot link against the GC-only dylib: %s", it->second->getPath()); + } + } + break; + case ObjectFile::Reader::kObjcRetainReleaseOrGC: + // can link against GC or RR dylibs + break; + case ObjectFile::Reader::kObjcGC: + // cannot link against RR-only dylibs + for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) { + if ( it->second->explicitlyLinked() ) { + if ( it->second->getObjCConstraint() == ObjectFile::Reader::kObjcRetainRelease ) + throwf("this linkage unit requires GC. It cannot link against Retain/Release dylib: %s", it->second->getPath()); + } + } + break; + } + + // synthesize __OBJC __image_info atom if needed + if ( fCurrentObjCConstraint != ObjectFile::Reader::kObjcNone ) { + this->addAtom(fOutputFile->makeObjcInfoAtom(fCurrentObjCConstraint, fObjcReplacmentClasses)); + } +} + +void Linker::addDtraceProbe(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* probeName) +{ + if ( probeName != NULL ) { + if ( strncmp(probeName, "___dtrace_probe$", 16) == 0 ) + fDtraceProbeSites.push_back(DTraceProbeInfo(&atom, offsetInAtom, probeName)); + else if ( strncmp(probeName, "___dtrace_isenabled$", 20) == 0 ) + fDtraceIsEnabledSites.push_back(DTraceProbeInfo(&atom, offsetInAtom, probeName)); + else if ( strncmp(probeName, "___dtrace_", 10) == 0 ) + fDtraceAtomToTypes[&atom].insert(probeName); + else if ( fOptions.dTrace() && (strncmp(probeName, "__dtrace_probe$", 15) == 0) ) + fDtraceProbes.push_back(DTraceProbeInfo(&atom, offsetInAtom, probeName)); + } +} + +static uint8_t pointerKind(cpu_type_t arch) +{ + switch ( arch ) { + case CPU_TYPE_POWERPC: + return ppc::kPointer; + case CPU_TYPE_POWERPC64: + return ppc64::kPointer; + case CPU_TYPE_I386: + return x86::kPointer; + case CPU_TYPE_X86_64: + return x86_64::kPointer; + case CPU_TYPE_ARM: + return arm::kPointer; + } + throw "uknown architecture"; +} + +static uint8_t pcRelKind(cpu_type_t arch) +{ + switch ( arch ) { + case CPU_TYPE_POWERPC: + return ppc::kPointerDiff32; + case CPU_TYPE_POWERPC64: + return ppc64::kPointerDiff32; + case CPU_TYPE_I386: + return x86::kPointerDiff; + case CPU_TYPE_X86_64: + return x86_64::kPointerDiff32; + case CPU_TYPE_ARM: + return arm::kPointerDiff; + } + throw "uknown architecture"; +} + +typedef uint8_t* (*oldcreatedof_func_t) (const char*, cpu_type_t, unsigned int, const char*[], const char*[], uint64_t offsetsInDOF[], size_t* size); +typedef uint8_t* (*createdof_func_t)(cpu_type_t, unsigned int, const char*[], unsigned int, const char*[], const char*[], uint64_t offsetsInDOF[], size_t* size); + + +void Linker::processDTrace() +{ + // handle dtrace 2.0 static probes + if ( (fOptions.outputKind() != Options::kObjectFile) && ((fDtraceProbeSites.size() != 0) || (fDtraceIsEnabledSites.size() != 0)) ) { + // partition probes by provider name + // The symbol names looks like: + // "___dtrace_isenabled$" provider-name "$" probe-name [ "$"... ] + // "___dtrace_probe$" provider-name "$" probe-name [ "$"... ] + ProviderToProbes providerToProbes; + std::vector emptyList; + for(std::vector::iterator it = fDtraceProbeSites.begin(); it != fDtraceProbeSites.end(); ++it) { + // ignore probes in functions that were coalesed away rdar://problem/5628149 + if ( fDeadAtoms.count((ObjectFile::Atom*)(it->atom)) == 0 ) { + const char* providerStart = &it->probeName[16]; + const char* providerEnd = strchr(providerStart, '$'); + if ( providerEnd != NULL ) { + char providerName[providerEnd-providerStart+1]; + strlcpy(providerName, providerStart, providerEnd-providerStart+1); + ProviderToProbes::iterator pos = providerToProbes.find(providerName); + if ( pos == providerToProbes.end() ) { + const char* dup = strdup(providerName); + providerToProbes[dup] = emptyList; + } + providerToProbes[providerName].push_back(*it); + } + } + } + for(std::vector::iterator it = fDtraceIsEnabledSites.begin(); it != fDtraceIsEnabledSites.end(); ++it) { + // ignore probes in functions that were coalesed away rdar://problem/5628149 + if ( fDeadAtoms.count((ObjectFile::Atom*)(it->atom)) == 0 ) { + const char* providerStart = &it->probeName[20]; + const char* providerEnd = strchr(providerStart, '$'); + if ( providerEnd != NULL ) { + char providerName[providerEnd-providerStart+1]; + strlcpy(providerName, providerStart, providerEnd-providerStart+1); + ProviderToProbes::iterator pos = providerToProbes.find(providerName); + if ( pos == providerToProbes.end() ) { + const char* dup = strdup(providerName); + providerToProbes[dup] = emptyList; + } + providerToProbes[providerName].push_back(*it); + } + } + } + + // create a DOF section for each provider + int dofIndex=1; + CStringSet sectionNamesUsed; + for(ProviderToProbes::iterator pit = providerToProbes.begin(); pit != providerToProbes.end(); ++pit, ++dofIndex) { + const char* providerName = pit->first; + const std::vector& probes = pit->second; + + // open library and find dtrace_create_dof() + void* handle = dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY); + if ( handle == NULL ) + throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s", dlerror()); + createdof_func_t pCreateDOF = (createdof_func_t)dlsym(handle, "dtrace_ld_create_dof"); + if ( pCreateDOF == NULL ) + throwf("couldn't find \"dtrace_ld_create_dof\" in /usr/lib/libdtrace.dylib: %s", dlerror()); + // build list of typedefs/stability infos for this provider + CStringSet types; + for(std::vector::const_iterator it = probes.begin(); it != probes.end(); ++it) { + std::map::iterator pos = fDtraceAtomToTypes.find(it->atom); + if ( pos != fDtraceAtomToTypes.end() ) { + for(CStringSet::iterator sit = pos->second.begin(); sit != pos->second.end(); ++sit) { + const char* providerStart = strchr(*sit, '$')+1; + const char* providerEnd = strchr(providerStart, '$'); + if ( providerEnd != NULL ) { + char aProviderName[providerEnd-providerStart+1]; + strlcpy(aProviderName, providerStart, providerEnd-providerStart+1); + if ( strcmp(aProviderName, providerName) == 0 ) + types.insert(*sit); + } + } + } + } + int typeCount = types.size(); + const char* typeNames[typeCount]; + //fprintf(stderr, "types for %s:\n", providerName); + uint32_t index = 0; + for(CStringSet::iterator it = types.begin(); it != types.end(); ++it) { + typeNames[index] = *it; + //fprintf(stderr, "\t%s\n", *it); + ++index; + } + + // build list of probe/isenabled sites + const uint32_t probeCount = probes.size(); + const char* probeNames[probeCount]; + const char* funtionNames[probeCount]; + uint64_t offsetsInDOF[probeCount]; + index = 0; + for(std::vector::const_iterator it = probes.begin(); it != probes.end(); ++it) { + probeNames[index] = it->probeName; + funtionNames[index] = it->atom->getName(); + offsetsInDOF[index] = 0; + ++index; + } + //fprintf(stderr, "calling libtrace to create DOF\n"); + //for(uint32_t i=0; i < probeCount; ++i) + // fprintf(stderr, " [%u]\t %s\t%s\n", i, probeNames[i], funtionNames[i]); + // call dtrace library to create DOF section + size_t dofSectionSize; + uint8_t* p = (*pCreateDOF)(fArchitecture, typeCount, typeNames, probeCount, probeNames, funtionNames, offsetsInDOF, &dofSectionSize); + if ( p != NULL ) { + char sectionName[18]; + strcpy(sectionName, "__dof_"); + strlcpy(§ionName[6], providerName, 10); + // create unique section name so each DOF is in its own section + if ( sectionNamesUsed.count(sectionName) != 0 ) { + sectionName[15] = '0'; + sectionName[16] = '\0'; + while ( sectionNamesUsed.count(sectionName) != 0 ) + ++sectionName[15]; + } + sectionNamesUsed.insert(sectionName); + char symbolName[strlen(providerName)+64]; + sprintf(symbolName, "__dtrace_dof_for_provider_%s", providerName); + opaque_section::Reader* reader = new opaque_section::Reader("__TEXT", sectionName, + "dtrace", p, dofSectionSize, fNextInputOrdinal, symbolName); + fNextInputOrdinal += dofSectionSize; + // add references + for (uint32_t i=0; i < probeCount; ++i) { + uint64_t offset = offsetsInDOF[i]; + //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset); + if ( offset > dofSectionSize ) + throwf("offsetsInDOF[i]=%0llX > dofSectionSize=%0lX\n", i, offset, dofSectionSize); + reader->addSectionReference(pcRelKind(fArchitecture), offset, probes[i].atom, probes[i].offset, reader->getAtoms()[0], 0); + } + this->addAtoms(reader->getAtoms()); + } + else { + throw "error creating dtrace DOF section"; + } + } + } + // create a __DATA __dof section iff -dtrace option was used and static probes were found in .o files + else if ( fOptions.dTrace() && (fDtraceProbes.size() != 0) ) { + const uint32_t probeCount = fDtraceProbes.size(); + const char* labels[probeCount]; + const char* funtionNames[probeCount]; + uint64_t offsetsInDOF[probeCount]; + + // open libray and find dtrace_ld64_create_dof() + void* handle = dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY); + if ( handle == NULL ) + throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s\n", dlerror()); + oldcreatedof_func_t pCreateDOF = (oldcreatedof_func_t)dlsym(handle, "dtrace_ld64_create_dof"); + if ( pCreateDOF == NULL ) + throwf("couldn't find \"dtrace_ld64_create_dof\" in /usr/lib/libdtrace.dylib: %s\n", dlerror()); + + // build argument list + uint32_t index = 0; + for(std::vector::iterator it = fDtraceProbes.begin(); it != fDtraceProbes.end(); ++it) { + labels[index] = it->probeName; + funtionNames[index] = it->atom->getName(); + offsetsInDOF[index] = 0; + ++index; + } + size_t dofSectionSize; + // call dtrace library to create DOF section + uint8_t* p = (*pCreateDOF)(fOptions.dTraceScriptName(), fArchitecture, probeCount, labels, funtionNames, offsetsInDOF, &dofSectionSize); + if ( p != NULL ) { + opaque_section::Reader* reader = new opaque_section::Reader("__DATA", "__dof", "dtrace", p, dofSectionSize, fNextInputOrdinal); + fNextInputOrdinal += dofSectionSize; + // add references + for (uint32_t i=0; i < probeCount; ++i) { + uint64_t offset = offsetsInDOF[i]; + if ( offset > dofSectionSize ) + throwf("offsetsInDOF[i]=%0llX > dofSectionSize=%0lX", i, offset, dofSectionSize); + reader->addSectionReference(pointerKind(fArchitecture), offset, fDtraceProbes[i].atom, fDtraceProbes[i].offset); + } + this->addAtoms(reader->getAtoms()); + } + else { + throw "error created dtrace DOF section"; + } + } +} + + +static bool matchesObjectFile(ObjectFile::Atom* atom, const char* objectFileLeafName) +{ + if ( objectFileLeafName == NULL ) + return true; + const char* atomFullPath = atom->getFile()->getPath(); + const char* lastSlash = strrchr(atomFullPath, '/'); + if ( lastSlash != NULL ) { + if ( strcmp(&lastSlash[1], objectFileLeafName) == 0 ) + return true; + } + else { + if ( strcmp(atomFullPath, objectFileLeafName) == 0 ) + return true; + } + return false; +} + + +static bool usesAnonymousNamespace(const char* symbol) +{ + return ( (strncmp(symbol, "__Z", 3) == 0) && (strstr(symbol, "_GLOBAL__N_") != NULL) ); +} + + +// +// convert: +// __ZN20_GLOBAL__N__Z5main2v3barEv => _ZN-3barEv +// __ZN37_GLOBAL__N_main.cxx_00000000_493A01A33barEv => _ZN-3barEv +// +static void canonicalizeAnonymousName(const char* inSymbol, char outSymbol[]) +{ + const char* globPtr = strstr(inSymbol, "_GLOBAL__N_"); + while ( isdigit(*(--globPtr)) ) + ; // loop + char* endptr; + unsigned long length = strtoul(globPtr+1, &endptr, 10); + const char* globEndPtr = endptr + length; + int startLen = globPtr-inSymbol+1; + memcpy(outSymbol, inSymbol, startLen); + outSymbol[startLen] = '-'; + strcpy(&outSymbol[startLen+1], globEndPtr); +} + + +ObjectFile::Atom* Linker::findAtom(const Options::OrderedSymbol& orderedSymbol) +{ + ObjectFile::Atom* atom = fGlobalSymbolTable.find(orderedSymbol.symbolName); + if ( atom != NULL ) { + if ( matchesObjectFile(atom, orderedSymbol.objectFileName) ) + return atom; + } + else { + // slow case. The requested symbol is not in symbol table, so might be static function + static SymbolTable::Mapper hashTableOfTranslationUnitScopedSymbols; + static SymbolTable::Mapper hashTableOfSymbolsWithAnonymousNamespace; + static bool built = false; + // build a hash_map the first time + if ( !built ) { + for (std::vector::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) { + atom = *it; + const char* name = atom->getName(); + if ( name != NULL) { + if ( usesAnonymousNamespace(name) ) { + // symbol that uses anonymous namespace + char canonicalName[strlen(name)+2]; + canonicalizeAnonymousName(name, canonicalName); + const char* hashName = strdup(canonicalName); + SymbolTable::Mapper::iterator pos = hashTableOfSymbolsWithAnonymousNamespace.find(hashName); + if ( pos == hashTableOfSymbolsWithAnonymousNamespace.end() ) + hashTableOfSymbolsWithAnonymousNamespace[hashName] = atom; + else + hashTableOfSymbolsWithAnonymousNamespace[hashName] = NULL; // collision, denote with NULL + } + else if ( atom->getScope() == ObjectFile::Atom::scopeTranslationUnit ) { + // static function or data + SymbolTable::Mapper::iterator pos = hashTableOfTranslationUnitScopedSymbols.find(name); + if ( pos == hashTableOfTranslationUnitScopedSymbols.end() ) + hashTableOfTranslationUnitScopedSymbols[name] = atom; + else + hashTableOfTranslationUnitScopedSymbols[name] = NULL; // collision, denote with NULL + } + } + } + //fprintf(stderr, "built hash table of %lu static functions\n", hashTableOfTranslationUnitScopedSymbols.size()); + built = true; + } + + // look for name in hashTableOfTranslationUnitScopedSymbols + SymbolTable::Mapper::iterator pos = hashTableOfTranslationUnitScopedSymbols.find(orderedSymbol.symbolName); + if ( pos != hashTableOfTranslationUnitScopedSymbols.end() ) { + if ( (pos->second != NULL) && matchesObjectFile(pos->second, orderedSymbol.objectFileName) ) { + //fprintf(stderr, "found %s in hash table\n", orderedSymbol.symbolName); + return pos->second; + } + if ( pos->second == NULL ) + // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way + for (std::vector::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) { + atom = *it; + if ( atom->getScope() == ObjectFile::Atom::scopeTranslationUnit ) { + const char* name = atom->getName(); + if ( (name != NULL) && (strcmp(name, orderedSymbol.symbolName) == 0) ) { + if ( matchesObjectFile(atom, orderedSymbol.objectFileName) ) { + if ( fOptions.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; + } + } + } + } + } + + // look for name in hashTableOfSymbolsWithAnonymousNamespace + if ( usesAnonymousNamespace(orderedSymbol.symbolName) ) { + // symbol that uses anonymous namespace + char canonicalName[strlen(orderedSymbol.symbolName)+2]; + canonicalizeAnonymousName(orderedSymbol.symbolName, canonicalName); + SymbolTable::Mapper::iterator pos = hashTableOfSymbolsWithAnonymousNamespace.find(canonicalName); + if ( pos != hashTableOfSymbolsWithAnonymousNamespace.end() ) { + if ( (pos->second != NULL) && matchesObjectFile(pos->second, orderedSymbol.objectFileName) ) { + //fprintf(stderr, "found %s in anonymous namespace hash table\n", canonicalName); + return pos->second; + } + if ( pos->second == NULL ) + // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way + for (std::vector::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) { + atom = *it; + const char* name = atom->getName(); + if ( (name != NULL) && usesAnonymousNamespace(name) ) { + char canonicalAtomName[strlen(name)+2]; + canonicalizeAnonymousName(name, canonicalAtomName); + if ( strcmp(canonicalAtomName, canonicalName) == 0 ) { + if ( matchesObjectFile(atom, orderedSymbol.objectFileName) ) { + if ( fOptions.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; + } + } + } + } + } + } + } + return NULL; +} + + +void Linker::sortSections() +{ + Section::assignIndexes(); +} + + +// +// Linker::sortAtoms() +// +// The purpose of this method is to take the graph of all Atoms and produce an ordered +// sequence of atoms. The constraints are that: 1) all Atoms of the same Segment must +// be contiguous, 2) all Atoms of the same Section must be contigous, 3) Atoms specified +// in an order_file are seqenced as in the order_file and before Atoms not specified, +// 4) Atoms in the same section from the same .o file should be contiguous and sequenced +// in the same order they were in the .o file, 5) Atoms in the same Section but which came +// from different .o files should be sequenced in the same order that the .o files +// were passed to the linker (i.e. command line order). +// +// The way this is implemented is that the linker passes a "base ordinal" to each Reader +// as it is constructed. The reader should construct it Atoms so that calling getOrdinal() +// on its atoms returns a contiguous range of values starting at the base ordinal. Then +// sorting is just sorting by section, then by ordinal. +// +// If an order_file is specified, it gets more complicated. First, an override-ordinal map +// is created. It causes the sort routine to ignore the value returned by getOrdinal() and +// use the override value instead. Next some Atoms must be layed out consecutively +// (e.g. hand written assembly that does not end with return, but rather falls into +// the next label). This is modeled in Readers via a "kFollowOn" reference. The use of +// kFollowOn refernces produces "clusters" of atoms that must stay together. +// If an order_file tries to move one atom, it may need to move a whole cluster. The +// algorithm to do this models clusters using two maps. The "starts" maps maps any +// atom in a cluster to the first Atom in the cluster. The "nexts" maps an Atom in a +// cluster to the next Atom in the cluster. With this in place, while processing an +// order_file, if any entry is in a cluster (in "starts" map), then the entire cluster is +// given ordinal overrides. +// +void Linker::sortAtoms() +{ + fStartSortTime = mach_absolute_time(); + // if -order_file is used, build map of atom ordinal overrides + std::map* ordinalOverrideMap = NULL; + std::map theOrdinalOverrideMap; + const bool log = false; + if ( fOptions.orderedSymbols().size() != 0 ) { + // first make a pass to find all follow-on references and build start/next maps + // which are a way to represent clusters of atoms that must layout together + std::map followOnStarts; + std::map followOnNexts; + for (std::vector::iterator ait=fAllAtoms.begin(); ait != fAllAtoms.end(); ait++) { + ObjectFile::Atom* atom = *ait; + std::vector& references = atom->getReferences(); + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + ObjectFile::Reference* ref = *rit; + if ( ref->getKind() == 1 ) { // FIX FIX + ObjectFile::Atom* targetAtom = &ref->getTarget(); + if ( log ) fprintf(stderr, "ref %s -> %s", atom->getDisplayName(), targetAtom->getDisplayName()); + std::map::iterator startFrom = followOnStarts.find(atom); + std::map::iterator startTo = followOnStarts.find(targetAtom); + if ( (startFrom == followOnStarts.end()) && (startTo == followOnStarts.end()) ) { + // this is first time we've seen either atom, make simple cluster of the two + if ( log ) fprintf(stderr, " new cluster\n"); + followOnStarts[atom] = atom; + followOnStarts[targetAtom] = atom; + followOnNexts[atom] = targetAtom; + followOnNexts[targetAtom] = NULL; + } + else if ( (startFrom != followOnStarts.end()) && (startTo == followOnStarts.end()) && (followOnNexts[atom] == NULL) ) { + // atom is at end of an existing cluster, so append target to end of cluster + if ( log ) fprintf(stderr, " end of cluster starting with %s\n", followOnStarts[atom]->getDisplayName()); + followOnNexts[atom] = targetAtom; + followOnNexts[targetAtom] = NULL; + followOnStarts[targetAtom] = followOnStarts[atom]; + } + else { + // gerneral case of inserting into an existing cluster + if ( followOnNexts[atom] != NULL ) { + // an atom with two follow-ons is illegal + warning("can't order %s because both %s and %s must follow it", + atom->getDisplayName(), targetAtom->getDisplayName(), followOnNexts[atom]->getDisplayName()); + } + else { + // there already exists an atom that says target must be its follow-on + const ObjectFile::Atom* originalStart = startTo->second; + const ObjectFile::Atom* originalPrevious = originalStart; + while ( followOnNexts[originalPrevious] != targetAtom ) + originalPrevious = followOnNexts[originalPrevious]; + bool otherIsAlias = (originalPrevious->getSize() == 0); + bool thisIsAlias = (atom->getSize() == 0); + if ( !otherIsAlias && !thisIsAlias ) { + warning("can't order %s because both %s and %s must preceed it", + targetAtom->getDisplayName(), originalPrevious->getDisplayName(), atom->getDisplayName()); + } + else if ( otherIsAlias ) { + if ( originalPrevious == originalStart ) { + // other is alias at start of cluster, make this the new start of cluster + if ( log ) fprintf(stderr, " becomes new start of cluster previous starting with %s\n", originalStart->getDisplayName()); + followOnNexts[atom] = originalPrevious; + for(const ObjectFile::Atom* nextAtom = atom; nextAtom != NULL; nextAtom = followOnNexts[nextAtom]) + followOnStarts[nextAtom] = atom; + } + else { + // other is alias in middle of cluster, insert new atom before it + if ( log ) fprintf(stderr, " insert into cluster starting with %s before alias %s\n", originalStart->getDisplayName(), originalPrevious->getDisplayName()); + followOnStarts[atom] = originalStart; + followOnNexts[atom] = originalPrevious; + for(const ObjectFile::Atom* a = originalStart; a != NULL; a = followOnNexts[a]) { + if ( followOnNexts[a] == originalPrevious ) { + followOnNexts[a] = atom; + break; + } + } + } + } + else { + // this is alias, so it can go inbetween originalPrevious and targetAtom + if ( log ) fprintf(stderr, " insert into cluster starting with %s after %s\n", originalStart->getDisplayName(), originalPrevious->getDisplayName()); + followOnStarts[atom] = originalStart; + followOnNexts[atom] = followOnNexts[originalPrevious]; + followOnNexts[originalPrevious] = atom; + } + } + } + } + } + } + + if ( log ) { + for(std::map::iterator it = followOnStarts.begin(); it != followOnStarts.end(); ++it) + fprintf(stderr, "start %s -> %s\n", it->first->getDisplayName(), it->second->getDisplayName()); + + for(std::map::iterator it = followOnNexts.begin(); it != followOnNexts.end(); ++it) + fprintf(stderr, "next %s -> %s\n", it->first->getDisplayName(), (it->second != NULL) ? it->second->getDisplayName() : "null"); + } + + // with the start/next maps of follow-on atoms we can process the order file and produce override ordinals + ordinalOverrideMap = &theOrdinalOverrideMap; + uint32_t index = 0; + uint32_t matchCount = 0; + std::vector& orderedSymbols = fOptions.orderedSymbols(); + for(std::vector::iterator it = orderedSymbols.begin(); it != orderedSymbols.end(); ++it) { + ObjectFile::Atom* atom = this->findAtom(*it); + if ( atom != NULL ) { + std::map::iterator start = followOnStarts.find(atom); + if ( start != followOnStarts.end() ) { + // this symbol for the order file corresponds to an atom that is in a cluster that must lay out together + for(const ObjectFile::Atom* nextAtom = start->second; nextAtom != NULL; nextAtom = followOnNexts[nextAtom]) { + std::map::iterator pos = theOrdinalOverrideMap.find(nextAtom); + if ( pos == theOrdinalOverrideMap.end() ) { + theOrdinalOverrideMap[nextAtom] = index++; + if (log ) fprintf(stderr, "override ordinal %u assigned to %s in cluster from %s\n", index, nextAtom->getDisplayName(), nextAtom->getFile()->getPath()); + } + else { + if (log ) fprintf(stderr, "could not order %s as %u because it was already laid out earlier by %s as %u\n", + atom->getDisplayName(), index, followOnStarts[atom]->getDisplayName(), theOrdinalOverrideMap[atom] ); + } + } + } + else { + theOrdinalOverrideMap[atom] = index; + if (log ) fprintf(stderr, "override ordinal %u assigned to %s from %s\n", index, atom->getDisplayName(), atom->getFile()->getPath()); + } + } + else { + ++matchCount; + //fprintf(stderr, "can't find match for order_file entry %s/%s\n", it->objectFileName, it->symbolName); + } + ++index; + } + if ( fOptions.printOrderFileStatistics() && (fOptions.orderedSymbols().size() != matchCount) ) { + warning("only %u out of %lu order_file symbols were applicable", matchCount, fOptions.orderedSymbols().size() ); + } + } + + // sort atoms + std::sort(fAllAtoms.begin(), fAllAtoms.end(), Linker::AtomSorter(ordinalOverrideMap)); + + //fprintf(stderr, "Sorted atoms:\n"); + //for (std::vector::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) { + // fprintf(stderr, "\t%p, %u %s\n", (*it)->getSection(), (*it)->getSection()->getIndex(), (*it)->getDisplayName()); + //} +} + + +// make sure given addresses are within reach of branches, etc +void Linker::tweakLayout() +{ + // > 2GB images need their large zero fill atoms sorted to the end to keep access with +/- 2GB + if ( fTotalSize > 0x7F000000 ) { + fBiggerThanTwoGigOutput = true; + + if ( (fTotalSize-fTotalZeroFillSize) > 0x7F000000 ) + throwf("total output size exceeds 2GB (%lldMB)", (fTotalSize-fTotalZeroFillSize)/(1024*1024)); + + // move very large (>1MB) zero fill atoms to a new section at very end of __DATA segment + Section* hugeZeroFills = Section::find("__huge", "__DATA", true); + for (std::vector::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) { + ObjectFile::Atom* atom = *it; + if ( atom->isZeroFill() && (atom->getSize() > 1024*1024) && (strcmp(atom->getSegment().getName(), "__DATA") == 0) ) + atom->setSection(hugeZeroFills); + } + } +} + + +void Linker::writeDotOutput() +{ + const char* dotOutFilePath = fOptions.dotOutputFile(); + if ( dotOutFilePath != NULL ) { + FILE* out = fopen(dotOutFilePath, "w"); + if ( out != NULL ) { + // print header + fprintf(out, "digraph dg\n{\n"); + fprintf(out, "\tconcentrate = true;\n"); + fprintf(out, "\trankdir = LR;\n"); + + // print each atom as a node + for (std::vector::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) { + ObjectFile::Atom* atom = *it; + if ( atom->getFile() != fOutputFile ) { + const char* name = atom->getDisplayName(); + if ( (atom->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition) + || (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) { + fprintf(out, "\taddr%p [ shape = plaintext, label = \"%s\" ];\n", atom, name); + } + else if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) { + char cstring[atom->getSize()+2]; + atom->copyRawContent((uint8_t*)cstring); + fprintf(out, "\taddr%p [ label = \"string: '", atom); + for (const char* s=cstring; *s != '\0'; ++s) { + if ( *s == '\n' ) + fprintf(out, "\\\\n"); + else + fputc(*s, out); + } + fprintf(out, "'\" ];\n"); + } + else { + fprintf(out, "\taddr%p [ label = \"%s\" ];\n", atom, name); + } + } + } + fprintf(out, "\n"); + + // print each reference as an edge + for (std::vector::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) { + ObjectFile::Atom* fromAtom = *it; + if ( fromAtom->getFile() != fOutputFile ) { + std::vector& references = fromAtom->getReferences(); + std::set seenTargets; + for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { + ObjectFile::Reference* reference = *rit; + ObjectFile::Atom* toAtom = &(reference->getTarget()); + if ( seenTargets.count(toAtom) == 0 ) { + seenTargets.insert(toAtom); + fprintf(out, "\taddr%p -> addr%p;\n", fromAtom, toAtom); + } + } + } + } + fprintf(out, "\n"); + + // push all imports to bottom of graph + fprintf(out, "{ rank = same; "); + for (std::vector::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) { + ObjectFile::Atom* atom = *it; + if ( atom->getFile() != fOutputFile ) + if ( (atom->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition) + || (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) { + fprintf(out, "addr%p; ", atom); + } + } + fprintf(out, "};\n "); + + // print footer + fprintf(out, "}\n"); + fclose(out); + } + else { + warning("could not write dot output file: %s", dotOutFilePath); + } + } +} + +ObjectFile::Atom* Linker::entryPoint(bool orInit) +{ + // if main executable, find entry point atom + ObjectFile::Atom* entryPoint = NULL; + switch ( fOptions.outputKind() ) { + case Options::kDynamicExecutable: + case Options::kStaticExecutable: + case Options::kDyld: + entryPoint = fGlobalSymbolTable.find(fOptions.entryName()); + if ( entryPoint == NULL ) { + throwf("could not find entry point \"%s\" (perhaps missing crt1.o)", fOptions.entryName()); + } + break; + case Options::kDynamicLibrary: + if ( orInit && (fOptions.initFunctionName() != NULL) ) { + entryPoint = fGlobalSymbolTable.find(fOptions.initFunctionName()); + if ( entryPoint == NULL ) { + throwf("could not find -init function: \"%s\"", fOptions.initFunctionName()); + } + } + break; + case Options::kObjectFile: + case Options::kDynamicBundle: + entryPoint = NULL; + break; + } + return entryPoint; +} + +ObjectFile::Atom* Linker::dyldHelper() +{ + return fGlobalSymbolTable.find("dyld_stub_binding_helper"); +} + +ObjectFile::Atom* Linker::dyldLazyLibraryHelper() +{ + return fGlobalSymbolTable.find("dyld_lazy_dylib_stub_binding_helper"); +} + +const char* Linker::assureFullPath(const char* path) +{ + if ( path[0] == '/' ) + return path; + char cwdbuff[MAXPATHLEN]; + if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) { + char* result; + asprintf(&result, "%s/%s", cwdbuff, path); + if ( result != NULL ) + return result; + } + return path; +} + + +// +// The stab strings are of the form: +// ':' +// but the contain a colon. +// For C++ may contain a double colon (e.g. std::string:f(0,1) ) +// For Objective-C name may contain a colon instead square bracket (e.g. [Foo doit:]:f(0,1) ) +// +const char* Linker::truncateStabString(const char* str) +{ + enum { start, inObjc } state = start; + for (const char* s = str; *s != 0; ++s) { + char c = *s; + switch (state) { + case start: + if ( c == '[' ) { + state = inObjc; + } + else { + if ( c == ':' ) { + if ( s[1] == ':' ) { + ++s; + } + else { + // found colon + // Duplicate strndup behavior here. + int trunStrLen = s-str+2; + char* temp = new char[trunStrLen+1]; + memcpy(temp, str, trunStrLen); + temp[trunStrLen] = '\0'; + return temp; + } + } + } + break; + case inObjc: + if ( c == ']' ) { + state = start; + } + break; + } + } + // malformed + return str; +} + + +bool Linker::minimizeStab(ObjectFile::Reader::Stab& stab) +{ + switch(stab.type){ + case N_GSYM: + case N_STSYM: + case N_LCSYM: + case N_FUN: + // these all need truncated strings + stab.string = truncateStabString(stab.string); + return true; + case N_SO: + case N_OSO: + case N_OPT: + case N_SOL: + // these are included in the minimal stabs, but they keep their full string + return true; + default: + return false; + } +} + + +struct HeaderRange { + std::vector::iterator begin; + std::vector::iterator end; + int parentRangeIndex; + uint32_t sum; + bool sumPrecomputed; + bool useEXCL; + bool cannotEXCL; // because of SLINE, etc stabs +}; + + +typedef __gnu_cxx::hash_map, __gnu_cxx::hash, CStringEquals> PathToSums; + +// hash table that maps header path to a vector of known checksums for that path +static PathToSums sKnownBINCLs; + + +void Linker::collectStabs(ObjectFile::Reader* reader, std::map& atomOrdinals) +{ + const bool log = false; + bool minimal = ( fOptions.readerOptions().fDebugInfoStripping == ObjectFile::ReaderOptions::kDebugInfoMinimal ); + std::vector* readerStabs = reader->getStabs(); + if ( readerStabs == NULL ) + return; + + if ( log ) fprintf(stderr, "processesing %lu stabs for %s\n", readerStabs->size(), reader->getPath()); + std::vector ranges; + int curRangeIndex = -1; + int count = 0; + ObjectFile::Atom* atomWithLowestOrdinal = NULL; + ObjectFile::Atom* atomWithHighestOrdinal = NULL; + uint32_t highestOrdinal = 0; + uint32_t lowestOrdinal = UINT_MAX; + std::vector > soRanges; + // 1) find all (possibly nested) BINCL/EINCL ranges and their checksums + // 2) find all SO/SO ranges and the first/last atom own by a FUN stab therein + for(std::vector::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) { + ++count; + switch ( it->type ) { + case N_BINCL: + { + HeaderRange range; + range.begin = it; + range.end = readerStabs->end(); + range.parentRangeIndex = curRangeIndex; + range.sum = it->value; + range.sumPrecomputed = (range.sum != 0); + range.useEXCL = false; + range.cannotEXCL = false; + curRangeIndex = ranges.size(); + if ( log ) fprintf(stderr, "[%d]BINCL %s\n", curRangeIndex, it->string); + ranges.push_back(range); + } + break; + case N_EINCL: + if ( curRangeIndex == -1 ) { + warning("EINCL missing BINCL in %s", reader->getPath()); + } + else { + ranges[curRangeIndex].end = it+1; + if ( log ) fprintf(stderr, "[%d->%d]EINCL %s\n", curRangeIndex, ranges[curRangeIndex].parentRangeIndex, it->string); + curRangeIndex = ranges[curRangeIndex].parentRangeIndex; + } + break; + case N_FUN: + { + std::map::iterator pos = atomOrdinals.find(it->atom); + if ( pos != atomOrdinals.end() ) { + uint32_t ordinal = pos->second; + if ( ordinal > highestOrdinal ) { + highestOrdinal = ordinal; + atomWithHighestOrdinal = it->atom; + } + if ( ordinal < lowestOrdinal ) { + lowestOrdinal = ordinal; + atomWithLowestOrdinal = it->atom; + } + } + } + // fall through + case N_BNSYM: + case N_ENSYM: + case N_LBRAC: + case N_RBRAC: + case N_SLINE: + case N_STSYM: + case N_LCSYM: + if ( curRangeIndex != -1 ) { + ranges[curRangeIndex].cannotEXCL = true; + if ( fOptions.warnStabs() ) + warning("cannot do BINCL/EINCL optimzation because of stabs kinds in %s for %s\n", ranges[curRangeIndex].begin->string, reader->getPath()); + } + break; + case N_SO: + if ( (it->string != NULL) && (strlen(it->string) > 0) ) { + // start SO, reset hi/low FUN tracking + atomWithLowestOrdinal = NULL; + atomWithHighestOrdinal = NULL; + highestOrdinal = 0; + lowestOrdinal = UINT_MAX; + } + else { + // end SO, record hi/low atoms for this SO range + soRanges.push_back(std::make_pair(atomWithLowestOrdinal, atomWithHighestOrdinal)); + } + // fall through + default: + if ( curRangeIndex != -1 ) { + if ( ! ranges[curRangeIndex].sumPrecomputed ) { + uint32_t sum = 0; + const char* s = it->string; + char c; + while ( (c = *s++) != 0 ) { + sum += c; + // don't checkusm first number (file index) after open paren in string + if ( c == '(' ) { + while(isdigit(*s)) + ++s; + } + } + ranges[curRangeIndex].sum += sum; + } + } + + } + } + if ( log ) fprintf(stderr, "processesed %d stabs for %s\n", count, reader->getPath()); + if ( curRangeIndex != -1 ) + warning("BINCL (%s) missing EINCL in %s", ranges[curRangeIndex].begin->string, reader->getPath()); + + // if no BINCLs + if ( ranges.size() == 0 ) { + unsigned int soIndex = 0; + for(std::vector::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) { + // copy minimal or all stabs + ObjectFile::Reader::Stab stab = *it; + if ( !minimal || minimizeStab(stab) ) { + if ( stab.type == N_SO ) { + if ( soIndex < soRanges.size() ) { + if ( (stab.string != NULL) && (strlen(stab.string) > 0) ) { + // starting SO is associated with first atom + stab.atom = soRanges[soIndex].first; + } + else { + // ending SO is associated with last atom + stab.atom = soRanges[soIndex].second; + ++soIndex; + } + } + } + fStabs.push_back(stab); + } + } + return; + } + + //fprintf(stderr, "BINCL/EINCL info for %s\n", reader->getPath()); + //for(std::vector::iterator it=ranges.begin(); it != ranges.end(); ++it) { + // fprintf(stderr, "%08X %s\n", it->sum, it->begin->string); + //} + + // see if any of these BINCL/EINCL ranges have already been seen and therefore can be replaced with EXCL + for(std::vector::iterator it=ranges.begin(); it != ranges.end(); ++it) { + if ( ! it->cannotEXCL ) { + const char* header = it->begin->string; + uint32_t sum = it->sum; + PathToSums::iterator pos = sKnownBINCLs.find(header); + if ( pos != sKnownBINCLs.end() ) { + std::vector& sums = pos->second; + for(std::vector::iterator sit=sums.begin(); sit != sums.end(); ++sit) { + if (*sit == sum) { + //fprintf(stderr, "use EXCL for %s in %s\n", header, reader->getPath()); + it->useEXCL = true; + break; + } + } + if ( ! it->useEXCL ) { + // have seen this path, but not this checksum + //fprintf(stderr, "registering another checksum %08X for %s\n", sum, header); + sums.push_back(sum); + } + } + else { + // have not seen this path, so add to known BINCLs + std::vector empty; + sKnownBINCLs[header] = empty; + sKnownBINCLs[header].push_back(sum); + //fprintf(stderr, "registering checksum %08X for %s\n", sum, header); + } + } + } + + // add a new set of stabs with BINCL/EINCL runs that have been seen before, replaced with EXCLs + curRangeIndex = -1; + const int maxRangeIndex = ranges.size(); + int soIndex = 0; + for(std::vector::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) { + switch ( it->type ) { + case N_BINCL: + for(int i=curRangeIndex+1; i < maxRangeIndex; ++i) { + if ( ranges[i].begin == it ) { + curRangeIndex = i; + HeaderRange& range = ranges[curRangeIndex]; + ObjectFile::Reader::Stab stab = *it; + stab.value = range.sum; // BINCL and EXCL have n_value set to checksum + if ( range.useEXCL ) + stab.type = N_EXCL; // transform BINCL into EXCL + if ( !minimal ) + fStabs.push_back(stab); + break; + } + } + break; + case N_EINCL: + if ( curRangeIndex != -1 ) { + if ( !ranges[curRangeIndex].useEXCL && !minimal ) + fStabs.push_back(*it); + curRangeIndex = ranges[curRangeIndex].parentRangeIndex; + } + break; + default: + if ( (curRangeIndex == -1) || !ranges[curRangeIndex].useEXCL ) { + ObjectFile::Reader::Stab stab = *it; + if ( !minimal || minimizeStab(stab) ) { + if ( stab.type == N_SO ) { + if ( (stab.string != NULL) && (strlen(stab.string) > 0) ) { + // starting SO is associated with first atom + stab.atom = soRanges[soIndex].first; + } + else { + // ending SO is associated with last atom + stab.atom = soRanges[soIndex].second; + ++soIndex; + } + } + fStabs.push_back(stab); + } + } + } + } + +} + + +// used to prune out atoms that don't need debug notes generated +class NoDebugNoteAtom +{ +public: + NoDebugNoteAtom(const std::map& readersWithDwarfOrdinals) + : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals) {} + + bool operator()(const ObjectFile::Atom* atom) const { + if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn ) + return true; + if ( atom->getName() == NULL ) + return true; + if ( fReadersWithDwarfOrdinals.find(atom->getFile()) == fReadersWithDwarfOrdinals.end() ) + return true; + return false; + } + +private: + const std::map& fReadersWithDwarfOrdinals; +}; + +// used to sort atoms with debug notes +class ReadersWithDwarfSorter +{ +public: + ReadersWithDwarfSorter(const std::map& readersWithDwarfOrdinals, + const std::map& atomOrdinals) + : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals), fAtomOrdinals(atomOrdinals) {} + + bool operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right) const + { + // first sort by reader + unsigned int leftReaderIndex = fReadersWithDwarfOrdinals.find(left->getFile())->second; + unsigned int rightReaderIndex = fReadersWithDwarfOrdinals.find(right->getFile())->second; + if ( leftReaderIndex != rightReaderIndex ) + return (leftReaderIndex < rightReaderIndex); + + // then sort by atom ordinal + unsigned int leftAtomIndex = fAtomOrdinals.find(left)->second; + unsigned int rightAtomIndex = fAtomOrdinals.find(right)->second; + return leftAtomIndex < rightAtomIndex; + } + +private: + const std::map& fReadersWithDwarfOrdinals; + const std::map& fAtomOrdinals; +}; + + + + + +void Linker::synthesizeDebugNotes(std::vector& allAtomsByReader) +{ + // synthesize "debug notes" and add them to master stabs vector + const char* dirPath = NULL; + const char* filename = NULL; + bool wroteStartSO = false; + bool useZeroOSOModTime = (getenv("RC_RELEASE") != NULL); + __gnu_cxx::hash_set, CStringEquals> seenFiles; + for (std::vector::iterator it=allAtomsByReader.begin(); it != allAtomsByReader.end(); it++) { + ObjectFile::Atom* atom = *it; + const char* newDirPath; + const char* newFilename; + //fprintf(stderr, "debug note for %s\n", atom->getDisplayName()); + if ( atom->getTranslationUnitSource(&newDirPath, &newFilename) ) { + // need SO's whenever the translation unit source file changes + if ( newFilename != filename ) { + // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/' + if ( (newDirPath != NULL) && (strlen(newDirPath) > 1 ) && (newDirPath[strlen(newDirPath)-1] != '/') ) + asprintf((char**)&newDirPath, "%s/", newDirPath); + if ( filename != NULL ) { + // translation unit change, emit ending SO + ObjectFile::Reader::Stab endFileStab; + endFileStab.atom = NULL; + endFileStab.type = N_SO; + endFileStab.other = 1; + endFileStab.desc = 0; + endFileStab.value = 0; + endFileStab.string = ""; + fStabs.push_back(endFileStab); + } + // new translation unit, emit start SO's + ObjectFile::Reader::Stab dirPathStab; + dirPathStab.atom = NULL; + dirPathStab.type = N_SO; + dirPathStab.other = 0; + dirPathStab.desc = 0; + dirPathStab.value = 0; + dirPathStab.string = newDirPath; + fStabs.push_back(dirPathStab); + ObjectFile::Reader::Stab fileStab; + fileStab.atom = NULL; + fileStab.type = N_SO; + fileStab.other = 0; + fileStab.desc = 0; + fileStab.value = 0; + fileStab.string = newFilename; + fStabs.push_back(fileStab); + // Synthesize OSO for start of file + ObjectFile::Reader::Stab objStab; + objStab.atom = NULL; + objStab.type = N_OSO; + objStab.other = 0; + objStab.desc = 1; + objStab.value = useZeroOSOModTime ? 0 : atom->getFile()->getModificationTime(); + objStab.string = assureFullPath(atom->getFile()->getPath()); + fStabs.push_back(objStab); + wroteStartSO = true; + // add the source file path to seenFiles so it does not show up in SOLs + seenFiles.insert(newFilename); + } + filename = newFilename; + dirPath = newDirPath; + if ( atom->getSegment().isContentExecutable() && (strncmp(atom->getSectionName(), "__text", 6) == 0) ) { + // Synthesize BNSYM and start FUN stabs + ObjectFile::Reader::Stab beginSym; + beginSym.atom = atom; + beginSym.type = N_BNSYM; + beginSym.other = 1; + beginSym.desc = 0; + beginSym.value = 0; + beginSym.string = ""; + fStabs.push_back(beginSym); + ObjectFile::Reader::Stab startFun; + startFun.atom = atom; + startFun.type = N_FUN; + startFun.other = 1; + startFun.desc = 0; + startFun.value = 0; + startFun.string = atom->getName(); + fStabs.push_back(startFun); + // Synthesize any SOL stabs needed + std::vector* lineInfo = atom->getLineInfo(); + if ( lineInfo != NULL ) { + const char* curFile = NULL; + for (std::vector::iterator it = lineInfo->begin(); it != lineInfo->end(); ++it) { + if ( it->fileName != curFile ) { + if ( seenFiles.count(it->fileName) == 0 ) { + seenFiles.insert(it->fileName); + ObjectFile::Reader::Stab sol; + sol.atom = 0; + sol.type = N_SOL; + sol.other = 0; + sol.desc = 0; + sol.value = 0; + sol.string = it->fileName; + fStabs.push_back(sol); + } + curFile = it->fileName; + } + } + } + // Synthesize end FUN and ENSYM stabs + ObjectFile::Reader::Stab endFun; + endFun.atom = atom; + endFun.type = N_FUN; + endFun.other = 0; + endFun.desc = 0; + endFun.value = 0; + endFun.string = ""; + fStabs.push_back(endFun); + ObjectFile::Reader::Stab endSym; + endSym.atom = atom; + endSym.type = N_ENSYM; + endSym.other = 1; + endSym.desc = 0; + endSym.value = 0; + endSym.string = ""; + fStabs.push_back(endSym); + } + else if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn ) { + // no stabs for atoms that would not be in the symbol table + } + else if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute ) { + // no stabs for absolute symbols + } + else if ( (strcmp(atom->getSectionName(), "__eh_frame") == 0) ) { + // no stabs for .eh atoms + } + else { + ObjectFile::Reader::Stab globalsStab; + const char* name = atom->getName(); + if ( atom->getScope() == ObjectFile::Atom::scopeTranslationUnit ) { + // Synthesize STSYM stab for statics + globalsStab.atom = atom; + globalsStab.type = N_STSYM; + globalsStab.other = 1; + globalsStab.desc = 0; + globalsStab.value = 0; + globalsStab.string = name; + fStabs.push_back(globalsStab); + } + else { + // Synthesize GSYM stab for other globals + globalsStab.atom = atom; + globalsStab.type = N_GSYM; + globalsStab.other = 1; + globalsStab.desc = 0; + globalsStab.value = 0; + globalsStab.string = name; + fStabs.push_back(globalsStab); + } + } + } + } + + if ( wroteStartSO ) { + // emit ending SO + ObjectFile::Reader::Stab endFileStab; + endFileStab.atom = NULL; + endFileStab.type = N_SO; + endFileStab.other = 1; + endFileStab.desc = 0; + endFileStab.value = 0; + endFileStab.string = ""; + fStabs.push_back(endFileStab); + } +} + + + + +void Linker::collectDebugInfo() +{ + std::map atomOrdinals; + fStartDebugTime = mach_absolute_time(); + if ( fOptions.readerOptions().fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone ) { + + // determine mixture of stabs and dwarf + bool someStabs = false; + bool someDwarf = false; + for (std::vector::iterator it=fReadersThatHaveSuppliedAtoms.begin(); + it != fReadersThatHaveSuppliedAtoms.end(); + it++) { + ObjectFile::Reader* reader = *it; + if ( reader != NULL ) { + switch ( reader->getDebugInfoKind() ) { + case ObjectFile::Reader::kDebugInfoNone: + break; + case ObjectFile::Reader::kDebugInfoStabs: + someStabs = true; + break; + case ObjectFile::Reader::kDebugInfoDwarf: + someDwarf = true; + fCreateUUID = true; + break; + case ObjectFile::Reader::kDebugInfoStabsUUID: + someStabs = true; + fCreateUUID = true; + break; + default: + throw "Unhandled type of debug information"; + } + } + } + + if ( someDwarf || someStabs ) { + // try to minimize re-allocations + fStabs.reserve(1024); + + // make mapping from atoms to ordinal + uint32_t ordinal = 1; + for (std::vector::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) { + atomOrdinals[*it] = ordinal++; + } + } + + // process all dwarf .o files as a batch + if ( someDwarf ) { + // make mapping from readers with dwarf to ordinal + std::map readersWithDwarfOrdinals; + uint32_t readerOrdinal = 1; + for (std::vector::iterator it=fReadersThatHaveSuppliedAtoms.begin(); + it != fReadersThatHaveSuppliedAtoms.end(); + it++) { + ObjectFile::Reader* reader = *it; + if ( (reader != NULL) && (reader->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoDwarf) ) { + readersWithDwarfOrdinals[reader] = readerOrdinal++; + } + } + + // make a vector of atoms + std::vector allAtomsByReader(fAllAtoms.begin(), fAllAtoms.end()); + // remove those not from a reader that has dwarf + allAtomsByReader.erase(std::remove_if(allAtomsByReader.begin(), allAtomsByReader.end(), + NoDebugNoteAtom(readersWithDwarfOrdinals)), allAtomsByReader.end()); + // sort by reader then atom ordinal + std::sort(allAtomsByReader.begin(), allAtomsByReader.end(), ReadersWithDwarfSorter(readersWithDwarfOrdinals, atomOrdinals)); + // add debug notes for each atom + this->synthesizeDebugNotes(allAtomsByReader); + } + + // process all stabs .o files one by one + if ( someStabs ) { + // get stabs from each reader, in command line order + for (std::vector::iterator it=fReadersThatHaveSuppliedAtoms.begin(); + it != fReadersThatHaveSuppliedAtoms.end(); + it++) { + ObjectFile::Reader* reader = *it; + if ( reader != NULL ) { + switch ( reader->getDebugInfoKind() ) { + case ObjectFile::Reader::kDebugInfoDwarf: + case ObjectFile::Reader::kDebugInfoNone: + // do nothing + break; + case ObjectFile::Reader::kDebugInfoStabs: + case ObjectFile::Reader::kDebugInfoStabsUUID: + collectStabs(reader, atomOrdinals); + break; + default: + throw "Unhandled type of debug information"; + } + } + } + // remove stabs associated with atoms that won't be in output + std::set allAtomsSet; + allAtomsSet.insert(fAllAtoms.begin(), fAllAtoms.end()); + fStabs.erase(std::remove_if(fStabs.begin(), fStabs.end(), NotInSet(allAtomsSet)), fStabs.end()); + } + } +} + +void Linker::writeOutput() +{ + if ( fOptions.forceCpuSubtypeAll() ) + fCurrentCpuConstraint = ObjectFile::Reader::kCpuAny; + + fStartWriteTime = mach_absolute_time(); + // tell writer about each segment's atoms + fOutputFileSize = fOutputFile->write(fAllAtoms, fStabs, this->entryPoint(true), + this->dyldHelper(), this->dyldLazyLibraryHelper(), + fCreateUUID, fCanScatter, + fCurrentCpuConstraint, fBiggerThanTwoGigOutput, + fGlobalSymbolTable.hasExternalWeakDefinitions()); +} + +ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info) +{ + // map in whole file + uint64_t len = info.fileLen; + int fd = ::open(info.path, O_RDONLY, 0); + if ( fd == -1 ) + throwf("can't open file, errno=%d", errno); + if ( info.fileLen < 20 ) + throw "file too small"; + + uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); + if ( p == (uint8_t*)(-1) ) + throwf("can't map file, errno=%d", errno); + + // if fat file, skip to architecture we want + // Note: fat header is always big-endian + const fat_header* fh = (fat_header*)p; + if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) { + const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header)); + uint32_t sliceToUse; + bool sliceFound = false; + if ( fOptions.preferSubArchitecture() ) { + // first try to find a slice that match cpu-type and cpu-sub-type + for (uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) { + if ( (OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)fArchitecture) + && (OSSwapBigToHostInt32(archs[i].cpusubtype) == (uint32_t)fOptions.subArchitecture()) ) { + sliceToUse = i; + sliceFound = true; + break; + } + } + } + if ( !sliceFound ) { + // look for any slice that matches just cpu-type + for (uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) { + if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)fArchitecture ) { + sliceToUse = i; + sliceFound = true; + break; + } + } + } + if ( sliceFound ) { + uint32_t fileOffset = OSSwapBigToHostInt32(archs[sliceToUse].offset); + len = OSSwapBigToHostInt32(archs[sliceToUse].size); + // if requested architecture is page aligned within fat file, then remap just that portion of file + if ( (fileOffset & 0x00000FFF) == 0 ) { + // unmap whole file + munmap((caddr_t)p, info.fileLen); + // re-map just part we need + p = (uint8_t*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, fileOffset); + if ( p == (uint8_t*)(-1) ) + throwf("can't re-map file, errno=%d", errno); + } + else { + p = &p[fileOffset]; + } + } + } + ::close(fd); + + switch (fArchitecture) { + case CPU_TYPE_POWERPC: + if ( mach_o::relocatable::Reader::validFile(p) ) + return this->addObject(new mach_o::relocatable::Reader::Reader(p, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len); + else if ( mach_o::dylib::Reader::validFile(p, info.options.fBundleLoader) ) + return this->addDylib(new mach_o::dylib::Reader::Reader(p, len, info.path, info.options, fOptions.readerOptions(), fNextInputOrdinal), info, len); + else if ( archive::Reader::validFile(p, len) ) + return this->addArchive(new archive::Reader::Reader(p, len, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len); + break; + case CPU_TYPE_POWERPC64: + if ( mach_o::relocatable::Reader::validFile(p) ) + return this->addObject(new mach_o::relocatable::Reader::Reader(p, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len); + else if ( mach_o::dylib::Reader::validFile(p, info.options.fBundleLoader) ) + return this->addDylib(new mach_o::dylib::Reader::Reader(p, len, info.path, info.options, fOptions.readerOptions(), fNextInputOrdinal), info, len); + else if ( archive::Reader::validFile(p, len) ) + return this->addArchive(new archive::Reader::Reader(p, len, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len); + break; + case CPU_TYPE_I386: + if ( mach_o::relocatable::Reader::validFile(p) ) + return this->addObject(new mach_o::relocatable::Reader::Reader(p, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len); + else if ( mach_o::dylib::Reader::validFile(p, info.options.fBundleLoader) ) + return this->addDylib(new mach_o::dylib::Reader::Reader(p, len, info.path, info.options, fOptions.readerOptions(), fNextInputOrdinal), info, len); + else if ( archive::Reader::validFile(p, len) ) + return this->addArchive(new archive::Reader::Reader(p, len, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len); + break; + case CPU_TYPE_X86_64: + if ( mach_o::relocatable::Reader::validFile(p) ) + return this->addObject(new mach_o::relocatable::Reader::Reader(p, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len); + else if ( mach_o::dylib::Reader::validFile(p, info.options.fBundleLoader) ) + return this->addDylib(new mach_o::dylib::Reader::Reader(p, len, info.path, info.options, fOptions.readerOptions(), fNextInputOrdinal), info, len); + else if ( archive::Reader::validFile(p, len) ) + return this->addArchive(new archive::Reader::Reader(p, len, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len); + case CPU_TYPE_ARM: + if ( mach_o::relocatable::Reader::validFile(p) ) + return this->addObject(new mach_o::relocatable::Reader::Reader(p, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len); + else if ( mach_o::dylib::Reader::validFile(p, info.options.fBundleLoader) ) + return this->addDylib(new mach_o::dylib::Reader::Reader(p, len, info.path, info.options, fOptions.readerOptions(), fNextInputOrdinal), info, len); + else if ( archive::Reader::validFile(p, len) ) + return this->addArchive(new archive::Reader::Reader(p, len, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len); + break; + break; + } + +#if LTO_SUPPORT + if ( lto::Reader::validFile(p, len, fArchitecture) ) { + return this->addObject(new lto::Reader(p, len, info.path, info.modTime, fOptions.readerOptions(), fArchitecture), info, len); + } + else if ( !lto::Reader::loaded() && (p[0] == 'B') && (p[1] == 'C') ) { + throw "could not process object file. Looks like an llvm bitcode object file, but libLTO.dylib could not be loaded"; + } +#endif + // error handling + if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) { + throwf("missing required architecture %s in file", fArchitectureName); + } + else { + throw "file is not of required architecture"; + } +} + +void Linker::logDylib(ObjectFile::Reader* reader, bool indirect) +{ + if ( fOptions.readerOptions().fTraceDylibs ) { + const char* fullPath = reader->getPath(); + char realName[MAXPATHLEN]; + if ( realpath(fullPath, realName) != NULL ) + fullPath = realName; + if ( indirect ) + logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath); + else + logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath); + } +} + + + +ObjectFile::Reader* Linker::findDylib(const char* installPath, const char* fromPath) +{ + //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath); + InstallNameToReader::iterator pos = fDylibMap.find(installPath); + if ( pos != fDylibMap.end() ) { + return pos->second; + } + else { + // allow -dylib_path option to override indirect library to use + for (std::vector::iterator dit = fOptions.dylibOverrides().begin(); dit != fOptions.dylibOverrides().end(); ++dit) { + if ( strcmp(dit->installName,installPath) == 0 ) {\ + try { + Options::FileInfo info = fOptions.findFile(dit->useInstead); + ObjectFile::Reader* reader = this->createReader(info); + fDylibMap[strdup(installPath)] = reader; + this->logDylib(reader, true); + return reader; + } + catch (const char* msg) { + warning("ignoring -dylib_file option, %s", msg); + } + } + } + char newPath[MAXPATHLEN]; + // handle @loader_path + if ( strncmp(installPath, "@loader_path/", 13) == 0 ) { + strcpy(newPath, fromPath); + char* addPoint = strrchr(newPath,'/'); + if ( addPoint != NULL ) + strcpy(&addPoint[1], &installPath[13]); + else + strcpy(newPath, &installPath[13]); + installPath = newPath; + } + // note: @executable_path case is handled inside findFileUsingPaths() + // search for dylib using -F and -L paths + Options::FileInfo info = fOptions.findFileUsingPaths(installPath); + try { + ObjectFile::Reader* reader = this->createReader(info); + fDylibMap[strdup(installPath)] = reader; + this->logDylib(reader, true); + return reader; + } + catch (const char* msg) { + throwf("in %s, %s", info.path, msg); + } + } +} + + +void Linker::processDylibs() +{ + fAllDirectDylibsLoaded = true; + + // mark all dylibs initially specified as required and check if they can be used + for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) { + it->second->setExplicitlyLinked(); + this->checkDylibClientRestrictions(it->second); + } + + // keep processing dylibs until no more dylibs are added + unsigned long lastMapSize = 0; + while ( lastMapSize != fDylibMap.size() ) { + lastMapSize = fDylibMap.size(); + // can't iterator fDylibMap while modifying it, so use temp buffer + std::vector currentUnprocessedReaders; + for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) { + if ( fDylibsProcessed.count(it->second) == 0 ) + currentUnprocessedReaders.push_back(it->second); + } + for (std::vector::iterator it=currentUnprocessedReaders.begin(); it != currentUnprocessedReaders.end(); it++) { + fDylibsProcessed.insert(*it); + (*it)->processIndirectLibraries(this); + } + } + + // go back over original dylibs and mark sub frameworks as re-exported + if ( fOptions.outputKind() == Options::kDynamicLibrary ) { + const char* myLeaf = strrchr(fOptions.installPath(), '/'); + if ( myLeaf != NULL ) { + for (std::vector::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) { + ObjectFile::Reader* reader = *it; + const char* childParent = reader->parentUmbrella(); + if ( childParent != NULL ) { + if ( strcmp(childParent, &myLeaf[1]) == 0 ) { + // set re-export bit of info + std::map::iterator pos = fDylibOptionsMap.find(reader); + if ( pos != fDylibOptionsMap.end() ) { + pos->second.fReExport = true; + } + } + } + } + } + } + +} + + + +void Linker::createReaders() +{ + fStartCreateReadersTime = mach_absolute_time(); + std::vector& files = fOptions.getInputFiles(); + const int count = files.size(); + if ( count == 0 ) + throw "no object files specified"; + // add all direct object, archives, and dylibs + for (int i=0; i < count; ++i) { + Options::FileInfo& entry = files[i]; + // ignore /usr/lib/dyld on command line in crt.o build + if ( strcmp(entry.path, "/usr/lib/dyld") != 0 ) { + try { + this->addInputFile(this->createReader(entry), entry); + } + catch (const char* msg) { + if ( strstr(msg, "architecture") != NULL ) { + if ( fOptions.ignoreOtherArchInputFiles() ) { + // ignore, because this is about an architecture not in use + } + else { + warning("in %s, %s", entry.path, msg); + } + } + else { + throwf("in %s, %s", entry.path, msg); + } + } + } + } + + this->processDylibs(); +} + + + +ObjectFile::Reader* Linker::addArchive(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen) +{ + fNextInputOrdinal += mappedLen; + // remember which readers are archives because they are logged differently + fArchiveReaders.insert(reader); + + // update stats + fTotalArchiveSize += mappedLen; + ++fTotalArchivesLoaded; + return reader; +} + +ObjectFile::Reader* Linker::addObject(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen) +{ + fNextInputOrdinal += mappedLen; + // any .o files that don't have MH_SUBSECTIONS_VIA_SYMBOLS, that means a generated .o file can't + if ( (fOptions.outputKind() == Options::kObjectFile) && !reader->canScatterAtoms() ) + fCanScatter = false; + + // update stats + fTotalObjectSize += mappedLen; + ++fTotalObjectLoaded; + return reader; +} + + +void Linker::checkDylibClientRestrictions(ObjectFile::Reader* reader) +{ + // Check for any restrictions on who can link with this dylib + const char* readerParentName = reader->parentUmbrella() ; + std::vector* clients = reader->getAllowableClients(); + if ( (readerParentName != NULL) || (clients != NULL) ) { + // only dylibs that are in an umbrella or have a client list need verification + const char* installName = fOptions.installPath(); + const char* installNameLastSlash = strrchr(installName, '/'); + bool isParent = false; + bool isSibling = false; + bool isAllowableClient = false; + // There are three cases: + if ( (readerParentName != NULL) && (installNameLastSlash != NULL) ) { + // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella + isParent = ( strcmp(&installNameLastSlash[1], readerParentName) == 0 ); + + // hack to support umbrella variants that encode the variant name in the install name + // e.g. CoreServices_profile + if ( !isParent ) { + const char* underscore = strchr(&installNameLastSlash[1], '_'); + if ( underscore != NULL ) { + isParent = ( strncmp(&installNameLastSlash[1], readerParentName, underscore-installNameLastSlash-1) == 0 ); + } + } + + // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent + isSibling = ( (fOptions.umbrellaName() != NULL) && (strcmp(fOptions.umbrellaName(), readerParentName) == 0) ); + } + + if ( !isParent && !isSibling && (clients != NULL) ) { + // case 3) the dylib has a list of allowable clients, and we are creating one of them + const char* clientName = fOptions.clientName(); + int clientNameLen = 0; + if ( clientName != NULL ) { + // use client name as specified on command line + clientNameLen = strlen(clientName); + } + else { + // infer client name from output path (e.g. xxx/libfoo_variant.A.dylib --> foo, Bar.framework/Bar_variant --> Bar) + clientName = installName; + clientNameLen = strlen(clientName); + // starts after last slash + if ( installNameLastSlash != NULL ) + clientName = &installNameLastSlash[1]; + if ( strncmp(clientName, "lib", 3) == 0 ) + clientName = &clientName[3]; + // up to first dot + const char* firstDot = strchr(clientName, '.'); + if ( firstDot != NULL ) + clientNameLen = firstDot - clientName; + // up to first underscore + const char* firstUnderscore = strchr(clientName, '_'); + if ( (firstUnderscore != NULL) && ((firstUnderscore - clientName) < clientNameLen) ) + clientNameLen = firstUnderscore - clientName; + } + + // Use clientName to check if this dylib is able to link against the allowable clients. + for (std::vector::iterator it = clients->begin(); it != clients->end(); it++) { + if ( strncmp(*it, clientName, clientNameLen) == 0 ) + isAllowableClient = true; + } + } + + if ( !isParent && !isSibling && !isAllowableClient ) { + if ( readerParentName != NULL ) { + throwf("cannot link directly with %s. Link against the umbrella framework '%s.framework' instead.", + reader->getPath(), readerParentName); + } + else { + throwf("cannot link directly with %s", reader->getPath()); + } + } + } + + +} + +ObjectFile::Reader* Linker::addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen) +{ + fNextInputOrdinal += mappedLen; + if ( (reader->getInstallPath() == NULL) && !info.options.fBundleLoader ) { + // this is a "blank" stub + // silently ignore it + return reader; + } + // add to map of loaded dylibs + const char* installPath = reader->getInstallPath(); + if ( installPath != NULL ) { + InstallNameToReader::iterator pos = fDylibMap.find(installPath); + if ( pos == fDylibMap.end() ) { + fDylibMap[strdup(installPath)] = reader; + } + else { + InstallNameToReader::iterator pos2 = fDylibMap.find(reader->getPath()); + if ( pos2 == fDylibMap.end() ) + fDylibMap[strdup(reader->getPath())] = reader; + else + warning("duplicate dylib %s", reader->getPath()); + } + } + else if ( info.options.fBundleLoader ) + fBundleLoaderReader = reader; + + // log direct readers + if ( !fAllDirectDylibsLoaded ) + this->logDylib(reader, false); + + // update stats + ++fTotalDylibsLoaded; + + return reader; +} + + +void Linker::logTraceInfo (const char* format, ...) +{ + static int trace_file = -1; + char trace_buffer[MAXPATHLEN * 2]; + char *buffer_ptr; + int length; + ssize_t amount_written; + const char *trace_file_path = fOptions.readerOptions().fTraceOutputFile; + + if(trace_file == -1) { + if(trace_file_path != NULL) { + trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666); + if(trace_file == -1) + throwf("Could not open or create trace file: %s", trace_file_path); + } + else { + trace_file = fileno(stderr); + } + } + + va_list ap; + va_start(ap, format); + length = vsnprintf(trace_buffer, sizeof(trace_buffer), format, ap); + va_end(ap); + buffer_ptr = trace_buffer; + + while(length > 0) { + amount_written = write(trace_file, buffer_ptr, length); + if(amount_written == -1) + /* Failure to write shouldn't fail the build. */ + return; + buffer_ptr += amount_written; + length -= amount_written; + } +} + + + +void Linker::createWriter() +{ + fStartCreateWriterTime = mach_absolute_time(); + + // make a vector out of all required dylibs in fDylibMap + std::vector dynamicLibraries; + // need to preserve command line order + for (std::vector::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) { + ObjectFile::Reader* reader = *it; + for (InstallNameToReader::iterator mit=fDylibMap.begin(); mit != fDylibMap.end(); mit++) { + if ( reader == mit->second ) { + ExecutableFile::DyLibUsed dylibInfo; + dylibInfo.reader = reader; + dylibInfo.options = fDylibOptionsMap[reader]; + dynamicLibraries.push_back(dylibInfo); + break; + } + } + } + // then add any other dylibs + for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) { + if ( it->second->implicitlyLinked() ) { + // if not already in dynamicLibraries + bool alreadyInDynamicLibraries = false; + for (std::vector::iterator dit=dynamicLibraries.begin(); dit != dynamicLibraries.end(); dit++) { + if ( dit->reader == it->second ) { + alreadyInDynamicLibraries = true; + break; + } + } + if ( ! alreadyInDynamicLibraries ) { + ExecutableFile::DyLibUsed dylibInfo; + dylibInfo.reader = it->second; + std::map::iterator pos = fDylibOptionsMap.find(it->second); + if ( pos != fDylibOptionsMap.end() ) { + dylibInfo.options = pos->second; + } + else { + dylibInfo.options.fWeakImport = false; // FIX ME + dylibInfo.options.fReExport = false; + dylibInfo.options.fBundleLoader = false; + } + dynamicLibraries.push_back(dylibInfo); + } + } + } + if ( fBundleLoaderReader != NULL ) { + ExecutableFile::DyLibUsed dylibInfo; + dylibInfo.reader = fBundleLoaderReader; + dylibInfo.options.fWeakImport = false; + dylibInfo.options.fReExport = false; + dylibInfo.options.fBundleLoader = true; + dynamicLibraries.push_back(dylibInfo); + } + + const char* path = fOptions.getOutputFilePath(); + switch ( fArchitecture ) { + case CPU_TYPE_POWERPC: + this->setOutputFile(new mach_o::executable::Writer(path, fOptions, dynamicLibraries)); + break; + case CPU_TYPE_POWERPC64: + this->setOutputFile(new mach_o::executable::Writer(path, fOptions, dynamicLibraries)); + break; + case CPU_TYPE_I386: + this->setOutputFile(new mach_o::executable::Writer(path, fOptions, dynamicLibraries)); + break; + case CPU_TYPE_X86_64: + this->setOutputFile(new mach_o::executable::Writer(path, fOptions, dynamicLibraries)); + break; + case CPU_TYPE_ARM: + this->setOutputFile(new mach_o::executable::Writer(path, fOptions, dynamicLibraries)); + break; + default: + throw "unknown architecture"; + } +} + + +Linker::SymbolTable::SymbolTable(Linker& owner) + : fOwner(owner), fRequireCount(0), fHasExternalTentativeDefinitions(false), fHasExternalWeakDefinitions(false) +{ +} + +void Linker::SymbolTable::require(const char* name) +{ + //fprintf(stderr, "require(%s)\n", name); + Mapper::iterator pos = fTable.find(name); + if ( pos == fTable.end() ) { + fTable[name] = NULL; + ++fRequireCount; + } +} + +// convenience labels for 2-dimensional switch statement +enum AllDefinitionCombinations { + kRegAndReg = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kRegularDefinition, + kRegAndWeak = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kWeakDefinition, + kRegAndTent = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kTentativeDefinition, + kRegAndExtern = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kExternalDefinition, + kRegAndExternWeak = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition, + kRegAndAbsolute = (ObjectFile::Atom::kRegularDefinition << 3) | ObjectFile::Atom::kAbsoluteSymbol, + kWeakAndReg = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kRegularDefinition, + kWeakAndWeak = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kWeakDefinition, + kWeakAndTent = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kTentativeDefinition, + kWeakAndExtern = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kExternalDefinition, + kWeakAndExternWeak = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition, + kWeakAndAbsolute = (ObjectFile::Atom::kWeakDefinition << 3) | ObjectFile::Atom::kAbsoluteSymbol, + kTentAndReg = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kRegularDefinition, + kTentAndWeak = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kWeakDefinition, + kTentAndTent = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kTentativeDefinition, + kTentAndExtern = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kExternalDefinition, + kTentAndExternWeak = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition, + kTentAndAbsolute = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kAbsoluteSymbol, + kExternAndReg = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kRegularDefinition, + kExternAndWeak = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kWeakDefinition, + kExternAndTent = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kTentativeDefinition, + kExternAndExtern = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kExternalDefinition, + kExternAndExternWeak = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition, + kExternAndAbsolute = (ObjectFile::Atom::kExternalDefinition << 3) | ObjectFile::Atom::kAbsoluteSymbol, + kExternWeakAndReg = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kRegularDefinition, + kExternWeakAndWeak = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kWeakDefinition, + kExternWeakAndTent = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kTentativeDefinition, + kExternWeakAndExtern = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kExternalDefinition, + kExternWeakAndExternWeak= (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition, + kExternWeakAndAbsolute = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kAbsoluteSymbol, + kAbsoluteAndReg = (ObjectFile::Atom::kAbsoluteSymbol << 3) | ObjectFile::Atom::kRegularDefinition, + kAbsoluteAndWeak = (ObjectFile::Atom::kAbsoluteSymbol << 3) | ObjectFile::Atom::kWeakDefinition, + kAbsoluteAndTent = (ObjectFile::Atom::kAbsoluteSymbol << 3) | ObjectFile::Atom::kTentativeDefinition, + kAbsoluteAndExtern = (ObjectFile::Atom::kAbsoluteSymbol << 3) | ObjectFile::Atom::kExternalDefinition, + kAbsoluteAndExternWeak = (ObjectFile::Atom::kAbsoluteSymbol << 3) | ObjectFile::Atom::kExternalWeakDefinition, + kAbsoluteAndAbsolute = (ObjectFile::Atom::kAbsoluteSymbol << 3) | ObjectFile::Atom::kAbsoluteSymbol +}; + +bool Linker::SymbolTable::add(ObjectFile::Atom& newAtom) +{ + bool useNew = true; + bool checkVisibilityMismatch = false; + const char* name = newAtom.getName(); + if ( newAtom.getScope() == ObjectFile::Atom::scopeGlobal ) { + switch ( newAtom.getDefinitionKind() ) { + case ObjectFile::Atom::kTentativeDefinition: + fHasExternalTentativeDefinitions = true; + break; + case ObjectFile::Atom::kWeakDefinition: + fHasExternalWeakDefinitions = true; + break; + default: + break; + } + } + //fprintf(stderr, "map.add(%s => %p from %s)\n", name, &newAtom, newAtom.getFile()->getPath()); + Mapper::iterator pos = fTable.find(name); + ObjectFile::Atom* existingAtom = NULL; + if ( pos != fTable.end() ) + existingAtom = pos->second; + if ( existingAtom != NULL ) { + // already have atom with same name in symbol table + switch ( (AllDefinitionCombinations)((existingAtom->getDefinitionKind() << 3) | newAtom.getDefinitionKind()) ) { + case kRegAndReg: + throwf("duplicate symbol %s in %s and %s", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath()); + case kRegAndWeak: + // ignore new weak atom, because we already have a non-weak one + useNew = false; + break; + case kRegAndTent: + // ignore new tentative atom, because we already have a regular one + useNew = false; + checkVisibilityMismatch = true; + if ( newAtom.getSize() > existingAtom->getSize() ) { + warning("for symbol %s tentative definition of size %llu from %s is " + "is smaller than the real definition of size %llu from %s", + newAtom.getDisplayName(), newAtom.getSize(), newAtom.getFile()->getPath(), + existingAtom->getSize(), existingAtom->getFile()->getPath()); + } + break; + case kRegAndExtern: + // ignore external atom, because we already have a one + useNew = false; + break; + case kRegAndExternWeak: + // ignore external atom, because we already have a one + useNew = false; + break; + case kRegAndAbsolute: + throwf("duplicate symbol %s in %s and %s", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath()); + break; + case kWeakAndReg: + // replace existing weak atom with regular one + break; + case kWeakAndWeak: + // have another weak atom, use whichever has largest alignment requirement + // because codegen of some client may require alignment + useNew = ( newAtom.getAlignment().trailingZeros() > existingAtom->getAlignment().trailingZeros() ); + checkVisibilityMismatch = true; + break; + case kWeakAndTent: + // replace existing weak atom with tentative one ??? + break; + case kWeakAndExtern: + // keep weak atom, at runtime external one may override + useNew = false; + break; + case kWeakAndExternWeak: + // keep weak atom, at runtime external one may override + useNew = false; + break; + case kWeakAndAbsolute: + // replace existing weak atom with absolute one + break; + case kTentAndReg: + // replace existing tentative atom with regular one + checkVisibilityMismatch = true; + if ( newAtom.getSize() < existingAtom->getSize() ) { + warning("for symbol %s tentative definition of size %llu from %s is " + "being replaced by a real definition of size %llu from %s", + newAtom.getDisplayName(), existingAtom->getSize(), existingAtom->getFile()->getPath(), + newAtom.getSize(), newAtom.getFile()->getPath()); + } + break; + case kTentAndWeak: + // replace existing tentative atom with weak one ??? + break; + case kTentAndTent: + // use largest + checkVisibilityMismatch = true; + if ( newAtom.getSize() < existingAtom->getSize() ) { + useNew = false; + } + else { + if ( newAtom.getAlignment().trailingZeros() < existingAtom->getAlignment().trailingZeros() ) + warning("alignment lost in merging tentative definition %s", newAtom.getDisplayName()); + } + break; + case kTentAndExtern: + case kTentAndExternWeak: + // a tentative definition and a dylib definition, so commons-mode decides how to handle + switch ( fOwner.fOptions.commonsMode() ) { + case Options::kCommonsIgnoreDylibs: + if ( fOwner.fOptions.warnCommons() ) + warning("using common symbol %s from %s and ignoring defintion from dylib %s", + existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath()); + useNew = false; + break; + case Options::kCommonsOverriddenByDylibs: + if ( fOwner.fOptions.warnCommons() ) + warning("replacing common symbol %s from %s with true definition from dylib %s", + existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath()); + break; + case Options::kCommonsConflictsDylibsError: + throwf("common symbol %s from %s conflicts with defintion from dylib %s", + existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath()); + } + break; + case kTentAndAbsolute: + // replace tentative with absolute (can't size check because absolutes have no size) + break; + case kExternAndReg: + // replace external atom with regular one + break; + case kExternAndWeak: + // replace external atom with weak one + break; + case kExternAndTent: + // a tentative definition and a dylib definition, so commons-mode decides how to handle + switch ( fOwner.fOptions.commonsMode() ) { + case Options::kCommonsIgnoreDylibs: + if ( fOwner.fOptions.warnCommons() ) + warning("using common symbol %s from %s and ignoring defintion from dylib %s", + newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath()); + break; + case Options::kCommonsOverriddenByDylibs: + if ( fOwner.fOptions.warnCommons() ) + warning("replacing defintion of %s from dylib %s with common symbol from %s", + newAtom.getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath()); + useNew = false; + break; + case Options::kCommonsConflictsDylibsError: + throwf("common symbol %s from %s conflicts with defintion from dylib %s", + newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath()); + } + break; + case kExternAndExtern: + throwf("duplicate symbol %s in %s and %s\n", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath()); + case kExternAndExternWeak: + // keep strong dylib atom, ignore weak one + useNew = false; + break; + case kExternAndAbsolute: + // replace external atom with absolute one + break; + case kExternWeakAndReg: + // replace existing weak external with regular + break; + case kExternWeakAndWeak: + // replace existing weak external with weak (let dyld decide at runtime which to use) + break; + case kExternWeakAndTent: + // a tentative definition and a dylib definition, so commons-mode decides how to handle + switch ( fOwner.fOptions.commonsMode() ) { + case Options::kCommonsIgnoreDylibs: + if ( fOwner.fOptions.warnCommons() ) + warning("using common symbol %s from %s and ignoring defintion from dylib %s", + newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath()); + break; + case Options::kCommonsOverriddenByDylibs: + if ( fOwner.fOptions.warnCommons() ) + warning("replacing defintion of %s from dylib %s with common symbol from %s", + newAtom.getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath()); + useNew = false; + break; + case Options::kCommonsConflictsDylibsError: + throwf("common symbol %s from %s conflicts with defintion from dylib %s", + newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath()); + } + break; + case kExternWeakAndExtern: + // replace existing weak external with external + break; + case kExternWeakAndExternWeak: + // keep existing external weak + useNew = false; + break; + case kExternWeakAndAbsolute: + // replace existing weak external with absolute + break; + case kAbsoluteAndReg: + throwf("duplicate symbol %s in %s and %s", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath()); + case kAbsoluteAndWeak: + // ignore new weak atom, because we already have a non-weak one + useNew = false; + break; + case kAbsoluteAndTent: + // ignore new tentative atom, because we already have a regular one + useNew = false; + break; + case kAbsoluteAndExtern: + // ignore external atom, because we already have a one + useNew = false; + break; + case kAbsoluteAndExternWeak: + // ignore external atom, because we already have a one + useNew = false; + break; + case kAbsoluteAndAbsolute: + throwf("duplicate symbol %s in %s and %s", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath()); + break; + } + } + if ( (existingAtom != NULL) && checkVisibilityMismatch && (newAtom.getScope() != existingAtom->getScope()) ) { + warning("%s has different visibility (%s) in %s and (%s) in %s", + newAtom.getDisplayName(), (newAtom.getScope() == 1 ? "hidden" : "default"), newAtom.getFile()->getPath(), (existingAtom->getScope() == 1 ? "hidden" : "default"), existingAtom->getFile()->getPath()); + } + if ( useNew ) { + fTable[name] = &newAtom; + if ( existingAtom != NULL ) + fOwner.markDead(existingAtom); + } + else { + fOwner.markDead(&newAtom); + } + return useNew; +} + + + +ObjectFile::Atom* Linker::SymbolTable::find(const char* name) +{ + Mapper::iterator pos = fTable.find(name); + if ( pos != fTable.end() ) { + return pos->second; + } + return NULL; +} + + +void Linker::SymbolTable::getNeededNames(bool andWeakDefintions, std::vector& undefines) +{ + for (Mapper::iterator it=fTable.begin(); it != fTable.end(); it++) { + if ( (it->second == NULL) || (andWeakDefintions && (it->second->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition)) ) { + undefines.push_back(it->first); + } + } +} + + + +bool Linker::AtomSorter::operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right) +{ + if ( left == right ) + return false; + + // first sort by section order (which is already sorted by segment) + unsigned int leftSectionIndex = left->getSection()->getIndex(); + unsigned int rightSectionIndex = right->getSection()->getIndex(); + if ( leftSectionIndex != rightSectionIndex) + return (leftSectionIndex < rightSectionIndex); + + // if a -order_file is specified, then sorting is altered to sort those symbols first + if ( fOverriddenOrdinalMap != NULL ) { + std::map::iterator leftPos = fOverriddenOrdinalMap->find(left); + std::map::iterator rightPos = fOverriddenOrdinalMap->find(right); + std::map::iterator end = fOverriddenOrdinalMap->end(); + if ( leftPos != end ) { + if ( rightPos != end ) { + // both left and right are overridden, so compare overridden ordinals + return leftPos->second < rightPos->second; + } + else { + // left is overridden and right is not, so left < right + return true; + } + } + else { + if ( rightPos != end ) { + // right is overridden and left is not, so right < left + return false; + } + else { + // neither are overridden, do default sort + // fall into default sorting below + } + } + } + + // the __common section can have real or tentative definitions + // we want the real ones to sort before tentative ones + bool leftIsTent = (left->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition); + bool rightIsTent = (right->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition); + if ( leftIsTent != rightIsTent ) + return rightIsTent; + + // lastly sort by atom ordinal. this is already sorted by .o order + return left->getOrdinal() < right->getOrdinal(); +} + + +int main(int argc, const char* argv[]) +{ + const char* archName = NULL; + bool showArch = false; + bool archInferred = false; + try { + // create linker object given command line arguments + Linker ld(argc, argv); + + // save error message prefix + archName = ld.architectureName(); + archInferred = ld.isInferredArchitecture(); + showArch = ld.showArchitectureInErrors(); + + // open all input files + ld.createReaders(); + + // open output file + ld.createWriter(); + + // do linking + ld.link(); + } + catch (const char* msg) { + if ( archInferred ) + fprintf(stderr, "ld: %s for inferred architecture %s\n", msg, archName); + else if ( showArch ) + fprintf(stderr, "ld: %s for architecture %s\n", msg, archName); + else + fprintf(stderr, "ld: %s\n", msg); + return 1; + } + + return 0; +} diff --git a/FireOpal/src/machochecker.cpp b/FireOpal/src/machochecker.cpp new file mode 100644 index 0000000..311809b --- /dev/null +++ b/FireOpal/src/machochecker.cpp @@ -0,0 +1,965 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006-2007 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "MachOFileAbstraction.hpp" +#include "Architectures.hpp" + + + __attribute__((noreturn)) +void throwf(const char* format, ...) +{ + va_list list; + char* p; + va_start(list, format); + vasprintf(&p, format, list); + va_end(list); + + const char* t = p; + throw t; +} + + +template +class MachOChecker +{ +public: + static bool validFile(const uint8_t* fileContent); + static MachOChecker* make(const uint8_t* fileContent, uint32_t fileLength, const char* path) + { return new MachOChecker(fileContent, fileLength, path); } + virtual ~MachOChecker() {} + + +private: + typedef typename A::P P; + typedef typename A::P::E E; + typedef typename A::P::uint_t pint_t; + + class CStringEquals + { + public: + bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } + }; + + typedef __gnu_cxx::hash_set, CStringEquals> StringSet; + + MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path); + void checkMachHeader(); + void checkLoadCommands(); + void checkSection(const macho_segment_command

* segCmd, const macho_section

* sect); + uint8_t loadCommandSizeMask(); + void checkSymbolTable(); + void checkIndirectSymbolTable(); + void checkRelocations(); + void checkExternalReloation(const macho_relocation_info

* reloc); + void checkLocalReloation(const macho_relocation_info

* reloc); + pint_t relocBase(); + bool addressInWritableSegment(pint_t address); + + const char* fPath; + const macho_header

* fHeader; + uint32_t fLength; + const char* fStrings; + const char* fStringsEnd; + const macho_nlist

* fSymbols; + uint32_t fSymbolCount; + const macho_dysymtab_command

* fDynamicSymbolTable; + const uint32_t* fIndirectTable; + uint32_t fIndirectTableCount; + const macho_relocation_info

* fLocalRelocations; + uint32_t fLocalRelocationsCount; + const macho_relocation_info

* fExternalRelocations; + uint32_t fExternalRelocationsCount; + bool fWriteableSegmentWithAddrOver4G; + const macho_segment_command

* fFirstSegment; + const macho_segment_command

* fFirstWritableSegment; +}; + + + +template <> +bool MachOChecker::validFile(const uint8_t* fileContent) +{ + const macho_header

* header = (const macho_header

*)fileContent; + if ( header->magic() != MH_MAGIC ) + return false; + if ( header->cputype() != CPU_TYPE_POWERPC ) + return false; + switch (header->filetype()) { + case MH_EXECUTE: + case MH_DYLIB: + case MH_BUNDLE: + case MH_DYLINKER: + return true; + } + return false; +} + +template <> +bool MachOChecker::validFile(const uint8_t* fileContent) +{ + const macho_header

* header = (const macho_header

*)fileContent; + if ( header->magic() != MH_MAGIC_64 ) + return false; + if ( header->cputype() != CPU_TYPE_POWERPC64 ) + return false; + switch (header->filetype()) { + case MH_EXECUTE: + case MH_DYLIB: + case MH_BUNDLE: + case MH_DYLINKER: + return true; + } + return false; +} + +template <> +bool MachOChecker::validFile(const uint8_t* fileContent) +{ + const macho_header

* header = (const macho_header

*)fileContent; + if ( header->magic() != MH_MAGIC ) + return false; + if ( header->cputype() != CPU_TYPE_I386 ) + return false; + switch (header->filetype()) { + case MH_EXECUTE: + case MH_DYLIB: + case MH_BUNDLE: + case MH_DYLINKER: + return true; + } + return false; +} + +template <> +bool MachOChecker::validFile(const uint8_t* fileContent) +{ + const macho_header

* header = (const macho_header

*)fileContent; + if ( header->magic() != MH_MAGIC_64 ) + return false; + if ( header->cputype() != CPU_TYPE_X86_64 ) + return false; + switch (header->filetype()) { + case MH_EXECUTE: + case MH_DYLIB: + case MH_BUNDLE: + case MH_DYLINKER: + return true; + } + return false; +} + +template <> +bool MachOChecker::validFile(const uint8_t* fileContent) +{ + const macho_header

* header = (const macho_header

*)fileContent; + if ( header->magic() != MH_MAGIC ) + return false; + if ( header->cputype() != CPU_TYPE_ARM ) + return false; + switch (header->filetype()) { + case MH_EXECUTE: + case MH_DYLIB: + case MH_BUNDLE: + case MH_DYLINKER: + return true; + } + return false; +} + +template <> uint8_t MachOChecker::loadCommandSizeMask() { return 0x03; } +template <> uint8_t MachOChecker::loadCommandSizeMask() { return 0x07; } +template <> uint8_t MachOChecker::loadCommandSizeMask() { return 0x03; } +template <> uint8_t MachOChecker::loadCommandSizeMask() { return 0x07; } +template <> uint8_t MachOChecker::loadCommandSizeMask() { return 0x03; } + +template +MachOChecker::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) +{ + // sanity check + if ( ! validFile(fileContent) ) + throw "not a mach-o file that can be checked"; + + fPath = strdup(path); + fHeader = (const macho_header

*)fileContent; + + // sanity check header + checkMachHeader(); + + // check load commands + checkLoadCommands(); + + checkIndirectSymbolTable(); + + checkRelocations(); + + checkSymbolTable(); +} + + +template +void MachOChecker::checkMachHeader() +{ + if ( (fHeader->sizeofcmds() + sizeof(macho_header

)) > fLength ) + throw "sizeofcmds in mach_header is larger than file"; + + uint32_t flags = fHeader->flags(); + const uint32_t invalidBits = MH_INCRLINK | MH_LAZY_INIT | 0xFFC00000; + if ( flags & invalidBits ) + 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"; +} + +template +void MachOChecker::checkLoadCommands() +{ + // check that all load commands fit within the load command space file + const macho_encryption_info_command

* encryption_info = NULL; + const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength; + const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header

) + fHeader->sizeofcmds(); + const uint32_t cmd_count = fHeader->ncmds(); + const macho_load_command

* const cmds = (macho_load_command

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

)); + const macho_load_command

* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + uint32_t size = cmd->cmdsize(); + if ( (size & this->loadCommandSizeMask()) != 0 ) + throwf("load command #%d has a unaligned size", i); + const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize(); + if ( endOfCmd > endOfLoadCommands ) + throwf("load command #%d extends beyond the end of the load commands", i); + if ( endOfCmd > endOfFile ) + throwf("load command #%d extends beyond the end of the file", i); + switch ( cmd->cmd() ) { + case macho_segment_command

::CMD: + case LC_SYMTAB: + case LC_UNIXTHREAD: + case LC_DYSYMTAB: + case LC_LOAD_DYLIB: + case LC_ID_DYLIB: + case LC_LOAD_DYLINKER: + case LC_ID_DYLINKER: + case macho_routines_command

::CMD: + case LC_SUB_FRAMEWORK: + case LC_SUB_CLIENT: + case LC_TWOLEVEL_HINTS: + case LC_PREBIND_CKSUM: + case LC_LOAD_WEAK_DYLIB: + case LC_LAZY_LOAD_DYLIB: + case LC_UUID: + case LC_REEXPORT_DYLIB: + case LC_SEGMENT_SPLIT_INFO: + case LC_CODE_SIGNATURE: + break; + case LC_ENCRYPTION_INFO: + encryption_info = (macho_encryption_info_command

*)cmd; + break; + case LC_SUB_UMBRELLA: + case LC_SUB_LIBRARY: + 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; + default: + throwf("load command #%d is an unknown kind 0x%X", i, cmd->cmd()); + } + cmd = (const macho_load_command

*)endOfCmd; + } + + // check segments + cmd = cmds; + std::vector > segmentAddressRanges; + std::vector > segmentFileOffsetRanges; + const macho_segment_command

* linkEditSegment = NULL; + for (uint32_t i = 0; i < cmd_count; ++i) { + if ( cmd->cmd() == macho_segment_command

::CMD ) { + const macho_segment_command

* segCmd = (const macho_segment_command

*)cmd; + if ( segCmd->cmdsize() != (sizeof(macho_segment_command

) + segCmd->nsects() * sizeof(macho_section_content

)) ) + throw "invalid segment load command size"; + + // see if this overlaps another segment address range + uint64_t startAddr = segCmd->vmaddr(); + uint64_t endAddr = startAddr + segCmd->vmsize(); + for (typename std::vector >::iterator it = segmentAddressRanges.begin(); it != segmentAddressRanges.end(); ++it) { + if ( it->first < startAddr ) { + if ( it->second > startAddr ) + throw "overlapping segment vm addresses"; + } + else if ( it->first > startAddr ) { + if ( it->first < endAddr ) + throw "overlapping segment vm addresses"; + } + else { + throw "overlapping segment vm addresses"; + } + segmentAddressRanges.push_back(std::make_pair(startAddr, endAddr)); + } + // see if this overlaps another segment file offset range + uint64_t startOffset = segCmd->fileoff(); + uint64_t endOffset = startOffset + segCmd->filesize(); + for (typename std::vector >::iterator it = segmentFileOffsetRanges.begin(); it != segmentFileOffsetRanges.end(); ++it) { + if ( it->first < startOffset ) { + if ( it->second > startOffset ) + throw "overlapping segment file data"; + } + else if ( it->first > startOffset ) { + if ( it->first < endOffset ) + throw "overlapping segment file data"; + } + else { + throw "overlapping segment file data"; + } + segmentFileOffsetRanges.push_back(std::make_pair(startOffset, endOffset)); + // check is within file bounds + if ( (startOffset > fLength) || (endOffset > fLength) ) + throw "segment file data is past end of file"; + } + // verify it fits in file + if ( startOffset > fLength ) + throw "segment fileoff does not fit in file"; + if ( endOffset > fLength ) + throw "segment fileoff+filesize does not fit in file"; + + // keep LINKEDIT segment + if ( strcmp(segCmd->segname(), "__LINKEDIT") == 0 ) + linkEditSegment = segCmd; + + // cache interesting segments + if ( fFirstSegment == NULL ) + fFirstSegment = 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

* const sectionsStart = (macho_section

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

)); + const macho_section

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

* sect = sectionsStart; sect < sectionsEnd; ++sect) { + // check all 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) && (segCmd->filesize() != 0) ) { + if ( sect->offset() < startOffset ) + throwf("section %s file offset not within segment", sect->sectname()); + if ( (sect->offset()+sect->size()) > endOffset ) + throwf("section %s file offset not within segment", sect->sectname()); + } + checkSection(segCmd, sect); + } + } + cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); + } + + // verify there was a LINKEDIT segment + if ( linkEditSegment == NULL ) + throw "no __LINKEDIT segment"; + + // checks for executables + bool isStaticExecutable = false; + if ( fHeader->filetype() == MH_EXECUTE ) { + isStaticExecutable = true; + cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch ( cmd->cmd() ) { + case LC_LOAD_DYLINKER: + // the existence of a dyld load command makes a executable dynamic + isStaticExecutable = false; + break; + } + cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); + } + if ( isStaticExecutable ) { + if ( fHeader->flags() != MH_NOUNDEFS ) + throw "invalid bits in mach_header flags for static executable"; + } + } + + // verify encryption info + if ( encryption_info != NULL ) { + if ( fHeader->filetype() != MH_EXECUTE ) + throw "LC_ENCRYPTION_INFO load command is only legal in main executables"; + if ( encryption_info->cryptoff() < (sizeof(macho_header

) + fHeader->sizeofcmds()) ) + throw "LC_ENCRYPTION_INFO load command has cryptoff covers some load commands"; + if ( (encryption_info->cryptoff() % 4096) != 0 ) + throw "LC_ENCRYPTION_INFO load command has cryptoff which is not page aligned"; + if ( (encryption_info->cryptsize() % 4096) != 0 ) + throw "LC_ENCRYPTION_INFO load command has cryptsize which is not page sized"; + for (typename std::vector >::iterator it = segmentFileOffsetRanges.begin(); + it != segmentFileOffsetRanges.end(); ++it) { + if ( (it->first <= encryption_info->cryptoff()) && (encryption_info->cryptoff() < it->second) ) { + if ( (encryption_info->cryptoff() + encryption_info->cryptsize()) > it->second ) + throw "LC_ENCRYPTION_INFO load command is not contained within one segment"; + } + } + } + + // check LC_SYMTAB, LC_DYSYMTAB, and LC_SEGMENT_SPLIT_INFO + cmd = cmds; + bool foundDynamicSymTab = false; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch ( cmd->cmd() ) { + case LC_SYMTAB: + { + const macho_symtab_command

* symtab = (macho_symtab_command

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

*)((char*)fHeader + symtab->symoff()); + if ( symtab->symoff() < linkEditSegment->fileoff() ) + throw "symbol table not in __LINKEDIT"; + if ( (symtab->symoff() + fSymbolCount*sizeof(macho_nlist

*)) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) ) + throw "symbol table end not in __LINKEDIT"; + if ( (symtab->symoff() % sizeof(pint_t)) != 0 ) + throw "symbol table start not pointer aligned"; + fStrings = (char*)fHeader + symtab->stroff(); + fStringsEnd = fStrings + symtab->strsize(); + if ( symtab->stroff() < linkEditSegment->fileoff() ) + throw "string pool not in __LINKEDIT"; + if ( (symtab->stroff()+symtab->strsize()) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) ) + throw "string pool extends beyond __LINKEDIT"; + if ( (symtab->stroff() % 4) != 0 ) // work around until rdar://problem/4737991 is fixed + throw "string pool start not pointer aligned"; + if ( (symtab->strsize() % sizeof(pint_t)) != 0 ) + throw "string pool size not a multiple of pointer size"; + } + break; + case LC_DYSYMTAB: + { + if ( isStaticExecutable ) + throw "LC_DYSYMTAB should not be used in static executable"; + foundDynamicSymTab = true; + fDynamicSymbolTable = (struct macho_dysymtab_command

*)cmd; + fIndirectTable = (uint32_t*)((char*)fHeader + fDynamicSymbolTable->indirectsymoff()); + fIndirectTableCount = fDynamicSymbolTable->nindirectsyms(); + if ( fIndirectTableCount != 0 ) { + if ( fDynamicSymbolTable->indirectsymoff() < linkEditSegment->fileoff() ) + throw "indirect symbol table not in __LINKEDIT"; + if ( (fDynamicSymbolTable->indirectsymoff()+fIndirectTableCount*8) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) ) + throw "indirect symbol table not in __LINKEDIT"; + if ( (fDynamicSymbolTable->indirectsymoff() % sizeof(pint_t)) != 0 ) + throw "indirect symbol table not pointer aligned"; + } + fLocalRelocationsCount = fDynamicSymbolTable->nlocrel(); + if ( fLocalRelocationsCount != 0 ) { + fLocalRelocations = (const macho_relocation_info

*)((char*)fHeader + fDynamicSymbolTable->locreloff()); + if ( fDynamicSymbolTable->locreloff() < linkEditSegment->fileoff() ) + throw "local relocations not in __LINKEDIT"; + if ( (fDynamicSymbolTable->locreloff()+fLocalRelocationsCount*sizeof(macho_relocation_info

)) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) ) + throw "local relocations not in __LINKEDIT"; + if ( (fDynamicSymbolTable->locreloff() % sizeof(pint_t)) != 0 ) + throw "local relocations table not pointer aligned"; + } + fExternalRelocationsCount = fDynamicSymbolTable->nextrel(); + if ( fExternalRelocationsCount != 0 ) { + fExternalRelocations = (const macho_relocation_info

*)((char*)fHeader + fDynamicSymbolTable->extreloff()); + if ( fDynamicSymbolTable->extreloff() < linkEditSegment->fileoff() ) + throw "external relocations not in __LINKEDIT"; + if ( (fDynamicSymbolTable->extreloff()+fExternalRelocationsCount*sizeof(macho_relocation_info

)) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) ) + throw "external relocations not in __LINKEDIT"; + if ( (fDynamicSymbolTable->extreloff() % sizeof(pint_t)) != 0 ) + throw "external relocations table not pointer aligned"; + } + } + break; + case LC_SEGMENT_SPLIT_INFO: + { + if ( isStaticExecutable ) + throw "LC_SEGMENT_SPLIT_INFO should not be used in static executable"; + const macho_linkedit_data_command

* info = (struct macho_linkedit_data_command

*)cmd; + if ( info->dataoff() < linkEditSegment->fileoff() ) + throw "split seg info not in __LINKEDIT"; + if ( (info->dataoff()+info->datasize()) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) ) + throw "split seg info not in __LINKEDIT"; + if ( (info->dataoff() % sizeof(pint_t)) != 0 ) + throw "split seg info table not pointer aligned"; + if ( (info->datasize() % sizeof(pint_t)) != 0 ) + throw "split seg info size not a multiple of pointer size"; + } + break; + } + cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); + } + if ( !isStaticExecutable && !foundDynamicSymTab ) + throw "missing dynamic symbol table"; + if ( fStrings == NULL ) + throw "missing symbol table"; + +} + +template +void MachOChecker::checkSection(const macho_segment_command

* segCmd, const macho_section

* sect) +{ + uint8_t sectionType = (sect->flags() & SECTION_TYPE); + if ( sectionType == S_ZEROFILL ) { + if ( sect->offset() != 0 ) + throwf("section offset should be zero for zero-fill section %s", sect->sectname()); + } + + // more section tests here +} + +template +void MachOChecker::checkIndirectSymbolTable() +{ + const macho_load_command

* const cmds = (macho_load_command

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

)); + const uint32_t cmd_count = fHeader->ncmds(); + const macho_load_command

* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + if ( cmd->cmd() == macho_segment_command

::CMD ) { + const macho_segment_command

* segCmd = (const macho_segment_command

*)cmd; + const macho_section

* const sectionsStart = (macho_section

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

)); + const macho_section

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

* sect = sectionsStart; sect < sectionsEnd; ++sect) { + // make sure all magic sections that use indirect symbol table fit within it + uint32_t start = 0; + uint32_t elementSize = 0; + switch ( sect->flags() & SECTION_TYPE ) { + case S_SYMBOL_STUBS: + elementSize = sect->reserved2(); + start = sect->reserved1(); + break; + case S_LAZY_SYMBOL_POINTERS: + case S_NON_LAZY_SYMBOL_POINTERS: + elementSize = sizeof(pint_t); + start = sect->reserved1(); + break; + } + if ( elementSize != 0 ) { + uint32_t count = sect->size() / elementSize; + if ( (count*elementSize) != sect->size() ) + throwf("%s section size is not an even multiple of element size", sect->sectname()); + if ( (start+count) > fIndirectTableCount ) + throwf("%s section references beyond end of indirect symbol table (%d > %d)", sect->sectname(), start+count, fIndirectTableCount ); + } + } + } + cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); + } +} + + +template +void MachOChecker::checkSymbolTable() +{ + // verify no duplicate external symbol names + if ( fDynamicSymbolTable != NULL ) { + StringSet externalNames; + const macho_nlist

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

* const exportedEnd = &exportedStart[fDynamicSymbolTable->nextdefsym()]; + for(const macho_nlist

* p = exportedStart; p < exportedEnd; ++p) { + const char* symName = &fStrings[p->n_strx()]; + if ( externalNames.find(symName) != externalNames.end() ) + throwf("duplicate external symbol: %s", symName); + externalNames.insert(symName); + } + } +} + + +template <> +ppc::P::uint_t MachOChecker::relocBase() +{ + if ( fHeader->flags() & MH_SPLIT_SEGS ) + return fFirstWritableSegment->vmaddr(); + else + return fFirstSegment->vmaddr(); +} + +template <> +ppc64::P::uint_t MachOChecker::relocBase() +{ + if ( fWriteableSegmentWithAddrOver4G ) + return fFirstWritableSegment->vmaddr(); + else + return fFirstSegment->vmaddr(); +} + +template <> +x86::P::uint_t MachOChecker::relocBase() +{ + if ( fHeader->flags() & MH_SPLIT_SEGS ) + return fFirstWritableSegment->vmaddr(); + else + return fFirstSegment->vmaddr(); +} + +template <> +x86_64::P::uint_t MachOChecker::relocBase() +{ + // check for split-seg + return fFirstWritableSegment->vmaddr(); +} + +template <> +arm::P::uint_t MachOChecker::relocBase() +{ + if ( fHeader->flags() & MH_SPLIT_SEGS ) + return fFirstWritableSegment->vmaddr(); + else + return fFirstSegment->vmaddr(); +} + + +template +bool MachOChecker::addressInWritableSegment(pint_t address) +{ + const macho_load_command

* const cmds = (macho_load_command

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

)); + const uint32_t cmd_count = fHeader->ncmds(); + const macho_load_command

* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + if ( cmd->cmd() == macho_segment_command

::CMD ) { + const macho_segment_command

* segCmd = (const macho_segment_command

*)cmd; + if ( (address >= segCmd->vmaddr()) && (address < segCmd->vmaddr()+segCmd->vmsize()) ) { + // if segment is writable, we are fine + if ( (segCmd->initprot() & VM_PROT_WRITE) != 0 ) + return true; + // could be a text reloc, make sure section bit is set + const macho_section

* const sectionsStart = (macho_section

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

)); + const macho_section

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

* sect = sectionsStart; sect < sectionsEnd; ++sect) { + if ( (sect->addr() <= address) && (address < (sect->addr()+sect->size())) ) { + // found section for this address, if has relocs we are fine + return ( (sect->flags() & (S_ATTR_EXT_RELOC|S_ATTR_LOC_RELOC)) != 0 ); + } + } + } + } + cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); + } + return false; +} + + +template <> +void MachOChecker::checkExternalReloation(const macho_relocation_info

* reloc) +{ + if ( reloc->r_length() != 2 ) + throw "bad external relocation length"; + if ( reloc->r_type() != GENERIC_RELOC_VANILLA ) + throw "unknown external relocation type"; + if ( reloc->r_pcrel() != 0 ) + throw "bad external relocation pc_rel"; + if ( reloc->r_extern() == 0 ) + throw "local relocation found with external relocations"; + if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) ) + throw "external relocation address not in writable segment"; + // FIX: check r_symbol +} + +template <> +void MachOChecker::checkExternalReloation(const macho_relocation_info

* reloc) +{ + if ( reloc->r_length() != 3 ) + throw "bad external relocation length"; + if ( reloc->r_type() != GENERIC_RELOC_VANILLA ) + throw "unknown external relocation type"; + if ( reloc->r_pcrel() != 0 ) + throw "bad external relocation pc_rel"; + if ( reloc->r_extern() == 0 ) + throw "local relocation found with external relocations"; + if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) ) + throw "external relocation address not in writable segment"; + // FIX: check r_symbol +} + +template <> +void MachOChecker::checkExternalReloation(const macho_relocation_info

* reloc) +{ + if ( reloc->r_length() != 2 ) + throw "bad external relocation length"; + if ( reloc->r_type() != GENERIC_RELOC_VANILLA ) + throw "unknown external relocation type"; + if ( reloc->r_pcrel() != 0 ) + throw "bad external relocation pc_rel"; + if ( reloc->r_extern() == 0 ) + throw "local relocation found with external relocations"; + if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) ) + throw "external relocation address not in writable segment"; + // FIX: check r_symbol +} + + +template <> +void MachOChecker::checkExternalReloation(const macho_relocation_info

* reloc) +{ + if ( reloc->r_length() != 3 ) + throw "bad external relocation length"; + if ( reloc->r_type() != X86_64_RELOC_UNSIGNED ) + throw "unknown external relocation type"; + if ( reloc->r_pcrel() != 0 ) + throw "bad external relocation pc_rel"; + if ( reloc->r_extern() == 0 ) + throw "local relocation found with external relocations"; + if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) ) + throw "exernal relocation address not in writable segment"; + // FIX: check r_symbol +} + +template <> +void MachOChecker::checkExternalReloation(const macho_relocation_info

* reloc) +{ + if ( reloc->r_length() != 2 ) + throw "bad external relocation length"; + if ( reloc->r_type() != ARM_RELOC_VANILLA ) + throw "unknown external relocation type"; + if ( reloc->r_pcrel() != 0 ) + throw "bad external relocation pc_rel"; + if ( reloc->r_extern() == 0 ) + throw "local relocation found with external relocations"; + if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) ) + throw "external relocation address not in writable segment"; + // FIX: check r_symbol +} + + +template <> +void MachOChecker::checkLocalReloation(const macho_relocation_info

* reloc) +{ + if ( reloc->r_address() & R_SCATTERED ) { + // scattered + const macho_scattered_relocation_info

* sreloc = (const macho_scattered_relocation_info

*)reloc; + // FIX + + } + else { + // ignore pair relocs + if ( reloc->r_type() == PPC_RELOC_PAIR ) + return; + // FIX + if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) ) + throwf("local relocation address 0x%08X not in writable segment", reloc->r_address()); + } +} + + +template <> +void MachOChecker::checkLocalReloation(const macho_relocation_info

* reloc) +{ + if ( reloc->r_length() != 3 ) + throw "bad local relocation length"; + if ( reloc->r_type() != GENERIC_RELOC_VANILLA ) + throw "unknown local relocation type"; + if ( reloc->r_pcrel() != 0 ) + throw "bad local relocation pc_rel"; + if ( reloc->r_extern() != 0 ) + throw "external relocation found with local relocations"; + if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) ) + throw "local relocation address not in writable segment"; +} + +template <> +void MachOChecker::checkLocalReloation(const macho_relocation_info

* reloc) +{ + // FIX +} + +template <> +void MachOChecker::checkLocalReloation(const macho_relocation_info

* reloc) +{ + if ( reloc->r_length() != 3 ) + throw "bad local relocation length"; + if ( reloc->r_type() != X86_64_RELOC_UNSIGNED ) + throw "unknown local relocation type"; + if ( reloc->r_pcrel() != 0 ) + throw "bad local relocation pc_rel"; + if ( reloc->r_extern() != 0 ) + throw "external relocation found with local relocations"; + if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) ) + throw "local relocation address not in writable segment"; +} + +template <> +void MachOChecker::checkLocalReloation(const macho_relocation_info

* reloc) +{ + if ( reloc->r_address() & R_SCATTERED ) { + // scattered + const macho_scattered_relocation_info

* sreloc = (const macho_scattered_relocation_info

*)reloc; + if ( sreloc->r_length() != 2 ) + throw "bad local scattered relocation length"; + if ( sreloc->r_type() != ARM_RELOC_PB_LA_PTR ) + throw "bad local scattered relocation type"; + } + else { + if ( reloc->r_length() != 2 ) + throw "bad local relocation length"; + if ( reloc->r_extern() != 0 ) + throw "external relocation found with local relocations"; + if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) ) + throw "local relocation address not in writable segment"; + } +} + +template +void MachOChecker::checkRelocations() +{ + // external relocations should be sorted to minimize dyld symbol lookups + // therefore every reloc with the same r_symbolnum value should be contiguous + std::set previouslySeenSymbolIndexes; + uint32_t lastSymbolIndex = 0xFFFFFFFF; + const macho_relocation_info

* const externRelocsEnd = &fExternalRelocations[fExternalRelocationsCount]; + for (const macho_relocation_info

* reloc = fExternalRelocations; reloc < externRelocsEnd; ++reloc) { + this->checkExternalReloation(reloc); + if ( reloc->r_symbolnum() != lastSymbolIndex ) { + if ( previouslySeenSymbolIndexes.count(reloc->r_symbolnum()) != 0 ) + throw "external relocations not sorted"; + previouslySeenSymbolIndexes.insert(lastSymbolIndex); + lastSymbolIndex = reloc->r_symbolnum(); + } + } + + const macho_relocation_info

* const localRelocsEnd = &fLocalRelocations[fLocalRelocationsCount]; + for (const macho_relocation_info

* reloc = fLocalRelocations; reloc < localRelocsEnd; ++reloc) { + this->checkLocalReloation(reloc); + } +} + + +static void check(const char* path) +{ + struct stat stat_buf; + + try { + int fd = ::open(path, O_RDONLY, 0); + if ( fd == -1 ) + throw "cannot open file"; + ::fstat(fd, &stat_buf); + uint32_t length = stat_buf.st_size; + uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); + if ( p == ((uint8_t*)(-1)) ) + throw "cannot map file"; + ::close(fd); + const mach_header* mh = (mach_header*)p; + 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) { + size_t offset = OSSwapBigToHostInt32(archs[i].offset); + size_t size = OSSwapBigToHostInt32(archs[i].size); + unsigned int cputype = OSSwapBigToHostInt32(archs[i].cputype); + + switch(cputype) { + case CPU_TYPE_POWERPC: + if ( MachOChecker::validFile(p + offset) ) + MachOChecker::make(p + offset, size, path); + else + throw "in universal file, ppc slice does not contain ppc mach-o"; + break; + case CPU_TYPE_I386: + if ( MachOChecker::validFile(p + offset) ) + MachOChecker::make(p + offset, size, path); + else + throw "in universal file, i386 slice does not contain i386 mach-o"; + break; + case CPU_TYPE_POWERPC64: + if ( MachOChecker::validFile(p + offset) ) + MachOChecker::make(p + offset, size, path); + else + throw "in universal file, ppc64 slice does not contain ppc64 mach-o"; + break; + case CPU_TYPE_X86_64: + if ( MachOChecker::validFile(p + offset) ) + MachOChecker::make(p + offset, size, path); + else + throw "in universal file, x86_64 slice does not contain x86_64 mach-o"; + break; + case CPU_TYPE_ARM: + if ( MachOChecker::validFile(p + offset) ) + MachOChecker::make(p + offset, size, path); + 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); + } + } + } + else if ( MachOChecker::validFile(p) ) { + MachOChecker::make(p, length, path); + } + else if ( MachOChecker::validFile(p) ) { + MachOChecker::make(p, length, path); + } + else if ( MachOChecker::validFile(p) ) { + MachOChecker::make(p, length, path); + } + else if ( MachOChecker::validFile(p) ) { + MachOChecker::make(p, length, path); + } + else if ( MachOChecker::validFile(p) ) { + MachOChecker::make(p, length, path); + } + else { + throw "not a known file type"; + } + } + catch (const char* msg) { + throwf("%s in %s", msg, 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); + } + } + else { + check(arg); + } + } + } + catch (const char* msg) { + fprintf(stderr, "machocheck failed: %s\n", msg); + return 1; + } + + return 0; +} + + + diff --git a/FireOpal/src/rebase.cpp b/FireOpal/src/rebase.cpp new file mode 100644 index 0000000..ad9b905 --- /dev/null +++ b/FireOpal/src/rebase.cpp @@ -0,0 +1,945 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "MachOFileAbstraction.hpp" +#include "Architectures.hpp" + +static bool verbose = false; + +__attribute__((noreturn)) +void throwf(const char* format, ...) +{ + va_list list; + char* p; + va_start(list, format); + vasprintf(&p, format, list); + va_end(list); + + const char* t = p; + throw t; +} + + +class AbstractRebaser +{ +public: + virtual cpu_type_t getArchitecture() const = 0; + virtual uint64_t getBaseAddress() const = 0; + virtual uint64_t getVMSize() const = 0; + virtual void setBaseAddress(uint64_t) = 0; +}; + + +template +class Rebaser : public AbstractRebaser +{ +public: + Rebaser(const void* machHeader); + virtual ~Rebaser() {} + + virtual cpu_type_t getArchitecture() const; + virtual uint64_t getBaseAddress() const; + virtual uint64_t getVMSize() const; + virtual void setBaseAddress(uint64_t); + +private: + typedef typename A::P P; + typedef typename A::P::E E; + typedef typename A::P::uint_t pint_t; + + struct vmmap { pint_t vmaddr; pint_t vmsize; pint_t fileoff; }; + + void setRelocBase(); + void buildSectionTable(); + void adjustLoadCommands(); + void adjustSymbolTable(); + void adjustDATA(); + void doLocalRelocation(const macho_relocation_info

* reloc); + pint_t* mappedAddressForVMAddress(uint32_t vmaddress); + + const macho_header

* fHeader; + pint_t fOrignalVMRelocBaseAddress; + pint_t fSlide; + pint_t fRelocBase; + std::vector fVMMApping; +}; + + + +class MultiArchRebaser +{ +public: + MultiArchRebaser(const char* path, bool writable=false); + ~MultiArchRebaser(); + + const std::vector& getArchs() const { return fRebasers; } + void commit(); + +private: + std::vector fRebasers; + void* fMappingAddress; + uint64_t fFileSize; +}; + + + +MultiArchRebaser::MultiArchRebaser(const char* path, bool writable) + : fMappingAddress(0), fFileSize(0) +{ + // map in whole file + int fd = ::open(path, (writable ? O_RDWR : O_RDONLY), 0); + if ( fd == -1 ) + throwf("can't open file, errno=%d", errno); + struct stat stat_buf; + if ( fstat(fd, &stat_buf) == -1) + throwf("can't stat open file %s, errno=%d", path, errno); + if ( stat_buf.st_size < 20 ) + throwf("file too small %s", path); + const int prot = writable ? (PROT_READ | PROT_WRITE) : PROT_READ; + const int flags = writable ? (MAP_FILE | MAP_SHARED) : (MAP_FILE | MAP_PRIVATE); + uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, prot, flags, fd, 0); + if ( p == (uint8_t*)(-1) ) + throwf("can't map file %s, errno=%d", path, errno); + ::close(fd); + + // if fat file, process each architecture + const fat_header* fh = (fat_header*)p; + const mach_header* mh = (mach_header*)p; + if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) { + // Fat header is always big-endian + const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header)); + for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) { + uint32_t fileOffset = OSSwapBigToHostInt32(archs[i].offset); + try { + switch ( OSSwapBigToHostInt32(archs[i].cputype) ) { + case CPU_TYPE_POWERPC: + fRebasers.push_back(new Rebaser(&p[fileOffset])); + break; + case CPU_TYPE_POWERPC64: + fRebasers.push_back(new Rebaser(&p[fileOffset])); + break; + case CPU_TYPE_I386: + fRebasers.push_back(new Rebaser(&p[fileOffset])); + break; + case CPU_TYPE_X86_64: + fRebasers.push_back(new Rebaser(&p[fileOffset])); + break; + case CPU_TYPE_ARM: + fRebasers.push_back(new Rebaser(&p[fileOffset])); + break; + default: + throw "unknown file format"; + } + } + catch (const char* msg) { + fprintf(stderr, "rebase warning: %s for %s\n", msg, path); + } + } + } + else { + try { + if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC)) { + fRebasers.push_back(new Rebaser(mh)); + } + else if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC64)) { + fRebasers.push_back(new Rebaser(mh)); + } + else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) { + fRebasers.push_back(new Rebaser(mh)); + } + else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_X86_64)) { + fRebasers.push_back(new Rebaser(mh)); + } + else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_ARM)) { + fRebasers.push_back(new Rebaser(mh)); + } + else { + throw "unknown file format"; + } + } + catch (const char* msg) { + fprintf(stderr, "rebase warning: %s for %s\n", msg, path); + } + } + + fMappingAddress = p; + fFileSize = stat_buf.st_size; +} + + +MultiArchRebaser::~MultiArchRebaser() +{ + ::munmap(fMappingAddress, fFileSize); +} + +void MultiArchRebaser::commit() +{ + ::msync(fMappingAddress, fFileSize, MS_ASYNC); +} + + + +template +Rebaser::Rebaser(const void* machHeader) + : fHeader((const macho_header

*)machHeader) +{ + switch ( fHeader->filetype() ) { + case MH_DYLIB: + if ( (fHeader->flags() & MH_SPLIT_SEGS) != 0 ) + throw "split-seg dylibs cannot be rebased"; + break; + case MH_BUNDLE: + break; + default: + throw "file is not a dylib or bundle"; + } + +} + +template <> cpu_type_t Rebaser::getArchitecture() const { return CPU_TYPE_POWERPC; } +template <> cpu_type_t Rebaser::getArchitecture() const { return CPU_TYPE_POWERPC64; } +template <> cpu_type_t Rebaser::getArchitecture() const { return CPU_TYPE_I386; } +template <> cpu_type_t Rebaser::getArchitecture() const { return CPU_TYPE_X86_64; } +template <> cpu_type_t Rebaser::getArchitecture() const { return CPU_TYPE_ARM; } + +template +uint64_t Rebaser::getBaseAddress() const +{ + uint64_t lowestSegmentAddress = LLONG_MAX; + const macho_load_command

* const cmds = (macho_load_command

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

)); + const uint32_t cmd_count = fHeader->ncmds(); + const macho_load_command

* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + if ( cmd->cmd() == macho_segment_command

::CMD ) { + const macho_segment_command

* segCmd = (const macho_segment_command

*)cmd; + if ( segCmd->vmaddr() < lowestSegmentAddress ) { + lowestSegmentAddress = segCmd->vmaddr(); + } + } + cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); + } + return lowestSegmentAddress; +} + +template +uint64_t Rebaser::getVMSize() const +{ + const macho_segment_command

* highestSegmentCmd = NULL; + const macho_load_command

* const cmds = (macho_load_command

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

)); + const uint32_t cmd_count = fHeader->ncmds(); + const macho_load_command

* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + if ( cmd->cmd() == macho_segment_command

::CMD ) { + const macho_segment_command

* segCmd = (const macho_segment_command

*)cmd; + if ( (highestSegmentCmd == NULL) || (segCmd->vmaddr() > highestSegmentCmd->vmaddr()) ) { + highestSegmentCmd = segCmd; + } + } + cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); + } + + return ((highestSegmentCmd->vmaddr() + highestSegmentCmd->vmsize() - this->getBaseAddress() + 4095) & (-4096)); +} + + +template +void Rebaser::setBaseAddress(uint64_t addr) +{ + // calculate slide + fSlide = addr - this->getBaseAddress(); + + // compute base address for relocations + this->setRelocBase(); + + // build cache of section index to section + this->buildSectionTable(); + + // update load commands + this->adjustLoadCommands(); + + // update symbol table + this->adjustSymbolTable(); + + // update writable segments that have internal pointers + this->adjustDATA(); +} + +template +void Rebaser::adjustLoadCommands() +{ + const macho_segment_command

* highestSegmentCmd = NULL; + const macho_load_command

* const cmds = (macho_load_command

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

)); + const uint32_t cmd_count = fHeader->ncmds(); + const macho_load_command

* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch ( cmd->cmd() ) { + case LC_ID_DYLIB: + if ( (fHeader->flags() & MH_PREBOUND) != 0 ) { + // clear timestamp so that any prebound clients are invalidated + macho_dylib_command

* dylib = (macho_dylib_command

*)cmd; + dylib->set_timestamp(1); + } + break; + case LC_LOAD_DYLIB: + case LC_LOAD_WEAK_DYLIB: + if ( (fHeader->flags() & MH_PREBOUND) != 0 ) { + // clear expected timestamps so that this image will load with invalid prebinding + macho_dylib_command

* dylib = (macho_dylib_command

*)cmd; + dylib->set_timestamp(2); + } + break; + case macho_routines_command

::CMD: + // update -init command + { + struct macho_routines_command

* routines = (struct macho_routines_command

*)cmd; + routines->set_init_address(routines->init_address() + fSlide); + } + break; + case macho_segment_command

::CMD: + // update segment commands + { + macho_segment_command

* seg = (macho_segment_command

*)cmd; + seg->set_vmaddr(seg->vmaddr() + fSlide); + macho_section

* const sectionsStart = (macho_section

*)((char*)seg + sizeof(macho_segment_command

)); + macho_section

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

* sect = sectionsStart; sect < sectionsEnd; ++sect) { + sect->set_addr(sect->addr() + fSlide); + } + } + break; + } + cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); + } +} + + +template +void Rebaser::buildSectionTable() +{ + // build vector of sections + const macho_load_command

* const cmds = (macho_load_command

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

)); + const uint32_t cmd_count = fHeader->ncmds(); + const macho_load_command

* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + if ( cmd->cmd() == macho_segment_command

::CMD ) { + const macho_segment_command

* seg = (macho_segment_command

*)cmd; + vmmap mapping; + mapping.vmaddr = seg->vmaddr(); + mapping.vmsize = seg->vmsize(); + mapping.fileoff = seg->fileoff(); + fVMMApping.push_back(mapping); + } + cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); + } +} + + +template +void Rebaser::adjustSymbolTable() +{ + const macho_dysymtab_command

* dysymtab = NULL; + macho_nlist

* symbolTable = NULL; + + // get symbol table info + const macho_load_command

* const cmds = (macho_load_command

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

)); + const uint32_t cmd_count = fHeader->ncmds(); + const macho_load_command

* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd()) { + case LC_SYMTAB: + { + const macho_symtab_command

* symtab = (macho_symtab_command

*)cmd; + symbolTable = (macho_nlist

*)(((uint8_t*)fHeader) + symtab->symoff()); + } + break; + case LC_DYSYMTAB: + dysymtab = (macho_dysymtab_command

*)cmd; + break; + } + cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); + } + + // walk all exports and slide their n_value + macho_nlist

* lastExport = &symbolTable[dysymtab->iextdefsym()+dysymtab->nextdefsym()]; + for (macho_nlist

* entry = &symbolTable[dysymtab->iextdefsym()]; entry < lastExport; ++entry) { + if ( (entry->n_type() & N_TYPE) == N_SECT ) + entry->set_n_value(entry->n_value() + fSlide); + } + + // walk all local symbols and slide their n_value + macho_nlist

* lastLocal = &symbolTable[dysymtab->ilocalsym()+dysymtab->nlocalsym()]; + for (macho_nlist

* entry = &symbolTable[dysymtab->ilocalsym()]; entry < lastLocal; ++entry) { + if ( entry->n_sect() != NO_SECT ) + entry->set_n_value(entry->n_value() + fSlide); + } + + // FIXME ¥¥¥ adjust dylib_module if it exists +} + +template +void Rebaser::adjustDATA() +{ + const macho_dysymtab_command

* dysymtab = NULL; + + // get symbol table info + const macho_load_command

* const cmds = (macho_load_command

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

)); + const uint32_t cmd_count = fHeader->ncmds(); + const macho_load_command

* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + switch (cmd->cmd()) { + case LC_DYSYMTAB: + dysymtab = (macho_dysymtab_command

*)cmd; + break; + } + cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); + } + + // walk all local relocations and slide every pointer + const macho_relocation_info

* const relocsStart = (macho_relocation_info

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

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

* reloc=relocsStart; reloc < relocsEnd; ++reloc) { + this->doLocalRelocation(reloc); + } + + // walk non-lazy-pointers and slide the ones that are LOCAL + cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + if ( cmd->cmd() == macho_segment_command

::CMD ) { + const macho_segment_command

* seg = (macho_segment_command

*)cmd; + const macho_section

* const sectionsStart = (macho_section

*)((char*)seg + sizeof(macho_segment_command

)); + const macho_section

* const sectionsEnd = §ionsStart[seg->nsects()]; + const uint32_t* const indirectTable = (uint32_t*)(((uint8_t*)fHeader) + dysymtab->indirectsymoff()); + for(const macho_section

* sect = sectionsStart; sect < sectionsEnd; ++sect) { + if ( (sect->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) { + const uint32_t indirectTableOffset = sect->reserved1(); + uint32_t pointerCount = sect->size() / sizeof(pint_t); + pint_t* nonLazyPointer = (pint_t*)(((uint8_t*)fHeader) + sect->offset()); + for (uint32_t i=0; i < pointerCount; ++i, ++nonLazyPointer) { + if ( E::get32(indirectTable[indirectTableOffset + i]) == INDIRECT_SYMBOL_LOCAL ) { + P::setP(*nonLazyPointer, A::P::getP(*nonLazyPointer) + fSlide); + } + } + } + } + } + cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); + } + +} + + +template +typename A::P::uint_t* Rebaser::mappedAddressForVMAddress(uint32_t vmaddress) +{ + for(typename std::vector::iterator it = fVMMApping.begin(); it != fVMMApping.end(); ++it) { + //fprintf(stderr, "vmaddr=0x%08lX, vmsize=0x%08lX\n", it->vmaddr, it->vmsize); + if ( (vmaddress >= it->vmaddr) && (vmaddress < (it->vmaddr+it->vmsize)) ) { + return (pint_t*)((vmaddress - it->vmaddr) + it->fileoff + (uint8_t*)fHeader); + } + } + throwf("reloc address 0x%08X not found", vmaddress); +} + + +template <> +void Rebaser::doLocalRelocation(const macho_relocation_info* reloc) +{ + if ( reloc->r_type() == X86_64_RELOC_UNSIGNED ) { + pint_t* addr = mappedAddressForVMAddress(reloc->r_address() + fOrignalVMRelocBaseAddress); + P::setP(*addr, P::getP(*addr) + fSlide); + } + else { + throw "invalid relocation type"; + } +} + +template <> +void Rebaser::doLocalRelocation(const macho_relocation_info

* reloc) +{ + if ( (reloc->r_address() & R_SCATTERED) == 0 ) { + if ( reloc->r_type() == GENERIC_RELOC_VANILLA ) { + pint_t* addr = mappedAddressForVMAddress(reloc->r_address() + fOrignalVMRelocBaseAddress); + P::setP(*addr, P::getP(*addr) + fSlide); + } + } + else { + macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; + if ( sreloc->r_type() == PPC_RELOC_PB_LA_PTR ) { + sreloc->set_r_value( sreloc->r_value() + fSlide ); + } + else { + throw "cannot rebase final linked image with scattered relocations"; + } + } +} + +template <> +void Rebaser::doLocalRelocation(const macho_relocation_info

* reloc) +{ + if ( (reloc->r_address() & R_SCATTERED) == 0 ) { + if ( reloc->r_type() == GENERIC_RELOC_VANILLA ) { + pint_t* addr = mappedAddressForVMAddress(reloc->r_address() + fOrignalVMRelocBaseAddress); + P::setP(*addr, P::getP(*addr) + fSlide); + } + } + else { + macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; + if ( sreloc->r_type() == GENERIC_RELOC_PB_LA_PTR ) { + sreloc->set_r_value( sreloc->r_value() + fSlide ); + } + else { + throw "cannot rebase final linked image with scattered relocations"; + } + } +} + +template <> +void Rebaser::doLocalRelocation(const macho_relocation_info

* reloc) +{ + if ( (reloc->r_address() & R_SCATTERED) == 0 ) { + if ( reloc->r_type() == ARM_RELOC_VANILLA ) { + pint_t* addr = mappedAddressForVMAddress(reloc->r_address() + fOrignalVMRelocBaseAddress); + P::setP(*addr, P::getP(*addr) + fSlide); + } + } + else { + macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; + if ( sreloc->r_type() == ARM_RELOC_PB_LA_PTR ) { + sreloc->set_r_value( sreloc->r_value() + fSlide ); + } + else { + throw "cannot rebase final linked image with scattered relocations"; + } + } +} + +template +void Rebaser::doLocalRelocation(const macho_relocation_info

* reloc) +{ + if ( (reloc->r_address() & R_SCATTERED) == 0 ) { + if ( reloc->r_type() == GENERIC_RELOC_VANILLA ) { + pint_t* addr = mappedAddressForVMAddress(reloc->r_address() + fOrignalVMRelocBaseAddress); + P::setP(*addr, P::getP(*addr) + fSlide); + } + } + else { + throw "cannot rebase final linked image with scattered relocations"; + } +} + + +template +void Rebaser::setRelocBase() +{ + // reloc addresses are from the start of the mapped file (base address) + fRelocBase = (pint_t)fHeader; + fOrignalVMRelocBaseAddress = this->getBaseAddress(); + //fprintf(stderr, "fOrignalVMRelocBaseAddress=0x%08X\n", fOrignalVMRelocBaseAddress); +} + +template <> +void Rebaser::setRelocBase() +{ + // reloc addresses either: + // 1) from the base address if no writable segment is > 4GB from base address + // 2) from start of first writable segment + const macho_load_command

* const cmds = (macho_load_command

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

)); + const uint32_t cmd_count = fHeader->ncmds(); + const macho_load_command

* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + if ( cmd->cmd() == macho_segment_command

::CMD ) { + const macho_segment_command

* segCmd = (const macho_segment_command

*)cmd; + if ( segCmd->initprot() & VM_PROT_WRITE ) { + if ( (segCmd->vmaddr() + segCmd->vmsize() - this->getBaseAddress()) > 0x100000000ULL ) { + // found writable segment with address > 4GB past base address + fRelocBase = segCmd->fileoff() + (pint_t)fHeader; + fOrignalVMRelocBaseAddress = segCmd->vmaddr(); + return; + } + } + } + cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); + } + // just use base address + fRelocBase = (pint_t)fHeader; + fOrignalVMRelocBaseAddress = this->getBaseAddress(); +} + +template <> +void Rebaser::setRelocBase() +{ + // reloc addresses are always based from the start of the first writable segment + const macho_load_command

* const cmds = (macho_load_command

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

)); + const uint32_t cmd_count = fHeader->ncmds(); + const macho_load_command

* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + if ( cmd->cmd() == macho_segment_command

::CMD ) { + const macho_segment_command

* segCmd = (const macho_segment_command

*)cmd; + if ( segCmd->initprot() & VM_PROT_WRITE ) { + fRelocBase = segCmd->fileoff() + (pint_t)fHeader; + fOrignalVMRelocBaseAddress = segCmd->vmaddr(); + return; + } + } + cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); + } + throw "no writable segment"; +} + + +static void copyFile(const char* srcFile, const char* dstFile) +{ + // open files + int src = open(srcFile, O_RDONLY); + if ( src == -1 ) + throwf("can't open file %s, errno=%d", srcFile, errno); + struct stat stat_buf; + if ( fstat(src, &stat_buf) == -1) + throwf("can't stat open file %s, errno=%d", srcFile, errno); + + // create new file with all same permissions to hold copy of dylib + ::unlink(dstFile); + int dst = open(dstFile, O_CREAT | O_RDWR | O_TRUNC, stat_buf.st_mode); + if ( dst == -1 ) + throwf("can't create temp file %s, errnor=%d", dstFile, errno); + + // mark source as "don't cache" + (void)fcntl(src, F_NOCACHE, 1); + // we want to cache the dst because we are about to map it in and modify it + + // copy permission bits + if ( chmod(dstFile, stat_buf.st_mode & 07777) == -1 ) + throwf("can't chmod temp file %s, errno=%d", dstFile, errno); + if ( chown(dstFile, stat_buf.st_uid, stat_buf.st_gid) == -1) + throwf("can't chown temp file %s, errno=%d", dstFile, errno); + + // copy contents + ssize_t len; + const uint32_t kBufferSize = 128*1024; + static uint8_t* buffer = NULL; + if ( buffer == NULL ) { + vm_address_t addr = 0; + if ( vm_allocate(mach_task_self(), &addr, kBufferSize, true /*find range*/) == KERN_SUCCESS ) + buffer = (uint8_t*)addr; + else + throw "can't allcoate copy buffer"; + } + while ( (len = read(src, buffer, kBufferSize)) > 0 ) { + if ( write(dst, buffer, len) == -1 ) + throwf("write failure copying feil %s, errno=%d", dstFile, errno); + } + + // close files + int result1 = close(dst); + int result2 = close(src); + if ( (result1 != 0) || (result2 != 0) ) + throw "can't close file"; +} + + +// scan dylibs and collect size info +// calculate new base address for each dylib +// rebase each file +// copy to temp and mmap +// update content +// unmap/flush +// rename + +struct archInfo { + cpu_type_t arch; + uint64_t vmSize; + uint64_t orgBase; + uint64_t newBase; +}; + +struct fileInfo +{ + fileInfo(const char* p) : path(p) {} + + const char* path; + std::vector archs; +}; + +// +// add archInfos to fileInfo for every slice of a fat file +// for ppc, there may be duplicate architectures (with different sub-types) +// +static void setSizes(fileInfo& info, const std::set& onlyArchs) +{ + const MultiArchRebaser mar(info.path); + const std::vector& rebasers = mar.getArchs(); + for(std::set::iterator ait=onlyArchs.begin(); ait != onlyArchs.end(); ++ait) { + for(std::vector::const_iterator rit=rebasers.begin(); rit != rebasers.end(); ++rit) { + AbstractRebaser* rebaser = *rit; + if ( rebaser->getArchitecture() == *ait ) { + archInfo ai; + ai.arch = *ait; + ai.vmSize = rebaser->getVMSize(); + ai.orgBase = rebaser->getBaseAddress(); + ai.newBase = 0; + //fprintf(stderr, "base=0x%llX, size=0x%llX\n", ai.orgBase, ai.vmSize); + info.archs.push_back(ai); + } + } + } +} + +static const char* nameForArch(cpu_type_t arch) +{ + switch( arch ) { + case CPU_TYPE_POWERPC: + return "ppc"; + case CPU_TYPE_POWERPC64: + return "ppca64"; + case CPU_TYPE_I386: + return "i386"; + case CPU_TYPE_X86_64: + return "x86_64"; + case CPU_TYPE_ARM: + return "arm"; + } + return "unknown"; +} + +static void rebase(const fileInfo& info) +{ + // generate temp file name + char realFilePath[PATH_MAX]; + if ( realpath(info.path, realFilePath) == NULL ) { + throwf("realpath() failed on %s, errno=%d", info.path, errno); + } + const char* tempPath; + asprintf((char**)&tempPath, "%s_rebase", realFilePath); + + // copy whole file to temp file + copyFile(info.path, tempPath); + + try { + // rebase temp file + MultiArchRebaser mar(tempPath, true); + const std::vector& rebasers = mar.getArchs(); + for(std::vector::const_iterator fait=info.archs.begin(); fait != info.archs.end(); ++fait) { + for(std::vector::const_iterator rit=rebasers.begin(); rit != rebasers.end(); ++rit) { + if ( (*rit)->getArchitecture() == fait->arch ) { + (*rit)->setBaseAddress(fait->newBase); + if ( verbose ) + printf("%8s 0x%0llX -> 0x%0llX %s\n", nameForArch(fait->arch), fait->orgBase, fait->newBase, info.path); + } + } + } + + // flush temp file out to disk + mar.commit(); + + // rename + int result = rename(tempPath, info.path); + if ( result != 0 ) { + throwf("can't swap temporary rebased file: rename(%s,%s) returned errno=%d", tempPath, info.path, errno); + } + + // make sure every really gets out to disk + ::sync(); + } + catch (const char* msg) { + // delete temp file + ::unlink(tempPath); + + // throw exception with file name added + const char* newMsg; + asprintf((char**)&newMsg, "%s for file %s", msg, info.path); + throw newMsg; + } +} + +static uint64_t totalVMSize(cpu_type_t arch, std::vector& files) +{ + uint64_t totalSize = 0; + for(std::vector::iterator fit=files.begin(); fit != files.end(); ++fit) { + fileInfo& fi = *fit; + for(std::vector::iterator fait=fi.archs.begin(); fait != fi.archs.end(); ++fait) { + if ( fait->arch == arch ) + totalSize += fait->vmSize; + } + } + return totalSize; +} + +static uint64_t startAddress(cpu_type_t arch, std::vector& files, uint64_t lowAddress, uint64_t highAddress) +{ + if ( lowAddress != 0 ) + return lowAddress; + else if ( highAddress != 0 ) { + uint64_t totalSize = totalVMSize(arch, files); + if ( highAddress < totalSize ) + throwf("cannot use -high_address 0x%X because total size of images is greater: 0x%X", highAddress, totalSize); + return highAddress - totalSize; + } + else { + if ( (arch == CPU_TYPE_I386) || (arch == CPU_TYPE_POWERPC) ) { + // place dylibs below dyld + uint64_t topAddr = 0x8FE00000; + uint64_t totalSize = totalVMSize(arch, files); + if ( totalSize > topAddr ) + throwf("total size of images (0x%X) does not fit below 0x8FE00000", totalSize); + return topAddr - totalSize; + } + else if ( arch == CPU_TYPE_POWERPC64 ) { + return 0x200000000ULL; + } + else if ( arch == CPU_TYPE_X86_64 ) { + return 0x200000000ULL; + } + else if ( arch == CPU_TYPE_ARM ) { + // place dylibs below dyld + uint64_t topAddr = 0x2FE00000; + uint64_t totalSize = totalVMSize(arch, files); + if ( totalSize > topAddr ) + throwf("total size of images (0x%X) does not fit below 0x2FE00000", totalSize); + return topAddr - totalSize; + } + else + throw "unknown architecture"; + } +} + +static void usage() +{ + fprintf(stderr, "rebase [-low_address] [-high_address] [-v] [-arch ] files...\n"); +} + + +int main(int argc, const char* argv[]) +{ + std::vector files; + std::set onlyArchs; + uint64_t lowAddress = 0; + uint64_t highAddress = 0; + + try { + // parse command line options + char* endptr; + for(int i=1; i < argc; ++i) { + const char* arg = argv[i]; + if ( arg[0] == '-' ) { + if ( strcmp(arg, "-v") == 0 ) { + verbose = true; + } + else if ( strcmp(arg, "-low_address") == 0 ) { + lowAddress = strtoull(argv[++i], &endptr, 16); + } + else if ( strcmp(arg, "-high_address") == 0 ) { + highAddress = strtoull(argv[++i], &endptr, 16); + } + else 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 ) + 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 { + usage(); + throwf("unknown option: %s\n", arg); + } + } + else { + files.push_back(fileInfo(arg)); + } + } + + if ( files.size() == 0 ) + throw "no files specified"; + + // 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); + } + + // scan files and collect sizes + for(std::vector::iterator it=files.begin(); it != files.end(); ++it) { + setSizes(*it, onlyArchs); + } + + // assign new base address for each arch + for(std::set::iterator ait=onlyArchs.begin(); ait != onlyArchs.end(); ++ait) { + cpu_type_t arch = *ait; + uint64_t baseAddress = startAddress(arch, files, lowAddress, highAddress); + for(std::vector::iterator fit=files.begin(); fit != files.end(); ++fit) { + fileInfo& fi = *fit; + for(std::vector::iterator fait=fi.archs.begin(); fait != fi.archs.end(); ++fait) { + if ( fait->arch == arch ) { + fait->newBase = baseAddress; + baseAddress += fait->vmSize; + baseAddress = (baseAddress + 4095) & (-4096); // page align + } + } + } + } + + // rebase each file if it contains something rebaseable + for(std::vector::iterator it=files.begin(); it != files.end(); ++it) { + fileInfo& fi = *it; + if ( fi.archs.size() > 0 ) + rebase(fi); + } + + } + catch (const char* msg) { + fprintf(stderr, "rebase failed: %s\n", msg); + return 1; + } + + return 0; +} + + + diff --git a/FireOpal/unit-tests/README b/FireOpal/unit-tests/README new file mode 100644 index 0000000..a0fd0a2 --- /dev/null +++ b/FireOpal/unit-tests/README @@ -0,0 +1,28 @@ + +The easy way to run all tests is within Xcode. Just select "unit-tests" as the target and click Build. + +When run from within Xcode, the just built linker will be used. If you cd into a test case and run it, the +installed linker (e.g. /usr/bin/ld) will be used. + +Each test case is a directory with a Makefile. The Makefile default target should do whatever work is necessary +to perform the test. If successful is should print "PASS xxx" where xxx is the name of the test case. Otherwise +it should print "FAIL xxx reason". If nothing is printed (for instance a tool crashed), the harness will +automatically print that it failed. The harness will always pass ARCH to the Makefile to specify which +architecture to test. The Makefile should also have a "clean" target which removes and generated files. + + +There are some utility functions for use in Makefiles for generating the PASS/FAIL strings: + + ${PASS_IFF} can be put in front of the last command in the make rule and it will print PASS + if the command returned 0 or FAIL otherwise. Example: + ${PASS_IFF} ${CC} foo.c -o foo + Will print PASS if and only if the compilation succeeded + + ${PASS_IFF_EMPTY} can have data piped into it. It prints PASS if there is no data, otherwise FAIL. + Example: + otool -hv foo.o | grep SUBSECTIONS_VIA_SYMBOLS | ${PASS_IFF_EMPTY} + Will print PASS if and only if the output of otool does not contain SUBSECTIONS_VIA_SYMBOLS + + + + diff --git a/FireOpal/unit-tests/bin/exit-non-zero-pass.pl b/FireOpal/unit-tests/bin/exit-non-zero-pass.pl new file mode 100755 index 0000000..fcc65eb --- /dev/null +++ b/FireOpal/unit-tests/bin/exit-non-zero-pass.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl -w + +# +# Usage: +# +# ${PASS_UNLESS} "test name" command +# + +use strict; + +my $string = shift @ARGV; +my $ret = system(@ARGV); +my $exit_value = $ret >> 8; +my $signal_num = $ret & 127; +my $dumped_core = $ret & 128; +my $crashed = $signal_num + $dumped_core; + +if(0 == $exit_value || 0 != $crashed) +{ + printf("FAIL $string\n"); +} +else +{ + printf("PASS $string\n"); +} + +exit 0; diff --git a/FireOpal/unit-tests/bin/fail-if-exit-non-zero.pl b/FireOpal/unit-tests/bin/fail-if-exit-non-zero.pl new file mode 100755 index 0000000..7fb54b2 --- /dev/null +++ b/FireOpal/unit-tests/bin/fail-if-exit-non-zero.pl @@ -0,0 +1,16 @@ +#!/usr/bin/perl -w + +use strict; + +my $test_name = ""; +if ( exists $ENV{UNIT_TEST_NAME} ) { + $test_name = $ENV{UNIT_TEST_NAME}; +} + +if(system(@ARGV) != 0) +{ + printf("FAIL $test_name\n"); + exit 1; +} + +exit 0; diff --git a/FireOpal/unit-tests/bin/fail-if-exit-zero.pl b/FireOpal/unit-tests/bin/fail-if-exit-zero.pl new file mode 100755 index 0000000..7859888 --- /dev/null +++ b/FireOpal/unit-tests/bin/fail-if-exit-zero.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl -w + +use strict; + +my $test_name = ""; +if ( exists $ENV{UNIT_TEST_NAME} ) { + $test_name = $ENV{UNIT_TEST_NAME}; +} + +my $ret = system(@ARGV); +my $exit_value = $ret >> 8; +my $signal_num = $ret & 127; +my $dumped_core = $ret & 128; +my $crashed = $signal_num + $dumped_core; + +if(0 == $exit_value || 0 != $crashed) +{ + printf("FAIL $test_name\n"); + exit 1; +} + +exit 0; diff --git a/FireOpal/unit-tests/bin/fail-if-no-stdin.pl b/FireOpal/unit-tests/bin/fail-if-no-stdin.pl new file mode 100755 index 0000000..a44f5d3 --- /dev/null +++ b/FireOpal/unit-tests/bin/fail-if-no-stdin.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl -w + +# +# Usage: +# +# command | ${FAIL_IF_EMPTY} +# + +use strict; + +my $test_name = ""; +if ( exists $ENV{UNIT_TEST_NAME} ) { + $test_name = $ENV{UNIT_TEST_NAME}; +} + +if( eof STDIN ) +{ + printf("FAIL $test_name\n"); + exit 1; +} + +exit 0; diff --git a/FireOpal/unit-tests/bin/fail-if-stdin.pl b/FireOpal/unit-tests/bin/fail-if-stdin.pl new file mode 100755 index 0000000..c0bf290 --- /dev/null +++ b/FireOpal/unit-tests/bin/fail-if-stdin.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl -w + +# +# Usage: +# +# command | ${FAIL_IF_STDIN} +# + +use strict; + +my $test_name = ""; +if ( exists $ENV{UNIT_TEST_NAME} ) { + $test_name = $ENV{UNIT_TEST_NAME}; +} + +if( eof STDIN ) +{ + exit 0; +} + +printf("FAIL $test_name\n"); +exit 1; diff --git a/FireOpal/unit-tests/bin/fail-iff-exit-zero.pl b/FireOpal/unit-tests/bin/fail-iff-exit-zero.pl new file mode 100755 index 0000000..6d49a25 --- /dev/null +++ b/FireOpal/unit-tests/bin/fail-iff-exit-zero.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl -w + +# +# Usage: +# +# ${FALL_IFF} command +# + +use strict; + +my $test_name = ""; +if ( exists $ENV{UNIT_TEST_NAME} ) { + $test_name = $ENV{UNIT_TEST_NAME}; +} + +my $ret = system(@ARGV); +my $exit_value = $ret >> 8; +my $signal_num = $ret & 127; +my $dumped_core = $ret & 128; +my $crashed = $signal_num + $dumped_core; + +if(0 == $exit_value || 0 != $crashed) +{ + printf("FAIL $test_name\n"); + exit 1; +} + +printf("PASS $test_name\n"); +exit 0; diff --git a/FireOpal/unit-tests/bin/make-recursive-newtest.pl b/FireOpal/unit-tests/bin/make-recursive-newtest.pl new file mode 100755 index 0000000..031a45d --- /dev/null +++ b/FireOpal/unit-tests/bin/make-recursive-newtest.pl @@ -0,0 +1,127 @@ +#!/usr/bin/perl + +use strict; +use Data::Dumper; +use File::Find; +use Cwd qw(realpath); + +my @args = @ARGV; + +$ENV{'LD_NO_CLASSSIC_LINKER'} = '1'; +$ENV{'LD_NO_CLASSSIC_LINKER_STATIC'} = '1'; + +my $makefiles = +{ + 'makefile' => undef, + 'Makefile' => undef, + 'makefile.newtest' => undef, + 'Makefile.newtest' => undef, +}; + +my $find_opts = +{ + 'wanted' => \&find_callback, +}; + +my $keywords = +{ + 'root' => '', + 'cwd' => '', + 'cmd' => '', + 'exit' => '', + 'stdout' => [], + 'stderr' => [], +}; + +my $keyword; +my $max_keyword_len = 0; +foreach $keyword (keys %$keywords) +{ if($max_keyword_len < length($keyword)) { $max_keyword_len = length($keyword); } } +my $delim = ':'; +$max_keyword_len += length($delim) + length(' '); + +my $last_keyword = ''; + +sub print_line +{ + my ($keyword, $val) = @_; + + if(!exists($$keywords{$keyword})) + { + print STDERR "error: keyword $keyword not in \$keywords set\n"; + exit(1); + } + + my $keyword_len = 0; + + if($keyword ne $last_keyword) + { + print("$keyword"); print($delim); + $keyword_len = length($keyword) + length($delim); + } + if($max_keyword_len > $keyword_len) + { + my $num_spaces = $max_keyword_len - $keyword_len; + print(' ' x $num_spaces); + } + print("$val"); + if(0) + { + $last_keyword = $keyword; + } +} + +my $root = '.'; +$root = &realpath($root); +print_line("root", "$root\n"); + +find($find_opts, $root); + +sub find_callback +{ + if(exists($$makefiles{$_})) + { + my $makefile = $_; + my $reldir = $File::Find::dir; + $reldir =~ s|^$root/||; + + &print_line("cwd", "\$root/$reldir\n"); + my $cmd = [ "make" ]; + + push @$cmd, "-f"; + push @$cmd, $makefile; + my $arg; foreach $arg (@ARGV) { push @$cmd, $arg; } # better way to do this? + &print_line("cmd", "@$cmd\n"); + + open(SAVEOUT, ">&STDOUT") || die("$!"); + open(SAVEERR, ">&STDERR") || die("$!"); + open(STDOUT, ">/tmp/unit-tests-stdout") || die("$!"); + open(STDERR, ">/tmp/unit-tests-stderr") || die("$!"); + + $ENV{UNIT_TEST_NAME} = $reldir; + my $exit = system(@$cmd); + + close(STDOUT) || die("$!"); + close(STDERR) || die("$!"); + open(STDOUT, ">&SAVEOUT") || die("$!"); + open(STDERR, ">&SAVEERR") || die("$!"); + + &print_line("exit", "$exit\n"); + + open(OUT, ") + { + &print_line("stdout", "$_"); + } + close(OUT) || die("$!"); + unlink("/tmp/unit-tests-stdout"); + + open(ERR, ") + { + &print_line("stderr", "$_"); + } + close(ERR) || die("$!"); + } + unlink("/tmp/unit-tests-stderr"); +} diff --git a/FireOpal/unit-tests/bin/make-recursive.pl b/FireOpal/unit-tests/bin/make-recursive.pl new file mode 100755 index 0000000..f860985 --- /dev/null +++ b/FireOpal/unit-tests/bin/make-recursive.pl @@ -0,0 +1,123 @@ +#!/usr/bin/perl + +use strict; +use Data::Dumper; +use File::Find; +use Cwd qw(realpath); + +my @args = @ARGV; + +$ENV{'LD_NO_CLASSSIC_LINKER'} = '1'; +$ENV{'LD_NO_CLASSSIC_LINKER_STATIC'} = '1'; + +my $makefiles = +{ + 'makefile' => undef, + 'Makefile' => undef, +}; + +my $find_opts = +{ + 'wanted' => \&find_callback, +}; + +my $keywords = +{ + 'root' => '', + 'cwd' => '', + 'cmd' => '', + 'exit' => '', + 'stdout' => [], + 'stderr' => [], +}; + +my $keyword; +my $max_keyword_len = 0; +foreach $keyword (keys %$keywords) +{ if($max_keyword_len < length($keyword)) { $max_keyword_len = length($keyword); } } +my $delim = ':'; +$max_keyword_len += length($delim) + length(' '); + +my $last_keyword = ''; + +sub print_line +{ + my ($keyword, $val) = @_; + + if(!exists($$keywords{$keyword})) + { + print STDERR "error: keyword $keyword not in \$keywords set\n"; + exit(1); + } + + my $keyword_len = 0; + + if($keyword ne $last_keyword) + { + print("$keyword"); print($delim); + $keyword_len = length($keyword) + length($delim); + } + if($max_keyword_len > $keyword_len) + { + my $num_spaces = $max_keyword_len - $keyword_len; + print(' ' x $num_spaces); + } + print("$val"); + if(0) + { + $last_keyword = $keyword; + } +} + +my $root = '.'; +$root = &realpath($root); +print_line("root", "$root\n"); + +find($find_opts, $root); + +sub find_callback +{ + if(exists($$makefiles{$_})) + { + my $makefile = $_; + my $reldir = $File::Find::dir; + $reldir =~ s|^$root/||; + + &print_line("cwd", "\$root/$reldir\n"); + my $cmd = [ "make" ]; + + my $arg; foreach $arg (@ARGV) { push @$cmd, $arg; } # better way to do this? + &print_line("cmd", "@$cmd\n"); + + open(SAVEOUT, ">&STDOUT") || die("$!"); + open(SAVEERR, ">&STDERR") || die("$!"); + open(STDOUT, ">/tmp/unit-tests-stdout") || die("$!"); + open(STDERR, ">/tmp/unit-tests-stderr") || die("$!"); + + $ENV{UNIT_TEST_NAME} = $reldir; + my $exit = system(@$cmd); + + close(STDOUT) || die("$!"); + close(STDERR) || die("$!"); + open(STDOUT, ">&SAVEOUT") || die("$!"); + open(STDERR, ">&SAVEERR") || die("$!"); + + &print_line("exit", "$exit\n"); + + open(OUT, ") + { + &print_line("stdout", "$_"); + } + close(OUT) || die("$!"); + unlink("/tmp/unit-tests-stdout"); + + open(ERR, ") + { + &print_line("stderr", "$_"); + } + close(ERR) || die("$!"); + } + unlink("/tmp/unit-tests-stderr"); +} diff --git a/FireOpal/unit-tests/bin/mkld b/FireOpal/unit-tests/bin/mkld new file mode 100755 index 0000000..33aacc1 --- /dev/null +++ b/FireOpal/unit-tests/bin/mkld @@ -0,0 +1,73 @@ +#!/bin/sh + +hide() +{ + $PROCTOR set_hidden $1 1 >/dev/null +} + +if [ -z "$1" ] + then echo "Usage: mkld HOST [ DBPATH ]" >&2 + exit 1 +fi + +if [ -z "$PROCTOR" ] + then PROCTOR=proctor +fi + +DBNAME="$2" +[ -z "$DBNAME" ] && DBNAME=ld +PROCTOR="$PROCTOR $1 $DBNAME" + +$PROCTOR tools gcc g++ objc obj-c++ libstdc++ ld ld ld_classic cctools +$PROCTOR sysattrs \ + ld64="ld64" \ + ld="ld (ld_classic)" \ + gcc="GCC" \ + cctools="cctools" \ + os="OS Build" \ + processor=Processor \ + platform=Platform \ + hostname="Hostname" \ + gcc_opts="gcc options" \ + g++_opts="g++ options" \ + objc_opts="objc options" \ + obj-c++_opts="obj-c++ options" \ + libstdc++_opts="libstdc++ options" \ + LANG="LANG environment variable" \ + LC_CTYPE="LC_CTYPE environment variable" \ + LC_MESSAGES="LC_MESSAGES environment variable" \ + LC_ALL="LC_ALL environment variable" \ + TMPDIR="TMPDIR environment variable" \ + GCC_EXEC_PREFIX="GCC_EXEC_PREFIX environment variable" \ + COMPILER_PATH="COMPILER_PATH environment variable" \ + LIBRARY_PATH="LIBRARY_PATH environment variable" \ + LANG="LANG environment variable" \ + CPATH="CPATH environment variable" \ + C_INCLUDE_PATH="C_INCLUDE_PATH environment variable" \ + CPLUS_INCLUDE_PATH="CPLUS_INCLUDE_PATH environment variable" \ + OBJC_INCLUDE_PATH="OBJC_INCLUDE_PATH environment variable" \ + DEPENDENCIES_OUTPUT="DEPENDENCIES_OUTPUT environment variable" \ + SUNPRO_DEPENDENCIES="SUNPRO_DEPENDENCIES environment variable" \ + +for TOOL in gcc g++ objc obj-c++ libstdc++ + do hide ${TOOL}_opts +done + +hide LANG +hide LC_CTYPE +hide LC_MESSAGES +hide LC_ALL +hide TMPDIR +hide GCC_EXEC_PREFIX +hide COMPILER_PATH +hide LIBRARY_PATH +hide LANG +hide CPATH +hide C_INCLUDE_PATH +hide CPLUS_INCLUDE_PATH +hide OBJC_INCLUDE_PATH +hide DEPENDENCIES_OUTPUT +hide SUNPRO_DEPENDENCIES + +$PROCTOR results PASS=1 XFAIL=1 KFAIL=1 FAIL=0 XPASS=0 KPASS=0 UNRESOLVED=0 TIMEDOUT=0 UNSUPPORTED=0 UNTESTED=0 +$PROCTOR severities logline NOTE WARNING ERROR diff --git a/FireOpal/unit-tests/bin/pass-iff-exit-non-zero.pl b/FireOpal/unit-tests/bin/pass-iff-exit-non-zero.pl new file mode 100755 index 0000000..beb76a9 --- /dev/null +++ b/FireOpal/unit-tests/bin/pass-iff-exit-non-zero.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl -w + +# +# Usage: +# +# ${PASS_IFF} command +# + +use strict; + +my $test_name = ""; +if ( exists $ENV{UNIT_TEST_NAME} ) { + $test_name = $ENV{UNIT_TEST_NAME}; +} + +my $ret = system(@ARGV); +my $exit_value = $ret >> 8; +my $signal_num = $ret & 127; +my $dumped_core = $ret & 128; +my $crashed = $signal_num + $dumped_core; + +if(0 == $exit_value || 0 != $crashed) +{ + printf("FAIL $test_name\n"); + exit 1; +} + +printf("PASS $test_name\n"); +exit 0; diff --git a/FireOpal/unit-tests/bin/pass-iff-exit-zero.pl b/FireOpal/unit-tests/bin/pass-iff-exit-zero.pl new file mode 100755 index 0000000..07854b5 --- /dev/null +++ b/FireOpal/unit-tests/bin/pass-iff-exit-zero.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl -w + +# +# Usage: +# +# ${PASS_IFF} command +# + +use strict; + +my $test_name = ""; +if ( exists $ENV{UNIT_TEST_NAME} ) { + $test_name = $ENV{UNIT_TEST_NAME}; +} + +if(0 != system(@ARGV)) +{ + printf("FAIL $test_name\n"); + exit 1; +} + +printf("PASS $test_name\n"); +exit 0; diff --git a/FireOpal/unit-tests/bin/pass-iff-no-stdin.pl b/FireOpal/unit-tests/bin/pass-iff-no-stdin.pl new file mode 100755 index 0000000..19b98b4 --- /dev/null +++ b/FireOpal/unit-tests/bin/pass-iff-no-stdin.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl -w + +# +# Usage: +# +# command | ${PASS_IFF_EMPTY} +# + +use strict; + +my $test_name = ""; +if ( exists $ENV{UNIT_TEST_NAME} ) { + $test_name = $ENV{UNIT_TEST_NAME}; +} + +if( eof STDIN ) +{ + printf("PASS $test_name\n"); + exit 0; +} + +printf("FAIL $test_name\n"); +exit 1; diff --git a/FireOpal/unit-tests/bin/pass-iff-stdin.pl b/FireOpal/unit-tests/bin/pass-iff-stdin.pl new file mode 100755 index 0000000..d5ee99f --- /dev/null +++ b/FireOpal/unit-tests/bin/pass-iff-stdin.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl -w + +# +# Usage: +# +# command | ${PASS_IFF_STDIN} +# + +use strict; + +my $test_name = ""; +if ( exists $ENV{UNIT_TEST_NAME} ) { + $test_name = $ENV{UNIT_TEST_NAME}; +} + +if( eof STDIN ) +{ + printf("FAIL $test_name\n"); + exit 1 +} + +printf("PASS $test_name\n"); +exit 0; + diff --git a/FireOpal/unit-tests/bin/result-filter.pl b/FireOpal/unit-tests/bin/result-filter.pl new file mode 100755 index 0000000..8168e79 --- /dev/null +++ b/FireOpal/unit-tests/bin/result-filter.pl @@ -0,0 +1,131 @@ +#!/usr/bin/perl -w + +use strict; +use Data::Dumper; +use File::Find; +use Cwd; + +$Data::Dumper::Terse = 1; + +my $root = undef; +my $entry = ''; +my $pass_count = 0; +my $total_count = 0; + +# first match "root: " + +# a line starting with "cwd:" marks the beginning of a new test case +# call process_entry() on each test case +while(<>) +{ + if(m/^root:\s+(.*?)$/) + { + $root = $1; + } + elsif(m/^cwd:\s+(.*?)$/) + { + if(length($entry)) + { + &process_entry($root, $entry); + $entry = ''; + } + $entry .= $_; + } + else + { + $entry .= $_; + } +} +# don't forget last test case (no cwd: to mark end) +if(length($entry)) +{ + &process_entry($root, $entry); +} + +# show totals +my $percentage = $pass_count * 100 / $total_count; +printf " * * * %d of %d unit-tests passed (%.1f percent) * * *\n", $pass_count, $total_count, $percentage; + + +sub process_entry +{ + my ($root, $lines) = @_; + + # build an associative array of keys to value(s) + my $lines_seq = [split /\n/, $lines]; + #print Dumper($lines_seq); + my $tbl = { 'root' => $root, 'stdout' => [], 'stderr' => [] }; + my $line; + foreach $line (@$lines_seq) + { + if($line =~ m/^(\w+):\s+(.*)$/) + { + my $key = $1; + my $val = $2; + if(!exists($$tbl{$key})) + { $$tbl{$key} = ''; } + + if($key eq 'stdout' || $key eq 'stderr') # if type is @array + { + push @{$$tbl{$key}}, $val; + } + else + { + $$tbl{$key} .= $val; + } + } + else + { + print "ERROR: $line"; + } + } + #print Dumper($tbl); + #return; + + my $test_name = $$tbl{cwd}; + if ($test_name =~ m|.*/([a-zA-Z0-9-+_]+)$|) + { + $test_name = $1; + } + + #if make failed (exit was non-zero), mark this as a failure + if(0 ne $$tbl{exit}) + { + printf "%-40s FAIL Makefile failure\n", $test_name; + $total_count++; + return; + } + + #if there was any output to stderr, mark this as a failure + foreach $line (@{$$tbl{stderr}}) + { + printf "%-40s FAIL spurious stderr failure: %s\n", $test_name, $line; + $total_count++; + return; + } + + # scan all stdout looking for lines that start with PASS or FAIL + my $seen_result = 0; + foreach $line (@{$$tbl{stdout}}) + { + if($line =~ m/^(PASS|XPASS|FAIL|XFAIL).+/) + { + $total_count++; + if($line =~ m/^PASS.+/) + { + $pass_count++; + } + else + { + # only print failure lines + printf "%-40s %s\n", $test_name, $line; + } + $seen_result = 1; + } + } + if(!$seen_result) + { + printf "%-40s AMBIGIOUS missing [X]PASS/[X]FAIL\n", $test_name; + $total_count++; + } +} diff --git a/FireOpal/unit-tests/bin/rm-stale-test-logs b/FireOpal/unit-tests/bin/rm-stale-test-logs new file mode 100755 index 0000000..936dec1 --- /dev/null +++ b/FireOpal/unit-tests/bin/rm-stale-test-logs @@ -0,0 +1,36 @@ +#!/bin/sh + +usage() { + echo Usage: $0 number-of-tests-logs-to-keep + echo where number-of-tests-logs-to-keep must be a non-zero integer + exit +} + +# Usage: if no arguments +[ -z "$1" ] && usage + +# Check if requesting 0 tests to remain! +[ "$1" -ne 0 ] + +# don't test directly--use the result value +# because the command can fail for badly formed integers +[ $? -ne 0 ] && usage + +# get the dir names of all tests in date order +ls -1dtr /tmp/proctor*>/tmp/all$$ 2>/dev/null + +# select the last few to keep +tail -$1 /tmp/all$$>/tmp/keep$$ + +# get a list of the others +DELLIST=`diff /tmp/all$$ /tmp/keep$$|grep '^<'|sed -e 's/^< //'` + +# any work to do? +if [ "$DELLIST" ] +then + echo rm -rf $DELLIST + rm -rf $DELLIST +fi + +# rm the temps +rm /tmp/all$$ /tmp/keep$$ diff --git a/FireOpal/unit-tests/clean-tests b/FireOpal/unit-tests/clean-tests new file mode 100755 index 0000000..4c38b4e --- /dev/null +++ b/FireOpal/unit-tests/clean-tests @@ -0,0 +1,63 @@ +find_makefile() +{ + local j + + MF="" + + if [ ! -d $1 ] + then + return 1 + fi + + for j in Makefile makefile Makefile.newtest makefile.newtest + do + [ -f $1/$j ] && MF=$j + done + + [ "$MF" ] && return 0 + return 1 +} + +find_path_to_test_dir() +{ + # FIND THE PATH TO THE TEST DIR + # SO THAT WE CAN ADD THE BIN DIR INTO + # THE SEARCH PATH + + # remember the top level execution dir + chmod +x "$0" # just in case + + #add path to $0 into search + savedir=$PWD + DIRNAME=`dirname $0` + [ -d "$DIRNAME" ] && cd "$DIRNAME" + PATH=$PATH:$PWD + cd "$savedir" + + chmod +x "$0" # just in case + EXECNAME=`which $0` + DIRNAME=`dirname "$EXECNAME"` + if [ -d "$DIRNAME" ] + then + TEST_HOME_DIR="$DIRNAME" + else + TEST_HOME_DIR="$savedir" # Give up and assume current dir + fi + + PATH="$PATH":"$TEST_HOME_DIR"/bin:"$savedir" +} + +find_path_to_test_dir + +cd "$TEST_HOME_DIR/test-cases" + +for i in * +do + [ -d "$i" ] && + ( + if find_makefile $i + then + make -C $i -f $MF -s -k clean >/dev/null 2>/dev/null + fi + ) +done diff --git a/FireOpal/unit-tests/include/common.makefile b/FireOpal/unit-tests/include/common.makefile new file mode 100644 index 0000000..70e05f8 --- /dev/null +++ b/FireOpal/unit-tests/include/common.makefile @@ -0,0 +1,76 @@ +# stuff to include in every test Makefile + +SHELL = /bin/sh + +# set default to be host +ARCH ?= $(shell arch) + +# set default to be all +VALID_ARCHS ?= "ppc ppc64 i386 x86_64 armv6" + +MYDIR=$(shell cd ../../bin;pwd) + +# if run within Xcode, add the just built tools to the command path +ifdef BUILT_PRODUCTS_DIR + PATH := ${BUILT_PRODUCTS_DIR}:${MYDIR}:${PATH} + COMPILER_PATH := ${BUILT_PRODUCTS_DIR}:${MYDIR}:${COMPILER_PATH} +else + ifneq "$(findstring /unit-tests/test-cases/, $(shell pwd))" "" + RELEASEDIR=$(shell cd ../../../build/Release;pwd) + PATH := ${RELEASEDIR}:${MYDIR}:${PATH} + COMPILER_PATH := ${RELEASEDIR}:${MYDIR}:${COMPILER_PATH} + else + PATH := ${MYDIR}:${PATH}: + COMPILER_PATH := ${MYDIR}:${COMPILER_PATH}: + endif +endif +export PATH +export COMPILER_PATH + +LD = ld +OBJECTDUMP = ObjectDump +MACHOCHECK = machocheck +OTOOL = otool + +CC = gcc-4.0 -arch ${ARCH} +CCFLAGS = -Wall -std=c99 +ASMFLAGS = + +CXX = g++-4.0 -arch ${ARCH} +CXXFLAGS = -Wall + +ifeq ($(ARCH),armv6) + LDFLAGS := -syslibroot /Developer/SDKs/Purple + override FILEARCH = arm +else + FILEARCH = $(ARCH) +endif + +ifeq ($(ARCH),thumb) + LDFLAGS := -syslibroot /Developer/SDKs/Purple + CCFLAGS += -mthumb + CXXFLAGS += -mthumb + override ARCH = armv6 + override FILEARCH = arm +else + FILEARCH = $(ARCH) +endif + +RM = rm +RMFLAGS = -rf + +# utilites for Makefiles +PASS_IFF = pass-iff-exit-zero.pl +PASS_IFF_SUCCESS = ${PASS_IFF} +PASS_IFF_EMPTY = pass-iff-no-stdin.pl +PASS_IFF_STDIN = pass-iff-stdin.pl +FAIL_IFF = fail-iff-exit-zero.pl +FAIL_IFF_SUCCESS = ${FAIL_IFF} +PASS_IFF_ERROR = pass-iff-exit-non-zero.pl +FAIL_IF_ERROR = fail-if-exit-non-zero.pl +FAIL_IF_SUCCESS = fail-if-exit-zero.pl +FAIL_IF_EMPTY = fail-if-no-stdin.pl +FAIL_IF_STDIN = fail-if-stdin.pl +PASS_IFF_GOOD_MACHO = ${PASS_IFF} ${MACHOCHECK} +FAIL_IF_BAD_MACHO = ${FAIL_IF_ERROR} ${MACHOCHECK} +FAIL_IF_BAD_OBJ = ${FAIL_IF_ERROR} ${OBJECTDUMP} >/dev/null diff --git a/FireOpal/unit-tests/include/test.h b/FireOpal/unit-tests/include/test.h new file mode 100644 index 0000000..faca714 --- /dev/null +++ b/FireOpal/unit-tests/include/test.h @@ -0,0 +1,35 @@ +#include +#include + +#define DEFINE_TEST_FUNC(name) \ + static \ + inline \ + void \ + name(const char *format, ...) \ + { \ + va_list args; \ + va_start(args, format); \ + common(stdout, #name, format, args); \ + va_end(args); \ + return; \ + } + +static +inline +void +common(FILE *file, const char *prefix, const char *format, va_list args) +{ + fprintf(file, "%s \"", prefix); + vfprintf(file, format, args); + fprintf(file, "\"\n"); // should check for trailing newline + return; +} + +DEFINE_TEST_FUNC(PASS); +DEFINE_TEST_FUNC(XPASS); +DEFINE_TEST_FUNC(FAIL); +DEFINE_TEST_FUNC(XFAIL); + +DEFINE_TEST_FUNC(UNTESTED); +DEFINE_TEST_FUNC(UNSUPPORTED); +DEFINE_TEST_FUNC(UNRESOLVED); diff --git a/FireOpal/unit-tests/proctor-run b/FireOpal/unit-tests/proctor-run new file mode 100755 index 0000000..e7bdea4 --- /dev/null +++ b/FireOpal/unit-tests/proctor-run @@ -0,0 +1,204 @@ +#!/bin/sh + +all_archs="ppc ppc64 i386 x86_64" + +sysattr() +{ + echo " " +} + +doresults() +{ + local ver + + echo "" + + echo " " + sysattr cctools "`as&1 |sed 's/.*cctools-//;s/,.*//'`" + sysattr hostname "`hostname`" + sysattr os "`uname -r`" + sysattr platform "`uname -m`" + sysattr ld64 "`ld64 -v 2>&1|sed 's/.*PROJECT://;s/ .*//'`" + sysattr ld "`ld_classic -v 2>&1|sed 's/.*cctools-//;s/ .*//'`" + sysattr gcc "`gcc --version|head -1`" + sysattr processor "`uname -p`" + sysattr LANG "$LANG" + sysattr LC_CTYPE "$LC_CTYPE" + sysattr LC_MESSAGES "$LC_MESSAGES" + sysattr LC_ALL "$LC_ALL" + sysattr TMPDIR "$TMPDIR" + sysattr GCC_EXEC_PREFIX "$GCC_EXEC_PREFIX" + sysattr COMPILER_PATH "$COMPILER_PATH" + sysattr LIBRARY_PATH "$LIBRARY_PATH" + sysattr LANG "$LANG" + sysattr CPATH "$CPATH" + sysattr C_INCLUDE_PATH "$C_INCLUDE_PATH" + sysattr CPLUS_INCLUDE_PATH "$CPLUS_INCLUDE_PATH" + sysattr OBJC_INCLUDE_PATH "$OBJC_INCLUDE_PATH" + sysattr DEPENDENCIES_OUTPUT "$DEPENDENCIES_OUTPUT" + sysattr SUNPRO_DEPENDENCIES "$SUNPRO_DEPENDENCIES" + echo " " + + echo "" + echo "" + echo " " + for i in $* + do + echo " " + cat $i + echo " " + done + + echo " " + echo "" + echo "" + echo "" + + #rm $* +} + +find_path_to_test_dir() +{ + # FIND THE PATH TO THE TEST DIR + # SO THAT WE CAN ADD THE BIN DIR INTO + # THE SEARCH PATH + + # remember the top level execution dir + chmod +x "$0" # just in case + + #add path to $0 into search + local savedir + savedir=$PWD + DIRNAME=`dirname $0` + [ -d "$DIRNAME" ] && cd "$DIRNAME" + PATH=$PATH:$PWD + cd "$savedir" + + chmod +x "$0" # just in case + EXECNAME=`which $0` + DIRNAME=`dirname "$EXECNAME"` + if [ -d "$DIRNAME" ] + then + TEST_HOME_DIR=`cd "$DIRNAME";pwd` + fi + + if [ -z "$TEST_HOME_DIR" ] + then + TEST_HOME_DIR="$savedir" # Give up and assume current dir + fi + + cd "$TEST_HOME_DIR" + cd ../build/Release + + PATH="$PWD":"$TEST_HOME_DIR/bin":"$PATH" + cd "$savedir" +} + +start_time=`date +%s` + +find_path_to_test_dir + +# Execute from the location of the script; or if not found the current loc +[ -d $TEST_HOME_DIR/test-cases ] && cd $TEST_HOME_DIR/test-cases || cd test-cases + +rm-stale-test-logs 3 >/dev/null & + +make -C ../src # make sure the binaries are available + +DATEFORMAT=`date +%F-%H%M | sed -e 's/ //'` +tmpdir=/tmp/proctor$DATEFORMAT + +if ! mkdir $tmpdir >/dev/null 2>/dev/null +then + rm -rf $tmpdir + mkdir $tmpdir +fi + + +linestart=0 +if [ x$1 = x-comment ] +then + shift + comment="$1" + shift +fi + +find_makefile() +{ + local j + + MF="" + + if [ ! -d $1 ] + then + return 1 + fi + + for j in Makefile makefile + do + [ -f $1/$j ] && MF=$j + done + + if [ "$NEWTEST" ] + then + for j in Makefile.newtest makefile.newtest + do + [ -f $1/$j ] && MF=$j + done + fi + + [ "$MF" ] && return 0 + return 1 +} + +one_test() +{ + echo cwd: $1 + echo cmd: $1 ARCH="$arch" + make -f "$MF" -C $1 ARCH="$arch" 2>$tmpdir/stderr >$tmpdir/stdout + result=$? + sed 's/^/stdout: /'<$tmpdir/stdout + sed 's/^/stderr: /'<$tmpdir/stderr + echo exit: $? +} + +if [ "$1" ] +then + i="$1" + for arch in $all_archs + do + rm -f $tmpdir/$arch + if find_makefile $i + then + one_test $i + fi + #fi | tee -a $tmpdir/raw | ../bin/results-to-xml $linestart>>$tmpdir/$arch + linestart=`expr $linestart + 10000` + done | tee -a $tmpdir/raw | ../bin/results-to-xml $linestart>>$tmpdir/$arch +else + for arch in $all_archs + do + rm -f $tmpdir/$arch + for i in * + do + if find_makefile $i + then + one_test $i + fi + done | tee -a $tmpdir/raw | ../bin/results-to-xml $linestart>>$tmpdir/$arch + linestart=`expr $linestart + 10000` + done +fi + +(cd $tmpdir; doresults $all_archs)>$tmpdir/o.xml +../bin/xmlparser $tmpdir/o.xml >/dev/null +if [ $? = 0 ] +then + if ! proctor localhost ld import $tmpdir/o.xml + then + proctor database load failed! + fi +else + echo Test results not loaded: internal xml error! + exit 1 +fi diff --git a/FireOpal/unit-tests/run-all-unit-tests b/FireOpal/unit-tests/run-all-unit-tests new file mode 100755 index 0000000..e21c2b3 --- /dev/null +++ b/FireOpal/unit-tests/run-all-unit-tests @@ -0,0 +1,35 @@ +#!/bin/sh + +unset RC_TRACE_DYLIBS +unset RC_TRACE_ARCHIVES +unset LD_TRACE_DYLIBS +unset LD_TRACE_ARCHIVES + +export DYLD_FALLBACK_LIBRARY_PATH=${DYLD_FALLBACK_LIBRARY_PATH}:/Developer/usr/lib +# cd into test-cases directory +cd `echo "$0" | sed 's/run-all-unit-tests/test-cases/'` + +[ "$PROCTORRUN" ] && exec ../proctor-run + +all_archs="x86_64 armv6 thumb ppc ppc64 i386 " +valid_archs="x86_64 armv6 ppc ppc64 i386 " + +# clean first +../bin/make-recursive.pl clean > /dev/null + +mkdir /tmp/$$ +for arch in $all_archs +do + echo "" + echo " * * * Running all unit tests for architecture $arch * * *" + + # build architecture + [ "$NEWTEST" ] && NT=-newtest + + ../bin/make-recursive$NT.pl ARCH=$arch VALID_ARCHS="$valid_archs" | ../bin/result-filter.pl + + # clean up so svn is happy + ../bin/make-recursive.pl ARCH=$arch clean > /dev/null + + echo "" +done diff --git a/FireOpal/unit-tests/run-all-unit-tests-debug b/FireOpal/unit-tests/run-all-unit-tests-debug new file mode 100755 index 0000000..a239748 --- /dev/null +++ b/FireOpal/unit-tests/run-all-unit-tests-debug @@ -0,0 +1,26 @@ +#!/bin/sh + +# cd into test-cases directory +cd `echo "$0" | sed 's/run-all-unit-tests/test-cases/'` + +[ "$PROCTORRUN" ] && exec ../proctor-run + +all_archs="ppc ppc64 i386 x86_64" + +mkdir /tmp/$$ +for arch in $all_archs +do + echo "" + echo " * * * Running all unit tests for architecture $arch * * *" + + # build architecture + [ "$NEWTEST" ] && NT=-newtest + + mkdir /tmp/$$ + ../bin/make-recursive$NT.pl ARCH=$arch VALID_ARCHS="$all_archs" | tee /tmp/$$/raw | ../bin/result-filter.pl | tee /tmp/$$/sum + + # clean up so svn is happy + ../bin/make-recursive.pl ARCH=$arch clean > /dev/null + + echo "" +done diff --git a/FireOpal/unit-tests/src/Makefile b/FireOpal/unit-tests/src/Makefile new file mode 100644 index 0000000..d3bdeab --- /dev/null +++ b/FireOpal/unit-tests/src/Makefile @@ -0,0 +1,9 @@ + +all: ../bin/results-to-xml ../bin/xmlparser + +../bin/results-to-xml: results-to-xml.cpp + g++ -g -O -Wall $< -o ../bin/results-to-xml + +../bin/xmlparser: + cd xmlparser; xcodebuild -alltargets + cp -p xmlparser/build/Release/xmlparser ../bin/. diff --git a/FireOpal/unit-tests/src/results-to-xml.cpp b/FireOpal/unit-tests/src/results-to-xml.cpp new file mode 100644 index 0000000..a305347 --- /dev/null +++ b/FireOpal/unit-tests/src/results-to-xml.cpp @@ -0,0 +1,260 @@ +#include +#include +#include + +using namespace std; + +#define NELEMENTS(a) (sizeof (a)/sizeof *(a)) + +#define NO_RESULT (-1) +#define PASS 1 +#define FAIL 0 + +#define DBG bhole + +void +bhole(...) +{ +} + +class line_category +{ +public: + const char *key; + char line[99999]; + void (*test)(line_category &); + int test_result; +} lc; + +void +deft(line_category &l) +{ + l.test_result = PASS; +} + +void +pass_fail(line_category &l) +{ + if(FAIL!=l.test_result) + l.test_result = strnstr(l.line, "FAIL", 4)? FAIL: PASS; +} + +void +stderr_output(line_category &l) +{ + if(FAIL==l.test_result) + return; + + if(l.line[0]) + l.test_result = FAIL; +} + +void +exit_test(line_category &l) +{ + if(!atoi(l.line)) { + DBG("exit_test(%s)==%d\n", l.line, atoi(l.line)); + l.test_result = PASS; + } +} + +#define STDOUT "stdout: " +#define STDERR "stderr: " +#define CWD "cwd: " +#define CMD "cmd: " +#define SEXIT "exit: " +line_category line_categories[] = { + { CWD, "" , deft, NO_RESULT}, /* must be first */ + { CMD, "", deft, NO_RESULT}, + { STDOUT, "", pass_fail, NO_RESULT}, + { STDERR, "", stderr_output, NO_RESULT }, + { SEXIT, "", exit_test, NO_RESULT }, +}; + +static line_category no_line_category = { "none", "no test", deft, NO_RESULT }; + +line_category & +retrieve(line_category &l, const char *s) +{ + unsigned j; + line_category *lp = &l; + //int final_result = PASS; + + for(j=0; jkey, s)) { + char *p; + + for(p=(char *)lp->line; *p; ++p) { + switch(*p) { + case '\0': + break; + case '"': + case '<': + *p = ' '; + // fall thru + default: + continue; + } + } +DBG("FOUND line_categories[j].line==%s\n", lp->line); + return line_categories[j]; + } + } + + return no_line_category; +} + +void +xml_string_print(FILE *strm, const char *s) +{ + fputc('"', strm); + for( ; ; ++s) { + switch(*s) { + case '\0': + break; + case '&': + fputs("&", strm); + continue; + default: + fputc(*s, strm); + continue; + } + break; + } + fputc('"', strm); +} + +// +// FAIL if stderr non-zero +// FAIL if stdout=="FAIL" +// UNRESOLVED if make exit non-zero +// PASS otherwise +// + +static int cnt; +void +dump_test(void) +{ + unsigned j; + int final_result = PASS; + + for(j=0; j\n"); + + printf(" \n"); + s = retrieve(line_categories[0], STDERR).line; + if(*s) { + printf(" \n"); + } +#if 1 + s = retrieve(line_categories[0], STDOUT).line; + if(*s) { + printf(" \n"); + } +#endif + printf(" \n"); + printf("\n\n"); + + for(j=0; j1) + cnt = atoi(argv[1]); + + for(;;) { + char line[99999]; + int i; + + line[0] = '\0'; + fgets(line, sizeof line, stdin); + if(feof(stdin)) { + dump_test(); + break; + } + + for(i=0; ; ++i) { + size_t len = strlen(line_categories[i].key); + + //DBG("strnstr(%s, %s, %u)\n", line, line_categories[i].key, len); + if(strnstr(line, line_categories[i].key, len)) { + if(firsttime) + firsttime = 0; + else if(0==i) + dump_test(); + + char *lp = &line[len]; + //DBG("%s%s", line_categories[i].key, lp); + strncpy(line_categories[i].line, lp, sizeof line_categories[i].line); + line_categories[i].test(line_categories[i]); + break; + } + + if(i==NELEMENTS(line_categories)-1) { + DBG("BADLINE:%s", line); + break; + } + } + } + return 0; +} diff --git a/FireOpal/unit-tests/src/xmlparser/xmlparser.1 b/FireOpal/unit-tests/src/xmlparser/xmlparser.1 new file mode 100644 index 0000000..6eab06a --- /dev/null +++ b/FireOpal/unit-tests/src/xmlparser/xmlparser.1 @@ -0,0 +1,79 @@ +.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples. +.\"See Also: +.\"man mdoc.samples for a complete listing of options +.\"man mdoc for the short list of editing options +.\"/usr/share/misc/mdoc.template +.Dd 9/18/06 \" DATE +.Dt xmlparser 1 \" Program name and manual section number +.Os Darwin +.Sh NAME \" Section Header - required - don't modify +.Nm xmlparser, +.\" The following lines are read in generating the apropos(man -k) database. Use only key +.\" words here as the database is built based on the words here and in the .ND line. +.Nm Other_name_for_same_program(), +.Nm Yet another name for the same program. +.\" Use .Nm macro to designate other names for the documented program. +.Nd This line parsed for whatis database. +.Sh SYNOPSIS \" Section Header - required - don't modify +.Nm +.Op Fl abcd \" [-abcd] +.Op Fl a Ar path \" [-a path] +.Op Ar file \" [file] +.Op Ar \" [file ...] +.Ar arg0 \" Underlined argument - use .Ar anywhere to underline +arg2 ... \" Arguments +.Sh DESCRIPTION \" Section Header - required - don't modify +Use the .Nm macro to refer to your program throughout the man page like such: +.Nm +Underlining is accomplished with the .Ar macro like this: +.Ar underlined text . +.Pp \" Inserts a space +A list of items with descriptions: +.Bl -tag -width -indent \" Begins a tagged list +.It item a \" Each item preceded by .It macro +Description of item a +.It item b +Description of item b +.El \" Ends the list +.Pp +A list of flags and their descriptions: +.Bl -tag -width -indent \" Differs from above in tag removed +.It Fl a \"-a flag as a list item +Description of -a flag +.It Fl b +Description of -b flag +.El \" Ends the list +.Pp +.\" .Sh ENVIRONMENT \" May not be needed +.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1 +.\" .It Ev ENV_VAR_1 +.\" Description of ENV_VAR_1 +.\" .It Ev ENV_VAR_2 +.\" Description of ENV_VAR_2 +.\" .El +.Sh FILES \" File used or created by the topic of the man page +.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact +.It Pa /usr/share/file_name +FILE_1 description +.It Pa /Users/joeuser/Library/really_long_file_name +FILE_2 description +.El \" Ends the list +.\" .Sh DIAGNOSTICS \" May not be needed +.\" .Bl -diag +.\" .It Diagnostic Tag +.\" Diagnostic informtion here. +.\" .It Diagnostic Tag +.\" Diagnostic informtion here. +.\" .El +.Sh SEE ALSO +.\" List links in ascending order by section, alphabetically within a section. +.\" Please do not reference files that do not exist without filing a bug report +.Xr a 1 , +.Xr b 1 , +.Xr c 1 , +.Xr a 2 , +.Xr b 2 , +.Xr a 3 , +.Xr b 3 +.\" .Sh BUGS \" Document known, unremedied bugs +.\" .Sh HISTORY \" Document history if command behaves in a unique manner \ No newline at end of file diff --git a/FireOpal/unit-tests/src/xmlparser/xmlparser.m b/FireOpal/unit-tests/src/xmlparser/xmlparser.m new file mode 100644 index 0000000..a9c82fc --- /dev/null +++ b/FireOpal/unit-tests/src/xmlparser/xmlparser.m @@ -0,0 +1,25 @@ +#import + +int main(int argc, char *argv[]) { + [[NSAutoreleasePool alloc] init]; + + if(argc != 2) { + NSLog(@"Usage: %s path-to-XML\n", argv[0]); + return 1; + } + NSString *path = [NSString stringWithUTF8String:argv[1]]; + + NSError *err = nil; + NSXMLDocument *doc = [[NSXMLDocument alloc] + initWithContentsOfURL:[NSURL + fileURLWithPath:path] + options:0 + error:&err]; + if(err) { + NSLog(@"ERROR: %@", err); + return 1; + } else { + NSLog(@"Parsed!"); + return 0; + } +} diff --git a/FireOpal/unit-tests/src/xmlparser/xmlparser.xcodeproj/project.pbxproj b/FireOpal/unit-tests/src/xmlparser/xmlparser.xcodeproj/project.pbxproj new file mode 100644 index 0000000..9492293 --- /dev/null +++ b/FireOpal/unit-tests/src/xmlparser/xmlparser.xcodeproj/project.pbxproj @@ -0,0 +1,218 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXBuildFile section */ + 8DD76F9A0486AA7600D96B5E /* xmlparser.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* xmlparser.m */; settings = {ATTRIBUTES = (); }; }; + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; + 8DD76F9F0486AA7600D96B5E /* xmlparser.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6859EA3029092ED04C91782 /* xmlparser.1 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8DD76F9E0486AA7600D96B5E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + 8DD76F9F0486AA7600D96B5E /* xmlparser.1 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 08FB7796FE84155DC02AAC07 /* xmlparser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = xmlparser.m; sourceTree = ""; }; + 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 32A70AAB03705E1F00C91783 /* xmlparser_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xmlparser_Prefix.pch; sourceTree = ""; }; + 8DD76FA10486AA7600D96B5E /* xmlparser */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = xmlparser; sourceTree = BUILT_PRODUCTS_DIR; }; + C6859EA3029092ED04C91782 /* xmlparser.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = xmlparser.1; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DD76F9B0486AA7600D96B5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* xmlparser */ = { + isa = PBXGroup; + children = ( + 08FB7795FE84155DC02AAC07 /* Source */, + C6859EA2029092E104C91782 /* Documentation */, + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = xmlparser; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 32A70AAB03705E1F00C91783 /* xmlparser_Prefix.pch */, + 08FB7796FE84155DC02AAC07 /* xmlparser.m */, + ); + name = Source; + sourceTree = ""; + }; + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 08FB779EFE84155DC02AAC07 /* Foundation.framework */, + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8DD76FA10486AA7600D96B5E /* xmlparser */, + ); + name = Products; + sourceTree = ""; + }; + C6859EA2029092E104C91782 /* Documentation */ = { + isa = PBXGroup; + children = ( + C6859EA3029092ED04C91782 /* xmlparser.1 */, + ); + name = Documentation; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8DD76F960486AA7600D96B5E /* xmlparser */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "xmlparser" */; + buildPhases = ( + 8DD76F990486AA7600D96B5E /* Sources */, + 8DD76F9B0486AA7600D96B5E /* Frameworks */, + 8DD76F9E0486AA7600D96B5E /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = xmlparser; + productInstallPath = "$(HOME)/bin"; + productName = xmlparser; + productReference = 8DD76FA10486AA7600D96B5E /* xmlparser */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "xmlparser" */; + hasScannedForEncodings = 1; + mainGroup = 08FB7794FE84155DC02AAC07 /* xmlparser */; + projectDirPath = ""; + targets = ( + 8DD76F960486AA7600D96B5E /* xmlparser */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DD76F990486AA7600D96B5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DD76F9A0486AA7600D96B5E /* xmlparser.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB927508733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = xmlparser_Prefix.pch; + INSTALL_PATH = "$(HOME)/bin"; + PRODUCT_NAME = xmlparser; + ZERO_LINK = YES; + }; + name = Debug; + }; + 1DEB927608733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + ppc, + i386, + ); + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = xmlparser_Prefix.pch; + INSTALL_PATH = "$(HOME)/bin"; + PRODUCT_NAME = xmlparser; + }; + name = Release; + }; + 1DEB927908733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + ZERO_LINK = YES; + }; + name = Debug; + }; + 1DEB927A08733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + ZERO_LINK = NO; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "xmlparser" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927508733DD40010E9CD /* Debug */, + 1DEB927608733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "xmlparser" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927908733DD40010E9CD /* Debug */, + 1DEB927A08733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/FireOpal/unit-tests/src/xmlparser/xmlparser_Prefix.pch b/FireOpal/unit-tests/src/xmlparser/xmlparser_Prefix.pch new file mode 100644 index 0000000..530e057 --- /dev/null +++ b/FireOpal/unit-tests/src/xmlparser/xmlparser_Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'xmlparser' target in the 'xmlparser' project. +// + +#ifdef __OBJC__ + #import +#endif diff --git a/FireOpal/unit-tests/test-cases/16-byte-alignment/Makefile b/FireOpal/unit-tests/test-cases/16-byte-alignment/Makefile new file mode 100644 index 0000000..a3a256f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/16-byte-alignment/Makefile @@ -0,0 +1,44 @@ +## +# 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 + +# +# Test that -O2 optimization fails when trying to make a long 16-byte aligned. +# + +run: all + +all: + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -arch ${ARCH} -c -O2 tl_test2.c -o tl_test2-${ARCH}.o + + # verify that the alignment is correct in the .o + ObjectDump -only _ai -align -no_content tl_test2-${ARCH}.o|${FAIL_IF_ERROR} grep '\<0 mod 16\>' >/dev/null + + # now verify the executable + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -arch ${ARCH} -O2 tl_test2-${ARCH}.o -o tl_test2-${ARCH} + ${FAIL_IF_ERROR} sh -c "nm tl_test2-${ARCH}|grep '0 D _ai\>' >/dev/null" + ${PASS_IFF_GOOD_MACHO} tl_test2-${ARCH} + +clean: + rm -rf tl_test2-* diff --git a/FireOpal/unit-tests/test-cases/16-byte-alignment/comment.txt b/FireOpal/unit-tests/test-cases/16-byte-alignment/comment.txt new file mode 100644 index 0000000..eb9eaf5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/16-byte-alignment/comment.txt @@ -0,0 +1 @@ +Test 16 byte alignment with -O2 optimization. Radar #4662185 diff --git a/FireOpal/unit-tests/test-cases/16-byte-alignment/tl_test2.c b/FireOpal/unit-tests/test-cases/16-byte-alignment/tl_test2.c new file mode 100644 index 0000000..ff27fec --- /dev/null +++ b/FireOpal/unit-tests/test-cases/16-byte-alignment/tl_test2.c @@ -0,0 +1,43 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * 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@ + */ + +#include + +int i = 1; +int ai __attribute__ ((aligned (16))) = 1; + +int main() { + + long addr = (long)&ai; + i = ai; + + if (addr & 0xf) { + printf("failed: ai = %p\n", (void *)addr); + return 1; + } + + printf("passed: ai = %p\n", (void *)addr); + return 0; + +} diff --git a/FireOpal/unit-tests/test-cases/absolute-symbol/Makefile b/FireOpal/unit-tests/test-cases/absolute-symbol/Makefile new file mode 100644 index 0000000..806c64e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/absolute-symbol/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Validate linker processing of absolute symbols +# + +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 + nm -m all.o | grep _myAbs | grep absolute | ${FAIL_IF_EMPTY} + ${LD} -arch ${ARCH} -static all.o -e _main -o main2 -new_linker + ${PASS_IFF_GOOD_MACHO} main2 + +clean: + rm -rf main.o abs.o all.o main main2 diff --git a/FireOpal/unit-tests/test-cases/absolute-symbol/abs.s b/FireOpal/unit-tests/test-cases/absolute-symbol/abs.s new file mode 100644 index 0000000..216867c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/absolute-symbol/abs.s @@ -0,0 +1,3 @@ + + .globl _myAbs + .set _myAbs, 0xfe000000 diff --git a/FireOpal/unit-tests/test-cases/absolute-symbol/main.c b/FireOpal/unit-tests/test-cases/absolute-symbol/main.c new file mode 100644 index 0000000..eec3f61 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/absolute-symbol/main.c @@ -0,0 +1,5 @@ + +extern int* myAbs; + +int main() { return *myAbs; } + diff --git a/FireOpal/unit-tests/test-cases/alias-command-line/Makefile b/FireOpal/unit-tests/test-cases/alias-command-line/Makefile new file mode 100644 index 0000000..9e87329 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/alias-command-line/Makefile @@ -0,0 +1,53 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is to verify that added aliases to a .o +# file via the command line is the same as doing so in the sources. +# The ObjectDump utility is used +# dump a "canonical" textual representation of a .o file. +# The before and after .o files are then diff'ed. +# No differences means this test passes +# + +run: all + +all: + ${CC} ${ASMFLAGS} aliases.s -DALIASES=1 -c -o aliases.source.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases.source.${ARCH}.o > aliases.source.${ARCH}.o.dump + + ${CC} ${ASMFLAGS} aliases.s -c -o aliases.tmp.${ARCH}.o + ${FAIL_IF_BAD_OBJ} aliases.tmp.${ARCH}.o + + ${LD} -arch ${ARCH} -r aliases.tmp.${ARCH}.o -alias _foo _fooalt -alias _foo _fooalt2 -o aliases.cmdline.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases.cmdline.${ARCH}.o > aliases.cmdline.${ARCH}.o.dump + ${FAIL_IF_ERROR} diff aliases.source.${ARCH}.o.dump aliases.cmdline.${ARCH}.o.dump + + ${LD} -arch ${ARCH} -r aliases.tmp.${ARCH}.o -alias_list aliases.txt -o aliases.file.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases.file.${ARCH}.o > aliases.file.${ARCH}.o.dump + ${PASS_IFF} diff aliases.source.${ARCH}.o.dump aliases.file.${ARCH}.o.dump + +clean: + rm -rf *.o *.dump diff --git a/FireOpal/unit-tests/test-cases/alias-command-line/aliases.s b/FireOpal/unit-tests/test-cases/alias-command-line/aliases.s new file mode 100644 index 0000000..ffab4a9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/alias-command-line/aliases.s @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2006 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@ + */ + + .text + +_temp: nop + nop + + .globl _foo +_foo: nop + nop + +#if ALIASES + .globl _fooalt + .globl _fooalt2 +/* this should make an alias "_fooalt" for "_foo" */ +_fooalt = _foo +_fooalt2 = _foo +#endif + +_bar: nop + nop + + + .subsections_via_symbols \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/alias-command-line/aliases.txt b/FireOpal/unit-tests/test-cases/alias-command-line/aliases.txt new file mode 100644 index 0000000..291f2f7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/alias-command-line/aliases.txt @@ -0,0 +1,6 @@ +_foo _fooalt +# comment +_foo _fooalt2 + + + diff --git a/FireOpal/unit-tests/test-cases/alias-objects/Makefile b/FireOpal/unit-tests/test-cases/alias-objects/Makefile new file mode 100644 index 0000000..f4bfdc8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/alias-objects/Makefile @@ -0,0 +1,44 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is to verify a .o file with aliases +# can round trip through ld -r correctly. The ObjectDump utility is used +# dump a "canonical" textual representation of a .o file. +# The before and after .o files are then diff'ed. +# No differences means this test passes +# + +run: all + +all: + ${CC} ${ASMFLAGS} aliases.s -c -o aliases.${ARCH}.o + ${LD} -arch ${ARCH} -r -keep_private_externs aliases.${ARCH}.o -o aliases-r.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases.${ARCH}.o > aliases.${ARCH}.o.dump + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases-r.${ARCH}.o > aliases-r.${ARCH}.o.dump + ${PASS_IFF} diff aliases.${ARCH}.o.dump aliases-r.${ARCH}.o.dump + +clean: + rm -rf *.o *.dump diff --git a/FireOpal/unit-tests/test-cases/alias-objects/aliases.s b/FireOpal/unit-tests/test-cases/alias-objects/aliases.s new file mode 100644 index 0000000..b21f8c7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/alias-objects/aliases.s @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2006 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@ + */ + + .text + +_temp: nop + nop + + .globl _foo +_foo: nop + nop + + .globl _fooalt + .globl _fooalt2 +/* this should make an alias "_fooalt" for "_foo" */ +_fooalt = _foo +_fooalt2 = _foo + +_bar: nop + nop + + + .subsections_via_symbols \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/align-modulus/Makefile b/FireOpal/unit-tests/test-cases/align-modulus/Makefile new file mode 100644 index 0000000..6b6a50f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/align-modulus/Makefile @@ -0,0 +1,40 @@ +## +# 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 + +# +# The point of this test is to verify that the modules of +# symbol _b is maintained. The address for _b must be +# 3 mod 16. Therefore the last hexdigit of the address +# must be 3. + +run: all + +all: + ${CC} ${ASMFLAGS} -dynamiclib -single_module -dead_strip foo.c align.s -exported_symbols_list foo.exp -o foo.${ARCH}.dylib + ${FAIL_IF_BAD_MACHO} foo.${ARCH}.dylib + nm foo.${ARCH}.dylib | grep "3 d _b" | ${PASS_IFF_STDIN} + +clean: + rm -rf *.dylib diff --git a/FireOpal/unit-tests/test-cases/align-modulus/align.s b/FireOpal/unit-tests/test-cases/align-modulus/align.s new file mode 100644 index 0000000..a288960 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/align-modulus/align.s @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2006 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@ + */ + + .data + .align 0 +_a: .byte 3 + .byte 3 + .byte 3 + .globl _b +_b: .byte 4 ;# address is 3 + .align 4 +L1: .quad 0 +_c: .long 8 + + .subsections_via_symbols + diff --git a/FireOpal/unit-tests/test-cases/align-modulus/comment.txt b/FireOpal/unit-tests/test-cases/align-modulus/comment.txt new file mode 100644 index 0000000..240c171 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/align-modulus/comment.txt @@ -0,0 +1,2 @@ +The point of this test is to verify that the modules of symbol _b is maintained. The address for _b must be +3 mod 16. Therefore the last hexdigit of the address must be 3. diff --git a/FireOpal/unit-tests/test-cases/align-modulus/foo.c b/FireOpal/unit-tests/test-cases/align-modulus/foo.c new file mode 100644 index 0000000..0b88dff --- /dev/null +++ b/FireOpal/unit-tests/test-cases/align-modulus/foo.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2006 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@ + */ + +extern char b; +int my = 2; + +char foo() +{ + return my+b; +} + + diff --git a/FireOpal/unit-tests/test-cases/align-modulus/foo.exp b/FireOpal/unit-tests/test-cases/align-modulus/foo.exp new file mode 100644 index 0000000..70eefe9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/align-modulus/foo.exp @@ -0,0 +1 @@ +_foo diff --git a/FireOpal/unit-tests/test-cases/allow-stack-execute/Makefile b/FireOpal/unit-tests/test-cases/allow-stack-execute/Makefile new file mode 100644 index 0000000..6e0be3f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/allow-stack-execute/Makefile @@ -0,0 +1,46 @@ +## +# Copyright (c) 2006 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 + +# +# Test the we set the stack execution bit properly. +# + +run: all + +all: + +# Test with the flag + ${CC} ${CCFLAGS} foo.c -o foo-${ARCH} -Wl,-allow_stack_execute + ${FAIL_IF_BAD_MACHO} foo-${ARCH} + ${OTOOL} -hv foo-${ARCH} | grep ALLOW_STACK_EXECUTION | ${FAIL_IF_EMPTY} + rm -f foo-${ARCH} + +# Test without the flag + ${CC} ${CCFLAGS} foo.c -o foo-${ARCH} + ${FAIL_IF_BAD_MACHO} foo-${ARCH} + ${OTOOL} -hv foo-${ARCH} | grep ALLOW_STACK_EXECUTION | ${PASS_IFF_EMPTY} + +clean: + rm -rf foo-* diff --git a/FireOpal/unit-tests/test-cases/allow-stack-execute/comment.txt b/FireOpal/unit-tests/test-cases/allow-stack-execute/comment.txt new file mode 100644 index 0000000..525ab2b --- /dev/null +++ b/FireOpal/unit-tests/test-cases/allow-stack-execute/comment.txt @@ -0,0 +1 @@ +Test the we set the stack execution bit properly. diff --git a/FireOpal/unit-tests/test-cases/allow-stack-execute/foo.c b/FireOpal/unit-tests/test-cases/allow-stack-execute/foo.c new file mode 100644 index 0000000..57ed6ba --- /dev/null +++ b/FireOpal/unit-tests/test-cases/allow-stack-execute/foo.c @@ -0,0 +1,4 @@ +int main (void) +{ + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/allowable-client/Makefile b/FireOpal/unit-tests/test-cases/allowable-client/Makefile new file mode 100644 index 0000000..ef293a6 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/allowable-client/Makefile @@ -0,0 +1,110 @@ +## +# 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 + +# +# Test that the -allowable_client and -client options +# work when linking against subframeworks. +# + +run: all + +all: +# build with two allowable_clients + ${CC} ${CCFLAGS} -dynamiclib -umbrella foo -allowable_client bar -allowable_client baz foo.c -o foo.${ARCH}.dylib + ${FAIL_IF_BAD_MACHO} foo.${ARCH}.dylib + +# test that -o works + ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.${ARCH}.dylib foo.${ARCH}.dylib + ${FAIL_IF_BAD_MACHO} libbar.${ARCH}.dylib + +# test that a framework style output works + mkdir -p bar.framework + ${CC} ${CCFLAGS} -dynamiclib bar.c -o bar.framework/bar foo.${ARCH}.dylib + ${FAIL_IF_BAD_MACHO} bar.framework/bar + +# test that second -o works + ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.${ARCH}.dylib foo.${ARCH}.dylib + ${FAIL_IF_BAD_MACHO} foo.${ARCH}.dylib + +# test that -o and -install_name works with install_name as an allowable + ${CC} ${CCFLAGS} -dynamiclib bar.c -o temp.${ARCH}.dylib -install_name /tmp/libbar.${ARCH}.dylib foo.${ARCH}.dylib + ${FAIL_IF_BAD_MACHO} temp.${ARCH}.dylib + +# test that -install_name works with variant name + ${CC} ${CCFLAGS} -dynamiclib bar.c -o temp.${ARCH}.dylib -install_name /tmp/libbar_profile foo.${ARCH}.dylib + ${FAIL_IF_BAD_MACHO} temp.${ARCH}.dylib + +# test that -o and -install_name fails with install_name different than allowable + ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} -dynamiclib bar.c -o bar.${ARCH}.dylib -install_name /tmp/fail.${ARCH}.dylib foo.${ARCH}.dylib >& fail.log + +# test that a bundle and no client_name fails + ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} -bundle bar.c -o temp.${ARCH}.bundle foo.${ARCH}.dylib >& fail.log + +# test that a bundle and an allowable client_name passes + ${CC} ${CCFLAGS} -bundle bar.c -client_name bar -o bar.${ARCH}.bundle foo.${ARCH}.dylib + ${FAIL_IF_BAD_MACHO} bar.${ARCH}.bundle + +# test umbrella can link against subs + mkdir -p foo.framework + ${CC} ${CCFLAGS} -dynamiclib foo.${ARCH}.dylib -o foo.framework/foo + ${FAIL_IF_BAD_MACHO} foo.framework/foo + +# test umbrella variant can link against subs + mkdir -p foo.framework + ${CC} ${CCFLAGS} -dynamiclib foo.${ARCH}.dylib -o foo.framework/foo_debug -install_name /path/foo.framework/foo_debug + ${FAIL_IF_BAD_MACHO} foo.framework/foo_debug + +# test sibling in umbrella can link against subs + ${CC} ${CCFLAGS} -dynamiclib main.c -umbrella foo foo.${ARCH}.dylib -o ./main.dylib + ${FAIL_IF_BAD_MACHO} main.dylib + +# test anyone can link against umbrella + ${CC} ${CCFLAGS} main.c -o main.${ARCH} -framework foo -F. + ${FAIL_IF_BAD_MACHO} main.${ARCH} + +# test that an executable and no client_name fails + ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -o main.${ARCH} foo.${ARCH}.dylib >& fail.log + +# test that an executable and an allowable client_name passes + ${CC} ${CCFLAGS} main.c -o main.${ARCH} -client_name bar foo.${ARCH}.dylib + ${PASS_IFF_GOOD_MACHO} main.${ARCH} + +# test that a regular dylib can be made unlinkable by using -allowable_client + ${CC} ${CCFLAGS} -dynamiclib foo.c -allowable_client '!' -o unlinkable_foo.${ARCH}.dylib + ${FAIL_IF_BAD_MACHO} unlinkable_foo.${ARCH}.dylib + ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -o main.${ARCH} unlinkable_foo.${ARCH}.dylib >& fail.log + +# test that a regular dylib can be made linkable by only specially named clients + ${CC} ${CCFLAGS} -dynamiclib foo.c -allowable_client special -o restrictive_foo.${ARCH}.dylib + ${FAIL_IF_BAD_MACHO} restrictive_foo.${ARCH}.dylib + ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -o main.${ARCH} restrictive_foo.${ARCH}.dylib >& fail.log + ${CC} ${CCFLAGS} main.c -o main.${ARCH} -client_name special restrictive_foo.${ARCH}.dylib + ${FAIL_IF_BAD_MACHO} main.${ARCH} + +# print final pass + ${PASS_IFF_GOOD_MACHO} foo.${ARCH}.dylib + +clean: + rm -rf *.dylib *.bundle main.???* fail.log *.framework diff --git a/FireOpal/unit-tests/test-cases/allowable-client/bar.c b/FireOpal/unit-tests/test-cases/allowable-client/bar.c new file mode 100644 index 0000000..dbaeef8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/allowable-client/bar.c @@ -0,0 +1,6 @@ +extern int foo (); + +int bar (void) +{ + return foo(); +} diff --git a/FireOpal/unit-tests/test-cases/allowable-client/baz.c b/FireOpal/unit-tests/test-cases/allowable-client/baz.c new file mode 100644 index 0000000..dbaeef8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/allowable-client/baz.c @@ -0,0 +1,6 @@ +extern int foo (); + +int bar (void) +{ + return foo(); +} diff --git a/FireOpal/unit-tests/test-cases/allowable-client/comment.txt b/FireOpal/unit-tests/test-cases/allowable-client/comment.txt new file mode 100644 index 0000000..0202b5f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/allowable-client/comment.txt @@ -0,0 +1 @@ +Test that the -allowable_client and -client options work when linking against subframeworks. diff --git a/FireOpal/unit-tests/test-cases/allowable-client/foo.c b/FireOpal/unit-tests/test-cases/allowable-client/foo.c new file mode 100644 index 0000000..d0cdf47 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/allowable-client/foo.c @@ -0,0 +1,4 @@ +int foo (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/allowable-client/main.c b/FireOpal/unit-tests/test-cases/allowable-client/main.c new file mode 100644 index 0000000..7b76173 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/allowable-client/main.c @@ -0,0 +1,6 @@ +extern int foo (); + +int main (void) +{ + return foo(); +} diff --git a/FireOpal/unit-tests/test-cases/archive-ObjC/Makefile b/FireOpal/unit-tests/test-cases/archive-ObjC/Makefile new file mode 100644 index 0000000..892043d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-ObjC/Makefile @@ -0,0 +1,49 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is to check that -ObjC loads all (and only) +# .o files that contain Objective-C code. +# + +run: all + +all: + ${CC} ${CCFLAGS} foo.m -c -o foo-${ARCH}.o + ${FAIL_IF_BAD_OBJ} foo-${ARCH}.o + ${CC} ${CCFLAGS} bar.c -c -o bar-${ARCH}.o + ${FAIL_IF_BAD_OBJ} bar-${ARCH}.o + ${CC} ${CCFLAGS} baz.m -c -o baz-${ARCH}.o + ${FAIL_IF_BAD_OBJ} baz-${ARCH}.o + libtool -static foo-${ARCH}.o bar-${ARCH}.o baz-${ARCH}.o -o libfoobarbaz-${ARCH}.a + ${CC} ${CCFLAGS} main.c -lfoobarbaz-${ARCH} -L. -o main-${ARCH} -ObjC -framework Foundation -framework CoreFoundation + ${FAIL_IF_BAD_MACHO} main-${ARCH} + nm main-${ARCH} | grep "_bar" | ${FAIL_IF_STDIN} + nm main-${ARCH} | grep "_Foo" | ${FAIL_IF_EMPTY} + nm main-${ARCH} | grep "_Baz" | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main-${ARCH} + +clean: + rm -rf main-* *.o *.a diff --git a/FireOpal/unit-tests/test-cases/archive-ObjC/bar.c b/FireOpal/unit-tests/test-cases/archive-ObjC/bar.c new file mode 100644 index 0000000..d9b468b --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-ObjC/bar.c @@ -0,0 +1,2 @@ + +int bar() { return 0; } diff --git a/FireOpal/unit-tests/test-cases/archive-ObjC/baz.m b/FireOpal/unit-tests/test-cases/archive-ObjC/baz.m new file mode 100644 index 0000000..90ae0a1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-ObjC/baz.m @@ -0,0 +1,8 @@ +#include + +@interface Baz : NSObject +@end + +@implementation Baz +@end + diff --git a/FireOpal/unit-tests/test-cases/archive-ObjC/foo.m b/FireOpal/unit-tests/test-cases/archive-ObjC/foo.m new file mode 100644 index 0000000..acba7a4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-ObjC/foo.m @@ -0,0 +1,8 @@ +#include + +@interface Foo : NSObject +@end + +@implementation Foo +@end + diff --git a/FireOpal/unit-tests/test-cases/archive-ObjC/main.c b/FireOpal/unit-tests/test-cases/archive-ObjC/main.c new file mode 100644 index 0000000..dc2fbef --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-ObjC/main.c @@ -0,0 +1,31 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + + +int main() +{ + fprintf(stdout, "hello\n"); + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/archive-basic/Makefile b/FireOpal/unit-tests/test-cases/archive-basic/Makefile new file mode 100644 index 0000000..39c0ef9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-basic/Makefile @@ -0,0 +1,46 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that .o files +# can be found in archives. +# + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -c -o foo-${ARCH}.o + ${FAIL_IF_BAD_OBJ} foo-${ARCH}.o + ${CC} ${CCFLAGS} bar.c -c -o bar-${ARCH}.o + ${FAIL_IF_BAD_OBJ} bar-${ARCH}.o + libtool -static foo-${ARCH}.o bar-${ARCH}.o -o libfoobar-${ARCH}.a + ${CC} ${CCFLAGS} main.c -lfoobar-${ARCH} -L. -o main-${ARCH} + ${FAIL_IF_BAD_MACHO} main-${ARCH} + nm main-${ARCH} | grep "_bar" | ${PASS_IFF_EMPTY} + ${CC} ${CCFLAGS} main.c -all_load -lfoobar-${ARCH} -L. -o main-${ARCH} + ${FAIL_IF_BAD_MACHO} main-${ARCH} + +clean: + rm -rf main-* *.o *.a diff --git a/FireOpal/unit-tests/test-cases/archive-basic/bar.c b/FireOpal/unit-tests/test-cases/archive-basic/bar.c new file mode 100644 index 0000000..7fe6403 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-basic/bar.c @@ -0,0 +1 @@ +int bar() { return 0; } diff --git a/FireOpal/unit-tests/test-cases/archive-basic/comment.txt b/FireOpal/unit-tests/test-cases/archive-basic/comment.txt new file mode 100644 index 0000000..0d34170 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-basic/comment.txt @@ -0,0 +1 @@ +The point of this test is a sanity check that .o files can be found in archives. diff --git a/FireOpal/unit-tests/test-cases/archive-basic/foo.c b/FireOpal/unit-tests/test-cases/archive-basic/foo.c new file mode 100644 index 0000000..a60f28c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-basic/foo.c @@ -0,0 +1 @@ +int foo() { return 1; } diff --git a/FireOpal/unit-tests/test-cases/archive-basic/main.c b/FireOpal/unit-tests/test-cases/archive-basic/main.c new file mode 100644 index 0000000..57c4c68 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-basic/main.c @@ -0,0 +1,32 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +extern int foo(); + +int main() +{ + fprintf(stdout, "hello\n"); + return foo(); +} \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/archive-duplicate/Makefile b/FireOpal/unit-tests/test-cases/archive-duplicate/Makefile new file mode 100644 index 0000000..61f4bc7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-duplicate/Makefile @@ -0,0 +1,45 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that ia an archive +# is listed multiple times, the extras are ignored. +# This is done in some makefiles because the traditional linker +# semantics is to only search an archive once. +# + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -c -o foo-${ARCH}.o + ${CC} ${CCFLAGS} bar.c -c -o bar-${ARCH}.o + libtool -static foo-${ARCH}.o bar-${ARCH}.o -o libfoobar-${ARCH}.a + ${CC} ${CCFLAGS} main.c -lfoobar-${ARCH} -lfoobar-${ARCH} -L. -o main-${ARCH} -all_load + ${FAIL_IF_BAD_MACHO} main-${ARCH} + ${CC} ${CCFLAGS} main.c ./libfoobar-${ARCH}.a ./libfoobar-${ARCH}.a -L. -o main-${ARCH} -all_load + ${PASS_IFF_GOOD_MACHO} main-${ARCH} + +clean: + rm -rf main-* *.o *.a diff --git a/FireOpal/unit-tests/test-cases/archive-duplicate/bar.c b/FireOpal/unit-tests/test-cases/archive-duplicate/bar.c new file mode 100644 index 0000000..7fe6403 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-duplicate/bar.c @@ -0,0 +1 @@ +int bar() { return 0; } diff --git a/FireOpal/unit-tests/test-cases/archive-duplicate/foo.c b/FireOpal/unit-tests/test-cases/archive-duplicate/foo.c new file mode 100644 index 0000000..a60f28c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-duplicate/foo.c @@ -0,0 +1 @@ +int foo() { return 1; } diff --git a/FireOpal/unit-tests/test-cases/archive-duplicate/main.c b/FireOpal/unit-tests/test-cases/archive-duplicate/main.c new file mode 100644 index 0000000..57c4c68 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-duplicate/main.c @@ -0,0 +1,32 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +extern int foo(); + +int main() +{ + fprintf(stdout, "hello\n"); + return foo(); +} \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/archive-weak/Makefile b/FireOpal/unit-tests/test-cases/archive-weak/Makefile new file mode 100644 index 0000000..2d53734 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-weak/Makefile @@ -0,0 +1,51 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test if the linker already has a weak definition +# it does not try to find another copy in an archive +# +# There are two case to test: +# 1) both the main .o files and the archive have the same weak symbol (_foo) +# 2) main.o has a weak symbol and the archive has a non-weak symbol (_baz) +# In both cases the linker should ignore the archive. +# + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -c -o foo-${ARCH}.o + ${FAIL_IF_BAD_OBJ} foo-${ARCH}.o + ${CC} ${CCFLAGS} bar.c -c -o bar-${ARCH}.o + ${FAIL_IF_BAD_OBJ} bar-${ARCH}.o + ${CC} ${CCFLAGS} baz.c -c -o baz-${ARCH}.o + ${FAIL_IF_BAD_OBJ} baz-${ARCH}.o + libtool -static foo-${ARCH}.o bar-${ARCH}.o baz-${ARCH}.o -o libfoobar-${ARCH}.a + ${CC} ${CCFLAGS} main.c foo.c -lfoobar-${ARCH} -L. -o main-${ARCH} + ${FAIL_IF_BAD_MACHO} main-${ARCH} + nm -m main-${ARCH} | grep _baz | grep weak | ${PASS_IFF_STDIN} + +clean: + rm -rf main-* *.o *.a diff --git a/FireOpal/unit-tests/test-cases/archive-weak/bar.c b/FireOpal/unit-tests/test-cases/archive-weak/bar.c new file mode 100644 index 0000000..7fe6403 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-weak/bar.c @@ -0,0 +1 @@ +int bar() { return 0; } diff --git a/FireOpal/unit-tests/test-cases/archive-weak/baz.c b/FireOpal/unit-tests/test-cases/archive-weak/baz.c new file mode 100644 index 0000000..387ccc1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-weak/baz.c @@ -0,0 +1,11 @@ + + + +// intentionally not-weak +int baz() +{ + return 1; +} + + + diff --git a/FireOpal/unit-tests/test-cases/archive-weak/comment.txt b/FireOpal/unit-tests/test-cases/archive-weak/comment.txt new file mode 100644 index 0000000..902d22c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-weak/comment.txt @@ -0,0 +1,7 @@ +The point of this test if the linker already has a weak definition +it does not try to find another copy in an archive + +There are two case to test: +1) both the main .o files and the archive have the same weak symbol (_foo) +2) main.o has a weak symbol and the archive has a non-weak symbol (_baz) +In both cases the linker should ignore the archive. diff --git a/FireOpal/unit-tests/test-cases/archive-weak/foo.c b/FireOpal/unit-tests/test-cases/archive-weak/foo.c new file mode 100644 index 0000000..d7003fa --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-weak/foo.c @@ -0,0 +1,13 @@ + + +void collisionChecker() { } + + +int __attribute__((weak)) foo() +{ + collisionChecker(); + return 1; +} + + + diff --git a/FireOpal/unit-tests/test-cases/archive-weak/main.c b/FireOpal/unit-tests/test-cases/archive-weak/main.c new file mode 100644 index 0000000..d1ce4a9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/archive-weak/main.c @@ -0,0 +1,42 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +extern int foo(); +extern int bar(); + +// intentionally weak +int __attribute__((weak)) baz() +{ + return 1; +} + +int main() +{ + fprintf(stdout, "hello\n"); + return foo() + bar() + baz(); +} + + + diff --git a/FireOpal/unit-tests/test-cases/auto-arch/Makefile b/FireOpal/unit-tests/test-cases/auto-arch/Makefile new file mode 100644 index 0000000..3b1cc7c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/auto-arch/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2006-2007 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 ld can figure out architecture from .o files without -arch option +# + +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} + +clean: + rm -rf hello.o hello diff --git a/FireOpal/unit-tests/test-cases/auto-arch/hello.c b/FireOpal/unit-tests/test-cases/auto-arch/hello.c new file mode 100644 index 0000000..14d9363 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/auto-arch/hello.c @@ -0,0 +1,29 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +int main() +{ + fprintf(stdout, "hello\n"); +} diff --git a/FireOpal/unit-tests/test-cases/blank-stubs/Makefile b/FireOpal/unit-tests/test-cases/blank-stubs/Makefile new file mode 100644 index 0000000..346e2b7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/blank-stubs/Makefile @@ -0,0 +1,61 @@ +## +# Copyright (c) 2006 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 + +ALL_ARCH_OPTIONS = $(patsubst %,-arch %,$(VALID_ARCHS)) + +# +# Test that blank stubs are handled properly +# + +run: all + +all: +# build example fully fat dylib + + gcc `echo ${ALL_ARCH_OPTIONS}` -dynamiclib foo.c -o libfoo.dylib -install_name libfoo.dylib + ${FAIL_IF_BAD_MACHO} libfoo.dylib + + # handle the case of a native ppc compile--this sets the subtype, which must be passed to lipo + if [ x${ARCH} != xppc ]; \ + then \ + SUB_ARCH=${ARCH}; \ + else \ + SUB_ARCH=`lipo -info libfoo.dylib | sed 's/.*://;s/ppc64 //;s/.* \(ppc[^ ]*\).*/\1/'`; \ + echo SUB_ARCH $$SUB_ARCH; \ + if [ x$$SUB_ARCH = xALL ]; \ + then \ + SUB_ARCH=ppc; \ + fi \ + fi; \ + lipo libfoo.dylib -remove $$SUB_ARCH -output libfoo.dylib + + lipo -create libfoo.dylib -arch_blank ${ARCH} -output libfoo.dylib + ${CC} ${CCFLAGS} main.c libfoo.dylib -o main + ${OTOOL} -L main | grep libfoo | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} main + + +clean: + rm -rf libfoo.dylib main diff --git a/FireOpal/unit-tests/test-cases/blank-stubs/comment.txt b/FireOpal/unit-tests/test-cases/blank-stubs/comment.txt new file mode 100644 index 0000000..77a8764 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/blank-stubs/comment.txt @@ -0,0 +1 @@ +Test that blank stubs are handled properly diff --git a/FireOpal/unit-tests/test-cases/blank-stubs/foo.c b/FireOpal/unit-tests/test-cases/blank-stubs/foo.c new file mode 100644 index 0000000..d0cdf47 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/blank-stubs/foo.c @@ -0,0 +1,4 @@ +int foo (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/blank-stubs/main.c b/FireOpal/unit-tests/test-cases/blank-stubs/main.c new file mode 100644 index 0000000..6c9f6a4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/blank-stubs/main.c @@ -0,0 +1,5 @@ + +int main (void) +{ + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/branch-islands/Makefile b/FireOpal/unit-tests/test-cases/branch-islands/Makefile new file mode 100644 index 0000000..c85f382 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/branch-islands/Makefile @@ -0,0 +1,47 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +ifeq ($(ARCH),armv6) + ARCH_FLAGS = -mlong-branch +else + ARCH_FLAGS = +endif + + + +# +# Simple test for branch islands +# + +run: all + + + +all: + ${CC} ${CCFLAGS} hello.c space.s extra.c -o hello ${ARCH_FLAGS} + ${PASS_IFF_GOOD_MACHO} hello + +clean: + rm hello diff --git a/FireOpal/unit-tests/test-cases/branch-islands/extra.c b/FireOpal/unit-tests/test-cases/branch-islands/extra.c new file mode 100644 index 0000000..a1991fe --- /dev/null +++ b/FireOpal/unit-tests/test-cases/branch-islands/extra.c @@ -0,0 +1,8 @@ +#include + + +void foo() +{ + fprintf(stdout, "foo\n"); +} + diff --git a/FireOpal/unit-tests/test-cases/branch-islands/hello.c b/FireOpal/unit-tests/test-cases/branch-islands/hello.c new file mode 100644 index 0000000..89caa9d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/branch-islands/hello.c @@ -0,0 +1,10 @@ +#include + +extern void foo(); + +int main() +{ + fprintf(stdout, "hello\n"); + foo(); +} + diff --git a/FireOpal/unit-tests/test-cases/branch-islands/space.s b/FireOpal/unit-tests/test-cases/branch-islands/space.s new file mode 100644 index 0000000..dd28637 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/branch-islands/space.s @@ -0,0 +1,39 @@ + +#if __ppc__ + + .text + +_prejunk: + mr r3,r5 + mr r3,r4 + blr + + +_space1: + .space 15*1024*1024 + 2 + + .align 5 +_junk: + mr r3,r5 + mr r3,r4 + blr + + +_space2: + .space 2*1024*1024 + +#endif + + +#if __arm__ + + +_space1: + .space 32*1024*1024 + 2 + + +#endif + + + .subsections_via_symbols + \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/bundle_loader/Makefile b/FireOpal/unit-tests/test-cases/bundle_loader/Makefile new file mode 100644 index 0000000..96d83b8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/bundle_loader/Makefile @@ -0,0 +1,55 @@ +## +# Copyright (c) 2006 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 + +# +# Ccheck that ld -bundle_loader works with bundles and executable, +# and _bar is found in the loader and not in libbar.dylib +# + +run: all + +all: + ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib + ${FAIL_IF_BAD_MACHO} libbar.dylib + # test with loader as main executable + ${CC} ${CCFLAGS} main.c bar.c -o main + ${FAIL_IF_BAD_MACHO} main + ${CC} ${CCFLAGS} bundle.c -bundle -bundle_loader main libbar.dylib -o bundle.bundle + ${FAIL_IF_BAD_MACHO} bundle.bundle + nm -m bundle.bundle | grep _bar | grep "from executable" | ${PASS_IFF_STDIN} + # test with loader as another bundle + ${CC} ${CCFLAGS} -bundle main.c bar.c -o mainbundle + ${FAIL_IF_BAD_MACHO} main + ${CC} ${CCFLAGS} bundle.c -bundle -bundle_loader mainbundle libbar.dylib -o bundle.bundle + ${FAIL_IF_BAD_MACHO} bundle.bundle + nm -m bundle.bundle | grep _bar | grep "from executable" | ${PASS_IFF_STDIN} + # verify error message when linking with raw bundle + ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c bar.c -o main bundle.bundle 2> error.log + grep "link with bundle" error.log | ${PASS_IFF_STDIN} + +clean: + rm *.dylib main bundle.bundle mainbundle error.log diff --git a/FireOpal/unit-tests/test-cases/bundle_loader/bar.c b/FireOpal/unit-tests/test-cases/bundle_loader/bar.c new file mode 100644 index 0000000..b737953 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/bundle_loader/bar.c @@ -0,0 +1,31 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + + +// funcation called by a loaded bundle +int bar() +{ + return 1; +} + diff --git a/FireOpal/unit-tests/test-cases/bundle_loader/bundle.c b/FireOpal/unit-tests/test-cases/bundle_loader/bundle.c new file mode 100644 index 0000000..ba78c28 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/bundle_loader/bundle.c @@ -0,0 +1,31 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +extern int bar(); + +int foo() +{ + return bar(); +} diff --git a/FireOpal/unit-tests/test-cases/bundle_loader/main.c b/FireOpal/unit-tests/test-cases/bundle_loader/main.c new file mode 100644 index 0000000..c9e53f9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/bundle_loader/main.c @@ -0,0 +1,30 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +int main() +{ + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/cfstring-coalesce/Makefile b/FireOpal/unit-tests/test-cases/cfstring-coalesce/Makefile new file mode 100644 index 0000000..c1ca816 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/cfstring-coalesce/Makefile @@ -0,0 +1,52 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Test that cfstring literals are coalesced and dead stripped +# There is 3 CFSTR in foo.c and 1 CFSTR in bar.c +# After coalescing and dead stripping there should be only one CFSTR in the output +# + +ifeq (,${findstring 64,$(ARCH)}) + CFSTRING_SIZE = 16 + CFSTRING_SIZE_WRITABLE = 32 +else + CFSTRING_SIZE = 32 + CFSTRING_SIZE_WRITABLE = 64 +endif + + + +run: all + +all: + ${CC} ${CCFLAGS} foo.c bar.c -o foo -framework CoreFoundation -dead_strip + size -l foo | grep "__cfstring: ${CFSTRING_SIZE}" | ${FAIL_IF_EMPTY} + # now try with -fwritable-strings + ${CC} ${CCFLAGS} foo.c bar.c -o foo_writable -framework CoreFoundation -dead_strip -fwritable-strings + size -l foo_writable | grep "__cfstring: ${CFSTRING_SIZE_WRITABLE}" | ${PASS_IFF_STDIN} + +clean: + rm -rf foo foo_writable diff --git a/FireOpal/unit-tests/test-cases/cfstring-coalesce/bar.c b/FireOpal/unit-tests/test-cases/cfstring-coalesce/bar.c new file mode 100644 index 0000000..9a84abd --- /dev/null +++ b/FireOpal/unit-tests/test-cases/cfstring-coalesce/bar.c @@ -0,0 +1,7 @@ +#include + + +void bar() +{ + CFStringGetLength(CFSTR("live")); +} diff --git a/FireOpal/unit-tests/test-cases/cfstring-coalesce/foo.c b/FireOpal/unit-tests/test-cases/cfstring-coalesce/foo.c new file mode 100644 index 0000000..fe1b30e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/cfstring-coalesce/foo.c @@ -0,0 +1,19 @@ +#include + +extern void bar(); + +void foo() +{ + CFStringGetLength(CFSTR("hello")); + CFStringGetLength(CFSTR("world")); +} + + +int main() +{ + CFStringGetLength(CFSTR("live")); + bar(); + return 0; +} + + diff --git a/FireOpal/unit-tests/test-cases/cfstring-utf16/Makefile b/FireOpal/unit-tests/test-cases/cfstring-utf16/Makefile new file mode 100644 index 0000000..3375aae --- /dev/null +++ b/FireOpal/unit-tests/test-cases/cfstring-utf16/Makefile @@ -0,0 +1,50 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Test that utf16 cfstring literals are not coalesced. +# There is 3 CFSTR in foo.m and 1 CFSTR in bar.m +# After coalescing and dead stripping there should be only one CFSTR in the output +# + +ifeq (,${findstring 64,$(ARCH)}) + CFSTRING_SIZE = 48 +else + CFSTRING_SIZE = 96 +endif + USTRING_SIZE = 37 + + + +run: all + +all: + ${CC} ${CCFLAGS} foo.m bar.m -o foo -framework CoreFoundation -dead_strip + size -l foo | grep "__cfstring: ${CFSTRING_SIZE}" | ${FAIL_IF_EMPTY} + size -l foo | grep "__ustring: ${USTRING_SIZE}" | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} foo + +clean: + rm -rf foo diff --git a/FireOpal/unit-tests/test-cases/cfstring-utf16/bar.m b/FireOpal/unit-tests/test-cases/cfstring-utf16/bar.m new file mode 100644 index 0000000..bdf5168 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/cfstring-utf16/bar.m @@ -0,0 +1,7 @@ +#include + + +void bar() +{ + CFStringGetLength(CFSTR("über")); +} diff --git a/FireOpal/unit-tests/test-cases/cfstring-utf16/foo.m b/FireOpal/unit-tests/test-cases/cfstring-utf16/foo.m new file mode 100644 index 0000000..6e4c268 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/cfstring-utf16/foo.m @@ -0,0 +1,20 @@ +#include + +extern void bar(); + +void foo() +{ + CFStringGetLength(CFSTR("hello")); + CFStringGetLength(CFSTR("überhund")); +} + + +int main() +{ + CFStringGetLength(CFSTR("über")); + CFStringGetLength(CFSTR("überhund")); + bar(); + return 0; +} + + diff --git a/FireOpal/unit-tests/test-cases/commons-alignment/Makefile b/FireOpal/unit-tests/test-cases/commons-alignment/Makefile new file mode 100644 index 0000000..d073c0e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-alignment/Makefile @@ -0,0 +1,37 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Validate linker preserves commons with custom alignment +# + +all: + ${CC} ${CCFLAGS} foo.s -c -o foo.o + nm -m foo.o | grep '(alignment 2^6)' | ${FAIL_IF_EMPTY} + ${LD} foo.o -r -o foo2.o + nm -m foo2.o | grep '(alignment 2^6)' | ${PASS_IFF_STDIN} + +clean: + rm -rf foo.o foo2.o diff --git a/FireOpal/unit-tests/test-cases/commons-alignment/foo.s b/FireOpal/unit-tests/test-cases/commons-alignment/foo.s new file mode 100644 index 0000000..03c28fc --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-alignment/foo.s @@ -0,0 +1,2 @@ + + .comm _mycomm64aligned,15,6 diff --git a/FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/Makefile b/FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/Makefile new file mode 100644 index 0000000..5823a61 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/Makefile @@ -0,0 +1,42 @@ +## +# Copyright (c) 2007 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 + + +# +# The point of this test is to verify if a header file is missing an extern that there won't be +# duplicates definitions when using -dead_strip. +# + +run: all + +all: + ${CC} ${CCFLAGS} a.c -c -o a.o + ${CC} ${CCFLAGS} b.c -c -o b.o + ${CC} ${CCFLAGS} c.c -c -o c.o + ${CC} -arch ${ARCH} -dynamiclib a.o b.o c.o -o libabc.dylib -dead_strip + ${PASS_IFF_GOOD_MACHO} libabc.dylib + +clean: + rm -rf a.o b.o c.o libabc.dylib one abc.bar.count diff --git a/FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/a.c b/FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/a.c new file mode 100644 index 0000000..fea7234 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/a.c @@ -0,0 +1,4 @@ +#include "c.h" + +float aa() { return bar; } + diff --git a/FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/b.c b/FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/b.c new file mode 100644 index 0000000..12e46e8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/b.c @@ -0,0 +1,4 @@ +#include "c.h" + +float bb() { return bar; } + diff --git a/FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/c.c b/FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/c.c new file mode 100644 index 0000000..165d5e4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/c.c @@ -0,0 +1,3 @@ + +const float bar = 1.0; + diff --git a/FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/c.h b/FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/c.h new file mode 100644 index 0000000..86a61ae --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-coalesced-dead_strip/c.h @@ -0,0 +1,4 @@ + +// missing extern +const float bar; + diff --git a/FireOpal/unit-tests/test-cases/commons-mixed/Makefile b/FireOpal/unit-tests/test-cases/commons-mixed/Makefile new file mode 100644 index 0000000..a59a858 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-mixed/Makefile @@ -0,0 +1,46 @@ +## +# Copyright (c) 2006 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 + + +# +# The point of this test is to verify a .o built with +# commons and one built without commons can be merged. +# +# problem merging .o files built with and without -fno-common +# + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -c -o foo.${ARCH}.o + ${FAIL_IF_BAD_OBJ} foo.${ARCH}.o + ${CC} ${CCFLAGS} bar.c -c -fno-common -o bar.${ARCH}.o + ${FAIL_IF_BAD_OBJ} bar.${ARCH}.o + ${LD} -arch ${ARCH} -r -keep_private_externs foo.${ARCH}.o bar.${ARCH}.o -o foobar.${ARCH}.o + ${FAIL_IF_BAD_OBJ} foobar.${ARCH}.o + nm -m foobar.${ARCH}.o | grep bar | grep __common | ${PASS_IFF_STDIN} + +clean: + rm -rf *.o diff --git a/FireOpal/unit-tests/test-cases/commons-mixed/bar.c b/FireOpal/unit-tests/test-cases/commons-mixed/bar.c new file mode 100644 index 0000000..771802c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-mixed/bar.c @@ -0,0 +1,2 @@ + +int bar; diff --git a/FireOpal/unit-tests/test-cases/commons-mixed/foo.c b/FireOpal/unit-tests/test-cases/commons-mixed/foo.c new file mode 100644 index 0000000..42e0a8e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-mixed/foo.c @@ -0,0 +1,2 @@ + +int foo; diff --git a/FireOpal/unit-tests/test-cases/commons-order/Makefile b/FireOpal/unit-tests/test-cases/commons-order/Makefile new file mode 100644 index 0000000..68d809c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-order/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Validate linker puts commons in the correct order. +# -fno-commons come first, followed by all other commons +# in .o order and alphabetically within each .o +# + +all: + ${CC} ${CCFLAGS} baz.c -fno-common -c -o baz.o + ${CC} ${CCFLAGS} main.c foo.c bar.c baz.o -o main -mmacosx-version-min=10.5 + nm -j -n main | grep _common > symbol.order + ${FAIL_IF_ERROR} diff symbol.order expected.order + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf main baz.o symbol.order diff --git a/FireOpal/unit-tests/test-cases/commons-order/bar.c b/FireOpal/unit-tests/test-cases/commons-order/bar.c new file mode 100644 index 0000000..2d258fc --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-order/bar.c @@ -0,0 +1,3 @@ +int ddd_common; +int iii_common[4]; +int bbb_common[4]; diff --git a/FireOpal/unit-tests/test-cases/commons-order/baz.c b/FireOpal/unit-tests/test-cases/commons-order/baz.c new file mode 100644 index 0000000..6497d29 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-order/baz.c @@ -0,0 +1,3 @@ +int fff_common; +int iii_common[4]; +int ttt_common; diff --git a/FireOpal/unit-tests/test-cases/commons-order/expected.order b/FireOpal/unit-tests/test-cases/commons-order/expected.order new file mode 100644 index 0000000..4738fc2 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-order/expected.order @@ -0,0 +1,8 @@ +_fff_common +_iii_common +_ttt_common +_aaa_common +_eee_common +_ggg_common +_bbb_common +_ddd_common diff --git a/FireOpal/unit-tests/test-cases/commons-order/foo.c b/FireOpal/unit-tests/test-cases/commons-order/foo.c new file mode 100644 index 0000000..ca80a59 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-order/foo.c @@ -0,0 +1,3 @@ +int aaa_common; +int ggg_common[4]; +int eee_common; diff --git a/FireOpal/unit-tests/test-cases/commons-order/main.c b/FireOpal/unit-tests/test-cases/commons-order/main.c new file mode 100644 index 0000000..df77448 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/commons-order/main.c @@ -0,0 +1,4 @@ + + +int main() { return 0; } + diff --git a/FireOpal/unit-tests/test-cases/cpu-sub-types-preference/Makefile b/FireOpal/unit-tests/test-cases/cpu-sub-types-preference/Makefile new file mode 100644 index 0000000..7586a51 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/cpu-sub-types-preference/Makefile @@ -0,0 +1,96 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Validate cpu subtype preference +# + +test: test-${ARCH} + +test-ppc64: + ${PASS_IFF} true + +test-i386: + ${PASS_IFF} true + +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 + + # check -arch armv4t pulls out V4 slice + ${LD} -r -arch armv4t foo.o -o fooa.o + otool -hv fooa.o | grep V4T | ${FAIL_IF_EMPTY} + nm fooa.o | grep _aaa | ${FAIL_IF_EMPTY} + + # check -arch armv5 pulls out V5 slice + ${LD} -r -arch armv5 foo.o -o foob.o + otool -hv foob.o | grep V5 | ${FAIL_IF_EMPTY} + nm foob.o | grep _bbb | ${FAIL_IF_EMPTY} + + # check -arch armv6 pulls out V6 slice + ${LD} -r -arch armv6 foo.o -o fooc.o + 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} + + ${PASS_IFF} true + + +test-ppc: + gcc foo.c -arch ppc750 -c -DAAA=1 -o foog3.o + gcc foo.c -arch ppc7400 -c -DBBB=1 -o foog4.o + gcc foo.c -arch ppc970 -c -DCCC=1 -o foog5.o + lipo foog3.o foog4.o foog5.o -create -output foo.o + + # check -arch ppc750 pulls out g3 slice + ${LD} -r -arch ppc750 foo.o -o fooa.o + otool -hv fooa.o | grep ppc750 | ${FAIL_IF_EMPTY} + nm fooa.o | grep _aaa | ${FAIL_IF_EMPTY} + + # check -arch ppc7400 pulls out g4 slice + ${LD} -r -arch ppc7400 foo.o -o foob.o + otool -hv foob.o | grep ppc7400 | ${FAIL_IF_EMPTY} + nm foob.o | grep _bbb | ${FAIL_IF_EMPTY} + + # check -arch ppc970 pulls out g5 slice + ${LD} -r -arch ppc970 foo.o -o fooc.o + otool -hv fooc.o | grep ppc970 | ${FAIL_IF_EMPTY} + nm fooc.o | grep _ccc | ${FAIL_IF_EMPTY} + + ${PASS_IFF} true + + +clean: + rm -f *.o diff --git a/FireOpal/unit-tests/test-cases/cpu-sub-types-preference/foo.c b/FireOpal/unit-tests/test-cases/cpu-sub-types-preference/foo.c new file mode 100644 index 0000000..983ed81 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/cpu-sub-types-preference/foo.c @@ -0,0 +1,25 @@ + + +#if AAA + void aaa() {} +#endif + +#if BBB + void bbb() {} +#endif + +#if CCC + void ccc() {} +#endif + +#if DDD + void ddd() {} +#endif + +#if EEE + void eee() {} +#endif + +#if FFFF + void fff() {} +#endif diff --git a/FireOpal/unit-tests/test-cases/cpu-sub-types/Makefile b/FireOpal/unit-tests/test-cases/cpu-sub-types/Makefile new file mode 100644 index 0000000..695ffba --- /dev/null +++ b/FireOpal/unit-tests/test-cases/cpu-sub-types/Makefile @@ -0,0 +1,157 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Validate cpu subtypes processing +# + +test: test-${ARCH} + +test-ppc64: + ${PASS_IFF} true + +test-i386: + ${PASS_IFF} true + +test-x86_64: + ${PASS_IFF} true + +test-armv6: + gcc 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 + ${FAIL_IF_BAD_OBJ} foo-v5.o + gcc 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 + ${FAIL_IF_BAD_OBJ} foo-xscale.o + gcc 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 + ${FAIL_IF_BAD_OBJ} main-v5.o + gcc 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 + ${FAIL_IF_BAD_OBJ} main-xscale.o + + # check V4+V4 -> V4 + ${LD} -r main-v4.o foo-v4.o -o all.o + ${FAIL_IF_BAD_OBJ} all.o + 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} + + # 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} + + # 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} + + # check V5+V5 -> V5 + ${LD} -r main-v5.o foo-v5.o -o all.o + ${FAIL_IF_BAD_OBJ} all.o + 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} + + # 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} + + # 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 + ${FAIL_IF_BAD_OBJ} all.o + otool -hv all.o | grep XSCALE | ${FAIL_IF_EMPTY} + + ${PASS_IFF} true + + +test-ppc: + gcc foo.c -arch ppc -mmacosx-version-min=10.4 -c -o foo.o + ${FAIL_IF_BAD_OBJ} foo.o + gcc foo.c -arch ppc750 -c -o foo-G3.o + ${FAIL_IF_BAD_OBJ} foo-G3.o + gcc foo.c -arch ppc7400 -c -o foo-G4.o + ${FAIL_IF_BAD_OBJ} foo-G4.o + gcc foo.c -arch ppc970 -c -o foo-G5.o + ${FAIL_IF_BAD_OBJ} foo-G5.o + gcc main.c -arch ppc -mmacosx-version-min=10.4 -c -o main.o + ${FAIL_IF_BAD_OBJ} main.o + gcc main.c -arch ppc970 -c -o main-G5.o + ${FAIL_IF_BAD_OBJ} main-G5.o + + # check ALL+ALL -> ALL + ${LD} -r main.o foo.o -o main-r.o + ${FAIL_IF_BAD_OBJ} main-r.o + otool -hv main-r.o | grep ALL | ${FAIL_IF_EMPTY} + + # check G3+ALL -> G3 + ${LD} -r main.o foo-G3.o -o main-r.o + ${FAIL_IF_BAD_OBJ} main-r.o + otool -hv main-r.o | grep ppc750 | ${FAIL_IF_EMPTY} + + # check G4+ALL -> G4 + ${LD} -r main.o foo-G4.o -o main-r.o + ${FAIL_IF_BAD_OBJ} main-r.o + otool -hv main-r.o | grep ppc7400 | ${FAIL_IF_EMPTY} + + # check G5+ALL -> G5 + ${LD} -r main.o foo-G5.o -o main-r.o + ${FAIL_IF_BAD_OBJ} main-r.o + otool -hv main-r.o | grep ppc970 | ${FAIL_IF_EMPTY} + + # check G5+G4 -> G5 + ${LD} -r main-G5.o foo-G4.o -o main-r.o + ${FAIL_IF_BAD_OBJ} main-r.o + otool -hv main-r.o | grep ppc970 | ${FAIL_IF_EMPTY} + + # check G4+G5 -> G5 + ${LD} -r foo-G4.o main-G5.o -o main-r.o + ${FAIL_IF_BAD_OBJ} main-r.o + otool -hv main-r.o | grep ppc970 | ${FAIL_IF_EMPTY} + + # check -force_cpusubtype_ALL + ${LD} -r main.o foo-G5.o -o main-r.o -force_cpusubtype_ALL + ${FAIL_IF_BAD_OBJ} main-r.o + otool -hv main-r.o | grep ALL | ${PASS_IFF_STDIN} + +clean: + rm -f *.o diff --git a/FireOpal/unit-tests/test-cases/cpu-sub-types/comment.txt b/FireOpal/unit-tests/test-cases/cpu-sub-types/comment.txt new file mode 100644 index 0000000..5e47ece --- /dev/null +++ b/FireOpal/unit-tests/test-cases/cpu-sub-types/comment.txt @@ -0,0 +1,2 @@ +The point of this test is validate cpu subtypes processsing for PowerPC + diff --git a/FireOpal/unit-tests/test-cases/cpu-sub-types/foo.c b/FireOpal/unit-tests/test-cases/cpu-sub-types/foo.c new file mode 100644 index 0000000..3695dc9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/cpu-sub-types/foo.c @@ -0,0 +1,3 @@ +void foo() +{ +} diff --git a/FireOpal/unit-tests/test-cases/cpu-sub-types/main.c b/FireOpal/unit-tests/test-cases/cpu-sub-types/main.c new file mode 100644 index 0000000..b48076d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/cpu-sub-types/main.c @@ -0,0 +1,10 @@ +#include + +extern void foo(); +extern void bar(); + +int main() +{ + foo(); + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/dead_strip-archive-global/Makefile b/FireOpal/unit-tests/test-cases/dead_strip-archive-global/Makefile new file mode 100644 index 0000000..ef985b7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip-archive-global/Makefile @@ -0,0 +1,43 @@ +## +# Copyright (c) 2006 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 + +# +# Tests that a global symbol in an archive will stil be exported (and not dead stripped). +# + +run: all + +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 -dynamiclib -Os libfoo.a -dead_strip -o libmain.dylib + nm libmain.dylib | grep _bar | ${FAIL_IF_EMPTY} + nm libmain.dylib | grep _baz | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} libmain.dylib + + +clean: + rm -rf *.dylib *.a *.o diff --git a/FireOpal/unit-tests/test-cases/dead_strip-archive-global/foo.c b/FireOpal/unit-tests/test-cases/dead_strip-archive-global/foo.c new file mode 100644 index 0000000..41478e8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip-archive-global/foo.c @@ -0,0 +1,12 @@ + +static int foo_count = 0; +static int bar_count = 0; +static int baz_count = 0; + + +void foo() { ++foo_count; } + +void bar() { ++bar_count; } + +void __attribute__((visibility("hidden"))) + baz() { ++baz_count; } diff --git a/FireOpal/unit-tests/test-cases/dead_strip-archive-global/main.c b/FireOpal/unit-tests/test-cases/dead_strip-archive-global/main.c new file mode 100644 index 0000000..da2b2fd --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip-archive-global/main.c @@ -0,0 +1,33 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + +extern void foo(); + +int main() +{ + foo(); + return 0; +} + + diff --git a/FireOpal/unit-tests/test-cases/dead_strip-archive/Makefile b/FireOpal/unit-tests/test-cases/dead_strip-archive/Makefile new file mode 100644 index 0000000..1542d78 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip-archive/Makefile @@ -0,0 +1,43 @@ +## +# Copyright (c) 2006 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 + +# +# Tests that a common symbol can be used from an archive with -dead_strip. The tricky +# part is that common symbols are not in the table of contents for archives. +# If the linker seens a need for my_common, that won't trigger pulling in the .o +# file from the archive. But the later use of foo will. +# + +run: all + +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 + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf main *.a *.o diff --git a/FireOpal/unit-tests/test-cases/dead_strip-archive/comment.txt b/FireOpal/unit-tests/test-cases/dead_strip-archive/comment.txt new file mode 100644 index 0000000..8dde1c5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip-archive/comment.txt @@ -0,0 +1 @@ +The point of this test that -dead_strip removes unreference code/data from archives diff --git a/FireOpal/unit-tests/test-cases/dead_strip-archive/foo.c b/FireOpal/unit-tests/test-cases/dead_strip-archive/foo.c new file mode 100644 index 0000000..be1b438 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip-archive/foo.c @@ -0,0 +1,7 @@ + + +void foo() {} + + +int my_common; + diff --git a/FireOpal/unit-tests/test-cases/dead_strip-archive/main.c b/FireOpal/unit-tests/test-cases/dead_strip-archive/main.c new file mode 100644 index 0000000..f6a7d5a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip-archive/main.c @@ -0,0 +1,37 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + +extern void foo(); +extern int my_common; + +int main() +{ + // the reference to the common symbol has to be first + my_common += 1; + // refrence to foo is next + foo(); + return 0; +} + + diff --git a/FireOpal/unit-tests/test-cases/dead_strip-init-archive/Makefile b/FireOpal/unit-tests/test-cases/dead_strip-init-archive/Makefile new file mode 100644 index 0000000..4b4f912 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip-init-archive/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2007 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 + +# +# Tests that a -init function can be pulled from an archive when using -dead_strip. +# + +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 -dynamiclib -Os libfoo.a -dead_strip -o libbar.dylib -init _foo + ${PASS_IFF_GOOD_MACHO} libbar.dylib + +clean: + rm -rf libbar.dylib libfoo.a foo.o + diff --git a/FireOpal/unit-tests/test-cases/dead_strip-init-archive/bar.c b/FireOpal/unit-tests/test-cases/dead_strip-init-archive/bar.c new file mode 100644 index 0000000..b348aa8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip-init-archive/bar.c @@ -0,0 +1,4 @@ + +void bar() {} + + diff --git a/FireOpal/unit-tests/test-cases/dead_strip-init-archive/foo.c b/FireOpal/unit-tests/test-cases/dead_strip-init-archive/foo.c new file mode 100644 index 0000000..95ec91c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip-init-archive/foo.c @@ -0,0 +1,6 @@ + + +void foo() {} + + + diff --git a/FireOpal/unit-tests/test-cases/dead_strip/Makefile b/FireOpal/unit-tests/test-cases/dead_strip/Makefile new file mode 100644 index 0000000..32ac1c5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip/Makefile @@ -0,0 +1,49 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check -dead_strip +# +# 1) in a main executable, dead globals are removed +# 2) in a dylib/bundle with -exported_symbols_list, dead globals are removed +# 3) in a dylib/bundle without -exported_symbols_list, dead globals are *not* removed +# + +run: all + +all: + ${CC} ${CCFLAGS} main.c deadwood.c -dead_strip -o main-${ARCH} + ${FAIL_IF_BAD_MACHO} main-${ARCH} + nm -j main-${ARCH} | egrep 'dead_wood|dead_door' | ${FAIL_IF_STDIN} + ${CC} ${CCFLAGS} -dynamiclib main.c deadwood.c -dead_strip -exported_symbols_list main.exp -o dylib-${ARCH} + ${FAIL_IF_BAD_MACHO} dylib-${ARCH} + nm -j dylib-${ARCH} | grep dead | ${FAIL_IF_STDIN} + ${CC} ${CCFLAGS} -dynamiclib main.c deadwood.c -dead_strip -o dylib2-${ARCH} + ${FAIL_IF_BAD_MACHO} dylib2-${ARCH} + nm -j dylib2-${ARCH} | grep dead_door_knob | ${FAIL_IF_EMPTY} + nm -j dylib2-${ARCH} | grep deadwood | ${PASS_IFF_EMPTY} + +clean: + rm -rf main-* dylib-* dylib2-* diff --git a/FireOpal/unit-tests/test-cases/dead_strip/comment.txt b/FireOpal/unit-tests/test-cases/dead_strip/comment.txt new file mode 100644 index 0000000..90a289c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip/comment.txt @@ -0,0 +1,5 @@ +The point of this test is a sanity check -dead_strip + +1) in a main executable, dead globals are removed +2) in a dylib/bundle with -exported_symbols_list, dead globals are removed +3) in a dylib/bundle without -exported_symbols_list, dead globals are *not* removed diff --git a/FireOpal/unit-tests/test-cases/dead_strip/deadwood.c b/FireOpal/unit-tests/test-cases/dead_strip/deadwood.c new file mode 100644 index 0000000..176ec78 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip/deadwood.c @@ -0,0 +1,11 @@ + + +// deadwood() is local to its linkage unit and is unsed, +// so reference to undef() is ok + +extern void undef(); + +void dead_wood() __attribute__((visibility("hidden"))); +void dead_wood() { undef(); } + + diff --git a/FireOpal/unit-tests/test-cases/dead_strip/main.c b/FireOpal/unit-tests/test-cases/dead_strip/main.c new file mode 100644 index 0000000..029aed9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip/main.c @@ -0,0 +1,32 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + +int main() +{ + return 0; +} + + + +void dead_door_knob() { } diff --git a/FireOpal/unit-tests/test-cases/dead_strip/main.exp b/FireOpal/unit-tests/test-cases/dead_strip/main.exp new file mode 100644 index 0000000..4eb9e89 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip/main.exp @@ -0,0 +1 @@ +_main diff --git a/FireOpal/unit-tests/test-cases/dead_strip_dylibs/Makefile b/FireOpal/unit-tests/test-cases/dead_strip_dylibs/Makefile new file mode 100644 index 0000000..309655e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip_dylibs/Makefile @@ -0,0 +1,52 @@ +## +# Copyright (c) 2007 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 -dead_strip_dylibs +# + + +run: all + +all: + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib + ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib + ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib + ${CC} ${CCFLAGS} main.c libfoo.dylib libbar.dylib libbaz.dylib -o main + ${FAIL_IF_BAD_MACHO} main + otool -L main | grep libfoo.dylib | ${FAIL_IF_EMPTY} + otool -L main | grep libbar.dylib | ${FAIL_IF_EMPTY} + otool -L main | grep libbaz.dylib | ${FAIL_IF_EMPTY} + ${CC} ${CCFLAGS} main.c -DCALL_BAR libfoo.dylib libbar.dylib libbaz.dylib -o main -Wl,-dead_strip_dylibs + ${FAIL_IF_BAD_MACHO} main + otool -L main | grep libfoo.dylib | ${FAIL_IF_STDIN} + otool -L main | grep libbar.dylib | ${FAIL_IF_EMPTY} + otool -L main | grep libbaz.dylib | ${FAIL_IF_STDIN} + ${PASS_IFF} /usr/bin/true + + +clean: + + rm -rf libbar.dylib libfoo.dylib libbaz.dylib main diff --git a/FireOpal/unit-tests/test-cases/dead_strip_dylibs/bar.c b/FireOpal/unit-tests/test-cases/dead_strip_dylibs/bar.c new file mode 100644 index 0000000..9c18401 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip_dylibs/bar.c @@ -0,0 +1,5 @@ + +int bar (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/dead_strip_dylibs/baz.c b/FireOpal/unit-tests/test-cases/dead_strip_dylibs/baz.c new file mode 100644 index 0000000..af6a9f8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip_dylibs/baz.c @@ -0,0 +1,5 @@ + +int baz (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/dead_strip_dylibs/foo.c b/FireOpal/unit-tests/test-cases/dead_strip_dylibs/foo.c new file mode 100644 index 0000000..d0cdf47 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip_dylibs/foo.c @@ -0,0 +1,4 @@ +int foo (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/dead_strip_dylibs/main.c b/FireOpal/unit-tests/test-cases/dead_strip_dylibs/main.c new file mode 100644 index 0000000..2b85b0e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip_dylibs/main.c @@ -0,0 +1,10 @@ + +extern void bar(); + +int main() +{ +#if CALL_BAR + bar(); +#endif + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/dead_strip_section_attribute/Makefile b/FireOpal/unit-tests/test-cases/dead_strip_section_attribute/Makefile new file mode 100644 index 0000000..e6471f7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip_section_attribute/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2007 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 + +# +# The point of this test is to check that -dead_strip does not remove +# atoms in sections with the S_ATTR_NO_DEAD_STRIP bit set +# + +run: all + +all: + ${CC} ${CCFLAGS} main.c -dead_strip -o main-${ARCH} + ${FAIL_IF_BAD_MACHO} main-${ARCH} + nm -j main-${ARCH} | grep _bar | ${FAIL_IF_STDIN} + nm -j main-${ARCH} | grep _foo | ${PASS_IFF_STDIN} + +clean: + rm -rf main-* diff --git a/FireOpal/unit-tests/test-cases/dead_strip_section_attribute/comment.txt b/FireOpal/unit-tests/test-cases/dead_strip_section_attribute/comment.txt new file mode 100644 index 0000000..6ca56e4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip_section_attribute/comment.txt @@ -0,0 +1,2 @@ +The point of this test is to check that -dead_strip does not remove +atoms in sections with the S_ATTR_NO_DEAD_STRIP bit set diff --git a/FireOpal/unit-tests/test-cases/dead_strip_section_attribute/main.c b/FireOpal/unit-tests/test-cases/dead_strip_section_attribute/main.c new file mode 100644 index 0000000..5fc1fad --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dead_strip_section_attribute/main.c @@ -0,0 +1,42 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 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@ + */ + +int main() +{ + return 0; +} + + +// foo should not be dead stripped +void __attribute__ ((section ("__TEXT,__text_no_strip,regular,no_dead_strip"))) foo() +{ + +} + +// bar should be dead stripped +void __attribute__ ((section ("__DATA,__text2"))) bar() +{ + +} + diff --git a/FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/Makefile b/FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/Makefile new file mode 100644 index 0000000..533169f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/Makefile @@ -0,0 +1,59 @@ +## +# Copyright (c) 2007 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 C++ coalescing throws away static probes associated +# with weak functions that are coalesced away. +# Build two programs that both should have the same number of probes +# and hence the same DOF section size +# + +all: simp coal + otool -lv coal | grep -A3 __dof_Number | grep size > coal-dof-size + otool -lv simp | grep -A3 __dof_Number | grep size > simp-dof-size + ${PASS_IFF_SUCCESS} diff coal-dof-size simp-dof-size + +Number.h: Number.d + dtrace -h -s Number.d + +a.o : a.cxx Number.h header.h + ${CXX} ${CXXFLAGS} -c -DFUNC=a a.cxx -o a.o + +b.o : a.cxx Number.h header.h + ${CXX} ${CXXFLAGS} -c -DFUNC=b a.cxx -o b.o + +c.o : a.cxx Number.h header.h + ${CXX} ${CXXFLAGS} -c -DFUNC=c a.cxx -o c.o + +coal : a.o b.o c.o + ${CXX} -dynamiclib a.o b.o c.o -o coal + +simp : x.cxx Number.h + ${CXX} -dynamiclib x.cxx -o simp + + + +clean: + rm -rf coal simp a.o b.o c.o Number.h coal-dof-size simp-dof-size diff --git a/FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/Number.d b/FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/Number.d new file mode 100644 index 0000000..9383fe4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/Number.d @@ -0,0 +1,3 @@ +provider Number { + probe hit(int value); +}; diff --git a/FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/a.cxx b/FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/a.cxx new file mode 100644 index 0000000..8e7e3c6 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/a.cxx @@ -0,0 +1,8 @@ + +#include + +#include "header.h" + + +void FUNC() { foo(); } + diff --git a/FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/header.h b/FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/header.h new file mode 100644 index 0000000..162419b --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/header.h @@ -0,0 +1,11 @@ + +#include "Number.h" + +#define LOTS_O_PROBES { NUMBER_HIT(1); NUMBER_HIT(2); NUMBER_HIT(3); NUMBER_HIT(4); } + + +inline void foo() { + LOTS_O_PROBES +} + + diff --git a/FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/x.cxx b/FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/x.cxx new file mode 100644 index 0000000..b756394 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dtrace-static-probes-coalescing/x.cxx @@ -0,0 +1,6 @@ + +#include "header.h" + +void f() { LOTS_O_PROBES } + + diff --git a/FireOpal/unit-tests/test-cases/dtrace-static-probes/Makefile b/FireOpal/unit-tests/test-cases/dtrace-static-probes/Makefile new file mode 100644 index 0000000..b59760f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dtrace-static-probes/Makefile @@ -0,0 +1,60 @@ +## +# Copyright (c) 2007 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 + +# +# The point of this test is a sanity check that ld +# can link a progam with dtrace static probes +# + +all: run + +run: main main-r main-dead_strip libmain.dylib + ${FAIL_IF_BAD_MACHO} main + ${PASS_IFF_GOOD_MACHO} main-r + +main: main.c foo.h bar.h + ${CC} ${CCFLAGS} main.c -o main + +main-dead_strip: main.c foo.h bar.h + ${CC} ${CCFLAGS} main.c -o main-dead_strip -dead_strip + +main-r: main.c foo.h bar.h + ${CC} ${CCFLAGS} main.c -c -o main.o + #${FAIL_IF_BAD_OBJ} main.o + ${LD} -r main.o -o main-r.o + #${FAIL_IF_BAD_OBJ} main-r.o + ${CC} ${CCFLAGS} main-r.o -o main-r + +libmain.dylib: main.c foo.h bar.h + ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain.dylib + +foo.h: foo.d + dtrace -h -s foo.d + +bar.h: bar.d + dtrace -h -s bar.d + +clean: + rm -rf main libmain.dylib main-r main-dead_strip foo.h bar.h *.o diff --git a/FireOpal/unit-tests/test-cases/dtrace-static-probes/bar.d b/FireOpal/unit-tests/test-cases/dtrace-static-probes/bar.d new file mode 100644 index 0000000..fab36ea --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dtrace-static-probes/bar.d @@ -0,0 +1,7 @@ +typedef int weirdType; + +provider Bar { + probe count1(weirdType); +}; + +#pragma D attributes Evolving/Evolving/Common provider Bar args diff --git a/FireOpal/unit-tests/test-cases/dtrace-static-probes/comment.txt b/FireOpal/unit-tests/test-cases/dtrace-static-probes/comment.txt new file mode 100644 index 0000000..b02ac8b --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dtrace-static-probes/comment.txt @@ -0,0 +1 @@ +The point of this test is a sanity check that ld can link a progam with dtrace static probes diff --git a/FireOpal/unit-tests/test-cases/dtrace-static-probes/foo.d b/FireOpal/unit-tests/test-cases/dtrace-static-probes/foo.d new file mode 100644 index 0000000..03f1a19 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dtrace-static-probes/foo.d @@ -0,0 +1,8 @@ +typedef int weirdType2; + +provider Foo { + probe count1(weirdType2); +}; + + +#pragma D attributes Evolving/Evolving/Common provider Foo args diff --git a/FireOpal/unit-tests/test-cases/dtrace-static-probes/main.c b/FireOpal/unit-tests/test-cases/dtrace-static-probes/main.c new file mode 100644 index 0000000..8a417e9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dtrace-static-probes/main.c @@ -0,0 +1,29 @@ + +#include + +typedef int weirdType; +typedef int weirdType2; + +#include "foo.h" +#include "bar.h" + + +int deadwood() +{ + BAR_COUNT1(2); + return 0; +} + + +int main() { + int a = 1; + + while(a) { + FOO_COUNT1(1); + printf("test\n"); + BAR_COUNT1(2); + sleep(1); + } + + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/Makefile b/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/Makefile new file mode 100644 index 0000000..8d38d99 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/Makefile @@ -0,0 +1,45 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Test that using -all_load to pull all .o files out of an archive +# proeduces good "debug notes". +# + +run: + ${CC} ${CCFLAGS} -gdwarf-2 foo.c -c -o foo.o + ${FAIL_IF_BAD_OBJ} foo.o + ${CC} ${CCFLAGS} -gdwarf-2 bar.c -c -o bar.o + ${FAIL_IF_BAD_OBJ} bar.o + ${CC} ${CCFLAGS} -gdwarf-2 baz.c -c -o baz.o + ${FAIL_IF_BAD_OBJ} baz.o + libtool -static bar.o baz.o foo.o -o liball.a + ${CC} ${CCFLAGS} liball.a -all_load -dynamiclib -o liball.dylib -nodefaultlibs + ${FAIL_IF_BAD_MACHO} liball.dylib + nm -fap liball.dylib | ./stabs-filter.pl > liball.dylib.stabs + ${PASS_IFF} diff liball.dylib.stabs expected-stabs + +clean: + rm -rf *.o liball.a liball.dylib liball.dylib.stabs diff --git a/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/bar.c b/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/bar.c new file mode 100644 index 0000000..06752f3 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/bar.c @@ -0,0 +1,2 @@ +void bar() {} + diff --git a/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/baz.c b/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/baz.c new file mode 100644 index 0000000..256a0e3 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/baz.c @@ -0,0 +1 @@ +void baz() {} diff --git a/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/comment.txt b/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/comment.txt new file mode 100644 index 0000000..6992acd --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/comment.txt @@ -0,0 +1,2 @@ +Test that using -all_load to pull all .o files out of an archive +proeduces good "debug notes". diff --git a/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/expected-stabs b/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/expected-stabs new file mode 100644 index 0000000..0071455 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/expected-stabs @@ -0,0 +1,24 @@ +0000 SO CWD/ +0000 SO bar.c +0001 OSO CWD/liball.a(bar.o) +0000 BNSYM +0000 FUN _bar +0000 FUN +0000 ENSYM +0000 SO +0000 SO CWD/ +0000 SO baz.c +0001 OSO CWD/liball.a(baz.o) +0000 BNSYM +0000 FUN _baz +0000 FUN +0000 ENSYM +0000 SO +0000 SO CWD/ +0000 SO foo.c +0001 OSO CWD/liball.a(foo.o) +0000 BNSYM +0000 FUN _foo +0000 FUN +0000 ENSYM +0000 SO diff --git a/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/foo.c b/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/foo.c new file mode 100644 index 0000000..85e6cd8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/foo.c @@ -0,0 +1 @@ +void foo() {} diff --git a/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/stabs-filter.pl b/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/stabs-filter.pl new file mode 100755 index 0000000..706fd12 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-archive-all_load/stabs-filter.pl @@ -0,0 +1,25 @@ +#!/usr/bin/perl + +use strict; +use Cwd; + +my $dir = getcwd; +#my $xxx = $ARGV[1]; + +while(<>) +{ + # get stabs lines that match "NNNNNNN - xxx" + if(m/^([0-9a-f]+) - ([0-9a-f]+) (.*?)$/) + { + # replace any occurances of cwd path with $CWD + my $line = $3; + if($line =~ m/(.*?)$dir(.*?)$/) + { + $line = $1 . "CWD" . $2; + } + + printf "$line\n"; + } +} + + diff --git a/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/Makefile b/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/Makefile new file mode 100644 index 0000000..1eb6310 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/Makefile @@ -0,0 +1,59 @@ +## +# 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 + +# +# The point of this test is a sanity check that ld +# produces good "debug notes" stabs from dwarf .o files after +# some of the .o files are merged with ld -r. +# Running nm through stabs-filter.pl produces connonical stabs +# that can be diffed against a checked in know good set of stabs +# + +run: all + +all: foobar.o main.o + ${CXX} ${CCXXFLAGS} foobar.o main.o -o dwarf-test-${ARCH} + ${FAIL_IF_BAD_MACHO} dwarf-test-${ARCH} + nm -ap dwarf-test-${ARCH} | ./stabs-filter.pl > dwarf-test-${ARCH}.stabs + ${PASS_IFF} diff dwarf-test-${ARCH}.stabs expected-stabs + +foobar.o : foo.o bar.o + ${LD} -r -arch ${ARCH} foo.o bar.o -o foobar.o + ${FAIL_IF_BAD_OBJ} foobar.o + +foo.o : foo.cxx + ${CXX} ${CCXXFLAGS} -gdwarf-2 foo.cxx -c -o $@ -mdynamic-no-pic + ${FAIL_IF_BAD_OBJ} $@ + +bar.o : bar.cxx + ${CXX} ${CCXXFLAGS} -gdwarf-2 bar.cxx -c -o $@ -mdynamic-no-pic + ${FAIL_IF_BAD_OBJ} $@ + +main.o : main.cxx + ${CXX} ${CCXXFLAGS} -gdwarf-2 main.cxx -c -o $@ -mdynamic-no-pic + ${FAIL_IF_BAD_OBJ} $@ + +clean: + rm -rf dwarf-test-* *.o *.stabs diff --git a/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/bar.cxx b/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/bar.cxx new file mode 100644 index 0000000..c3f6a18 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/bar.cxx @@ -0,0 +1,4 @@ +int bar() +{ + return 10; +} diff --git a/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/comment.txt b/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/comment.txt new file mode 100644 index 0000000..0f1d0b1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/comment.txt @@ -0,0 +1,5 @@ +The point of this test is a sanity check that ld +produces good "debug notes" stabs from dwarf .o files after +some of the .o files are merged with ld -r. +Running nm through stabs-filter.pl produces connonical stabs +that can be diffed against a checked in know good set of stabs diff --git a/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/expected-stabs b/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/expected-stabs new file mode 100644 index 0000000..f8abc12 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/expected-stabs @@ -0,0 +1,24 @@ +0000 SO CWD/ +0000 SO main.cxx +0001 OSO CWD/main.o +0000 BNSYM +0000 FUN _main +0000 FUN +0000 ENSYM +0000 SO +0000 SO CWD/ +0000 SO foo.cxx +0001 OSO CWD/foo.o +0000 BNSYM +0000 FUN __Z3foov +0000 FUN +0000 ENSYM +0000 SO +0000 SO CWD/ +0000 SO bar.cxx +0001 OSO CWD/bar.o +0000 BNSYM +0000 FUN __Z3barv +0000 FUN +0000 ENSYM +0000 SO diff --git a/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/foo.cxx b/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/foo.cxx new file mode 100644 index 0000000..1f46ef4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/foo.cxx @@ -0,0 +1,4 @@ +int foo() +{ + return 10; +} diff --git a/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/main.cxx b/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/main.cxx new file mode 100644 index 0000000..f8b643a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/main.cxx @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/stabs-filter.pl b/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/stabs-filter.pl new file mode 100755 index 0000000..706fd12 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-debug-notes-r/stabs-filter.pl @@ -0,0 +1,25 @@ +#!/usr/bin/perl + +use strict; +use Cwd; + +my $dir = getcwd; +#my $xxx = $ARGV[1]; + +while(<>) +{ + # get stabs lines that match "NNNNNNN - xxx" + if(m/^([0-9a-f]+) - ([0-9a-f]+) (.*?)$/) + { + # replace any occurances of cwd path with $CWD + my $line = $3; + if($line =~ m/(.*?)$dir(.*?)$/) + { + $line = $1 . "CWD" . $2; + } + + printf "$line\n"; + } +} + + diff --git a/FireOpal/unit-tests/test-cases/dwarf-debug-notes/Makefile b/FireOpal/unit-tests/test-cases/dwarf-debug-notes/Makefile new file mode 100644 index 0000000..42f1cb7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-debug-notes/Makefile @@ -0,0 +1,50 @@ +## +# 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 + +# +# The point of this test is a sanity check that ld +# produces good "debug notes" stabs from dwarf .o files +# Running nm through stabs-filter.pl produces connonical stabs +# that can be diffed against a checked in know good set of stabs +# + +run: all + +all: hello.o other.o + ${CXX} ${CCXXFLAGS} -gdwarf-2 hello.o other.o -o dwarf-hello-${ARCH} + ${FAIL_IF_BAD_MACHO} dwarf-hello-${ARCH} + nm -ap dwarf-hello-${ARCH} | ./stabs-filter.pl > dwarf-hello-${ARCH}.stabs + ${PASS_IFF} diff dwarf-hello-${ARCH}.stabs expected-stabs + +hello.o : hello.cxx + ${CXX} ${CCXXFLAGS} -gdwarf-2 hello.cxx -c -o $@ -mdynamic-no-pic + ${FAIL_IF_BAD_OBJ} $@ + +other.o : other.cxx + ${CXX} ${CCXXFLAGS} -gdwarf-2 other.cxx -c -o $@ -mdynamic-no-pic + ${FAIL_IF_BAD_OBJ} $@ + +clean: + rm -rf dwarf-hello-* *.o *.stabs diff --git a/FireOpal/unit-tests/test-cases/dwarf-debug-notes/comment.txt b/FireOpal/unit-tests/test-cases/dwarf-debug-notes/comment.txt new file mode 100644 index 0000000..5caf129 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-debug-notes/comment.txt @@ -0,0 +1,4 @@ +The point of this test is a sanity check that ld +produces good "debug notes" stabs from dwarf .o files +Running nm through stabs-filter.pl produces connonical stabs +that can be diffed against a checked in know good set of stabs diff --git a/FireOpal/unit-tests/test-cases/dwarf-debug-notes/expected-stabs b/FireOpal/unit-tests/test-cases/dwarf-debug-notes/expected-stabs new file mode 100644 index 0000000..4ab634d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-debug-notes/expected-stabs @@ -0,0 +1,33 @@ +0000 SO CWD/ +0000 SO hello.cxx +0001 OSO CWD/hello.o +0000 BNSYM +0000 FUN _main +0000 FUN +0000 ENSYM +0000 BNSYM +0000 FUN __Z3fooi +0000 SOL header.h +0000 FUN +0000 ENSYM +0000 SO +0000 SO CWD/ +0000 SO other.cxx +0001 OSO CWD/other.o +0000 BNSYM +0000 FUN __Z3bari +0000 FUN +0000 ENSYM +0000 BNSYM +0000 FUN .my_non_standard_function_name +0000 FUN +0000 ENSYM +0000 GSYM _init +0000 STSYM .my_non_standard_name +0000 STSYM .my_non_standard_name_static +0000 STSYM __ZZ3bariE8bar_init +0000 GSYM _uninit +0000 STSYM _sinit +0000 STSYM _suninit +0000 STSYM __ZZ3bariE10bar_uninit +0000 SO diff --git a/FireOpal/unit-tests/test-cases/dwarf-debug-notes/header.h b/FireOpal/unit-tests/test-cases/dwarf-debug-notes/header.h new file mode 100644 index 0000000..aa960dd --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-debug-notes/header.h @@ -0,0 +1,8 @@ + + +inline int foo(int x) +{ + return x + 10; +} + +extern int bar(int x); \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/dwarf-debug-notes/hello.cxx b/FireOpal/unit-tests/test-cases/dwarf-debug-notes/hello.cxx new file mode 100644 index 0000000..0d508e1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-debug-notes/hello.cxx @@ -0,0 +1,33 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * 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@ + */ +#include + +#include "header.h" + + +int main() +{ + foo(bar(3)); + fprintf(stdout, "hello\n"); +} \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/dwarf-debug-notes/other.cxx b/FireOpal/unit-tests/test-cases/dwarf-debug-notes/other.cxx new file mode 100644 index 0000000..b1b0e77 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-debug-notes/other.cxx @@ -0,0 +1,27 @@ + +#include "header.h" + +int uninit; +int init = 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; + +int bar(int x) +{ + static int bar_uninit; + static int bar_init=3; + bar_uninit = x; + scustominit = x; + custom = x; + return 20 + suninit + sinit + + bar_init + bar_uninit + foo(x); +} + +extern void disappear() _asm("lbegone"); +void disappear() {} + +extern void foo() _asm(".my_non_standard_function_name"); +void foo() { disappear(); } + diff --git a/FireOpal/unit-tests/test-cases/dwarf-debug-notes/stabs-filter.pl b/FireOpal/unit-tests/test-cases/dwarf-debug-notes/stabs-filter.pl new file mode 100755 index 0000000..706fd12 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-debug-notes/stabs-filter.pl @@ -0,0 +1,25 @@ +#!/usr/bin/perl + +use strict; +use Cwd; + +my $dir = getcwd; +#my $xxx = $ARGV[1]; + +while(<>) +{ + # get stabs lines that match "NNNNNNN - xxx" + if(m/^([0-9a-f]+) - ([0-9a-f]+) (.*?)$/) + { + # replace any occurances of cwd path with $CWD + my $line = $3; + if($line =~ m/(.*?)$dir(.*?)$/) + { + $line = $1 . "CWD" . $2; + } + + printf "$line\n"; + } +} + + diff --git a/FireOpal/unit-tests/test-cases/dwarf-ignore/Makefile b/FireOpal/unit-tests/test-cases/dwarf-ignore/Makefile new file mode 100644 index 0000000..94b026c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-ignore/Makefile @@ -0,0 +1,39 @@ +## +# 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 + +# +# The point of this test is a sanity check that ld +# strips out the dwarf segment by default +# + +run: all + +all: + ${CC} ${CCFLAGS} -gdwarf-2 hello.c -o dwarf-hello-${ARCH} + ${FAIL_IF_BAD_MACHO} dwarf-hello-${ARCH} + size -l dwarf-hello-${ARCH} | grep __DWARF | ${PASS_IFF_EMPTY} + +clean: + rm -rf dwarf-hello-* diff --git a/FireOpal/unit-tests/test-cases/dwarf-ignore/comment.txt b/FireOpal/unit-tests/test-cases/dwarf-ignore/comment.txt new file mode 100644 index 0000000..06822b2 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-ignore/comment.txt @@ -0,0 +1 @@ +The point of this test is a sanity check that ld strips out the dwarf segment by default diff --git a/FireOpal/unit-tests/test-cases/dwarf-ignore/hello.c b/FireOpal/unit-tests/test-cases/dwarf-ignore/hello.c new file mode 100644 index 0000000..e2f0fe9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-ignore/hello.c @@ -0,0 +1,29 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * 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@ + */ +#include + +int main() +{ + fprintf(stdout, "hello\n"); +} \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/dwarf-strip/Makefile b/FireOpal/unit-tests/test-cases/dwarf-strip/Makefile new file mode 100644 index 0000000..947afa7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-strip/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that ld -S +# produces no debug notes (stabs) +# + +run: all + +all: + ${CC} ${CCFLAGS} -gdwarf-2 hello.c -Wl,-S -o dwarf-hello-${ARCH} + #${CC} ${CCFLAGS} -gdwarf-2 hello.c -o dwarf-hello-${ARCH} + ${FAIL_IF_BAD_MACHO} dwarf-hello-${ARCH} + nm -ap dwarf-hello-${ARCH} | grep -e " - " | ${PASS_IFF_EMPTY} + +clean: + rm -rf dwarf-hello-* diff --git a/FireOpal/unit-tests/test-cases/dwarf-strip/comment.txt b/FireOpal/unit-tests/test-cases/dwarf-strip/comment.txt new file mode 100644 index 0000000..5a23827 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-strip/comment.txt @@ -0,0 +1 @@ +The point of this test is a sanity check that ld -S produces no debug notes (stabs) diff --git a/FireOpal/unit-tests/test-cases/dwarf-strip/hello.c b/FireOpal/unit-tests/test-cases/dwarf-strip/hello.c new file mode 100644 index 0000000..ddca819 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dwarf-strip/hello.c @@ -0,0 +1,29 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +int main() +{ + fprintf(stdout, "hello\n"); +} \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/dylib-aliases/Makefile b/FireOpal/unit-tests/test-cases/dylib-aliases/Makefile new file mode 100644 index 0000000..1cf9fa0 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib-aliases/Makefile @@ -0,0 +1,47 @@ +## +# 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 + +# +# Test that libfoo.dylib can be aliases with a symlink or +# as another dylib and still link +# + +run: all + +all: libfoo.dylib libbar.dylib libbaz.dylib + ${CC} ${CCFLAGS} main.c -o main -lfoo -lbar -lbaz -L. + ${PASS_IFF_GOOD_MACHO} main + +libfoo.dylib : foo.c + ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib + +libbar.dylib : bar.c + ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib -install_name libfoo.dylib + +libbaz.dylib : libfoo.dylib + ln -s libfoo.dylib libbaz.dylib + +clean: + rm -rf *.dylib main diff --git a/FireOpal/unit-tests/test-cases/dylib-aliases/bar.c b/FireOpal/unit-tests/test-cases/dylib-aliases/bar.c new file mode 100644 index 0000000..981110f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib-aliases/bar.c @@ -0,0 +1 @@ +void bar() { } diff --git a/FireOpal/unit-tests/test-cases/dylib-aliases/foo.c b/FireOpal/unit-tests/test-cases/dylib-aliases/foo.c new file mode 100644 index 0000000..2fb55ee --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib-aliases/foo.c @@ -0,0 +1 @@ +void foo() { } diff --git a/FireOpal/unit-tests/test-cases/dylib-aliases/main.c b/FireOpal/unit-tests/test-cases/dylib-aliases/main.c new file mode 100644 index 0000000..03c4b39 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib-aliases/main.c @@ -0,0 +1,8 @@ +extern void foo(); +extern void bar(); + +int main() { + foo(); + bar(); + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/dylib-re-export-cycle/Makefile b/FireOpal/unit-tests/test-cases/dylib-re-export-cycle/Makefile new file mode 100644 index 0000000..617fbfc --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib-re-export-cycle/Makefile @@ -0,0 +1,52 @@ +## +# Copyright (c) 2007 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 that searches for indirect libraries does not cause a cycle +# OpenGL.framework and X11 both have a libGL.dylib which can cause ld to segfault if both are found +# + +run: all + +all: libfoo.dylib + ${CC} main.c libfoo.dylib -o main -L. 2>errmsg || true + grep "cycle" errmsg | ${PASS_IFF_STDIN} + +libfoo.dylib : foo.c libbar.dylib + ${CC} foo.c -dynamiclib -o libfoo.dylib libbar.dylib -sub_library libbar -mmacosx-version-min=10.4 + +libbar.dylib : bar.c other/libfoo.dylib + ${CC} bar.c -dynamiclib -o libbar.dylib other/libfoo.dylib -sub_library libfoo -mmacosx-version-min=10.4 + +other/libfoo.dylib : foo.c + mkdir -p other + ${CC} foo.c -dynamiclib -o other/libfoo.dylib -mmacosx-version-min=10.4 + + + +clean: + rm -rf other libfoo.dylib libbar.dylib main errmsg diff --git a/FireOpal/unit-tests/test-cases/dylib-re-export-cycle/bar.c b/FireOpal/unit-tests/test-cases/dylib-re-export-cycle/bar.c new file mode 100644 index 0000000..981110f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib-re-export-cycle/bar.c @@ -0,0 +1 @@ +void bar() { } diff --git a/FireOpal/unit-tests/test-cases/dylib-re-export-cycle/foo.c b/FireOpal/unit-tests/test-cases/dylib-re-export-cycle/foo.c new file mode 100644 index 0000000..2fb55ee --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib-re-export-cycle/foo.c @@ -0,0 +1 @@ +void foo() { } diff --git a/FireOpal/unit-tests/test-cases/dylib-re-export-cycle/main.c b/FireOpal/unit-tests/test-cases/dylib-re-export-cycle/main.c new file mode 100644 index 0000000..8273541 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib-re-export-cycle/main.c @@ -0,0 +1,6 @@ +extern void unfindable(); + +int main() { + unfindable(); + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/dylib_file-missing/Makefile b/FireOpal/unit-tests/test-cases/dylib_file-missing/Makefile new file mode 100644 index 0000000..f6371af --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib_file-missing/Makefile @@ -0,0 +1,42 @@ +## +# Copyright (c) 2007 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 + +PWD = $(shell pwd) +SHELL = bash # use bash shell so we can redirect just stderr + + +# Verify that if -dylib_file option points to a missing, file the link does not fail + +run: all + +all: + ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib -install_name "${PWD}/libbar.dylib" + ${CC} ${CCFLAGS} foo.c "${PWD}/libbar.dylib" -dynamiclib -o libfoo.dylib -sub_library libbar + ${CC} ${CCFLAGS} main.c libfoo.dylib -o main + ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -dylib_file "${PWD}/libbar.dylib:libbar2.dylib" 2>warnings.log + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf *.dylib main warnings.log diff --git a/FireOpal/unit-tests/test-cases/dylib_file-missing/bar.c b/FireOpal/unit-tests/test-cases/dylib_file-missing/bar.c new file mode 100644 index 0000000..2668f9a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib_file-missing/bar.c @@ -0,0 +1,13 @@ + + + +void bar() +{ +} + +#if BAR_EXTRA +void bar_extra() +{ +} +#endif + diff --git a/FireOpal/unit-tests/test-cases/dylib_file-missing/foo.c b/FireOpal/unit-tests/test-cases/dylib_file-missing/foo.c new file mode 100644 index 0000000..aa31241 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib_file-missing/foo.c @@ -0,0 +1,7 @@ + +extern void bar(); + +void foo() +{ + bar(); +} diff --git a/FireOpal/unit-tests/test-cases/dylib_file-missing/main.c b/FireOpal/unit-tests/test-cases/dylib_file-missing/main.c new file mode 100644 index 0000000..3f109f2 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib_file-missing/main.c @@ -0,0 +1,15 @@ + +extern void foo(); +extern void bar(); +extern void bar_extra(); + +int main() +{ + foo(); + bar(); +#if BAR_EXTRA + bar_extra(); +#endif + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/dylib_file/Makefile b/FireOpal/unit-tests/test-cases/dylib_file/Makefile new file mode 100644 index 0000000..181eee5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib_file/Makefile @@ -0,0 +1,46 @@ +## +# Copyright (c) 2007 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 + +PWD = $(shell pwd) +SHELL = bash # use bash shell so we can redirect just stderr + + +# Verify that -dylib_file option allows you to replace an indirect dylib + +run: all + +all: + ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib -install_name "${PWD}/libbar.dylib" + ${CC} ${CCFLAGS} bar.c -DBAR_EXTRA -dynamiclib -o libbar2.dylib -install_name "${PWD}/libbar.dylib" + ${CC} ${CCFLAGS} foo.c "${PWD}/libbar.dylib" -dynamiclib -o libfoo.dylib -sub_library libbar + ${CC} ${CCFLAGS} main.c libfoo.dylib -o main + # verify that if main needs bar_extra, it fails + ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -DBAR_EXTRA libfoo.dylib -o main 2> fail.log + # verify that if main needs bar_extra, it works with -dylib_file option + ${CC} ${CCFLAGS} main.c -DBAR_EXTRA libfoo.dylib -o main -dylib_file "${PWD}/libbar.dylib:libbar2.dylib" + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf *.dylib main fail.log diff --git a/FireOpal/unit-tests/test-cases/dylib_file/bar.c b/FireOpal/unit-tests/test-cases/dylib_file/bar.c new file mode 100644 index 0000000..2668f9a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib_file/bar.c @@ -0,0 +1,13 @@ + + + +void bar() +{ +} + +#if BAR_EXTRA +void bar_extra() +{ +} +#endif + diff --git a/FireOpal/unit-tests/test-cases/dylib_file/comment.txt b/FireOpal/unit-tests/test-cases/dylib_file/comment.txt new file mode 100644 index 0000000..e3bfbb7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib_file/comment.txt @@ -0,0 +1 @@ +Verify that -dylib_file option allows you to replace an indirect dylib diff --git a/FireOpal/unit-tests/test-cases/dylib_file/foo.c b/FireOpal/unit-tests/test-cases/dylib_file/foo.c new file mode 100644 index 0000000..aa31241 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib_file/foo.c @@ -0,0 +1,7 @@ + +extern void bar(); + +void foo() +{ + bar(); +} diff --git a/FireOpal/unit-tests/test-cases/dylib_file/main.c b/FireOpal/unit-tests/test-cases/dylib_file/main.c new file mode 100644 index 0000000..3f109f2 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib_file/main.c @@ -0,0 +1,15 @@ + +extern void foo(); +extern void bar(); +extern void bar_extra(); + +int main() +{ + foo(); + bar(); +#if BAR_EXTRA + bar_extra(); +#endif + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/dylib_init/Makefile b/FireOpal/unit-tests/test-cases/dylib_init/Makefile new file mode 100644 index 0000000..3ccbc85 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib_init/Makefile @@ -0,0 +1,36 @@ +## +# Copyright (c) 2005-2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# Verify -init option creates a LC_ROUTINES load command + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -init __init + otool -lv libfoo.dylib | grep LC_ROUTINES | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} libfoo.dylib + +clean: + rm -rf libfoo.dylib diff --git a/FireOpal/unit-tests/test-cases/dylib_init/foo.c b/FireOpal/unit-tests/test-cases/dylib_init/foo.c new file mode 100644 index 0000000..9ba156e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/dylib_init/foo.c @@ -0,0 +1,2 @@ +void _init() { +} diff --git a/FireOpal/unit-tests/test-cases/eh-coalescing-r/Makefile b/FireOpal/unit-tests/test-cases/eh-coalescing-r/Makefile new file mode 100644 index 0000000..3fb8a25 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/eh-coalescing-r/Makefile @@ -0,0 +1,47 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + + +SHELL = bash # use bash shell so we can redirect just stderr + + +# +# +# comdat warnings in ld -r +# +# also use -falign-functions to force an out of order coalesing +# +run: all + +all: + ${CXX} ${CCXXFLAGS} foo.cxx -c -o foo.o + ${CXX} ${CCXXFLAGS} bar.cxx -c -o bar.o -falign-functions=32 + ${CXX} ${CCXXFLAGS} baz.cxx -c -o baz.o + ${LD} -r foo.o bar.o baz.o -o foobarbaz.o 2> warnings.log + grep warning warnings.log | ${PASS_IFF_EMPTY} + + +clean: + rm foo.o bar.o baz.o foobarbaz.o warnings.log diff --git a/FireOpal/unit-tests/test-cases/eh-coalescing-r/bar.cxx b/FireOpal/unit-tests/test-cases/eh-coalescing-r/bar.cxx new file mode 100644 index 0000000..b48923c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/eh-coalescing-r/bar.cxx @@ -0,0 +1,32 @@ +/* -*- 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@ + */ +#include +#include "func.h" + +void bar() +{ + func(); +} + + diff --git a/FireOpal/unit-tests/test-cases/eh-coalescing-r/foo.cxx b/FireOpal/unit-tests/test-cases/eh-coalescing-r/foo.cxx new file mode 100644 index 0000000..0a8d99a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/eh-coalescing-r/foo.cxx @@ -0,0 +1,32 @@ +/* -*- 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@ + */ +#include + +#include "func.h" + + +void test() +{ + func(); +} diff --git a/FireOpal/unit-tests/test-cases/eh-coalescing-r/func.h b/FireOpal/unit-tests/test-cases/eh-coalescing-r/func.h new file mode 100644 index 0000000..4505225 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/eh-coalescing-r/func.h @@ -0,0 +1,35 @@ +/* -*- 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@ + */ + +extern int global; +extern void foo(int); + + +// this weak func() will have unwind info and a LSDA +inline int func() +{ + global = 1; + return global; +} + diff --git a/FireOpal/unit-tests/test-cases/eh-coalescing/Makefile b/FireOpal/unit-tests/test-cases/eh-coalescing/Makefile new file mode 100644 index 0000000..0c7fb32 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/eh-coalescing/Makefile @@ -0,0 +1,50 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# There are two copies of func(). The one from +# foo.o is weak and has an FDE (.eh) and LSDA. +# The one from bar.o is not weak and does not have +# exception info. Verify that since linker uses func() +# from bar.o that it does not use exception info +# from foo.o +# +# wrong EH information might be used +# + +run: all + +all: + ${CXX} ${CCXXFLAGS} foo.cxx -c -o foo.o + ${CXX} ${CCXXFLAGS} foo2.cxx -c -o foo2.o + ${CXX} ${CCXXFLAGS} bar.cxx -c -o bar.o -fno-exceptions + ${CXX} ${CCXXFLAGS} -dynamiclib foo.o foo2.o bar.o -o libfoobar.dylib -Wl,-map,libfoobar.map + # verify .eh symbol is missing or is from bar.o (file 3) + grep '\[ 2\] __Z4funcv.eh' libfoobar.map | ${FAIL_IF_STDIN} + # verify no LSDA + size -l libfoobar.dylib | grep __gcc_except_tab | ${PASS_IFF_EMPTY} + +clean: + rm foo.o foo2.o bar.o libfoobar.map libfoobar.dylib diff --git a/FireOpal/unit-tests/test-cases/eh-coalescing/bar.cxx b/FireOpal/unit-tests/test-cases/eh-coalescing/bar.cxx new file mode 100644 index 0000000..83d1845 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/eh-coalescing/bar.cxx @@ -0,0 +1,31 @@ +/* -*- 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@ + */ +#include + +// this non-seak func() will have no unwind info and no LSDA +int func() { return 0; } + +void foo(int x) {} + + diff --git a/FireOpal/unit-tests/test-cases/eh-coalescing/foo.cxx b/FireOpal/unit-tests/test-cases/eh-coalescing/foo.cxx new file mode 100644 index 0000000..ce9939f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/eh-coalescing/foo.cxx @@ -0,0 +1,33 @@ +/* -*- 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@ + */ +#include + +#include "func.h" + +int global; + +void test() +{ + func(); +} diff --git a/FireOpal/unit-tests/test-cases/eh-coalescing/foo2.cxx b/FireOpal/unit-tests/test-cases/eh-coalescing/foo2.cxx new file mode 100644 index 0000000..4440aed --- /dev/null +++ b/FireOpal/unit-tests/test-cases/eh-coalescing/foo2.cxx @@ -0,0 +1,31 @@ +/* -*- 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@ + */ +#include + +#include "func.h" + +void test2() +{ + func(); +} diff --git a/FireOpal/unit-tests/test-cases/eh-coalescing/func.h b/FireOpal/unit-tests/test-cases/eh-coalescing/func.h new file mode 100644 index 0000000..5bb7c28 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/eh-coalescing/func.h @@ -0,0 +1,43 @@ +/* -*- 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@ + */ + +extern int global; +extern void foo(int); + + +// this weak func() will have unwind info and a LSDA +inline int func() +{ + global = 1; + try { + foo(1); + global = 2; + } + catch (int x) { + foo(2); + global = 3; + } + return global; +} + diff --git a/FireOpal/unit-tests/test-cases/eh-strip-test/Makefile b/FireOpal/unit-tests/test-cases/eh-strip-test/Makefile new file mode 100644 index 0000000..0b8fcff --- /dev/null +++ b/FireOpal/unit-tests/test-cases/eh-strip-test/Makefile @@ -0,0 +1,34 @@ +## +# 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 + +run: all + + +all: + ${FAIL_IF_ERROR} $(CXX) main.cxx -arch ${ARCH} -o main + ${FAIL_IF_ERROR} nm -j main | grep '\.eh$$'| ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} main +clean: + rm -rf *.o main main-* *.nm diff --git a/FireOpal/unit-tests/test-cases/eh-strip-test/comment.txt b/FireOpal/unit-tests/test-cases/eh-strip-test/comment.txt new file mode 100644 index 0000000..a99f78e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/eh-strip-test/comment.txt @@ -0,0 +1,21 @@ +Test strip: symbols referenced by indirect symbol table entries can't be stripped (4096290) + +__ZN9__gnu_cxx13new_allocatorIiE7destroyEPi +__ZNKSt12_Vector_baseIiSaIiEE13get_allocatorEv +__ZN9__gnu_cxx13new_allocatorIiEC2ERKS1_ +__ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPim +__ZN9__gnu_cxx13new_allocatorIiED2Ev +__ZNSt6vectorIiSaIiEEC1ERKS0_ +__ZNSaIiEC1ERKS_ +__ZN9__gnu_cxx13new_allocatorIiE10deallocateEPim +__ZNSt12_Vector_baseIiSaIiEE12_Vector_implC1ERKS0_ +__ZNSaIiED2Ev +__ZNSt12_Vector_baseIiSaIiEED2Ev +__ZNSaIiEC1Ev +__ZNSt12_Vector_baseIiSaIiEEC2ERKS0_ +__ZNSt6vectorIiSaIiEED1Ev +__ZNSaIiED1Ev +__ZSt8_DestroyIPiSaIiEEvT_S2_T0_ +__ZN9__gnu_cxx13new_allocatorIiEC2Ev +__ZNSaIiEC2ERKS_ +__ZNSt12_Vector_baseIiSaIiEE12_Vector_implD1Ev diff --git a/FireOpal/unit-tests/test-cases/eh-strip-test/main.cxx b/FireOpal/unit-tests/test-cases/eh-strip-test/main.cxx new file mode 100644 index 0000000..dd65fef --- /dev/null +++ b/FireOpal/unit-tests/test-cases/eh-strip-test/main.cxx @@ -0,0 +1,6 @@ +#include +int main() +{ + std::vector stuff; + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/eh_frame/Makefile b/FireOpal/unit-tests/test-cases/eh_frame/Makefile new file mode 100644 index 0000000..6216d8e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/eh_frame/Makefile @@ -0,0 +1,47 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that ld +# strips .eh symbols out of final linked images, +# even when an intermediate ld -r was used. +# + +run: all + +all: + ${CXX} ${CCXXFLAGS} foo.cxx -dynamiclib -o libfoo.dylib + ${FAIL_IF_BAD_MACHO} libfoo.dylib + nm libfoo.dylib | grep '.eh' | ${FAIL_IF_STDIN} + ${CXX} ${CCXXFLAGS} foo.cxx -c -o foo.o + ${FAIL_IF_BAD_OBJ} foo.o + ${LD} -r foo.o -o foo2.o + ${FAIL_IF_BAD_OBJ} foo2.o + ${CXX} ${CCXXFLAGS} foo2.o bar.cxx -dynamiclib -o libfoobar.dylib + ${FAIL_IF_BAD_MACHO} libfoobar.dylib + nm libfoobar.dylib | grep '.eh' | ${PASS_IFF_EMPTY} + +clean: + rm *.dylib *.o diff --git a/FireOpal/unit-tests/test-cases/eh_frame/bar.cxx b/FireOpal/unit-tests/test-cases/eh_frame/bar.cxx new file mode 100644 index 0000000..9623da1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/eh_frame/bar.cxx @@ -0,0 +1,38 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + + +static void bar1() +{ + fprintf(stderr, "hello\n"); +} + +void bar2() +{ + bar1(); + fprintf(stderr, "world\n"); +} + + diff --git a/FireOpal/unit-tests/test-cases/eh_frame/foo.cxx b/FireOpal/unit-tests/test-cases/eh_frame/foo.cxx new file mode 100644 index 0000000..d1e2dd1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/eh_frame/foo.cxx @@ -0,0 +1,38 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + + +static void foo1() +{ + fprintf(stderr, "hello\n"); +} + +void foo2() +{ + foo1(); + fprintf(stderr, "world\n"); +} + + diff --git a/FireOpal/unit-tests/test-cases/empty-object/Makefile b/FireOpal/unit-tests/test-cases/empty-object/Makefile new file mode 100644 index 0000000..4142b8c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/empty-object/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2007 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 + +# +# The point of this test is a sanity check that ld +# can handle an empty (no load commands) .o file +# + +run: all + +all: + touch empty.s + as -arch ${ARCH} -n empty.s -o empty.o + ${CC} ${CCFLAGS} main.c empty.o -o main + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm main empty.s empty.o diff --git a/FireOpal/unit-tests/test-cases/empty-object/main.c b/FireOpal/unit-tests/test-cases/empty-object/main.c new file mode 100644 index 0000000..76e8197 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/empty-object/main.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/FireOpal/unit-tests/test-cases/end-label/Makefile b/FireOpal/unit-tests/test-cases/end-label/Makefile new file mode 100644 index 0000000..69f51a7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/end-label/Makefile @@ -0,0 +1,41 @@ +## +# Copyright (c) 2007 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 ld maintains two symbols with the same address and in different sections +# + +run: all + +all: + ${CC} ${CCFLAGS} foo.s -c -o foo.o + ${CC} ${CCFLAGS} bar.s -c -o bar.o + ${LD} -r foo.o bar.o -o foobar.o + nm -m foobar.o | grep _next | grep __other | ${FAIL_IF_EMPTY} + ${LD} -r foobar.o -o foobar2.o + nm -m foobar2.o | grep _next | grep __other | ${PASS_IFF_STDIN} + +clean: + rm -rf *.o diff --git a/FireOpal/unit-tests/test-cases/end-label/bar.s b/FireOpal/unit-tests/test-cases/end-label/bar.s new file mode 100644 index 0000000..db389c4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/end-label/bar.s @@ -0,0 +1,7 @@ + + .section __DATA,__other,regular + + .globl _next +_next: + nop + \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/end-label/foo.s b/FireOpal/unit-tests/test-cases/end-label/foo.s new file mode 100644 index 0000000..888af5f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/end-label/foo.s @@ -0,0 +1,11 @@ + + .data + + .globl _start + .globl _end +_start: + .long 0 + .long 0 +_end: + + diff --git a/FireOpal/unit-tests/test-cases/exported-symbols-wildcards-dead_strip/Makefile b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards-dead_strip/Makefile new file mode 100644 index 0000000..cf300a3 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards-dead_strip/Makefile @@ -0,0 +1,39 @@ +## +# Copyright (c) 2007 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 + +# +# Tests the use of wildcards in exported symbol lists and dead stripping +# + +run: all + +all: + ${CC} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_AB*' -dead_strip + nm -j -f libfoo.dylib | grep _good | ${FAIL_IF_EMPTY} + nm -j -f libfoo.dylib | grep _bad | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} libfoo.dylib + +clean: + rm libfoo.dylib diff --git a/FireOpal/unit-tests/test-cases/exported-symbols-wildcards-dead_strip/foo.c b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards-dead_strip/foo.c new file mode 100644 index 0000000..6bb8d95 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards-dead_strip/foo.c @@ -0,0 +1,34 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 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 + +void good() {} +void bad() {} + + +void ABC() {} +void ABD() { good(); } +void DEF() {} +void DEG() { bad(); } + diff --git a/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/Makefile b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/Makefile new file mode 100644 index 0000000..10d1eb1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/Makefile @@ -0,0 +1,78 @@ +## +# Copyright (c) 2007 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 + +# +# Tests the use of wildcards in exported symbol lists +# + +run: all + +all: + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_foo*bar' + nm -j -g -f libfoo.dylib | diff - expect1 | ${FAIL_IF_STDIN} + ${FAIL_IF_BAD_MACHO} libfoo.dylib + + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f?o' + nm -j -g -f libfoo.dylib | diff - expect2 | ${FAIL_IF_STDIN} + ${FAIL_IF_BAD_MACHO} libfoo.dylib + + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_foo*' + nm -j -g -f libfoo.dylib | diff - expect3 | ${FAIL_IF_STDIN} + ${FAIL_IF_BAD_MACHO} libfoo.dylib + + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f*o*' + nm -j -g -f libfoo.dylib | diff - expect4 | ${FAIL_IF_STDIN} + ${FAIL_IF_BAD_MACHO} libfoo.dylib + + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,_foo -Wl,-exported_symbol -Wl,'_*bar' + nm -j -g -f libfoo.dylib | diff - expect5 | ${FAIL_IF_STDIN} + ${FAIL_IF_BAD_MACHO} libfoo.dylib + + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -exported_symbols_list list5 + nm -j -g -f libfoo.dylib | diff - expect5 | ${FAIL_IF_STDIN} + ${FAIL_IF_BAD_MACHO} libfoo.dylib + + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-unexported_symbol -Wl,'_*2*' + nm -j -g -f libfoo.dylib | diff - expect6 | ${FAIL_IF_STDIN} + ${FAIL_IF_BAD_MACHO} libfoo.dylib + + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f[abcdef]o' + nm -j -g -f libfoo.dylib | diff - expect7 | ${FAIL_IF_STDIN} + ${FAIL_IF_BAD_MACHO} libfoo.dylib + + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f[a-f]o' + nm -j -g -f libfoo.dylib | diff - expect7 | ${FAIL_IF_STDIN} + ${FAIL_IF_BAD_MACHO} libfoo.dylib + + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f[a-z]o' + nm -j -g -f libfoo.dylib | diff - expect8 | ${FAIL_IF_STDIN} + ${FAIL_IF_BAD_MACHO} libfoo.dylib + + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f[a-fnop]o' + nm -j -g -f libfoo.dylib | diff - expect8 | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} libfoo.dylib + +clean: + rm libfoo.dylib diff --git a/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect1 b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect1 new file mode 100644 index 0000000..75aadb3 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect1 @@ -0,0 +1,2 @@ +_foo2bar +_foobar diff --git a/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect2 b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect2 new file mode 100644 index 0000000..09883f8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect2 @@ -0,0 +1,3 @@ +_fao +_ffo +_foo diff --git a/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect3 b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect3 new file mode 100644 index 0000000..478bf69 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect3 @@ -0,0 +1,4 @@ +_foo +_foo2 +_foo2bar +_foobar diff --git a/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect4 b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect4 new file mode 100644 index 0000000..b78c206 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect4 @@ -0,0 +1,6 @@ +_fao +_ffo +_foo +_foo2 +_foo2bar +_foobar diff --git a/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect5 b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect5 new file mode 100644 index 0000000..cc935a4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect5 @@ -0,0 +1,3 @@ +_foo +_foo2bar +_foobar diff --git a/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect6 b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect6 new file mode 100644 index 0000000..bdf1d31 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect6 @@ -0,0 +1,4 @@ +_fao +_ffo +_foo +_foobar diff --git a/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect7 b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect7 new file mode 100644 index 0000000..c691c40 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect7 @@ -0,0 +1,2 @@ +_fao +_ffo diff --git a/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect8 b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect8 new file mode 100644 index 0000000..09883f8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/expect8 @@ -0,0 +1,3 @@ +_fao +_ffo +_foo diff --git a/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/foo.c b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/foo.c new file mode 100644 index 0000000..bc5be8e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/foo.c @@ -0,0 +1,55 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include + + +int foo() +{ + return 1; +} + +int foo2() +{ + return 1; +} + +int foobar() +{ + return 1; +} + +int foo2bar() +{ + return 1; +} + +int fao() +{ + return 1; +} + +int ffo() +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/list5 b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/list5 new file mode 100644 index 0000000..a6776d2 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported-symbols-wildcards/list5 @@ -0,0 +1,2 @@ +_foo +_*bar diff --git a/FireOpal/unit-tests/test-cases/exported_symbols_list-eol/Makefile b/FireOpal/unit-tests/test-cases/exported_symbols_list-eol/Makefile new file mode 100644 index 0000000..25a50b4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported_symbols_list-eol/Makefile @@ -0,0 +1,41 @@ +## +# Copyright (c) 2007 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 that -exported_symbols_list can be used with a file with Mac (0x0D) line endings +# + +run: all + +all: + ${CC} ${CCFLAGS} test.c -dynamiclib -exported_symbols_list test.exp -o libtest.dylib + nm -jg libtest.dylib | grep _ > test.nm + diff test.nm expected.nm + ${PASS_IFF_GOOD_MACHO} libtest.dylib + +clean: + rm -rf libtest.dylib test.nm diff --git a/FireOpal/unit-tests/test-cases/exported_symbols_list-eol/expected.nm b/FireOpal/unit-tests/test-cases/exported_symbols_list-eol/expected.nm new file mode 100644 index 0000000..b21cbbf --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported_symbols_list-eol/expected.nm @@ -0,0 +1,2 @@ +_common_global2 +_func_global2 diff --git a/FireOpal/unit-tests/test-cases/exported_symbols_list-eol/test.c b/FireOpal/unit-tests/test-cases/exported_symbols_list-eol/test.c new file mode 100644 index 0000000..c9fdc35 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported_symbols_list-eol/test.c @@ -0,0 +1,18 @@ + + + +static int data_static1 = 1; +static int data_static2 = 2; + +void func_global1() { ++data_static1; } +void func_global2() { ++data_static2; } + +void __attribute__((visibility("hidden"))) func_hidden1() {} +void __attribute__((visibility("hidden"))) func_hidden2() {} + +int common_global1; +int common_global2; + +int __attribute__((visibility("hidden"))) common_hidden1; +int __attribute__((visibility("hidden"))) common_hidden2; + diff --git a/FireOpal/unit-tests/test-cases/exported_symbols_list-eol/test.exp b/FireOpal/unit-tests/test-cases/exported_symbols_list-eol/test.exp new file mode 100644 index 0000000..6ab1532 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported_symbols_list-eol/test.exp @@ -0,0 +1 @@ +_func_global2 _common_global2 \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/exported_symbols_list-hidden/Makefile b/FireOpal/unit-tests/test-cases/exported_symbols_list-hidden/Makefile new file mode 100644 index 0000000..c27287d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported_symbols_list-hidden/Makefile @@ -0,0 +1,41 @@ +## +# Copyright (c) 2007 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 that -exported_symbols_list of a hidden symbol causes a warning +# + +run: all + +all: + ${CC} ${CCFLAGS} test.c -dynamiclib -exported_symbols_list test.exp -o libtest.dylib 2>warning.log + grep _func_hidden1 warning.log | ${FAIL_IF_EMPTY} + grep _common_hidden1 warning.log | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} libtest.dylib + +clean: + rm -rf libtest.dylib warning.log diff --git a/FireOpal/unit-tests/test-cases/exported_symbols_list-hidden/test.c b/FireOpal/unit-tests/test-cases/exported_symbols_list-hidden/test.c new file mode 100644 index 0000000..c9fdc35 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported_symbols_list-hidden/test.c @@ -0,0 +1,18 @@ + + + +static int data_static1 = 1; +static int data_static2 = 2; + +void func_global1() { ++data_static1; } +void func_global2() { ++data_static2; } + +void __attribute__((visibility("hidden"))) func_hidden1() {} +void __attribute__((visibility("hidden"))) func_hidden2() {} + +int common_global1; +int common_global2; + +int __attribute__((visibility("hidden"))) common_hidden1; +int __attribute__((visibility("hidden"))) common_hidden2; + diff --git a/FireOpal/unit-tests/test-cases/exported_symbols_list-hidden/test.exp b/FireOpal/unit-tests/test-cases/exported_symbols_list-hidden/test.exp new file mode 100644 index 0000000..f45858b --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported_symbols_list-hidden/test.exp @@ -0,0 +1,4 @@ +_func_global1 +_func_hidden1 +_common_global1 +_common_hidden1 diff --git a/FireOpal/unit-tests/test-cases/exported_symbols_list-r/Makefile b/FireOpal/unit-tests/test-cases/exported_symbols_list-r/Makefile new file mode 100644 index 0000000..96ef763 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported_symbols_list-r/Makefile @@ -0,0 +1,55 @@ +## +# Copyright (c) 2007 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 that -exported_symbols_list can be used with -r +# to reduce visibility of symbols and any missing symbols +# causes an error +# + +run: all + +all: + ${CC} ${CCFLAGS} test.c -c -o test.o + ${FAIL_IF_BAD_OBJ} test.o + ${LD} -arch ${ARCH} -r -keep_private_externs test.o -exported_symbols_list test.exp -o test-r.o + ${FAIL_IF_BAD_OBJ} test-r.o + # verify common not in export-list got demoted to private extern + nm -m test-r.o | grep "private external _common_global1" | ${FAIL_IF_EMPTY} + # verify only _common_global1 and _func_global1 changed + nm -m test.o | egrep -v '_common_global1|_func_global1|__eh_frame|__data' > test.nm + nm -m test-r.o | egrep -v '_common_global1|_func_global1|__eh_frame|__data' > test-r.nm + diff test.nm test-r.nm + # verify without -keep_private_externs that commons stay private extern + ${LD} -arch ${ARCH} -r test.o -exported_symbols_list test.exp -o test-rr.o + nm -m test-rr.o | grep _common_hidden | grep ') external' | ${FAIL_IF_STDIN} + nm -m test-rr.o | grep _common_global1 | grep ') external' | ${FAIL_IF_STDIN} + # should error out if told to export unavailable symbol + ${FAIL_IFF_SUCCESS} ${LD} -arch ${ARCH} -r test.o -exported_symbols_list test-bad.exp -o test2.o 2>/dev/null + +clean: + rm -rf test.o test-r.o test-rr.o test.nm test-r.nm test2.o diff --git a/FireOpal/unit-tests/test-cases/exported_symbols_list-r/test-bad.exp b/FireOpal/unit-tests/test-cases/exported_symbols_list-r/test-bad.exp new file mode 100644 index 0000000..73154ba --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported_symbols_list-r/test-bad.exp @@ -0,0 +1,3 @@ +_bar +_baz +_foobar diff --git a/FireOpal/unit-tests/test-cases/exported_symbols_list-r/test.c b/FireOpal/unit-tests/test-cases/exported_symbols_list-r/test.c new file mode 100644 index 0000000..c9fdc35 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported_symbols_list-r/test.c @@ -0,0 +1,18 @@ + + + +static int data_static1 = 1; +static int data_static2 = 2; + +void func_global1() { ++data_static1; } +void func_global2() { ++data_static2; } + +void __attribute__((visibility("hidden"))) func_hidden1() {} +void __attribute__((visibility("hidden"))) func_hidden2() {} + +int common_global1; +int common_global2; + +int __attribute__((visibility("hidden"))) common_hidden1; +int __attribute__((visibility("hidden"))) common_hidden2; + diff --git a/FireOpal/unit-tests/test-cases/exported_symbols_list-r/test.exp b/FireOpal/unit-tests/test-cases/exported_symbols_list-r/test.exp new file mode 100644 index 0000000..93e7e17 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/exported_symbols_list-r/test.exp @@ -0,0 +1,2 @@ +_func_global2 +_common_global2 diff --git a/FireOpal/unit-tests/test-cases/external-reloc-sorting/Makefile b/FireOpal/unit-tests/test-cases/external-reloc-sorting/Makefile new file mode 100644 index 0000000..d9b92d5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/external-reloc-sorting/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2007 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 + +# +# The point of this test is to see that external relocations +# are sorted so that dyld only has to look up symbols once. +# The machochecker tool verifies that the relocs are sorted. +# + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib + ${CC} ${CCFLAGS} main.c libfoo.dylib -o main + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf main libfoo.dylib diff --git a/FireOpal/unit-tests/test-cases/external-reloc-sorting/foo.c b/FireOpal/unit-tests/test-cases/external-reloc-sorting/foo.c new file mode 100644 index 0000000..bc28725 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/external-reloc-sorting/foo.c @@ -0,0 +1,5 @@ + +int foo = 1; +int bar = 2; +int baz = 3; + diff --git a/FireOpal/unit-tests/test-cases/external-reloc-sorting/main.c b/FireOpal/unit-tests/test-cases/external-reloc-sorting/main.c new file mode 100644 index 0000000..6c68c4c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/external-reloc-sorting/main.c @@ -0,0 +1,39 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 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 + +// in libfoo.dylib +extern int foo; +extern int bar; +extern int baz; + +// this initialilzed data will result in external relocations +// alternating the values, will create relocs that need sorting +int* array[] = { &foo, &bar, &baz, &foo, &bar, &baz, &foo, &bar, &baz }; + + +int main() +{ + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/filelist/Makefile b/FireOpal/unit-tests/test-cases/filelist/Makefile new file mode 100644 index 0000000..0b1a743 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/filelist/Makefile @@ -0,0 +1,47 @@ +## +# Copyright (c) 2006 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 + + +PWD = $(shell pwd) + +# +# The point of this test is to check the two forms of the +# -filelist option +# + +run: all + +all: + ${CC} ${CCFLAGS} -c hello.c -o hello-${ARCH}.o + ${FAIL_IF_BAD_OBJ} hello-${ARCH}.o + echo "${PWD}/hello-${ARCH}.o" > "${PWD}/filelist1" + cd /tmp && ${CC} ${CCFLAGS} -filelist "${PWD}/filelist1" -o "${PWD}/hello-${ARCH}" + ${FAIL_IF_BAD_MACHO} hello-${ARCH} + echo "hello-${ARCH}.o" > "${PWD}/filelist2" + cd /tmp && ${CC} ${CCFLAGS} -filelist "${PWD}/filelist2,${PWD}" -o "${PWD}/hello-${ARCH}" + ${PASS_IFF_GOOD_MACHO} hello-${ARCH} + +clean: + rm hello-* *.o filelist1 filelist2 diff --git a/FireOpal/unit-tests/test-cases/filelist/comment.txt b/FireOpal/unit-tests/test-cases/filelist/comment.txt new file mode 100644 index 0000000..f193b11 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/filelist/comment.txt @@ -0,0 +1 @@ +The point of this test is to check the two forms of the -filelist option diff --git a/FireOpal/unit-tests/test-cases/filelist/hello.c b/FireOpal/unit-tests/test-cases/filelist/hello.c new file mode 100644 index 0000000..14d9363 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/filelist/hello.c @@ -0,0 +1,29 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +int main() +{ + fprintf(stdout, "hello\n"); +} diff --git a/FireOpal/unit-tests/test-cases/flat-dylib/Makefile b/FireOpal/unit-tests/test-cases/flat-dylib/Makefile new file mode 100644 index 0000000..b1015b2 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/flat-dylib/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that ld +# can link a small dylib -flat_namespace and +# indirect internal references. +# + +run: all + +all: + ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain.dylib -flat_namespace + otool -Iv libmain.dylib | grep _foo | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} libmain.dylib + +clean: + rm *.dylib diff --git a/FireOpal/unit-tests/test-cases/flat-dylib/main.c b/FireOpal/unit-tests/test-cases/flat-dylib/main.c new file mode 100644 index 0000000..6014829 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/flat-dylib/main.c @@ -0,0 +1,33 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +void foo() {} + + +int main() +{ + foo(); + fprintf(stdout, "hello\n"); +} diff --git a/FireOpal/unit-tests/test-cases/flat-indirect-undefines/Makefile b/FireOpal/unit-tests/test-cases/flat-indirect-undefines/Makefile new file mode 100644 index 0000000..a3715e0 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/flat-indirect-undefines/Makefile @@ -0,0 +1,49 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Test that when linking a main executable for flat-namespace +# that undefines in loaded flat-namespace dylibs are resolved. +# + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -flat_namespace -dynamiclib -o libfoo.dylib -undefined suppress + ${CC} ${CCFLAGS} bar.c -c -o bar.o + libtool -static bar.o -o libbar.a + # test that linking main executable -twolevel_namespace does not pull in bar() + ${CC} ${CCFLAGS} main.c libfoo.dylib libbar.a -o main + nm -mn main | grep _bar | ${FAIL_IF_STDIN} + # test that linking dylib -flat_namespace does not pull in bar() + ${CC} ${CCFLAGS} main.c -flat_namespace libfoo.dylib libbar.a -dynamiclib -o main.dylib + nm -mn main.dylib | grep _bar | ${FAIL_IF_STDIN} + # test that linking main executable -flat_namespace pulls in bar() + ${CC} ${CCFLAGS} main.c -flat_namespace libfoo.dylib libbar.a -o main_flat + nm -mn main_flat | grep _bar | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main_flat + +clean: + rm libfoo.dylib libbar.a bar.o main main_flat main.dylib diff --git a/FireOpal/unit-tests/test-cases/flat-indirect-undefines/bar.c b/FireOpal/unit-tests/test-cases/flat-indirect-undefines/bar.c new file mode 100644 index 0000000..b348aa8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/flat-indirect-undefines/bar.c @@ -0,0 +1,4 @@ + +void bar() {} + + diff --git a/FireOpal/unit-tests/test-cases/flat-indirect-undefines/foo.c b/FireOpal/unit-tests/test-cases/flat-indirect-undefines/foo.c new file mode 100644 index 0000000..39df2ea --- /dev/null +++ b/FireOpal/unit-tests/test-cases/flat-indirect-undefines/foo.c @@ -0,0 +1,8 @@ + +extern void bar(); + +void foo() +{ + bar(); +} + diff --git a/FireOpal/unit-tests/test-cases/flat-indirect-undefines/main.c b/FireOpal/unit-tests/test-cases/flat-indirect-undefines/main.c new file mode 100644 index 0000000..246fed4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/flat-indirect-undefines/main.c @@ -0,0 +1,10 @@ +#include + +extern void foo(); + + +int main() +{ + foo(); + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/flat-main/Makefile b/FireOpal/unit-tests/test-cases/flat-main/Makefile new file mode 100644 index 0000000..d31b7ab --- /dev/null +++ b/FireOpal/unit-tests/test-cases/flat-main/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that ld +# can link a hello-world program -flat_namespace and +# does not indirect internal references. +# + +run: all + +all: + ${CC} ${CCFLAGS} main.c -o main-${ARCH} -flat_namespace + otool -Iv main-${ARCH} | grep _foo | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} main-${ARCH} + +clean: + rm main-* diff --git a/FireOpal/unit-tests/test-cases/flat-main/main.c b/FireOpal/unit-tests/test-cases/flat-main/main.c new file mode 100644 index 0000000..6014829 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/flat-main/main.c @@ -0,0 +1,33 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +void foo() {} + + +int main() +{ + foo(); + fprintf(stdout, "hello\n"); +} diff --git a/FireOpal/unit-tests/test-cases/got-elimination/Makefile b/FireOpal/unit-tests/test-cases/got-elimination/Makefile new file mode 100644 index 0000000..3f70e74 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/got-elimination/Makefile @@ -0,0 +1,50 @@ +## +# Copyright (c) 2007 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 ld can remove non-lazy pointers for x86_64 +# + +all: all-${ARCH} + +all-armv6: all-true + +all-ppc: all-true + +all-ppc64: all-true + +all-i386: all-true + +all-true: + ${PASS_IFF} true + +all-x86_64: + ${CC} ${CCFLAGS} foo.c bar.c -dynamiclib -o libfoobar.dylib + otool -Iv libfoobar.dylib | grep 0x | ${FAIL_IF_STDIN} + ${CC} ${CCFLAGS} foo.c bar.c -dynamiclib -o libfoobar.dylib -flat_namespace + otool -Iv libfoobar.dylib | grep 0x | ${PASS_IFF_STDIN} + +clean: + rm -rf libfoobar.dylib diff --git a/FireOpal/unit-tests/test-cases/got-elimination/bar.c b/FireOpal/unit-tests/test-cases/got-elimination/bar.c new file mode 100644 index 0000000..781c6fd --- /dev/null +++ b/FireOpal/unit-tests/test-cases/got-elimination/bar.c @@ -0,0 +1,28 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 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@ + */ + +int bar1 = 1; +int bar2 = 2; +int bar3 = 3; + diff --git a/FireOpal/unit-tests/test-cases/got-elimination/foo.c b/FireOpal/unit-tests/test-cases/got-elimination/foo.c new file mode 100644 index 0000000..45675a3 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/got-elimination/foo.c @@ -0,0 +1,42 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 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 bar1; +extern int bar2; // just under 2GB array +extern int bar3; + +int getbar1() +{ + return bar1; +} + +int getbar2() +{ + return bar2; +} + +int getbar3() +{ + return bar3; +} diff --git a/FireOpal/unit-tests/test-cases/header-pad/Makefile b/FireOpal/unit-tests/test-cases/header-pad/Makefile new file mode 100644 index 0000000..d8cdd51 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/header-pad/Makefile @@ -0,0 +1,38 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that ld +# can link a hello-world program with no errors (or crashes) +# + +run: all + +all: + ${CC} ${CCFLAGS} hello.c -o hello-${ARCH} -Wl,-headerpad -Wl,0x3000 + ${PASS_IFF_GOOD_MACHO} hello-${ARCH} + +clean: + rm hello-* diff --git a/FireOpal/unit-tests/test-cases/header-pad/comment.txt b/FireOpal/unit-tests/test-cases/header-pad/comment.txt new file mode 100644 index 0000000..79114eb --- /dev/null +++ b/FireOpal/unit-tests/test-cases/header-pad/comment.txt @@ -0,0 +1 @@ +The point of this test is a sanity check that ld can link a hello-world program with no errors (or crashes) diff --git a/FireOpal/unit-tests/test-cases/header-pad/hello.c b/FireOpal/unit-tests/test-cases/header-pad/hello.c new file mode 100644 index 0000000..14d9363 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/header-pad/hello.c @@ -0,0 +1,29 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +int main() +{ + fprintf(stdout, "hello\n"); +} diff --git a/FireOpal/unit-tests/test-cases/hello-world/Makefile b/FireOpal/unit-tests/test-cases/hello-world/Makefile new file mode 100644 index 0000000..a1ade02 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/hello-world/Makefile @@ -0,0 +1,38 @@ +## +# 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 + +# +# The point of this test is a sanity check that ld +# can link a hello-world program with no errors (or crashes) +# + +run: all + +all: + ${CC} ${CCFLAGS} hello.c -o hello-${ARCH} + ${PASS_IFF_GOOD_MACHO} hello-${ARCH} + +clean: + rm hello-* diff --git a/FireOpal/unit-tests/test-cases/hello-world/comment.txt b/FireOpal/unit-tests/test-cases/hello-world/comment.txt new file mode 100644 index 0000000..79114eb --- /dev/null +++ b/FireOpal/unit-tests/test-cases/hello-world/comment.txt @@ -0,0 +1 @@ +The point of this test is a sanity check that ld can link a hello-world program with no errors (or crashes) diff --git a/FireOpal/unit-tests/test-cases/hello-world/hello.c b/FireOpal/unit-tests/test-cases/hello-world/hello.c new file mode 100644 index 0000000..e2f0fe9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/hello-world/hello.c @@ -0,0 +1,29 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * 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@ + */ +#include + +int main() +{ + fprintf(stdout, "hello\n"); +} \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/implicit-common2/Makefile.newtest b/FireOpal/unit-tests/test-cases/implicit-common2/Makefile.newtest new file mode 100644 index 0000000..af93da1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common2/Makefile.newtest @@ -0,0 +1,47 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that ld +# can link a program with a large zero-fill section +# + +run: all + +all: + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c test.c -o test-${ARCH}.o + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c a.c -o a-${ARCH}.o + ${FAIL_IF_ERROR} ar -r libtest-${ARCH}.a test-${ARCH}.o 2>/dev/null + #ranlib libtest-${ARCH}.a + #${FAIL_IF_ERROR} ${CC} ${LDFLAGS} a-${ARCH}.o -L. -ltest-${ARCH} -o a-${ARCH} + #${PASS_IFF_GOOD_MACHO} a-${ARCH} + + ${FAIL_IF_ERROR} ar -r libtest-${ARCH}.a test-${ARCH}.o a-${ARCH}.o 2>/dev/null + ${FAIL_IF_ERROR} ranlib libtest-${ARCH}.a + ${FAIL_IF_ERROR} ${CC} ${LDFLAGS} a-${ARCH}.o -L. -ltest-${ARCH} -o a-${ARCH} + ${PASS_IFF_GOOD_MACHO} a-${ARCH} + +clean: + rm -rf *.o *.a diff --git a/FireOpal/unit-tests/test-cases/implicit-common2/a.c b/FireOpal/unit-tests/test-cases/implicit-common2/a.c new file mode 100644 index 0000000..8f92c9d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common2/a.c @@ -0,0 +1,7 @@ +extern int common_variable; + +int +main(int argc, char **argv) +{ + return common_variable; +} diff --git a/FireOpal/unit-tests/test-cases/implicit-common2/comment.txt b/FireOpal/unit-tests/test-cases/implicit-common2/comment.txt new file mode 100644 index 0000000..a1710c1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common2/comment.txt @@ -0,0 +1 @@ +The point of this test is a sanity check that ld can link a program with a large zero-fill section diff --git a/FireOpal/unit-tests/test-cases/implicit-common2/test.c b/FireOpal/unit-tests/test-cases/implicit-common2/test.c new file mode 100644 index 0000000..94578c6 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common2/test.c @@ -0,0 +1,26 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + +int common_variable; +extern int main(); diff --git a/FireOpal/unit-tests/test-cases/implicit-common3/Makefile b/FireOpal/unit-tests/test-cases/implicit-common3/Makefile new file mode 100644 index 0000000..6785960 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common3/Makefile @@ -0,0 +1,44 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that ld +# can link a program with a large zero-fill section +# + +run: all + +all: + ${CC} ${CCFLAGS} -c test.c -o test-${ARCH}.o + ${FAIL_IF_BAD_OBJ} test-${ARCH}.o + ${CC} ${CCFLAGS} -c a.c -o a-${ARCH}.o + ${FAIL_IF_BAD_OBJ} a-${ARCH}.o + ${FAIL_IF_ERROR} ar -r libtest-${ARCH}.a test-${ARCH}.o 2>/dev/null + ${FAIL_IF_ERROR} ranlib libtest-${ARCH}.a + ${CC} ${CCFLAGS} a-${ARCH}.o -L. -ltest-${ARCH} -o a-${ARCH} + ${PASS_IFF_GOOD_MACHO} a-${ARCH} + +clean: + rm -rf *.o *.a a-* diff --git a/FireOpal/unit-tests/test-cases/implicit-common3/a.c b/FireOpal/unit-tests/test-cases/implicit-common3/a.c new file mode 100644 index 0000000..110842f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common3/a.c @@ -0,0 +1,8 @@ +extern int common_var; +int *fn(); + +int +main(int argc, char **argv) +{ + return 0!=&common_var; +} diff --git a/FireOpal/unit-tests/test-cases/implicit-common3/comment.txt b/FireOpal/unit-tests/test-cases/implicit-common3/comment.txt new file mode 100644 index 0000000..a1710c1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common3/comment.txt @@ -0,0 +1 @@ +The point of this test is a sanity check that ld can link a program with a large zero-fill section diff --git a/FireOpal/unit-tests/test-cases/implicit-common3/test.c b/FireOpal/unit-tests/test-cases/implicit-common3/test.c new file mode 100644 index 0000000..e0fd7e8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common3/test.c @@ -0,0 +1,37 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + +struct abc { + int a; + int b; + int c; +} struct_var; + +int common_var; +extern const int defined_var; + +int *fn() +{ + return &common_var; +} diff --git a/FireOpal/unit-tests/test-cases/implicit-common4/Makefile.newtest b/FireOpal/unit-tests/test-cases/implicit-common4/Makefile.newtest new file mode 100644 index 0000000..d70c634 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common4/Makefile.newtest @@ -0,0 +1,45 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that ld +# can link a program with a large zero-fill section +# + +run: all + +all: + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c test.c -o test-${ARCH}.o + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c a.c -o a-${ARCH}.o + ${FAIL_IF_ERROR} libtool -o libtest-${ARCH}.a test-${ARCH}.o + #${FAIL_IF_ERROR} ${CC} ${LDFLAGS} a-${ARCH}.o -L. -ltest-${ARCH} -o a-${ARCH} + #${PASS_IFF_GOOD_MACHO} a-${ARCH} + + ${FAIL_IF_ERROR} libtool -o libtest-${ARCH}.a test-${ARCH}.o a-${ARCH}.o + ${FAIL_IF_ERROR} ${CC} ${LDFLAGS} a-${ARCH}.o -L. -ltest-${ARCH} -o a-${ARCH} + ${PASS_IFF_GOOD_MACHO} a-${ARCH} + +clean: + rm -rf *.o *.a diff --git a/FireOpal/unit-tests/test-cases/implicit-common4/a.c b/FireOpal/unit-tests/test-cases/implicit-common4/a.c new file mode 100644 index 0000000..8f92c9d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common4/a.c @@ -0,0 +1,7 @@ +extern int common_variable; + +int +main(int argc, char **argv) +{ + return common_variable; +} diff --git a/FireOpal/unit-tests/test-cases/implicit-common4/comment.txt b/FireOpal/unit-tests/test-cases/implicit-common4/comment.txt new file mode 100644 index 0000000..a1710c1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common4/comment.txt @@ -0,0 +1 @@ +The point of this test is a sanity check that ld can link a program with a large zero-fill section diff --git a/FireOpal/unit-tests/test-cases/implicit-common4/test.c b/FireOpal/unit-tests/test-cases/implicit-common4/test.c new file mode 100644 index 0000000..94578c6 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common4/test.c @@ -0,0 +1,26 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + +int common_variable; +extern int main(); diff --git a/FireOpal/unit-tests/test-cases/implicit-common5/Makefile.newtest b/FireOpal/unit-tests/test-cases/implicit-common5/Makefile.newtest new file mode 100644 index 0000000..d5b6d73 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common5/Makefile.newtest @@ -0,0 +1,41 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that ld +# can link a program with a large zero-fill section +# + +run: all + +all: + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c test.c -o test-${ARCH}.o + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c a.c -o a-${ARCH}.o + ${FAIL_IF_ERROR} libtool -o libtest-${ARCH}.a test-${ARCH}.o + ${FAIL_IF_ERROR} ${CC} ${LDFLAGS} a-${ARCH}.o -L. -ltest-${ARCH} -o a-${ARCH} + ${PASS_IFF_GOOD_MACHO} a-${ARCH} + +clean: + rm -rf *.o *a diff --git a/FireOpal/unit-tests/test-cases/implicit-common5/a.c b/FireOpal/unit-tests/test-cases/implicit-common5/a.c new file mode 100644 index 0000000..8f92c9d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common5/a.c @@ -0,0 +1,7 @@ +extern int common_variable; + +int +main(int argc, char **argv) +{ + return common_variable; +} diff --git a/FireOpal/unit-tests/test-cases/implicit-common5/comment.txt b/FireOpal/unit-tests/test-cases/implicit-common5/comment.txt new file mode 100644 index 0000000..a1710c1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common5/comment.txt @@ -0,0 +1 @@ +The point of this test is a sanity check that ld can link a program with a large zero-fill section diff --git a/FireOpal/unit-tests/test-cases/implicit-common5/test.c b/FireOpal/unit-tests/test-cases/implicit-common5/test.c new file mode 100644 index 0000000..f34267a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit-common5/test.c @@ -0,0 +1,25 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + +int common_variable; diff --git a/FireOpal/unit-tests/test-cases/implicit_dylib/Makefile b/FireOpal/unit-tests/test-cases/implicit_dylib/Makefile new file mode 100644 index 0000000..c982885 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit_dylib/Makefile @@ -0,0 +1,48 @@ +## +# Copyright (c) 2007 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 + +PWD = $(shell pwd) + + +# Verify -no_implicit_dylibs option +# add option to disable implicit load commands for indirectly used public dylibs +# + + +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 + # 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} + # verify that -no_implicit_dylibs causes main to get bar from libfoo + ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -Wl,-no_implicit_dylibs -L. + nm -m main | grep _bar | grep libfoo | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf libfoo.dylib libbar.dylib main diff --git a/FireOpal/unit-tests/test-cases/implicit_dylib/bar.c b/FireOpal/unit-tests/test-cases/implicit_dylib/bar.c new file mode 100644 index 0000000..e2164a2 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit_dylib/bar.c @@ -0,0 +1,7 @@ + + + +void bar() +{ +} + diff --git a/FireOpal/unit-tests/test-cases/implicit_dylib/foo.c b/FireOpal/unit-tests/test-cases/implicit_dylib/foo.c new file mode 100644 index 0000000..1624757 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit_dylib/foo.c @@ -0,0 +1,5 @@ + + +void foo() +{ +} diff --git a/FireOpal/unit-tests/test-cases/implicit_dylib/main.c b/FireOpal/unit-tests/test-cases/implicit_dylib/main.c new file mode 100644 index 0000000..1f50353 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/implicit_dylib/main.c @@ -0,0 +1,11 @@ + +extern void foo(); +extern void bar(); + +int main() +{ + foo(); + bar(); + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/indirect-dylib/Makefile b/FireOpal/unit-tests/test-cases/indirect-dylib/Makefile new file mode 100644 index 0000000..e3056a5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/indirect-dylib/Makefile @@ -0,0 +1,46 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that an indirect +# library is not accidentally searched for symbols. +# +# wrong error message when symbol is found in unused indirect library# +# + +run: all + +all: + ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib + ${FAIL_IF_BAD_MACHO} libbar.dylib + ${CC} ${CCFLAGS} foo.c libbar.dylib -dynamiclib -o libfoo.dylib + ${FAIL_IF_BAD_MACHO} libfoo.dylib + ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -o main libfoo.dylib 2> fail.log + grep ordinal fail.log | ${PASS_IFF_EMPTY} + +clean: + rm *.dylib main fail.log diff --git a/FireOpal/unit-tests/test-cases/indirect-dylib/bar.c b/FireOpal/unit-tests/test-cases/indirect-dylib/bar.c new file mode 100644 index 0000000..f39ee21 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/indirect-dylib/bar.c @@ -0,0 +1,31 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + + +// function called by a loaded bundle +int bar() +{ + return 1; +} + diff --git a/FireOpal/unit-tests/test-cases/indirect-dylib/comment.txt b/FireOpal/unit-tests/test-cases/indirect-dylib/comment.txt new file mode 100644 index 0000000..311aa79 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/indirect-dylib/comment.txt @@ -0,0 +1,4 @@ +The point of this test is a sanity check that an indirect +library is not accidentally searched for symbols. + + wrong error message when symbol is found in unused indirect library# diff --git a/FireOpal/unit-tests/test-cases/indirect-dylib/foo.c b/FireOpal/unit-tests/test-cases/indirect-dylib/foo.c new file mode 100644 index 0000000..ba78c28 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/indirect-dylib/foo.c @@ -0,0 +1,31 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +extern int bar(); + +int foo() +{ + return bar(); +} diff --git a/FireOpal/unit-tests/test-cases/indirect-dylib/main.c b/FireOpal/unit-tests/test-cases/indirect-dylib/main.c new file mode 100644 index 0000000..13f57d7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/indirect-dylib/main.c @@ -0,0 +1,33 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +extern void bar(); + +int main() +{ + bar(); + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/indirect-path-search/Makefile b/FireOpal/unit-tests/test-cases/indirect-path-search/Makefile new file mode 100644 index 0000000..e79eb0f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/indirect-path-search/Makefile @@ -0,0 +1,106 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Test that -F and -L work when finding indirect libraries +# + + +run: all + +all: + +# build foo that re-exports bar + ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib + ${FAIL_IF_BAD_MACHO} libbar.dylib + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lbar -L. -sub_library libbar + ${FAIL_IF_BAD_MACHO} libfoo.dylib + +# build an alternate libbar that also has baz + mkdir -p hide + ${CC} ${CCFLAGS} -dynamiclib bar.c baz.c -o hide/libbar.dylib -install_name libbar.dylib + ${FAIL_IF_BAD_MACHO} hide/libbar.dylib + +# build an executable that depends on a symbol in the alternate bar to validate that -L is used for indirect dylibs + ${CC} ${CCFLAGS} main.c -o main -lfoo -Lhide -L. + ${FAIL_IF_BAD_MACHO} main + + + +# build Foo.framework that re-exports Bar.framework + mkdir -p Bar.framework Foo.framework + ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" + ${FAIL_IF_BAD_MACHO} Bar.framework/Bar + ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -framework Bar -sub_umbrella Bar + ${FAIL_IF_BAD_MACHO} Foo.framework/Foo + +# build an alternate Bar.framework that also has baz + mkdir -p hide/Bar.framework + ${CC} ${CCFLAGS} -dynamiclib bar.c baz.c -o hide/Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" + ${FAIL_IF_BAD_MACHO} hide/Bar.framework/Bar + +# build an executable that depends on a symbol in the alternate Bar.framework to validate that -F is used for indirect dylibs + ${CC} ${CCFLAGS} main.c -o main -Fhide -F. -framework Foo + ${FAIL_IF_BAD_MACHO} main + + + +# build foo that links against bar + ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib + ${FAIL_IF_BAD_MACHO} libbar.dylib + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib + ${FAIL_IF_BAD_MACHO} libfoo.dylib + +# build an alternate libbar that also has baz + mkdir -p hide + ${CC} ${CCFLAGS} -dynamiclib bar.c baz.c -o hide/libbar.dylib -install_name libbar.dylib + ${FAIL_IF_BAD_MACHO} hide/libbar.dylib + +# build a flat executable that depends on a symbol in the alternate bar to validate that -L is used for indirect dylibs + ${CC} ${CCFLAGS} -flat_namespace main.c -o main -lfoo -Lhide -L. + ${FAIL_IF_BAD_MACHO} main + + + +# build Foo.framework that re-exports libbar.dylib embedded in framework + mkdir -p Foo.framework + ${CC} ${CCFLAGS} -dynamiclib bar.c baz.c -o Foo.framework/libbar.dylib -install_name "`pwd`/Foo.framework/libbar.dylib" + ${FAIL_IF_BAD_MACHO} Foo.framework/libbar.dylib + ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. Foo.framework/libbar.dylib -sub_library libbar + ${FAIL_IF_BAD_MACHO} Foo.framework/Foo + +# build an alternate libbar.dylib that does not have baz + mkdir -p hide + ${CC} ${CCFLAGS} -dynamiclib bar.c -o hide/libbar.dylib + ${FAIL_IF_BAD_MACHO} hide/libbar.dylib + +# build an executable that depends on a symbol not in the alternate libbar.dylib to validate dylibs embedded in frameworks are not searched for + ${CC} ${CCFLAGS} main.c -o main -Lhide -F. -framework Foo + ${PASS_IFF_GOOD_MACHO} main + + +clean: + + rm -rf hide libbar.dylib libfoo.dylib Foo.framework Bar.framework main diff --git a/FireOpal/unit-tests/test-cases/indirect-path-search/bar.c b/FireOpal/unit-tests/test-cases/indirect-path-search/bar.c new file mode 100644 index 0000000..9c18401 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/indirect-path-search/bar.c @@ -0,0 +1,5 @@ + +int bar (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/indirect-path-search/baz.c b/FireOpal/unit-tests/test-cases/indirect-path-search/baz.c new file mode 100644 index 0000000..af6a9f8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/indirect-path-search/baz.c @@ -0,0 +1,5 @@ + +int baz (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/indirect-path-search/foo.c b/FireOpal/unit-tests/test-cases/indirect-path-search/foo.c new file mode 100644 index 0000000..d0cdf47 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/indirect-path-search/foo.c @@ -0,0 +1,4 @@ +int foo (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/indirect-path-search/main.c b/FireOpal/unit-tests/test-cases/indirect-path-search/main.c new file mode 100644 index 0000000..f02701a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/indirect-path-search/main.c @@ -0,0 +1,8 @@ +extern int foo (); +extern int bar (); +extern int baz (); + +int main (void) +{ + return foo() + bar() + baz(); +} diff --git a/FireOpal/unit-tests/test-cases/interposable_list/Makefile b/FireOpal/unit-tests/test-cases/interposable_list/Makefile new file mode 100644 index 0000000..2fe99a8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/interposable_list/Makefile @@ -0,0 +1,47 @@ +## +# Copyright (c) 2007 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 -interposable and -interposable_list work +# + +run: all + +all: + # by default, no test* functions should go through stubs + ${CC} ${CCFLAGS} test.c -dynamiclib -o libtest.dylib + # -interposable should make all four test* functions go through stubs + ${CC} ${CCFLAGS} test.c -dynamiclib -Wl,-interposable -o libtest.dylib + otool -Iv libtest.dylib | grep '4 entries' | ${FAIL_IF_EMPTY} + otool -Iv libtest.dylib | grep '_test' | ${FAIL_IF_EMPTY} + # -interposable_list should make just two test* functions go through stubs + ${CC} ${CCFLAGS} test.c -dynamiclib -Wl,-interposable_list test.exp -o libtest.dylib + otool -Iv libtest.dylib | grep '2 entries' | ${FAIL_IF_EMPTY} + otool -Iv libtest.dylib | grep '_test3' | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} libtest.dylib + + +clean: + rm libtest.dylib diff --git a/FireOpal/unit-tests/test-cases/interposable_list/test.c b/FireOpal/unit-tests/test-cases/interposable_list/test.c new file mode 100644 index 0000000..937420e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/interposable_list/test.c @@ -0,0 +1,57 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 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 + +const char kMyStr[] = "hello"; + +int test1() +{ + return 10; +} + +int test2() +{ + return 10; +} + +int test3() +{ + return 10; +} + +int test4() +{ + return 10; +} + +const char* getstr() +{ + test1(); + test2(); + test3(); + test4(); + return kMyStr; +} + + diff --git a/FireOpal/unit-tests/test-cases/interposable_list/test.exp b/FireOpal/unit-tests/test-cases/interposable_list/test.exp new file mode 100644 index 0000000..8f104f1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/interposable_list/test.exp @@ -0,0 +1,2 @@ +_test1 +_test2 diff --git a/FireOpal/unit-tests/test-cases/large-data/Makefile b/FireOpal/unit-tests/test-cases/large-data/Makefile new file mode 100644 index 0000000..408a2da --- /dev/null +++ b/FireOpal/unit-tests/test-cases/large-data/Makefile @@ -0,0 +1,50 @@ +## +# Copyright (c) 2007 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 ld can link > 4GB zero fill section +# + +SHELL = bash # use bash shell so we can redirect just stderr + +ifeq (,${findstring 64,$(ARCH)}) + 32BIT_SHOULD_FAIL = ${FAIL_IF_SUCCESS} +else + 32BIT_SHOULD_FAIL = +endif + + +run: all + +all: + ${CC} ${CCFLAGS} test1.c -c -o test1.o + ${CC} ${CCFLAGS} test2.c -c -o test2.o + ${CC} ${CCFLAGS} test3.c -c -o test3.o + ${CC} ${CCFLAGS} test4.c -c -o test4.o + ${32BIT_SHOULD_FAIL} ${CC} ${CCFLAGS} test1.o test2.o test3.o test4.o -dynamiclib -o libtest.dylib 2> fail.log + ${PASS_IFF} true + +clean: + rm -rf test*.o libtest.dylib fail.log diff --git a/FireOpal/unit-tests/test-cases/large-data/test1.c b/FireOpal/unit-tests/test-cases/large-data/test1.c new file mode 100644 index 0000000..2d9ec94 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/large-data/test1.c @@ -0,0 +1,42 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 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@ + */ + +int mediumarray1[1000]; +int bigarray1[500000000]; // just under 2GB array +int small1; + +int getbig1() +{ + return bigarray1[0]; +} + +int getmedium1() +{ + return mediumarray1[0]; +} + +int getsmall1() +{ + return small1; +} diff --git a/FireOpal/unit-tests/test-cases/large-data/test2.c b/FireOpal/unit-tests/test-cases/large-data/test2.c new file mode 100644 index 0000000..d97bed1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/large-data/test2.c @@ -0,0 +1,37 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 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@ + */ + +int bigarray2[500000000]; // just under 2GB array +int small2; + +int getbig2() +{ + return bigarray2[0]; +} + + +int getsmall2() +{ + return small2; +} diff --git a/FireOpal/unit-tests/test-cases/large-data/test3.c b/FireOpal/unit-tests/test-cases/large-data/test3.c new file mode 100644 index 0000000..b7ca398 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/large-data/test3.c @@ -0,0 +1,37 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 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@ + */ + +int bigarray3[500000000]; // just under 2GB array +int small3; + +int getbig3() +{ + return bigarray3[0]; +} + + +int getsmall3() +{ + return small3; +} diff --git a/FireOpal/unit-tests/test-cases/large-data/test4.c b/FireOpal/unit-tests/test-cases/large-data/test4.c new file mode 100644 index 0000000..d879c5c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/large-data/test4.c @@ -0,0 +1,37 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 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@ + */ + +int bigarray4[500000000]; // just under 2GB array +int small4; + +int getbig4() +{ + return bigarray4[0]; +} + + +int getsmall4() +{ + return small4; +} diff --git a/FireOpal/unit-tests/test-cases/late-link-error/Makefile b/FireOpal/unit-tests/test-cases/late-link-error/Makefile new file mode 100644 index 0000000..e3a0d65 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/late-link-error/Makefile @@ -0,0 +1,41 @@ +## +# Copyright (c) 2006 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 + + +# +# The point of this test is a sanity check that if +# ld errors out during linking, that no output file is remaining +# + +run: all + +all: + ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} link_error.s -dynamiclib -o link_error-${ARCH} 2> fail.log + ${FAIL_IFF} cat link_error-${ARCH} 2> fail.log + +clean: + rm link_error-* fail.log diff --git a/FireOpal/unit-tests/test-cases/late-link-error/comment.txt b/FireOpal/unit-tests/test-cases/late-link-error/comment.txt new file mode 100644 index 0000000..716686d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/late-link-error/comment.txt @@ -0,0 +1,2 @@ +The point of this test is a sanity check that if +ld errors out during linking, that no output file is remaining diff --git a/FireOpal/unit-tests/test-cases/late-link-error/link_error.s b/FireOpal/unit-tests/test-cases/late-link-error/link_error.s new file mode 100644 index 0000000..05d80f1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/late-link-error/link_error.s @@ -0,0 +1,22 @@ + + +#if __ppc__ || __ppc64__ + ; illegal absolute load +_foo: lis r2,ha16(_strcmp) +#endif + +#if __i386__ + // illegal absolute load +_foo: movl _strcmp, %eax +#endif + + +#if __x86_64__ + // illegal external load +_foo: movl _strcmp(%rip), %eax +#endif + +#if __arm__ + ; illegal absolute load +_foo: ldr r2, _strcmp +#endif diff --git a/FireOpal/unit-tests/test-cases/lazy-dylib-objc/Makefile b/FireOpal/unit-tests/test-cases/lazy-dylib-objc/Makefile new file mode 100644 index 0000000..975ad29 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/lazy-dylib-objc/Makefile @@ -0,0 +1,45 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + + +SHELL = bash # use bash shell so we can redirect just stderr + + +# +# Verify that -lazy_library fails if an objc class is referenced +# + +run: all + +all: + ${CC} ${CCFLAGS} foo.m -dynamiclib -o libfoo.dylib -framework Foundation + ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.m -Wl,-lazy_library,libfoo.dylib -o main -framework Foundation 2> fail.log + ${CC} ${CCFLAGS} main.m libfoo.dylib -o main -framework Foundation + ${PASS_IFF_GOOD_MACHO} main + + + +clean: + rm libfoo.dylib main rm fail.log diff --git a/FireOpal/unit-tests/test-cases/lazy-dylib-objc/foo.h b/FireOpal/unit-tests/test-cases/lazy-dylib-objc/foo.h new file mode 100644 index 0000000..eaa591f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/lazy-dylib-objc/foo.h @@ -0,0 +1,9 @@ + +#include + + +@interface Foo : NSObject + + + +@end diff --git a/FireOpal/unit-tests/test-cases/lazy-dylib-objc/foo.m b/FireOpal/unit-tests/test-cases/lazy-dylib-objc/foo.m new file mode 100644 index 0000000..35a63b1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/lazy-dylib-objc/foo.m @@ -0,0 +1,8 @@ + +#include "foo.h" + +@implementation Foo + + + +@end diff --git a/FireOpal/unit-tests/test-cases/lazy-dylib-objc/main.m b/FireOpal/unit-tests/test-cases/lazy-dylib-objc/main.m new file mode 100644 index 0000000..0f11f68 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/lazy-dylib-objc/main.m @@ -0,0 +1,12 @@ +#include +#include + +#include "foo.h" + + +int main() +{ + [[Foo alloc] init]; + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/lazy-dylib/Makefile b/FireOpal/unit-tests/test-cases/lazy-dylib/Makefile new file mode 100644 index 0000000..e3d0d6a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/lazy-dylib/Makefile @@ -0,0 +1,46 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +SHELL = bash # use bash shell so we can redirect just stderr + +# +# Verify that -lazy_library works for function calls +# but fails for data references +# + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib + ${CC} ${CCFLAGS} main.c -Wl,-lazy_library,libfoo.dylib -o main + ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bad.c -Wl,-lazy_library,libfoo.dylib -o bad 2> fail.log + ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bad2.c -Wl,-lazy_library,libfoo.dylib -o bad2 2> fail.log + + + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -f libfoo.dylib main bad bad2 fail.log + diff --git a/FireOpal/unit-tests/test-cases/lazy-dylib/bad.c b/FireOpal/unit-tests/test-cases/lazy-dylib/bad.c new file mode 100644 index 0000000..59a13fb --- /dev/null +++ b/FireOpal/unit-tests/test-cases/lazy-dylib/bad.c @@ -0,0 +1,12 @@ +#include +#include + + +extern int data; + +static int* pd = &data; + +int main() +{ + return *pd; +} diff --git a/FireOpal/unit-tests/test-cases/lazy-dylib/bad2.c b/FireOpal/unit-tests/test-cases/lazy-dylib/bad2.c new file mode 100644 index 0000000..ffd2ce1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/lazy-dylib/bad2.c @@ -0,0 +1,13 @@ +#include +#include + + +extern int foo(); + +int main() +{ + int (*func)() = foo; + if ( func != NULL ) + (*func)(); + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/lazy-dylib/foo.c b/FireOpal/unit-tests/test-cases/lazy-dylib/foo.c new file mode 100644 index 0000000..c23c9dc --- /dev/null +++ b/FireOpal/unit-tests/test-cases/lazy-dylib/foo.c @@ -0,0 +1,5 @@ + +int data = 5; + +int foo() { return 1; } +int bar() { return 1; } diff --git a/FireOpal/unit-tests/test-cases/lazy-dylib/main.c b/FireOpal/unit-tests/test-cases/lazy-dylib/main.c new file mode 100644 index 0000000..8546854 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/lazy-dylib/main.c @@ -0,0 +1,18 @@ +#include +#include + + +extern int foo(); +extern int bar(); + +int main() +{ + // two regular external function calls + void* x = malloc(16); + free(x); + // two lazy dylib external function calls + int result = foo(); + fprintf(stderr, "foo() returned %d\n", result); + bar(); + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce-alignment/Makefile b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment/Makefile new file mode 100644 index 0000000..15f3307 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment/Makefile @@ -0,0 +1,46 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is to verify that when two cstrings +# are coalesced that the one with greater alignment is used. +# + +run: all + +all: + ${CC} ${ASMFLAGS} cstring-align-0.s -c -o cstring-align-0-${ARCH}.o + ${FAIL_IF_BAD_OBJ} cstring-align-0-${ARCH}.o + + ${CC} ${ASMFLAGS} cstring-align-3.s -c -o cstring-align-3-${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} cstring-align-3-${ARCH}.o | grep 'align:' > align-3 + + ${LD} -arch ${ARCH} -r cstring-align-0-${ARCH}.o cstring-align-3-${ARCH}.o -o cstring-r-${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} cstring-r-${ARCH}.o | grep 'align:' > align-r + + ${PASS_IFF} diff align-3 align-r + +clean: + rm -rf *.o align-3 align-r diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce-alignment/cstring-align-0.s b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment/cstring-align-0.s new file mode 100644 index 0000000..0dacbad --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment/cstring-align-0.s @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2006 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@ + */ + + + .cstring +L21: .ascii "hello\0" diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce-alignment/cstring-align-3.s b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment/cstring-align-3.s new file mode 100644 index 0000000..d2661dc --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment/cstring-align-3.s @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2006 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@ + */ + + .cstring + .align 3 +L21: .ascii "hello\0" diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/Makefile b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/Makefile new file mode 100644 index 0000000..c3c8c80 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/Makefile @@ -0,0 +1,47 @@ +## +# Copyright (c) 2006 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 + +LD=ld + +# +# The point of this test is to verify that when two cstrings +# are coalesced that the one with greater alignment is used. +# + +run: all + +all: + ${CC} ${ASMFLAGS} cstring-align-0.s -c -o cstring-align-0-${ARCH}.o + ${FAIL_IF_BAD_OBJ} cstring-align-0-${ARCH}.o + + ${CC} ${ASMFLAGS} cstring-align-3.s -c -o cstring-align-3-${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -align -only cstring=hello cstring-align-3-${ARCH}.o > align-3 + + ${LD} -arch ${ARCH} -r cstring-align-0-${ARCH}.o cstring-align-3-${ARCH}.o -o cstring-r-${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -align -only cstring=hello cstring-r-${ARCH}.o > align-r + ${PASS_IFF} diff -C 6 align-3 align-r + +clean: + rm -rf *.o align-3 align-r diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/comment.txt b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/comment.txt new file mode 100644 index 0000000..3b2e3c7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/comment.txt @@ -0,0 +1 @@ +The point of this test is to verify that when two cstrings are coalesced that the one with greater alignment is used. diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/cstring-align-0.s b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/cstring-align-0.s new file mode 100644 index 0000000..1a55cf6 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/cstring-align-0.s @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2006 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@ + */ + + + .cstring +L20: .asciz "XXX" +L22: .ascii "hell\0" diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/cstring-align-3.s b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/cstring-align-3.s new file mode 100644 index 0000000..211aa72 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment2/cstring-align-3.s @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2006 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@ + */ + + .cstring + .align 2 +L21: .ascii "hell\0" + .align 13 +L99: .ascii "\0" diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/Makefile b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/Makefile new file mode 100644 index 0000000..cac20b9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/Makefile @@ -0,0 +1,48 @@ +## +# Copyright (c) 2006 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 + +#LD=ld64 + +# +# The point of this test is to verify that when two cstrings +# are coalesced that the one with greater alignment is used. +# + +run: all + +all: + ${CC} ${ASMFLAGS} cstring-align-0.s -c -o cstring-align-0-${ARCH}.o + ${FAIL_IF_BAD_OBJ} cstring-align-0-${ARCH}.o + + ${CC} ${ASMFLAGS} cstring-align-3.s -c -o cstring-align-3-${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -align -only cstring=hello cstring-align-3-${ARCH}.o > align-3 + + ${LD} -arch ${ARCH} -r cstring-align-0-${ARCH}.o cstring-align-3-${ARCH}.o -o cstring-r-${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -align -only cstring=hello cstring-r-${ARCH}.o > align-r + + ${PASS_IFF} diff -C 6 align-3 align-r + +clean: + rm -rf *.o align-3 align-r diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/comment.txt b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/comment.txt new file mode 100644 index 0000000..3b2e3c7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/comment.txt @@ -0,0 +1 @@ +The point of this test is to verify that when two cstrings are coalesced that the one with greater alignment is used. diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/cstring-align-0.s b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/cstring-align-0.s new file mode 100644 index 0000000..1a55cf6 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/cstring-align-0.s @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2006 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@ + */ + + + .cstring +L20: .asciz "XXX" +L22: .ascii "hell\0" diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/cstring-align-3.s b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/cstring-align-3.s new file mode 100644 index 0000000..211aa72 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce-alignment3/cstring-align-3.s @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2006 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@ + */ + + .cstring + .align 2 +L21: .ascii "hell\0" + .align 13 +L99: .ascii "\0" diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce/Makefile b/FireOpal/unit-tests/test-cases/literals-coalesce/Makefile new file mode 100644 index 0000000..dcf1dbe --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce/Makefile @@ -0,0 +1,40 @@ +## +# 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 + +# +# The point of this test is to verify that literals are uniqued. +# After running ld -r all duplicates should be removed. +# + +run: all + +all: + ${CC} ${ASMFLAGS} literals.s -c -o literals-${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} literals-${ARCH}.o | grep 'name:'| uniq -c | grep -v '^ [1|2]' | ${FAIL_IF_STDIN} + ${LD} -arch ${ARCH} -r literals-${ARCH}.o -o literals-r-${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} literals-r-${ARCH}.o | grep 'name:' | uniq -d | ${PASS_IFF_EMPTY} + +clean: + rm -rf *.o diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce/literals.s b/FireOpal/unit-tests/test-cases/literals-coalesce/literals.s new file mode 100644 index 0000000..6e5febc --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce/literals.s @@ -0,0 +1,69 @@ +/* + * 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@ + */ + + .literal16 +L01:.long 12345678 + .long 87654321 + .long 12345678 + .long 87654321 + +L02:.long 12345678 + .long 87654321 + .long 12345678 + .long 87654322 + +L03:.long 22345678 + .long 87654321 + .long 12345678 + .long 87654321 + +L04:.long 12345678 + .long 87654321 + .long 12345678 + .long 87654321 + + + .literal8 +L1: .long 12345678 + .long 87654321 + +L2: .long 12345678 + .long 87654322 + +L3: .long 22345678 + .long 87654321 + +L4: .long 12345678 + .long 87654321 + + .literal4 +L11:.long 12345678 +L12:.long 12345679 +L13:.long 22345678 +L14:.long 12345678 + + .cstring +L21: .ascii "hello\0" +L22: .ascii "hello,there\0" +L23: .ascii "there\0" +L24: .ascii "hello\0" diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce2/Makefile.newtest b/FireOpal/unit-tests/test-cases/literals-coalesce2/Makefile.newtest new file mode 100644 index 0000000..0f9d1b5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce2/Makefile.newtest @@ -0,0 +1,40 @@ +## +# 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 + +# +# The point of this test is to verify that literals are uniqued. +# After running ld -r all duplicates should be removed. +# + +run: all + +all: + ${FAIL_IF_ERROR} ${CC} ${ASMFLAGS} literals.s -c -o literals-${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -only literals-${ARCH}.o | uniq -c | grep -v '^ [1|2]' | ${FAIL_IF_STDIN} + ${FAIL_IF_ERROR} ${LD} -arch ${ARCH} -r literals-${ARCH}.o -o literals-r-${ARCH}.o + ${PASS_IFF} ./test.sh literals-r-${ARCH}.o + +clean: + rm -rf *.o diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce2/comment.txt b/FireOpal/unit-tests/test-cases/literals-coalesce2/comment.txt new file mode 100644 index 0000000..56cea21 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce2/comment.txt @@ -0,0 +1 @@ +The point of this test is to verify that literals are uniqued. After running ld -r all duplicates should be removed. diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce2/literals.s b/FireOpal/unit-tests/test-cases/literals-coalesce2/literals.s new file mode 100644 index 0000000..b8d4354 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce2/literals.s @@ -0,0 +1,48 @@ +/* + * 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@ + */ + + .literal8 + +L1: .long 12345678 + .long 87654321 + +L2: .long 12345678 + .long 87654322 + +L3: .long 22345678 + .long 87654321 + +L4: .long 12345678 + .long 87654321 + + .literal4 +L11:.long 12345678 +L12:.long 12345679 +L13:.long 22345678 +L14:.long 12345678 + + .cstring +L21: .ascii "hello\0" +L22: .ascii "hello,there\0" +L23: .ascii "there\0" +L24: .ascii "hello\0" diff --git a/FireOpal/unit-tests/test-cases/literals-coalesce2/test.sh b/FireOpal/unit-tests/test-cases/literals-coalesce2/test.sh new file mode 100755 index 0000000..57a36b7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/literals-coalesce2/test.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +SZ=`size "$1" | tail -n 1 | sed 's,\([0-9]*\).*,\1,'` +[ "$SZ" ] && [ "$SZ" = 54 ] && exit 0 +exit 1 diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/Makefile b/FireOpal/unit-tests/test-cases/llvm-integration/Makefile new file mode 100644 index 0000000..42c71e4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/Makefile @@ -0,0 +1,289 @@ +## +# Copyright (c) 2006-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@ +## +TESTROOT = ../.. + +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 + +# +# Test the we set the stack execution bit properly. + +run: + if [ -f /Developer/usr/bin/llvm-gcc-4.2 ] ; then \ + $(MAKE) all ; \ + else \ + ${PASS_IFF} /usr/bin/true ; \ + fi + +all: zero one two three four five six seven eight nine ten \ + eleven twelve thirteen fourteen fifteen sixteen seventeen \ + eighteen nineteen twenty + + +zero: + # + # llvm : a.c : Dfoo3 + # llvm : b.c : Dfoo2 + # 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 + ${PASS_IFF_GOOD_MACHO} main.exe + +one: + # + # llvm : a1.c : Dfoo3, Ufoo4 + # llvm : b1.c : Dfoo2, Ufoo4 + # 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 + ${PASS_IFF_GOOD_MACHO} main1.exe + +two: + # + # llvm : a2.c : Dfoo3, Ufoo4 + # llvm : b2.c : Dfoo2, Dfoo4 + # 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 + ${PASS_IFF_GOOD_MACHO} main2.exe + +three: + # + # llvm : a3.c : Dfoo1, Dbar + # llvm : b3.c : Dfoo2, Ubar + # 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 + ${PASS_IFF_GOOD_MACHO} main3.exe + +four: + # + # llvm : a4.c : Dfoo3, Ufoo4 + # llvm : b4.c : Dfoo2, DLmyfoo, Ufoo4 + # 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 + ${PASS_IFF_GOOD_MACHO} main4.exe + +five: + # + # llvm : a5.c : Dfoo1, Ufoo2, Ufoo3 + # llvm : b5.c : Dfoo2 + # MachO : main5.c : Dfoo3, Ufoo1 + # + #echo "Five..." + ${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 + ${OTOOL} -tV main5.exe | grep foo3 | ${PASS_IFF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main5.exe + +six: + # + # llvm : a6.c : Dfoo1, Dfoo2 + # 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 + ${PASS_IFF_GOOD_MACHO} main6.exe + ${OTOOL} -tV main6.exe | grep foo2 | ${PASS_IFF_EMPTY} + +seven: + # + # llvm : a7.c : Dfoo1, Dfoo2, Ufoo3 + # llvm : b7.c : Dfoo3, ufoo2 + # 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 + ${PASS_IFF_GOOD_MACHO} main7.exe + +eight: + # + # llvm : a8.c : Dfoo1, Dfoo2 + # 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 + ${OTOOL} -tV main8.exe | grep foo2 | ${PASS_IFF_EMPTY} + ${OTOOL} -tV main8.exe | grep unnamed_2_1 | ${PASS_IFF_EMPTY} + +nine: + # + # llvm : a9.c : Dfoo1, Dfoo2, Dfoo3, Ufoo3, Ufoo4 + # 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 + ${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} + +ten: + # + # llvm : a10.c + # llvm : b10.c + # 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 + ${PASS_IFF_GOOD_MACHO} main10.exe + +eleven: + # + # llvm : a11.c + # 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 + ${PASS_IFF_GOOD_MACHO} main11.exe + +twelve: + # + # llvm : a12.c + # MachO : main12.c + # + #echo "Tweleve..." + ${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 + ${PASS_IFF_GOOD_MACHO} main12.exe + +thirteen: + # + # llvm : a13.cc + # 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 + +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 + ${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 + ${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 + ${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 + ${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 + ${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 b17.o + ${LD} -arch ${ARCH} -r a17.o b17.o -o ab17.o + file ab17.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 + ${LD} -arch ${ARCH} -r -keep_private_externs a18.o -o a18-rkpe.o + ObjectDump -nm a18-rkpe.o | grep _common_hidden1 | grep " hidden" | ${FAIL_IF_EMPTY} + ObjectDump -nm a18-rkpe.o | grep _func_hidden2 | grep " hidden" | ${FAIL_IF_EMPTY} + #echo verify ld -r makes hidden symbols internal (except for commons) + ${LD} -arch ${ARCH} -r a18.o -o a18-r.o + #ObjectDump -nm a18-r.o | grep _common_hidden1 | grep " hidden" | ${FAIL_IF_EMPTY} + #ObjectDump -nm a18-r.o | grep _func_hidden2 | grep " internal" | ${FAIL_IF_EMPTY} + +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 + 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 + ar cru lib20.a a20.o b20.o + ${LLVMGCC} ${CCFLAGS} main20.c lib20.a -all_load -o main20.exe + nm main20.exe | grep _foo | ${PASS_IFF_STDIN} + + + + +clean: + rm -rf *.o main*.exe big.* *.dylib main16.exe.lto.bc fail.log lib20.a + diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a.c b/FireOpal/unit-tests/test-cases/llvm-integration/a.c new file mode 100644 index 0000000..0c96178 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a.c @@ -0,0 +1,5 @@ +int foo3() +{ + return 21; +} + diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a1.c b/FireOpal/unit-tests/test-cases/llvm-integration/a1.c new file mode 100644 index 0000000..f9fb403 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a1.c @@ -0,0 +1,10 @@ +#include +#include +#include +extern int foo4(); +int foo3() +{ +/* printf ("%s\n",strerror(errno)); */ + return foo4(); +} + diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a10.c b/FireOpal/unit-tests/test-cases/llvm-integration/a10.c new file mode 100644 index 0000000..0dc181e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a10.c @@ -0,0 +1,5 @@ +extern void foo(void); + +void foo(void) +{ +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a11.c b/FireOpal/unit-tests/test-cases/llvm-integration/a11.c new file mode 100644 index 0000000..e95dc40 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a11.c @@ -0,0 +1,6 @@ +#include +void foo3(void) +{ + fputc ('x', stderr); + printf ("\n"); +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a12.c b/FireOpal/unit-tests/test-cases/llvm-integration/a12.c new file mode 100644 index 0000000..80bc1e8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a12.c @@ -0,0 +1,8 @@ +#include "a12.h" + +enum E e[1000]; +void foo(void) +{ + e[1] = ONE; +} + diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a12.h b/FireOpal/unit-tests/test-cases/llvm-integration/a12.h new file mode 100644 index 0000000..be43955 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a12.h @@ -0,0 +1,8 @@ +enum E + { + ZERO, + ONE + }; + +extern enum E e[1000]; +extern void foo(void); diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a13.cc b/FireOpal/unit-tests/test-cases/llvm-integration/a13.cc new file mode 100644 index 0000000..edc938a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a13.cc @@ -0,0 +1,3 @@ +#include "a13.h" + +A::~A() {} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a13.h b/FireOpal/unit-tests/test-cases/llvm-integration/a13.h new file mode 100644 index 0000000..bc00448 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a13.h @@ -0,0 +1,7 @@ +#include + +class A { + public: + virtual ~A(); + void foo() { printf ("Hi\n"); } +}; diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a14.c b/FireOpal/unit-tests/test-cases/llvm-integration/a14.c new file mode 100644 index 0000000..8f4ea09 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a14.c @@ -0,0 +1 @@ +int X __attribute__((visibility("hidden"))) = 14; diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a15.c b/FireOpal/unit-tests/test-cases/llvm-integration/a15.c new file mode 100644 index 0000000..a25431b --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a15.c @@ -0,0 +1,3 @@ +void __attribute__((visibility("hidden"))) foo() +{ +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a17.c b/FireOpal/unit-tests/test-cases/llvm-integration/a17.c new file mode 100644 index 0000000..3cd06fd --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a17.c @@ -0,0 +1,4 @@ + +int a = 0; +int func_a() { return a; } + diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a18.c b/FireOpal/unit-tests/test-cases/llvm-integration/a18.c new file mode 100644 index 0000000..c9fdc35 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a18.c @@ -0,0 +1,18 @@ + + + +static int data_static1 = 1; +static int data_static2 = 2; + +void func_global1() { ++data_static1; } +void func_global2() { ++data_static2; } + +void __attribute__((visibility("hidden"))) func_hidden1() {} +void __attribute__((visibility("hidden"))) func_hidden2() {} + +int common_global1; +int common_global2; + +int __attribute__((visibility("hidden"))) common_hidden1; +int __attribute__((visibility("hidden"))) common_hidden2; + diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a2.c b/FireOpal/unit-tests/test-cases/llvm-integration/a2.c new file mode 100644 index 0000000..0eb20c5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a2.c @@ -0,0 +1,6 @@ +extern int foo4(void); +int foo3() +{ + return foo4(); +} + diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a20.c b/FireOpal/unit-tests/test-cases/llvm-integration/a20.c new file mode 100644 index 0000000..cd52955 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a20.c @@ -0,0 +1,2 @@ +void foo() {} +void bar() {} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a3.c b/FireOpal/unit-tests/test-cases/llvm-integration/a3.c new file mode 100644 index 0000000..040ca5f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a3.c @@ -0,0 +1,6 @@ +int bar; +int foo1() +{ + return bar; +} + diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a4.c b/FireOpal/unit-tests/test-cases/llvm-integration/a4.c new file mode 100644 index 0000000..0eb20c5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a4.c @@ -0,0 +1,6 @@ +extern int foo4(void); +int foo3() +{ + return foo4(); +} + diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a5.c b/FireOpal/unit-tests/test-cases/llvm-integration/a5.c new file mode 100644 index 0000000..bcb22d9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a5.c @@ -0,0 +1,10 @@ +extern int foo2(void); +extern int foo3(void); + +int foo1() +{ + int i = 42; + if (foo2()) + i = foo3(); + return i; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a6.c b/FireOpal/unit-tests/test-cases/llvm-integration/a6.c new file mode 100644 index 0000000..b621453 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a6.c @@ -0,0 +1,10 @@ + +int foo1() +{ + return 42; +} + +int foo2() +{ + return 21; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a7.c b/FireOpal/unit-tests/test-cases/llvm-integration/a7.c new file mode 100644 index 0000000..560919a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a7.c @@ -0,0 +1,11 @@ +extern int foo3(void); + +int foo1(void) +{ + return foo3(); +} + +int foo2(void) +{ + return 42; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a8.c b/FireOpal/unit-tests/test-cases/llvm-integration/a8.c new file mode 100644 index 0000000..47352a7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a8.c @@ -0,0 +1,23 @@ + +static signed int i = 0; +extern int foo1(void); +extern void foo2(void); + +void foo2(void) { + + i = -1; + +} + +static int foo3() { + return 10; +} + +int foo1(void) +{ + int data = 0; + if (i < 0) + data = foo3(); + data += 42; + return data; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a9.c b/FireOpal/unit-tests/test-cases/llvm-integration/a9.c new file mode 100644 index 0000000..da2c8fa --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a9.c @@ -0,0 +1,25 @@ + +static signed int i = 0; +extern int foo1(void); +extern void foo2(void); +extern void foo4(void); + +void foo2(void) { + + i = -1; + +} + +static int foo3() { + foo4(); + return 10; +} + +int foo1(void) +{ + int data = 0; + if (i < 0) + data = foo3(); + data += 42; + return data; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/a9.list b/FireOpal/unit-tests/test-cases/llvm-integration/a9.list new file mode 100644 index 0000000..583bc2f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/a9.list @@ -0,0 +1,3 @@ +_foo1 +_main +_bar diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/b.c b/FireOpal/unit-tests/test-cases/llvm-integration/b.c new file mode 100644 index 0000000..61c92dc --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/b.c @@ -0,0 +1,3 @@ +int foo2() { + return 21; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/b1.c b/FireOpal/unit-tests/test-cases/llvm-integration/b1.c new file mode 100644 index 0000000..5158abe --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/b1.c @@ -0,0 +1,4 @@ +extern int foo4(); +int foo2() { + return foo4(); +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/b10.c b/FireOpal/unit-tests/test-cases/llvm-integration/b10.c new file mode 100644 index 0000000..d899aa9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/b10.c @@ -0,0 +1,7 @@ +#include "b10.h" +extern void foo(void); + +struct my_struct my_hooks = { + foo +}; + diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/b10.h b/FireOpal/unit-tests/test-cases/llvm-integration/b10.h new file mode 100644 index 0000000..fcb50d2 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/b10.h @@ -0,0 +1,6 @@ +struct my_struct +{ + void (*f)(void); +}; + +extern struct my_struct my_hooks; diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/b14.c b/FireOpal/unit-tests/test-cases/llvm-integration/b14.c new file mode 100644 index 0000000..59c5120 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/b14.c @@ -0,0 +1,7 @@ +#include + +int Y; +extern int X __attribute__((visibility("hidden"))); +void foo() { + printf ("%d\n", X); +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/b15.c b/FireOpal/unit-tests/test-cases/llvm-integration/b15.c new file mode 100644 index 0000000..13c88d7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/b15.c @@ -0,0 +1,8 @@ +extern void foo(); +void bar() { + foo(); +} + +void __attribute__((visibility("hidden"))) f2() +{} + diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/b17.c b/FireOpal/unit-tests/test-cases/llvm-integration/b17.c new file mode 100644 index 0000000..47d4cc3 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/b17.c @@ -0,0 +1,4 @@ +int b = 0; +int func_b() { return b; } + + diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/b2.c b/FireOpal/unit-tests/test-cases/llvm-integration/b2.c new file mode 100644 index 0000000..a20f6e3 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/b2.c @@ -0,0 +1,9 @@ +extern int foo4(void); + +int foo4(void) +{ + return 21; +} +int foo2() { + return foo4(); +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/b20.c b/FireOpal/unit-tests/test-cases/llvm-integration/b20.c new file mode 100644 index 0000000..f6c0ed3 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/b20.c @@ -0,0 +1 @@ +void frob() {} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/b3.c b/FireOpal/unit-tests/test-cases/llvm-integration/b3.c new file mode 100644 index 0000000..31e7ee8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/b3.c @@ -0,0 +1,4 @@ +extern int bar; +int foo2() { + return bar; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/b4.c b/FireOpal/unit-tests/test-cases/llvm-integration/b4.c new file mode 100644 index 0000000..9437ad0 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/b4.c @@ -0,0 +1,13 @@ +extern int foo4(void); + +int foo4(void) +{ + return 21; +} +static int myfoo() +{ + return foo4(); +} +int foo2() { + return myfoo(); +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/b5.c b/FireOpal/unit-tests/test-cases/llvm-integration/b5.c new file mode 100644 index 0000000..a105df9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/b5.c @@ -0,0 +1,4 @@ +int foo2(void) +{ + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/b7.c b/FireOpal/unit-tests/test-cases/llvm-integration/b7.c new file mode 100644 index 0000000..d34f91a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/b7.c @@ -0,0 +1,7 @@ +extern int foo2(void); +extern int foo3(void); + +int foo3(void) +{ + return foo2(); +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/c15.c b/FireOpal/unit-tests/test-cases/llvm-integration/c15.c new file mode 100644 index 0000000..0089d64 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/c15.c @@ -0,0 +1,9 @@ +extern void foo(); +int main() { + foo(); + return 0; +} + +void __attribute__((visibility("hidden"))) f2() +{ +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main.c b/FireOpal/unit-tests/test-cases/llvm-integration/main.c new file mode 100644 index 0000000..ac424ca --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main.c @@ -0,0 +1,9 @@ +extern int foo2(); +extern int foo3(); +int main(){ + int i = foo3() + foo2(); + if (i == 42) + return 0; + else + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main1.c b/FireOpal/unit-tests/test-cases/llvm-integration/main1.c new file mode 100644 index 0000000..ccad10d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main1.c @@ -0,0 +1,13 @@ +extern int foo2(); +extern int foo3(); +int foo4() +{ + return 21; +} +int main(){ + int i = foo3() + foo2(); + if (i == 42) + return 0; + else + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main10.c b/FireOpal/unit-tests/test-cases/llvm-integration/main10.c new file mode 100644 index 0000000..dabcdcf --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main10.c @@ -0,0 +1,10 @@ +#include "b10.h" + +int main() +{ + struct my_struct *mh = &my_hooks; + + mh->f(); + + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main11.c b/FireOpal/unit-tests/test-cases/llvm-integration/main11.c new file mode 100644 index 0000000..82ef7ff --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main11.c @@ -0,0 +1,7 @@ + +extern void foo3(void); +int main() +{ + foo3(); + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main12.c b/FireOpal/unit-tests/test-cases/llvm-integration/main12.c new file mode 100644 index 0000000..4de8725 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main12.c @@ -0,0 +1,7 @@ +#include "a12.h" +int main() +{ + e[0] = ZERO; + foo(); + return e[0]; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main13.cc b/FireOpal/unit-tests/test-cases/llvm-integration/main13.cc new file mode 100644 index 0000000..697d81b --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main13.cc @@ -0,0 +1,8 @@ +#include "a13.h" + +int main() +{ + A a; + a.foo(); + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main16.c b/FireOpal/unit-tests/test-cases/llvm-integration/main16.c new file mode 100644 index 0000000..67112aa --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main16.c @@ -0,0 +1,8 @@ + +int tent; +int global = 5; + +int foo() { return tent + global; } + +int main() { foo(); return 0; } + diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main19.c b/FireOpal/unit-tests/test-cases/llvm-integration/main19.c new file mode 100644 index 0000000..e09c1c9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main19.c @@ -0,0 +1,8 @@ +extern int foo(); + +int main() +{ + foo(); + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main2.c b/FireOpal/unit-tests/test-cases/llvm-integration/main2.c new file mode 100644 index 0000000..ac424ca --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main2.c @@ -0,0 +1,9 @@ +extern int foo2(); +extern int foo3(); +int main(){ + int i = foo3() + foo2(); + if (i == 42) + return 0; + else + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main20.c b/FireOpal/unit-tests/test-cases/llvm-integration/main20.c new file mode 100644 index 0000000..624e009 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main20.c @@ -0,0 +1,7 @@ +extern void foo(); + +int main() +{ + foo(); + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main3.c b/FireOpal/unit-tests/test-cases/llvm-integration/main3.c new file mode 100644 index 0000000..a5058fe --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main3.c @@ -0,0 +1,13 @@ +extern int foo1(); +extern int foo2(); +extern int bar; +int main(){ + int i; + bar = 14; + i = foo1() + foo2() + bar; + if (i == 42) + return 0; + else + return 1; + +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main4.c b/FireOpal/unit-tests/test-cases/llvm-integration/main4.c new file mode 100644 index 0000000..ac424ca --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main4.c @@ -0,0 +1,9 @@ +extern int foo2(); +extern int foo3(); +int main(){ + int i = foo3() + foo2(); + if (i == 42) + return 0; + else + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main5.c b/FireOpal/unit-tests/test-cases/llvm-integration/main5.c new file mode 100644 index 0000000..28d551d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main5.c @@ -0,0 +1,16 @@ + +extern int foo1(void); + +int foo3(void) +{ + return 42; +} + +int main() +{ + int i = foo1(); + if (i == 42) + return 0; + else + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main6.c b/FireOpal/unit-tests/test-cases/llvm-integration/main6.c new file mode 100644 index 0000000..3d00382 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main6.c @@ -0,0 +1,10 @@ +extern int foo1(); + +int main() +{ + int i = foo1(); + if (i == 42) + return 0; + else + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main7.c b/FireOpal/unit-tests/test-cases/llvm-integration/main7.c new file mode 100644 index 0000000..22427e3 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main7.c @@ -0,0 +1,10 @@ +extern int foo1(void); + +int main(void) +{ + int i = foo1(); + if (i == 42) + return 0; + else + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main8.c b/FireOpal/unit-tests/test-cases/llvm-integration/main8.c new file mode 100644 index 0000000..a9c924d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main8.c @@ -0,0 +1,11 @@ +extern int foo1(void); +extern void foo2(void); + +int main() +{ + int i = foo1(); + if (i == 42) + return 0; + else + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/llvm-integration/main9.c b/FireOpal/unit-tests/test-cases/llvm-integration/main9.c new file mode 100644 index 0000000..b44bf6e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/llvm-integration/main9.c @@ -0,0 +1,14 @@ +extern int foo1(void); +extern void foo2(void); + +void foo4(void) +{ +} +int main() +{ + int i = foo1(); + if (i == 42) + return 0; + else + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/loader_path/Makefile b/FireOpal/unit-tests/test-cases/loader_path/Makefile new file mode 100644 index 0000000..126c10d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/loader_path/Makefile @@ -0,0 +1,46 @@ +## +# Copyright (c) 2007 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 + +# +# The point of this test is a sanity check that an indirect +# library loaded with @loader_path works +# +# ld64 should handle linking against dylibs that have @loader_path based dylib load commands +# + +run: all + +all: + ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib -install_name @loader_path/libbar.dylib + ${FAIL_IF_BAD_MACHO} libbar.dylib + ${CC} ${CCFLAGS} foo.c libbar.dylib -dynamiclib -o libfoo.dylib + ${FAIL_IF_BAD_MACHO} libfoo.dylib + ${CC} ${CCFLAGS} main.c -o main libfoo.dylib + ${PASS_IFF_GOOD_MACHO} libfoo.dylib + +clean: + rm *.dylib main diff --git a/FireOpal/unit-tests/test-cases/loader_path/bar.c b/FireOpal/unit-tests/test-cases/loader_path/bar.c new file mode 100644 index 0000000..a307157 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/loader_path/bar.c @@ -0,0 +1,6 @@ + +int bar() +{ + return 1; +} + diff --git a/FireOpal/unit-tests/test-cases/loader_path/foo.c b/FireOpal/unit-tests/test-cases/loader_path/foo.c new file mode 100644 index 0000000..8c2179d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/loader_path/foo.c @@ -0,0 +1,7 @@ + +extern int bar(); + +int foo() +{ + return bar(); +} diff --git a/FireOpal/unit-tests/test-cases/loader_path/main.c b/FireOpal/unit-tests/test-cases/loader_path/main.c new file mode 100644 index 0000000..829ca5e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/loader_path/main.c @@ -0,0 +1,8 @@ +extern void foo(); + +int main() +{ + foo(); + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/Makefile b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/Makefile new file mode 100644 index 0000000..8fc14f7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/Makefile @@ -0,0 +1,75 @@ +## +# Copyright (c) 2007 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 + +# +# This test case checks -non_global_symbols_no_strip_list and -non_global_symbols_strip_list +# with and without wildcards +# + + +run: all + +all: + ${CC} ${CCFLAGS} main.c foo.c -o main + ${FAIL_IF_BAD_MACHO} main + nm -j main > main.nm + # build stripping a.list + ${CC} ${CCFLAGS} main.c foo.c -Wl,-non_global_symbols_strip_list,a.list -o main-a + ${FAIL_IF_BAD_MACHO} main-a + nm -j main-a > main-a.nm + diff main.nm main-a.nm | egrep '<|>' > a.diff + diff a.diff a.expect | ${FAIL_IF_STDIN} + # build but strip at .o file level a.list + ${CC} ${CCFLAGS} main.c -c -o main.o + ${CC} ${CCFLAGS} foo.c -c -o foo.o + ${LD} -r -arch ${ARCH} main.o foo.o -o all-a.o -non_global_symbols_strip_list a.list + ${CC} ${CCFLAGS} all-a.o -Wl,-non_global_symbols_strip_list,a.list -o main-a + ${FAIL_IF_BAD_MACHO} main-a + nm -j main-a > main-a.nm + diff main.nm main-a.nm | egrep '<|>' > a.diff + diff a.diff a.expect | ${FAIL_IF_STDIN} + # build stripping b.list + ${CC} ${CCFLAGS} main.c foo.c -Wl,-non_global_symbols_strip_list,b.list -o main-b + ${FAIL_IF_BAD_MACHO} main-b + nm -j main-b > main-b.nm + diff main.nm main-b.nm | egrep '<|>' > b.diff + diff b.diff b.expect | ${FAIL_IF_STDIN} + # build but strip at .o file level b.list + ${CC} ${CCFLAGS} main.c -c -o main.o + ${CC} ${CCFLAGS} foo.c -c -o foo.o + ${LD} -r -arch ${ARCH} main.o foo.o -o all-b.o -non_global_symbols_strip_list b.list + ${CC} ${CCFLAGS} all-b.o -Wl,-non_global_symbols_strip_list,b.list -o main-b + ${FAIL_IF_BAD_MACHO} main-b + nm -j main-b > main-b.nm + diff main.nm main-b.nm | egrep '<|>' > b.diff + diff b.diff b.expect | ${FAIL_IF_STDIN} + # build stripping c.list + ${CC} ${CCFLAGS} main.c foo.c -Wl,-non_global_symbols_no_strip_list,c.list -o main-c + nm -m main-c | grep non-external | grep -v my | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} main-c + + +clean: + rm -rf main main.nm main-a main-a.nm a.diff main-b main-b.nm b.diff main-c all-a.o all-b.o foo.o main.o diff --git a/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/a.expect b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/a.expect new file mode 100644 index 0000000..9ecbf53 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/a.expect @@ -0,0 +1,2 @@ +< _myglobal +< _xmyglobal2 diff --git a/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/a.list b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/a.list new file mode 100644 index 0000000..16c59a2 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/a.list @@ -0,0 +1,2 @@ +_myglobal +_xmyglobal2 diff --git a/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/b.expect b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/b.expect new file mode 100644 index 0000000..f1d15e4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/b.expect @@ -0,0 +1,3 @@ +< _myfunction +< _myglobal2 +< _xmyglobal2 diff --git a/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/b.list b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/b.list new file mode 100644 index 0000000..97170ac --- /dev/null +++ b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/b.list @@ -0,0 +1,2 @@ +*2 +_myf*on diff --git a/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/c.list b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/c.list new file mode 100644 index 0000000..be715cd --- /dev/null +++ b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/c.list @@ -0,0 +1 @@ +*my* diff --git a/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/foo.c b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/foo.c new file mode 100644 index 0000000..42e6cb7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/foo.c @@ -0,0 +1,11 @@ + + +int __attribute__((visibility("hidden"))) myglobal = 3; +int __attribute__((visibility("hidden"))) myglobal2 = 3; +int __attribute__((visibility("hidden"))) xmyglobal = 3; +int __attribute__((visibility("hidden"))) xmyglobal2 = 3; + +void __attribute__((visibility("hidden"))) myfunction(int x) { } + + + diff --git a/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/main.c b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/main.c new file mode 100644 index 0000000..013bc55 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/local-symbol-partial-stripping/main.c @@ -0,0 +1,11 @@ +#include + +extern int myglobal; +extern void myfunction(int); + +int main() +{ + myfunction(myglobal); + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/lto-llvm-options/Makefile b/FireOpal/unit-tests/test-cases/lto-llvm-options/Makefile new file mode 100644 index 0000000..5d4e991 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/lto-llvm-options/Makefile @@ -0,0 +1,45 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Check that -mllvm optiions work. Verify --disable-inlining +# 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 + ${LLVMGCC} ${CCFLAGS} main.o -o main + nm main | grep _foo | ${FAIL_IF_STDIN} + ${LLVMGCC} ${CCFLAGS} main.o -o main2 -Wl,-mllvm -Wl,--disable-inlining + nm main2 | grep _foo | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm main main.o main2 diff --git a/FireOpal/unit-tests/test-cases/lto-llvm-options/main.c b/FireOpal/unit-tests/test-cases/lto-llvm-options/main.c new file mode 100644 index 0000000..578d24b --- /dev/null +++ b/FireOpal/unit-tests/test-cases/lto-llvm-options/main.c @@ -0,0 +1,15 @@ + +#include + + +void foo(int x) +{ + printf("hello, world %d\n", x); +} + +int main() +{ + foo(10); + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/lto-weak-native-override/Makefile b/FireOpal/unit-tests/test-cases/lto-weak-native-override/Makefile new file mode 100644 index 0000000..55ac0f1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/lto-weak-native-override/Makefile @@ -0,0 +1,45 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Check that LTO works when a llvm bitcode has a weak symbol _foo +# 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 + otool -Iv main | grep _abort | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm main foo.o main.o + \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/lto-weak-native-override/foo.c b/FireOpal/unit-tests/test-cases/lto-weak-native-override/foo.c new file mode 100644 index 0000000..8df913a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/lto-weak-native-override/foo.c @@ -0,0 +1,6 @@ + + +__attribute__((visibility("hidden"))) void foo() +{ + // do nothing +} diff --git a/FireOpal/unit-tests/test-cases/lto-weak-native-override/main.c b/FireOpal/unit-tests/test-cases/lto-weak-native-override/main.c new file mode 100644 index 0000000..6a433db --- /dev/null +++ b/FireOpal/unit-tests/test-cases/lto-weak-native-override/main.c @@ -0,0 +1,17 @@ + +#include + +static void die() { abort(); } + + +__attribute__((visibility("hidden"),weak)) void foo() +{ + die(); +} + +int main() +{ + foo(); + +} + diff --git a/FireOpal/unit-tests/test-cases/main-stripped/Makefile b/FireOpal/unit-tests/test-cases/main-stripped/Makefile new file mode 100644 index 0000000..03756ff --- /dev/null +++ b/FireOpal/unit-tests/test-cases/main-stripped/Makefile @@ -0,0 +1,38 @@ +## +# Copyright (c) 2006 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 + +# +# Test that a dynamically referenced symbol is always exported +# + +run: all + +all: + ${CC} main.c -o main-${ARCH} -exported_symbols_list main.exp + ${FAIL_IF_BAD_MACHO} main-${ARCH} + nm -m main-${ARCH} | grep _magicSymbol | grep "referenced dynamically" | ${PASS_IFF_STDIN} + +clean: + rm main-* diff --git a/FireOpal/unit-tests/test-cases/main-stripped/main.c b/FireOpal/unit-tests/test-cases/main-stripped/main.c new file mode 100644 index 0000000..1e71f1b --- /dev/null +++ b/FireOpal/unit-tests/test-cases/main-stripped/main.c @@ -0,0 +1,34 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +// set magic "dynamically referenced" bit on magicSymbol +int magicSymbol = 1; +asm(".desc _magicSymbol, 0x10"); + + +int main() +{ + return 0; +} \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/main-stripped/main.exp b/FireOpal/unit-tests/test-cases/main-stripped/main.exp new file mode 100644 index 0000000..4eb9e89 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/main-stripped/main.exp @@ -0,0 +1 @@ +_main diff --git a/FireOpal/unit-tests/test-cases/missing-option-args/Makefile b/FireOpal/unit-tests/test-cases/missing-option-args/Makefile new file mode 100644 index 0000000..81c3f58 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/missing-option-args/Makefile @@ -0,0 +1,98 @@ +## +# Copyright (c) 2007 Apple, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Verify that missing arguments don't cause ld to crash +# This tests 64-bit arguments only +# + + +OUTPUT=2>/dev/null +LDCMD=${FAIL_IF_SUCCESS} ${LD} -arch ${ARCH} ${OUTPUT} + +run: all + +all: + ${FAIL_IF_SUCCESS} ${LD} -arch 2>/dev/null + ${LDCMD} -filelist + ${LDCMD} -o + ${LDCMD} -read_only_relocs + ${LDCMD} -sect_diff_relocs + ${LDCMD} -weak_reference_mismatches + ${LDCMD} -l + ${LDCMD} -weak-l + ${LDCMD} -weak-library + ${LDCMD} -L + ${LDCMD} -syslibroot + ${LDCMD} -framework + ${LDCMD} -framework name, + ${LDCMD} -weak_framework + ${LDCMD} -weak_framework name + ${LDCMD} -weak_framework name, + ${LDCMD} -F + ${LDCMD} -dylib_file + ${LDCMD} -dylib_file install_name + ${LDCMD} -sectcreate segname sectname + ${LDCMD} -sectorder + ${LDCMD} -sectorder segname sectname + ${LDCMD} -u + ${LDCMD} -e + ${LDCMD} -i + ${LDCMD} -idefinition: + ${LDCMD} -undefined + ${LDCMD} -U + ${LDCMD} -commons + ${LDCMD} -warn_commons + ${LDCMD} -exported_symbols_list + ${LDCMD} -unexported_symbols_list + ${LDCMD} -filelist + ${LDCMD} -filelist listfile, + ${LDCMD} -headerpad + ${LDCMD} -A + ${LDCMD} -dylib_install_name + ${LDCMD} -umbrella + ${LDCMD} -allowable_client + ${LDCMD} -client_name + ${LDCMD} -sub_umbrella + ${LDCMD} -sub_library + ${LDCMD} -init + ${LDCMD} -dylinker_install_name + ${LDCMD} -macosx_version_min + ${LDCMD} -final_output + ${LDCMD} -seg1addr + ${LDCMD} -pagezero_size + ${LDCMD} -dylib_compatibility_version + ${LDCMD} -stack_addr + ${LDCMD} -stack_size + ${LDCMD} -sectcreate + ${LDCMD} -sectcreate segname + ${LDCMD} -sectalign + ${LDCMD} -sectalign segname + ${LDCMD} -sectalign segname sectname + ${LDCMD} -sectorder segname + ${LDCMD} -dylib_current_version + ${PASS_IFF} true + +clean: diff --git a/FireOpal/unit-tests/test-cases/missing-option-args/comment.txt b/FireOpal/unit-tests/test-cases/missing-option-args/comment.txt new file mode 100644 index 0000000..8000102 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/missing-option-args/comment.txt @@ -0,0 +1 @@ +Verify that missing arguments don't cause ld to crash diff --git a/FireOpal/unit-tests/test-cases/multiple-entry-points/Makefile b/FireOpal/unit-tests/test-cases/multiple-entry-points/Makefile new file mode 100644 index 0000000..136bcf6 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/multiple-entry-points/Makefile @@ -0,0 +1,46 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is to verify a .o file can round-trip +# through ld -r correctly. The ObjectDump utility is used +# dump a "canonical" textual representation of a .o file. +# The before and after .o files are then diff'ed. +# No differences means this test passes +# + +run: all + +all: + ${CC} ${ASMFLAGS} test.s -c -o test.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_sort test.${ARCH}.o > test.${ARCH}.o.dump + + ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_sort test-r.${ARCH}.o > test-r.${ARCH}.o.dump + + ${PASS_IFF} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump + +clean: + rm -rf *.o *.dump diff --git a/FireOpal/unit-tests/test-cases/multiple-entry-points/comment.txt b/FireOpal/unit-tests/test-cases/multiple-entry-points/comment.txt new file mode 100644 index 0000000..4e819e1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/multiple-entry-points/comment.txt @@ -0,0 +1,3 @@ +The point of this test is to verify a .o file can round-trip through ld -r correctly. The ObjectDump utility is used +dump a "canonical" textual representation of a .o file. The before and after .o files are then diff'ed. +No differences means this test passes diff --git a/FireOpal/unit-tests/test-cases/multiple-entry-points/test.s b/FireOpal/unit-tests/test-cases/multiple-entry-points/test.s new file mode 100644 index 0000000..4559893 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/multiple-entry-points/test.s @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2006 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@ + */ + + + .text + .align 2 + + .globl _foo + .globl _foo2 + .globl _foo3 +_foo: +_foo2: +_foo3: + nop + + + + .align 2 +_bar: + nop + + + .align 2 + .globl _xx + .globl __xx +_xx: +__xx: + nop + + + .align 2 +_ok: + nop + diff --git a/FireOpal/unit-tests/test-cases/no-dynamic-common/Makefile.newtest b/FireOpal/unit-tests/test-cases/no-dynamic-common/Makefile.newtest new file mode 100644 index 0000000..d0f7df8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/no-dynamic-common/Makefile.newtest @@ -0,0 +1,39 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is to determine if +# common symbols are not allowed with MH_DYLIB output format with the -multi_module option +# + +run: all + +all: + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c test.c -o test-${ARCH}.o + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c a.c -o a-${ARCH}.o + ${PASS_IFF_ERROR} libtool -dynamic -o libtest-${ARCH}.a test-${ARCH}.o 2>/dev/null + +clean: + rm -rf *.o *.a diff --git a/FireOpal/unit-tests/test-cases/no-dynamic-common/a.c b/FireOpal/unit-tests/test-cases/no-dynamic-common/a.c new file mode 100644 index 0000000..8f92c9d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/no-dynamic-common/a.c @@ -0,0 +1,7 @@ +extern int common_variable; + +int +main(int argc, char **argv) +{ + return common_variable; +} diff --git a/FireOpal/unit-tests/test-cases/no-dynamic-common/comment.txt b/FireOpal/unit-tests/test-cases/no-dynamic-common/comment.txt new file mode 100644 index 0000000..a5a960d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/no-dynamic-common/comment.txt @@ -0,0 +1 @@ +The point of this test is to determine if common symbols are not allowed with MH_DYLIB output format with the -multi_module option diff --git a/FireOpal/unit-tests/test-cases/no-dynamic-common/test.c b/FireOpal/unit-tests/test-cases/no-dynamic-common/test.c new file mode 100644 index 0000000..f34267a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/no-dynamic-common/test.c @@ -0,0 +1,25 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + +int common_variable; diff --git a/FireOpal/unit-tests/test-cases/no-uuid/Makefile b/FireOpal/unit-tests/test-cases/no-uuid/Makefile new file mode 100644 index 0000000..5d52553 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/no-uuid/Makefile @@ -0,0 +1,63 @@ +## +# Copyright (c) 2006 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 + +# +# Test the we set emit LC_UUID correctly +# + +run: all + +all: + +# Test main executable built with dwarf has uuid + ${CC} ${CCFLAGS} foo.c -o foo -gdwarf-2 + ${FAIL_IF_BAD_MACHO} foo + ${OTOOL} -hlv foo | grep LC_UUID | ${FAIL_IF_EMPTY} + rm -f foo + +# Test main executable built with stabs has uuid + ${CC} ${CCFLAGS} foo.c -o foo -gfull -gstabs+ + ${FAIL_IF_BAD_MACHO} foo + ${OTOOL} -hlv foo | grep LC_UUID | ${FAIL_IF_EMPTY} + +# Test main executable built with dwarf and -no_uuid does not have uuid + ${CC} ${CCFLAGS} foo.c -o foo -Wl,-no_uuid -gdwarf-2 + ${FAIL_IF_BAD_MACHO} foo + ${OTOOL} -hlv foo | grep LC_UUID | ${FAIL_IF_STDIN} + +# Test ld -r of stabs file has no uuid + ${CC} ${CCFLAGS} foo.c -c -o foo.o -gfull -gstabs+ + ${LD} -arch ${ARCH} foo.o -r -o foo2.o + ${OTOOL} -hlv foo2.o | grep LC_UUID | ${FAIL_IF_STDIN} + +# Test ld -r of two files one with uuid produces a uuid + ${CC} ${CCFLAGS} foo.c -c -o foo.o -gdwarf-2 + ${LD} -arch ${ARCH} foo.o -r -o foo2.o + ${CC} ${CCFLAGS} bar.c -c -gstabs+ -o bar.o + ${LD} -arch ${ARCH} -r foo.o bar.o -o foobar.o + ${OTOOL} -hlv foobar.o | grep LC_UUID | ${PASS_IFF_STDIN} + +clean: + rm -rf foo foo.o foo2.o bar.o foobar.o foo.dSYM diff --git a/FireOpal/unit-tests/test-cases/no-uuid/bar.c b/FireOpal/unit-tests/test-cases/no-uuid/bar.c new file mode 100644 index 0000000..cbefe0f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/no-uuid/bar.c @@ -0,0 +1,4 @@ +int bar (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/no-uuid/comment.txt b/FireOpal/unit-tests/test-cases/no-uuid/comment.txt new file mode 100644 index 0000000..269bbbd --- /dev/null +++ b/FireOpal/unit-tests/test-cases/no-uuid/comment.txt @@ -0,0 +1 @@ +Test the we set emit LC_UUID correctly diff --git a/FireOpal/unit-tests/test-cases/no-uuid/foo.c b/FireOpal/unit-tests/test-cases/no-uuid/foo.c new file mode 100644 index 0000000..57ed6ba --- /dev/null +++ b/FireOpal/unit-tests/test-cases/no-uuid/foo.c @@ -0,0 +1,4 @@ +int main (void) +{ + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/non-lazy-r/Makefile b/FireOpal/unit-tests/test-cases/non-lazy-r/Makefile new file mode 100644 index 0000000..3c14103 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/non-lazy-r/Makefile @@ -0,0 +1,61 @@ +## +# Copyright (c) 2007 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 non-lazy-pointers are properly handled by -r +# + + +all: all-${ARCH} + +all-ppc: hasnl + +all-ppc64: hasnl + +all-i386: hasnl + +all-armv6: hasnl + +all-x86_64: all-true + +all-true: + ${PASS_IFF} true + + +hasnl: + ${CC} ${CCFLAGS} -c foo.c -o foo.o + ${CC} ${CCFLAGS} -c other.c -o other.o + ${LD} -r -arch ${ARCH} foo.o other.o -o fooall.o -exported_symbol _foo + # make sure there are two indirect symbols: _foo and LOCAL + otool -Iv fooall.o | grep "2 entries" | ${FAIL_IF_EMPTY} + otool -Iv fooall.o | grep _foo | ${FAIL_IF_EMPTY} + otool -Iv fooall.o | grep _other | ${FAIL_IF_STDIN} + # make sure re-parsed correctly + ${OBJECTDUMP} fooall.o | grep name: | grep '_foo$$non_lazy_ptr' | ${FAIL_IF_EMPTY} + ${OBJECTDUMP} fooall.o | grep name: | grep '_other$$non_lazy_ptr' | ${FAIL_IF_EMPTY} + ${PASS_IFF} true + +clean: + rm -rf *.o diff --git a/FireOpal/unit-tests/test-cases/non-lazy-r/foo.c b/FireOpal/unit-tests/test-cases/non-lazy-r/foo.c new file mode 100644 index 0000000..1fa325e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/non-lazy-r/foo.c @@ -0,0 +1,12 @@ + + + +extern int foo; + +int getfoo() { return foo; } + + +extern int other; + +int getother() { return other; } + diff --git a/FireOpal/unit-tests/test-cases/non-lazy-r/other.c b/FireOpal/unit-tests/test-cases/non-lazy-r/other.c new file mode 100644 index 0000000..6420437 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/non-lazy-r/other.c @@ -0,0 +1,2 @@ +int foo = 2; +int other = 3; diff --git a/FireOpal/unit-tests/test-cases/objc-category-debug-notes/Makefile b/FireOpal/unit-tests/test-cases/objc-category-debug-notes/Makefile new file mode 100644 index 0000000..44023e6 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-category-debug-notes/Makefile @@ -0,0 +1,40 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + + +# +# Verify no GSYM for .objc_category_* +# Linker should not make GSYM debug note for .objc_category_* symbols# +# + +run: all + +all: + ${CC} ${CCFLAGS} test.m -g -o test -framework Foundation + nm -ap test | grep GSYM | grep category | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} test + +clean: + rm -rf test test.dSYM diff --git a/FireOpal/unit-tests/test-cases/objc-category-debug-notes/test.m b/FireOpal/unit-tests/test-cases/objc-category-debug-notes/test.m new file mode 100644 index 0000000..3f45e25 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-category-debug-notes/test.m @@ -0,0 +1,44 @@ +/* -*- 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@ + */ + +#include + + +@interface NSObject (stuff) +@end + +@implementation NSObject (stuff) +@end + +@interface NSObject (other) +@end + +@implementation NSObject (other) +- (id) init { return self; } +@end + +int main() +{ + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/objc-exported_symbols_list/Makefile b/FireOpal/unit-tests/test-cases/objc-exported_symbols_list/Makefile new file mode 100644 index 0000000..454a412 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-exported_symbols_list/Makefile @@ -0,0 +1,40 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + + +# +# Test that ObjC class exports can be suppressed +# + +run: all + +all: + ${CC} ${CCFLAGS} -dynamiclib foo.m -framework Foundation -exported_symbols_list foo.exp -o libfoo.dylib + nm -m libfoo.dylib | grep Foo | grep ') external' | ${FAIL_IF_EMPTY} + nm -m libfoo.dylib | grep Bar | grep non-external | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} libfoo.dylib + +clean: + rm -rf *~ libfoo.dylib diff --git a/FireOpal/unit-tests/test-cases/objc-exported_symbols_list/foo.exp b/FireOpal/unit-tests/test-cases/objc-exported_symbols_list/foo.exp new file mode 100644 index 0000000..720c52d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-exported_symbols_list/foo.exp @@ -0,0 +1 @@ +.objc_class_name_Foo diff --git a/FireOpal/unit-tests/test-cases/objc-exported_symbols_list/foo.m b/FireOpal/unit-tests/test-cases/objc-exported_symbols_list/foo.m new file mode 100644 index 0000000..d39c8f7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-exported_symbols_list/foo.m @@ -0,0 +1,18 @@ +#include + +@interface Foo : NSObject +@end + +@implementation Foo +@end + + + +@interface Bar : NSObject +@end + +@implementation Bar +@end + + + diff --git a/FireOpal/unit-tests/test-cases/objc-gc-checks/Makefile b/FireOpal/unit-tests/test-cases/objc-gc-checks/Makefile new file mode 100644 index 0000000..0abe7d5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-gc-checks/Makefile @@ -0,0 +1,84 @@ +## +# Copyright (c) 2007-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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +SHELL = bash # use bash shell so we can redirect just stderr + + + +# +# Validate that the linker catches illegal combinations of .o files +# compiled with different GC settings. +# + +test: + ${CC} ${CCFLAGS} foo.m -c -o foo.o + ${FAIL_IF_BAD_OBJ} foo.o + + ${CC} ${CCFLAGS} foo.m -c -o foo-gc.o -fobjc-gc + ${FAIL_IF_BAD_OBJ} foo-gc.o + + ${CC} ${CCFLAGS} foo.m -c -o foo-gc-only.o -fobjc-gc-only + ${FAIL_IF_BAD_OBJ} foo-gc-only.o + + ${CC} ${CCFLAGS} bar.m -c -o bar.o + ${FAIL_IF_BAD_OBJ} bar.o + + ${CC} ${CCFLAGS} bar.m -c -o bar-gc.o -fobjc-gc + ${FAIL_IF_BAD_OBJ} bar-gc.o + + ${CC} ${CCFLAGS} bar.m -c -o bar-gc-only.o -fobjc-gc-only + ${FAIL_IF_BAD_OBJ} bar-gc-only.o + + # check RR + RR -> RR + ${CC} ${CCFLAGS} foo.o bar.o runtime.c -dynamiclib -o libfoobar.dylib + ${FAIL_IF_BAD_MACHO} libfoobar.dylib + + # check GC/RR + GC/RR -> GC/RR + ${CC} ${CCFLAGS} foo-gc.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib + ${FAIL_IF_BAD_MACHO} libfoobar.dylib + otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x2 | ${FAIL_IF_EMPTY} + + # check GC + GC -> GC + ${CC} ${CCFLAGS} foo-gc-only.o bar-gc-only.o runtime.c -dynamiclib -o libfoobar.dylib + ${FAIL_IF_BAD_MACHO} libfoobar.dylib + otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x6 | ${FAIL_IF_EMPTY} + + # check RR + GC/RR -> RR + ${CC} ${CCFLAGS} foo.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib + ${FAIL_IF_BAD_MACHO} libfoobar.dylib + otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x[26] | ${FAIL_IF_STDIN} + + # check GC + GC/RR -> GC + ${CC} ${CCFLAGS} foo-gc-only.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib + ${FAIL_IF_BAD_MACHO} libfoobar.dylib + otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x6 | ${FAIL_IF_EMPTY} + + # check RR + GC -> error + ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} foo.o bar-gc-only.o runtime.c -dynamiclib -o libfoobar.dylib 2> fail.log + + ${PASS_IFF} true + +clean: + rm -rf foo*.o bar*.o libfoobar.dylib fail.log diff --git a/FireOpal/unit-tests/test-cases/objc-gc-checks/bar.m b/FireOpal/unit-tests/test-cases/objc-gc-checks/bar.m new file mode 100644 index 0000000..5c98709 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-gc-checks/bar.m @@ -0,0 +1,11 @@ + +@interface Bar { + int f; +} +- (void) doit; +@end + +@implementation Bar +- (void) doit { } +@end + diff --git a/FireOpal/unit-tests/test-cases/objc-gc-checks/comment.txt b/FireOpal/unit-tests/test-cases/objc-gc-checks/comment.txt new file mode 100644 index 0000000..953da58 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-gc-checks/comment.txt @@ -0,0 +1 @@ +Validate that the linker catches illegal combintations of .o files compiled with different GC settings diff --git a/FireOpal/unit-tests/test-cases/objc-gc-checks/foo.m b/FireOpal/unit-tests/test-cases/objc-gc-checks/foo.m new file mode 100644 index 0000000..e13367e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-gc-checks/foo.m @@ -0,0 +1,12 @@ + +@interface Foo { + int f; +} +- (void) doit; +@end + + +@implementation Foo +- (void) doit { } +@end + diff --git a/FireOpal/unit-tests/test-cases/objc-gc-checks/runtime.c b/FireOpal/unit-tests/test-cases/objc-gc-checks/runtime.c new file mode 100644 index 0000000..df4aeef --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-gc-checks/runtime.c @@ -0,0 +1,2 @@ +void _objc_empty_cache() {} +void _objc_empty_vtable() {} diff --git a/FireOpal/unit-tests/test-cases/objc-literal-pointers/Makefile b/FireOpal/unit-tests/test-cases/objc-literal-pointers/Makefile new file mode 100644 index 0000000..9edc357 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-literal-pointers/Makefile @@ -0,0 +1,47 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + + +# +# Verify an Objective-C object file when run through +# ld -r is unaltered. +# __cls_refs section losing S_LITERAL_POINTERS section type +# +# note: i386 and ppc objc use some anonymous zerofill that moves and needs to be ignore to compare +# + +run: all + +all: + ${CC} ${CCFLAGS} test.m -c -o test.o + ObjectDump -no_content test.o | grep -v zero-fill-at> test.dump + + ${LD} -arch ${ARCH} -r test.o -o test-r.o + ObjectDump -no_content test-r.o | grep -v zero-fill-at > test-r.dump + + diff test.dump test-r.dump | ${PASS_IFF_EMPTY} + +clean: + rm -rf test.o test.dump test-r.o test-r.dump diff --git a/FireOpal/unit-tests/test-cases/objc-literal-pointers/test.m b/FireOpal/unit-tests/test-cases/objc-literal-pointers/test.m new file mode 100644 index 0000000..a5c1ea8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-literal-pointers/test.m @@ -0,0 +1,33 @@ +/* -*- 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@ + */ + +#include + +void test() +{ + // two class references + // two selector references + [NSObject superclass]; + [NSString description]; +} \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/objc-references/Makefile b/FireOpal/unit-tests/test-cases/objc-references/Makefile new file mode 100644 index 0000000..a11f1d0 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-references/Makefile @@ -0,0 +1,47 @@ +## +# 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 + + +# +# The point of this test is to verify an Objective-C object file +# is parsed to find the proper class references +# + +run: all + +all: + ${CC} ${CCFLAGS} test.m -c -o test.${ARCH}.o + ${FAIL_IF_BAD_OBJ} test.${ARCH}.o + + ${LD} -arch ${ARCH} -r test.${ARCH}.o -o test-r.${ARCH}.o + ${FAIL_IF_BAD_OBJ} test-r.${ARCH}.o + + nm test-r.${ARCH}.o | grep -i 'objc_class_.*_NSObject' | ${FAIL_IF_EMPTY} + nm test-r.${ARCH}.o | grep -i 'objc_class_.*_NSData' | ${FAIL_IF_EMPTY} + nm test-r.${ARCH}.o | grep -i 'objc_class_.*_NSArray' | ${FAIL_IF_EMPTY} + nm test-r.${ARCH}.o | grep -i 'objc_class_.*_NSString' | ${PASS_IFF_STDIN} + +clean: + rm -rf *.o *.dump diff --git a/FireOpal/unit-tests/test-cases/objc-references/comment.txt b/FireOpal/unit-tests/test-cases/objc-references/comment.txt new file mode 100644 index 0000000..ce67b71 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-references/comment.txt @@ -0,0 +1 @@ +The point of this test is to verify an Objective-C object file is parsed to find the proper class references diff --git a/FireOpal/unit-tests/test-cases/objc-references/test.m b/FireOpal/unit-tests/test-cases/objc-references/test.m new file mode 100644 index 0000000..d845227 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-references/test.m @@ -0,0 +1,52 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + +#include + + +@interface Foo : NSObject +- (NSString*) foo; +@end + + +@implementation Foo +- (NSString*) foo +{ + return [NSString stringWithUTF8String:"hello"]; +} +@end + + +@interface Bar : NSData +- (NSArray*) bar; +@end + + +@implementation Bar +- (NSArray*) bar +{ + return [NSArray array]; +} +@end + diff --git a/FireOpal/unit-tests/test-cases/objc-selector-coalescing/Makefile b/FireOpal/unit-tests/test-cases/objc-selector-coalescing/Makefile new file mode 100644 index 0000000..982f41d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-selector-coalescing/Makefile @@ -0,0 +1,39 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + + +# +# Test that two ObjC translation units that use the same selector +# link together. +# + +run: all + +all: + ${CC} ${CCFLAGS} main.m other.m -o main -framework Foundation + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf main diff --git a/FireOpal/unit-tests/test-cases/objc-selector-coalescing/main.m b/FireOpal/unit-tests/test-cases/objc-selector-coalescing/main.m new file mode 100644 index 0000000..a266128 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-selector-coalescing/main.m @@ -0,0 +1,7 @@ +#include + + +NSString* other() +{ + return [NSString stringWithUTF8String:"hello"]; +} diff --git a/FireOpal/unit-tests/test-cases/objc-selector-coalescing/other.m b/FireOpal/unit-tests/test-cases/objc-selector-coalescing/other.m new file mode 100644 index 0000000..77fd926 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/objc-selector-coalescing/other.m @@ -0,0 +1,10 @@ + +#include + + +int main() +{ + [NSString stringWithUTF8String:"hello"]; + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/operator-new/Makefile b/FireOpal/unit-tests/test-cases/operator-new/Makefile new file mode 100644 index 0000000..8abf3e1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/operator-new/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2006-2007 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 + + +run: all + +all: + # verify if operator new is overridden that WEAK_DEFINES is set + ${CXX} ${CXXFLAGS} -DOP_NEW -I${TESTROOT}/include -o main main.cxx + otool -hv main | grep WEAK_DEFINES | ${FAIL_IF_EMPTY} + # verify if operator new is not overridden that WEAK_DEFINES is not set + ${CXX} ${CXXFLAGS} -I${TESTROOT}/include -o main main.cxx + otool -hv main | grep WEAK_DEFINES | ${PASS_IFF_EMPTY} + + +clean: + ${RM} ${RMFLAGS} *~ main + diff --git a/FireOpal/unit-tests/test-cases/operator-new/main.cxx b/FireOpal/unit-tests/test-cases/operator-new/main.cxx new file mode 100644 index 0000000..3c99e35 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/operator-new/main.cxx @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2006-2007 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 // fprintf(), NULL +#include // exit(), EXIT_SUCCESS + +#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() + +#include +#include + + +// +// This test case verifies overriding operator new sets the MH_WEAK_DEFINES bit +// + +#if OP_NEW +void* operator new(size_t s) throw (std::bad_alloc) +{ + return malloc(s);; +} +#endif + +int main() +{ + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/order_file-ans/Makefile b/FireOpal/unit-tests/test-cases/order_file-ans/Makefile new file mode 100644 index 0000000..23fe568 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/order_file-ans/Makefile @@ -0,0 +1,40 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Verify that -order_file can be used to order symbols with anonymous name spaces +# + +run: all + +all: + ${CXX} ${CXXFLAGS} main.cxx -DANCHOR=1 -o main -Wl,-order_file -Wl,main.order + ${FAIL_IF_BAD_MACHO} main + nm -n -g -j main | grep "_GLOBAL__N" > main.actual + ${PASS_IFF} diff main.actual main.expected + + +clean: + rm -rf main main.actual diff --git a/FireOpal/unit-tests/test-cases/order_file-ans/main.cxx b/FireOpal/unit-tests/test-cases/order_file-ans/main.cxx new file mode 100644 index 0000000..b0412f9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/order_file-ans/main.cxx @@ -0,0 +1,62 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 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 + + +#if ANCHOR + int anchor = 4; +#endif + +namespace { + struct myanonstruct { int a; }; +} + +// function defined in anonymous namespace +namespace { + void foo() { } +} + +// function that has an anonymous namespace parameter +void bar(myanonstruct* x) { } + + +// function in anonymous namespace that has an anonymous namespace parameter +namespace { + void baz(myanonstruct* x) { } +} + +// nested namespace +namespace wow { + namespace { + void inner() { } + } +} + + + + +int main() +{ + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/order_file-ans/main.expected b/FireOpal/unit-tests/test-cases/order_file-ans/main.expected new file mode 100644 index 0000000..75e104f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/order_file-ans/main.expected @@ -0,0 +1,4 @@ +__Z3barPN17_GLOBAL__N_anchor12myanonstructE +__ZN3wow17_GLOBAL__N_anchor5innerEv +__ZN17_GLOBAL__N_anchor3bazEPNS_12myanonstructE +__ZN17_GLOBAL__N_anchor3fooEv diff --git a/FireOpal/unit-tests/test-cases/order_file-ans/main.order b/FireOpal/unit-tests/test-cases/order_file-ans/main.order new file mode 100644 index 0000000..36dd786 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/order_file-ans/main.order @@ -0,0 +1,4 @@ +__Z3barPN95_GLOBAL__N__Volumes_my_src_ld64_unit_tests_test_cases_order_file_ans_main.cxx_00000000_38BA812C12myanonstructE +__ZN3wow95_GLOBAL__N__Volumes_my_src_ld64_unit_tests_test_cases_order_file_ans_main.cxx_00000000_38BA812C5innerEv +__ZN95_GLOBAL__N__Volumes_my_src_ld64_unit_tests_test_cases_order_file_ans_main.cxx_00000000_38BA812C3bazEPNS_12myanonstructE +__ZN95_GLOBAL__N__Volumes_my_src_ld64_unit_tests_test_cases_order_file_ans_main.cxx_00000000_38BA812C3fooEv diff --git a/FireOpal/unit-tests/test-cases/order_file/Makefile b/FireOpal/unit-tests/test-cases/order_file/Makefile new file mode 100644 index 0000000..21ae0ea --- /dev/null +++ b/FireOpal/unit-tests/test-cases/order_file/Makefile @@ -0,0 +1,57 @@ +## +# Copyright (c) 2006-2007 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 + +# +# The point of this test is a sanity check -order_file. +# The main1 test verifies that C functions can be re-ordered +# The main2 test verifies that a block of assembly is not moves en mas +# The main1 test verifies that an order file with spaces and comments works +# + +run: all + +all: + as -arch ${ARCH} -L extra.s -o extra.o + ${CC} ${CCFLAGS} main.c extra.o -o main1 -Wl,-order_file -Wl,main1.order + ${FAIL_IF_BAD_MACHO} main1 + nm -n -g -j main1 | grep "_main" > main1.nm + ${PASS_IFF} diff main1.nm main1.expected + + ${CC} ${CCFLAGS} main.c extra.o -o main2 -Wl,-order_file -Wl,main2.order + ${FAIL_IF_BAD_MACHO} main2 + nm -n -j main2 | egrep '^_[a-z]+[0-9]$$' > main2.nm + ${PASS_IFF} diff main2.nm main2.expected + + ${CC} -arch ${ARCH} -c main.c -o main.o + ${CC} ${CCFLAGS} main.o extra.o -o main3 -Wl,-order_file -Wl,main3.order + ${FAIL_IF_BAD_MACHO} main3 + nm -n -g -j main3 | grep "_main" > main3.nm + ${PASS_IFF} diff main3.nm main3.expected + + + + +clean: + rm -rf main1 *.nm main2 *.o warnings.log main3 diff --git a/FireOpal/unit-tests/test-cases/order_file/extra.s b/FireOpal/unit-tests/test-cases/order_file/extra.s new file mode 100644 index 0000000..90166ce --- /dev/null +++ b/FireOpal/unit-tests/test-cases/order_file/extra.s @@ -0,0 +1,24 @@ + + + .text + + .globl _foo1 +_foo1: nop + + .globl _aaa2 +_aaa2: +_bbb2: +_ccc2: + nop + + .globl _bbb3 +_aaa3: +_bbb3: +_ccc3: + nop + + +_aaa4: + nop + + \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/order_file/main.c b/FireOpal/unit-tests/test-cases/order_file/main.c new file mode 100644 index 0000000..5643b45 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/order_file/main.c @@ -0,0 +1,33 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +int main() +{ + return 0; +} + +void main2() {} +void main3() {} +void main4() {} diff --git a/FireOpal/unit-tests/test-cases/order_file/main1.expected b/FireOpal/unit-tests/test-cases/order_file/main1.expected new file mode 100644 index 0000000..04d128b --- /dev/null +++ b/FireOpal/unit-tests/test-cases/order_file/main1.expected @@ -0,0 +1,4 @@ +_main4 +_main3 +_main +_main2 diff --git a/FireOpal/unit-tests/test-cases/order_file/main1.order b/FireOpal/unit-tests/test-cases/order_file/main1.order new file mode 100644 index 0000000..06b34d5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/order_file/main1.order @@ -0,0 +1,4 @@ +_main4 +_main3 + + diff --git a/FireOpal/unit-tests/test-cases/order_file/main2.expected b/FireOpal/unit-tests/test-cases/order_file/main2.expected new file mode 100644 index 0000000..8aca65c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/order_file/main2.expected @@ -0,0 +1,11 @@ +_main3 +_foo1 +_aaa2 +_bbb2 +_ccc2 +_aaa3 +_bbb3 +_ccc3 +_aaa4 +_main4 +_main2 diff --git a/FireOpal/unit-tests/test-cases/order_file/main2.order b/FireOpal/unit-tests/test-cases/order_file/main2.order new file mode 100644 index 0000000..87f89e6 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/order_file/main2.order @@ -0,0 +1,6 @@ +_main3 +_aaa3 +_main4 + + + diff --git a/FireOpal/unit-tests/test-cases/order_file/main3.expected b/FireOpal/unit-tests/test-cases/order_file/main3.expected new file mode 100644 index 0000000..04d128b --- /dev/null +++ b/FireOpal/unit-tests/test-cases/order_file/main3.expected @@ -0,0 +1,4 @@ +_main4 +_main3 +_main +_main2 diff --git a/FireOpal/unit-tests/test-cases/order_file/main3.order b/FireOpal/unit-tests/test-cases/order_file/main3.order new file mode 100644 index 0000000..d135527 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/order_file/main3.order @@ -0,0 +1,8 @@ + +# spaces before and after main4 +main.o: _main4 +# +main.o: _main3# trailing comment +# + + diff --git a/FireOpal/unit-tests/test-cases/prebound-main/Makefile b/FireOpal/unit-tests/test-cases/prebound-main/Makefile new file mode 100644 index 0000000..79ef53e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/prebound-main/Makefile @@ -0,0 +1,51 @@ +## +# Copyright (c) 2006 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 + +# +# 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: + ${CC} ${CCFLAGS} main.c -o main -prebind -mmacosx-version-min=10.3 + otool -hv main | grep ${KEYWORD} | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm main diff --git a/FireOpal/unit-tests/test-cases/prebound-main/main.c b/FireOpal/unit-tests/test-cases/prebound-main/main.c new file mode 100644 index 0000000..251979e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/prebound-main/main.c @@ -0,0 +1,3 @@ + +int main() { return 0; } + diff --git a/FireOpal/unit-tests/test-cases/prebound-split-seg/Makefile b/FireOpal/unit-tests/test-cases/prebound-split-seg/Makefile new file mode 100644 index 0000000..07bce59 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/prebound-split-seg/Makefile @@ -0,0 +1,39 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is to build a prebound split-seg library +# + +run: all + +all: + ${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 diff --git a/FireOpal/unit-tests/test-cases/prebound-split-seg/address_table b/FireOpal/unit-tests/test-cases/prebound-split-seg/address_table new file mode 100644 index 0000000..b611ca8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/prebound-split-seg/address_table @@ -0,0 +1,4 @@ +# comment +0x91000000 0xA1000000 /foo/bar/libbar.dylib +# + diff --git a/FireOpal/unit-tests/test-cases/prebound-split-seg/bar.c b/FireOpal/unit-tests/test-cases/prebound-split-seg/bar.c new file mode 100644 index 0000000..46b7269 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/prebound-split-seg/bar.c @@ -0,0 +1,36 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + + +int x = 3; +int* xp = &x; + + +int bar() +{ + return *xp; +} + +void* pbar = &bar; + diff --git a/FireOpal/unit-tests/test-cases/private-non-lazy/Makefile b/FireOpal/unit-tests/test-cases/private-non-lazy/Makefile new file mode 100644 index 0000000..be0ba42 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/private-non-lazy/Makefile @@ -0,0 +1,54 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is to check that a non-lazy-pointer +# in foo.o to a private-extern symbol in bar.o will +# properly survive ld -r +# + +run: all + +all: + ${CC} ${CCFLAGS} -c foo.c -o foo.o + ${FAIL_IF_BAD_OBJ} foo.o + + ${CC} ${CCFLAGS} -c bar.c -o bar.o + ${FAIL_IF_BAD_OBJ} bar.o + + ${LD} -r foo.o bar.o -o foobar.o -arch ${ARCH} + ${FAIL_IF_BAD_OBJ} foobar.o + + ${CC} ${CCFLAGS} hello.c foobar.o -o hello + ${FAIL_IF_BAD_MACHO} hello + + ${LD} -r foo.o bar.o -o foobar2.o -arch ${ARCH} -keep_private_externs + ${FAIL_IF_BAD_OBJ} foobar2.o + + ${CC} ${CCFLAGS} hello.c foobar2.o -o hello2 + ${PASS_IFF_GOOD_MACHO} hello2 + +clean: + rm -rf *.o hello hello2 diff --git a/FireOpal/unit-tests/test-cases/private-non-lazy/bar.c b/FireOpal/unit-tests/test-cases/private-non-lazy/bar.c new file mode 100644 index 0000000..601dc69 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/private-non-lazy/bar.c @@ -0,0 +1,3 @@ + +int __attribute__((visibility("hidden"))) foo = 0; + diff --git a/FireOpal/unit-tests/test-cases/private-non-lazy/comment.txt b/FireOpal/unit-tests/test-cases/private-non-lazy/comment.txt new file mode 100644 index 0000000..e6d11c0 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/private-non-lazy/comment.txt @@ -0,0 +1 @@ +The point of this test is to check that a non-lazy-pointer in foo.o to a private-extern symbol in bar.o will properly survive ld -r diff --git a/FireOpal/unit-tests/test-cases/private-non-lazy/foo.c b/FireOpal/unit-tests/test-cases/private-non-lazy/foo.c new file mode 100644 index 0000000..6816d0b --- /dev/null +++ b/FireOpal/unit-tests/test-cases/private-non-lazy/foo.c @@ -0,0 +1,7 @@ + + +extern int foo; + +int getfoo() { return foo; } + + diff --git a/FireOpal/unit-tests/test-cases/private-non-lazy/hello.c b/FireOpal/unit-tests/test-cases/private-non-lazy/hello.c new file mode 100644 index 0000000..20dccc4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/private-non-lazy/hello.c @@ -0,0 +1,31 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +extern int getfoo(); + +int main() +{ + return getfoo(); +} diff --git a/FireOpal/unit-tests/test-cases/re-export-cases/Makefile b/FireOpal/unit-tests/test-cases/re-export-cases/Makefile new file mode 100644 index 0000000..64ec112 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-cases/Makefile @@ -0,0 +1,167 @@ +## +# Copyright (c) 2007 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 all the different ways that re-exports can be specified and implemented +# + + +run: all + +all: + +# -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 + ${FAIL_IF_BAD_MACHO} libbar.dylib + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lbar -L. -sub_library libbar -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} + + +# -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 + 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 + ${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 + ${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 + 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 + ${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 + ${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 + ${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 + otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_EMPTY} + otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN} + +# -reexport_library 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_library,libbar.dylib -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-l 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 -Wl,-reexport-lbar -L. -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} + +# -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 + 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. -Wl,-reexport_framework,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} + +# -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" -mmacosx-version-min=10.5 + ${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 + ${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 -mmacosx-version-min=10.4 + ${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 + ${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} + + +# -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 + ${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 + ${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 + + +clean: + + rm -rf hide libbar.dylib libfoo.dylib Foo.framework Bar.framework diff --git a/FireOpal/unit-tests/test-cases/re-export-cases/bar.c b/FireOpal/unit-tests/test-cases/re-export-cases/bar.c new file mode 100644 index 0000000..9c18401 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-cases/bar.c @@ -0,0 +1,5 @@ + +int bar (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/re-export-cases/baz.c b/FireOpal/unit-tests/test-cases/re-export-cases/baz.c new file mode 100644 index 0000000..af6a9f8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-cases/baz.c @@ -0,0 +1,5 @@ + +int baz (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/re-export-cases/foo.c b/FireOpal/unit-tests/test-cases/re-export-cases/foo.c new file mode 100644 index 0000000..d0cdf47 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-cases/foo.c @@ -0,0 +1,4 @@ +int foo (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/re-export-flag/Makefile b/FireOpal/unit-tests/test-cases/re-export-flag/Makefile new file mode 100644 index 0000000..82228ee --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-flag/Makefile @@ -0,0 +1,48 @@ +## +# Copyright (c) 2006 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 + +# +# Test that the MH_NO_REEXPORTED_DYLIBS bit is set in dylibs with no re-exports +# + +run: all + +all: +# build base library + ${CC} ${CCFLAGS} -dynamiclib bar.c -o `pwd`/libbar.dylib + ${FAIL_IF_BAD_MACHO} libbar.dylib + +# build library the re-exports base library + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib -sub_library libbar +# test that foo does not have MH_NO_REEXPORTED_DYLIBS bit + ${FAIL_IF_BAD_MACHO} libfoo.dylib + +# build libray that links with base but does not re-export it + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo2.dylib libbar.dylib + ${FAIL_IF_BAD_MACHO} libfoo.dylib + otool -hv libfoo2.dylib | grep NO_REEXPORTED_DYLIBS | ${PASS_IFF_STDIN} + +clean: + rm -rf *.dylib diff --git a/FireOpal/unit-tests/test-cases/re-export-flag/bar.c b/FireOpal/unit-tests/test-cases/re-export-flag/bar.c new file mode 100644 index 0000000..34e5666 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-flag/bar.c @@ -0,0 +1,5 @@ + +int bar(void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/re-export-flag/foo.c b/FireOpal/unit-tests/test-cases/re-export-flag/foo.c new file mode 100644 index 0000000..714540a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-flag/foo.c @@ -0,0 +1,4 @@ +int foo(void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/re-export-optimizations/Makefile b/FireOpal/unit-tests/test-cases/re-export-optimizations/Makefile new file mode 100644 index 0000000..a1dfd88 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-optimizations/Makefile @@ -0,0 +1,65 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Test that a public re-exported library is automatically added as a dependent +# unless nothing is used from it. +# + + +run: all + +all: + +# -sub_library for 10.4 + ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -install_name /usr/lib/libbar.dylib -mmacosx-version-min=10.4 + ${FAIL_IF_BAD_MACHO} libbar.dylib + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lbar -L. -sub_library libbar -mmacosx-version-min=10.4 + ${FAIL_IF_BAD_MACHO} libfoo.dylib + ${CC} ${CCFLAGS} main.c -DCALL_BAR libfoo.dylib -o main -L. -mmacosx-version-min=10.4 + 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.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 + ${FAIL_IF_BAD_MACHO} libbar.dylib + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lbar -L. -sub_library libbar -mmacosx-version-min=10.5 + ${FAIL_IF_BAD_MACHO} libfoo.dylib + ${CC} ${CCFLAGS} main.c -DCALL_BAR libfoo.dylib -o main -L. -mmacosx-version-min=10.5 + 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 + otool -L main | grep libbar | ${FAIL_IF_STDIN} + + + ${PASS_IFF} /usr/bin/true + + +clean: + + rm -rf libbar.dylib libfoo.dylib main diff --git a/FireOpal/unit-tests/test-cases/re-export-optimizations/bar.c b/FireOpal/unit-tests/test-cases/re-export-optimizations/bar.c new file mode 100644 index 0000000..9c18401 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-optimizations/bar.c @@ -0,0 +1,5 @@ + +int bar (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/re-export-optimizations/foo.c b/FireOpal/unit-tests/test-cases/re-export-optimizations/foo.c new file mode 100644 index 0000000..d0cdf47 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-optimizations/foo.c @@ -0,0 +1,4 @@ +int foo (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/re-export-optimizations/main.c b/FireOpal/unit-tests/test-cases/re-export-optimizations/main.c new file mode 100644 index 0000000..2b85b0e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-optimizations/main.c @@ -0,0 +1,10 @@ + +extern void bar(); + +int main() +{ +#if CALL_BAR + bar(); +#endif + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/re-export-relative-paths/Makefile b/FireOpal/unit-tests/test-cases/re-export-relative-paths/Makefile new file mode 100644 index 0000000..2560a86 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-relative-paths/Makefile @@ -0,0 +1,49 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Test that @loader_path and @executable_path can be resolved finding indirect dylibs +# + + +run: all + +all: + mkdir -p hide + ${CC} ${CCFLAGS} -dynamiclib foo.c -install_name '@loader_path/libfoo.dylib' -o hide/libfoo.dylib + ${FAIL_IF_BAD_MACHO} hide/libfoo.dylib + ${CC} ${CCFLAGS} -dynamiclib bar.c -o hide/libbar.dylib -install_name '@executable_path/hide/libbar.dylib' + ${FAIL_IF_BAD_MACHO} hide/libbar.dylib + ${CC} ${CCFLAGS} -dynamiclib wrap.c -o hide/libwrap.dylib -Wl,-reexport-lfoo -Wl,-reexport-lbar -Lhide + ${FAIL_IF_BAD_MACHO} hide/libwrap.dylib + ${CC} ${CCFLAGS} main.c -o main hide/libwrap.dylib + ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain.dylib hide/libwrap.dylib -Wl,-executable_path,`pwd`/main + ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain.dylib hide/libwrap.dylib -Wl,-executable_path,`pwd` + ${PASS_IFF} /usr/bin/true + + +clean: + + rm -rf hide libbar.dylib libfoo.dylib libwrap.dylib main libmain.dylib diff --git a/FireOpal/unit-tests/test-cases/re-export-relative-paths/bar.c b/FireOpal/unit-tests/test-cases/re-export-relative-paths/bar.c new file mode 100644 index 0000000..9c18401 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-relative-paths/bar.c @@ -0,0 +1,5 @@ + +int bar (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/re-export-relative-paths/foo.c b/FireOpal/unit-tests/test-cases/re-export-relative-paths/foo.c new file mode 100644 index 0000000..d0cdf47 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-relative-paths/foo.c @@ -0,0 +1,4 @@ +int foo (void) +{ + return 1; +} diff --git a/FireOpal/unit-tests/test-cases/re-export-relative-paths/main.c b/FireOpal/unit-tests/test-cases/re-export-relative-paths/main.c new file mode 100644 index 0000000..367c6cb --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-relative-paths/main.c @@ -0,0 +1,11 @@ +extern int foo(); +extern int bar(); +extern int wrap(); + +int main() +{ + foo(); + bar(); + wrap(); + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/re-export-relative-paths/wrap.c b/FireOpal/unit-tests/test-cases/re-export-relative-paths/wrap.c new file mode 100644 index 0000000..d3cdd85 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/re-export-relative-paths/wrap.c @@ -0,0 +1,2 @@ +int wrap() { return 0; } + diff --git a/FireOpal/unit-tests/test-cases/read-only-relocs/Makefile b/FireOpal/unit-tests/test-cases/read-only-relocs/Makefile new file mode 100644 index 0000000..02ed1df --- /dev/null +++ b/FireOpal/unit-tests/test-cases/read-only-relocs/Makefile @@ -0,0 +1,63 @@ +## +# Copyright (c) 2006-2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Test that ld can linke a dylib built with -mdynamic-no-pic +# + + +SHELL = bash # use bash shell so we can redirect just stderr + +NO_PIC = +STATIC = + +ifeq (${ARCH},i386) + NO_PIC = -mdynamic-no-pic + STATIC = -static +else + ifeq (${ARCH},ppc) + NO_PIC = -mdynamic-no-pic + STATIC = -mdynamic-no-pic + endif +endif + + + +all: + # build libfoo.dylib as regular dylib + ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib + # build libtest.dylib using -mdynamic-no-pic and -read_only_relocs suppress + ${CC} ${CCFLAGS} test.c -c ${NO_PIC} + ${CC} ${CCFLAGS} test.o libfoo.dylib -dynamiclib -o libtest.dylib -read_only_relocs suppress -Wl,-w + # build libtest.dylib using -static and -read_only_relocs suppress + ${CC} ${CCFLAGS} test.c -c ${STATIC} + ${CC} ${CCFLAGS} test.o libfoo.dylib -dynamiclib -o libtest.dylib -read_only_relocs suppress -Wl,-w + # build main using -static and -read_only_relocs suppress + ${CC} ${CCFLAGS} test.c -c ${STATIC} + ${CC} ${CCFLAGS} test.o libfoo.dylib -o foo -read_only_relocs suppress -Wl,-w + ${PASS_IFF_GOOD_MACHO} foo + +clean: + rm -rf test.o libfoo.dylib libtest.dylib foo diff --git a/FireOpal/unit-tests/test-cases/read-only-relocs/foo.c b/FireOpal/unit-tests/test-cases/read-only-relocs/foo.c new file mode 100644 index 0000000..bef1580 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/read-only-relocs/foo.c @@ -0,0 +1,6 @@ + +int b=0; + +void func() {} + + diff --git a/FireOpal/unit-tests/test-cases/read-only-relocs/test.c b/FireOpal/unit-tests/test-cases/read-only-relocs/test.c new file mode 100644 index 0000000..f3484e2 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/read-only-relocs/test.c @@ -0,0 +1,34 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + +int a=0; +extern int b; +extern void func(); + +int main() +{ + func(); + return a+b; +} + diff --git a/FireOpal/unit-tests/test-cases/rebase-basic/Makefile b/FireOpal/unit-tests/test-cases/rebase-basic/Makefile new file mode 100644 index 0000000..ba262aa --- /dev/null +++ b/FireOpal/unit-tests/test-cases/rebase-basic/Makefile @@ -0,0 +1,53 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is to see that a dylib +# run through the rebase tool is the same as if +# the dylib was originally built at that address +# + +run: all + +all: + ${CC} ${CCFLAGS} -c foo.c -o foo.${ARCH}.o + ${FAIL_IF_BAD_OBJ} foo.${ARCH}.o + + ${CC} ${CCFLAGS} -c bar.m -o bar.${ARCH}.o + ${FAIL_IF_BAD_OBJ} bar.${ARCH}.o + + ${CC} ${CCFLAGS} foo.${ARCH}.o bar.${ARCH}.o -dynamiclib -Wl,-no_uuid -o libfoo.${ARCH}.dylib -framework Foundation -framework CoreFoundation + ${FAIL_IF_BAD_MACHO} libfoo.${ARCH}.dylib + + ${CC} ${CCFLAGS} foo.${ARCH}.o bar.${ARCH}.o -dynamiclib -Wl,-no_uuid -o libfoo-alt.${ARCH}.dylib -framework Foundation -framework CoreFoundation -seg1addr 0x12340000 -install_name libfoo.${ARCH}.dylib + ${FAIL_IF_BAD_MACHO} libfoo-alt.${ARCH}.dylib + + rebase -arch ${ARCH} -low_address 0x12340000 libfoo.${ARCH}.dylib + ${FAIL_IF_BAD_MACHO} libfoo.${ARCH}.dylib + + ${PASS_IFF} diff libfoo.${ARCH}.dylib libfoo-alt.${ARCH}.dylib + +clean: + rm *.o *.dylib diff --git a/FireOpal/unit-tests/test-cases/rebase-basic/bar.m b/FireOpal/unit-tests/test-cases/rebase-basic/bar.m new file mode 100644 index 0000000..ff4f2ac --- /dev/null +++ b/FireOpal/unit-tests/test-cases/rebase-basic/bar.m @@ -0,0 +1,13 @@ +#include + +@interface Bar : NSObject + +-(void) blah; + +@end + +@implementation Bar + +-(void) blah {} + +@end \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/rebase-basic/comment.txt b/FireOpal/unit-tests/test-cases/rebase-basic/comment.txt new file mode 100644 index 0000000..013eb45 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/rebase-basic/comment.txt @@ -0,0 +1 @@ +The point of this test is to see that a dylib run through the rebase tool is the same as if the dylib was originally built at that address diff --git a/FireOpal/unit-tests/test-cases/rebase-basic/foo.c b/FireOpal/unit-tests/test-cases/rebase-basic/foo.c new file mode 100644 index 0000000..15d4ae6 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/rebase-basic/foo.c @@ -0,0 +1,14 @@ + +int foo() { return 10; } + +void* foop = &foo; + +int glob = 5; + +int* globp = &glob; + + +int big[3000]; + + + \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/relocs-asm/Makefile b/FireOpal/unit-tests/test-cases/relocs-asm/Makefile new file mode 100644 index 0000000..c231ac4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-asm/Makefile @@ -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 + +# +# The point of this test is to verify a .o file can round-trip +# through ld -r correctly. The ObjectDump utility is used +# dump a "canonical" textual representation of a .o file. +# The before and after .o files are then diff'ed. +# No differences means this test passes +# + +run: all + +all: + ${CC} ${ASMFLAGS} relocs-asm.s -c -o relocs-asm.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content relocs-asm.${ARCH}.o > relocs-asm.${ARCH}.o.dump + + ${LD} -arch ${ARCH} -r -keep_private_externs relocs-asm.${ARCH}.o -o relocs-asm-r.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content relocs-asm-r.${ARCH}.o > relocs-asm-r.${ARCH}.o.dump + + ${PASS_IFF} diff relocs-asm.${ARCH}.o.dump relocs-asm-r.${ARCH}.o.dump + +clean: + rm -rf *.o *.dump diff --git a/FireOpal/unit-tests/test-cases/relocs-asm/comment.txt b/FireOpal/unit-tests/test-cases/relocs-asm/comment.txt new file mode 100644 index 0000000..4e819e1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-asm/comment.txt @@ -0,0 +1,3 @@ +The point of this test is to verify a .o file can round-trip through ld -r correctly. The ObjectDump utility is used +dump a "canonical" textual representation of a .o file. The before and after .o files are then diff'ed. +No differences means this test passes diff --git a/FireOpal/unit-tests/test-cases/relocs-asm/relocs-asm.s b/FireOpal/unit-tests/test-cases/relocs-asm/relocs-asm.s new file mode 100644 index 0000000..06e10e8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-asm/relocs-asm.s @@ -0,0 +1,471 @@ +/* + * Copyright (c) 2005-2007 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if __arm__ + .text + .align 2 + + .globl _test_loads +_test_loads: + @ PIC load of a + ldr r0, L6 +L0: + ldr r0, [pc, r0] + + @ PIC load of c + ldr r0, L6+4 +L1: + ldr r0, [pc, r0] + + @ sorta-absolute load of a + ldr r0, L6+8 + ldr r0, [r0, #0] + + @ sorta-absolute load of c + ldr r0, L6+12 + ldr r0, [r0, #0] + + @ sorta-absolute load of external + ldr r0, L6+16 + ldr r0, [r0, #0] + + @ PIC load of a + addend ?? + bx lr + +L6: + .long _a-(L0+8) + .long _c-(L1+8) + .long _a + .long _c + .long _ax + +_test_calls: + @ call internal + bl _test_branches + + @ call internal + addend + bl _test_branches+0x19000 + + @ call external + bl _external + + @ call external + addend + bl _external+0x19000 + + +_test_branches: + @ call internal + bne _test_calls + + @ call internal + addend + bne _test_calls+16 + + @ call external + bne _external + + @ call external + addend + bne _external+16 +#endif + +#if __ppc__ || __ppc64__ + + .text + .align 2 + + .globl _test_loads +_test_loads: + stmw r30,-8(r1) + stwu r1,-48(r1) +Lpicbase: + + ; PIC load of a + addis r2,r10,ha16(_a-Lpicbase) + lwz r2,lo16(_a-Lpicbase)(r2) + + ; PIC load of c + addis r2,r10,ha16(_c-Lpicbase) + lwz r2,lo16(_c-Lpicbase)(r2) + + ; absolute load of a + lis r2,ha16(_a) + lwz r2,lo16(_a)(r2) + + ; absolute load of c + lis r2,ha16(_c) + lwz r2,lo16(_c)(r2) + + ; absolute load of external + lis r2,ha16(_ax) + lwz r2,lo16(_ax)(r2) + + ; absolute lea of external + lis r2,hi16(_ax) + ori r2,r2,lo16(_ax) + + + ; PIC load of a + addend + addis r2,r10,ha16(_a+0x19000-Lpicbase) + lwz r2,lo16(_a+0x19000-Lpicbase)(r2) + + ; absolute load of a + addend + lis r2,ha16(_a+0x19000) + lwz r2,lo16(_a+0x19000)(r2) + + ; lea of a + addend + lis r2,ha16(_a+0x19000) + addi r2,r2,lo16(_a+0x19000) + + ; alt lea of a + addend + lis r2,hi16(_a+0x19000) + ori r2,r2,lo16(_a+0x19000) + + ; absolute load of external + addend + lis r2,ha16(_ax+0x19000) + lwz r2,lo16(_ax+0x19000)(r2) + + ; absolute lea of external + addend + lis r2,hi16(_ax+0x19000) + ori r2,r2,lo16(_ax+0x19000) + + + ; PIC load of a + addend + addis r2,r10,ha16(_a+0x09000-Lpicbase) + lwz r2,lo16(_a+0x09000-Lpicbase)(r2) + + ; absolute load of a + addend + lis r2,ha16(_a+0x09000) + lwz r2,lo16(_a+0x09000)(r2) + + ; lea of a + addend + lis r2,ha16(_a+0x09000) + addi r2,r2,lo16(_a+0x09000) + + ; alt lea of a + addend + lis r2,hi16(_a+0x09000) + ori r2,r2,lo16(_a+0x09000) + + ; absolute load of external + addend + lis r2,ha16(_ax+0x09000) + lwz r2,lo16(_ax+0x09000)(r2) + + ; absolute lea of external + addend + lis r2,hi16(_ax+0x09000) + ori r2,r2,lo16(_ax+0x09000) + + blr + + +_test_calls: + ; call internal + bl _test_branches + + ; call internal + addend + bl _test_branches+0x19000 + + ; call external + bl _external + + ; call external + addend + bl _external+0x19000 + + +_test_branches: + ; call internal + bne _test_calls + + ; call internal + addend + bne _test_calls+16 + + ; call external + bne _external + + ; call external + addend + bne _external+16 +#endif + + + +#if __i386__ + .text + .align 2 + + .globl _test_loads +_test_loads: + pushl %ebp +Lpicbase: + + # PIC load of a + movl _a-Lpicbase(%ebx), %eax + + # absolute load of a + movl _a, %eax + + # absolute load of external + movl _ax, %eax + + # absolute lea of external + leal _ax, %eax + + + # PIC load of a + addend + movl _a-Lpicbase+0x19000(%ebx), %eax + + # absolute load of a + addend + movl _a+0x19000(%ebx), %eax + + # absolute load of external + addend + movl _ax+0x19000(%ebx), %eax + + # absolute lea of external + addend + leal _ax+0x1900, %eax + + ret + + +_test_calls: + # call internal + call _test_branches + + # call internal + addend + call _test_branches+0x19000 + + # call external + call _external + + # call external + addend + call _external+0x19000 + + +_test_branches: + # call internal + jne _test_calls + + # call internal + addend + jne _test_calls+16 + + # call external + jne _external + + # call external + addend + jne _external+16 + +_pointer_diffs: + nop + call _get_ret_eax +1: movl _foo-1b(%eax),%esi + movl _foo+10-1b(%eax),%esi + movl _test_branches-1b(%eax),%esi + movl _test_branches+3-1b(%eax),%esi + +_word_relocs: + callw _pointer_diffs + +_byte_relocs: + mov $100, %ecx +c_1: + loop c_1 + mov $100, %ecx +c_2: + sub $(1), %ecx + jcxz c_2 + +#endif + + + +#if __x86_64__ + .text + .align 2 + + .globl _test_loads +_test_loads: + + # PIC load of a + movl _a(%rip), %eax + + # PIC load of a + addend + movl _a+0x1234(%rip), %eax + + # PIC lea + leaq _a(%rip), %rax + + # PIC lea through GOT + movq _a@GOTPCREL(%rip), %rax + + # PIC access of GOT + pushq _a@GOTPCREL(%rip) + + # PIC lea external through GOT + movq _ax@GOTPCREL(%rip), %rax + + # PIC external access of GOT + pushq _ax@GOTPCREL(%rip) + + # 1-byte store + movb $0x12, _a(%rip) + movb $0x12, _a+2(%rip) + movb $0x12, L0(%rip) + + # 4-byte store + movl $0x12345678, _a(%rip) + movl $0x12345678, _a+4(%rip) + movl $0x12345678, L0(%rip) + + # test local labels + lea L1(%rip), %rax + movl L0(%rip), %eax + + ret + + +_test_calls: + # call internal + call _test_branches + + # call internal + addend + call _test_branches+0x19000 + + # call external + call _external + + # call external + addend + call _external+0x19000 + + +_test_branches: + # call internal + jne _test_calls + + # call internal + addend + jne _test_calls+16 + + # call external + jne _external + + # call external + addend + jne _external+16 + +_byte_relocs: + mov $100, %ecx +c_1: + loop _byte_relocs + nop + +#endif + + + + # test that pointer-diff relocs are preserved + .text +_test_diffs: + .align 2 +Llocal2: + .long 0 + .long Llocal2-_test_branches + .long . - _test_branches + .long . - _test_branches + 8 + .long _test_branches - . + .long _test_branches - . + 8 + .long _test_branches - . - 8 +#if __ppc64__ + .quad Llocal2-_test_branches +#endif + +_foo: nop + + .align 2 +_distance_from_foo: + .long 0 + .long . - _foo + .long . - 8 - _foo + + +_distance_to_foo: + .long _foo - . + .long _foo - . + 4 + + +_distance_to_here: + .long _foo - _distance_to_here + .long _foo - _distance_to_here - 4 + .long _foo - _distance_to_here - 12 + .long 0 + + +#if __x86_64__ + .data +L0: .quad _test_branches +_prev: + .quad _test_branches+4 +L1: .quad _test_branches - _test_diffs + .quad _test_branches - _test_diffs + 4 + .long _test_branches - _test_diffs +# .long LCL0-. ### assembler bug: should SUB/UNSIGNED with content= LCL0-24, or single pc-rel SIGNED reloc with content = LCL0-.+4 + .quad L1 + .quad L0 + .quad _test_branches - . + .quad _test_branches - L1 + .quad L1 - _prev + +# the following generates: _foo cannot be undefined in a subtraction expression +# but it should be ok (it will be a linker error if _foo and _bar are not in same linkage unit) +# .quad _foo - _bar ### assembler bug + + .section __DATA,__data2 +LCL0: .long 2 + + +#endif + + + .data +_a: + .long 0 + +_b: +#if __ppc__ || __i386__ || __arm__ + .long _test_calls + .long _test_calls+16 + .long _external + .long _external+16 +#elif __ppc64__ || __x86_64__ + .quad _test_calls + .quad _test_calls+16 + .quad _external + .quad _external+16 +#endif + + # test that reloc sizes are the same +Llocal3: + .long 0 + +Llocal4: + .long 0 + + .long Llocal4-Llocal3 + +Lfiller: + .space 0x9000 +_c: + .long 0 + diff --git a/FireOpal/unit-tests/test-cases/relocs-c/Makefile b/FireOpal/unit-tests/test-cases/relocs-c/Makefile new file mode 100644 index 0000000..7428127 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-c/Makefile @@ -0,0 +1,57 @@ +## +# Copyright (c) 2005-2008 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 + + +# +# The point of this test is to verify a .o file can round-trip +# through ld -r correctly. The ObjectDump utility is used +# dump a "canonical" textual representation of a .o file. +# The before and after .o files are then diff'ed. +# No differences means this test passes +# + +ifeq (${ARCH},x86_64) + ADDR_SHIFT = 0x1FF000000 +else + ADDR_SHIFT = 0xF0000000 +endif + + +run: all + +all: + ${CC} ${CCFLAGS} test.c -c -o test.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump + + ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump + ${FAIL_IF_ERROR} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump + + ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -seg1addr ${ADDR_SHIFT} -o test2-r.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test2-r.${ARCH}.o > test2-r.${ARCH}.o.dump + ${PASS_IFF} diff test.${ARCH}.o.dump test2-r.${ARCH}.o.dump + +clean: + rm -rf *.o *.dump diff --git a/FireOpal/unit-tests/test-cases/relocs-c/test.c b/FireOpal/unit-tests/test-cases/relocs-c/test.c new file mode 100644 index 0000000..b877760 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-c/test.c @@ -0,0 +1,76 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * 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@ + */ + +static int foo; + +int __attribute__((visibility("hidden"))) foofoo; + +static int uninit_static; +static int init_static = 1; + int __attribute__((visibility("hidden"))) uninit_hidden; + int __attribute__((visibility("hidden"))) init_hidden = 1; + int uninit_global; + int init_global = 1; +extern int extern_global; +extern int __attribute__((visibility("hidden"))) extern_hidden; + +static int uninit_static_array[4]; +static int init_static_array[4] = {1,2,3,4}; + int __attribute__((visibility("hidden"))) uninit_hidden_array[4]; + int __attribute__((visibility("hidden"))) init_hidden_array[4] = {1,2,3,4}; + int uninit_global_array[4]; + int init_global_array[4] = {1,2,3,4}; +extern int extern_global_array[4]; + +int test1() { return uninit_static; } +int test2() { return init_static; } +int test3() { return uninit_hidden; } +int test4() { return init_hidden; } +int test5() { return uninit_global; } +int test6() { return init_global; } +int test7() { return extern_global; } +int test8() { return extern_hidden; } + +int test_array1() { return uninit_static_array[2]; } +int test_array2() { return init_static_array[2]; } +int test_array3() { return uninit_hidden_array[2]; } +int test_array4() { return init_hidden_array[2]; } +int test_array5() { return uninit_global_array[2]; } +int test_array6() { return init_global_array[2]; } +int test_array7() { return extern_global_array[2]; } + +static int foo2; +int test9() { return foo2; } + + +int* p_init_global = &init_global; +void* p_test1 = (void*)&test1; +unsigned char pad = 2; +unsigned char pad2 = 3; // this padding throws off alignment on compiler generated anonymous non-lazy pointers... + +int func() __attribute__((visibility("hidden"))); +int func() { return foo; } + +int func2() { return func() + 1; } + diff --git a/FireOpal/unit-tests/test-cases/relocs-c2/Makefile b/FireOpal/unit-tests/test-cases/relocs-c2/Makefile new file mode 100644 index 0000000..767b210 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-c2/Makefile @@ -0,0 +1,58 @@ +## +# Copyright (c) 2005-2006 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 + + +# +# The point of this test is to verify a .o file can round-trip +# through ld -r correctly. The ObjectDump utility is used +# dump a "canonical" textual representation of a .o file. +# The before and after .o files are then diff'ed. +# No differences means this test passes +# +# Currently for ppc64 the .o's alternate! in content +# + + +run: all + +all: + ${CC} ${CCFLAGS} test.c -c -o test.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump + #grep "plus" test.${ARCH}.o.dump | ${FAIL_IF_STDIN} + + ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump + #grep "plus" test-r.${ARCH}.o.dump | ${FAIL_IF_STDIN} + + ${LD} -arch ${ARCH} -r -keep_private_externs test-r.${ARCH}.o -o test-r-r.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r-r.${ARCH}.o > test-r-r.${ARCH}.o.dump + + ${LD} -arch ${ARCH} -r -keep_private_externs test-r-r.${ARCH}.o -o test-r-r-r.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r-r-r.${ARCH}.o > test-r-r-r.${ARCH}.o.dump + + ${PASS_IFF} diff -c -w test.${ARCH}.o.dump test-r.${ARCH}.o.dump + +clean: + rm -rf *.o *.dump diff --git a/FireOpal/unit-tests/test-cases/relocs-c2/comment.txt b/FireOpal/unit-tests/test-cases/relocs-c2/comment.txt new file mode 100644 index 0000000..2499674 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-c2/comment.txt @@ -0,0 +1,5 @@ +The point of this test is to verify a .o file can round-trip through ld -r correctly. The ObjectDump utility is used +dump a "canonical" textual representation of a .o file. The before and after .o files are then diff'ed. +No differences means this test passes + +Currently for ppc64 the .o's alternate! in content diff --git a/FireOpal/unit-tests/test-cases/relocs-c2/test.c b/FireOpal/unit-tests/test-cases/relocs-c2/test.c new file mode 100644 index 0000000..b877760 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-c2/test.c @@ -0,0 +1,76 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * 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@ + */ + +static int foo; + +int __attribute__((visibility("hidden"))) foofoo; + +static int uninit_static; +static int init_static = 1; + int __attribute__((visibility("hidden"))) uninit_hidden; + int __attribute__((visibility("hidden"))) init_hidden = 1; + int uninit_global; + int init_global = 1; +extern int extern_global; +extern int __attribute__((visibility("hidden"))) extern_hidden; + +static int uninit_static_array[4]; +static int init_static_array[4] = {1,2,3,4}; + int __attribute__((visibility("hidden"))) uninit_hidden_array[4]; + int __attribute__((visibility("hidden"))) init_hidden_array[4] = {1,2,3,4}; + int uninit_global_array[4]; + int init_global_array[4] = {1,2,3,4}; +extern int extern_global_array[4]; + +int test1() { return uninit_static; } +int test2() { return init_static; } +int test3() { return uninit_hidden; } +int test4() { return init_hidden; } +int test5() { return uninit_global; } +int test6() { return init_global; } +int test7() { return extern_global; } +int test8() { return extern_hidden; } + +int test_array1() { return uninit_static_array[2]; } +int test_array2() { return init_static_array[2]; } +int test_array3() { return uninit_hidden_array[2]; } +int test_array4() { return init_hidden_array[2]; } +int test_array5() { return uninit_global_array[2]; } +int test_array6() { return init_global_array[2]; } +int test_array7() { return extern_global_array[2]; } + +static int foo2; +int test9() { return foo2; } + + +int* p_init_global = &init_global; +void* p_test1 = (void*)&test1; +unsigned char pad = 2; +unsigned char pad2 = 3; // this padding throws off alignment on compiler generated anonymous non-lazy pointers... + +int func() __attribute__((visibility("hidden"))); +int func() { return foo; } + +int func2() { return func() + 1; } + diff --git a/FireOpal/unit-tests/test-cases/relocs-literals/Makefile b/FireOpal/unit-tests/test-cases/relocs-literals/Makefile new file mode 100644 index 0000000..a9ca5ef --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-literals/Makefile @@ -0,0 +1,47 @@ +## +# 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 + + +# +# The point of this test is to verify a .o file can round-trip +# through ld -r correctly. The ObjectDump utility is used +# dump a "canonical" textual representation of a .o file. +# The before and after .o files are then diff'ed. +# No differences means this test passes +# + +run: all + +all: + ${CC} ${CCFLAGS} -Os $(MDYNAMIC_NO_PIC) test.c -c -o test.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump + + ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump + + ${PASS_IFF} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump + +clean: + rm -rf *.o *.dump diff --git a/FireOpal/unit-tests/test-cases/relocs-literals/test.c b/FireOpal/unit-tests/test-cases/relocs-literals/test.c new file mode 100644 index 0000000..2d199d0 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-literals/test.c @@ -0,0 +1,54 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * 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@ + */ + +const char* foo = "foo"; +const char* const bar = "bar"; + +const char charArray1[] = "charArray1"; +static const char charArray2[] = "charArray2"; + + +const char* getString() { return "string"; } +const char* getString2() { return charArray2; } +const char* getString3() { return charArray1; } +const char* getString4() { return foo; } + + +float f1 = 3.0; +double d1 = 3.0; +long double ld1 = 3.0; + + + +float getSingle() { return 1.0; } +double getDouble() { return 2.0; } +long double getLongDouble() { return 3.0; } + + +// rdar://problem/4732996 +const char* stringFutz(int x) { + return "hello" + 0x1000 + x; +} + +const char* usesAddend = "teststr" + 0x2000; diff --git a/FireOpal/unit-tests/test-cases/relocs-literals2/Makefile b/FireOpal/unit-tests/test-cases/relocs-literals2/Makefile new file mode 100644 index 0000000..23e4a82 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-literals2/Makefile @@ -0,0 +1,50 @@ +## +# 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 + + +# +# The point of this test is to verify a .o file can round-trip +# through ld -r correctly. The ObjectDump utility is used +# dump a "canonical" textual representation of a .o file. +# The before and after .o files are then diff'ed. +# No differences means this test passes +# +ifneq (${ARCH},x86_64) + PIC=-mdynamic-no-pic +endif + +run: all + +all: + ${CC} ${CCFLAGS} -Os $(PIC) test.c -c -o test.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump + + ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump + + ${PASS_IFF} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump + +clean: + rm -rf *.o *.dump diff --git a/FireOpal/unit-tests/test-cases/relocs-literals2/test.c b/FireOpal/unit-tests/test-cases/relocs-literals2/test.c new file mode 100644 index 0000000..2d199d0 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-literals2/test.c @@ -0,0 +1,54 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * 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@ + */ + +const char* foo = "foo"; +const char* const bar = "bar"; + +const char charArray1[] = "charArray1"; +static const char charArray2[] = "charArray2"; + + +const char* getString() { return "string"; } +const char* getString2() { return charArray2; } +const char* getString3() { return charArray1; } +const char* getString4() { return foo; } + + +float f1 = 3.0; +double d1 = 3.0; +long double ld1 = 3.0; + + + +float getSingle() { return 1.0; } +double getDouble() { return 2.0; } +long double getLongDouble() { return 3.0; } + + +// rdar://problem/4732996 +const char* stringFutz(int x) { + return "hello" + 0x1000 + x; +} + +const char* usesAddend = "teststr" + 0x2000; diff --git a/FireOpal/unit-tests/test-cases/relocs-literals3/Makefile b/FireOpal/unit-tests/test-cases/relocs-literals3/Makefile new file mode 100644 index 0000000..e0fa4ad --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-literals3/Makefile @@ -0,0 +1,47 @@ +## +# 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 + + +# +# The point of this test is to verify a .o file can round-trip +# through ld -r correctly. The ObjectDump utility is used +# dump a "canonical" textual representation of a .o file. +# The before and after .o files are then diff'ed. +# No differences means this test passes +# + +run: all + +all: + ${CC} ${CCFLAGS} -Os -mdynamic-no-pic test.c -c -o test.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump + + ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump + + ${PASS_IFF} diff -C 6 test.${ARCH}.o.dump test-r.${ARCH}.o.dump + +clean: + rm -rf *.o *.dump diff --git a/FireOpal/unit-tests/test-cases/relocs-literals3/comment.txt b/FireOpal/unit-tests/test-cases/relocs-literals3/comment.txt new file mode 100644 index 0000000..4e819e1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-literals3/comment.txt @@ -0,0 +1,3 @@ +The point of this test is to verify a .o file can round-trip through ld -r correctly. The ObjectDump utility is used +dump a "canonical" textual representation of a .o file. The before and after .o files are then diff'ed. +No differences means this test passes diff --git a/FireOpal/unit-tests/test-cases/relocs-literals3/test.c b/FireOpal/unit-tests/test-cases/relocs-literals3/test.c new file mode 100644 index 0000000..31e87c2 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-literals3/test.c @@ -0,0 +1,47 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * 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@ + */ + +const char* foo = "foo"; +const char* const bar = "bar"; + +const char charArray1[] = "charArray1"; +static const char charArray2[] = "charArray2"; + + +const char* getString() { return "string"; } +const char* getString2() { return charArray2; } +const char* getString3() { return charArray1; } +const char* getString4() { return foo; } + + +float f1 = 3.0; +double d1 = 3.0; +long double ld1 = 3.0; + + + +float getSingle() { return 1.0; } +double getDouble() { return 2.0; } +long double getLongDouble() { return 3.0; } + diff --git a/FireOpal/unit-tests/test-cases/relocs-objc/Makefile b/FireOpal/unit-tests/test-cases/relocs-objc/Makefile new file mode 100644 index 0000000..0f8846d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-objc/Makefile @@ -0,0 +1,47 @@ +## +# 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 + + +# +# The point of this test is to verify a .o file can round-trip +# through ld -r correctly. The ObjectDump utility is used +# dump a "canonical" textual representation of a .o file. +# The before and after .o files are then diff'ed. +# No differences means this test passes +# + +run: all + +all: + ${CC} ${CCFLAGS} test.m -c -o test.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump + + ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump + + ${PASS_IFF} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump + +clean: + rm -rf *.o *.dump diff --git a/FireOpal/unit-tests/test-cases/relocs-objc/comment.txt b/FireOpal/unit-tests/test-cases/relocs-objc/comment.txt new file mode 100644 index 0000000..4e819e1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-objc/comment.txt @@ -0,0 +1,3 @@ +The point of this test is to verify a .o file can round-trip through ld -r correctly. The ObjectDump utility is used +dump a "canonical" textual representation of a .o file. The before and after .o files are then diff'ed. +No differences means this test passes diff --git a/FireOpal/unit-tests/test-cases/relocs-objc/test.m b/FireOpal/unit-tests/test-cases/relocs-objc/test.m new file mode 100644 index 0000000..1ca2157 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/relocs-objc/test.m @@ -0,0 +1,59 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * 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@ + */ +#include + + +@interface Foo : NSObject +{ + int ivar; +} +- (id) init; +- (void) foo; +@end + + +@implementation Foo +- (id) init +{ + self = [super init]; + return self; +} + +- (void) foo +{ + [self class]; +} +@end + + + +@interface Base +@end + + +@implementation Base +@end + + + diff --git a/FireOpal/unit-tests/test-cases/segment-order/Makefile b/FireOpal/unit-tests/test-cases/segment-order/Makefile new file mode 100644 index 0000000..76b4e95 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/segment-order/Makefile @@ -0,0 +1,37 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Validate linker puts non-standard segments in order of discovery +# + +all: + ${CC} ${CCFLAGS} main.c segKKK.s segJJJ.s segLLL.s -o main + nm -j -n main | grep _sym_ > symbol.order + ${FAIL_IF_ERROR} diff symbol.order expected.order + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf main symbol.order diff --git a/FireOpal/unit-tests/test-cases/segment-order/expected.order b/FireOpal/unit-tests/test-cases/segment-order/expected.order new file mode 100644 index 0000000..e05b042 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/segment-order/expected.order @@ -0,0 +1,3 @@ +_sym_kkk +_sym_jjj +_sym_lll diff --git a/FireOpal/unit-tests/test-cases/segment-order/main.c b/FireOpal/unit-tests/test-cases/segment-order/main.c new file mode 100644 index 0000000..df77448 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/segment-order/main.c @@ -0,0 +1,4 @@ + + +int main() { return 0; } + diff --git a/FireOpal/unit-tests/test-cases/segment-order/segJJJ.s b/FireOpal/unit-tests/test-cases/segment-order/segJJJ.s new file mode 100644 index 0000000..d9f5f71 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/segment-order/segJJJ.s @@ -0,0 +1,7 @@ + + .section __JJJ,__jjj +_sym_jjj: .space 128 + + + + diff --git a/FireOpal/unit-tests/test-cases/segment-order/segKKK.s b/FireOpal/unit-tests/test-cases/segment-order/segKKK.s new file mode 100644 index 0000000..70b1952 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/segment-order/segKKK.s @@ -0,0 +1,7 @@ + + .section __KKK,__kkk +_sym_kkk: .space 128 + + + + diff --git a/FireOpal/unit-tests/test-cases/segment-order/segLLL.s b/FireOpal/unit-tests/test-cases/segment-order/segLLL.s new file mode 100644 index 0000000..045eea4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/segment-order/segLLL.s @@ -0,0 +1,7 @@ + + .section __LLL,__lll +_sym_lll: .space 128 + + + + diff --git a/FireOpal/unit-tests/test-cases/slow-x86-stubs/Makefile b/FireOpal/unit-tests/test-cases/slow-x86-stubs/Makefile new file mode 100644 index 0000000..ee6a0e5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/slow-x86-stubs/Makefile @@ -0,0 +1,42 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Sanity check that -slow_stubs for i386 leaves no __IMPORT segment +# + +run: all + + + +all: + ${CC} ${CCFLAGS} hello.c -o hello -Wl,-slow_stubs + size -l hello | grep __IMPORT | ${FAIL_IF_STDIN} + ${CC} ${CCFLAGS} hello.c -dynamiclib -o libhello.dylib -Wl,-slow_stubs + size -l libhello.dylib | grep __IMPORT | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} hello + +clean: + rm hello libhello.dylib diff --git a/FireOpal/unit-tests/test-cases/slow-x86-stubs/hello.c b/FireOpal/unit-tests/test-cases/slow-x86-stubs/hello.c new file mode 100644 index 0000000..fe3b0df --- /dev/null +++ b/FireOpal/unit-tests/test-cases/slow-x86-stubs/hello.c @@ -0,0 +1,7 @@ +#include + +int main() +{ + fprintf(stdout, "hello\n"); + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/special-labels/Makefile b/FireOpal/unit-tests/test-cases/special-labels/Makefile new file mode 100644 index 0000000..060f12e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/special-labels/Makefile @@ -0,0 +1,41 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that ld +# automatically strips labels starting with 'l' and 'L' +# + +run: all + +all: + as -arch ${ARCH} -L extra.s -o extra.o + ${CC} ${CCFLAGS} main.c extra.o -o main + nm main | grep "lother" | ${FAIL_IF_STDIN} + nm main | grep "L123" | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf main *.o diff --git a/FireOpal/unit-tests/test-cases/special-labels/extra.s b/FireOpal/unit-tests/test-cases/special-labels/extra.s new file mode 100644 index 0000000..0755508 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/special-labels/extra.s @@ -0,0 +1,9 @@ + + + .data + +_foo: .long 0 +lother: .long 0 +L123: .long 0 +_bar: .long 0 + diff --git a/FireOpal/unit-tests/test-cases/special-labels/main.c b/FireOpal/unit-tests/test-cases/special-labels/main.c new file mode 100644 index 0000000..5c73586 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/special-labels/main.c @@ -0,0 +1,29 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +int main() +{ + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/stabs-coalesce/Makefile b/FireOpal/unit-tests/test-cases/stabs-coalesce/Makefile new file mode 100644 index 0000000..6e11c59 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stabs-coalesce/Makefile @@ -0,0 +1,52 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that ld +# removes the stabs associated with a copy of a coalesced +# function that was removed. +# Running nm through stabs-filter.pl produces connonical stabs +# that can be diffed against a checked in know good set of stabs +# + +run: all + +all: hello.o other.o + ${CXX} ${CCXXFLAGS} -gstabs+ -gused hello.o other.o -o stabs-hello-${ARCH} + ${FAIL_IF_BAD_MACHO} stabs-hello-${ARCH} + nm -ap stabs-hello-${ARCH} | grep FUN | grep _Z3fooi | wc -l > stabs-hello-foo-count + echo " 1" > one + ${PASS_IFF} diff stabs-hello-foo-count one + +hello.o : hello.cxx + ${CXX} ${CCXXFLAGS} -gstabs+ -gused hello.cxx -c -o $@ + ${FAIL_IF_BAD_OBJ} $@ + +other.o : other.cxx + ${CXX} ${CCXXFLAGS} -gstabs+ -gused other.cxx -c -o $@ + ${FAIL_IF_BAD_OBJ} $@ + +clean: + rm -rf stabs-hello-* *.o *.stabs stabs-hello-foo-count one diff --git a/FireOpal/unit-tests/test-cases/stabs-coalesce/comment.txt b/FireOpal/unit-tests/test-cases/stabs-coalesce/comment.txt new file mode 100644 index 0000000..f22b9a1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stabs-coalesce/comment.txt @@ -0,0 +1,3 @@ +The point of this test is a sanity check that ld removes the stabs associated with a copy of a coalesced +function that was removed. Running nm through stabs-filter.pl produces connonical stabs +that can be diffed against a checked in know good set of stabs diff --git a/FireOpal/unit-tests/test-cases/stabs-coalesce/header.h b/FireOpal/unit-tests/test-cases/stabs-coalesce/header.h new file mode 100644 index 0000000..378308f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stabs-coalesce/header.h @@ -0,0 +1,31 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + + +inline int foo(int x) +{ + return x + 10; +} + +extern int bar(int x); diff --git a/FireOpal/unit-tests/test-cases/stabs-coalesce/hello.cxx b/FireOpal/unit-tests/test-cases/stabs-coalesce/hello.cxx new file mode 100644 index 0000000..33bf273 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stabs-coalesce/hello.cxx @@ -0,0 +1,33 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +#include "header.h" + + +int main() +{ + foo(bar(3)); + fprintf(stdout, "hello\n"); +} \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/stabs-coalesce/other.cxx b/FireOpal/unit-tests/test-cases/stabs-coalesce/other.cxx new file mode 100644 index 0000000..ee97d7d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stabs-coalesce/other.cxx @@ -0,0 +1,41 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + +#include "header.h" + +int uninit; +int init = 1; +static int suninit; +static int sinit=0; + +int bar(int x) +{ + static int bar_uninit; + static int bar_init=3; + bar_uninit = x; + return 20 + suninit + sinit + + bar_init + bar_uninit + foo(x); +} + + diff --git a/FireOpal/unit-tests/test-cases/stabs-directory-slash/Makefile b/FireOpal/unit-tests/test-cases/stabs-directory-slash/Makefile new file mode 100644 index 0000000..5318933 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stabs-directory-slash/Makefile @@ -0,0 +1,39 @@ +## +# 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 + +# Test that file paths in a stab reference ends with a / +# if there is no terminating /, gdb does not recognize this as a file path +# The provided files coalesced1a.o coalesced1b.o are ppc64 linked +# rdar://problem/4565088 + +run: all + +all: + $(CXX) -gstabs+ main.c -o outfile + ${FAIL_IF_BAD_MACHO} outfile + nm -ap outfile | ${PASS_IFF} grep '.*\.*test-cases.*/$$' + +clean: + rm outfile* diff --git a/FireOpal/unit-tests/test-cases/stabs-directory-slash/main.c b/FireOpal/unit-tests/test-cases/stabs-directory-slash/main.c new file mode 100644 index 0000000..54dc4c5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stabs-directory-slash/main.c @@ -0,0 +1,3 @@ +main() +{ +} diff --git a/FireOpal/unit-tests/test-cases/stack_addr_no_size/Makefile.newtest b/FireOpal/unit-tests/test-cases/stack_addr_no_size/Makefile.newtest new file mode 100644 index 0000000..a9e452f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stack_addr_no_size/Makefile.newtest @@ -0,0 +1,77 @@ +## +# 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 + +# Test the ld commands -stack_addr, -stack_size +# Test using -stack_addr only + + +ifeq (,${findstring 64,$(ARCH)}) + STACK_ADDR = 0xC0000000 + STACK_SIZE = 0x04000000 + STACK_TOP = 0xbc000000 +else +#ifeq (${ARCH},x86_64) + STACK_ADDR = 0x0007fff5fc000000 + STACK_TOP = 0x00007fff57000000 + STACK_SIZE = 0x0000000005000000 +#else + #STACK_ADDR = 0x0007ffff00000000 + #STACK_TOP = 0x0007fffefb000000 + #STACK_SIZE = 0x0000000005000000 +#endif +endif + + +run: all + +all: +# info seems to not work, use warning: + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c main.c -o main-${ARCH}.o + + + ${FAIL_IF_ERROR} ${LD} -arch ${ARCH} \ + -stack_addr ${STACK_ADDR} \ + -lcrt1.o -lSystem \ + main-${ARCH}.o -o main \ + 2>lderr.out + +# Can check warning if desired. +#ifeq (,${findstring 64,$(ARCH)}) +# grep "warning no -stack_size specified using the default size" lderr.out | ${FAIL_IF_EMPTY} +#else +# grep "failed: -stack_addr must be used with -stack_size" lderr.out | ${FAIL_IF_EMPTY} +#endif + + +# Check for __UNIXSTACK section in object, check that it has the correct value + ${FAIL_IF_ERROR} ${OTOOL} -l main>ldcmds.out + (echo '1,/^[ ]*segname __UNIXSTACK$$/-d'; echo '/^[ ]*segname /,$$d'; echo w; echo q) | ed ldcmds.out >/dev/null + grep __UNIXSTACK ldcmds.out | ${FAIL_IF_EMPTY} + grep " vmsize[ ]*${STACK_SIZE}" ldcmds.out | ${FAIL_IF_EMPTY} + grep " vmaddr[ ]*${STACK_TOP}" ldcmds.out | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf *.o *.err *.out main diff --git a/FireOpal/unit-tests/test-cases/stack_addr_no_size/comment.txt b/FireOpal/unit-tests/test-cases/stack_addr_no_size/comment.txt new file mode 100644 index 0000000..da74f89 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stack_addr_no_size/comment.txt @@ -0,0 +1,11 @@ +Test the ld commands -stack_addr, -stack_size (3939852 and 4729162) + + +-stack_addr value +Specifies the initial address of the stack pointer value, where value is a hexadecimal number rounded to the segment alignment. The default segment alignment is the target pagesize (currently, 1000 hexadecimal for the PowerPC and for i386). If -stack_size is specified and -stack_addr is not, a default stack address specific for the architecture being linked will be used and its value printed as a warning message. This creates a segment named __UNIXSTACK. Note that the initial stack address will be either at the high address of the segment or the low address of the segment depending on which direction the stack grows for the architecture being linked. + + +-stack_size value +Specifies the size of the stack segment value, where value is a hexadecimal number rounded to the segment alignment. The default segment alignment is the target pagesize (currently, 1000 hexadecimal for the PowerPC and for i386). If -stack_addr is specified and -stack_size is not, a default stack size specific for the architecture being linked will be used and its value printed as a warning message. This creates a segment named __UNIXSTACK . + + diff --git a/FireOpal/unit-tests/test-cases/stack_addr_no_size/main.c b/FireOpal/unit-tests/test-cases/stack_addr_no_size/main.c new file mode 100644 index 0000000..5c73586 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stack_addr_no_size/main.c @@ -0,0 +1,29 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +int main() +{ + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/stack_addr_size/Makefile b/FireOpal/unit-tests/test-cases/stack_addr_size/Makefile new file mode 100644 index 0000000..670f014 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stack_addr_size/Makefile @@ -0,0 +1,57 @@ +## +# 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 + +# Test the ld option -stack_addr and -stack_size used together + +ifeq ($(ARCH),armv6) + STACK_ADDR = 0x2C000000 + STACK_SIZE = 0x05000000 + STACK_TOP = 0x27000000 +else +ifeq (,${findstring 64,$(ARCH)}) + STACK_ADDR = 0xCC000000 + STACK_SIZE = 0x05000000 + STACK_TOP = 0xc7000000 +else + STACK_ADDR = 0x110000000 + STACK_TOP = 0x000000010b000000 + STACK_SIZE = 0x0000000005000000 +endif +endif + +run: all + + + +all: + ${CC} ${CCFLAGS} main.c -o main -Wl,-stack_size,${STACK_SIZE} -Wl,-stack_addr,${STACK_ADDR} + # Check for __UNIXSTACK section in object, check that it has the correct value + 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 + +clean: + rm -rf main main.otool diff --git a/FireOpal/unit-tests/test-cases/stack_addr_size/comment.txt b/FireOpal/unit-tests/test-cases/stack_addr_size/comment.txt new file mode 100644 index 0000000..da74f89 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stack_addr_size/comment.txt @@ -0,0 +1,11 @@ +Test the ld commands -stack_addr, -stack_size (3939852 and 4729162) + + +-stack_addr value +Specifies the initial address of the stack pointer value, where value is a hexadecimal number rounded to the segment alignment. The default segment alignment is the target pagesize (currently, 1000 hexadecimal for the PowerPC and for i386). If -stack_size is specified and -stack_addr is not, a default stack address specific for the architecture being linked will be used and its value printed as a warning message. This creates a segment named __UNIXSTACK. Note that the initial stack address will be either at the high address of the segment or the low address of the segment depending on which direction the stack grows for the architecture being linked. + + +-stack_size value +Specifies the size of the stack segment value, where value is a hexadecimal number rounded to the segment alignment. The default segment alignment is the target pagesize (currently, 1000 hexadecimal for the PowerPC and for i386). If -stack_addr is specified and -stack_size is not, a default stack size specific for the architecture being linked will be used and its value printed as a warning message. This creates a segment named __UNIXSTACK . + + diff --git a/FireOpal/unit-tests/test-cases/stack_addr_size/main.c b/FireOpal/unit-tests/test-cases/stack_addr_size/main.c new file mode 100644 index 0000000..5c73586 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stack_addr_size/main.c @@ -0,0 +1,29 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +int main() +{ + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/stack_size_no_addr/Makefile b/FireOpal/unit-tests/test-cases/stack_size_no_addr/Makefile new file mode 100644 index 0000000..6134c7e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stack_size_no_addr/Makefile @@ -0,0 +1,56 @@ +## +# Copyright (c) 2005-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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# Test the ld option -stack_size adds a custom stack segment + +ifeq ($(ARCH),armv6) + STACK_ADDR = 0x30000000 + STACK_SIZE = 0x05000000 + STACK_TOP = 0x2b000000 +else +ifeq (,${findstring 64,$(ARCH)}) + STACK_ADDR = 0xC0000000 + STACK_SIZE = 0x05000000 + STACK_TOP = 0xbb000000 +else + STACK_ADDR = 0x0007fff5fc000000 + STACK_TOP = 0x00007fff57000000 + STACK_SIZE = 0x0000000005000000 +endif +endif + + +run: all + +all: + ${CC} ${CCFLAGS} main.c -o main -Wl,-stack_size,${STACK_SIZE} + # Check for __UNIXSTACK section in object, check that it has the correct value + 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 + +clean: + rm -rf main main.otool diff --git a/FireOpal/unit-tests/test-cases/stack_size_no_addr/comment.txt b/FireOpal/unit-tests/test-cases/stack_size_no_addr/comment.txt new file mode 100644 index 0000000..5933975 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stack_size_no_addr/comment.txt @@ -0,0 +1,11 @@ +Test the ld commands -stack_addr, -stack_size + + +-stack_addr value +Specifies the initial address of the stack pointer value, where value is a hexadecimal number rounded to the segment alignment. The default segment alignment is the target pagesize (currently, 1000 hexadecimal for the PowerPC and for i386). If -stack_size is specified and -stack_addr is not, a default stack address specific for the architecture being linked will be used and its value printed as a warning message. This creates a segment named __UNIXSTACK. Note that the initial stack address will be either at the high address of the segment or the low address of the segment depending on which direction the stack grows for the architecture being linked. + + +-stack_size value +Specifies the size of the stack segment value, where value is a hexadecimal number rounded to the segment alignment. The default segment alignment is the target pagesize (currently, 1000 hexadecimal for the PowerPC and for i386). If -stack_addr is specified and -stack_size is not, a default stack size specific for the architecture being linked will be used and its value printed as a warning message. This creates a segment named __UNIXSTACK . + + diff --git a/FireOpal/unit-tests/test-cases/stack_size_no_addr/main.c b/FireOpal/unit-tests/test-cases/stack_size_no_addr/main.c new file mode 100644 index 0000000..4aaef3a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stack_size_no_addr/main.c @@ -0,0 +1,37 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006-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@ + */ +#include + +#if __x86_64__ +static char buffer[8000000000]; +#elif __arm__ +static char buffer[100000000]; +#else +static char buffer[2000000000]; +#endif + +int main() +{ + return buffer[0]; +} diff --git a/FireOpal/unit-tests/test-cases/static-executable/Makefile b/FireOpal/unit-tests/test-cases/static-executable/Makefile new file mode 100644 index 0000000..2d71eff --- /dev/null +++ b/FireOpal/unit-tests/test-cases/static-executable/Makefile @@ -0,0 +1,35 @@ +## +# Copyright (c) 2006 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 + +# +# Test that ld can link a static executable +# + +all: + ${CC} ${CCFLAGS} test.c -static -o test -e _entry -nostdlib -Wl,-new_linker + ${PASS_IFF_GOOD_MACHO} test + +clean: + rm -rf test diff --git a/FireOpal/unit-tests/test-cases/static-executable/test.c b/FireOpal/unit-tests/test-cases/static-executable/test.c new file mode 100644 index 0000000..27fe88d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/static-executable/test.c @@ -0,0 +1,11 @@ + +int foo() +{ + return 0; +} + + +int entry() +{ + return foo(); +} diff --git a/FireOpal/unit-tests/test-cases/static-strip/Makefile.newtest b/FireOpal/unit-tests/test-cases/static-strip/Makefile.newtest new file mode 100644 index 0000000..323200e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/static-strip/Makefile.newtest @@ -0,0 +1,40 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that ld +# can link a static executable (requires non-public archives) +# + +run: all + +all: + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} test.c -static -o test-${ARCH} -L/usr/local/lib/system -lc_static -lm_static -Wl,-new_linker + ${FAIL_IF_BAD_MACHO} test-${ARCH} + ${FAIL_IF_ERROR} strip test-${ARCH} + ${PASS_IFF_GOOD_MACHO} test-${ARCH} + +clean: + rm -rf test-* diff --git a/FireOpal/unit-tests/test-cases/static-strip/comment.txt b/FireOpal/unit-tests/test-cases/static-strip/comment.txt new file mode 100644 index 0000000..bc535a3 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/static-strip/comment.txt @@ -0,0 +1 @@ +The point of this test is a sanity check that ld can link a static executable (requires non-public archives) diff --git a/FireOpal/unit-tests/test-cases/static-strip/test.c b/FireOpal/unit-tests/test-cases/static-strip/test.c new file mode 100644 index 0000000..ab472fb --- /dev/null +++ b/FireOpal/unit-tests/test-cases/static-strip/test.c @@ -0,0 +1,28 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ + +int main() +{ + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/strip-test2/Makefile b/FireOpal/unit-tests/test-cases/strip-test2/Makefile new file mode 100644 index 0000000..778770e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/strip-test2/Makefile @@ -0,0 +1,70 @@ +## +# 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 + +# Test strip: symbols referenced by indirect symbol table entries that can'tÊ +# be stripped in: +# __ZN9__gnu_cxx13new_allocatorIiE7destroyEPi +# __ZNKSt12_Vector_baseIiSaIiEE13get_allocatorEv +# __ZN9__gnu_cxx13new_allocatorIiEC2ERKS1_ +# __ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPim +# __ZN9__gnu_cxx13new_allocatorIiED2Ev +# __ZNSt6vectorIiSaIiEEC1ERKS0_ +# __ZNSaIiEC1ERKS_ +# __ZN9__gnu_cxx13new_allocatorIiE10deallocateEPim +# __ZNSt12_Vector_baseIiSaIiEE12_Vector_implC1ERKS0_ +# __ZNSaIiED2Ev +# __ZNSt12_Vector_baseIiSaIiEED2Ev +# __ZNSaIiEC1Ev +# __ZNSt12_Vector_baseIiSaIiEEC2ERKS0_ +# __ZNSt6vectorIiSaIiEED1Ev +# __ZNSaIiED1Ev +# __ZSt8_DestroyIPiSaIiEEvT_S2_T0_ +# __ZN9__gnu_cxx13new_allocatorIiEC2Ev +# __ZNSaIiEC2ERKS_ +# __ZNSt12_Vector_baseIiSaIiEE12_Vector_implD1Ev + + +run: all + + +all: + $(CXX) main.cxx -arch ${ARCH} -o main + ${FAIL_IF_BAD_MACHO} main + ${FAIL_IF_ERROR} nm -j main >main-no-strip.nm + $(CXX) main.cxx -arch ${ARCH} -o main + ${FAIL_IF_BAD_MACHO} main + + # Make sure there are no symbols in the stripped file that aren't + # in the unstripped + nm -j main | comm -23 - main-no-strip.nm | ${FAIL_IF_STDIN} + + # Now make sure that all the __Z symbols exist + strip_cnt=`nm -j main | comm -12 - main-no-strip.nm | grep -c __Z`; \ + nostrip_cnt=`nm -j main|grep -c __Z`; \ + [ x"$$strip_cnt" = x"$$nostrip_cnt" ] + @echo PASS $$UNIT_TEST_NAME + +clean: + rm -rf *.o main-* main diff --git a/FireOpal/unit-tests/test-cases/strip-test2/comment.txt b/FireOpal/unit-tests/test-cases/strip-test2/comment.txt new file mode 100644 index 0000000..a99f78e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/strip-test2/comment.txt @@ -0,0 +1,21 @@ +Test strip: symbols referenced by indirect symbol table entries can't be stripped (4096290) + +__ZN9__gnu_cxx13new_allocatorIiE7destroyEPi +__ZNKSt12_Vector_baseIiSaIiEE13get_allocatorEv +__ZN9__gnu_cxx13new_allocatorIiEC2ERKS1_ +__ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPim +__ZN9__gnu_cxx13new_allocatorIiED2Ev +__ZNSt6vectorIiSaIiEEC1ERKS0_ +__ZNSaIiEC1ERKS_ +__ZN9__gnu_cxx13new_allocatorIiE10deallocateEPim +__ZNSt12_Vector_baseIiSaIiEE12_Vector_implC1ERKS0_ +__ZNSaIiED2Ev +__ZNSt12_Vector_baseIiSaIiEED2Ev +__ZNSaIiEC1Ev +__ZNSt12_Vector_baseIiSaIiEEC2ERKS0_ +__ZNSt6vectorIiSaIiEED1Ev +__ZNSaIiED1Ev +__ZSt8_DestroyIPiSaIiEEvT_S2_T0_ +__ZN9__gnu_cxx13new_allocatorIiEC2Ev +__ZNSaIiEC2ERKS_ +__ZNSt12_Vector_baseIiSaIiEE12_Vector_implD1Ev diff --git a/FireOpal/unit-tests/test-cases/strip-test2/main.cxx b/FireOpal/unit-tests/test-cases/strip-test2/main.cxx new file mode 100644 index 0000000..dd65fef --- /dev/null +++ b/FireOpal/unit-tests/test-cases/strip-test2/main.cxx @@ -0,0 +1,6 @@ +#include +int main() +{ + std::vector stuff; + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/strip-test3/Makefile.newtest b/FireOpal/unit-tests/test-cases/strip-test3/Makefile.newtest new file mode 100644 index 0000000..c1ad4c4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/strip-test3/Makefile.newtest @@ -0,0 +1,71 @@ +## +# 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 + +# Test strip: symbols referenced by indirect symbol table entries that can'tÊ +# be stripped in: +# __ZN9__gnu_cxx13new_allocatorIiE7destroyEPi +# __ZNKSt12_Vector_baseIiSaIiEE13get_allocatorEv +# __ZN9__gnu_cxx13new_allocatorIiEC2ERKS1_ +# __ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPim +# __ZN9__gnu_cxx13new_allocatorIiED2Ev +# __ZNSt6vectorIiSaIiEEC1ERKS0_ +# __ZNSaIiEC1ERKS_ +# __ZN9__gnu_cxx13new_allocatorIiE10deallocateEPim +# __ZNSt12_Vector_baseIiSaIiEE12_Vector_implC1ERKS0_ +# __ZNSaIiED2Ev +# __ZNSt12_Vector_baseIiSaIiEED2Ev +# __ZNSaIiEC1Ev +# __ZNSt12_Vector_baseIiSaIiEEC2ERKS0_ +# __ZNSt6vectorIiSaIiEED1Ev +# __ZNSaIiED1Ev +# __ZSt8_DestroyIPiSaIiEEvT_S2_T0_ +# __ZN9__gnu_cxx13new_allocatorIiEC2Ev +# __ZNSaIiEC2ERKS_ +# __ZNSt12_Vector_baseIiSaIiEE12_Vector_implD1Ev + + +run: all + + +all: + ${FAIL_IF_ERROR} $(CXX) main.cxx -arch ${ARCH} -o main + ${FAIL_IF_BAD_MACHO} main + ${FAIL_IF_ERROR} nm -j main >main-no-strip.nm + ${FAIL_IF_ERROR} strip main + ${FAIL_IF_BAD_MACHO} main + ${FAIL_IF_ERROR} $(CXX) main.cxx -arch ${ARCH} -s -o main + ${PASS_IFF_GOOD_MACHO} main + + # Make sure there are no symbols in the stripped file that aren't + # in the unstripped + nm -j main | comm -23 - main-no-strip.nm | ${FAIL_IF_STDIN} + + # Now make sure that all the __Z symbols exist + strip_cnt=`nm -j main | comm -12 - main-no-strip.nm | grep -c __Z`; \ + nostrip_cnt=`nm -j main|grep -c __Z`; \ + [ x"$$strip_cnt" = x"$$nostrip_cnt" ] + @echo PASS $$UNIT_TEST_NAME +clean: + rm -rf *.o main main-* *.nm *.out diff --git a/FireOpal/unit-tests/test-cases/strip-test3/comment.txt b/FireOpal/unit-tests/test-cases/strip-test3/comment.txt new file mode 100644 index 0000000..a99f78e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/strip-test3/comment.txt @@ -0,0 +1,21 @@ +Test strip: symbols referenced by indirect symbol table entries can't be stripped (4096290) + +__ZN9__gnu_cxx13new_allocatorIiE7destroyEPi +__ZNKSt12_Vector_baseIiSaIiEE13get_allocatorEv +__ZN9__gnu_cxx13new_allocatorIiEC2ERKS1_ +__ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPim +__ZN9__gnu_cxx13new_allocatorIiED2Ev +__ZNSt6vectorIiSaIiEEC1ERKS0_ +__ZNSaIiEC1ERKS_ +__ZN9__gnu_cxx13new_allocatorIiE10deallocateEPim +__ZNSt12_Vector_baseIiSaIiEE12_Vector_implC1ERKS0_ +__ZNSaIiED2Ev +__ZNSt12_Vector_baseIiSaIiEED2Ev +__ZNSaIiEC1Ev +__ZNSt12_Vector_baseIiSaIiEEC2ERKS0_ +__ZNSt6vectorIiSaIiEED1Ev +__ZNSaIiED1Ev +__ZSt8_DestroyIPiSaIiEEvT_S2_T0_ +__ZN9__gnu_cxx13new_allocatorIiEC2Ev +__ZNSaIiEC2ERKS_ +__ZNSt12_Vector_baseIiSaIiEE12_Vector_implD1Ev diff --git a/FireOpal/unit-tests/test-cases/strip-test3/main.cxx b/FireOpal/unit-tests/test-cases/strip-test3/main.cxx new file mode 100644 index 0000000..dd65fef --- /dev/null +++ b/FireOpal/unit-tests/test-cases/strip-test3/main.cxx @@ -0,0 +1,6 @@ +#include +int main() +{ + std::vector stuff; + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/strip_local/Makefile b/FireOpal/unit-tests/test-cases/strip_local/Makefile new file mode 100644 index 0000000..f32267c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/strip_local/Makefile @@ -0,0 +1,53 @@ +## +# Copyright (c) 2006-2007 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 + +# +# This test case checks merges two .o files. One uses +# a lazy and non-lazy pointer to access the second. +# The result then has local symbols stripped. So the +# end result is a .o file with a lazy and non-lazy pointer to +# anonymous stuff. +# +# + + +run: all + +all: + ${CC} ${CCFLAGS} hello.c -c + ${FAIL_IF_BAD_OBJ} hello.o + + ${CC} ${CCFLAGS} foo.c -c + ${FAIL_IF_BAD_OBJ} foo.o + + ${LD} -r hello.o foo.o -o hellofoo.o + ${FAIL_IF_BAD_OBJ} hellofoo.o + + strip -x hellofoo.o -o hellofoostripped.o + ${CC} ${CCFLAGS} hellofoostripped.o -o main + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm -rf *.o main diff --git a/FireOpal/unit-tests/test-cases/strip_local/foo.c b/FireOpal/unit-tests/test-cases/strip_local/foo.c new file mode 100644 index 0000000..defa5eb --- /dev/null +++ b/FireOpal/unit-tests/test-cases/strip_local/foo.c @@ -0,0 +1,8 @@ + + +int __attribute__((visibility("hidden"))) data = 3; + +void __attribute__((visibility("hidden"))) func(int x) { } + + + diff --git a/FireOpal/unit-tests/test-cases/strip_local/hello.c b/FireOpal/unit-tests/test-cases/strip_local/hello.c new file mode 100644 index 0000000..2deed42 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/strip_local/hello.c @@ -0,0 +1,33 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * 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@ + */ +#include + +extern int data; +extern void func(int); + +int main() +{ + func(data); +} + diff --git a/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/Makefile b/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/Makefile new file mode 100644 index 0000000..c0647b3 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/Makefile @@ -0,0 +1,57 @@ +## +# Copyright (c) 2007 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 + +ifeq "${ARCH}" "i386" + POINTER_SEGMENT = __IMPORT + POINTER_SECTION = __pointers +else + POINTER_SEGMENT = __DATA + POINTER_SECTION = __nl_symbol_ptr +endif + + +# +# Test that using strip -R to selectively strip symbol names +# of of a .o file still works with ld. +# + +run: all + +all: + ${CC} ${CCFLAGS} a.c -c -o a.o + ${CC} ${CCFLAGS} b.c -c -o b.o + ${CC} ${CCFLAGS} c.c -c -o c.o + ${CC} ${CCFLAGS} func.c -c -o func.o + ${LD} -arch ${ARCH} -r a.o b.o c.o -o most.o + strip -x -R strip.list most.o -o most.stripped.o + ${CC} ${CCFLAGS} most.stripped.o func.o -dynamiclib -o dylib1 + ${LD} -arch ${ARCH} -r most.stripped.o func.o -o all.o + ${CC} ${CCFLAGS} all.o -dynamiclib -o dylib2 + otool -X -s ${POINTER_SEGMENT} ${POINTER_SECTION} dylib1 >dylib1.pointers + otool -X -s ${POINTER_SEGMENT} ${POINTER_SECTION} dylib2 >dylib2.pointers + ${PASS_IFF} diff dylib1.pointers dylib2.pointers + +clean: + rm -rf *.o dylib1 dylib2 *.pointers diff --git a/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/a.c b/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/a.c new file mode 100644 index 0000000..141b6d9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/a.c @@ -0,0 +1,7 @@ + +int aData = 0; + +void a() +{ + ++aData; +} diff --git a/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/b.c b/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/b.c new file mode 100644 index 0000000..9608402 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/b.c @@ -0,0 +1,12 @@ + +int bData = 0; + +void b() +{ + ++bData; +} + +void bb() +{ + ++bData; +} diff --git a/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/c.c b/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/c.c new file mode 100644 index 0000000..db8276a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/c.c @@ -0,0 +1,11 @@ +extern void b(); +extern void bb(); + +extern void func(void*); + + +void c() +{ + func(&b); + func(&bb); +} \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/func.c b/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/func.c new file mode 100644 index 0000000..5724811 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/func.c @@ -0,0 +1 @@ +void func(void* x) {} diff --git a/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/strip.list b/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/strip.list new file mode 100644 index 0000000..77ac6e9 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stripped-indirect-symbol-table/strip.list @@ -0,0 +1,2 @@ +_b +_bb diff --git a/FireOpal/unit-tests/test-cases/stub-generation-weak/Makefile b/FireOpal/unit-tests/test-cases/stub-generation-weak/Makefile new file mode 100644 index 0000000..e7cf05c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stub-generation-weak/Makefile @@ -0,0 +1,42 @@ +## +# Copyright (c) 2007 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 ld generates correct stubs when some are weak_import +# + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib + ${CC} ${CCFLAGS} main.c libfoo.dylib -o main + otool -Iv main | grep '_foo' | ${FAIL_IF_EMPTY} + otool -Iv main | grep '_bar' | ${FAIL_IF_EMPTY} + otool -Iv main | grep '_baz' | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main + + +clean: + rm libfoo.dylib main diff --git a/FireOpal/unit-tests/test-cases/stub-generation-weak/foo.c b/FireOpal/unit-tests/test-cases/stub-generation-weak/foo.c new file mode 100644 index 0000000..0122e53 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stub-generation-weak/foo.c @@ -0,0 +1,5 @@ + +void foo() {} +void bar() {} +void baz() {} + diff --git a/FireOpal/unit-tests/test-cases/stub-generation-weak/main.c b/FireOpal/unit-tests/test-cases/stub-generation-weak/main.c new file mode 100644 index 0000000..1803c6a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stub-generation-weak/main.c @@ -0,0 +1,40 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 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 + +extern void foo() __attribute__((weak_import)); +extern void bar() __attribute__((weak_import)); +extern void baz(); + +int main() +{ + if ( &foo != 0 ) { + foo(); + bar(); + } + baz(); + return 0; +} + + diff --git a/FireOpal/unit-tests/test-cases/stub-generation/Makefile b/FireOpal/unit-tests/test-cases/stub-generation/Makefile new file mode 100644 index 0000000..9e6ecc0 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stub-generation/Makefile @@ -0,0 +1,41 @@ +## +# Copyright (c) 2007 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 ld generates correct stubs +# + +run: all + +all: + ${CC} ${CCFLAGS} test.c -dynamiclib -Wl,-interposable -o libtest.dylib + # only stub should be to _test + otool -Iv libtest.dylib | grep '1 entries' | ${FAIL_IF_EMPTY} + otool -Iv libtest.dylib | grep '_test' | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} libtest.dylib + + +clean: + rm libtest.dylib diff --git a/FireOpal/unit-tests/test-cases/stub-generation/test.c b/FireOpal/unit-tests/test-cases/stub-generation/test.c new file mode 100644 index 0000000..4573622 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/stub-generation/test.c @@ -0,0 +1,40 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 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 + +const char kMyStr[] = "hello"; + +int test() +{ + return 10; +} + + +const char* getstr() +{ + test(); + return kMyStr; +} + + diff --git a/FireOpal/unit-tests/test-cases/switch-jump-table/Makefile b/FireOpal/unit-tests/test-cases/switch-jump-table/Makefile new file mode 100644 index 0000000..aacd78d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/switch-jump-table/Makefile @@ -0,0 +1,56 @@ +## +# 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@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Test that -mdynamic-no-pic jump table in the middle of +# a function does not cause relocations. +# +# SPEC2000/eon built with -mdynamic-no-pic won't run +# + +run: all + +all: + # check jump table in a weak function + ${CC} ${CCFLAGS} main.c switch.s -o main + 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 + 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 + 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 + ${CC} ${CCFLAGS} main.c switch.s -o main -Wl,-pie -read_only_relocs suppress + otool -rv main | grep "External relocation" | ${FAIL_IF_STDIN} + otool -rv main | grep "Local relocation" | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main + + +clean: + rm -f main diff --git a/FireOpal/unit-tests/test-cases/switch-jump-table/interpose.exp b/FireOpal/unit-tests/test-cases/switch-jump-table/interpose.exp new file mode 100644 index 0000000..b9e50b8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/switch-jump-table/interpose.exp @@ -0,0 +1,2 @@ +_foo +_bar diff --git a/FireOpal/unit-tests/test-cases/switch-jump-table/main.c b/FireOpal/unit-tests/test-cases/switch-jump-table/main.c new file mode 100644 index 0000000..f44b624 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/switch-jump-table/main.c @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/switch-jump-table/switch.s b/FireOpal/unit-tests/test-cases/switch-jump-table/switch.s new file mode 100644 index 0000000..12b559f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/switch-jump-table/switch.s @@ -0,0 +1,49 @@ + + .section __TEXT,__textcoal_nt,coalesced,pure_instructions + + + +/* + Simulate a switch statement in a weak function compiled + to a jump table +*/ + .globl _foo + .weak_definition _foo +_foo: + nop + nop +#if __arm__ || __i386__ + .long L1 + .long L2 + .long L3 +#endif + nop +L1: nop +L2: nop +L3: nop + nop + + +/* + Simulate a switch statement in a regular function compiled + to a jump table +*/ + .text + .globl _bar +_bar: nop + nop + nop + nop +#if __arm__ || __i386__ + .long L5 + .long L6 + .long L7 +#endif + nop +L5: nop +L6: nop +L7: nop + nop + + + diff --git a/FireOpal/unit-tests/test-cases/symbol-moving/Makefile b/FireOpal/unit-tests/test-cases/symbol-moving/Makefile new file mode 100644 index 0000000..fc85d7b --- /dev/null +++ b/FireOpal/unit-tests/test-cases/symbol-moving/Makefile @@ -0,0 +1,93 @@ +## +# Copyright (c) 2007 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 magic $ld$ symbols which tell ld to view exported symbols +# differently than dyld sees them. +# +# In this test case aaa and bbb both moved between libfoo and libar +# between 10.4 and 10.5. +# + + +run: all + +all: + # In this test case aaa and bbb both moved between libfoo and libar + # between 10.4 and 10.5. + ${CC} ${CCFLAGS} -dynamiclib bar.c bbb.c anotb.c -o libbar.dylib + ${FAIL_IF_BAD_MACHO} libbar.dylib + ${CC} ${CCFLAGS} -dynamiclib foo.c aaa.c bnota.c -o libfoo.dylib + ${FAIL_IF_BAD_MACHO} libfoo.dylib + ${CC} ${CCFLAGS} main.c -o main-10.4 libfoo.dylib libbar.dylib -mmacosx-version-min=10.4 + nm -m main-10.4 | grep _aaa | grep libbar | ${FAIL_IF_EMPTY} + nm -m main-10.4 | grep _bbb | grep libfoo | ${FAIL_IF_EMPTY} + ${CC} ${CCFLAGS} main.c -o main-10.4a libbar.dylib libfoo.dylib -mmacosx-version-min=10.4 + nm -m main-10.4a | grep _aaa | grep libbar | ${FAIL_IF_EMPTY} + nm -m main-10.4a | grep _bbb | grep libfoo | ${FAIL_IF_EMPTY} + ${CC} ${CCFLAGS} main.c -o main-10.5 libfoo.dylib libbar.dylib -mmacosx-version-min=10.5 + nm -m main-10.5 | grep _aaa | grep libfoo | ${FAIL_IF_EMPTY} + nm -m main-10.5 | grep _bbb | grep libbar | ${FAIL_IF_EMPTY} + ${CC} ${CCFLAGS} main.c -o main-10.5a libbar.dylib libfoo.dylib -mmacosx-version-min=10.5 + nm -m main-10.5a | grep _aaa | grep libfoo | ${FAIL_IF_EMPTY} + nm -m main-10.5a | grep _bbb | grep libbar | ${FAIL_IF_EMPTY} + # In this test case aaa and bbb both moved between subframeworks of Foo and Bar + # between 10.4 and 10.5. + mkdir -p Frameworks/Foo.framework/Frameworks/subFoo.framework + ${CC} ${CCFLAGS} -dynamiclib foo.c aaa.c -o Frameworks/Foo.framework/Frameworks/subFoo.framework/subFoo \ + -install_name /System/Library/Frameworks/Foo.framework/Frameworks/subFoo.framework/subFoo \ + -umbrella Foo + ${CC} ${CCFLAGS} -dynamiclib bnota.c -o Frameworks/Foo.framework/Foo \ + -install_name /System/Library/Frameworks/Frameworks/Foo.framework/Foo \ + Frameworks/Foo.framework/Frameworks/subFoo.framework/subFoo + mkdir -p Frameworks/Bar.framework/Frameworks/subBar.framework + ${CC} ${CCFLAGS} -dynamiclib bar.c bbb.c -o Frameworks/Bar.framework/Frameworks/subBar.framework/subBar \ + -install_name /System/Library/Frameworks/Bar.framework/Frameworks/subBar.framework/subBar \ + -umbrella Bar + ${CC} ${CCFLAGS} -dynamiclib anotb.c -o Frameworks/Bar.framework/Bar \ + -install_name /System/Library/Frameworks/Frameworks/Bar.framework/Bar \ + Frameworks/Bar.framework/Frameworks/subBar.framework/subBar + ${CC} ${CCFLAGS} main.c -o main-10.4 -framework Foo -framework Bar -mmacosx-version-min=10.4 \ + -F./Frameworks -F./Frameworks/Bar.framework/Frameworks -F./Frameworks/Foo.framework/Frameworks + nm -m main-10.4 | grep _aaa | grep " Bar" | ${FAIL_IF_EMPTY} + nm -m main-10.4 | grep _bbb | grep " Foo" | ${FAIL_IF_EMPTY} + ${CC} ${CCFLAGS} main.c -o main-10.4a -framework Bar -framework Foo -mmacosx-version-min=10.4 \ + -F./Frameworks -F./Frameworks/Bar.framework/Frameworks -F./Frameworks/Foo.framework/Frameworks + nm -m main-10.4a | grep _aaa | grep " Bar" | ${FAIL_IF_EMPTY} + nm -m main-10.4a | grep _bbb | grep " Foo" | ${FAIL_IF_EMPTY} + ${CC} ${CCFLAGS} main.c -o main-10.5 -framework Foo -framework Bar -mmacosx-version-min=10.5 \ + -F./Frameworks -F./Frameworks/Bar.framework/Frameworks -F./Frameworks/Foo.framework/Frameworks + nm -m main-10.5 | grep _aaa | grep " Foo" | ${FAIL_IF_EMPTY} + nm -m main-10.5 | grep _bbb | grep " Bar" | ${FAIL_IF_EMPTY} + ${CC} ${CCFLAGS} main.c -o main-10.5a -framework Bar -framework Foo -mmacosx-version-min=10.5 \ + -F./Frameworks -F./Frameworks/Bar.framework/Frameworks -F./Frameworks/Foo.framework/Frameworks + nm -m main-10.5a | grep _aaa | grep " Foo" | ${FAIL_IF_EMPTY} + nm -m main-10.5a | grep _bbb | grep " Bar" | ${FAIL_IF_EMPTY} + ${PASS_IFF} /usr/bin/true + + +clean: + + rm -rf libbar.dylib libfoo.dylib main-10.4 main-10.5 main-10.4a main-10.5a diff --git a/FireOpal/unit-tests/test-cases/symbol-moving/aaa.c b/FireOpal/unit-tests/test-cases/symbol-moving/aaa.c new file mode 100644 index 0000000..71123eb --- /dev/null +++ b/FireOpal/unit-tests/test-cases/symbol-moving/aaa.c @@ -0,0 +1,3 @@ + +void aaa() {} + diff --git a/FireOpal/unit-tests/test-cases/symbol-moving/anotb.c b/FireOpal/unit-tests/test-cases/symbol-moving/anotb.c new file mode 100644 index 0000000..60fcf64 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/symbol-moving/anotb.c @@ -0,0 +1,26 @@ + + +#define SYMBOL_IS_HERE_IN_10_4(sym) \ + extern const char sym##_tmp __asm("$ld$add$os10.4$_" #sym ); const char sym##_tmp = 0; + +#define SYMBOL_IS_HERE_IN_10_5(sym) \ + extern const char sym##_tmp __asm("$ld$add$os10.5$_" #sym ); const char sym##_tmp = 0; + +#define SYMBOL_NOT_HERE_IN_10_4(sym) \ + extern const char sym##_tmp __asm("$ld$hide$os10.4$_" #sym ); const char sym##_tmp = 0; + +#define SYMBOL_NOT_HERE_IN_10_5(sym) \ + extern const char sym##_tmp __asm("$ld$hide$os10.5$_" #sym ); const char sym##_tmp = 0; + + +// 10.4 10.5 +// aaa libbar libfoo +// bbb libfoo libbar +// + +// bbb is new here in 10.5. It was elsewhere in 10.4 +SYMBOL_NOT_HERE_IN_10_4(bbb) + +// aaa was here in 10.4 and move elsewhere +SYMBOL_IS_HERE_IN_10_4(aaa) + diff --git a/FireOpal/unit-tests/test-cases/symbol-moving/bar.c b/FireOpal/unit-tests/test-cases/symbol-moving/bar.c new file mode 100644 index 0000000..e425999 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/symbol-moving/bar.c @@ -0,0 +1 @@ +void bar() {} diff --git a/FireOpal/unit-tests/test-cases/symbol-moving/bbb.c b/FireOpal/unit-tests/test-cases/symbol-moving/bbb.c new file mode 100644 index 0000000..b6e9cc0 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/symbol-moving/bbb.c @@ -0,0 +1 @@ +void bbb() {} diff --git a/FireOpal/unit-tests/test-cases/symbol-moving/bnota.c b/FireOpal/unit-tests/test-cases/symbol-moving/bnota.c new file mode 100644 index 0000000..d29b878 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/symbol-moving/bnota.c @@ -0,0 +1,25 @@ +#define SYMBOL_IS_HERE_IN_10_4(sym) \ + extern const char sym##_tmp __asm("$ld$add$os10.4$_" #sym ); const char sym##_tmp = 0; + +#define SYMBOL_IS_HERE_IN_10_5(sym) \ + extern const char sym##_tmp __asm("$ld$add$os10.5$_" #sym ); const char sym##_tmp = 0; + +#define SYMBOL_NOT_HERE_IN_10_4(sym) \ + extern const char sym##_tmp __asm("$ld$hide$os10.4$_" #sym ); const char sym##_tmp = 0; + +#define SYMBOL_NOT_HERE_IN_10_5(sym) \ + extern const char sym##_tmp __asm("$ld$hide$os10.5$_" #sym ); const char sym##_tmp = 0; + + +// 10.4 10.5 +// aaa libbar libfoo +// bbb libfoo libbar +// + + +// bbb was here in 10.4 and move elsewhere +SYMBOL_IS_HERE_IN_10_4(bbb) + +// aaa is new here in 10.5. It was elsewhere in 10.4 +SYMBOL_NOT_HERE_IN_10_4(aaa) + diff --git a/FireOpal/unit-tests/test-cases/symbol-moving/foo.c b/FireOpal/unit-tests/test-cases/symbol-moving/foo.c new file mode 100644 index 0000000..6924ac6 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/symbol-moving/foo.c @@ -0,0 +1,3 @@ + +void foo() {} + diff --git a/FireOpal/unit-tests/test-cases/symbol-moving/main.c b/FireOpal/unit-tests/test-cases/symbol-moving/main.c new file mode 100644 index 0000000..902e908 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/symbol-moving/main.c @@ -0,0 +1,17 @@ + +extern void foo(); +extern void bar(); + +extern void aaa(); +extern void bbb(); + + +int main() +{ + foo(); + bar(); + aaa(); + bbb(); + + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/tentative-and-archive/Makefile b/FireOpal/unit-tests/test-cases/tentative-and-archive/Makefile new file mode 100644 index 0000000..e8a4a0e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/tentative-and-archive/Makefile @@ -0,0 +1,50 @@ +## +# 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@ +## +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 _var which +# should *not* cause libfoo.a(foo.o) to be loaded. +# +# ld crashes building XsanFS +# -undefined dynamic_lookup causes spurious extra symbols +# + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -c -o foo.o + libtool -static foo.o -o libfoo.a + ${CC} ${CCFLAGS} main.c libfoo.a -o main + ${CC} ${CCFLAGS} main.c libfoo.a -o main -undefined dynamic_lookup + nm -m main | grep "looked up" | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} main + + +clean: + rm -rf main libfoo.a foo.o diff --git a/FireOpal/unit-tests/test-cases/tentative-and-archive/foo.c b/FireOpal/unit-tests/test-cases/tentative-and-archive/foo.c new file mode 100644 index 0000000..a2254b5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/tentative-and-archive/foo.c @@ -0,0 +1,6 @@ + +extern void bar(); + +void foo() { bar(); } + +int var = 9; diff --git a/FireOpal/unit-tests/test-cases/tentative-and-archive/main.c b/FireOpal/unit-tests/test-cases/tentative-and-archive/main.c new file mode 100644 index 0000000..e5046a0 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/tentative-and-archive/main.c @@ -0,0 +1,8 @@ + +int var; + +int main() +{ + var = 3; + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/tentative-and-dylib/Makefile b/FireOpal/unit-tests/test-cases/tentative-and-dylib/Makefile new file mode 100644 index 0000000..0ed1fa4 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/tentative-and-dylib/Makefile @@ -0,0 +1,56 @@ +## +# Copyright (c) 2007 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 dylibs +# + +run: all + +all: + ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib + ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -Wl,-reexport_library,libbar.dylib + # verify -warn_commons works + ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -Wl,-warn_commons 2> warnings.log + grep "using common symbol" warnings.log | ${FAIL_IF_EMPTY} + # verify -commons use_dylibs works + ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -Wl,-commons,use_dylibs + nm -m main | grep _var | grep libfoo | ${FAIL_IF_EMPTY} + # verify -commons ignore_dylibs works + ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -Wl,-commons,ignore_dylibs + nm -m main | grep _var | grep __DATA | ${FAIL_IF_EMPTY} + # verify -commons error works + ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -Wl,-commons,error 2> warnings.log + # verify -commons use_dylibs works with indirect dylibs + ${CC} ${CCFLAGS} main.c -Dvar=bar libfoo.dylib -o main -Wl,-commons,use_dylibs + nm -m main | grep _bar | grep libfoo | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main + + +clean: + rm -rf main libfoo.dylib libbar.dylib warnings.log diff --git a/FireOpal/unit-tests/test-cases/tentative-and-dylib/bar.c b/FireOpal/unit-tests/test-cases/tentative-and-dylib/bar.c new file mode 100644 index 0000000..e425999 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/tentative-and-dylib/bar.c @@ -0,0 +1 @@ +void bar() {} diff --git a/FireOpal/unit-tests/test-cases/tentative-and-dylib/foo.c b/FireOpal/unit-tests/test-cases/tentative-and-dylib/foo.c new file mode 100644 index 0000000..c1bb919 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/tentative-and-dylib/foo.c @@ -0,0 +1,2 @@ +void foo() {} +int var = 9; diff --git a/FireOpal/unit-tests/test-cases/tentative-and-dylib/main.c b/FireOpal/unit-tests/test-cases/tentative-and-dylib/main.c new file mode 100644 index 0000000..e5046a0 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/tentative-and-dylib/main.c @@ -0,0 +1,8 @@ + +int var; + +int main() +{ + var = 3; + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/tentative-to-real-hidden/Makefile b/FireOpal/unit-tests/test-cases/tentative-to-real-hidden/Makefile new file mode 100644 index 0000000..833d676 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/tentative-to-real-hidden/Makefile @@ -0,0 +1,52 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + + +# +# Verify that -r -d -exported_symbol_list uses proper relocations for hidden +# newly defined (no longer tentative) definitions. +# + +ifneq (${ARCH},x86_64) + BETTER_NOT_FIND = _tent +else + # x86_64 uses a different style of relocations, so external relocs are ok to have + BETTER_NOT_FIND = blahblah +endif + + + +run: all + +all: + ${CC} ${CCFLAGS} test.c -c -o test.o + ${FAIL_IF_BAD_OBJ} test.o + + ${LD} -arch ${ARCH} -d -r test.o -exported_symbol _tent1 -o test-r.o + otool -rv test-r.o | grep ${BETTER_NOT_FIND} | ${PASS_IFF_EMPTY} + + +clean: + rm -rf *.o diff --git a/FireOpal/unit-tests/test-cases/tentative-to-real-hidden/test.c b/FireOpal/unit-tests/test-cases/tentative-to-real-hidden/test.c new file mode 100644 index 0000000..c9cf479 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/tentative-to-real-hidden/test.c @@ -0,0 +1,11 @@ + +// tentative definitions +int tent1; +int tent2; +int __attribute__((visibility("hidden"))) tent3; + +// initialized to point to tentative definitions +int* pa = &tent1; +int* pb = &tent2; +int* pc = &tent3; + diff --git a/FireOpal/unit-tests/test-cases/tentative-to-real/Makefile b/FireOpal/unit-tests/test-cases/tentative-to-real/Makefile new file mode 100644 index 0000000..092aa2e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/tentative-to-real/Makefile @@ -0,0 +1,45 @@ +## +# Copyright (c) 2006 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 + + +# +# The point of this test is to verify that -r -d +# will transform a tentative definition into a real one. +# + +run: all + +all: + ${CC} ${CCFLAGS} test.c -c -o test.${ARCH}.o + ${FAIL_IF_BAD_OBJ} test.${ARCH}.o + + ${LD} -arch ${ARCH} -r test.${ARCH}.o -o test-r.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} test-r.${ARCH}.o | grep tentative | ${FAIL_IF_EMPTY} + + ${LD} -arch ${ARCH} -r -d test.${ARCH}.o -o test-r-d.${ARCH}.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} test-r-d.${ARCH}.o | grep tentative | ${PASS_IFF_EMPTY} + +clean: + rm -rf *.o diff --git a/FireOpal/unit-tests/test-cases/tentative-to-real/comment.txt b/FireOpal/unit-tests/test-cases/tentative-to-real/comment.txt new file mode 100644 index 0000000..de80bea --- /dev/null +++ b/FireOpal/unit-tests/test-cases/tentative-to-real/comment.txt @@ -0,0 +1 @@ +The point of this test is to verify that -r -d will transform a tentative definition into a real one. diff --git a/FireOpal/unit-tests/test-cases/tentative-to-real/test.c b/FireOpal/unit-tests/test-cases/tentative-to-real/test.c new file mode 100644 index 0000000..87360fc --- /dev/null +++ b/FireOpal/unit-tests/test-cases/tentative-to-real/test.c @@ -0,0 +1,3 @@ + +// a tentative definition +int a; diff --git a/FireOpal/unit-tests/test-cases/thumb-blx/Makefile b/FireOpal/unit-tests/test-cases/thumb-blx/Makefile new file mode 100644 index 0000000..65b3131 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/thumb-blx/Makefile @@ -0,0 +1,54 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + + +# +# Verify the linker parses call sites correctly. +# The tricky case is thumb, which uses a blx to call to +# the arm stubs. This test verifies that there is no +# +2 error by checking for "plus" and that when the file +# is regenerated through ld -r that the dumped output +# remains unchanged. +# + +run: all + +all: + ${CC} ${CCFLAGS} test.c -c -o test.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.o > test.o.dump + # verify no +2 errors + grep "plus" test.o.dump | ${FAIL_IF_STDIN} + # verify .o file can be regenerated to an equivalent state + ${LD} -arch ${ARCH} -r -keep_private_externs test.o -o test-r.o + ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r.o > test-r.o.dump + # verify final linked image has no +2 errors + ${CC} ${CCFLAGS} test.o -o test + otool -tV -p _main test | grep blx | grep -v _malloc | ${FAIL_IF_STDIN} + ${CC} ${CCFLAGS} test-r.o -o test-r + otool -tV -p _main test-r | grep blx | grep -v _malloc | ${FAIL_IF_STDIN} + ${PASS_IFF} diff test.o.dump test-r.o.dump + +clean: + rm -rf test.o test-r.o test.o.dump test-r.o.dump test test-r diff --git a/FireOpal/unit-tests/test-cases/thumb-blx/test.c b/FireOpal/unit-tests/test-cases/thumb-blx/test.c new file mode 100644 index 0000000..ce0359f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/thumb-blx/test.c @@ -0,0 +1,36 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include + +int main() +{ + malloc(1); + malloc(2); + malloc(3); + malloc(4); + return 0; +} + + diff --git a/FireOpal/unit-tests/test-cases/undefined-dynamic-lookup/Makefile b/FireOpal/unit-tests/test-cases/undefined-dynamic-lookup/Makefile new file mode 100644 index 0000000..eebcc37 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/undefined-dynamic-lookup/Makefile @@ -0,0 +1,47 @@ +## +# Copyright (c) 2007 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 -U and -undefined dynamic_lookup work +# + +run: all + +all: + ${CC} ${CCFLAGS} main.c -o main -undefined dynamic_lookup + nm -m main | grep _foo | grep "dynamically looked up" | ${FAIL_IF_EMPTY} + ${FAIL_IF_BAD_MACHO} main + + ${CC} ${CCFLAGS} main.c -o main -Wl,-U,_foo + nm -m main | grep _foo | grep "dynamically looked up" | ${FAIL_IF_EMPTY} + ${FAIL_IF_BAD_MACHO} main + + ${CC} ${CCFLAGS} main.c -o main -flat_namespace -Wl,-U,_foo + nm -m main | grep _foo | grep "dynamically looked up" | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} main + + +clean: + rm main diff --git a/FireOpal/unit-tests/test-cases/undefined-dynamic-lookup/main.c b/FireOpal/unit-tests/test-cases/undefined-dynamic-lookup/main.c new file mode 100644 index 0000000..5de972f --- /dev/null +++ b/FireOpal/unit-tests/test-cases/undefined-dynamic-lookup/main.c @@ -0,0 +1,32 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2007 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 + +extern void foo(); + +int main() +{ + foo(); + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/Makefile b/FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/Makefile new file mode 100644 index 0000000..789a304 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/Makefile @@ -0,0 +1,46 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Test that a late loaded hidden symbol from an archive does not conflict +# with a symbol previously found in a dylib. +# gcc 4.2: DejaGnu failures due to libgcc visibility issues with -m64 -mmacosx-version-min=10.4 (G5) +# + +SHELL = bash # use bash shell so we can redirect just stderr + + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib + ${CC} ${CCFLAGS} -c bar.c -o bar.o + libtool -static bar.o -o libbar.a + ${CC} ${CCFLAGS} main.c -o main libfoo.dylib libbar.a 2>warning.log + cat warning.log | ${PASS_IFF_EMPTY} + + +clean: + rm -f libfoo.dylib bar.o libbar.a main warning.log diff --git a/FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/bar.c b/FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/bar.c new file mode 100644 index 0000000..276f502 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/bar.c @@ -0,0 +1,11 @@ + + +void __attribute__((weak,visibility("hidden"))) foo() +{ + +} + + +void bar() +{ +} diff --git a/FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/foo.c b/FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/foo.c new file mode 100644 index 0000000..3d8616a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/foo.c @@ -0,0 +1,5 @@ + + +void __attribute__((weak)) foo() +{ +} diff --git a/FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/main.c b/FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/main.c new file mode 100644 index 0000000..8c9c95c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/visibility-warning-dylib-v-archive/main.c @@ -0,0 +1,11 @@ + +extern void foo(); +extern void bar(); + + +int main() +{ + foo(); + bar(); + return 0; +} diff --git a/FireOpal/unit-tests/test-cases/visibility-warning/Makefile b/FireOpal/unit-tests/test-cases/visibility-warning/Makefile new file mode 100644 index 0000000..43bdcd8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/visibility-warning/Makefile @@ -0,0 +1,57 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Test that two weak symbols with different visibility causes a warning +# and a weak and strong with different visibilities do not cause a warning. +# Spurious link warnings for inline members of C++ template classes +# + +SHELL = bash # use bash shell so we can redirect just stderr + + +run: all + +all: + ${CC} ${CCFLAGS} -c foo_weak_hidden.c -o foo_weak_hidden.o + ${CC} ${CCFLAGS} -c foo_weak.c -o foo_weak.o + ${CC} ${CCFLAGS} -c foo.c -o foo.o + ${CC} ${CCFLAGS} -c foo_hidden.c -o foo_hidden.o + # weak default and weak hidden should warn + ${CC} ${CCFLAGS} foo_weak_hidden.o foo_weak.o -dynamiclib -o libfoo.dylib 2> warnings.log + grep visibility warnings.log | ${FAIL_IF_EMPTY} + # weak hidden and strong should not warn + ${CC} ${CCFLAGS} foo_weak_hidden.o foo.o -dynamiclib -o libfoo.dylib 2> warnings.log + grep visibility warnings.log | ${FAIL_IF_STDIN} + # weak default and strong hidden should not warn + ${CC} ${CCFLAGS} foo_weak.o foo_hidden.o -dynamiclib -o libfoo.dylib 2> warnings.log + grep visibility warnings.log | ${FAIL_IF_STDIN} + # weak default and weak hidden but -w should not warn + ${CC} ${CCFLAGS} foo_weak_hidden.o foo_weak.o -dynamiclib -w -o libfoo.dylib 2> warnings.log + cat warnings.log | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} libfoo.dylib + +clean: + rm libfoo.dylib foo_weak_hidden.o foo_weak.o foo.o foo_hidden.o warnings.log diff --git a/FireOpal/unit-tests/test-cases/visibility-warning/foo.c b/FireOpal/unit-tests/test-cases/visibility-warning/foo.c new file mode 100644 index 0000000..1624757 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/visibility-warning/foo.c @@ -0,0 +1,5 @@ + + +void foo() +{ +} diff --git a/FireOpal/unit-tests/test-cases/visibility-warning/foo_hidden.c b/FireOpal/unit-tests/test-cases/visibility-warning/foo_hidden.c new file mode 100644 index 0000000..cac53ce --- /dev/null +++ b/FireOpal/unit-tests/test-cases/visibility-warning/foo_hidden.c @@ -0,0 +1,5 @@ + + +void __attribute__((visibility("hidden"))) foo() +{ +} diff --git a/FireOpal/unit-tests/test-cases/visibility-warning/foo_weak.c b/FireOpal/unit-tests/test-cases/visibility-warning/foo_weak.c new file mode 100644 index 0000000..3d8616a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/visibility-warning/foo_weak.c @@ -0,0 +1,5 @@ + + +void __attribute__((weak)) foo() +{ +} diff --git a/FireOpal/unit-tests/test-cases/visibility-warning/foo_weak_hidden.c b/FireOpal/unit-tests/test-cases/visibility-warning/foo_weak_hidden.c new file mode 100644 index 0000000..8d461e6 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/visibility-warning/foo_weak_hidden.c @@ -0,0 +1,5 @@ + + +void __attribute__((weak, visibility("hidden"))) foo() +{ +} diff --git a/FireOpal/unit-tests/test-cases/weak-def-ordinal/Makefile b/FireOpal/unit-tests/test-cases/weak-def-ordinal/Makefile new file mode 100644 index 0000000..222a82d --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak-def-ordinal/Makefile @@ -0,0 +1,50 @@ +## +# Copyright (c) 2007 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 + + +# +# libfoo.dylib has weak defintiion of _foo +# libbar.dylib has strong defintiion of _foo +# +# Tests that if you link against libfoo.dylib and libbar.dylib +# that the two-level-namespace ordinal is set to the non-weak definition +# +# ld should keep looking when it finds a weak definition in a dylib# +# + +run: all + +all: + ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib + ${FAIL_IF_BAD_MACHO} libfoo.dylib + ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib + ${FAIL_IF_BAD_MACHO} libbar.dylib + ${CC} ${CCFLAGS} main.c -o main libfoo.dylib libbar.dylib + nm -m main | grep _aaa | grep libbar | ${FAIL_IF_EMPTY} + nm -m main | grep _bbb | grep libfoo | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm libfoo.dylib libbar.dylib main diff --git a/FireOpal/unit-tests/test-cases/weak-def-ordinal/bar.c b/FireOpal/unit-tests/test-cases/weak-def-ordinal/bar.c new file mode 100644 index 0000000..ae61731 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak-def-ordinal/bar.c @@ -0,0 +1,6 @@ + +int aaa() +{ + return 1; +} + diff --git a/FireOpal/unit-tests/test-cases/weak-def-ordinal/foo.c b/FireOpal/unit-tests/test-cases/weak-def-ordinal/foo.c new file mode 100644 index 0000000..d371654 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak-def-ordinal/foo.c @@ -0,0 +1,11 @@ + +int __attribute__((weak)) aaa() +{ + return 0; +} + +int __attribute__((weak)) bbb() +{ + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/weak-def-ordinal/main.c b/FireOpal/unit-tests/test-cases/weak-def-ordinal/main.c new file mode 100644 index 0000000..74726fb --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak-def-ordinal/main.c @@ -0,0 +1,35 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +extern void aaa(); +extern void bbb(); + +int main() +{ + aaa(); + bbb(); + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/weak_dylib/Makefile b/FireOpal/unit-tests/test-cases/weak_dylib/Makefile new file mode 100644 index 0000000..0a00a39 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_dylib/Makefile @@ -0,0 +1,49 @@ +## +# Copyright (c) 2007 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + +# +# Test the if all symbols from a dylib are weak_import, that the whole dylib is weakly loaded +# + + +run: all + +all: + ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib + ${FAIL_IF_BAD_MACHO} libfoo.dylib + + ${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 + # 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 + otool -lv main | grep -B2 libbar.dylib | grep LC_LOAD_DYLIB | ${FAIL_IF_EMPTY} + ${PASS_IFF_GOOD_MACHO} main + + +clean: + rm -rf libfoo.dylib libbar.dylib main diff --git a/FireOpal/unit-tests/test-cases/weak_dylib/bar.c b/FireOpal/unit-tests/test-cases/weak_dylib/bar.c new file mode 100644 index 0000000..261a806 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_dylib/bar.c @@ -0,0 +1,9 @@ + + +#include "bar.h" + +void bar1() {} +void bar2() {} +void bar3() {} +void bar4() {} + diff --git a/FireOpal/unit-tests/test-cases/weak_dylib/bar.h b/FireOpal/unit-tests/test-cases/weak_dylib/bar.h new file mode 100644 index 0000000..7ea2ef3 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_dylib/bar.h @@ -0,0 +1,9 @@ + + +extern void bar1(); +extern void bar2() __attribute__((weak_import)); +extern void bar3(); +extern void bar4() __attribute__((weak_import)); + + + diff --git a/FireOpal/unit-tests/test-cases/weak_dylib/foo.c b/FireOpal/unit-tests/test-cases/weak_dylib/foo.c new file mode 100644 index 0000000..aa25da5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_dylib/foo.c @@ -0,0 +1,9 @@ + + +#include "foo.h" + +void foo1() {} +void foo2() {} +void foo3() {} +void foo4() {} + diff --git a/FireOpal/unit-tests/test-cases/weak_dylib/foo.h b/FireOpal/unit-tests/test-cases/weak_dylib/foo.h new file mode 100644 index 0000000..54b3e36 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_dylib/foo.h @@ -0,0 +1,6 @@ + + +extern void foo1(); +extern void foo2() __attribute__((weak_import)); +extern void foo3(); +extern void foo4() __attribute__((weak_import)); diff --git a/FireOpal/unit-tests/test-cases/weak_dylib/main.c b/FireOpal/unit-tests/test-cases/weak_dylib/main.c new file mode 100644 index 0000000..cb61aeb --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_dylib/main.c @@ -0,0 +1,22 @@ + +#include "foo.h" +#include "bar.h" + +void* p; + +int main (void) +{ + // non-lazy reference to foo2 + p = &foo2; + // lazy reference to foo4 + foo4(); + + // non-lazy reference to bar2 + p = &bar2; + // lazy reference to bar4 and bar1 + bar4(); + bar1(); + + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/weak_import/Makefile b/FireOpal/unit-tests/test-cases/weak_import/Makefile new file mode 100644 index 0000000..d1fa1f3 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import/Makefile @@ -0,0 +1,62 @@ +## +# Copyright (c) 2006 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 + +# +# Test the weak_import attribute works +# + + +run: all + +all: + ${CC} ${CCFLAGS} -dynamiclib -single_module foo.c -o libfoo-${ARCH}.dylib + ${FAIL_IF_BAD_MACHO} libfoo-${ARCH}.dylib + + ${CC} ${CCFLAGS} -mmacosx-version-min=10.4 main.c -o main-${ARCH} libfoo-${ARCH}.dylib + nm -m main-${ARCH} | grep _func1 | grep -v weak >/dev/null + nm -m main-${ARCH} | grep _func2 | grep weak >/dev/null + nm -m main-${ARCH} | grep _func3 | grep -v weak >/dev/null + nm -m main-${ARCH} | grep _func4 | grep weak >/dev/null + nm -m main-${ARCH} | grep _data1 | grep -v weak >/dev/null + nm -m main-${ARCH} | grep _data2 | grep weak >/dev/null + nm -m main-${ARCH} | grep _data3 | grep -v weak >/dev/null + nm -m main-${ARCH} | grep _data4 | grep weak >/dev/null + otool -rv main-${ARCH} | grep _data6 > /dev/null + ${FAIL_IF_BAD_MACHO} main-${ARCH} + + ${CC} ${CCFLAGS} -mmacosx-version-min=10.4 main.c -dynamiclib -o main-${ARCH}.dylib libfoo-${ARCH}.dylib + nm -m main-${ARCH}.dylib | grep _func1 | grep -v weak >/dev/null + nm -m main-${ARCH}.dylib | grep _func2 | grep weak >/dev/null + nm -m main-${ARCH}.dylib | grep _func3 | grep -v weak >/dev/null + nm -m main-${ARCH}.dylib | grep _func4 | grep weak >/dev/null + nm -m main-${ARCH}.dylib | grep _data1 | grep -v weak >/dev/null + nm -m main-${ARCH}.dylib | grep _data2 | grep weak >/dev/null + nm -m main-${ARCH}.dylib | grep _data3 | grep -v weak >/dev/null + nm -m main-${ARCH}.dylib | grep _data4 | grep weak >/dev/null + otool -rv main-${ARCH}.dylib | grep _data6 > /dev/null + ${PASS_IFF_GOOD_MACHO} main-${ARCH}.dylib + +clean: + rm -rf *.dylib main-* diff --git a/FireOpal/unit-tests/test-cases/weak_import/foo.c b/FireOpal/unit-tests/test-cases/weak_import/foo.c new file mode 100644 index 0000000..900b052 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import/foo.c @@ -0,0 +1,17 @@ + + +#include "foo.h" + +void func1() {} +void func2() {} +void func3() {} +void func4() {} + + +int data1 = 0; +int data2 = 0; // weak_import initialized +int data3; +int data4; // weak_import uninitialized +int data5 = 0; +int data6 = 0; // weak_import + diff --git a/FireOpal/unit-tests/test-cases/weak_import/foo.h b/FireOpal/unit-tests/test-cases/weak_import/foo.h new file mode 100644 index 0000000..f455515 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import/foo.h @@ -0,0 +1,16 @@ + + +extern void func1(); +extern void func2() __attribute__((weak_import)); +extern void func3(); +extern void func4() __attribute__((weak_import)); + +extern int data1; +extern int data2 __attribute__((weak_import)); +extern int data3; +extern int data4 __attribute__((weak_import)); +extern int data5; +extern int data6 __attribute__((weak_import)); + + + diff --git a/FireOpal/unit-tests/test-cases/weak_import/main.c b/FireOpal/unit-tests/test-cases/weak_import/main.c new file mode 100644 index 0000000..3266aed --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import/main.c @@ -0,0 +1,20 @@ + +#include "foo.h" + + +int* pdata5 = &data5; +int* pdata6 = &data6; + + +int main (void) +{ + // make non-lazy reference to func3 and func4 + if ( &func3 == &func4 ) { + // make lazy reference to func3 and func4 + func1(); + func2(); + } + + return data1 + data2 + data3 + data4; +} + diff --git a/FireOpal/unit-tests/test-cases/weak_import2/Makefile.newtest b/FireOpal/unit-tests/test-cases/weak_import2/Makefile.newtest new file mode 100644 index 0000000..5e51b89 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import2/Makefile.newtest @@ -0,0 +1,58 @@ +## +# Copyright (c) 2006 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 + +# +# Test the weak_import attribute works +# + + +run: all + +all: + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c foo.c -o foo-${ARCH}.o + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c foo1.c -o foo1-${ARCH}.o + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -dynamiclib foo-${ARCH}.o foo1-${ARCH}.o -o libfoo-${ARCH}.dylib + ${PASS_IFF_ERROR} ${CC} ${CCFLAGS} -mmacosx-version-min=10.4 main.c -o main-${ARCH} libfoo-${ARCH}.dylib + nm -m main-${ARCH} | grep _func1 | grep -v weak >/dev/null + nm -m main-${ARCH} | grep _func2 | grep weak >/dev/null + nm -m main-${ARCH} | grep _func3 | grep -v weak >/dev/null + nm -m main-${ARCH} | grep _func4 | grep weak >/dev/null + nm -m main-${ARCH} | grep _data1 | grep -v weak >/dev/null + nm -m main-${ARCH} | grep _data2 | grep weak >/dev/null + nm -m main-${ARCH} | grep _data3 | grep -v weak >/dev/null + nm -m main-${ARCH} | grep _data4 | grep weak >/dev/null + ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -mmacosx-version-min=10.4 main.c -dynamiclib -o main-${ARCH}.dylib libfoo-${ARCH}.dylib + nm -m main-${ARCH}.dylib | grep _func1 | grep -v weak >/dev/null + nm -m main-${ARCH}.dylib | grep _func2 | grep weak >/dev/null + nm -m main-${ARCH}.dylib | grep _func3 | grep -v weak >/dev/null + nm -m main-${ARCH}.dylib | grep _func4 | grep weak >/dev/null + nm -m main-${ARCH}.dylib | grep _data1 | grep -v weak >/dev/null + nm -m main-${ARCH}.dylib | grep _data2 | grep weak >/dev/null + nm -m main-${ARCH}.dylib | grep _data3 | grep -v weak >/dev/null + nm -m main-${ARCH}.dylib | grep _data4 | grep weak >/dev/null + ${PASS_IFF_GOOD_MACHO} main-${ARCH}.dylib + +clean: + rm -rf *.dylib main-* *.o diff --git a/FireOpal/unit-tests/test-cases/weak_import2/comment.txt b/FireOpal/unit-tests/test-cases/weak_import2/comment.txt new file mode 100644 index 0000000..5be42d8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import2/comment.txt @@ -0,0 +1 @@ +Test the weak_import attribute works diff --git a/FireOpal/unit-tests/test-cases/weak_import2/foo.c b/FireOpal/unit-tests/test-cases/weak_import2/foo.c new file mode 100644 index 0000000..900b052 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import2/foo.c @@ -0,0 +1,17 @@ + + +#include "foo.h" + +void func1() {} +void func2() {} +void func3() {} +void func4() {} + + +int data1 = 0; +int data2 = 0; // weak_import initialized +int data3; +int data4; // weak_import uninitialized +int data5 = 0; +int data6 = 0; // weak_import + diff --git a/FireOpal/unit-tests/test-cases/weak_import2/foo.h b/FireOpal/unit-tests/test-cases/weak_import2/foo.h new file mode 100644 index 0000000..f455515 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import2/foo.h @@ -0,0 +1,16 @@ + + +extern void func1(); +extern void func2() __attribute__((weak_import)); +extern void func3(); +extern void func4() __attribute__((weak_import)); + +extern int data1; +extern int data2 __attribute__((weak_import)); +extern int data3; +extern int data4 __attribute__((weak_import)); +extern int data5; +extern int data6 __attribute__((weak_import)); + + + diff --git a/FireOpal/unit-tests/test-cases/weak_import2/foo1.c b/FireOpal/unit-tests/test-cases/weak_import2/foo1.c new file mode 100644 index 0000000..4580a87 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import2/foo1.c @@ -0,0 +1,10 @@ + + +void func2() {} +void func4() {} + + +int data2 = 0; // foo.c also has weak_import initialized +int data4; // foo.c also has weak_import uninitialized +int data6 = 0; // foo.c also has weak_import + diff --git a/FireOpal/unit-tests/test-cases/weak_import2/main.c b/FireOpal/unit-tests/test-cases/weak_import2/main.c new file mode 100644 index 0000000..3266aed --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import2/main.c @@ -0,0 +1,20 @@ + +#include "foo.h" + + +int* pdata5 = &data5; +int* pdata6 = &data6; + + +int main (void) +{ + // make non-lazy reference to func3 and func4 + if ( &func3 == &func4 ) { + // make lazy reference to func3 and func4 + func1(); + func2(); + } + + return data1 + data2 + data3 + data4; +} + diff --git a/FireOpal/unit-tests/test-cases/weak_import3/Makefile b/FireOpal/unit-tests/test-cases/weak_import3/Makefile new file mode 100644 index 0000000..98a2779 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import3/Makefile @@ -0,0 +1,43 @@ +## +# Copyright (c) 2006 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 + +# +# Test the weak_import attribute works +# + + +run: all + +all: + ${CC} ${CCFLAGS} -c foo.c -o foo-${ARCH}.o + ${FAIL_IF_BAD_OBJ} foo-${ARCH}.o + + ${CC} ${CCFLAGS} -c foo1.c -o foo1-${ARCH}.o + ${FAIL_IF_BAD_OBJ} foo1-${ARCH}.o + + ${PASS_IFF_ERROR} ${CC} ${CCFLAGS} -dynamiclib foo-${ARCH}.o foo1-${ARCH}.o -o libfoo-${ARCH}.dylib 2>/dev/null + +clean: + rm -rf *.o *.dylib main-* diff --git a/FireOpal/unit-tests/test-cases/weak_import3/comment.txt b/FireOpal/unit-tests/test-cases/weak_import3/comment.txt new file mode 100644 index 0000000..5be42d8 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import3/comment.txt @@ -0,0 +1 @@ +Test the weak_import attribute works diff --git a/FireOpal/unit-tests/test-cases/weak_import3/foo.c b/FireOpal/unit-tests/test-cases/weak_import3/foo.c new file mode 100644 index 0000000..900b052 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import3/foo.c @@ -0,0 +1,17 @@ + + +#include "foo.h" + +void func1() {} +void func2() {} +void func3() {} +void func4() {} + + +int data1 = 0; +int data2 = 0; // weak_import initialized +int data3; +int data4; // weak_import uninitialized +int data5 = 0; +int data6 = 0; // weak_import + diff --git a/FireOpal/unit-tests/test-cases/weak_import3/foo.h b/FireOpal/unit-tests/test-cases/weak_import3/foo.h new file mode 100644 index 0000000..f455515 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import3/foo.h @@ -0,0 +1,16 @@ + + +extern void func1(); +extern void func2() __attribute__((weak_import)); +extern void func3(); +extern void func4() __attribute__((weak_import)); + +extern int data1; +extern int data2 __attribute__((weak_import)); +extern int data3; +extern int data4 __attribute__((weak_import)); +extern int data5; +extern int data6 __attribute__((weak_import)); + + + diff --git a/FireOpal/unit-tests/test-cases/weak_import3/foo1.c b/FireOpal/unit-tests/test-cases/weak_import3/foo1.c new file mode 100644 index 0000000..392a5b7 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import3/foo1.c @@ -0,0 +1,4 @@ +#include "foo.h" + +int data4; // foo.c also has weak_import uninitialized + diff --git a/FireOpal/unit-tests/test-cases/weak_import3/main.c b/FireOpal/unit-tests/test-cases/weak_import3/main.c new file mode 100644 index 0000000..3266aed --- /dev/null +++ b/FireOpal/unit-tests/test-cases/weak_import3/main.c @@ -0,0 +1,20 @@ + +#include "foo.h" + + +int* pdata5 = &data5; +int* pdata6 = &data6; + + +int main (void) +{ + // make non-lazy reference to func3 and func4 + if ( &func3 == &func4 ) { + // make lazy reference to func3 and func4 + func1(); + func2(); + } + + return data1 + data2 + data3 + data4; +} + diff --git a/FireOpal/unit-tests/test-cases/why_live/Makefile b/FireOpal/unit-tests/test-cases/why_live/Makefile new file mode 100644 index 0000000..9c4811e --- /dev/null +++ b/FireOpal/unit-tests/test-cases/why_live/Makefile @@ -0,0 +1,44 @@ +## +# Copyright (c) 2007 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 + + +# +# Text -why_live option with dead code stripping +# + +run: all + +all: + ${CC} ${CCFLAGS} main.c foo.c bar.c -o main -dead_strip -Wl,-why_live,_bar 2>call_chains + grep _bar call_chains | ${FAIL_IF_EMPTY} + grep _foo call_chains | ${FAIL_IF_EMPTY} + grep _main call_chains | ${FAIL_IF_EMPTY} + grep _frob call_chains | ${FAIL_IF_STDIN} + ${PASS_IFF_GOOD_MACHO} main + +clean: + rm main call_chains diff --git a/FireOpal/unit-tests/test-cases/why_live/bar.c b/FireOpal/unit-tests/test-cases/why_live/bar.c new file mode 100644 index 0000000..e425999 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/why_live/bar.c @@ -0,0 +1 @@ +void bar() {} diff --git a/FireOpal/unit-tests/test-cases/why_live/foo.c b/FireOpal/unit-tests/test-cases/why_live/foo.c new file mode 100644 index 0000000..9a2edf5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/why_live/foo.c @@ -0,0 +1,12 @@ + +extern void bar(); + +void foo() +{ + bar(); +} + +void frob() +{ + bar(); +} \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/why_live/main.c b/FireOpal/unit-tests/test-cases/why_live/main.c new file mode 100644 index 0000000..a5a79d5 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/why_live/main.c @@ -0,0 +1,7 @@ +extern void foo(); + +int main() +{ + foo(); + return 0; +} \ No newline at end of file diff --git a/FireOpal/unit-tests/test-cases/zero-fill/Makefile b/FireOpal/unit-tests/test-cases/zero-fill/Makefile new file mode 100644 index 0000000..d6c0639 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/zero-fill/Makefile @@ -0,0 +1,38 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that ld +# can link a program with a large zero-fill section +# + +run: all + +all: + ${CC} ${CCFLAGS} test.c -o test-${ARCH} + ${PASS_IFF_GOOD_MACHO} test-${ARCH} + +clean: + rm -rf test-* diff --git a/FireOpal/unit-tests/test-cases/zero-fill/test.c b/FireOpal/unit-tests/test-cases/zero-fill/test.c new file mode 100644 index 0000000..cfdc08c --- /dev/null +++ b/FireOpal/unit-tests/test-cases/zero-fill/test.c @@ -0,0 +1,51 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +// if we used one big array, the linker would page align it +// but we want to test a non-page align big chunk of zero-fill data +int bigarray1[256]; +int bigarray2[256]; +int bigarray3[256]; +int bigarray4[256]; +int bigarray5[256]; +int bigarray6[256]; +static int staticbigarray1[256]; +static int staticbigarray2[256]; +static int staticbigarray3[256]; +static int staticbigarray4[256]; +static int staticbigarray5[256]; +static int staticbigarray6[256]; + +int main() +{ + staticbigarray1[10] = 4; + staticbigarray2[10] = 4; + staticbigarray3[10] = 4; + staticbigarray4[10] = 4; + staticbigarray5[10] = 4; + staticbigarray6[10] = 4; + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/zero-fill2/Makefile b/FireOpal/unit-tests/test-cases/zero-fill2/Makefile new file mode 100644 index 0000000..b011e70 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/zero-fill2/Makefile @@ -0,0 +1,38 @@ +## +# Copyright (c) 2006-2007 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 + +# +# The point of this test is a sanity check that ld +# can link a program with a large zero-fill section +# + +run: all + +all: + ${CC} ${CCFLAGS} test.c -o test + ${PASS_IFF_GOOD_MACHO} test + +clean: + rm -rf test diff --git a/FireOpal/unit-tests/test-cases/zero-fill2/comment.txt b/FireOpal/unit-tests/test-cases/zero-fill2/comment.txt new file mode 100644 index 0000000..a1710c1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/zero-fill2/comment.txt @@ -0,0 +1 @@ +The point of this test is a sanity check that ld can link a program with a large zero-fill section diff --git a/FireOpal/unit-tests/test-cases/zero-fill2/test.c b/FireOpal/unit-tests/test-cases/zero-fill2/test.c new file mode 100644 index 0000000..219cdc2 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/zero-fill2/test.c @@ -0,0 +1,58 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +// if we used one big array, the linker would page align it +// but we want to test a non-page align big chunk of zero-fill data + +#if __LP64__ + #define BOOST 100UL +#else + #define BOOST 1 +#endif + +int bigarray1[256]; +int bigarray2[2560]; +int bigarray3[25600]; +int bigarray4[256000]; +int bigarray5[2560000]; +int bigarray6[256000000*BOOST]; +static int staticbigarray1[256]; +static int staticbigarray2[2560]; +static int staticbigarray3[25600]; +static int staticbigarray4[256000]; +static int staticbigarray5[2560000]; +static int staticbigarray6[25600000*BOOST]; + +int main() +{ + staticbigarray1[10] = 4; + staticbigarray2[10] = 4; + staticbigarray3[10] = 4; + staticbigarray4[10] = 4; + staticbigarray5[10] = 4; + staticbigarray6[10] = 4; + return 0; +} + diff --git a/FireOpal/unit-tests/test-cases/zero-fill3/Makefile b/FireOpal/unit-tests/test-cases/zero-fill3/Makefile new file mode 100644 index 0000000..6266019 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/zero-fill3/Makefile @@ -0,0 +1,50 @@ +## +# Copyright (c) 2006 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 + +# +# The point of this test is a sanity check that ld +# can link a program with a large zero-fill section +# + +run: test-run-${ARCH} + +# i386 catches the problem in the assembler phase +test-run-i386: + ${PASS_IFF} true + +test-run-ppc test-run-ppc64: test-${ARCH} + +test-run-x86_64 test-ppc64: + ${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: + ${PASS_IFF_ERROR} ${CC} ${CCFLAGS} -DSHRINK=4 test.c --save-temps -o test-${ARCH} 2>/dev/null + +clean: + rm -rf test-* *.o *.s *.i diff --git a/FireOpal/unit-tests/test-cases/zero-fill3/comment.txt b/FireOpal/unit-tests/test-cases/zero-fill3/comment.txt new file mode 100644 index 0000000..a1710c1 --- /dev/null +++ b/FireOpal/unit-tests/test-cases/zero-fill3/comment.txt @@ -0,0 +1 @@ +The point of this test is a sanity check that ld can link a program with a large zero-fill section diff --git a/FireOpal/unit-tests/test-cases/zero-fill3/test.c b/FireOpal/unit-tests/test-cases/zero-fill3/test.c new file mode 100644 index 0000000..64ac72a --- /dev/null +++ b/FireOpal/unit-tests/test-cases/zero-fill3/test.c @@ -0,0 +1,63 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006 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@ + */ +#include + +// if we used one big array, the linker would page align it +// but we want to test a non-page align big chunk of zero-fill data +int bigarray1[256]; +int bigarray2[2560]; +int bigarray3[25600]; +int bigarray4[256000]; +int bigarray5[2560000]; +int bigarray7[16777216L+1]; +int bigarray8[2*16777216L+1]; +int bigarray9[4*16777216L+1]; +int bigarray10[8*16777216L+1]; +int bigarray11[16*16777216L+1]; +int bigarray99[2147483647U/SHRINK]; +static int staticbigarray1[256]; +static int staticbigarray2[2560]; +static int staticbigarray3[25600]; +static int staticbigarray4[256000]; +static int staticbigarray5[2560000]; +static int staticbigarray6[25600000]; +//static int staticbigarray99[2147483647U/SHRINK]; + +int main() +{ + bigarray5[10] = 4; + bigarray7[10] = 4; + bigarray8[10] = 4; + bigarray9[10] = 4; + bigarray10[10] = 4; + bigarray11[10] = 4; + bigarray99[10] = 4; + staticbigarray1[10] = 4; + staticbigarray2[10] = 4; + staticbigarray3[10] = 4; + staticbigarray4[10] = 4; + staticbigarray5[10] = 4; + staticbigarray6[10] = 4; + return 0; +} diff --git a/src/ArchiveReader.hpp b/src/ArchiveReader.hpp index c3aebf8..a195090 100644 --- a/src/ArchiveReader.hpp +++ b/src/ArchiveReader.hpp @@ -65,7 +65,9 @@ public: virtual std::vector* getJustInTimeAtomsFor(const char* name); virtual std::vector* getStabs() { return NULL; } virtual void optimize(std::vector&, std::vector&, - std::vector&, uint32_t, ObjectFile::Reader* writer, + std::vector&, const std::set&, + uint32_t, ObjectFile::Reader* writer, + const std::vector& llvmOptions, bool allGlobalsAReDeadStripRoots, int okind, bool verbose, bool saveTemps, const char* outputFilePath, bool pie, bool allowTextRelocs); @@ -366,14 +368,16 @@ std::vector& Reader::getAtoms() template void Reader::optimize(std::vector& allAtoms, std::vector& newAtoms, - std::vector& additionalUndefines, uint32_t nextOrdinal, ObjectFile::Reader* writer, + std::vector& additionalUndefines, const std::set& deadAtoms, + uint32_t nextOrdinal, ObjectFile::Reader* writer, + const std::vector& llvmOptions, bool allGlobalsAReDeadStripRoots, int okind, bool verbose, bool saveTemps, const char* outputFilePath, bool pie, bool allowTextRelocs) { for(std::vector::iterator it=fInstantiatedReaders.begin(); it != fInstantiatedReaders.end(); ++it) { - (*it)->optimize(allAtoms, newAtoms, additionalUndefines, nextOrdinal, writer, allGlobalsAReDeadStripRoots, - okind, verbose, saveTemps, outputFilePath, pie, allowTextRelocs); + (*it)->optimize(allAtoms, newAtoms, additionalUndefines, deadAtoms, nextOrdinal, writer, llvmOptions, + allGlobalsAReDeadStripRoots, okind, verbose, saveTemps, outputFilePath, pie, allowTextRelocs); } } diff --git a/src/LTOReader.hpp b/src/LTOReader.hpp index 4cd5644..2736f43 100644 --- a/src/LTOReader.hpp +++ b/src/LTOReader.hpp @@ -209,7 +209,7 @@ public: bool getTranslationUnitSource (const char **dir, const char **name) const { return false; } const char * getName () const { return "__llvm-internal-atom"; } - const char * getDisplayName() const { return this->getName(); } + const char * getDisplayName() const { return "llvm bitcode"; } Scope getScope() const { return scopeTranslationUnit; } DefinitionKind getDefinitionKind() const { return kRegularDefinition; } SymbolTableInclusion getSymbolTableInclusion() const { return kSymbolTableNotIn; } @@ -232,7 +232,7 @@ public: void addReference(const char* targetName); private: - class Reader& fOwner; + class Reader& fOwner; std::vector fReferences; }; @@ -279,9 +279,12 @@ public: virtual time_t getModificationTime() { return fModTime; } virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return kDebugInfoNone; } virtual std::vector* getStabs() { return NULL; } - virtual void optimize(std::vector &allAtoms, std::vector &newAtoms, - std::vector &additionalUndefines, uint32_t nextInputOrdinal, - ObjectFile::Reader* writer, bool allGlobalsAReDeadStripRoots, + virtual void optimize(std::vector& allAtoms, std::vector& newAtoms, + std::vector& additionalUndefines, const std::set&, + uint32_t nextInputOrdinal, + ObjectFile::Reader* writer, + const std::vector& llvmOptions, + bool allGlobalsAReDeadStripRoots, int outputKind, bool verbose, bool saveTemps, const char* outputFilePath, bool pie, bool allowTextRelocs); @@ -321,7 +324,7 @@ Reader::~Reader() Reader::Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options, cpu_type_t arch) - : fArchitecture(arch), fPath(path), fModTime(modTime), fInternalAtom(*this), fReaderOptions(options) + : fArchitecture(arch), fPath(strdup(path)), fModTime(modTime), fInternalAtom(*this), fReaderOptions(options) { fgReaders.insert(this); @@ -329,6 +332,7 @@ Reader::Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path if ( fModule == NULL ) throwf("could not parse object file %s: %s", path, lto_get_error_message()); + fAtoms.push_back(&fInternalAtom); uint32_t count = ::lto_module_get_num_symbols(fModule); for (uint32_t i=0; i < count; ++i) { @@ -406,8 +410,10 @@ bool Reader::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type } void Reader::optimize(std::vector& allAtoms, std::vector& newAtoms, - std::vector& additionalUndefines, uint32_t nextInputOrdinal, - ObjectFile::Reader* writer, bool allGlobalsAReDeadStripRoots, + std::vector& additionalUndefines, const std::set& deadAtoms, + uint32_t nextInputOrdinal, ObjectFile::Reader* writer, + const std::vector& llvmOptions, + bool allGlobalsAReDeadStripRoots, int okind, bool verbose, bool saveTemps, const char* outputFilePath, bool pie, bool allowTextRelocs) { @@ -427,7 +433,12 @@ void Reader::optimize(std::vector& allAtoms, std::vector::iterator it=fgReaders.begin(); it != fgReaders.end(); ++it) { if ( ::lto_codegen_add_module(generator, (*it)->fModule) ) - throwf("lto: could not merge in %s", (*it)->fPath); + throwf("lto: could not merge in %s because %s", (*it)->fPath, ::lto_get_error_message()); + } + + // add any -mllvm command line options + for (std::vector::const_iterator it=llvmOptions.begin(); it != llvmOptions.end(); ++it) { + ::lto_codegen_debug_options(generator, *it); } // the linker must preserve all globals in dylibs and flat images @@ -444,7 +455,7 @@ void Reader::optimize(std::vector& allAtoms, std::vectorgetFile())) == 0 ) { - // remember if we've seen an atoms not from an llvm reader and not from the writer + // remember if we've seen any atoms not from an llvm reader and not from the writer if ( atom->getFile() != writer ) hasNonllvmAtoms = true; std::vector& refs = atom->getReferences(); @@ -462,6 +473,21 @@ void Reader::optimize(std::vector& allAtoms, std::vector::iterator it = deadAtoms.begin(); it != deadAtoms.end(); ++it) { + ObjectFile::Atom* atom = *it; + if ( fgReaders.count((Reader*)(atom->getFile())) != 0 ) { + const char* name = atom->getName(); + ::lto_codegen_add_must_preserve_symbol(generator, name); + deadllvmAtoms[name] = (Atom*)atom; + } + } + + // tell code generator about symbols that must be preserved for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) { const char* name = it->first; @@ -539,7 +565,7 @@ void Reader::optimize(std::vector& allAtoms, std::vectormakeMachOReader(machOFile, machOFileLen, nextInputOrdinal); - // sync generated mach-o atoms with existing atoms ld know about + // sync generated mach-o atoms with existing atoms ld knows about std::vector machoAtoms = machoReader->getAtoms(); for (std::vector::iterator it = machoAtoms.begin(); it != machoAtoms.end(); ++it) { ObjectFile::Atom* atom = *it; @@ -551,8 +577,24 @@ void Reader::optimize(std::vector& allAtoms, std::vectorsecond->setRealAtom(atom); } else { - // this atom is did not exist orginally, tell ld about it - newAtoms.push_back(atom); + // an atom of this name was not in the allAtoms list the linker gave us + if ( deadllvmAtoms.find(name) != deadllvmAtoms.end() ) { + // this corresponding to an atom that the linker coalesced away. Ignore it + // Make sure there any dependent atoms are also marked dead + std::vector& refs = atom->getReferences(); + for (std::vector::iterator ri=refs.begin(), re=refs.end(); ri != re; ++ri) { + ObjectFile::Reference* ref = *ri; + if ( ref->getKind() == 2 /*kGroupSubordinate*/ ) { // FIX FIX + ObjectFile::Atom* targ = &ref->getTarget(); + deadllvmAtoms[targ->getName()] = (Atom*)atom; + } + } + } + else + { + // this is something new that lto conjured up, tell ld its new + newAtoms.push_back(atom); + } } } else { diff --git a/src/MachOWriterExecutable.hpp b/src/MachOWriterExecutable.hpp index f983c6c..8667ae4 100644 --- a/src/MachOWriterExecutable.hpp +++ b/src/MachOWriterExecutable.hpp @@ -6550,6 +6550,8 @@ void Writer::partitionIntoSections() currentSegmentInfo->fInitProtection = initprot; if ( initprot == 0 ) currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0 + else if ( fOptions.architecture() == CPU_TYPE_ARM ) + currentSegmentInfo->fMaxProtection = currentSegmentInfo->fInitProtection; // iPhoneOS wants max==init else currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; std::vector& customSegProtections = fOptions.customSegmentProtections(); @@ -6951,7 +6953,7 @@ void Writer::adjustLoadCommandsAndPadding() } else if ( fOptions.makeEncryptable() ) { // want load commands to end on a page boundary, so __text starts on page boundary - paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096); + paddingSize = 4096 - ((totalSizeOfHeaderAndLoadCommands+fOptions.minimumHeaderPad()) % 4096) + fOptions.minimumHeaderPad(); fEncryptionLoadCommand->setStartEncryptionOffset(totalSizeOfHeaderAndLoadCommands+paddingSize); } else { diff --git a/src/ObjectDump.cpp b/src/ObjectDump.cpp index e46cd3d..a06c7a2 100644 --- a/src/ObjectDump.cpp +++ b/src/ObjectDump.cpp @@ -30,7 +30,7 @@ #include "MachOReaderRelocatable.hpp" -#define LTO_SUPPORT 1 +#define LTO_SUPPORT 0 #if LTO_SUPPORT #include "LTOReader.hpp" diff --git a/src/ObjectFile.h b/src/ObjectFile.h index 37a2892..1f42994 100644 --- a/src/ObjectFile.h +++ b/src/ObjectFile.h @@ -29,6 +29,7 @@ #include #include #include +#include @@ -139,7 +140,9 @@ public: // For relocatable object files only virtual bool canScatterAtoms() { return true; } virtual void optimize(std::vector&, std::vector&, - std::vector&, uint32_t, ObjectFile::Reader* writer, + std::vector&, const std::set&, + uint32_t, ObjectFile::Reader* writer, + const std::vector& llvmOptions, bool allGlobalsAReDeadStripRoots, int okind, bool verbose, bool saveTemps, const char* outputFilePath, bool pie, bool allowTextRelocs) { } diff --git a/src/Options.cpp b/src/Options.cpp index d0a2d15..eb244ed 100644 --- a/src/Options.cpp +++ b/src/Options.cpp @@ -2311,6 +2311,12 @@ void Options::parse(int argc, const char* argv[]) else if ( strcmp(arg, "-no_encryption") == 0 ) { fEncryptable = false; } + else if ( strcmp(arg, "-mllvm") == 0 ) { + const char* opts = argv[++i]; + if ( opts == NULL ) + throw "missing argument to -mllvm"; + fLLVMOptions.push_back(opts); + } else { throwf("unknown option: %s", arg); } diff --git a/src/Options.h b/src/Options.h index d185848..4bbcffe 100644 --- a/src/Options.h +++ b/src/Options.h @@ -207,7 +207,8 @@ public: bool usingLazyDylibLinking() { return fUsingLazyDylibLinking; } bool verbose() { return fVerbose; } bool makeEncryptable() { return fEncryptable; } - + std::vector& llvmOptions() { return fLLVMOptions; } + private: class CStringEquals { @@ -355,7 +356,7 @@ private: std::vector fCustomSegmentAddresses; std::vector fCustomSegmentProtections; std::vector fDylibOverrides; - + std::vector fLLVMOptions; std::vector fLibrarySearchPaths; std::vector fFrameworkSearchPaths; std::vector fSDKPaths; diff --git a/src/ld.cpp b/src/ld.cpp index be90999..acd18c8 100644 --- a/src/ld.cpp +++ b/src/ld.cpp @@ -565,7 +565,8 @@ void Linker::optimize() std::vector newAtoms; std::vector additionalUndefines; for (std::vector::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) { - (*it)->optimize(fAllAtoms, newAtoms, additionalUndefines, fNextInputOrdinal, fOutputFile, + (*it)->optimize(fAllAtoms, newAtoms, additionalUndefines, fDeadAtoms, fNextInputOrdinal, fOutputFile, + fOptions.llvmOptions(), fOptions.allGlobalsAreDeadStripRoots(), (int)fOptions.outputKind(), fOptions.verbose(), fOptions.saveTempFiles(), fOptions.getOutputFilePath(), fOptions.positionIndependentExecutable(), fOptions.allowTextRelocs()); -- 2.45.2