--- /dev/null
+
+----- Tagged ld64-47
+
+
+----- Tagged ld64-46
+
+2006-03-10 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4419505> ld64 should figure out architecture from .o files
+ * unit-tests/test-cases/auto-arch: added
+ * src/ld.cpp: added Linker::inferArchitecture() to scan .o files are infer architecture to link
+ * src/MachOReaderArchive.hpp: enhanced validFile() to look deeper into archive and really valdate
+ * src/MachOWriterExecutable.hpp: stop using fOptions.architecture()
+ * src/Options.cpp: stop defaulting to ppc64
+
+
+2006-03-09 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4465004> Need "intentionally left blank" dylib stubs
+ * unit-tests/include/common.makefile: add VALID_ARCHS
+ * unit-tests/run-all-unit-tests: set up VALID_ARCHS
+ * unit-tests/test-cases/blank-stubs: add test case
+ * src/ld.cpp: in addDylib(), detect and ignore blank stubs
+ * src/MachOReaderDylib.hpp: in constructor, handle blank stubs
+
+2006-03-09 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4471424> crash in stub with 2GB pagezero
+ * src/MachOWriterExecutable.hpp: StubAtom<ppc64> can't be no-pic if a large zero-page is used
+
+2006-03-06 Nick Kledzik <kledzik@apple.com>
+
+ * src/Options.cpp: addSectionAlignment, warn if -sectalign alignment is not a power of two
+
+----- Tagged ld64-45
+
+
+2006-03-06 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4466930> LP64/9A122: ld64: hang when trying to link DiscRecording framework
+ * src/Options.cpp: addSectionAlignment, warn on zero. Use log2() for alignment conversion
+
+
+----- Tagged ld64-44
+
+2006-03-04 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: fix again test for detection of anonymous non-lazy-pointer.
+ Error out if .o file contains old __DWARFA style dwarf.
+
+2006-03-02 Nick Kledzik <kledzik@apple.com>
+
+ * src/ld.cpp: only re-map page aligned sub-parts of a fat file. A conformat mmap() requires alignment.
+
+----- Tagged ld64-43
+
+2006-03-02 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: <rdar://problem/4464370> tighten detection of anonymous non-lazy-pointer
+
+----- Tagged ld64-42
+
+2006-02-28 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: fix x86 __IMPORT permissions for class Segment
+
+2006-02-28 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4461240> SWB: ld64-37 (can't resolve symbol ___dso_handle)
+ * src/MachOWriterExecutable.hpp: add class DsoHandleAtom
+
+2006-02-28 Nick Kledzik <kledzik@apple.com>
+
+ * unit-tests/test-cases/literals-coalesce-alignment: added test case
+ * src/ld.cpp: when coalescing strings pick one with greater alignment
+ <rdar://problem/4458660> ld64: CG link failed because lo14 reference to anonymous non-lazy-pointer not aligned
+ * unit-tests/test-cases/relocs-c/test.c: tweak to fail like 4458660
+ * src/MachOReaderRelocatable.hpp: detect anonymous non-lazy-pointer and transform into real non-lazy-pointers
+
+----- Tagged ld64-41
+
+2006-02-24 Nick Kledzik <kledzik@apple.com>
+
+ * src/Options.cpp: Warning about -no_dead_strip_inits_and_terms and -i options.
+ Fix -weak-l option.
+
+----- Tagged ld64-40
+
+2006-02-24 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4454698> Leopard9A113: ppc64 libstdc++.dylib initializer crashes in pthread_once
+ * unit-tests/test-cases/multiple-entry-points: added
+ * src/MachOReaderRelocatable.hpp: make sure that if there are multiple symbols with the same
+ address, that we properly make zero length atoms for all but last symbol
+
+2006-02-24 Nick Kledzik <kledzik@apple.com>
+
+ * src/Options.cpp: <rdar://problem/4456093> ld64 doesn't realpath(3) B&I tracing paths
+
+2006-02-24 Nick Kledzik <kledzik@apple.com>
+
+ * src/Options.cpp: <rdar://problem/4457078> 9A110: ld64 can't deal with section names >16 chars
+
+2006-02-23 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOWriterExecutable.hpp: use vector.reserve() to minimize re-allocations
+ * src/Options.cpp: use vector.reserve() to minimize re-allocations
+ * src/MachOReaderRelocatable.hpp: use vector.reserve() to minimize re-allocations
+ * src/MachOReaderDylib.hpp: use vector.reserve() to minimize re-allocations
+ * src/ld.cpp: use vector.reserve() to minimize re-allocations
+
+2006-02-23 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4455927> ld64 creates corrupt executables (and has malloc errors) with -headerpad option
+ * src/MachOWriterExecutable.hpp: Change LoadCommandsPaddingAtom<A>::setSize() to update fLargestAtomSize
+ * unit-tests/test-cases/header-pad: added
+
+2006-02-23 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4455192> ld64 creates invalid static executables
+ * src/MachOWriterExecutable.hpp: Change MachHeaderAtom<A>::copyRawContent() to create correct header
+ for static executables. Change SymbolTableLoadCommandsAtom to skip LC_DYSYMTAB for static executables
+ * src/machochecker.cpp: Add tests that static executables are well formed
+ * unit-tests/test-cases/static-executable: added
+
+2006-02-22 Nick Kledzik <kledzik@apple.com>
+
+ * src/Options.cpp: <rdar://problem/4453468> chnage printf on unknown arg to a throw
+
+----- Tagged ld64-39
+
+2006-02-20 Nick Kledzik <kledzik@apple.com>
+
+ * unit-tests/test-cases/read-only-relocs: added new test case
+ * src/MachOWriterExecutable.hpp: <rdar://problem/4448922> detect and error on relocs in read-only sections
+ * src/MachOReaderRelocatable.hpp: fix parsing of i386 absolute addressing relocs
+
+2006-02-20 Nick Kledzik <kledzik@apple.com>
+
+ * unit-tests/test-cases/stabs-coalesce: added new test case
+ * src/ld.cpp.hpp: <rdar://problem/4449226> in collectStabs removed unused stabs
+
+----- Tagged ld64-38
+
+2006-02-17 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOWriterExecutable.hpp: <rdar://problem/4434578> set correct n_sect field of stabs
+
+2006-02-15 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderArchive.hpp: <rdar://problem/4441920> with -all_load skip over both kinds of SYMDEFs
+ * unit-tests/test-cases/archive-basic/Makefile: add -all_load test case
+
+----- Tagged ld64-37
+
+2006-02-13 Eric Christopher <echristo@apple.com>
+
+ * src/MachOWriterExecutable.hpp (assignFileOffsets): Simplify. Add comments.
+ Adjust whitespace.
+
+2006-02-13 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOWriterExecutable.hpp: in Writer<x86>::fixUpReferenceRelocatable() fix kPCRel32 for external case
+
+2006-02-13 Nick Kledzik <kledzik@apple.com>
+
+ * unit-tests/test-cases/zero-fill: added
+ * src/machochecker.cpp: check that S_ZEROFILL have no file offset
+ * src/MachOWriterExecutable.hpp: rework assignFileOffsets() to fix rdar://problem/4441145
+
+2006-02-12 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: <rdar://problem/4440880> fix use of first zero-length c-string in .o file
+
+2006-02-12 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: <rdar://problem/4440905> fix uninitialized fAlignment
+
+2006-02-12 Nick Kledzik <kledzik@apple.com>
+
+ * unit-tests/test-cases/relocs-asm/relocs-asm.s: add pointer-diff cases
+ * src/Architectures.hpp: make size explicit in ppc/ppc64 kPointerDiff
+ * src/MachOReaderRelocatable.hpp: don't allow kPointerDiff64 for ppc (just ppc64)
+ * src/MachOWriterExecutable.cpp: set proper r_length for ld -r of kPointerDiff
+
+----- Tagged ld64-36
+
+2006-02-08 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.cpp: rdar://problem/4438677 Handle when a .o file dwarf line info entries but no functions
+
+2006-02-08 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOWriterExecutable.cpp: Properly set address of first TEXT section
+ Keep S_COALESCED attribute for __eh_frame
+
+2006-02-08 Nick Kledzik <kledzik@apple.com>
+
+ * src/ld.cpp: Temporarily turn allowable client errors into warnings
+ * unit-tests/test-cases/allowable-clientMakefile: Temporarily let warnings be ok for above
+ * src/MachOWriterExecutable.hpp: fix ld -r to not use external relocations for symbols make static
+
+2006-02-08 Nick Kledzik <kledzik@apple.com>
+
+ * src/ld.cpp: A sibling in an umbrella can always link with its other siblings
+ * unit-tests/test-cases/allowable-client: add test case for above
+
+2006-02-08 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: support LOCAL non-lazy pointers to hidden symbols
+ * src/machochecker.cpp: verify indirect symbol table
+ * unit-tests/test-cases/private-non-lazy: added test case
+
+2006-02-07 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOWriterExecutable.hpp: fix calculation of file offsets in ld -r mode
+ * src/machochecker.cpp: verify segment file offsets are within file
+
+----- Tagged ld64-35
+
+2006-02-06 Nick Kledzik <kledzik@apple.com>
+
+ * ld.cpp: allow parent of sub-framework to link
+ * unit-tests/test-cases/allowable-client/Makefile: added cases for parent and clients of parent
+
+2006-02-04 Nick Kledzik <kledzik@apple.com>
+
+ * unit-tests/test-cases/relocs-c/test.c: added some array cases
+ * src/MachOReaderRelocatable.hpp: factor out makeReferenceToEH()
+ * src/MachOWriterExecutable.hpp: add initial support for non-lazy pointer synthesis
+
+----- Tagged ld64-34
+
+2006-02-04 Nick Kledzik <kledzik@apple.com>
+
+ * src/ld.cpp: <rdar://problem/4432917> fix -no_arch_warnings
+ <rdar://problem/4432932> fix -undefined warning
+ Do BINCL/EINCL optimization for gfull stabs
+ Implement "essential symbols" for stabs (-Sp)
+ Fix allowable clients to only test on direct libraries
+ * src/MachOReaderRelocatable.hpp: support BINCL/EINCL stabs
+
+2006-02-03 Nick Kledzik <kledzik@apple.com>
+
+ * src/machochecker.cpp: add code to check load command alignment
+ * src/MachOWriterExecutable.hpp: make load command alignment depend on architecture
+
+2006-02-03 Nick Kledzik <kledzik@apple.com>
+
+ * unit-tests/test-cases/literals-coalesce: added
+ * src/MachOReaderRelocatable.hpp: assure all targets of low14 ppc relocs are at least 4-byte alignmented
+
+----- Tagged ld64-33
+
+2006-02-02 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: properly coalesce 8-byte literals
+ * src/MachOWriterExecutable.hpp: support ppc64::kPointerDiff32
+
+----- Tagged ld64-32
+
+2006-02-02 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: support anonymous zero fill atoms
+
+2006-02-02 Nick Kledzik <kledzik@apple.com>
+
+ * src/ld.cpp: A weak definition is good enough, do not search archives for a non-weak one
+ * unit-tests/test-cases/archive-weak: add test case for above
+ * src/MachOReaderRelocatable.hpp: an atom should never have a by-name reference to itself
+ * src/Options.cpp: prevent .eh symbols from being exported via a -exported_symbols_list
+
+2006-02-01 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: Support -macosx_version_min 10.5
+
+2006-02-01 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: don't try to parse debug_line dwarf if no symboled atoms
+
+----- Tagged ld64-31
+
+2006-02-01 Eric Christopher <echristo@apple.com>
+
+ * unit-tests/test-cases/allow-stack-execute/Makefile: Move otool handling...
+ * unit-tests/include/common.makefile: ... here.
+ * unit-tests/bin/fail-if-stdin.pl: New.
+ * unit-tests/test-cases/no-uuid: Ditto.
+ * src/ld.cpp (Linker::) Add fCreateUUID.
+ (::Linker): Initialize.
+ (::collectStabs): Use. Set if dwarf or we have a UUID already.
+ (::writeOutput): Pass as argument to Writer::write along with option.
+ * src/Options.h (Option::emitUUID): Declare.
+ (Option::fEmitUUID): Ditto.
+ * src/Options.cpp (Option::emitUUID): New.
+ (parse): Handle -no_uuid.
+ * src/MachOReaderRelocatable (Reader::Reader): Handle LC_UUID.
+ * src/ExecutableFile.h (Writer::Write): Add createUUID boolean.
+ * src/MachOWriterExecutable: Add UUID forward declaration.
+ (fUUIDAtom): New.
+ (UUIDLoadCommandAtom): Emit LC_UUID if fEmit. New function emit. Size
+ to zero at start.
+ (Writer::writer): Add handle for LC_UUID. If createUUID emit LC_UUID.
+ (MachHeaderAtom::copyRawContent): Don't count a load command if its size is
+ 0.
+ (UUIDLoadCommandAtom::copyRawContent): Depend on fEmit.
+
+
+2006-01-31 Nick Kledzik <kledzik@apple.com>
+
+ * unit-tests/test-cases/dwarf-debug-notes : Added
+ * src/ld.cpp: don't generate debug note for .eh symbols
+ * src/MachOReaderRelocatable.hpp: make dwarf line info to atom matching faster and better
+
+2006-01-31 Nick Kledzik <kledzik@apple.com>
+
+ * ld64.xcodeproj/project.pbxproj : Make buildable on Leopard
+ * src/MachOFileAbstraction.hpp: make buildable without latest cctools headers
+
+2006-01-31 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: better error message for bad relocs
+ * src/ObjectDump.cpp: add emacs tab settings
+ * src/SectCreate.h: ditto
+ * src/SectCreate.cpp: ditto
+ * src/machochecker.cpp: ditto
+ * src/ExecutableFile.h: ditto
+
+2006-01-30 Eric Christopher <echristo@apple.com>
+
+ * src/ExecutableFile.h: Indent.
+
+2006-01-30 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: performance improvements
+ * src/ld.cpp: now that stubs are synthesized in write, don't need to special case anymore
+
+2006-01-30 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: fix parsing of pcc relocs
+ * unit-tests/test-cases/relocs-asm/relocs-asm.s: add test case for above
+
+2006-01-29 Nick Kledzik <kledzik@apple.com>
+
+ * unit-tests/test-cases/weak_import: added test case
+ * src/ld.cpp: move code for weak_import mismatch to writer
+ * src/ObjectFile.h: remove ImportWeakness methods
+ * src/MachOReaderDylib.hpp: ditto
+ * src/SectCreate.cpp: ditto
+ * src/Architectures.hpp: add new ReferenceKinds for weak_imports
+ * src/MachOReaderRelocatable.hpp: implement new ReferenceKinds
+ * src/MachOWriterExecutable.hpp: handle new ReferenceKinds and weak_import mismatches
+
+2006-01-29 Nick Kledzik <kledzik@apple.com>
+
+ * src/Options.cpp: verify -allow_stack_execute is only used on main executables
+
+2006-01-29 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: sync with latest dwarf reader from Geoff
+ * src/debugline.c: sync with latest dwarf reader from Geoff
+
+2006-01-27 Eric Christopher <echristo@apple.com>
+
+ * src/ld.cpp (Linker::syntesizeStabs): Correct spelling. Update all uses.
+
+2006-01-27 Eric Christopher <echristo@apple.com>
+
+ * src/Options.h (Options): Add hasExecutableStack, fExecutableStack.
+ * src/Options.cpp (Options::hasExecutableStack): New.
+ (Options::parse): Parse -allow_stack_execute.
+ * src/MachOWriterExecutable.hpp (MachHeaderAtom::copyRawContent):
+ Implement MH_ALLOW_STACK_EXECUTION.
+ * unit-tests/include/common.makefile (FAIL_IF_EMPTY): New.
+ * unit-tests/bin/fail-if-no-stdin.pl: New file.
+ * unit-tests/test-cases/allow-stack-execute: New directory.
+
+2006-01-27 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOFileAbstraction.hpp: rely on latest system headers
+ * src/MachOWriterExecutable.hpp: fix ppc stubs.
+ wrote new relocationNeededInFinalLinkedImage() to replace common code
+
+2006-01-27 Eric Christopher <echristo@apple.com>
+
+ * src/ld.cpp (logTraceInfo): New.
+ (Linker::addArchive): Use.
+ (Linker::addDylib): Ditto.
+ * src/ObjectFile (ReaderOptions::fTraceOutputFile): New.
+ * src/MachOReaderArchive.hpp (Reader::Reader): Move trace
+ logging to Linker::addArchive.
+ * src/Options.cpp (parsePreCommandLineEnvironment): Check
+ LD_PRINT_FILE if tracing dylibs or archives.
+
+2006-01-26 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOWriterExecutable.hpp: handle NULL strings in SO debug notes
+
+2006-01-26 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOWriterExecutable.hpp: fix header padding calculation and thread state
+
+2006-01-26 Nick Kledzik <kledzik@apple.com>
+
+ Rewrite all stabs processing.
+ Move sythesize of debug notes into ld.cpp
+
+2006-01-26 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOWriterExecutable.hpp: fix ppc and ppc64 stub relocs
+
+2006-01-25 Nick Kledzik <kledzik@apple.com>
+
+ * ld64.xcodeproj/project.pbxproj: special case building in Curry
+
+2006-01-25 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOWriterExecutable.hpp: fix bugs in stub/lazy-pointer synthesis
+
+2006-01-24 Eric Christopher <echristo@apple.com>
+
+ * src/ld.cpp (Linker::createReaders): Change logging title to XBS.
+ (Linker::addDylib): Ditto.
+ * src/MachOReaderArchive.hpp (Reader::Reader): Ditto.
+ * src/Options.h (fPrintOptions): New.
+ * src/Options.cpp (Options::Options): Initialize above.
+ (Options::checkForFile): Change logging title to XBS.
+ (Options::findFramework): Ditto.
+ (Options::parse): Add log for options.
+ (Options::parsePreCommandLineEnvironmentSettings): Add LD_TRACE_ARCHIVES,
+ LD_TRACE_DYLIBS, and LD_PRINT_OPTIONS.
+
+2006-01-24 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: better C++ eh parsing
+
+2006-01-23 Eric Christopher <echristo@apple.com>
+
+ * unit-tests/bin/fail-if-exit-zero.pl: New.
+ * unit-tests/include/common.makefile (FAIL_IF_SUCCESS): Use.
+ * unit-tests/allowable-client: New test.
+ * src/ld.cpp (Linker::addDylib): Check allowable clients before adding dylib.
+ * src/Options.h (allowableClients): New.
+ (clientName): Ditto.
+ (fAllowableClients): Ditto.
+ (fClientName): Ditto.
+ * src/Options.cpp: Implement above.
+ (parse): Handle -allowable_client and -client_name.
+ * src/MachOReaderDylib.hpp (getAllowableClients): New.
+ (fAllowableClients): Ditto.
+ (Reader): Process LC_SUB_CLIENT load command.
+ * src/ObjectFile.h (parentUmbrella): New.
+ (getAllowableClients): New.
+ * src/MachOWriterExecutable.hpp (AllowableClientLoadCommandsAtom): New.
+
+2006-01-23 Nick Kledzik <kledzik@apple.com>
+
+ * unit-tests/test-cases/archive-basic: added
+ * src/ld.cpp: fix shadowed local variable
+ * src/FileAbstraction.hpp: <rdar://problem/4417372> ld64 shouldn't inline when building debug
+
+2006-01-23 Nick Kledzik <kledzik@apple.com>
+
+ * src/ld.cpp: fix symbol not found error message
+ * src/MachOReaderDylib.hpp: add logging to hash table
+ * src/MachOReaderRelocatable.hpp: enable stabs processing. Handle static functions with stubs
+ handle labeled cstrings.
+ * src/MachOWriterExecutable.hpp: properly suppress atoms not in symbol table. fix low14 error check.
+ add StubAtomHelper.
+ * unit-tests/test-cases/relocs-literals/test.c: add more interesting edge cases
+
+2006-01-17 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: tweaks to synthesizing debug notes
+
+2006-01-16 Nick Kledzik <kledzik@apple.com>
+
+ * src/debugline.{sh}: added
+ * src/MachOReaderRelocatable.hpp: synthesize debug notes SOL from dwarf
+ * src/MachOWriterExecutable.hpp: fix lazy pointer section
+ * src/ObjectDump.hpp: Fix conditionalization
+ * unit-tests/test-cases/dwarf-strip: added
+
+2006-01-11 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: support Tiger crt1.o build with old ld64
+ * src/ObjectDump.hpp: Support -arch option
+
+2006-01-10 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOWriterExecutable.hpp: fix stubs for ppc64
+ * src/MachOFileAbstraction.hpp: fix typo for macho_routines
+ * ld64.xcodeproj/project.pbxproj: add machochecker target
+ * src/machochecker.cpp: new skeleton for checking mach-o file bit
+ * unit-tests/: Add support for running machochecker
+
+2006-01-10 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: warn if dwarf can't be parsed
+ * src/MachOReaderArchive.hpp: modTime for OSO stabs from archives is .a modTime
+
+2006-01-09 Nick Kledzik <kledzik@apple.com>
+
+ * track modification time of .o files so that sythesized OSO stab will have it
+
+2006-01-09 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOFileAbstraction.hpp: add macho_uuid_command
+ * src/MachOWriterExecutable.cpp: add UUID load command to generated files
+
+2006-01-09 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderDylib.hpp: no longer keep dylib memory mapped
+ * src/ld.cpp: don't track dylib sizes because they are not longer memory mapped
+
+2006-01-05 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: support new relocations
+
+2006-01-05 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderDylib.hpp: support MH_DYLIB_STUB
+ * src/MachOReaderRelocatable.hpp: Add Geoff's comp unit extractor
+
+2006-01-05 Nick Kledzik <kledzik@apple.com>
+
+ refactor: transform Atom::dontStripName() to getSymbolTableInclusion()
+ * src/ld.cpp: pass dyld_stub_binding_helper to writer
+ * src/MachOReaderRelocatable.hpp: update synthesized stabs
+ Ignore stubs and lazy pointers in .o files
+ Support initializers and terminators
+ * src/MachOWriterExecutable.hpp: synthesize stubs and lazy pointers as needed
+ * ld64.xcodeproj/project.pbxproj: change Release target to build with dwarf
+
+2006-01-03 Eric Christopher <echristo@apple.com>
+
+ * src/Options.h (multipleDefinitionsInDylibs): Declare.
+ (overridingDefinitionInDependentDylib): Ditto.
+ (warnOnMultipleDefinitionsInObjectFiles): Ditto.
+ (multiplyDefined): Remove.
+ (multiplyDefinedUnused): Ditto.
+ (fMultiplyDefined): Ditto.
+ (fWarnOnMultiplyDefined): New.
+ (fMultiplyDefinedDynamic): Ditto.
+ * src/Options.cpp (Options::Options): Initialize above.
+ (overridingDefinitionInDependentDylib): New.
+ (multipleDefinitionsInDylibs): Ditto.
+ (warnOnMultipleDefinitionsInObjectFiles): Ditto.
+ (parse): Update comments. Fix parsing of -y option.
+ Update error message for -dead_strip. Parse above
+ options.
+
+2006-01-02 Nick Kledzik <kledzik@apple.com>
+
+ * Refactor: move Atom::writeContent() to Writer
+
+2005-12-23 Nick Kledzik <kledzik@apple.com>
+
+ * Reworked, simplify, and document test harness
+ * unit-tests/README: Added
+
+2005-12-23 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: fixes for Objective-C
+ * unit-tests/test-cases/relocs-objc: Added
+
+2005-12-22 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: fix check that next reloc is pair
+ * src/MachOReaderRelocatable.hpp: Add code to synthesize essential stabs from dwarf
+
+2005-12-21 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: Fix parsing of literal sections
+ * src/MachOWriterExecutable.hpp: Fix writing of literal sections
+ * unit-tests/test-cases/relocs-literals: Added
+
+2005-12-15 Eric Christopher <echristo@apple.com>
+
+ * src/Options.h (enum Treatment): New.
+ (enum PICTreatment): Delete.
+ (enum VersionMin): New.
+ (prebind): Declare.
+ (macosxVersionMin): Ditto.
+ (multiplyDefined): Ditto.
+ (multiplyDefinedUnused): Ditto.
+ (setVersionMin): Ditto.
+ (setPICTreatment): Delete.
+ (setReadOnlyRelocTreatment): Ditto.
+ (picTreatment): Adjust return type.
+ (parseTreatment): New.
+ (fPrebind): Ditto.
+ (fVersionMin): Ditto.
+ (fPICTreatment): Change type.
+ (fMultiplyDefined): New.
+ (fMultiplyDefinedUnused): Ditto.
+ (fLimitUndefinedSymbols): Ditto.
+
+ * src/Options.cpp: Fix whitespace. Add comments on options.
+ (Options::Options): Add initializers for new variables.
+ (Options::prebind): New.
+ (Options::macosxVersionMin): Ditto.
+ (Options::parseTreatment): Ditto.
+ (Options::setVersionMin): Ditto.
+ (Options::setReadOnlyRelocTreatment): Delete.
+ (Options::setPICTreatment): Ditto.
+ (Options::Parse): Update for above. Add comments.
+
+2005-12-15 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: Add comments about dwarf
+
+2005-12-14 Nick Kledzik <kledzik@apple.com>
+
+ * src/ELFFileAbstraction.hpp: Added
+ * src/ELFReaderRelocatable.hpp: Added
+ * Lot of fixes for new architecture
+
+2005-12-13 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: check for S_ATTR_DEBUG and ignore those sections
+ * unit-tests/test-cases/dwarf-ignore: added
+
+2005-12-12 Nick Kledzik <kledzik@apple.com>
+
+ * Added test harness and three initial tests:
+ relocs-asm, relocs-c, and hello-world
+
+2005-12-12 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOReaderRelocatable.hpp: Massive refactoring:
+ Now there are three Atom classes, Chopping into Atoms
+ is done on label boundaries or by knowledge of special
+ sections, Share lots of ppc/ppc64 code.
+ Stabs process code is temporarily disabled.
+
+2005-12-12 Nick Kledzik <kledzik@apple.com>
+
+ * src/ObjectDump.cpp: Add command line options: -no_content, -stabs, -no_sort
+
+2005-12-11 Eric Christopher <echristo@apple.com>
+
+ * src/Options.cpp: Reformat.
+ * src/Options.h: Ditto.
+
+2005-12-07 Eric Christopher <echristo@apple.com>
+
+ * src/MachOReaderRelocatable.hpp (Atom::getAlignment):
+ When calculating alignment of an Atom, take into account
+ the alignment from which we pulled the Atom.
+
+2005-12-06 Nick Kledzik <kledzik@apple.com>
+
+ * src/Options.cpp src/Options.h: Add design comments
+
+2005-12-05 Eric Christopher <echristo@apple.com>
+
+ * src/ld.cpp (Linker::createWriter): Uncomment ppc64 and
+ i386 linkers.
+
+2005-12-05 Eric Christopher <echristo@apple.com>
+
+ * ChangeLog: New file.
+
+2005-12-02 Nick Kledzik <kledzik@apple.com>
+
+ * src/ObjectFile.h: Add design comments
+
+2005-11-28 Nick Kledzik <kledzik@apple.com>
+
+ * Refactor Atom to use getDefinitionKind()
+
+2005-11-21 Nick Kledzik <kledzik@apple.com>
+
+ * src/MachOWriterExecutable.hpp: don't generate section for commons in -r mode
+
+2005-11-18 Nick Kledzik <kledzik@apple.com>
+
+ * x86 tweaks
+
+2005-11-18 Nick Kledzik <kledzik@apple.com>
+
+ * src/ObjectDump.cpp: make work with command line arguments
+
+2005-11-18 Nick Kledzik <kledzik@apple.com>
+
+ * Massive rework to remove preprocessor conditionals and use templates
+
+2005-11-14 Nick Kledzik <kledzik@apple.com>
+
+ * Created new Subversion repository for ld64 from cvs tag ld64-27.2
+++ /dev/null
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 39;
- objects = {
- F9023C2C06D5A227001BBF46 = {
- children = (
- F971EED706D5AD240041D381,
- F9023C3F06D5A254001BBF46,
- F9C0D48A06DD1E1B001C7193,
- F9C0D48B06DD1E1B001C7193,
- F9023C3E06D5A254001BBF46,
- F9023C4006D5A254001BBF46,
- F9023C4106D5A254001BBF46,
- F97288E607D277570031794D,
- F972890007D27FD00031794D,
- F9023C4206D5A254001BBF46,
- F9023C4806D5A254001BBF46,
- F97F5028070D0BB200B9FCD7,
- F9023C3A06D5A23E001BBF46,
- );
- isa = PBXGroup;
- refType = 4;
- sourceTree = "<group>";
- };
- F9023C2E06D5A227001BBF46 = {
- buildSettings = {
- COPY_PHASE_STRIP = NO;
- GCC_OPTIMIZATION_LEVEL = 0;
- };
- isa = PBXBuildStyle;
- name = Development;
- };
- F9023C2F06D5A227001BBF46 = {
- buildSettings = {
- COPY_PHASE_STRIP = YES;
- };
- isa = PBXBuildStyle;
- name = Deployment;
- };
- F9023C3006D5A227001BBF46 = {
- buildSettings = {
- };
- buildStyles = (
- F9023C2E06D5A227001BBF46,
- F9023C2F06D5A227001BBF46,
- );
- hasScannedForEncodings = 0;
- isa = PBXProject;
- mainGroup = F9023C2C06D5A227001BBF46;
- productRefGroup = F9023C3A06D5A23E001BBF46;
- projectDirPath = "";
- targets = (
- F9023C3806D5A23E001BBF46,
- F971EED206D5ACF60041D381,
- );
- };
- F9023C3606D5A23E001BBF46 = {
- buildActionMask = 2147483647;
- files = (
- F9023C4E06D5A272001BBF46,
- F9C0D4BD06DD28D2001C7193,
- F9023C4F06D5A272001BBF46,
- F9023C5006D5A272001BBF46,
- F97288E707D277570031794D,
- );
- isa = PBXSourcesBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- F9023C3706D5A23E001BBF46 = {
- buildActionMask = 2147483647;
- files = (
- );
- isa = PBXFrameworksBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- F9023C3806D5A23E001BBF46 = {
- buildPhases = (
- F9023C3606D5A23E001BBF46,
- F9023C3706D5A23E001BBF46,
- F97F5025070D0B6300B9FCD7,
- );
- buildRules = (
- F9E8D4BE07FCAF2A00FD5801,
- F9E8D4BD07FCAF2000FD5801,
- );
- buildSettings = {
- CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_MODEL_TUNING = G5;
- GCC_OPTIMIZATION_LEVEL = 3;
- INSTALL_PATH = /usr/bin;
- OTHER_CFLAGS = "";
- OTHER_LDFLAGS = "";
- OTHER_REZFLAGS = "";
- PREBINDING = NO;
- PRODUCT_NAME = ld64;
- SECTORDER_FLAGS = "";
- VERSIONING_SYSTEM = "apple-generic";
- WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
- };
- dependencies = (
- );
- isa = PBXNativeTarget;
- name = ld64;
- productName = ld64;
- productReference = F9023C3906D5A23E001BBF46;
- productType = "com.apple.product-type.tool";
- };
- F9023C3906D5A23E001BBF46 = {
- explicitFileType = "compiled.mach-o.executable";
- includeInIndex = 0;
- isa = PBXFileReference;
- path = ld64;
- refType = 3;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- F9023C3A06D5A23E001BBF46 = {
- children = (
- F9023C3906D5A23E001BBF46,
- F971EED306D5ACF60041D381,
- );
- isa = PBXGroup;
- name = Products;
- refType = 4;
- sourceTree = "<group>";
- };
- F9023C3E06D5A254001BBF46 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.c.h;
- name = ExecutableFile.h;
- path = src/ExecutableFile.h;
- refType = 4;
- sourceTree = "<group>";
- };
- F9023C3F06D5A254001BBF46 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.cpp.cpp;
- name = ld.cpp;
- path = src/ld.cpp;
- refType = 4;
- sourceTree = "<group>";
- };
- F9023C4006D5A254001BBF46 = {
- fileEncoding = 30;
- indentWidth = 4;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.c.h;
- name = MachOAbstraction.h;
- path = src/MachOAbstraction.h;
- refType = 4;
- sourceTree = "<group>";
- tabWidth = 4;
- usesTabs = 1;
- };
- F9023C4106D5A254001BBF46 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.c.h;
- name = ObjectFile.h;
- path = src/ObjectFile.h;
- refType = 4;
- sourceTree = "<group>";
- };
- F9023C4206D5A254001BBF46 = {
- children = (
- F9023C4706D5A254001BBF46,
- F9023C4406D5A254001BBF46,
- F95DD3B106EE395A007CAFEB,
- F9023C4506D5A254001BBF46,
- F9023C4606D5A254001BBF46,
- );
- isa = PBXGroup;
- name = Readers;
- path = src/Readers;
- refType = 4;
- sourceTree = "<group>";
- };
- F9023C4406D5A254001BBF46 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.cpp.cpp;
- path = ObjectFileDylibMachO.cpp;
- refType = 4;
- sourceTree = "<group>";
- };
- F9023C4506D5A254001BBF46 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.cpp.cpp;
- path = "ObjectFileMachO-all.cpp";
- refType = 4;
- sourceTree = "<group>";
- };
- F9023C4606D5A254001BBF46 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.c.h;
- path = "ObjectFileMachO-all.h";
- refType = 4;
- sourceTree = "<group>";
- };
- F9023C4706D5A254001BBF46 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.cpp.cpp;
- path = ObjectFileMachO.cpp;
- refType = 4;
- sourceTree = "<group>";
- };
- F9023C4806D5A254001BBF46 = {
- children = (
- F9023C4906D5A254001BBF46,
- F9023C4A06D5A254001BBF46,
- F9023C4B06D5A254001BBF46,
- );
- isa = PBXGroup;
- name = Writers;
- path = src/Writers;
- refType = 4;
- sourceTree = "<group>";
- };
- F9023C4906D5A254001BBF46 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.cpp.cpp;
- path = "ExecutableFileMachO-all.cpp";
- refType = 4;
- sourceTree = "<group>";
- };
- F9023C4A06D5A254001BBF46 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.c.h;
- path = "ExecutableFileMachO-all.h";
- refType = 4;
- sourceTree = "<group>";
- };
- F9023C4B06D5A254001BBF46 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.cpp.cpp;
- path = ExecutableFileMachO.cpp;
- refType = 4;
- sourceTree = "<group>";
- };
- F9023C4E06D5A272001BBF46 = {
- fileRef = F9023C3F06D5A254001BBF46;
- isa = PBXBuildFile;
- settings = {
- };
- };
- F9023C4F06D5A272001BBF46 = {
- fileRef = F9023C4506D5A254001BBF46;
- isa = PBXBuildFile;
- settings = {
- };
- };
- F9023C5006D5A272001BBF46 = {
- fileRef = F9023C4906D5A254001BBF46;
- isa = PBXBuildFile;
- settings = {
- };
- };
- F95DD3B106EE395A007CAFEB = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.cpp.cpp;
- path = ObjectFileArchiveMachO.cpp;
- refType = 4;
- sourceTree = "<group>";
- };
- F971EED006D5ACF60041D381 = {
- buildActionMask = 2147483647;
- files = (
- F971EED806D5AD240041D381,
- F971EEDA06D5AD450041D381,
- );
- isa = PBXSourcesBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- F971EED106D5ACF60041D381 = {
- buildActionMask = 2147483647;
- files = (
- );
- isa = PBXFrameworksBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- F971EED206D5ACF60041D381 = {
- buildPhases = (
- F971EED006D5ACF60041D381,
- F971EED106D5ACF60041D381,
- );
- buildRules = (
- );
- buildSettings = {
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_MODEL_TUNING = G5;
- GCC_OPTIMIZATION_LEVEL = 0;
- INSTALL_PATH = "$(HOME)/bin";
- OTHER_CFLAGS = "";
- OTHER_LDFLAGS = "";
- OTHER_REZFLAGS = "";
- PREBINDING = NO;
- PRODUCT_NAME = ObjectDump;
- SECTORDER_FLAGS = "";
- WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
- };
- dependencies = (
- );
- isa = PBXNativeTarget;
- name = ObjectDump;
- productName = ObjectDump;
- productReference = F971EED306D5ACF60041D381;
- productType = "com.apple.product-type.tool";
- };
- F971EED306D5ACF60041D381 = {
- explicitFileType = "compiled.mach-o.executable";
- includeInIndex = 0;
- isa = PBXFileReference;
- path = ObjectDump;
- refType = 3;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- F971EED706D5AD240041D381 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.cpp.cpp;
- name = ObjDump.cpp;
- path = src/ObjDump.cpp;
- refType = 4;
- sourceTree = "<group>";
- };
- F971EED806D5AD240041D381 = {
- fileRef = F971EED706D5AD240041D381;
- isa = PBXBuildFile;
- settings = {
- };
- };
- F971EEDA06D5AD450041D381 = {
- fileRef = F9023C4506D5A254001BBF46;
- isa = PBXBuildFile;
- settings = {
- };
- };
- F97288E607D277570031794D = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.cpp.cpp;
- name = SectCreate.cpp;
- path = src/SectCreate.cpp;
- refType = 4;
- sourceTree = "<group>";
- };
- F97288E707D277570031794D = {
- fileRef = F97288E607D277570031794D;
- isa = PBXBuildFile;
- settings = {
- };
- };
- F972890007D27FD00031794D = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.c.h;
- name = SectCreate.h;
- path = src/SectCreate.h;
- refType = 4;
- sourceTree = "<group>";
- };
- F97F5025070D0B6300B9FCD7 = {
- buildActionMask = 8;
- dstPath = /usr/share/man/man1;
- dstSubfolderSpec = 0;
- files = (
- F97F5029070D0BB200B9FCD7,
- );
- isa = PBXCopyFilesBuildPhase;
- runOnlyForDeploymentPostprocessing = 1;
- };
- F97F5028070D0BB200B9FCD7 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = text.man;
- name = ld64.1;
- path = doc/man/man1/ld64.1;
- refType = 4;
- sourceTree = "<group>";
- };
- F97F5029070D0BB200B9FCD7 = {
- fileRef = F97F5028070D0BB200B9FCD7;
- isa = PBXBuildFile;
- settings = {
- };
- };
- F9C0D48A06DD1E1B001C7193 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.cpp.cpp;
- name = Options.cpp;
- path = src/Options.cpp;
- refType = 4;
- sourceTree = "<group>";
- };
- F9C0D48B06DD1E1B001C7193 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.c.h;
- name = Options.h;
- path = src/Options.h;
- refType = 4;
- sourceTree = "<group>";
- };
- F9C0D4BD06DD28D2001C7193 = {
- fileRef = F9C0D48A06DD1E1B001C7193;
- isa = PBXBuildFile;
- settings = {
- };
- };
- F9E8D4BD07FCAF2000FD5801 = {
- compilerSpec = com.apple.compilers.gcc.4_0;
- fileType = sourcecode.c;
- isEditable = 1;
- isa = PBXBuildRule;
- outputFiles = (
- );
- };
- F9E8D4BE07FCAF2A00FD5801 = {
- compilerSpec = com.apple.compilers.gcc.4_0;
- fileType = sourcecode.cpp;
- isEditable = 1;
- isa = PBXBuildRule;
- outputFiles = (
- );
- };
- };
- rootObject = F9023C3006D5A227001BBF46;
-}
--- /dev/null
+// !$*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 */,
+ );
+ buildSettings = {
+ PRODUCT_NAME = "unit-tests";
+ };
+ dependencies = (
+ F96D536A094A275D008E9EE8 /* PBXTargetDependency */,
+ F96D536C094A275F008E9EE8 /* PBXTargetDependency */,
+ F9EA73970974999B008B4F1D /* PBXTargetDependency */,
+ );
+ name = "unit-tests";
+ productName = "unit-tests";
+ };
+/* 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 */; };
+ F97288E707D277570031794D /* SectCreate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F97288E607D277570031794D /* SectCreate.cpp */; };
+ F97F5029070D0BB200B9FCD7 /* ld64.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = F97F5028070D0BB200B9FCD7 /* ld64.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 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXBuildRule section */
+ F9E8D4BD07FCAF2000FD5801 /* PBXBuildRule */ = {
+ isa = PBXBuildRule;
+ compilerSpec = com.apple.compilers.gcc.4_0;
+ fileType = sourcecode.c;
+ isEditable = 1;
+ outputFiles = (
+ );
+ };
+ F9E8D4BE07FCAF2A00FD5801 /* PBXBuildRule */ = {
+ isa = PBXBuildRule;
+ compilerSpec = com.apple.compilers.gcc.4_0;
+ fileType = sourcecode.cpp;
+ isEditable = 1;
+ outputFiles = (
+ );
+ };
+/* End PBXBuildRule section */
+
+/* Begin PBXBuildStyle section */
+ F933D92F09291D070083EAC8 /* Development */ = {
+ isa = PBXBuildStyle;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ };
+ name = Development;
+ };
+ F933D93009291D070083EAC8 /* Deployment */ = {
+ isa = PBXBuildStyle;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ };
+ name = Deployment;
+ };
+/* End PBXBuildStyle section */
+
+/* Begin PBXContainerItemProxy section */
+ 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;
+ };
+ 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 /* ld64.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ C02A29DE0953B26E001FB8C1 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = ChangeLog; sourceTree = "<group>"; };
+ F9023C3906D5A23E001BBF46 /* ld64 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ld64; sourceTree = BUILT_PRODUCTS_DIR; };
+ F9023C3E06D5A254001BBF46 /* ExecutableFile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ExecutableFile.h; path = src/ExecutableFile.h; sourceTree = "<group>"; };
+ F9023C3F06D5A254001BBF46 /* ld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ld.cpp; path = src/ld.cpp; sourceTree = "<group>"; };
+ F9023C4106D5A254001BBF46 /* ObjectFile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ObjectFile.h; path = src/ObjectFile.h; sourceTree = "<group>"; };
+ F933D9460929277C0083EAC8 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FileAbstraction.hpp; path = src/FileAbstraction.hpp; sourceTree = "<group>"; };
+ F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOFileAbstraction.hpp; path = src/MachOFileAbstraction.hpp; sourceTree = "<group>"; };
+ F933DC37092A82480083EAC8 /* Architectures.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Architectures.hpp; path = src/Architectures.hpp; sourceTree = "<group>"; };
+ F933E3CB092E84250083EAC8 /* MachOReaderArchive.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOReaderArchive.hpp; path = src/MachOReaderArchive.hpp; sourceTree = "<group>"; };
+ F933E3CC092E84250083EAC8 /* MachOReaderDylib.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOReaderDylib.hpp; path = src/MachOReaderDylib.hpp; sourceTree = "<group>"; };
+ F933E3CD092E84250083EAC8 /* MachOReaderRelocatable.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOReaderRelocatable.hpp; path = src/MachOReaderRelocatable.hpp; sourceTree = "<group>"; };
+ F933E3CE092E84250083EAC8 /* MachOWriterExecutable.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOWriterExecutable.hpp; path = src/MachOWriterExecutable.hpp; sourceTree = "<group>"; };
+ 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 = "<group>"; };
+ F97288E607D277570031794D /* SectCreate.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SectCreate.cpp; path = src/SectCreate.cpp; sourceTree = "<group>"; };
+ F972890007D27FD00031794D /* SectCreate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SectCreate.h; path = src/SectCreate.h; sourceTree = "<group>"; };
+ F97F5028070D0BB200B9FCD7 /* ld64.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = ld64.1; path = doc/man/man1/ld64.1; sourceTree = "<group>"; };
+ F9C0D48A06DD1E1B001C7193 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Options.cpp; path = src/Options.cpp; sourceTree = "<group>"; };
+ F9C0D48B06DD1E1B001C7193 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Options.h; path = src/Options.h; sourceTree = "<group>"; };
+ 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 = "<group>"; };
+ F9EA7582097882F3008B4F1D /* debugline.c */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.c; name = debugline.c; path = src/debugline.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9EA7583097882F3008B4F1D /* debugline.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = debugline.h; path = src/debugline.h; sourceTree = "<group>"; };
+/* 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;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ F9023C2C06D5A227001BBF46 = {
+ isa = PBXGroup;
+ children = (
+ C02A29DE0953B26E001FB8C1 /* ChangeLog */,
+ F933DC37092A82480083EAC8 /* Architectures.hpp */,
+ F933D9460929277C0083EAC8 /* FileAbstraction.hpp */,
+ F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */,
+ F933E3CD092E84250083EAC8 /* MachOReaderRelocatable.hpp */,
+ F933E3CB092E84250083EAC8 /* MachOReaderArchive.hpp */,
+ F933E3CC092E84250083EAC8 /* MachOReaderDylib.hpp */,
+ F933E3CE092E84250083EAC8 /* MachOWriterExecutable.hpp */,
+ F9023C3E06D5A254001BBF46 /* ExecutableFile.h */,
+ F9023C4106D5A254001BBF46 /* ObjectFile.h */,
+ F9023C3F06D5A254001BBF46 /* ld.cpp */,
+ F9C0D48A06DD1E1B001C7193 /* Options.cpp */,
+ F9C0D48B06DD1E1B001C7193 /* Options.h */,
+ F97288E607D277570031794D /* SectCreate.cpp */,
+ F972890007D27FD00031794D /* SectCreate.h */,
+ F9EA7582097882F3008B4F1D /* debugline.c */,
+ F9EA7583097882F3008B4F1D /* debugline.h */,
+ F9EA72D4097454FF008B4F1D /* machochecker.cpp */,
+ F971EED706D5AD240041D381 /* ObjectDump.cpp */,
+ F97F5028070D0BB200B9FCD7 /* ld64.1 */,
+ F9023C3A06D5A23E001BBF46 /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ F9023C3A06D5A23E001BBF46 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ F9023C3906D5A23E001BBF46 /* ld64 */,
+ F971EED306D5ACF60041D381 /* ObjectDump */,
+ F9EA72CB097454A6008B4F1D /* machocheck */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ F9023C3806D5A23E001BBF46 /* ld */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F933D91B09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ld" */;
+ buildPhases = (
+ F9023C3606D5A23E001BBF46 /* Sources */,
+ F9023C3706D5A23E001BBF46 /* Frameworks */,
+ F97F5025070D0B6300B9FCD7 /* CopyFiles */,
+ );
+ buildRules = (
+ F9E8D4BE07FCAF2A00FD5801 /* PBXBuildRule */,
+ F9E8D4BD07FCAF2000FD5801 /* PBXBuildRule */,
+ );
+ buildSettings = {
+ PRODUCT_NAME = ld64;
+ };
+ dependencies = (
+ );
+ name = ld;
+ productName = ld64;
+ productReference = F9023C3906D5A23E001BBF46 /* ld64 */;
+ productType = "com.apple.product-type.tool";
+ };
+ F971EED206D5ACF60041D381 /* ObjectDump */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F933D91F09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ObjectDump" */;
+ buildPhases = (
+ F971EED006D5ACF60041D381 /* Sources */,
+ F971EED106D5ACF60041D381 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ buildSettings = {
+ PRODUCT_NAME = ObjectDump;
+ };
+ 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 = (
+ );
+ buildSettings = {
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = "$(HOME)/bin";
+ PREBINDING = NO;
+ PRODUCT_NAME = machocheck;
+ };
+ dependencies = (
+ );
+ name = machocheck;
+ productName = machocheck;
+ productReference = F9EA72CB097454A6008B4F1D /* machocheck */;
+ 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" */;
+ buildSettings = {
+ };
+ buildStyles = (
+ F933D92F09291D070083EAC8 /* Development */,
+ F933D93009291D070083EAC8 /* Deployment */,
+ );
+ hasScannedForEncodings = 0;
+ mainGroup = F9023C2C06D5A227001BBF46;
+ productRefGroup = F9023C3A06D5A23E001BBF46 /* Products */;
+ projectDirPath = "";
+ targets = (
+ F9023C3806D5A23E001BBF46 /* ld */,
+ F971EED206D5ACF60041D381 /* ObjectDump */,
+ F9EA72CA097454A6008B4F1D /* machocheck */,
+ F96D5368094A2754008E9EE8 /* unit-tests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 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# make an symlink to ld64 called ld, so that gcc will use this linker for all linking\nrm -rf $BUILT_PRODUCTS_DIR/ld\nln -s $BUILT_PRODUCTS_DIR/ld64 $BUILT_PRODUCTS_DIR/ld\n\n# run full test suite\n$SRCROOT/unit-tests/run-all-unit-tests\n\nexit 0";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ F9023C3606D5A23E001BBF46 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F9023C4E06D5A272001BBF46 /* ld.cpp in Sources */,
+ F9C0D4BD06DD28D2001C7193 /* Options.cpp in Sources */,
+ F97288E707D277570031794D /* SectCreate.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;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ F96D536A094A275D008E9EE8 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F9023C3806D5A23E001BBF46 /* ld */;
+ targetProxy = F96D5369094A275D008E9EE8 /* PBXContainerItemProxy */;
+ };
+ F96D536C094A275F008E9EE8 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F971EED206D5ACF60041D381 /* ObjectDump */;
+ targetProxy = F96D536B094A275F008E9EE8 /* 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)";
+ GCC_DYNAMIC_NO_PIC = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ 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;
+ INSTALL_PATH = /usr/bin;
+ OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
+ OTHER_LDFLAGS = "";
+ PREBINDING = NO;
+ PRODUCT_NAME = ld64;
+ 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)";
+ GCC_DYNAMIC_NO_PIC = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 3;
+ GCC_PREPROCESSOR_DEFINITIONS = "$(GCC_PREPROCESSOR_DEFINITIONS_$(RC_RELEASE))";
+ GCC_PREPROCESSOR_DEFINITIONS_Curry = __OPEN_SOURCE__;
+ GCC_PREPROCESSOR_DEFINITIONS_CurryWeed = __OPEN_SOURCE__;
+ GCC_PREPROCESSOR_DEFINITIONS_Leopard = __OPEN_SOURCE__;
+ 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;
+ INSTALL_PATH = /usr/bin;
+ OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
+ OTHER_LDFLAGS = "";
+ PREBINDING = NO;
+ PRODUCT_NAME = ld64;
+ SECTORDER_FLAGS = "";
+ VERSIONING_SYSTEM = "apple-generic";
+ WARNING_CFLAGS = "-Wall";
+ };
+ name = Release;
+ };
+ F933D92009291AC90083EAC8 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ INSTALL_PATH = "$(HOME)/bin";
+ OTHER_LDFLAGS = "";
+ 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;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ INSTALL_PATH = "$(HOME)/bin";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PREBINDING = NO;
+ PRODUCT_NAME = ObjectDump;
+ SECTORDER_FLAGS = "";
+ 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;
+ };
+ 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;
+ };
+ F9EA72D0097454D5008B4F1D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = "$(HOME)/bin";
+ PREBINDING = NO;
+ PRODUCT_NAME = machocheck;
+ };
+ name = Debug;
+ };
+ F9EA72D1097454D5008B4F1D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = "$(HOME)/bin";
+ PREBINDING = NO;
+ PRODUCT_NAME = machocheck;
+ };
+ 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;
+ };
+ F9EA72CF097454D5008B4F1D /* Build configuration list for PBXNativeTarget "machocheck" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F9EA72D0097454D5008B4F1D /* Debug */,
+ F9EA72D1097454D5008B4F1D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = F9023C3006D5A227001BBF46 /* Project object */;
+}
--- /dev/null
+/* -*- 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 __ARCHITECTURES__
+#define __ARCHITECTURES__
+
+#include "FileAbstraction.hpp"
+
+
+//
+// Architectures
+//
+struct ppc
+{
+ typedef Pointer32<BigEndian> P;
+
+ enum ReferenceKinds { kNoFixUp, kFollowOn, kPointer, kPointerWeakImport, kPointerDiff32, kPointerDiff64,
+ kBranch24, kBranch24WeakImport, kBranch14,
+ kPICBaseLow16, kPICBaseLow14, kPICBaseHigh16,
+ kAbsLow16, kAbsLow14, kAbsHigh16, kAbsHigh16AddLow };
+};
+
+struct ppc64
+{
+ typedef Pointer64<BigEndian> P;
+
+ enum ReferenceKinds { kNoFixUp, kFollowOn, kPointer, kPointerWeakImport, kPointerDiff32, kPointerDiff64,
+ kBranch24, kBranch24WeakImport, kBranch14,
+ kPICBaseLow16, kPICBaseLow14, kPICBaseHigh16,
+ kAbsLow16, kAbsLow14, kAbsHigh16, kAbsHigh16AddLow };
+};
+
+struct x86
+{
+ typedef Pointer32<LittleEndian> P;
+
+ enum ReferenceKinds { kNoFixUp, kFollowOn, kPointer, kPointerWeakImport, kPointerDiff,
+ kPCRel32, kPCRel32WeakImport };
+};
+
+
+
+
+
+
+
+#endif // __ARCHITECTURES__
+
+
-/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+/* -*- 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,
* FITNESS FOR A PARTICULAR PURPOSE, 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__
namespace ExecutableFile {
- struct DyLibUsed
+ struct DyLibUsed
{
ObjectFile::Reader* reader;
DynamicLibraryOptions options;
- bool indirect; // library found indirect. Do not make load command
+ bool indirect; // library found indirect. Do not make load command
ObjectFile::Reader* directReader; // direct library which re-exports this library
};
-
+
class Writer : public ObjectFile::Reader
{
- public:
- virtual ~Writer() {};
-
+ public:
+ virtual ~Writer() {};
+
virtual const char* getPath() = 0;
virtual std::vector<class ObjectFile::Atom*>& getAtoms() = 0;
virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) = 0;
- virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo() = 0;
virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name) = 0;
- virtual void write(std::vector<class ObjectFile::Atom*>& atoms, class ObjectFile::Atom* entryPointAtom) = 0;
-
-
+ virtual uint64_t write(std::vector<class ObjectFile::Atom*>& atoms,
+ std::vector<class ObjectFile::Reader::Stab>& stabs,
+ class ObjectFile::Atom* entryPointAtom,
+ class ObjectFile::Atom* dyldHelperAtom,
+ bool createUUID) = 0;
protected:
- Writer(std::vector<DyLibUsed>&) {};
+ Writer(std::vector<DyLibUsed>&) {};
};
};
-
-
-
#endif // __EXECUTABLEFILE__
-
-
-
--- /dev/null
+/* -*- 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 <stdint.h>
+#include <string.h>
+#include <libkern/OSByteOrder.h>
+
+#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<LittleEndian>
+//
+//
+// 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<<bitCount)-1)); }
+ static void setBitsRaw(uint32_t& into, uint32_t value,
+ uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
+ const uint32_t mask = ((1<<bitCount)-1);
+ temp &= ~(mask << (32-firstBit-bitCount));
+ temp |= ((value & mask) << (32-firstBit-bitCount));
+ into = temp; }
+ enum { little_endian = 0 };
+};
+
+
+class LittleEndian
+{
+public:
+ static uint16_t get16(const uint16_t& from) INLINE { return OSReadLittleInt16(&from, 0); }
+ static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteLittleInt16(&into, 0, value); }
+
+ static uint32_t get32(const uint32_t& from) INLINE { return OSReadLittleInt32(&from, 0); }
+ static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteLittleInt32(&into, 0, value); }
+
+ static uint64_t get64(const uint64_t& from) INLINE { return OSReadLittleInt64(&from, 0); }
+ static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteLittleInt64(&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 >> firstBit) & ((1<<bitCount)-1)); }
+ static void setBitsRaw(uint32_t& into, uint32_t value,
+ uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
+ const uint32_t mask = ((1<<bitCount)-1);
+ temp &= ~(mask << firstBit);
+ temp |= ((value & mask) << firstBit);
+ into = temp; }
+ enum { little_endian = 1 };
+};
+
+
+template <typename _E>
+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 <typename _E>
+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__
+
+
+++ /dev/null
-/* -*- 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 <stdint.h>
-#include <string.h>
-#include <mach-o/nlist.h>
-#include <mach-o/loader.h>
-#include <libkern/OSByteOrder.h>
-
-
-#undef ENDIAN_READ16
-#undef ENDIAN_WRITE16
-#undef ENDIAN_READ32
-#undef ENDIAN_WRITE32
-#undef ENDIAN_SWAP64
-#undef ENDIAN_SWAP_POINTER
-
-#if defined(MACHO_32_SAME_ENDIAN) || defined(MACHO_64_SAME_ENDIAN)
- #define ENDIAN_READ16(x) (x)
- #define ENDIAN_WRITE16(into, value) into = (value);
-
- #define ENDIAN_READ32(x) (x)
- #define ENDIAN_WRITE32(into, value) into = (value);
-
- #define ENDIAN_SWAP64(x) (x)
-
-#elif defined(MACHO_32_OPPOSITE_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
- #define ENDIAN_READ16(x) OSReadSwapInt16((uint16_t*)&(x), 0)
- #define ENDIAN_WRITE16(into, value) OSWriteSwapInt16(&(into), 0, value);
-
- #define ENDIAN_READ32(x) OSReadSwapInt32((uint32_t*)&(x), 0)
- #define ENDIAN_WRITE32(into, value) OSWriteSwapInt32(&(into), 0, value);
-
- #define ENDIAN_SWAP64(x) OSSwapInt64(x)
-
-#else
- #error file format undefined
-#endif
-
-
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
- typedef uint64_t macho_uintptr_t;
- typedef int64_t macho_intptr_t;
-#else
- typedef uint32_t macho_uintptr_t;
- typedef int32_t macho_intptr_t;
-#endif
-
-#if defined(MACHO_32_SAME_ENDIAN)
- #define ENDIAN_SWAP_POINTER(x) (x)
-#elif defined(MACHO_64_SAME_ENDIAN)
- #define ENDIAN_SWAP_POINTER(x) (x)
-#elif defined(MACHO_32_OPPOSITE_ENDIAN)
- #define ENDIAN_SWAP_POINTER(x) OSSwapInt32(x)
-#elif defined(MACHO_64_OPPOSITE_ENDIAN)
- #define ENDIAN_SWAP_POINTER(x) OSSwapInt64(x)
-#else
- #error file format undefined
-#endif
-
-
-#undef mach_header
-#undef mach_header_64
-class macho_header {
-public:
- uint32_t magic() const;
- void set_magic(uint32_t);
-
- cpu_type_t cputype() const;
- void set_cputype(cpu_type_t);
-
- cpu_subtype_t cpusubtype() const;
- void set_cpusubtype(cpu_subtype_t);
-
- uint32_t filetype() const;
- void set_filetype(uint32_t);
-
- uint32_t ncmds() const;
- void set_ncmds(uint32_t);
-
- uint32_t sizeofcmds() const;
- void set_sizeofcmds(uint32_t);
-
- uint32_t flags() const;
- void set_flags(uint32_t);
-
- void set_reserved();
-
-#if defined(MACHO_64_SAME_ENDIAN)
- enum { size = sizeof(mach_header_64) };
- enum { magic_value = MH_MAGIC_64 };
-#elif defined(MACHO_64_OPPOSITE_ENDIAN)
- enum { size = sizeof(mach_header_64) };
- enum { magic_value = MH_MAGIC_64 };
-#elif defined(MACHO_32_SAME_ENDIAN)
- enum { size = sizeof(mach_header) };
- enum { magic_value = MH_MAGIC };
-#elif defined(MACHO_32_OPPOSITE_ENDIAN)
- enum { size = sizeof(mach_header) };
- enum { magic_value = MH_MAGIC };
-#endif
-
-private:
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
- struct mach_header_64 content;
-#else
- struct mach_header content;
-#endif
-};
-#define mach_header __my_bad
-#define mach_header_64 __my_bad
-
-inline __attribute__((always_inline))
-uint32_t macho_header::magic() const {
- return ENDIAN_READ32(content.magic);
-}
-
-inline __attribute__((always_inline))
-void macho_header::set_magic(uint32_t _value) {
- ENDIAN_WRITE32(content.magic, _value);
-}
-
-inline __attribute__((always_inline))
-cpu_type_t macho_header::cputype() const {
- return ENDIAN_READ32(content.cputype);
-}
-
-inline __attribute__((always_inline))
-void macho_header::set_cputype(cpu_type_t _value) {
- ENDIAN_WRITE32(content.cputype, _value);
-}
-
-inline __attribute__((always_inline))
-cpu_subtype_t macho_header::cpusubtype() const {
- return ENDIAN_READ32(content.cpusubtype);
-}
-
-inline __attribute__((always_inline))
-void macho_header::set_cpusubtype(cpu_subtype_t _value) {
- ENDIAN_WRITE32(content.cpusubtype, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_header::filetype() const {
- return ENDIAN_READ32(content.filetype);
-}
-
-inline __attribute__((always_inline))
-void macho_header::set_filetype(uint32_t _value) {
- ENDIAN_WRITE32(content.filetype, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_header::ncmds() const {
- return ENDIAN_READ32(content.ncmds);
-}
-
-inline __attribute__((always_inline))
-void macho_header::set_ncmds(uint32_t _value) {
- ENDIAN_WRITE32(content.ncmds, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_header::sizeofcmds() const {
- return ENDIAN_READ32(content.sizeofcmds);
-}
-
-inline __attribute__((always_inline))
-void macho_header::set_sizeofcmds(uint32_t _value) {
- ENDIAN_WRITE32(content.sizeofcmds, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_header::flags() const {
- return ENDIAN_READ32(content.flags);
-}
-
-inline __attribute__((always_inline))
-void macho_header::set_flags(uint32_t _value) {
- ENDIAN_WRITE32(content.flags, _value);
-}
-
-inline __attribute__((always_inline))
-void macho_header::set_reserved() {
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
- content.reserved = 0;
-#endif
-}
-
-
-#undef load_command
-class macho_load_command {
-public:
- uint32_t cmd() const;
- void set_cmd(uint32_t);
-
- uint32_t cmdsize() const;
- void set_cmdsize(uint32_t);
-
-private:
- struct load_command content;
-};
-
-inline __attribute__((always_inline))
-uint32_t macho_load_command::cmd() const {
- return ENDIAN_READ32(content.cmd);
-}
-
-inline __attribute__((always_inline))
-void macho_load_command::set_cmd(uint32_t _value) {
- ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_load_command::cmdsize() const {
- return ENDIAN_READ32(content.cmdsize);
-}
-
-inline __attribute__((always_inline))
-void macho_load_command::set_cmdsize(uint32_t _value) {
- ENDIAN_WRITE32(content.cmdsize, _value);
-}
-#define load_command __my_bad
-
-
-#undef segment_command
-#undef segment_command_64
-class macho_segment_command {
-public:
- uint32_t cmd() const;
- void set_cmd(uint32_t);
-
- uint32_t cmdsize() const;
- void set_cmdsize(uint32_t);
-
- const char* segname() const;
- void set_segname(const char*);
-
- uint64_t vmaddr() const;
- void set_vmaddr(uint64_t);
-
- uint64_t vmsize() const;
- void set_vmsize(uint64_t);
-
- uint64_t fileoff() const;
- void set_fileoff(uint64_t);
-
- uint64_t filesize() const;
- void set_filesize(uint64_t);
-
- vm_prot_t maxprot() const;
- void set_maxprot(vm_prot_t);
-
- vm_prot_t initprot() const;
- void set_initprot(vm_prot_t);
-
- uint32_t nsects() const;
- void set_nsects(uint32_t);
-
- uint32_t flags() const;
- void set_flags(uint32_t);
-
- enum { size =
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
- sizeof(segment_command_64) };
-#else
- sizeof(segment_command) };
-#endif
-
- enum { command =
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
- LC_SEGMENT_64
-#else
- LC_SEGMENT
-#endif
- };
-
-private:
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
- struct segment_command_64 content;
-#else
- struct segment_command content;
-#endif
-};
-#define segment_command __my_bad
-#define segment_command_64 __my_bad
-
-inline __attribute__((always_inline))
-uint32_t macho_segment_command::cmd() const {
- return ENDIAN_READ32(content.cmd);
-}
-
-inline __attribute__((always_inline))
-void macho_segment_command::set_cmd(uint32_t _value) {
- ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_segment_command::cmdsize() const {
- return ENDIAN_READ32(content.cmdsize);
-}
-
-inline __attribute__((always_inline))
-void macho_segment_command::set_cmdsize(uint32_t _value) {
- ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline __attribute__((always_inline))
-const char* macho_segment_command::segname() const {
- return content.segname;
-}
-
-inline __attribute__((always_inline))
-void macho_segment_command::set_segname(const char* _value) {
- strncpy(content.segname, _value, 16);
-}
-
-inline __attribute__((always_inline))
-uint64_t macho_segment_command::vmaddr() const {
-#if defined(ARCH_PPC64)
- return ENDIAN_SWAP64(content.vmaddr);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- return ENDIAN_READ32(content.vmaddr);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-void macho_segment_command::set_vmaddr(uint64_t _value) {
-#if defined(ARCH_PPC64)
- content.vmaddr = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- ENDIAN_WRITE32(content.vmaddr, _value);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-uint64_t macho_segment_command::vmsize() const {
-#if defined(ARCH_PPC64)
- return ENDIAN_SWAP64(content.vmsize);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- return ENDIAN_READ32(content.vmsize);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-void macho_segment_command::set_vmsize(uint64_t _value) {
-#if defined(ARCH_PPC64)
- content.vmsize = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- ENDIAN_WRITE32(content.vmsize, _value);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-uint64_t macho_segment_command::fileoff() const {
-#if defined(ARCH_PPC64)
- return ENDIAN_SWAP64(content.fileoff);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- return ENDIAN_READ32(content.fileoff);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-void macho_segment_command::set_fileoff(uint64_t _value) {
-#if defined(ARCH_PPC64)
- content.fileoff = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- ENDIAN_WRITE32(content.fileoff, _value);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-uint64_t macho_segment_command::filesize() const {
-#if defined(ARCH_PPC64)
- return ENDIAN_SWAP64(content.filesize);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- return ENDIAN_READ32(content.filesize);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-void macho_segment_command::set_filesize(uint64_t _value) {
-#if defined(ARCH_PPC64)
- content.filesize = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- ENDIAN_WRITE32(content.filesize, _value);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-vm_prot_t macho_segment_command::maxprot() const {
- return ENDIAN_READ32(content.maxprot);
-}
-
-inline __attribute__((always_inline))
-void macho_segment_command::set_maxprot(vm_prot_t _value) {
- ENDIAN_WRITE32(content.maxprot, _value);
-}
-
-inline __attribute__((always_inline))
-vm_prot_t macho_segment_command::initprot() const {
- return ENDIAN_READ32(content.initprot);
-}
-
-inline __attribute__((always_inline))
-void macho_segment_command::set_initprot(vm_prot_t _value) {
- ENDIAN_WRITE32(content.initprot, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_segment_command::nsects() const {
- return ENDIAN_READ32(content.nsects);
-}
-
-inline __attribute__((always_inline))
-void macho_segment_command::set_nsects(uint32_t _value) {
- ENDIAN_WRITE32(content.nsects, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_segment_command::flags() const {
- return ENDIAN_READ32(content.flags);
-}
-
-inline __attribute__((always_inline))
-void macho_segment_command::set_flags(uint32_t _value) {
- ENDIAN_WRITE32(content.flags, _value);
-}
-
-#undef section
-#undef section_64
-class macho_section {
-public:
- const char* sectname() const;
- void set_sectname(const char*);
-
- const char* segname() const;
- void set_segname(const char*);
-
- uint64_t addr() const;
- void set_addr(uint64_t);
-
- uint64_t size() const;
- void set_size(uint64_t);
-
- uint32_t offset() const;
- void set_offset(uint32_t);
-
- uint32_t align() const;
- void set_align(uint32_t);
-
- uint32_t reloff() const;
- void set_reloff(uint32_t);
-
- uint32_t nreloc() const;
- void set_nreloc(uint32_t);
-
- uint32_t flags() const;
- void set_flags(uint32_t);
-
- uint32_t reserved1() const;
- void set_reserved1(uint32_t);
-
- uint32_t reserved2() const;
- void set_reserved2(uint32_t);
-
- enum { content_size =
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
- sizeof(section_64) };
-#else
- sizeof(section) };
-#endif
-
-private:
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
- struct section_64 content;
-#else
- struct section content;
-#endif
-};
-#define section __my_bad
-#define section_64 __my_bad
-
-inline __attribute__((always_inline))
-const char* macho_section::sectname() const {
- return content.sectname;
-}
-
-inline __attribute__((always_inline))
-void macho_section::set_sectname(const char* _value) {
- strncpy(content.sectname, _value, 16);
-}
-
-inline __attribute__((always_inline))
-const char* macho_section::segname() const {
- return content.segname;
-}
-
-inline __attribute__((always_inline))
-void macho_section::set_segname(const char* _value) {
- strncpy(content.segname, _value, 16);
-}
-
-inline __attribute__((always_inline))
-uint64_t macho_section::addr() const {
-#if defined(ARCH_PPC64)
- return ENDIAN_SWAP64(content.addr);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- return ENDIAN_READ32(content.addr);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-void macho_section::set_addr(uint64_t _value) {
-#if defined(ARCH_PPC64)
- content.addr = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- ENDIAN_WRITE32(content.addr, _value);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-uint64_t macho_section::size() const {
-#if defined(ARCH_PPC64)
- return ENDIAN_SWAP64(content.size);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- return ENDIAN_READ32(content.size);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-void macho_section::set_size(uint64_t _value) {
-#if defined(ARCH_PPC64)
- content.size = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- ENDIAN_WRITE32(content.size, _value);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_section::offset() const {
- return ENDIAN_READ32(content.offset);
-}
-
-inline __attribute__((always_inline))
-void macho_section::set_offset(uint32_t _value) {
- ENDIAN_WRITE32(content.offset, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_section::align() const {
- return ENDIAN_READ32(content.align);
-}
-
-inline __attribute__((always_inline))
-void macho_section::set_align(uint32_t _value) {
- ENDIAN_WRITE32(content.align, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_section::reloff() const {
- return ENDIAN_READ32(content.reloff);
-}
-
-inline __attribute__((always_inline))
-void macho_section::set_reloff(uint32_t _value) {
- ENDIAN_WRITE32(content.reloff, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_section::nreloc() const {
- return ENDIAN_READ32(content.nreloc);
-}
-
-inline __attribute__((always_inline))
-void macho_section::set_nreloc(uint32_t _value) {
- ENDIAN_WRITE32(content.nreloc, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_section::flags() const {
- return ENDIAN_READ32(content.flags);
-}
-
-inline __attribute__((always_inline))
-void macho_section::set_flags(uint32_t _value) {
- ENDIAN_WRITE32(content.flags, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_section::reserved1() const {
- return ENDIAN_READ32(content.reserved1);
-}
-
-inline __attribute__((always_inline))
-void macho_section::set_reserved1(uint32_t _value) {
- ENDIAN_WRITE32(content.reserved1, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_section::reserved2() const {
- return ENDIAN_READ32(content.reserved2);
-}
-
-inline __attribute__((always_inline))
-void macho_section::set_reserved2(uint32_t _value) {
- ENDIAN_WRITE32(content.reserved2, _value);
-}
-
-#undef dylib_command
-class macho_dylib_command {
-public:
- uint32_t cmd() const;
- void set_cmd(uint32_t);
-
- uint32_t cmdsize() const;
- void set_cmdsize(uint32_t);
-
- const char* name() const;
- void set_name_offset();
-
- uint32_t timestamp() const;
- void set_timestamp(uint32_t);
-
- uint32_t current_version() const;
- void set_current_version(uint32_t);
-
- uint32_t compatibility_version() const;
- void set_compatibility_version(uint32_t);
-
- enum { name_offset = sizeof(struct dylib_command) };
-
-private:
- struct dylib_command content;
-};
-#define dylib_command __my_bad
-
-inline __attribute__((always_inline))
-uint32_t macho_dylib_command::cmd() const {
- return ENDIAN_READ32(content.cmd);
-}
-
-inline __attribute__((always_inline))
-void macho_dylib_command::set_cmd(uint32_t _value) {
- ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dylib_command::cmdsize() const {
- return ENDIAN_READ32(content.cmdsize);
-}
-
-inline __attribute__((always_inline))
-void macho_dylib_command::set_cmdsize(uint32_t _value) {
- ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline __attribute__((always_inline))
-const char* macho_dylib_command::name() const {
- return (char*)(&content) + ENDIAN_READ32(content.dylib.name.offset);
-}
-
-inline __attribute__((always_inline))
-void macho_dylib_command::set_name_offset() {
- ENDIAN_WRITE32(content.dylib.name.offset, name_offset);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dylib_command::timestamp() const {
- return ENDIAN_READ32(content.dylib.timestamp);
-}
-
-inline __attribute__((always_inline))
-void macho_dylib_command::set_timestamp(uint32_t _value) {
- ENDIAN_WRITE32(content.dylib.timestamp, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dylib_command::current_version() const {
- return ENDIAN_READ32(content.dylib.current_version);
-}
-
-inline __attribute__((always_inline))
-void macho_dylib_command::set_current_version(uint32_t _value) {
- ENDIAN_WRITE32(content.dylib.current_version, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dylib_command::compatibility_version() const {
- return ENDIAN_READ32(content.dylib.compatibility_version);
-}
-
-inline __attribute__((always_inline))
-void macho_dylib_command::set_compatibility_version(uint32_t _value) {
- ENDIAN_WRITE32(content.dylib.compatibility_version, _value);
-}
-
-
-
-#undef dylinker_command
-class macho_dylinker_command {
-public:
- uint32_t cmd() const;
- void set_cmd(uint32_t);
-
- uint32_t cmdsize() const;
- void set_cmdsize(uint32_t);
-
- void set_name_offset();
-
- enum { name_offset = sizeof(struct dylinker_command) };
-
-private:
- struct dylinker_command content;
-};
-#define dylinker_command __my_bad
-
-inline __attribute__((always_inline))
-uint32_t macho_dylinker_command::cmd() const {
- return ENDIAN_READ32(content.cmd);
-}
-
-inline __attribute__((always_inline))
-void macho_dylinker_command::set_cmd(uint32_t _value) {
- ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dylinker_command::cmdsize() const {
- return ENDIAN_READ32(content.cmdsize);
-}
-
-inline __attribute__((always_inline))
-void macho_dylinker_command::set_cmdsize(uint32_t _value) {
- ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline __attribute__((always_inline))
-void macho_dylinker_command::set_name_offset() {
- ENDIAN_WRITE32(content.name.offset, name_offset);
-}
-
-
-
-#undef sub_framework_command
-class macho_sub_framework_command {
-public:
- uint32_t cmd() const;
- void set_cmd(uint32_t);
-
- uint32_t cmdsize() const;
- void set_cmdsize(uint32_t);
-
- const char* name() const;
- void set_name_offset();
-
- enum { name_offset = sizeof(struct sub_framework_command) };
-
-private:
- struct sub_framework_command content;
-};
-#define sub_framework_command __my_bad
-
-inline __attribute__((always_inline))
-uint32_t macho_sub_framework_command::cmd() const {
- return ENDIAN_READ32(content.cmd);
-}
-
-inline __attribute__((always_inline))
-void macho_sub_framework_command::set_cmd(uint32_t _value) {
- ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_sub_framework_command::cmdsize() const {
- return ENDIAN_READ32(content.cmdsize);
-}
-
-inline __attribute__((always_inline))
-void macho_sub_framework_command::set_cmdsize(uint32_t _value) {
- ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline __attribute__((always_inline))
-const char* macho_sub_framework_command::name() const {
- return (char*)(&content) + ENDIAN_READ32(content.umbrella.offset);
-}
-
-inline __attribute__((always_inline))
-void macho_sub_framework_command::set_name_offset() {
- ENDIAN_WRITE32(content.umbrella.offset, name_offset);
-}
-
-#undef sub_client_command
-class macho_sub_client_command {
-public:
- uint32_t cmd() const;
- void set_cmd(uint32_t);
-
- uint32_t cmdsize() const;
- void set_cmdsize(uint32_t);
-
- const char* name() const;
- void set_name_offset();
-
- enum { name_offset = sizeof(struct sub_client_command) };
-private:
- struct sub_client_command content;
-};
-#define sub_client_command __my_bad
-
-inline __attribute__((always_inline))
-uint32_t macho_sub_client_command::cmd() const {
- return ENDIAN_READ32(content.cmd);
-}
-
-inline __attribute__((always_inline))
-void macho_sub_client_command::set_cmd(uint32_t _value) {
- ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_sub_client_command::cmdsize() const {
- return ENDIAN_READ32(content.cmdsize);
-}
-
-inline __attribute__((always_inline))
-void macho_sub_client_command::set_cmdsize(uint32_t _value) {
- ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline __attribute__((always_inline))
-const char* macho_sub_client_command::name() const {
- return (char*)(&content) + ENDIAN_READ32(content.client.offset);
-}
-
-inline __attribute__((always_inline))
-void macho_sub_client_command::set_name_offset() {
- ENDIAN_WRITE32(content.client.offset, name_offset);
-}
-
-
-
-#undef sub_umbrella_command
-class macho_sub_umbrella_command {
-public:
- uint32_t cmd() const;
- void set_cmd(uint32_t);
-
- uint32_t cmdsize() const;
- void set_cmdsize(uint32_t);
-
- const char* name() const;
- void set_name_offset();
-
- enum { name_offset = sizeof(struct sub_umbrella_command) };
-private:
- struct sub_umbrella_command content;
-};
-#define sub_umbrella_command __my_bad
-
-inline __attribute__((always_inline))
-uint32_t macho_sub_umbrella_command::cmd() const {
- return ENDIAN_READ32(content.cmd);
-}
-
-inline __attribute__((always_inline))
-void macho_sub_umbrella_command::set_cmd(uint32_t _value) {
- ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_sub_umbrella_command::cmdsize() const {
- return ENDIAN_READ32(content.cmdsize);
-}
-
-inline __attribute__((always_inline))
-void macho_sub_umbrella_command::set_cmdsize(uint32_t _value) {
- ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline __attribute__((always_inline))
-const char* macho_sub_umbrella_command::name() const {
- return (char*)(&content) + ENDIAN_READ32(content.sub_umbrella.offset);
-}
-
-inline __attribute__((always_inline))
-void macho_sub_umbrella_command::set_name_offset() {
- ENDIAN_WRITE32(content.sub_umbrella.offset, name_offset);
-}
-
-
-
-
-#undef sub_library_command
-class macho_sub_library_command {
-public:
- uint32_t cmd() const;
- void set_cmd(uint32_t);
-
- uint32_t cmdsize() const;
- void set_cmdsize(uint32_t);
-
- const char* name() const;
- void set_name_offset();
-
- enum { name_offset = sizeof(struct sub_library_command) };
-private:
- struct sub_library_command content;
-};
-#define sub_library_command __my_bad
-
-inline __attribute__((always_inline))
-uint32_t macho_sub_library_command::cmd() const {
- return ENDIAN_READ32(content.cmd);
-}
-
-inline __attribute__((always_inline))
-void macho_sub_library_command::set_cmd(uint32_t _value) {
- ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_sub_library_command::cmdsize() const {
- return ENDIAN_READ32(content.cmdsize);
-}
-
-inline __attribute__((always_inline))
-void macho_sub_library_command::set_cmdsize(uint32_t _value) {
- ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline __attribute__((always_inline))
-const char* macho_sub_library_command::name() const {
- return (char*)(&content) + ENDIAN_READ32(content.sub_library.offset);
-}
-
-inline __attribute__((always_inline))
-void macho_sub_library_command::set_name_offset() {
- ENDIAN_WRITE32(content.sub_library.offset, name_offset);
-}
-
-
-
-#undef routines_command
-#undef routines_command_64
-class macho_routines_command {
-public:
- uint32_t cmd() const;
- void set_cmd(uint32_t);
-
- uint32_t cmdsize() const;
- void set_cmdsize(uint32_t);
-
- uint64_t init_address() const;
- void set_init_address(uint64_t);
-
- uint64_t init_module() const;
- void set_init_module(uint64_t);
-
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
- enum { size = sizeof(struct routines_command_64) };
- enum { command = LC_ROUTINES_64 };
-#else
- enum { size = sizeof(struct routines_command) };
- enum { command = LC_ROUTINES };
-#endif
-
-private:
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
- struct routines_command_64 content;
-#else
- struct routines_command content;
-#endif
-};
-#define routines_command __my_bad
-#define routines_command_64 __my_bad
-
-inline __attribute__((always_inline))
-uint32_t macho_routines_command::cmd() const {
- return ENDIAN_READ32(content.cmd);
-}
-
-inline __attribute__((always_inline))
-void macho_routines_command::set_cmd(uint32_t _value) {
- ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_routines_command::cmdsize() const {
- return ENDIAN_READ32(content.cmdsize);
-}
-
-inline __attribute__((always_inline))
-void macho_routines_command::set_cmdsize(uint32_t _value) {
- ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline __attribute__((always_inline))
-uint64_t macho_routines_command::init_address() const {
-#if defined(ARCH_PPC64)
- return ENDIAN_SWAP64(content.init_address);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- return ENDIAN_READ32(content.init_address);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-void macho_routines_command::set_init_address(uint64_t _value) {
-#if defined(ARCH_PPC64)
- content.init_address = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- ENDIAN_WRITE32(content.init_address, _value);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-uint64_t macho_routines_command::init_module() const {
-#if defined(ARCH_PPC64)
- return ENDIAN_SWAP64(content.init_module);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- return ENDIAN_READ32(content.init_module);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-void macho_routines_command::set_init_module(uint64_t _value) {
-#if defined(ARCH_PPC64)
- content.init_module = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- ENDIAN_WRITE32(content.init_module, _value);
-#else
- #error unknown architecture
-#endif
-}
-
-
-
-#undef symtab_command
-class macho_symtab_command {
-public:
- uint32_t cmd() const;
- void set_cmd(uint32_t);
-
- uint32_t cmdsize() const;
- void set_cmdsize(uint32_t);
-
- uint32_t symoff() const;
- void set_symoff(uint32_t);
-
- uint32_t nsyms() const;
- void set_nsyms(uint32_t);
-
- uint32_t stroff() const;
- void set_stroff(uint32_t);
-
- uint32_t strsize() const;
- void set_strsize(uint32_t);
-
- enum { size = sizeof(struct symtab_command ) };
-
-private:
- struct symtab_command content;
-};
-#define symtab_command __my_bad
-
-
-inline __attribute__((always_inline))
-uint32_t macho_symtab_command::cmd() const {
- return ENDIAN_READ32(content.cmd);
-}
-
-inline __attribute__((always_inline))
-void macho_symtab_command::set_cmd(uint32_t _value) {
- ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_symtab_command::cmdsize() const {
- return ENDIAN_READ32(content.cmdsize);
-}
-
-inline __attribute__((always_inline))
-void macho_symtab_command::set_cmdsize(uint32_t _value) {
- ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_symtab_command::symoff() const {
- return ENDIAN_READ32(content.symoff);
-}
-
-inline __attribute__((always_inline))
-void macho_symtab_command::set_symoff(uint32_t _value) {
- ENDIAN_WRITE32(content.symoff, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_symtab_command::nsyms() const {
- return ENDIAN_READ32(content.nsyms);
-}
-
-inline __attribute__((always_inline))
-void macho_symtab_command::set_nsyms(uint32_t _value) {
- ENDIAN_WRITE32(content.nsyms, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_symtab_command::stroff() const {
- return ENDIAN_READ32(content.stroff);
-}
-
-inline __attribute__((always_inline))
-void macho_symtab_command::set_stroff(uint32_t _value) {
- ENDIAN_WRITE32(content.stroff, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_symtab_command::strsize() const {
- return ENDIAN_READ32(content.strsize);
-}
-
-inline __attribute__((always_inline))
-void macho_symtab_command::set_strsize(uint32_t _value) {
- ENDIAN_WRITE32(content.strsize, _value);
-}
-
-
-#undef dysymtab_command
-class macho_dysymtab_command {
-public:
- uint32_t cmd() const;
- void set_cmd(uint32_t);
-
- uint32_t cmdsize() const;
- void set_cmdsize(uint32_t);
-
- uint32_t ilocalsym() const;
- void set_ilocalsym(uint32_t);
-
- uint32_t nlocalsym() const;
- void set_nlocalsym(uint32_t);
-
- uint32_t iextdefsym() const;
- void set_iextdefsym(uint32_t);
-
- uint32_t nextdefsym() const;
- void set_nextdefsym(uint32_t);
-
- uint32_t iundefsym() const;
- void set_iundefsym(uint32_t);
-
- uint32_t nundefsym() const;
- void set_nundefsym(uint32_t);
-
- uint32_t tocoff() const;
- void set_tocoff(uint32_t);
-
- uint32_t ntoc() const;
- void set_ntoc(uint32_t);
-
- uint32_t modtaboff() const;
- void set_modtaboff(uint32_t);
-
- uint32_t nmodtab() const;
- void set_nmodtab(uint32_t);
-
- uint32_t extrefsymoff() const;
- void set_extrefsymoff(uint32_t);
-
- uint32_t nextrefsyms() const;
- void set_nextrefsyms(uint32_t);
-
- uint32_t indirectsymoff() const;
- void set_indirectsymoff(uint32_t);
-
- uint32_t nindirectsyms() const;
- void set_nindirectsyms(uint32_t);
-
- uint32_t extreloff() const;
- void set_extreloff(uint32_t);
-
- uint32_t nextrel() const;
- void set_nextrel(uint32_t);
-
- uint32_t locreloff() const;
- void set_locreloff(uint32_t);
-
- uint32_t nlocrel() const;
- void set_nlocrel(uint32_t);
-
- enum { size = sizeof(struct dysymtab_command ) };
-private:
- struct dysymtab_command content;
-};
-#define dysymtab_command __my_bad
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::cmd() const {
- return ENDIAN_READ32(content.cmd);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_cmd(uint32_t _value) {
- ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::cmdsize() const {
- return ENDIAN_READ32(content.cmdsize);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_cmdsize(uint32_t _value) {
- ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::ilocalsym() const {
- return ENDIAN_READ32(content.ilocalsym);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_ilocalsym(uint32_t _value) {
- ENDIAN_WRITE32(content.ilocalsym, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nlocalsym() const {
- return ENDIAN_READ32(content.nlocalsym);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_nlocalsym(uint32_t _value) {
- ENDIAN_WRITE32(content.nlocalsym, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::iextdefsym() const {
- return ENDIAN_READ32(content.iextdefsym);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_iextdefsym(uint32_t _value) {
- ENDIAN_WRITE32(content.iextdefsym, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nextdefsym() const {
- return ENDIAN_READ32(content.nextdefsym);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_nextdefsym(uint32_t _value) {
- ENDIAN_WRITE32(content.nextdefsym, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::iundefsym() const {
- return ENDIAN_READ32(content.iundefsym);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_iundefsym(uint32_t _value) {
- ENDIAN_WRITE32(content.iundefsym, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nundefsym() const {
- return ENDIAN_READ32(content.nundefsym);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_nundefsym(uint32_t _value) {
- ENDIAN_WRITE32(content.nundefsym, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::tocoff() const {
- return ENDIAN_READ32(content.tocoff);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_tocoff(uint32_t _value) {
- ENDIAN_WRITE32(content.tocoff, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::ntoc() const {
- return ENDIAN_READ32(content.ntoc);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_ntoc(uint32_t _value) {
- ENDIAN_WRITE32(content.ntoc, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::modtaboff() const {
- return ENDIAN_READ32(content.modtaboff);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_modtaboff(uint32_t _value) {
- ENDIAN_WRITE32(content.modtaboff, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nmodtab() const {
- return ENDIAN_READ32(content.nmodtab);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_nmodtab(uint32_t _value) {
- ENDIAN_WRITE32(content.nmodtab, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::extrefsymoff() const {
- return ENDIAN_READ32(content.extrefsymoff);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_extrefsymoff(uint32_t _value) {
- ENDIAN_WRITE32(content.extrefsymoff, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nextrefsyms() const {
- return ENDIAN_READ32(content.nextrefsyms);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_nextrefsyms(uint32_t _value) {
- ENDIAN_WRITE32(content.nextrefsyms, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::indirectsymoff() const {
- return ENDIAN_READ32(content.indirectsymoff);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_indirectsymoff(uint32_t _value) {
- ENDIAN_WRITE32(content.indirectsymoff, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nindirectsyms() const {
- return ENDIAN_READ32(content.nindirectsyms);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_nindirectsyms(uint32_t _value) {
- ENDIAN_WRITE32(content.nindirectsyms, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::extreloff() const {
- return ENDIAN_READ32(content.extreloff);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_extreloff(uint32_t _value) {
- ENDIAN_WRITE32(content.extreloff, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nextrel() const {
- return ENDIAN_READ32(content.nextrel);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_nextrel(uint32_t _value) {
- ENDIAN_WRITE32(content.nextrel, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::locreloff() const {
- return ENDIAN_READ32(content.locreloff);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_locreloff(uint32_t _value) {
- ENDIAN_WRITE32(content.locreloff, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nlocrel() const {
- return ENDIAN_READ32(content.nlocrel);
-}
-
-inline __attribute__((always_inline))
-void macho_dysymtab_command::set_nlocrel(uint32_t _value) {
- ENDIAN_WRITE32(content.nlocrel, _value);
-}
-
-
-
-#undef twolevel_hints_command
-class macho_twolevel_hints_command {
-public:
- uint32_t cmd() const;
- void set_cmd(uint32_t);
-
- uint32_t cmdsize() const;
- void set_cmdsize(uint32_t);
-
- uint32_t offset() const;
- void set_offset(uint32_t);
-
- uint32_t nhints() const;
- void set_nhints(uint32_t);
-
-private:
- struct twolevel_hints_command content;
-};
-#define twolevel_hints_command __my_bad
-
-inline __attribute__((always_inline))
-uint32_t macho_twolevel_hints_command::cmd() const {
- return ENDIAN_READ32(content.cmd);
-}
-
-inline __attribute__((always_inline))
-void macho_twolevel_hints_command::set_cmd(uint32_t _value) {
- ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_twolevel_hints_command::cmdsize() const {
- return ENDIAN_READ32(content.cmdsize);
-}
-
-inline __attribute__((always_inline))
-void macho_twolevel_hints_command::set_cmdsize(uint32_t _value) {
- ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_twolevel_hints_command::offset() const {
- return ENDIAN_READ32(content.offset);
-}
-
-inline __attribute__((always_inline))
-void macho_twolevel_hints_command::set_offset(uint32_t _value) {
- ENDIAN_WRITE32(content.offset, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_twolevel_hints_command::nhints() const {
- return ENDIAN_READ32(content.nhints);
-}
-
-inline __attribute__((always_inline))
-void macho_twolevel_hints_command::set_nhints(uint32_t _value) {
- ENDIAN_WRITE32(content.nhints, _value);
-}
-
-
-#undef thread_command
-class macho_thread_command {
-public:
- uint32_t cmd() const;
- void set_cmd(uint32_t);
-
- uint32_t cmdsize() const;
- void set_cmdsize(uint32_t);
-
- uint32_t flavor() const;
- void set_flavor(uint32_t);
-
- uint32_t count() const;
- void set_count(uint32_t);
-
- uint32_t threadState32(uint32_t index) const;
- void set_threadState32(uint32_t index, uint32_t value);
-
- uint64_t threadState64(uint32_t offset) const;
- void set_threadState64(uint32_t index, uint64_t value);
-
- enum { size = sizeof(struct thread_command) + 8 };
-
-private:
- struct thread_command content;
- uint32_t content_flavor;
- uint32_t content_count;
- uint32_t threadState[1];
-};
-#define thread_command __my_bad
-
-inline __attribute__((always_inline))
-uint32_t macho_thread_command::cmd() const {
- return ENDIAN_READ32(content.cmd);
-}
-
-inline __attribute__((always_inline))
-void macho_thread_command::set_cmd(uint32_t _value) {
- ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_thread_command::cmdsize() const {
- return ENDIAN_READ32(content.cmdsize);
-}
-
-inline __attribute__((always_inline))
-void macho_thread_command::set_cmdsize(uint32_t _value) {
- ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_thread_command::flavor() const {
- return ENDIAN_READ32(content_flavor);
-}
-
-inline __attribute__((always_inline))
-void macho_thread_command::set_flavor(uint32_t _value) {
- ENDIAN_WRITE32(content_flavor, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_thread_command::count() const {
- return ENDIAN_READ32(content_count);
-}
-
-inline __attribute__((always_inline))
-void macho_thread_command::set_count(uint32_t _value) {
- ENDIAN_WRITE32(content_count, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_thread_command::threadState32(uint32_t index) const
-{
- return ENDIAN_READ32(threadState[index]);
-}
-
-inline __attribute__((always_inline))
-void macho_thread_command::set_threadState32(uint32_t index, uint32_t _value)
-{
- ENDIAN_WRITE32(threadState[index], _value);
-}
-
-inline __attribute__((always_inline))
-uint64_t macho_thread_command::threadState64(uint32_t index) const
-{
- uint64_t temp = *((uint64_t*)(&threadState[index]));
- return ENDIAN_SWAP64(temp);
-}
-
-inline __attribute__((always_inline))
-void macho_thread_command::set_threadState64(uint32_t index, uint64_t _value)
-{
- *((uint64_t*)(&threadState[index])) = ENDIAN_SWAP64(_value);
-}
-
-
-
-#undef nlist
-#undef nlist_64
-class macho_nlist {
-public:
- uint32_t n_strx() const;
- void set_n_strx(uint32_t);
-
- uint8_t n_type() const;
- void set_n_type(uint8_t);
-
- uint8_t n_sect() const;
- void set_n_sect(uint8_t);
-
- uint16_t n_desc() const;
- void set_n_desc(uint16_t);
-
- uint64_t n_value() const;
- void set_n_value(uint64_t);
-
-
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
- enum { size = sizeof(struct nlist_64) };
-#else
- enum { size = sizeof(struct nlist) };
-#endif
-
-private:
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
- struct nlist_64 content;
-#else
- struct nlist content;
-#endif
-};
-#define nlist __my_bad
-#define nlist_64 __my_bad
-
-inline __attribute__((always_inline))
-uint32_t macho_nlist::n_strx() const {
- return ENDIAN_READ32(content.n_un.n_strx);
-}
-
-inline __attribute__((always_inline))
-void macho_nlist::set_n_strx(uint32_t _value) {
- ENDIAN_WRITE32(content.n_un.n_strx, _value);
-}
-
-inline __attribute__((always_inline))
-uint8_t macho_nlist::n_type() const {
- return content.n_type;
-}
-
-inline __attribute__((always_inline))
-void macho_nlist::set_n_type(uint8_t _value) {
- content.n_type = _value;
-}
-
-inline __attribute__((always_inline))
-uint8_t macho_nlist::n_sect() const {
- return content.n_sect;
-}
-
-inline __attribute__((always_inline))
-void macho_nlist::set_n_sect(uint8_t _value) {
- content.n_sect = _value;
-}
-
-inline __attribute__((always_inline))
-uint16_t macho_nlist::n_desc() const {
- return ENDIAN_READ16(content.n_desc);
-}
-
-inline __attribute__((always_inline))
-void macho_nlist::set_n_desc(uint16_t _value) {
- ENDIAN_WRITE16(content.n_desc, _value);
-}
-
-inline __attribute__((always_inline))
-uint64_t macho_nlist::n_value() const {
-#if defined(ARCH_PPC64)
- return ENDIAN_SWAP64(content.n_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- return ENDIAN_READ32(content.n_value);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-void macho_nlist::set_n_value(uint64_t _value) {
-#if defined(ARCH_PPC64)
- content.n_value = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- ENDIAN_WRITE32(content.n_value, _value);
-#else
- #error unknown architecture
-#endif
-}
-
-
-
-#undef relocation_info
-class macho_relocation_info {
-public:
- int32_t r_address() const;
- void set_r_address(int32_t);
-
- uint32_t r_symbolnum() const;
- void set_r_symbolnum(uint32_t);
-
- bool r_pcrel() const;
- void set_r_pcrel(bool);
-
- uint8_t r_length() const;
- void set_r_length(uint8_t);
-
- bool r_extern() const;
- void set_r_extern(bool);
-
- uint8_t r_type() const;
- void set_r_type(uint8_t);
-
- enum { size = sizeof(struct relocation_info) };
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
- enum { pointer_length = 3 };
-#else
- enum { pointer_length = 2 };
-#endif
-
-private:
- struct relocation_info content;
-};
-#define relocation_info __my_bad
-
-
-inline __attribute__((always_inline))
-int32_t macho_relocation_info::r_address() const {
- return ENDIAN_READ32(content.r_address);
-}
-
-inline __attribute__((always_inline))
-void macho_relocation_info::set_r_address(int32_t _value) {
- ENDIAN_WRITE32(content.r_address, _value);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_relocation_info::r_symbolnum() const {
- uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- return (temp >> 8);
-#elif defined(ARCH_I386)
- return temp & 0x00FFFFFF;
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-void macho_relocation_info::set_r_symbolnum(uint32_t _value) {
- uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- temp &= 0x000000FF;
- temp |= ((_value & 0x00FFFFFF) << 8);
-#elif defined(ARCH_I386)
- temp &= 0xFF000000;
- temp |= (_value & 0x00FFFFFF);
-#else
- #error unknown architecture
-#endif
- ENDIAN_WRITE32(((uint32_t*)&content)[1], temp);
-}
-
-inline __attribute__((always_inline))
-bool macho_relocation_info::r_pcrel() const {
- uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- return ((temp & 0x00000080) != 0);
-#elif defined(ARCH_I386)
- return ((temp & 0x01000000) != 0);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-void macho_relocation_info::set_r_pcrel(bool _value) {
- uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- temp &= 0xFFFFFF7F;
- if ( _value )
- temp |= 0x00000080;
-#elif defined(ARCH_I386)
- temp &= 0xFEFFFFFF;
- if ( _value )
- temp |= 0x01000000;
-#else
- #error unknown architecture
-#endif
- ENDIAN_WRITE32(((uint32_t*)&content)[1], temp);
-}
-
-inline __attribute__((always_inline))
-uint8_t macho_relocation_info::r_length() const {
- uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- return ((temp & 0x00000060) >> 5);
-#elif defined(ARCH_I386)
- return ((temp & 0x06000000) >> 25);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-void macho_relocation_info::set_r_length(uint8_t _value) {
- uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- temp &= 0xFFFFFF9F;
- temp |= ((_value & 0x03) << 5);
-#elif defined(ARCH_I386)
- temp &= 0xF9FFFFFF;
- temp |= ((_value & 0x03) << 25);
-#else
- #error unknown architecture
-#endif
- ENDIAN_WRITE32(((uint32_t*)&content)[1], temp);
-}
-
-inline __attribute__((always_inline))
-bool macho_relocation_info::r_extern() const {
- uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- return ((temp & 0x00000010) != 0);
-#elif defined(ARCH_I386)
- return ((temp & 0x08000000) != 0);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-void macho_relocation_info::set_r_extern(bool _value) {
- uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- temp &= 0xFFFFFFEF;
- if ( _value )
- temp |= 0x00000010;
-#elif defined(ARCH_I386)
- temp &= 0xF7FFFFFF;
- if ( _value )
- temp |= 0x08000000;
-#else
- #error unknown architecture
-#endif
- ENDIAN_WRITE32(((uint32_t*)&content)[1], temp);
-}
-
-inline __attribute__((always_inline))
-uint8_t macho_relocation_info::r_type() const {
- uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- return (temp & 0x0000000F);
-#elif defined(ARCH_I386)
- return ((temp & 0xF0000000) >> 28);
-#else
- #error unknown architecture
-#endif
-}
-
-inline __attribute__((always_inline))
-void macho_relocation_info::set_r_type(uint8_t _value) {
- uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- temp &= 0xFFFFFFF0;
- temp |= (_value & 0x0F);
-#elif defined(ARCH_I386)
- temp &= 0x0FFFFFFF;
- temp |= ((_value & 0x0F) << 28);
-#else
- #error unknown architecture
-#endif
- ENDIAN_WRITE32(((uint32_t*)&content)[1], temp);
-}
-
-
-
-#undef scattered_relocation_info
-class macho_scattered_relocation_info {
-public:
- bool r_scattered() const;
- void set_r_scattered(bool);
-
- bool r_pcrel() const;
- void set_r_pcrel(bool);
-
- uint8_t r_length() const;
- void set_r_length(uint8_t);
-
- uint8_t r_type() const;
- void set_r_type(uint8_t);
-
- uint32_t r_address() const;
- void set_r_address(uint32_t);
-
- int32_t r_value() const;
- void set_r_value(int32_t);
-
-private:
- struct scattered_relocation_info content;
-};
-#define scattered_relocation_info __my_bad
-
-inline __attribute__((always_inline))
-bool macho_scattered_relocation_info::r_scattered() const {
- uint32_t temp = *((const uint32_t*)&content);
- temp = ENDIAN_READ32(temp);
- return ((temp & 0x80000000) != 0);
-}
-
-inline __attribute__((always_inline))
-void macho_scattered_relocation_info::set_r_scattered(bool _value) {
- uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
- if ( _value )
- temp |= 0x80000000;
- else
- temp &= ~0x80000000;
- ENDIAN_WRITE32(*((uint32_t*)&content), temp);
-}
-
-inline __attribute__((always_inline))
-bool macho_scattered_relocation_info::r_pcrel() const {
- uint32_t temp = *((const uint32_t*)&content);
- temp = ENDIAN_READ32(temp);
- return ((temp & 0x40000000) != 0);
-}
-
-inline __attribute__((always_inline))
-void macho_scattered_relocation_info::set_r_pcrel(bool _value) {
- uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
- if ( _value )
- temp |= 0x40000000;
- else
- temp &= ~0x40000000;
- ENDIAN_WRITE32(*((uint32_t*)&content), temp);
-}
-
-inline __attribute__((always_inline))
-uint8_t macho_scattered_relocation_info::r_length() const {
- uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
- return (temp >> 28) & 0x03;
-}
-
-inline __attribute__((always_inline))
-void macho_scattered_relocation_info::set_r_length(uint8_t _value) {
- uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
- temp &= 0xCFFFFFFF;
- temp |= ((_value & 0x03) << 28);
- ENDIAN_WRITE32(*((uint32_t*)&content), temp);
-}
-
-inline __attribute__((always_inline))
-uint8_t macho_scattered_relocation_info::r_type() const {
- uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
- return (temp >> 24) & 0x0F;
-}
-
-inline __attribute__((always_inline))
-void macho_scattered_relocation_info::set_r_type(uint8_t _value) {
- uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
- temp &= 0xF0FFFFFF;
- temp |= ((_value &0x0F) << 24);
- ENDIAN_WRITE32(*((uint32_t*)&content), temp);
-}
-
-inline __attribute__((always_inline))
-uint32_t macho_scattered_relocation_info::r_address() const {
- uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
- return temp & 0x00FFFFFF;
-}
-
-inline __attribute__((always_inline))
-void macho_scattered_relocation_info::set_r_address(uint32_t _value) {
- uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
- _value &= 0x00FFFFFF;
- temp &= 0xFF000000;
- temp |= _value;
- ENDIAN_WRITE32(*((uint32_t*)&content), temp);
-}
-
-inline __attribute__((always_inline))
-int32_t macho_scattered_relocation_info::r_value() const {
- return ENDIAN_READ32(content.r_value);
-}
-
-inline __attribute__((always_inline))
-void macho_scattered_relocation_info::set_r_value(int32_t _value) {
- ENDIAN_WRITE32(content.r_value, _value);
-}
-
-
-
-
--- /dev/null
+/* -*- 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 __MACH_O_FILE_ABSTRACTION__
+#define __MACH_O_FILE_ABSTRACTION__
+
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/reloc.h>
+#include <mach/machine.h>
+
+// suport older versions of mach-o/loader.h
+#ifndef LC_UUID
+#define LC_UUID 0x1b
+struct uuid_command {
+ uint32_t cmd; /* LC_UUID */
+ uint32_t cmdsize; /* sizeof(struct uuid_command) */
+ uint8_t uuid[16]; /* the 128-bit uuid */
+};
+#endif
+
+
+#include "FileAbstraction.hpp"
+#include "Architectures.hpp"
+
+
+
+//
+// This abstraction layer makes every mach-o file look like a 64-bit mach-o file with native endianness
+//
+
+
+
+//
+// mach-o file header
+//
+template <typename P> struct macho_header_content {};
+template <> struct macho_header_content<Pointer32<BigEndian> > { mach_header fields; };
+template <> struct macho_header_content<Pointer64<BigEndian> > { mach_header_64 fields; };
+template <> struct macho_header_content<Pointer32<LittleEndian> > { mach_header fields; };
+template <> struct macho_header_content<Pointer64<LittleEndian> > { mach_header_64 fields; };
+
+template <typename P>
+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<P> header;
+};
+
+
+//
+// mach-o load command
+//
+template <typename P>
+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 <typename P> struct macho_segment_content {};
+template <> struct macho_segment_content<Pointer32<BigEndian> > { segment_command fields; enum { CMD = LC_SEGMENT }; };
+template <> struct macho_segment_content<Pointer64<BigEndian> > { segment_command_64 fields; enum { CMD = LC_SEGMENT_64 }; };
+template <> struct macho_segment_content<Pointer32<LittleEndian> > { segment_command fields; enum { CMD = LC_SEGMENT }; };
+template <> struct macho_segment_content<Pointer64<LittleEndian> > { segment_command_64 fields; enum { CMD = LC_SEGMENT_64 }; };
+
+template <typename P>
+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 { memcpy(&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<P>::CMD
+ };
+
+ typedef typename P::E E;
+private:
+ macho_segment_content<P> segment;
+};
+
+
+//
+// mach-o section
+//
+template <typename P> struct macho_section_content {};
+template <> struct macho_section_content<Pointer32<BigEndian> > { section fields; };
+template <> struct macho_section_content<Pointer64<BigEndian> > { section_64 fields; };
+template <> struct macho_section_content<Pointer32<LittleEndian> > { section fields; };
+template <> struct macho_section_content<Pointer64<LittleEndian> > { section_64 fields; };
+
+template <typename P>
+class macho_section {
+public:
+ const char* sectname() const INLINE { return section.fields.sectname; }
+ void set_sectname(const char* value) INLINE { memcpy(§ion.fields.sectname, value, 16); }
+
+ const char* segname() const INLINE { return section.fields.segname; }
+ void set_segname(const char* value) INLINE { memcpy(§ion.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<P> section;
+};
+
+
+//
+// mach-o dylib load command
+//
+template <typename P>
+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 <typename P>
+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 <typename P>
+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 <typename P>
+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 <typename P>
+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 <typename P>
+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 <typename P>
+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 <typename P> struct macho_routines_content {};
+template <> struct macho_routines_content<Pointer32<BigEndian> > { routines_command fields; enum { CMD = LC_ROUTINES }; };
+template <> struct macho_routines_content<Pointer64<BigEndian> > { routines_command_64 fields; enum { CMD = LC_ROUTINES_64 }; };
+template <> struct macho_routines_content<Pointer32<LittleEndian> > { routines_command fields; enum { CMD = LC_ROUTINES }; };
+template <> struct macho_routines_content<Pointer64<LittleEndian> > { routines_command_64 fields; enum { CMD = LC_ROUTINES_64 }; };
+
+template <typename P>
+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<P>::CMD
+ };
+private:
+ macho_routines_content<P> routines;
+};
+
+
+//
+// mach-o symbol table load command
+//
+template <typename P>
+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 <typename P>
+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 two-level hints load command
+//
+template <typename P>
+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 <typename P>
+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 symbol table entry
+//
+template <typename P> struct macho_nlist_content {};
+template <> struct macho_nlist_content<Pointer32<BigEndian> > { struct nlist fields; };
+template <> struct macho_nlist_content<Pointer64<BigEndian> > { struct nlist_64 fields; };
+template <> struct macho_nlist_content<Pointer32<LittleEndian> > { struct nlist fields; };
+template <> struct macho_nlist_content<Pointer64<LittleEndian> > { struct nlist_64 fields; };
+
+template <typename P>
+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<P> entry;
+};
+
+
+
+//
+// mach-o relocation info
+//
+template <typename P>
+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 <typename P>
+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) INLINE { 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; }
+
+ typedef typename P::E E;
+private:
+ uint32_t other;
+ uint32_t value;
+};
+
+
+
+
+
+
+#endif // __MACH_O_FILE_ABSTRACTION__
+
+
--- /dev/null
+/* -*- 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 __OBJECT_FILE_ARCHIVE_MACH_O__
+#define __OBJECT_FILE_ARCHIVE_MACH_O__
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <mach-o/ranlib.h>
+#include <ar.h>
+
+#include <vector>
+#include <set>
+#include <algorithm>
+#include <ext/hash_map>
+
+#include "MachOFileAbstraction.hpp"
+#include "ObjectFile.h"
+#include "MachOReaderRelocatable.hpp"
+
+
+namespace mach_o {
+namespace archive {
+
+typedef const struct ranlib* ConstRanLibPtr;
+
+template <typename A>
+class Reader : public ObjectFile::Reader
+{
+public:
+ static bool validFile(const uint8_t* fileContent, uint64_t fileLength);
+ static Reader<A>* make(const uint8_t* fileContent, uint64_t fileLength, const char* path,
+ time_t modTime, const ObjectFile::ReaderOptions& options)
+ { return new Reader<A>(fileContent, fileLength, path, modTime, options); }
+ virtual ~Reader() {}
+
+ virtual const char* getPath() { return fPath; }
+ virtual time_t getModificationTime(){ return 0; }
+ virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; }
+ virtual std::vector<class ObjectFile::Atom*>& getAtoms();
+ virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name);
+ virtual std::vector<Stab>* getStabs() { return NULL; }
+
+private:
+ 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<const char*, const struct ranlib*, __gnu_cxx::hash<const char*>, CStringEquals> NameToEntryMap;
+
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+
+ Reader(const uint8_t fileContent[], uint64_t fileLength,
+ const char* path, time_t modTime, const ObjectFile::ReaderOptions& options);
+ const struct ranlib* ranlibBinarySearch(const char* name);
+ const struct ranlib* ranlibLinearSearch(const char* name);
+ 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;
+ const uint8_t* fFileContent;
+ uint64_t fFileLength;
+ const struct ranlib* fTableOfContents;
+ uint32_t fTableOfContentCount;
+ const char* fStringPool;
+ std::vector<class ObjectFile::Atom*> fAllAtoms;
+ std::set<const class Entry*> fInstantiatedEntries;
+ std::set<const class Entry*> fPossibleEntries;
+ NameToEntryMap fHashTable;
+
+ static std::vector<class ObjectFile::Atom*> fgEmptyList;
+};
+
+template <typename A>
+std::vector<class ObjectFile::Atom*> Reader<A>::fgEmptyList;
+
+
+template <typename A>
+bool Reader<A>::Entry::hasLongName() const
+{
+ return ( strncmp(this->ar_name, AR_EFMT1, strlen(AR_EFMT1)) == 0 );
+}
+
+template <typename A>
+unsigned int Reader<A>::Entry::getLongNameSpace() const
+{
+ char* endptr;
+ long result = strtol(&this->ar_name[strlen(AR_EFMT1)], &endptr, 10);
+ return result;
+}
+
+template <typename A>
+const char* Reader<A>::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 <typename A>
+time_t Reader<A>::Entry::getModTime() const
+{
+ char temp[14];
+ strncpy(temp, this->ar_size, 12);
+ temp[12] = '\0';
+ char* endptr;
+ return (time_t)strtol(temp, &endptr, 12);
+}
+
+
+template <typename A>
+const uint8_t* Reader<A>::Entry::getContent() const
+{
+ if ( this->hasLongName() )
+ return ((uint8_t*)this) + sizeof(ar_hdr) + this->getLongNameSpace();
+ else
+ return ((uint8_t*)this) + sizeof(ar_hdr);
+}
+
+
+template <typename A>
+uint32_t Reader<A>::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 <typename A>
+const class Reader<A>::Entry* Reader<A>::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<A>::Entry*)p;
+}
+
+template <typename A>
+bool Reader<A>::validFile(const uint8_t* fileContent, uint64_t fileLength)
+{
+ // must have valid archive header
+ if ( strncmp((const char*)fileContent, "!<arch>\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 mach_o::relocatable::Reader<A>::validFile(p->getContent());
+ }
+ // empty archive
+ return true;
+}
+
+template <typename A>
+Reader<A>::Reader(const uint8_t fileContent[], uint64_t fileLength, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options)
+ : fPath(NULL), fModTime(modTime), fOptions(options), fFileContent(NULL), fTableOfContents(NULL), fTableOfContentCount(0),
+ fStringPool(NULL)
+{
+ fPath = strdup(path);
+ fFileContent = fileContent;
+ fFileLength = fileLength;
+
+ if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
+ throw "not an archive";
+
+ 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 <typename A>
+ObjectFile::Reader* Reader<A>::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 {
+ ObjectFile::Reader* obj = mach_o::relocatable::Reader<A>::make(member->getContent(), memberPath, fModTime, fOptions);
+ unsigned int objIndex = 0;
+ for (class std::set<const class Entry*>::iterator it=fPossibleEntries.begin(); it != fPossibleEntries.end(); it++, objIndex++) {
+ if ( *it == member )
+ break;
+ }
+ obj->setSortOrder((fSortOrder<<16) + objIndex);
+ //fprintf(stderr, "%s order = 0x%08X, index=%u\n", memberPath, obj->getSortOrder(), objIndex);
+ return obj;
+ }
+ catch (const char* msg) {
+ throwf("in %s, %s", memberPath, msg);
+ }
+}
+
+template <typename A>
+std::vector<class ObjectFile::Atom*>& Reader<A>::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];
+ unsigned int objIndex = 0;
+ 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;
+ ObjectFile::Reader* r = this->makeObjectReaderForMember(p);
+ r->setSortOrder((fSortOrder<<16) + objIndex++);
+ std::vector<class ObjectFile::Atom*>& atoms = r->getAtoms();
+ fAllAtoms.insert(fAllAtoms.end(), atoms.begin(), atoms.end());
+ }
+ return fAllAtoms;
+ }
+ else {
+ // return nonthing for now, getJustInTimeAtomsFor() will return atoms as needed
+ return fgEmptyList;
+ }
+}
+
+
+template <typename A>
+ConstRanLibPtr Reader<A>::ranlibBinarySearch(const char* key)
+{
+ const struct ranlib* base = fTableOfContents;
+ for (uint32_t n = fTableOfContentCount; n > 0; n /= 2) {
+ const struct ranlib* pivot = &base[n/2];
+ const char* pivotStr = &fStringPool[E::get32(pivot->ran_un.ran_strx)];
+ int cmp = strcmp(key, pivotStr);
+ if ( cmp == 0 )
+ return pivot;
+ if ( cmp > 0 ) {
+ // key > pivot
+ // move base to symbol after pivot
+ base = &pivot[1];
+ --n;
+ }
+ else {
+ // key < pivot
+ // keep same base
+ }
+ }
+ return NULL;
+}
+
+template <typename A>
+ConstRanLibPtr Reader<A>::ranlibLinearSearch(const char* key)
+{
+ for (uint32_t i = 0; i < fTableOfContentCount; ++i) {
+ const struct ranlib* entry = &fTableOfContents[i];
+ const char* entryName = &fStringPool[E::get32(entry->ran_un.ran_strx)];
+ if ( strcmp(key, entryName) == 0 )
+ return entry;
+ }
+ return NULL;
+}
+
+template <typename A>
+ConstRanLibPtr Reader<A>::ranlibHashSearch(const char* name)
+{
+ class NameToEntryMap::iterator pos = fHashTable.find(name);
+ if ( pos != fHashTable.end() )
+ return pos->second;
+ else
+ return NULL;
+}
+
+template <typename A>
+void Reader<A>::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 <typename A>
+void Reader<A>::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 <typename A>
+std::vector<class ObjectFile::Atom*>* Reader<A>::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 ) {
+ // only return these atoms once
+ fInstantiatedEntries.insert(member);
+ ObjectFile::Reader* r = makeObjectReaderForMember(member);
+ //fprintf(stderr, "%s found in %s(%s)\n", name, this->getPath(), member->getName());
+ return new std::vector<class ObjectFile::Atom*>(r->getAtoms());
+ }
+ }
+ //fprintf(stderr, "%s NOT found in archive %s\n", name, fPath);
+ return NULL;
+ }
+}
+
+
+
+
+
+}; // namespace archive
+}; // namespace mach_o
+
+
+#endif // __OBJECT_FILE_ARCHIVE_MACH_O__
--- /dev/null
+/* -*- 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 __OBJECT_FILE_DYLIB_MACH_O__
+#define __OBJECT_FILE_DYLIB_MACH_O__
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <sys/param.h>
+
+
+#include <vector>
+#include <set>
+#include <algorithm>
+#include <ext/hash_map>
+
+#include "MachOFileAbstraction.hpp"
+#include "ObjectFile.h"
+
+//
+//
+// To implement architecture xxx, you must write template specializations for the following method:
+// Reader<xxx>::validFile()
+//
+//
+
+
+
+
+namespace mach_o {
+namespace dylib {
+
+
+// forward reference
+template <typename A> 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 can from which dynamic libraries.
+//
+template <typename A>
+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 isZeroFill() const { return false; }
+ virtual uint64_t getSize() const { return 0; }
+ virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
+ virtual bool mustRemainInSection() const { return false; }
+ virtual const char* getSectionName() const { return "._imports"; }
+ virtual Segment& getSegment() const { return fgImportSegment; }
+ virtual bool requiresFollowOnAtom() const{ return false; }
+ virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
+ virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
+ virtual uint8_t getAlignment() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {}
+
+ virtual void setScope(Scope) { }
+
+protected:
+ friend class Reader<A>;
+ typedef typename A::P P;
+
+ ExportAtom(ObjectFile::Reader& owner, const char* name, bool weak)
+ : fOwner(owner), fName(name), fWeakDefinition(weak) {}
+ virtual ~ExportAtom() {}
+
+ ObjectFile::Reader& fOwner;
+ const char* fName;
+ bool fWeakDefinition;
+
+ static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
+ static Segment fgImportSegment;
+};
+
+template <typename A>
+Segment ExportAtom<A>::fgImportSegment("__LINKEDIT");
+
+template <typename A>
+std::vector<ObjectFile::Reference*> ExportAtom<A>::fgEmptyReferenceList;
+
+
+//
+// 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 <typename A>
+class Reader : public ObjectFile::Reader
+{
+public:
+ static bool validFile(const uint8_t* fileContent);
+ static Reader<A>* make(const uint8_t* fileContent, uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options)
+ { return new Reader<A>(fileContent, fileLength, path, options); }
+ virtual ~Reader() {}
+
+ virtual const char* getPath() { return fPath; }
+ virtual time_t getModificationTime() { return 0; }
+ virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; }
+ virtual std::vector<class ObjectFile::Atom*>& getAtoms();
+ virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name);
+ virtual std::vector<Stab>* getStabs() { return NULL; }
+ 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 std::vector<const char*>* getDependentLibraryPaths();
+ virtual bool reExports(ObjectFile::Reader*);
+ virtual std::vector<const char*>* getAllowableClients();
+
+protected:
+ const char* parentUmbrella() { return fParentUmbrella; }
+
+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; };
+ typedef __gnu_cxx::hash_map<const char*, AtomAndWeak, __gnu_cxx::hash<const char*>, CStringEquals> NameToAtomMap;
+ typedef typename NameToAtomMap::iterator NameToAtomMapIterator;
+
+ struct PathAndFlag { const char* path; bool reExport; };
+
+ Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
+
+ const char* fPath;
+ const char* fParentUmbrella;
+ std::vector<const char*> fAllowableClients;
+ const char* fDylibInstallPath;
+ uint32_t fDylibTimeStamp;
+ uint32_t fDylibtCurrentVersion;
+ uint32_t fDylibCompatibilityVersion;
+ std::vector<PathAndFlag> fDependentLibraryPaths;
+ NameToAtomMap fAtoms;
+
+ static bool fgLogHashtable;
+ static std::vector<class ObjectFile::Atom*> fgEmptyAtomList;
+};
+
+template <typename A>
+std::vector<class ObjectFile::Atom*> Reader<A>::fgEmptyAtomList;
+template <typename A>
+bool Reader<A>::fgLogHashtable = false;
+
+
+template <typename A>
+Reader<A>::Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options)
+ : fParentUmbrella(NULL), fDylibInstallPath(NULL), fDylibTimeStamp(0), fDylibtCurrentVersion(0), fDylibCompatibilityVersion(0)
+{
+ // sanity check
+ if ( ! validFile(fileContent) )
+ throw "not a valid mach-o object file";
+
+ fPath = strdup(path);
+
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ const uint32_t cmd_count = header->ncmds();
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
+
+ // 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;
+ }
+
+ // pass 1 builds list of all dependent libraries
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch (cmd->cmd()) {
+ case LC_LOAD_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ PathAndFlag entry;
+ entry.path = strdup(((struct macho_dylib_command<P>*)cmd)->name());
+ entry.reExport = false;
+ fDependentLibraryPaths.push_back(entry);
+ break;
+ }
+ cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+ }
+
+ // pass 2 determines re-export info
+ const macho_dysymtab_command<P>* dynamicInfo = NULL;
+ const macho_nlist<P>* 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<P>* symtab = (macho_symtab_command<P>*)cmd;
+ symbolTable = (const macho_nlist<P>*)((char*)header + symtab->symoff());
+ strings = (char*)header + symtab->stroff();
+ }
+ break;
+ case LC_DYSYMTAB:
+ dynamicInfo = (macho_dysymtab_command<P>*)cmd;
+ break;
+ case LC_ID_DYLIB:
+ macho_dylib_command<P>* dylibID = (macho_dylib_command<P>*)cmd;
+ fDylibInstallPath = strdup(dylibID->name());
+ fDylibTimeStamp = dylibID->timestamp();
+ fDylibtCurrentVersion = dylibID->current_version();
+ fDylibCompatibilityVersion = dylibID->compatibility_version();
+ break;
+ case LC_SUB_UMBRELLA:
+ if ( !options.fFlatNamespace ) {
+ const char* frameworkLeafName = ((macho_sub_umbrella_command<P>*)cmd)->sub_umbrella();
+ for (typename std::vector<PathAndFlag>::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 ( !options.fFlatNamespace ) {
+ const char* dylibBaseName = ((macho_sub_library_command<P>*)cmd)->sub_library();
+ for (typename std::vector<PathAndFlag>::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<P>*)cmd)->umbrella());
+ break;
+ }
+
+ cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+ }
+ // 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<P>*)cmd)->client());
+
+ fAllowableClients.push_back(temp);
+ break;
+ }
+
+ cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+ }
+
+ // validate minimal load commands
+ if ( fDylibInstallPath == NULL )
+ throw "dylib missing LC_ID_DYLIB load command";
+ if ( symbolTable == NULL )
+ throw "dylib missing LC_SYMTAB load command";
+ if ( dynamicInfo == NULL )
+ throw "dylib missing LC_DYSYMTAB load command";
+
+ // build hash table
+ if ( dynamicInfo->tocoff() == 0 ) {
+ if ( fgLogHashtable ) fprintf(stderr, "ld64: building hashtable of %u toc entries for %s\n", dynamicInfo->nextdefsym(), path);
+ const macho_nlist<P>* start = &symbolTable[dynamicInfo->iextdefsym()];
+ const macho_nlist<P>* end = &start[dynamicInfo->nextdefsym()];
+ fAtoms.resize(dynamicInfo->nextdefsym()); // set initial bucket count
+ for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
+ AtomAndWeak bucket;
+ bucket.atom = NULL;
+ bucket.weak = ((sym->n_desc() & N_WEAK_DEF) != 0);
+ const char* name = strdup(&strings[sym->n_strx()]);
+ if ( fgLogHashtable ) fprintf(stderr, " adding %s to hash table for %s\n", name, this->getPath());
+ fAtoms[name] = bucket;
+ }
+ }
+ else {
+ int32_t count = dynamicInfo->ntoc();
+ fAtoms.resize(count); // set initial bucket count
+ if ( fgLogHashtable ) fprintf(stderr, "ld64: 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<P>* sym = &symbolTable[index];
+ AtomAndWeak bucket;
+ bucket.atom = NULL;
+ bucket.weak = ((sym->n_desc() & N_WEAK_DEF) != 0);
+ const char* name = strdup(&strings[sym->n_strx()]);
+ if ( fgLogHashtable ) fprintf(stderr, " adding %s to hash table for %s\n", name, this->getPath());
+ fAtoms[name] = bucket;
+ }
+ }
+
+ // unmap file
+ munmap((caddr_t)fileContent, fileLength);
+}
+
+template <typename A>
+std::vector<class ObjectFile::Atom*>& Reader<A>::getAtoms()
+{
+ // TO DO: for flat-namespace libraries, when linking flat_namespace
+ // we need to create an atom which references all undefines
+ return fgEmptyAtomList;
+}
+
+
+template <typename A>
+std::vector<class ObjectFile::Atom*>* Reader<A>::getJustInTimeAtomsFor(const char* name)
+{
+ std::vector<class ObjectFile::Atom*>* 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<A>(*this, name, pos->second.weak);
+ if ( fgLogHashtable ) fprintf(stderr, "getJustInTimeAtomsFor: %s found in %s\n", name, this->getPath());
+ }
+ // return a vector of one atom
+ atoms = new std::vector<class ObjectFile::Atom*>;
+ atoms->push_back(pos->second.atom);
+ }
+ else {
+ if ( fgLogHashtable ) fprintf(stderr, "getJustInTimeAtomsFor: %s NOT found in %s\n", name, this->getPath());
+ }
+ return atoms;
+}
+
+
+
+template <typename A>
+std::vector<const char*>* Reader<A>::getDependentLibraryPaths()
+{
+ std::vector<const char*>* result = new std::vector<const char*>;
+ for (typename std::vector<PathAndFlag>::iterator it = fDependentLibraryPaths.begin(); it != fDependentLibraryPaths.end(); it++) {
+ result->push_back(it->path);
+ }
+ return result;
+}
+
+template <typename A>
+std::vector<const char*>* Reader<A>::getAllowableClients()
+{
+ std::vector<const char*>* result = new std::vector<const char*>;
+ for (typename std::vector<const char*>::iterator it = fAllowableClients.begin();
+ it != fAllowableClients.end();
+ it++) {
+ result->push_back(*it);
+ }
+ return (fAllowableClients.size() != 0 ? result : NULL);
+}
+
+template <typename A>
+bool Reader<A>::reExports(ObjectFile::Reader* child)
+{
+ // A dependent dylib is re-exported under two conditions:
+ // 1) parent contains LC_SUB_UMBRELLA or LC_SUB_LIBRARY with child name
+ for (typename std::vector<PathAndFlag>::iterator it = fDependentLibraryPaths.begin(); it != fDependentLibraryPaths.end(); it++) {
+ if ( it->reExport && (strcmp(it->path, child->getPath()) == 0) )
+ return true;
+ }
+
+ // 2) child contains LC_SUB_FRAMEWORK with parent name
+ const char* parentUmbrellaName = ((Reader<A>*)child)->parentUmbrella();
+ if ( parentUmbrellaName != NULL ) {
+ const char* parentName = this->getPath();
+ const char* lastSlash = strrchr(parentName, '/');
+ if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], parentUmbrellaName) == 0) )
+ return true;
+ }
+
+ return false;
+}
+
+template <>
+bool Reader<ppc>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_POWERPC )
+ return false;
+ if ( (header->filetype() != MH_DYLIB) && (header->filetype() != MH_DYLIB_STUB) )
+ return false;
+ return true;
+}
+
+template <>
+bool Reader<ppc64>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_POWERPC64 )
+ return false;
+ if ( (header->filetype() != MH_DYLIB) && (header->filetype() != MH_DYLIB_STUB) )
+ return false;
+ return true;
+}
+
+template <>
+bool Reader<x86>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_I386 )
+ return false;
+ if ( (header->filetype() != MH_DYLIB) && (header->filetype() != MH_DYLIB_STUB) )
+ return false;
+ return true;
+}
+
+
+
+
+}; // namespace dylib
+}; // namespace mach_o
+
+
+#endif // __OBJECT_FILE_DYLIB_MACH_O__
--- /dev/null
+/* -*- 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 __OBJECT_FILE_MACH_O__
+#define __OBJECT_FILE_MACH_O__
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <mach-o/ppc/reloc.h>
+#include <mach-o/stab.h>
+#ifndef S_ATTR_DEBUG
+ #define S_ATTR_DEBUG 0x02000000
+#endif
+
+#include <vector>
+#include <set>
+#include <algorithm>
+
+#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<xxx>::validFile()
+// Reader<xxx>::validSectionType()
+// Reader<xxx>::addRelocReference()
+// Reference<xxx>::getDescription()
+//
+//
+
+
+
+extern __attribute__((noreturn)) void throwf(const char* format, ...);
+
+namespace mach_o {
+namespace relocatable {
+
+
+
+// forward reference
+template <typename A> class Reader;
+template <typename A> class SymbolAtomSorter;
+
+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 <typename A>
+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 bool isTargetUnbound() const { return ( fToTarget.atom == NULL ); }
+ virtual bool isFromTargetUnbound() const { return ( fFromTarget.atom == NULL ); }
+ 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 fToTarget.offset; }
+ virtual bool hasFromTarget() const { return ( (fFromTarget.atom != NULL) || (fFromTargetName != NULL) ); }
+ 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; }
+
+
+private:
+ pint_t fFixUpOffsetInSrc;
+ AtomAndOffset fToTarget;
+ AtomAndOffset fFromTarget;
+ const char* fToTargetName;
+ const char* fFromTargetName;
+ Kinds fKind;
+};
+
+
+template <typename A>
+Reference<A>::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 where needed
+ if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit) ) {
+ fToTargetName = toTarget.atom->getName();
+ //fprintf(stderr, "Reference(): changing to by-name %p %s, target scope=%d\n", toTarget.atom, fToTargetName, toTarget.atom->getScope());
+ 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 <typename A>
+Reference<A>::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)
+ && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
+ && (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 <typename A>
+Reference<A>::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 <typename A>
+class Segment : public ObjectFile::Segment
+{
+public:
+ Segment(const macho_section<typename A::P>* 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<typename A::P>* fSection;
+ bool fWritable;
+ bool fExecutable;
+};
+
+template <typename A>
+Segment<A>::Segment(const macho_section<typename A::P>* sect)
+ : fSection(sect), fWritable(false), fExecutable(false)
+{
+ if ( strcmp(fSection->segname(), "__DATA") == 0 ) {
+ fWritable = true;
+ }
+ else if ( strcmp(fSection->segname(), "__OBJC") == 0 ) {
+ fWritable = true;
+ }
+ else if ( strcmp(fSection->segname(), "__TEXT") == 0 ) {
+ 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 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 addLineInfo(const ObjectFile::LineInfo& info) = 0;
+ virtual void alignAtLeast(uint8_t align) = 0;
+
+ uint32_t fStabsStartIndex;
+ uint32_t fStabsCount;
+};
+
+
+//
+// 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 <typename A>
+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 ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0)
+ ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; }
+ virtual bool isZeroFill() const { return ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL); }
+ virtual uint64_t getSize() const { return fSize; }
+ virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
+ virtual bool mustRemainInSection() const { return true; }
+ virtual const char* getSectionName() const;
+ virtual Segment<A>& getSegment() const { return *fSegment; }
+ virtual bool requiresFollowOnAtom() const;
+ virtual ObjectFile::Atom& getFollowOnAtom() const;
+ virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return (std::vector<ObjectFile::LineInfo>*)&fLineInfo; }
+ virtual uint8_t 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.insert(fReferences.begin(), (Reference<A>*)ref); }
+ virtual void addLineInfo(const ObjectFile::LineInfo& info) { fLineInfo.push_back(info); }
+ virtual void alignAtLeast(uint8_t align) { fAlignment = std::max(align, fAlignment); }
+
+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<Reference<A>*> 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<A>;
+ friend class SymbolAtomSorter<A>;
+
+ SymbolAtom(Reader<A>&, const macho_nlist<P>*, const macho_section<P>*);
+ virtual ~SymbolAtom() {}
+
+ Reader<A>& fOwner;
+ const macho_nlist<P>* fSymbol;
+ pint_t fAddress;
+ pint_t fSize;
+ const macho_section<P>* fSection;
+ Segment<A>* fSegment;
+ ReferenceVector fReferences;
+ std::vector<ObjectFile::LineInfo> fLineInfo;
+ ObjectFile::Atom::Scope fScope;
+ uint8_t fAlignment;
+};
+
+
+template <typename A>
+SymbolAtom<A>::SymbolAtom(Reader<A>& owner, const macho_nlist<P>* symbol, const macho_section<P>* 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<A>(fSection);
+ fAddress = fSymbol->n_value();
+ if ( (fSymbol->n_desc() & N_NO_DEAD_STRIP) != 0 )
+ this->setDontDeadStrip();
+ }
+ else {
+ printf("unknown symbol type: %d\n", 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<P>* symbolsStart = fOwner.fSymbols;
+ const macho_nlist<P>* symbolsEnd = &symbolsStart[fOwner.fSymbolCount];
+ for(const macho_nlist<P>* 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_CSTRING_LITERALS:
+ setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1);
+ case S_REGULAR:
+ case S_ZEROFILL:
+ case S_COALESCED:
+ // size calculate later after next atom is found
+ break;
+ }
+}
+
+
+template <typename A>
+void SymbolAtom<A>::setSize(uint64_t size)
+{
+ fSize = size;
+
+ // Try to compute the alignment base on the address aligned at in object file and the size
+ uint8_t sizeAlign = __builtin_ctz(fSize);
+ uint8_t sizeAndSectAlign = std::min((uint8_t)fSection->align(), sizeAlign);
+ // If address is zero, can't figure out better alignment than section alignment and size
+ if ( fAddress == 0 )
+ fAlignment = sizeAndSectAlign;
+ else
+ fAlignment = std::min((uint8_t)__builtin_ctz(fAddress), sizeAndSectAlign);
+}
+
+
+template <typename A>
+const char* SymbolAtom<A>::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 <typename A>
+bool SymbolAtom<A>::requiresFollowOnAtom() const
+{
+ // requires follow-on if built with old compiler and not the last atom
+ if ( (fOwner.fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0) {
+ for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
+ Reference<A>* ref = *it;
+ if ( ref->getKind() == A::kFollowOn )
+ return true;
+ }
+ }
+ return false;
+}
+
+template <typename A>
+ObjectFile::Atom& SymbolAtom<A>::getFollowOnAtom() const
+{
+ for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
+ Reference<A>* ref = *it;
+ if ( ref->getKind() == A::kFollowOn )
+ return ref->getTarget();
+ }
+ return *((ObjectFile::Atom*)NULL);
+}
+
+
+
+
+template <typename A>
+void SymbolAtom<A>::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);
+ }
+}
+
+
+template <typename A>
+class SymbolAtomSorter
+{
+public:
+ SymbolAtomSorter(std::map<uint32_t, BaseAtom*>& map) : fMap(map) {}
+
+ typedef typename A::P::uint_t pint_t;
+
+ bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
+ {
+ pint_t leftAddr = ((SymbolAtom<A>*)left)->fAddress;
+ pint_t rightAddr = ((SymbolAtom<A>*)right)->fAddress;
+ if ( leftAddr == rightAddr ) {
+ // two atoms with same address, must have been a function with multiple labels
+ // make sure we sort these so the one with real content (in map) is last
+ std::map<uint32_t, BaseAtom*>::iterator pos = fMap.find(leftAddr);
+ if ( pos != fMap.end() ) {
+ return ( pos->second == right );
+ }
+ return false;
+ }
+ else {
+ return ( leftAddr < rightAddr );
+ }
+ }
+private:
+ std::map<uint32_t, BaseAtom*>& fMap;
+};
+
+
+//
+// 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 <typename A>
+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 SymbolTableInclusion getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0)
+ ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; }
+ virtual uint64_t getSize() const { return fSymbol->n_value(); }
+ virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
+ virtual bool mustRemainInSection() const { return true; }
+ virtual const char* getSectionName() const { return "__common"; }
+ virtual ObjectFile::Segment& getSegment() const { return DataSegment::fgSingleton; }
+ virtual bool requiresFollowOnAtom() const { return false; }
+ virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
+ virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
+ virtual uint8_t 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 "can't add references"; }
+ virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "can't add line info to tentative definition"; }
+ virtual void alignAtLeast(uint8_t align) { }
+
+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<A>;
+
+ TentativeAtom(Reader<A>&, const macho_nlist<P>*);
+ virtual ~TentativeAtom() {}
+
+ Reader<A>& fOwner;
+ const macho_nlist<P>* fSymbol;
+ ObjectFile::Atom::Scope fScope;
+ static std::vector<ObjectFile::Reference*> fgNoReferences;
+};
+
+template <typename A>
+std::vector<ObjectFile::Reference*> TentativeAtom<A>::fgNoReferences;
+
+template <typename A>
+TentativeAtom<A>::TentativeAtom(Reader<A>& owner, const macho_nlist<P>* 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 {
+ printf("unknown symbol type: %d\n", type);
+ }
+ //fprintf(stderr, "TentativeAtom(%p) %s\n", this, this->getDisplayName());
+}
+
+
+template <typename A>
+uint8_t TentativeAtom<A>::getAlignment() const
+{
+ // common symbols align to their size
+ // that is, a 4-byte common aligns to 4-bytes
+ // to be safe, odd size commons align to the next power-of-2 size
+ uint8_t alignment = (uint8_t)ceil(log2(this->getSize()));
+ // limit alignment of extremely large commons to 2^15 bytes (8-page)
+ if ( alignment < 15 )
+ return alignment;
+ else
+ return 15;
+}
+
+template <typename A>
+void TentativeAtom<A>::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 <typename A>
+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;
+ virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
+ virtual bool isZeroFill() const;
+ virtual uint64_t getSize() const { return fSize; }
+ virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
+ virtual bool mustRemainInSection() const { return true; }
+ virtual const char* getSectionName() const;
+ virtual Segment<A>& getSegment() const { return *fSegment; }
+ virtual bool requiresFollowOnAtom() const;
+ virtual ObjectFile::Atom& getFollowOnAtom() const;
+ virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
+ virtual uint8_t getAlignment() const;
+ virtual void copyRawContent(uint8_t buffer[]) const;
+ virtual void setScope(ObjectFile::Atom::Scope newScope) { }
+ virtual void setSize(uint64_t size) { fSize = size; }
+ virtual void addReference(ObjectFile::Reference* ref) { fReferences.insert(fReferences.begin(), (Reference<A>*)ref); }
+ virtual void addLineInfo(const ObjectFile::LineInfo& info) { fprintf(stderr, "can't add line info to anonymous symbol %s\n", this->getDisplayName()); }
+ virtual void alignAtLeast(uint8_t align) { }
+ BaseAtom* redirectTo() { return fRedirect; }
+ bool isWeakImportStub() { return fWeakImportStub; }
+
+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<Reference<A>*> 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<A>;
+
+ AnonymousAtom(Reader<A>&, const macho_section<P>*, uint32_t addr, uint32_t size);
+ virtual ~AnonymousAtom() {}
+
+ Reader<A>& fOwner;
+ const char* fSynthesizedName;
+ const macho_section<P>* fSection;
+ uint32_t fAddress;
+ uint32_t fSize;
+ Segment<A>* fSegment;
+ ReferenceVector fReferences;
+ BaseAtom* fRedirect;
+ bool fWeakImportStub;
+ bool fReallyNonLazyPointer; // HACK until compiler stops emitting anonymous non-lazy pointers
+};
+
+template <typename A>
+AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* section, uint32_t addr, uint32_t size)
+ : fOwner(owner), fSynthesizedName(NULL), fSection(section), fAddress(addr), fSize(size), fSegment(NULL),
+ fWeakImportStub(false), fReallyNonLazyPointer(false)
+{
+ fSegment = new Segment<A>(fSection);
+ fRedirect = this;
+ uint8_t type = fSection->flags() & SECTION_TYPE;
+ switch ( type ) {
+ case S_ZEROFILL:
+ {
+ asprintf((char**)&fSynthesizedName, "zero-fill-at-0x%08X", addr);
+ }
+ break;
+ case S_REGULAR:
+ // handle .o files created by old ld64 -r that are missing cstring section type
+ if ( strcmp(fSection->sectname(), "__cstring") != 0 )
+ break;
+ // else fall into cstring case
+ case S_CSTRING_LITERALS:
+ {
+ const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
+ asprintf((char**)&fSynthesizedName, "cstring=%s", str);
+ }
+ 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);
+ }
+ 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);
+ }
+ break;
+ case S_LITERAL_POINTERS:
+ {
+ // FIX FIX, we need the name to include the name of the target so that we can coalesce them
+ asprintf((char**)&fSynthesizedName, "literal-pointer@%d", addr - (uint32_t)fSection->addr());
+ }
+ 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<P>* 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_desc() & N_WEAK_DEF) == 0) ) {
+ BaseAtom* staticAtom = fOwner.findAtomByName(fSynthesizedName);
+ if ( staticAtom != NULL )
+ fRedirect = staticAtom;
+ }
+ }
+ break;
+ case S_LAZY_SYMBOL_POINTERS:
+ case S_NON_LAZY_SYMBOL_POINTERS:
+ {
+ 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
+ // All atoms not created yet, so we need to scan symbol table
+ uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
+ pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fOwner.fHeader)+fileOffset)));
+ const macho_nlist<P>* end = &fOwner.fSymbols[fOwner.fSymbolCount];
+ for (const macho_nlist<P>* sym = fOwner.fSymbols; sym < end; ++sym) {
+ if ( ((sym->n_type() & N_TYPE) == N_SECT) && (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);
+ return;
+ }
+ }
+ throwf("malformed .o file: non-lazy-pointer with value 0x%08X missing symbol", nonLazyPtrValue);
+ }
+ const macho_nlist<P>* 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;
+
+ if ( fOwner.isWeakImportSymbol(targetSymbol) )
+ new Reference<A>(A::kPointerWeakImport, AtomAndOffset(this), name, 0);
+ else
+ new Reference<A>(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());
+}
+
+
+template <typename A>
+const char* AnonymousAtom<A>::getDisplayName() const
+{
+ if ( fSynthesizedName != NULL )
+ return fSynthesizedName;
+
+ static char temp[512];
+ if ( (fSection->flags() & SECTION_TYPE) == S_CSTRING_LITERALS ) {
+ uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
+ sprintf(temp, "atom string literal: \"%s\"", (char*)(fOwner.fHeader)+fileOffset);
+ }
+ else {
+ sprintf(temp, "%s@%d", fSection->sectname(), fAddress - (uint32_t)fSection->addr() );
+ }
+ return temp;
+}
+
+template <typename A>
+ObjectFile::Atom::Scope AnonymousAtom<A>::getScope() const
+{
+ if ( fReallyNonLazyPointer )
+ return ObjectFile::Atom::scopeLinkageUnit;
+ // in order for literals to be coalesced they must be scoped to linkage unit
+ switch ( fSection->flags() & SECTION_TYPE ) {
+ case S_CSTRING_LITERALS:
+ case S_4BYTE_LITERALS:
+ case S_8BYTE_LITERALS:
+ case S_SYMBOL_STUBS:
+ case S_NON_LAZY_SYMBOL_POINTERS:
+ return ObjectFile::Atom::scopeLinkageUnit;
+ default:
+ return ObjectFile::Atom::scopeTranslationUnit;
+ }
+}
+
+template <typename A>
+ObjectFile::Atom::DefinitionKind AnonymousAtom<A>::getDefinitionKind() const
+{
+ if ( fReallyNonLazyPointer )
+ return ObjectFile::Atom::kWeakDefinition;
+ // in order for literals to be coalesced they must be weak
+ switch ( fSection->flags() & SECTION_TYPE ) {
+ case S_CSTRING_LITERALS:
+ case S_4BYTE_LITERALS:
+ case S_8BYTE_LITERALS:
+ case S_NON_LAZY_SYMBOL_POINTERS:
+ return ObjectFile::Atom::kWeakDefinition;
+ default:
+ return ObjectFile::Atom::kRegularDefinition;
+ }
+}
+
+template <typename A>
+bool AnonymousAtom<A>::isZeroFill() const
+{
+ return ( (fSection->flags() & SECTION_TYPE) == S_ZEROFILL );
+}
+
+
+template <typename A>
+const char* AnonymousAtom<A>::getSectionName() const
+{
+ if ( fReallyNonLazyPointer )
+ return "__nl_symbol_ptr";
+ if ( strlen(fSection->sectname()) > 15 ) {
+ static char temp[18];
+ strncpy(temp, fSection->sectname(), 16);
+ temp[17] = '\0';
+ return temp;
+ }
+ return fSection->sectname();
+}
+
+template <typename A>
+uint8_t AnonymousAtom<A>::getAlignment() const
+{
+ if ( fReallyNonLazyPointer )
+ return (uint8_t)log2(sizeof(pint_t));
+ switch ( fSection->flags() & SECTION_TYPE ) {
+ case S_4BYTE_LITERALS:
+ return 2;
+ case S_8BYTE_LITERALS:
+ return 3;
+ case S_NON_LAZY_SYMBOL_POINTERS:
+ return (uint8_t)log2(sizeof(pint_t));
+ default:
+ return fSection->align();
+ }
+}
+
+template <typename A>
+bool AnonymousAtom<A>::requiresFollowOnAtom() const
+{
+ // requires follow-on if built with old compiler and not the last atom
+ if ( (fOwner.fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0) {
+ for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
+ Reference<A>* ref = *it;
+ if ( ref->getKind() == A::kFollowOn )
+ return true;
+ }
+ }
+ return false;
+}
+
+template <typename A>
+ObjectFile::Atom& AnonymousAtom<A>::getFollowOnAtom() const
+{
+ for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
+ Reference<A>* ref = *it;
+ if ( ref->getKind() == A::kFollowOn )
+ return ref->getTarget();
+ }
+ return *((ObjectFile::Atom*)NULL);
+}
+
+template <typename A>
+void AnonymousAtom<A>::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);
+ }
+}
+
+
+
+
+template <typename A>
+class Reader : public ObjectFile::Reader
+{
+public:
+ static bool validFile(const uint8_t* fileContent);
+ static Reader<A>* make(const uint8_t* fileContent, const char* path, time_t modTime,
+ const ObjectFile::ReaderOptions& options)
+ { return new Reader<A>(fileContent, path, modTime, options); }
+ virtual ~Reader() {}
+
+ virtual const char* getPath() { return fPath; }
+ virtual time_t getModificationTime() { return fModTime; }
+ virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return fDebugInfo; }
+ virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return (std::vector<class ObjectFile::Atom*>&)(fAtoms); }
+ virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
+ virtual std::vector<Stab>* getStabs() { return &fStabs; }
+
+ 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<Atom<A>*> AtomVector;
+ //typedef typename AtomVector::iterator AtomVectorIterator; // seems to help C++ parser
+ typedef typename A::ReferenceKinds Kinds;
+ friend class AnonymousAtom<A>;
+ friend class TentativeAtom<A>;
+ friend class SymbolAtom<A>;
+ Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options);
+ bool addRelocReference(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
+ bool addRelocReference_powerpc(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
+ Kinds pointerDiffKindForLength_powerpc(uint8_t r_length);
+ bool read_comp_unit(const char ** name, const char ** comp_dir, uint64_t *stmt_list);
+ static bool isWeakImportSymbol(const macho_nlist<P>* 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(uint32_t addr);
+ AtomAndOffset findAtomAndOffset(uint32_t baseAddr, uint32_t realAddr);
+ Reference<A>* makeReference(Kinds kind, uint32_t atAddr, uint32_t toAddr);
+ Reference<A>* makeReference(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr);
+ Reference<A>* makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t toAddr, uint32_t toBaseAddr);
+ Reference<A>* makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr, uint32_t toBaseAddr);
+ Reference<A>* makeByNameReference(Kinds kind, uint32_t atAddr, const char* toName, uint32_t toOffset);
+ Reference<A>* makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect);
+ void validSectionType(uint8_t type);
+
+ BaseAtom* findAtomByName(const char*);
+
+ const char* fPath;
+ time_t fModTime;
+ const ObjectFile::ReaderOptions& fOptions;
+ const macho_header<P>* fHeader;
+ const char* fStrings;
+ const macho_nlist<P>* fSymbols;
+ uint32_t fSymbolCount;
+ const macho_segment_command<P>* fSegment;
+ const uint32_t* fIndirectTable;
+ std::vector<ObjectFile::Atom*> fAtoms;
+ std::map<uint32_t, BaseAtom*> fAddrToAtom;
+ std::vector<class AnonymousAtom<A>*> fLocalNonLazys;
+ ObjectFile::Reader::DebugInfoKind fDebugInfo;
+ const macho_section<P>* fDwarfDebugInfoSect;
+ const macho_section<P>* fDwarfDebugAbbrevSect;
+ const macho_section<P>* fDwarfDebugLineSect;
+ const char* fDwarfTranslationUnitDir;
+ const char* fDwarfTranslationUnitFile;
+ std::map<uint32_t,const char*> fDwarfIndexToFile;
+ std::vector<Stab> fStabs;
+};
+
+
+template <typename A>
+Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options)
+ : fPath(strdup(path)), fModTime(modTime), fOptions(options), fHeader((const macho_header<P>*)fileContent),
+ fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL),
+ fDebugInfo(kDebugInfoNone), fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL),
+ fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL)
+{
+ // sanity check
+ if ( ! validFile(fileContent) )
+ throw "not a valid mach-o object file";
+
+ // cache intersting pointers
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ const uint32_t cmd_count = header->ncmds();
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch (cmd->cmd()) {
+ case LC_SYMTAB:
+ {
+ const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
+ fSymbolCount = symtab->nsyms();
+ fSymbols = (const macho_nlist<P>*)((char*)header + symtab->symoff());
+ fStrings = (char*)header + symtab->stroff();
+ }
+ break;
+ case LC_DYSYMTAB:
+ {
+ const macho_dysymtab_command<P>* dsymtab = (struct macho_dysymtab_command<P>*)cmd;
+ fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
+ }
+ break;
+ case LC_UUID:
+ if (getDebugInfoKind() != kDebugInfoDwarf)
+ fDebugInfo = kDebugInfoStabsUUID;
+ break;
+
+ default:
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ fSegment = (macho_segment_command<P>*)cmd;
+ }
+ break;
+ }
+ cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+ }
+ const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
+ const macho_section<P>* 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<P>* sections = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
+ for (uint32_t i=0; i < fSymbolCount; ++i) {
+ const macho_nlist<P>& 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<P>* section = §ions[sym.n_sect()-1];
+ bool suppress = false;
+ // ignore atoms in debugger sections
+ if ( (section->flags() & S_ATTR_DEBUG) == 0 ) {
+ // 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_CSTRING_LITERALS:
+ {
+ BaseAtom* newAtom = new SymbolAtom<A>(*this, &sym, section);
+ std::map<uint32_t, BaseAtom*>::iterator pos = fAddrToAtom.find(sym.n_value());
+ if ( pos != fAddrToAtom.end() ) {
+ // another label to an existing address
+ // make this one be the real one and followed by the previous
+ BaseAtom* existingAtom = pos->second;
+ //fprintf(stderr, "new atom %s has same address as existing atom %s\n", newAtom->getDisplayName(), existingAtom->getDisplayName());
+ new Reference<A>(A::kFollowOn, AtomAndOffset(newAtom), AtomAndOffset(existingAtom));
+ newAtom->setSize(0);
+ }
+ else {
+ fAddrToAtom[sym.n_value()] = 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:
+ fprintf(stderr, "ld64 warning: symbol %s found in unsupported section in %s\n",
+ &fStrings[sym.n_strx()], this->getPath());
+ }
+ }
+ }
+ else if ( (type == N_UNDF) && (sym.n_value() != 0) ) {
+ fAtoms.push_back(new TentativeAtom<A>(*this, &sym));
+ }
+ }
+ }
+
+ // sort SymbolAtoms by address
+ std::sort(fAtoms.begin(), fAtoms.end(), SymbolAtomSorter<A>(fAddrToAtom));
+
+ // add all fixed size anonymous atoms from special sections
+ for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+ uint32_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;
+ }
+ if ( atomSize != 0 ) {
+ for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += atomSize) {
+ uint32_t atomAddr = sect->addr() + sectOffset;
+ // add if not already an atom at that address
+ if ( fAddrToAtom.find(atomAddr) == fAddrToAtom.end() ) {
+ AnonymousAtom<A>* newAtom = new AnonymousAtom<A>(*this, sect, atomAddr, atomSize);
+ if ( !suppress )
+ fAtoms.push_back(newAtom);
+ fAddrToAtom[atomAddr] = newAtom->redirectTo();
+ }
+ }
+ }
+ }
+
+ // add all c-string anonymous atoms
+ for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+ if ( ((sect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS) || strcmp(sect->sectname(), "__cstring") == 0 ) {
+ uint32_t stringLen;
+ uint32_t stringAddr;
+ BaseAtom* firstEmptyString = NULL;
+ for(uint32_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<A>(*this, sect, stringAddr, stringLen);
+ if ( stringLen == 1 ) {
+ // because of padding it may look like there are lots of empty strings
+ // map them all to the first empty string
+ if ( firstEmptyString == NULL ) {
+ firstEmptyString = newAtom;
+ fAtoms.push_back(firstEmptyString);
+ }
+ fAddrToAtom[stringAddr] = firstEmptyString;
+ }
+ else {
+ fAtoms.push_back(newAtom);
+ fAddrToAtom[stringAddr] = newAtom;
+ }
+ }
+ }
+ }
+ }
+
+ // create atoms to cover any non-debug ranges not handled above
+ for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+ pint_t sectionStartAddr = sect->addr();
+ pint_t sectionEndAddr = sect->addr() + sect->size();
+ const bool setFollowOnAtom = ((fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0);
+ 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:
+ // detect if compiler has generated anonymous non-lazy pointers at end of __data section
+ // HACK BEGIN - until compiler stops generated anonymous non-lazy pointers
+ if ( (sect->size() >= sizeof(pint_t))
+ && ((sect->size() % sizeof(pint_t)) == 0)
+ && (sect->align() >= log2(sizeof(pint_t)))
+ && (strcmp(sect->sectname(), "__data") == 0)
+ && (strcmp(sect->segname(), "__DATA") == 0) ) {
+ // find every pointer sized external reloc from end of section and split off into own atom
+ uint32_t possiblePointerAddress = sect->size() - sizeof(pint_t);
+ const uint8_t* sectionContent = ((uint8_t*)(fHeader))+sect->offset();
+ const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + sect->reloff());
+ const macho_relocation_info<P>* relocsEnd = &relocs[sect->nreloc()];
+ for (const macho_relocation_info<P>* r = relocs; r < relocsEnd; ++r) {
+ if ( ((r->r_address() & R_SCATTERED) == 0)
+ && r->r_extern()
+ && (r->r_address() == possiblePointerAddress)
+ && (fAddrToAtom.find(possiblePointerAddress+sect->addr()) == fAddrToAtom.end())
+ && (P::getP(*((pint_t*)(sectionContent+possiblePointerAddress))) == 0) ) {
+ // create an anonymous atom to cover this non-lazy pointer
+ AnonymousAtom<A>* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr()+possiblePointerAddress, sizeof(pint_t));
+ const macho_nlist<P>* targetSymbol = &fSymbols[r->r_symbolnum()];
+ char* name;
+ asprintf(&name, "%s$non_lazy_ptr", &fStrings[targetSymbol->n_strx()]);
+ newAtom->fSynthesizedName = name;
+ newAtom->fReallyNonLazyPointer = true;
+ fAtoms.push_back(newAtom);
+ fAddrToAtom[sect->addr()+possiblePointerAddress] = newAtom;
+ possiblePointerAddress -= sizeof(pint_t);
+ sectionEndAddr -= sizeof(pint_t);
+ }
+ else {
+ break;
+ }
+ }
+ }
+ // HACK END - until compiler stops generated anonymous non-lazy pointers
+ uint32_t previousAtomAddr = 0;
+ BaseAtom* previousAtom = NULL;
+ if ( fAddrToAtom.find(sectionStartAddr) == fAddrToAtom.end() ) {
+ // if there is not an atom already at the start of this section, add an anonymous one
+ BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr(), 0);
+ fAtoms.push_back(newAtom);
+ fAddrToAtom[sect->addr()] = newAtom;
+ previousAtomAddr = sectionStartAddr;
+ previousAtom = newAtom;
+ }
+ // calculate size of all atoms in this section and add follow-on references
+ for (std::map<uint32_t, BaseAtom*>::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
+ // note: this algorithm depends on the map iterator returning entries in address order
+ if ( (it->first >= sectionStartAddr) && (it->first < sectionEndAddr) ) {
+ //fprintf(stderr, " atom %s in section\n", it->second->getDisplayName());
+ if ( previousAtom != NULL ) {
+ previousAtom->setSize(it->first - previousAtomAddr);
+ // FIX FIX: this setting of followOn atoms does not work when there are multiple
+ // labels for the same atom
+ if ( setFollowOnAtom && (it->second != previousAtom) )
+ makeReference(A::kFollowOn, previousAtomAddr, it->first);
+ }
+ previousAtomAddr = it->first;
+ previousAtom = it->second;
+ }
+ }
+ if ( previousAtom != NULL ) {
+ // set last atom in section
+ previousAtom->setSize(sectionEndAddr - previousAtomAddr);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // add relocation based references
+ for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+ // ignore dwarf sections. If ld every 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<P>* relocs = (macho_relocation_info<P>*)((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\n", sect->segname(), sect->sectname(), r, msg);
+ }
+ }
+ }
+ }
+ }
+
+ // add direct references to local non-lazy-pointers, can do this now that all atoms are constructed
+ for (typename std::vector<AnonymousAtom<A>*>::iterator it=fLocalNonLazys.begin(); it != fLocalNonLazys.end(); it++) {
+ AnonymousAtom<A>* 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<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+ if ( ((sect->flags() & SECTION_TYPE) == S_COALESCED) && (strcmp(sect->sectname(), "__eh_frame") == 0) ) {
+ for (std::map<uint32_t, BaseAtom*>::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()) ) {
+ uint32_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);
+ }
+ }
+ }
+ }
+
+
+ //for (std::map<uint32_t, BaseAtom*>::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) ) {
+ if ( !read_comp_unit(&fDwarfTranslationUnitFile, &fDwarfTranslationUnitDir, &stmtList) ) {
+ // if can't parse dwarf, warn and give up
+ fDwarfTranslationUnitFile = NULL;
+ fDwarfTranslationUnitDir = NULL;
+ fprintf(stderr, "ld64: warning can't parse dwarf compilation unit info in %s\n", 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) ) {
+ // 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_line) ) {
+ // for performance, see if in next pc is in current atom
+ if ( (curAtom != NULL) && (result.pc <= curAtomAddress+curAtomSize) && (curAtomAddress <= result.pc) ) {
+ 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
+ curAtomOffset = ao.offset;
+ curAtomAddress = result.pc;
+ curAtomSize = curAtom->getSize();
+ }
+ const char* filename;
+ std::map<uint32_t,const char*>::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\n", result.pc, result.line, filename);
+ ((BaseAtom*)curAtom)->addLineInfo(info);
+ }
+ line_free(lines);
+ }
+ else {
+ fprintf(stderr, "ld64: warning could not parse dwarf line number info in %s\n", 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<P>* sym = &fSymbols[symbolIndex];
+ uint8_t type = sym->n_type();
+ const char* symString = (sym->n_strx() != 0) ? &fStrings[sym->n_strx()] : NULL;
+ if ( (type & N_STAB) != 0 ) {
+ fDebugInfo = 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\n",
+ (uint64_t)sym->n_value(), path);
+ }
+ break;
+ case N_SO:
+ case N_OSO:
+ case N_OPT:
+ case N_LSYM:
+ // 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;
+ }
+ }
+ if ( stab.atom == NULL ) {
+ fprintf(stderr, "can't find atom for N_GSYM stabs %s in %s\n", symString, path);
+ }
+ 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 {
+ fprintf(stderr, "can't find atom for stabs FUN at %08llX in %s\n",
+ (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:
+ fprintf(stderr, "unknown stabs type 0x%X in %s\n", 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 {
+ fprintf(stderr, "can't find atom for stabs 0x%X at %08llX in %s\n",
+ 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 {
+ fprintf(stderr, "can't find atom for stabs FUN at %08llX in %s\n",
+ (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
+ 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<A>(*this, (uint32_t)0);
+ //phony->fSynthesizedName = ".gch.o";
+ fAtoms.push_back(phony);
+ }
+ }
+#endif
+}
+
+
+template <typename A>
+void Reader<A>::validSectionType(uint8_t type)
+{
+}
+
+template <typename A>
+bool Reader<A>::getTranslationUnitSource(const char** dir, const char** name) const
+{
+ if ( fDebugInfo == kDebugInfoDwarf ) {
+ *dir = fDwarfTranslationUnitDir;
+ *name = fDwarfTranslationUnitFile;
+ return true;
+ }
+ return false;
+}
+
+template <typename A>
+BaseAtom* Reader<A>::findAtomByName(const char* name)
+{
+ // first search the more important atoms
+ for (std::map<uint32_t, BaseAtom*>::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<ObjectFile::Atom*>::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 <typename A>
+Reference<A>* Reader<A>::makeReference(Kinds kind, uint32_t atAddr, uint32_t toAddr)
+{
+ return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toAddr));
+}
+
+template <typename A>
+Reference<A>* Reader<A>::makeReference(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr)
+{
+ return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toAddr));
+}
+
+template <typename A>
+Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t toAddr, uint32_t toBaseAddr)
+{
+ return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toBaseAddr, toAddr));
+}
+
+template <typename A>
+Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr, uint32_t toBaseAddr)
+{
+ return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toBaseAddr, toAddr));
+}
+
+template <typename A>
+Reference<A>* Reader<A>::makeByNameReference(Kinds kind, uint32_t atAddr, const char* toName, uint32_t toOffset)
+{
+ return new Reference<A>(kind, findAtomAndOffset(atAddr), toName, toOffset);
+}
+
+template <typename A>
+Reference<A>* Reader<A>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* 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
+ uint32_t funcAddr = ehAtomAddress + deltaMinus8 + 8;
+ return makeReference(A::kNoFixUp, funcAddr, ehAtomAddress) ;
+}
+
+
+
+template <typename A>
+AtomAndOffset Reader<A>::findAtomAndOffset(uint32_t addr)
+{
+ // STL has no built-in for "find largest key that is same or less than"
+ std::map<uint32_t, BaseAtom*>::iterator it = fAddrToAtom.upper_bound(addr);
+ --it; // upper_bound gets us next key, so we back up one
+ AtomAndOffset result;
+ result.atom = it->second;
+ result.offset = addr - it->first;
+ //fprintf(stderr, "findAtomAndOffset(0x%0X) ==> %s (0x%0X -> 0x%0llX)\n",
+ // addr, result.atom->getDisplayName(), 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 <typename A>
+AtomAndOffset Reader<A>::findAtomAndOffset(uint32_t baseAddr, uint32_t realAddr)
+{
+ std::map<uint32_t, BaseAtom*>::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 <typename A>
+bool Reader<A>::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 <typename A>
+bool Reader<A>::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 <typename A>
+const char* Reader<A>::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<xxx>::validFile()
+// Reader<xxx>::addRelocReference()
+// Reference<xxx>::getDescription()
+//
+//
+
+
+template <>
+bool Reader<ppc>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_POWERPC )
+ return false;
+ if ( header->filetype() != MH_OBJECT )
+ return false;
+ return true;
+}
+
+template <>
+bool Reader<ppc64>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_POWERPC64 )
+ return false;
+ if ( header->filetype() != MH_OBJECT )
+ return false;
+ return true;
+}
+
+template <>
+bool Reader<x86>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_I386 )
+ return false;
+ if ( header->filetype() != MH_OBJECT )
+ return false;
+ return true;
+}
+
+
+
+template <typename A>
+bool Reader<A>::isWeakImportSymbol(const macho_nlist<P>* sym)
+{
+ return ( ((sym->n_type() & N_TYPE) == N_UNDF) && ((sym->n_desc() & N_WEAK_REF) != 0) );
+}
+
+template <>
+bool Reader<ppc64>::addRelocReference(const macho_section<ppc64::P>* sect, const macho_relocation_info<ppc64::P>* reloc)
+{
+ return addRelocReference_powerpc(sect, reloc);
+}
+
+template <>
+bool Reader<ppc>::addRelocReference(const macho_section<ppc::P>* sect, const macho_relocation_info<ppc::P>* reloc)
+{
+ return addRelocReference_powerpc(sect, reloc);
+}
+
+
+//
+// ppc and ppc64 both use the same relocations, so process them in one common routine
+//
+template <typename A>
+bool Reader<A>::addRelocReference_powerpc(const macho_section<typename A::P>* sect,
+ const macho_relocation_info<typename A::P>* 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<P>* 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<P>* 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 ( 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;
+ if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
+ && ((AnonymousAtom<A>*)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 ) {
+ printf("PPC_RELOC_LO16 missing following pair\n");
+ 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);
+ makeReference(A::kAbsLow16, srcAddr, dstAddr);
+ }
+ }
+ break;
+ case PPC_RELOC_LO14:
+ {
+ if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+ printf("PPC_RELOC_LO14 missing following pair\n");
+ 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);
+ Reference<A>* ref = makeReference(A::kAbsLow14, srcAddr, dstAddr);
+ BaseAtom* target = ((BaseAtom*)&(ref->getTarget()));
+ if ( target != NULL )
+ target->alignAtLeast(2);
+ }
+ }
+ break;
+ case PPC_RELOC_HI16:
+ {
+ if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+ printf("PPC_RELOC_HI16 missing following pair\n");
+ 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);
+ makeReference(A::kAbsHigh16, srcAddr, dstAddr);
+ }
+ }
+ break;
+ case PPC_RELOC_HA16:
+ {
+ if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+ printf("PPC_RELOC_HA16 missing following pair\n");
+ 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;
+ 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
+ if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+ printf("PPC_RELOC_JBSR missing following pair\n");
+ break;
+ }
+ result = true;
+ makeReference(A::kBranch24, srcAddr, nextReloc->r_address());
+ break;
+ default:
+ printf("unknown relocation type %d\n", reloc->r_type());
+ }
+ }
+ else {
+ const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)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<P>* nextSReloc = &sreloc[1];
+ const macho_relocation_info<P>* 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 ) {
+ printf("PPC_RELOC_LO16_SECTDIFF missing following PAIR\n");
+ 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 ) {
+ printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
+ break;
+ }
+ instruction = BigEndian::get32(*fixUpPtr);
+ lowBits = (instruction & 0xFFFC);
+ displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
+ Reference<A>* ref = makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
+ BaseAtom* target = ((BaseAtom*)&(ref->getTarget()));
+ if ( target != NULL ) // can be NULL if target is turned into by-name reference
+ target->alignAtLeast(2);
+ }
+ break;
+ case PPC_RELOC_HA16_SECTDIFF:
+ {
+ if ( ! nextRelocIsPair ) {
+ printf("PPC_RELOC_HA16_SECTDIFF missing following PAIR\n");
+ 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 ) {
+ printf("PPC_RELOC_LO14 missing following PAIR\n");
+ 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 ) {
+ printf("PPC_RELOC_LO16 missing following PAIR\n");
+ 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 ) {
+ printf("PPC_RELOC_HA16 missing following PAIR\n");
+ 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_SECTDIFF:
+ case PPC_RELOC_LOCAL_SECTDIFF:
+ {
+ if ( ! nextRelocIsPair ) {
+ printf("PPC_RELOC_SECTDIFF missing following pair\n");
+ break;
+ }
+ makeReference(pointerDiffKindForLength_powerpc(sreloc->r_length()), srcAddr, nextRelocValue, dstAddr);
+ }
+ break;
+ case PPC_RELOC_PAIR:
+ break;
+ case PPC_RELOC_HI16_SECTDIFF:
+ printf("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF\n");
+ break;
+ default:
+ printf("unknown scattered relocation type %d\n", sreloc->r_type());
+ }
+ }
+ return result;
+}
+
+template <>
+ppc::ReferenceKinds Reader<ppc>::pointerDiffKindForLength_powerpc(uint8_t r_length)
+{
+ if ( r_length == 2 )
+ return ppc::kPointerDiff32;
+ else
+ throw "bad diff relocations r_length for ppc architecture";
+ }
+
+template <>
+ppc64::ReferenceKinds Reader<ppc64>::pointerDiffKindForLength_powerpc(uint8_t r_length)
+{
+ if ( r_length == 2 )
+ return ppc64::kPointerDiff32;
+ else if ( r_length == 3 )
+ return ppc64::kPointerDiff64;
+ else
+ throw "bad diff relocations r_length for ppc64 architecture";
+ }
+
+template <>
+bool Reader<x86>::addRelocReference(const macho_section<x86::P>* sect, const macho_relocation_info<x86::P>* 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:
+ {
+ if ( reloc->r_length() != 2 )
+ throw "bad vanilla relocation length";
+ x86::ReferenceKinds kind;
+ uint32_t pointerValue = E::get32(*fixUpPtr);
+ if ( reloc->r_pcrel() ) {
+ kind = x86::kPCRel32;
+ pointerValue += srcAddr + sizeof(uint32_t);
+ }
+ else {
+ kind = x86::kPointer;
+ }
+ if ( reloc->r_extern() ) {
+ const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
+ if ( this->isWeakImportSymbol(targetSymbol) )
+ kind = x86::kPointerWeakImport;
+ const char* targetName = &fStrings[targetSymbol->n_strx()];
+ 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;
+ if ( reloc->r_pcrel() && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
+ && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
+ makeReference(x86::kPCRel32WeakImport, srcAddr, pointerValue);
+ else
+ makeReference(kind, srcAddr, pointerValue);
+ }
+ }
+ break;
+ default:
+ printf("unknown relocation type %d\n", reloc->r_type());
+ }
+ }
+ else {
+ const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)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<P>* nextSReloc = &sreloc[1];
+ const macho_relocation_info<P>* 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() == 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();
+ }
+ }
+ 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 {
+ makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr);
+ }
+ break;
+ case GENERIC_RELOC_SECTDIFF:
+ case GENERIC_RELOC_LOCAL_SECTDIFF:
+ {
+ if ( !nextRelocIsPair ) {
+ printf("GENERIC_RELOC_SECTDIFF missing following pair\n");
+ break;
+ }
+ if ( sreloc->r_length() != 2 )
+ throw "bad length for GENERIC_RELOC_SECTDIFF";
+ betterDstAddr = LittleEndian::get32(*fixUpPtr);
+ makeReferenceWithToBase(x86::kPointerDiff, srcAddr, nextRelocValue, betterDstAddr+nextRelocValue, dstAddr);
+ }
+ break;
+ case GENERIC_RELOC_PAIR:
+ // do nothing, already used via a look ahead
+ break;
+ default:
+ printf("unknown scattered relocation type %d\n", sreloc->r_type());
+ }
+ }
+ return result;
+}
+
+
+
+template <>
+const char* Reference<x86>::getDescription() const
+{
+ static char temp[1024];
+ switch( fKind ) {
+ case x86::kNoFixUp:
+ sprintf(temp, "reference to ");
+ break;
+ case x86::kFollowOn:
+ sprintf(temp, "followed by ");
+ 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::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;
+ }
+ // 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<ppc>::getDescription() const
+{
+ static char temp[1024];
+ switch( fKind ) {
+ case ppc::kNoFixUp:
+ sprintf(temp, "reference to ");
+ break;
+ case ppc::kFollowOn:
+ sprintf(temp, "followed by ");
+ 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::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 offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
+ break;
+ case ppc::kPICBaseLow14:
+ sprintf(temp, "offset 0x%04X, low 14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
+ break;
+ case ppc::kPICBaseHigh16:
+ sprintf(temp, "offset 0x%04X, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, 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 to absolute address of ", fFixUpOffsetInSrc);
+ break;
+ case ppc::kAbsHigh16AddLow:
+ sprintf(temp, "offset 0x%04X, high 16 fixup to absolute address of ", 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<ppc64>::getDescription() const
+{
+ static char temp[1024];
+ switch( fKind ) {
+ case ppc64::kNoFixUp:
+ sprintf(temp, "reference to ");
+ break;
+ case ppc64::kFollowOn:
+ sprintf(temp, "followed by ");
+ 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::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 to absolute address of ", fFixUpOffsetInSrc);
+ break;
+ case ppc64::kAbsHigh16AddLow:
+ sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", 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__
--- /dev/null
+/* -*- 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 __EXECUTABLE_MACH_O__
+#define __EXECUTABLE_MACH_O__
+
+#include <stdint.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/reloc.h>
+//#include <mach-o/ppc/reloc.h>
+#include <mach-o/stab.h>
+#include <uuid/uuid.h>
+#include <mach/i386/thread_status.h>
+#include <mach/ppc/thread_status.h>
+
+#include <vector>
+#include <algorithm>
+#include <map>
+#include <set>
+#include <ext/hash_map>
+
+#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<xxx>::setHeaderInfo()
+// ThreadsLoadCommandsAtom<xxx>::getSize()
+// ThreadsLoadCommandsAtom<xxx>::copyRawContent()
+// Writer<xxx>::addObjectRelocs()
+// Writer<xxx>::fixUpReferenceRelocatable()
+// Writer<xxx>::fixUpReferenceFinal()
+// Writer<xxx>::stubableReferenceKind()
+// Writer<xxx>::weakImportReferenceKind()
+// Writer<xxx>::GOTReferenceKind()
+//
+
+
+namespace mach_o {
+namespace executable {
+
+// forward references
+template <typename A> class WriterAtom;
+template <typename A> class PageZeroAtom;
+template <typename A> class CustomStackAtom;
+template <typename A> class MachHeaderAtom;
+template <typename A> class SegmentLoadCommandsAtom;
+template <typename A> class SymbolTableLoadCommandsAtom;
+template <typename A> class ThreadsLoadCommandsAtom;
+template <typename A> class DylibIDLoadCommandsAtom;
+template <typename A> class RoutinesLoadCommandsAtom;
+template <typename A> class DyldLoadCommandsAtom;
+template <typename A> class UUIDLoadCommandAtom;
+template <typename A> class LinkEditAtom;
+template <typename A> class SectionRelocationsLinkEditAtom;
+template <typename A> class LocalRelocationsLinkEditAtom;
+template <typename A> class ExternalRelocationsLinkEditAtom;
+template <typename A> class SymbolTableLinkEditAtom;
+template <typename A> class IndirectTableLinkEditAtom;
+template <typename A> class StringsLinkEditAtom;
+template <typename A> class LoadCommandsPaddingAtom;
+template <typename A> class StubAtom;
+template <typename A> class StubHelperAtom;
+template <typename A> class LazyPointerAtom;
+template <typename A> class NonLazyPointerAtom;
+
+
+// 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), fAllNonLazyPointers(false), fAllStubs(false),
+ fAllSelfModifyingStubs(false), fAllZeroFill(false), fVirtualSection(false)
+ { fSegmentName[0] = '\0'; fSectionName[0] = '\0'; }
+ void setIndex(unsigned int index) { fIndex=index; }
+ std::vector<ObjectFile::Atom*> 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 fAllNonLazyPointers;
+ bool fAllStubs;
+ bool fAllSelfModifyingStubs;
+ bool fAllZeroFill;
+ bool fVirtualSection;
+};
+
+// 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) { fName[0] = '\0'; }
+ std::vector<class SectionInfo*> fSections;
+ char fName[20];
+ uint32_t fInitProtection;
+ uint32_t fMaxProtection;
+ uint64_t fFileOffset;
+ uint64_t fFileSize;
+ uint64_t fBaseAddress;
+ uint64_t fSize;
+ bool fFixedAddress;
+};
+
+template <typename A>
+class Writer : public ExecutableFile::Writer
+{
+public:
+ Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& 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<class ObjectFile::Atom*>& getAtoms() { return fWriterSynthesizedAtoms; }
+ virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
+ virtual std::vector<Stab>* getStabs() { return NULL; }
+
+ virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name);
+ virtual uint64_t write(std::vector<class ObjectFile::Atom*>& atoms,
+ std::vector<class ObjectFile::Reader::Stab>& stabs,
+ class ObjectFile::Atom* entryPointAtom,
+ class ObjectFile::Atom* dyldHelperAtom,
+ bool createUUID);
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::uint_t pint_t;
+
+ enum RelocKind { kRelocNone, kRelocInternal, kRelocExternal };
+
+ void assignFileOffsets();
+ void synthesizeStubs();
+ void partitionIntoSections();
+ bool addBranchIslands();
+ bool addPPCBranchIslands();
+ uint8_t branch24Reference();
+ void adjustLoadCommandsAndPadding();
+ void createDynamicLinkerCommand();
+ void createDylibCommands();
+ void buildLinkEdit();
+ uint64_t writeAtoms();
+ void writeNoOps(uint32_t from, uint32_t to);
+ void collectExportedAndImportedAndLocalAtoms();
+ void setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
+ void buildSymbolTable();
+ void setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
+ void setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
+ void setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
+ 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 referenceRequiresRuntimeFixUp(const ObjectFile::Reference* ref, bool slideable) 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);
+ uint32_t addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
+ uint32_t addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
+ uint8_t getRelocPointerSize();
+ bool stubableReferenceKind(uint8_t kind);
+ bool GOTReferenceKind(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(uint8_t kind, bool slideable);
+
+
+ struct DirectLibrary {
+ class ObjectFile::Reader* fLibrary;
+ bool fWeak;
+ bool fReExport;
+ };
+
+ friend class WriterAtom<A>;
+ friend class PageZeroAtom<A>;
+ friend class CustomStackAtom<A>;
+ friend class MachHeaderAtom<A>;
+ friend class SegmentLoadCommandsAtom<A>;
+ friend class SymbolTableLoadCommandsAtom<A>;
+ friend class ThreadsLoadCommandsAtom<A>;
+ friend class DylibIDLoadCommandsAtom<A>;
+ friend class RoutinesLoadCommandsAtom<A>;
+ friend class DyldLoadCommandsAtom<A>;
+ friend class UUIDLoadCommandAtom<A>;
+ friend class LinkEditAtom<A>;
+ friend class SectionRelocationsLinkEditAtom<A>;
+ friend class LocalRelocationsLinkEditAtom<A>;
+ friend class ExternalRelocationsLinkEditAtom<A>;
+ friend class SymbolTableLinkEditAtom<A>;
+// friend class IndirectTableLinkEditAtom<A>;
+ friend class StringsLinkEditAtom<A>;
+ friend class LoadCommandsPaddingAtom<A>;
+ friend class StubAtom<A>;
+ friend class StubHelperAtom<A>;
+ friend class LazyPointerAtom<A>;
+ friend class NonLazyPointerAtom<A>;
+
+ const char* fFilePath;
+ Options& fOptions;
+ int fFileDescriptor;
+ std::vector<class ObjectFile::Atom*>* fAllAtoms;
+ std::vector<class ObjectFile::Reader::Stab>* fStabs;
+ class SectionInfo* fLoadCommandsSection;
+ class SegmentInfo* fLoadCommandsSegment;
+ class SegmentLoadCommandsAtom<A>* fSegmentCommands;
+ class SymbolTableLoadCommandsAtom<A>* fSymbolTableCommands;
+ class LoadCommandsPaddingAtom<A>* fHeaderPadding;
+ class UUIDLoadCommandAtom<A>* fUUIDAtom;
+ std::vector<class ObjectFile::Atom*> fWriterSynthesizedAtoms;
+ std::vector<SegmentInfo*> fSegmentInfos;
+ class ObjectFile::Atom* fEntryPoint;
+ class ObjectFile::Atom* fDyldHelper;
+ std::vector<DirectLibrary> fDirectLibraries;
+ std::map<class ObjectFile::Reader*, uint32_t> fLibraryToOrdinal;
+ std::vector<class ObjectFile::Atom*> fExportedAtoms;
+ std::vector<class ObjectFile::Atom*> fImportedAtoms;
+ std::vector<class ObjectFile::Atom*> fLocalSymbolAtoms;
+ class SectionRelocationsLinkEditAtom<A>* fSectionRelocationsAtom;
+ class LocalRelocationsLinkEditAtom<A>* fLocalRelocationsAtom;
+ class ExternalRelocationsLinkEditAtom<A>* fExternalRelocationsAtom;
+ class SymbolTableLinkEditAtom<A>* fSymbolTableAtom;
+ class IndirectTableLinkEditAtom<A>* fIndirectTableAtom;
+ class StringsLinkEditAtom<A>* fStringsAtom;
+ macho_nlist<P>* fSymbolTable;
+ std::vector<macho_relocation_info<P> > fSectionRelocs;
+ std::vector<macho_relocation_info<P> > fInternalRelocs;
+ std::vector<macho_relocation_info<P> > fExternalRelocs;
+ std::map<ObjectFile::Atom*,ObjectFile::Atom*> fStubsMap;
+ std::map<ObjectFile::Atom*,ObjectFile::Atom*> fGOTMap;
+ std::vector<class StubAtom<A>*> fAllSynthesizedStubs;
+ std::vector<ObjectFile::Atom*> fAllSynthesizedStubHelpers;
+ std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyPointers;
+ std::vector<class NonLazyPointerAtom<A>*> 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 fSeenFollowOnReferences;
+ std::map<const ObjectFile::Atom*,bool> fWeakImportMap;
+};
+
+
+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 fgDataSegment;
+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::fgDataSegment("__DATA", true, true, false, false);
+
+
+template <typename A>
+class WriterAtom : public ObjectFile::Atom
+{
+public:
+ enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
+ WriterAtom(Writer<A>& writer, Segment& segment) : fWriter(writer), fSegment(segment) { setDontDeadStrip(); }
+
+ 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 isZeroFill() const { return false; }
+ virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
+ virtual bool mustRemainInSection() const { return true; }
+ virtual ObjectFile::Segment& getSegment() const { return fSegment; }
+ virtual bool requiresFollowOnAtom() const { return false; }
+ virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
+ virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
+ virtual uint8_t getAlignment() const { return 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<ObjectFile::Reference*> fgEmptyReferenceList;
+
+ Writer<A>& fWriter;
+ Segment& fSegment;
+};
+
+template <typename A> std::vector<ObjectFile::Reference*> WriterAtom<A>::fgEmptyReferenceList;
+
+
+template <typename A>
+class PageZeroAtom : public WriterAtom<A>
+{
+public:
+ PageZeroAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgPageZeroSegment) {}
+ virtual const char* getDisplayName() const { return "page zero content"; }
+ virtual bool isZeroFill() const { return true; }
+ virtual uint64_t getSize() const { return fWriter.fOptions.zeroPageSize(); }
+ virtual const char* getSectionName() const { return "._zeropage"; }
+ virtual uint8_t getAlignment() const { return 12; }
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+};
+
+template <typename A>
+class DsoHandleAtom : public WriterAtom<A>
+{
+public:
+ DsoHandleAtom(Writer<A>& writer) : WriterAtom<A>(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 uint8_t getAlignment() const { return 12; }
+ virtual const char* getSectionName() const { return "._mach_header"; }
+ virtual void copyRawContent(uint8_t buffer[]) const {}
+};
+
+
+template <typename A>
+class MachHeaderAtom : public WriterAtom<A>
+{
+public:
+ MachHeaderAtom(Writer<A>& writer) : WriterAtom<A>(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<typename A::P>); }
+ virtual uint8_t getAlignment() const { return 12; }
+ virtual const char* getSectionName() const { return "._mach_header"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+ void setHeaderInfo(macho_header<typename A::P>& header) const;
+};
+
+template <typename A>
+class CustomStackAtom : public WriterAtom<A>
+{
+public:
+ CustomStackAtom(Writer<A>& 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 uint8_t getAlignment() const { return 12; }
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+ static bool stackGrowsDown();
+};
+
+template <typename A>
+class LoadCommandAtom : public WriterAtom<A>
+{
+protected:
+ LoadCommandAtom(Writer<A>& writer, Segment& segment) : WriterAtom<A>(writer, segment) {}
+ static uint64_t alignedSize(uint64_t size);
+};
+
+
+template <typename A>
+class SegmentLoadCommandsAtom : public LoadCommandAtom<A>
+{
+public:
+ SegmentLoadCommandsAtom(Writer<A>& writer)
+ : LoadCommandAtom<A>(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 uint8_t getAlignment() const { return 2; }
+ virtual const char* getSectionName() const { return "._load_commands"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+
+ void computeSize();
+ void setup();
+ unsigned int commandCount() { return fCommandCount; }
+ void assignFileOffsets();
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+ unsigned int fCommandCount;
+ uint32_t fSize;
+};
+
+template <typename A>
+class SymbolTableLoadCommandsAtom : public LoadCommandAtom<A>
+{
+public:
+ SymbolTableLoadCommandsAtom(Writer<A>&);
+ virtual const char* getDisplayName() const { return "symbol table load commands"; }
+ virtual uint64_t getSize() const;
+ virtual uint8_t getAlignment() const { return 2; }
+ virtual const char* getSectionName() const { return "._load_commands"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+ unsigned int commandCount();
+
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+ macho_symtab_command<typename A::P> fSymbolTable;
+ macho_dysymtab_command<typename A::P> fDynamicSymbolTable;
+};
+
+template <typename A>
+class ThreadsLoadCommandsAtom : public LoadCommandAtom<A>
+{
+public:
+ ThreadsLoadCommandsAtom(Writer<A>& writer)
+ : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
+ virtual const char* getDisplayName() const { return "thread load commands"; }
+ virtual uint64_t getSize() const;
+ virtual uint8_t getAlignment() const { return 2; }
+ virtual const char* getSectionName() const { return "._load_commands"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+ uint8_t* fBuffer;
+ uint32_t fBufferSize;
+};
+
+template <typename A>
+class DyldLoadCommandsAtom : public LoadCommandAtom<A>
+{
+public:
+ DyldLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
+ virtual const char* getDisplayName() const { return "dyld load command"; }
+ virtual uint64_t getSize() const;
+ virtual uint8_t getAlignment() const { return 2; }
+ virtual const char* getSectionName() const { return "._load_commands"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+};
+
+template <typename A>
+class AllowableClientLoadCommandsAtom : public LoadCommandAtom<A>
+{
+public:
+ AllowableClientLoadCommandsAtom(Writer<A>& writer, const char* client) :
+ LoadCommandAtom<A>(writer, Segment::fgTextSegment), clientString(client) {}
+ virtual const char* getDisplayName() const { return "allowable_client load command"; }
+ virtual uint64_t getSize() const;
+ virtual uint8_t getAlignment() const { return 2; }
+ virtual const char* getSectionName() const { return "._load_commands"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+ const char* clientString;
+};
+
+template <typename A>
+class DylibLoadCommandsAtom : public LoadCommandAtom<A>
+{
+public:
+ DylibLoadCommandsAtom(Writer<A>& writer, ExecutableFile::DyLibUsed& info)
+ : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fInfo(info) {}
+ virtual const char* getDisplayName() const { return "dylib load command"; }
+ virtual uint64_t getSize() const;
+ virtual uint8_t getAlignment() const { return 2; }
+ virtual const char* getSectionName() const { return "._load_commands"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+ ExecutableFile::DyLibUsed& fInfo;
+};
+
+template <typename A>
+class DylibIDLoadCommandsAtom : public LoadCommandAtom<A>
+{
+public:
+ DylibIDLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
+ virtual const char* getDisplayName() const { return "dylib ID load command"; }
+ virtual uint64_t getSize() const;
+ virtual uint8_t getAlignment() const { return 2; }
+ virtual const char* getSectionName() const { return "._load_commands"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+};
+
+template <typename A>
+class RoutinesLoadCommandsAtom : public LoadCommandAtom<A>
+{
+public:
+ RoutinesLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
+ virtual const char* getDisplayName() const { return "routines load command"; }
+ virtual uint64_t getSize() const { return sizeof(macho_routines_command<typename A::P>); }
+ virtual uint8_t getAlignment() const { return 2; }
+ virtual const char* getSectionName() const { return "._load_commands"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+};
+
+template <typename A>
+class SubUmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
+{
+public:
+ SubUmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
+ : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fName(name) {}
+ virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
+ virtual uint64_t getSize() const;
+ virtual uint8_t getAlignment() const { return 2; }
+ virtual const char* getSectionName() const { return "._load_commands"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+private:
+ typedef typename A::P P;
+ const char* fName;
+};
+
+template <typename A>
+class SubLibraryLoadCommandsAtom : public LoadCommandAtom<A>
+{
+public:
+ SubLibraryLoadCommandsAtom(Writer<A>& writer, const char* nameStart, int nameLen)
+ : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fNameStart(nameStart), fNameLength(nameLen) {}
+ virtual const char* getDisplayName() const { return "sub-library load command"; }
+ virtual uint64_t getSize() const;
+ virtual uint8_t getAlignment() const { return 2; }
+ virtual const char* getSectionName() const { return "._load_commands"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+ const char* fNameStart;
+ int fNameLength;
+};
+
+template <typename A>
+class UmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
+{
+public:
+ UmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
+ : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fName(name) {}
+ virtual const char* getDisplayName() const { return "umbrella load command"; }
+ virtual uint64_t getSize() const;
+ virtual uint8_t getAlignment() const { return 2; }
+ virtual const char* getSectionName() const { return "._load_commands"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+ const char* fName;
+};
+
+template <typename A>
+class UUIDLoadCommandAtom : public LoadCommandAtom<A>
+{
+public:
+ UUIDLoadCommandAtom(Writer<A>& writer)
+ : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fEmit(false) { ::uuid_generate_random(fUUID);}
+ virtual const char* getDisplayName() const { return "uuid load command"; }
+ virtual uint64_t getSize() const { return fEmit ? sizeof(macho_uuid_command<typename A::P>) : 0; }
+ virtual uint8_t getAlignment() const { return 2; }
+ virtual const char* getSectionName() const { return "._load_commands"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+ virtual void emit() { fEmit = true; }
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+ uuid_t fUUID;
+ bool fEmit;
+};
+
+template <typename A>
+class LoadCommandsPaddingAtom : public WriterAtom<A>
+{
+public:
+ LoadCommandsPaddingAtom(Writer<A>& writer)
+ : WriterAtom<A>(writer, Segment::fgTextSegment), fSize(0) {}
+ virtual const char* getDisplayName() const { return "header padding"; }
+ virtual uint64_t getSize() const { return fSize; }
+ virtual uint8_t getAlignment() const { return 2; }
+ virtual const char* getSectionName() const { return "._load_cmds_pad"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+
+ void setSize(uint64_t newSize);
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+ uint64_t fSize;
+};
+
+template <typename A>
+class LinkEditAtom : public WriterAtom<A>
+{
+public:
+ LinkEditAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgLinkEditSegment) {}
+ uint64_t getFileOffset() const;
+private:
+ typedef typename A::P P;
+};
+
+template <typename A>
+class SectionRelocationsLinkEditAtom : public LinkEditAtom<A>
+{
+public:
+ SectionRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
+ virtual const char* getDisplayName() const { return "section relocations"; }
+ virtual uint64_t getSize() const;
+ virtual uint8_t getAlignment() const { return 3; }
+ virtual const char* getSectionName() const { return "._section_relocs"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+};
+
+template <typename A>
+class LocalRelocationsLinkEditAtom : public LinkEditAtom<A>
+{
+public:
+ LocalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
+ virtual const char* getDisplayName() const { return "local relocations"; }
+ virtual uint64_t getSize() const;
+ virtual uint8_t getAlignment() const { return 3; }
+ virtual const char* getSectionName() const { return "._local_relocs"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+};
+
+template <typename A>
+class SymbolTableLinkEditAtom : public LinkEditAtom<A>
+{
+public:
+ SymbolTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
+ virtual const char* getDisplayName() const { return "symbol table"; }
+ virtual uint64_t getSize() const;
+ virtual uint8_t getAlignment() const { return 2; }
+ virtual const char* getSectionName() const { return "._symbol_table"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+};
+
+template <typename A>
+class ExternalRelocationsLinkEditAtom : public LinkEditAtom<A>
+{
+public:
+ ExternalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
+ virtual const char* getDisplayName() const { return "external relocations"; }
+ virtual uint64_t getSize() const;
+ virtual uint8_t getAlignment() const { return 3; }
+ virtual const char* getSectionName() const { return "._extern_relocs"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+};
+
+struct IndirectEntry {
+ uint32_t indirectIndex;
+ uint32_t symbolIndex;
+};
+
+template <typename A>
+class IndirectTableLinkEditAtom : public LinkEditAtom<A>
+{
+public:
+ IndirectTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
+ virtual const char* getDisplayName() const { return "indirect symbol table"; }
+ virtual uint64_t getSize() const;
+ virtual uint8_t getAlignment() const { return 2; }
+ virtual const char* getSectionName() const { return "._indirect_syms"; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+
+ std::vector<IndirectEntry> fTable;
+
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+};
+
+class CStringEquals
+{
+public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+};
+
+template <typename A>
+class StringsLinkEditAtom : public LinkEditAtom<A>
+{
+public:
+ StringsLinkEditAtom(Writer<A>& writer);
+ virtual const char* getDisplayName() const { return "string pool"; }
+ virtual uint64_t getSize() const;
+ virtual uint8_t getAlignment() const { return 2; }
+ 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; }
+
+private:
+ using WriterAtom<A>::fWriter;
+ typedef typename A::P P;
+ enum { kBufferSize = 0x01000000 };
+ class CStringComparor {
+ public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) < 0); }
+ };
+ typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
+
+ std::vector<char*> fFullBuffers;
+ char* fCurrentBuffer;
+ uint32_t fCurrentBufferUsed;
+ StringToOffset fUniqueStrings;
+};
+
+
+
+template <typename A>
+class UndefinedSymbolProxyAtom : public WriterAtom<A>
+{
+public:
+ UndefinedSymbolProxyAtom(Writer<A>& writer, const char* name) : WriterAtom<A>(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<A>::fWriter;
+ typedef typename A::P P;
+ const char* fName;
+};
+
+template <typename A>
+class BranchIslandAtom : public WriterAtom<A>
+{
+public:
+ BranchIslandAtom(Writer<A>& 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<A>::fWriter;
+ const char* fName;
+ ObjectFile::Atom& fTarget;
+ uint32_t fTargetOffset;
+};
+
+template <typename A>
+class StubAtom : public WriterAtom<A>
+{
+public:
+ StubAtom(Writer<A>& writer, ObjectFile::Atom& target);
+ virtual const char* getName() const { return fName; }
+ virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
+ virtual uint8_t getAlignment() const { return 2; }
+ virtual uint64_t getSize() const;
+ virtual const char* getSectionName() const { return "__symbol_stub1"; }
+ virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+ ObjectFile::Atom* getTarget() { return &fTarget; }
+private:
+ static const char* stubName(const char* importName);
+ bool pic() const;
+ using WriterAtom<A>::fWriter;
+ const char* fName;
+ ObjectFile::Atom& fTarget;
+ std::vector<ObjectFile::Reference*> fReferences;
+};
+
+
+template <typename A>
+class LazyPointerAtom : public WriterAtom<A>
+{
+public:
+ LazyPointerAtom(Writer<A>& 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 "__la_symbol_ptr"; }
+ virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+ ObjectFile::Atom* getTarget() { return &fTarget; }
+private:
+ using WriterAtom<A>::fWriter;
+ static const char* lazyPointerName(const char* importName);
+ const char* fName;
+ ObjectFile::Atom& fTarget;
+ std::vector<ObjectFile::Reference*> fReferences;
+};
+
+
+template <typename A>
+class NonLazyPointerAtom : public WriterAtom<A>
+{
+public:
+ NonLazyPointerAtom(Writer<A>& 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<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+ ObjectFile::Atom* getTarget() { return &fTarget; }
+private:
+ using WriterAtom<A>::fWriter;
+ static const char* nonlazyPointerName(const char* importName);
+ const char* fName;
+ ObjectFile::Atom& fTarget;
+ std::vector<ObjectFile::Reference*> fReferences;
+};
+
+
+template <typename A>
+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 bool isTargetUnbound() const { return false; }
+ virtual bool isFromTargetUnbound() const { return false; }
+ 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 bool hasFromTarget() const { return (fFromTarget != NULL); }
+ 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 refrence"; }
+ 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;
+};
+
+
+
+struct ExportSorter
+{
+ bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
+ {
+ return (strcmp(left->getName(), right->getName()) < 0);
+ }
+};
+
+
+
+
+template <typename A>
+Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
+ : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options), fLoadCommandsSection(NULL),
+ fLoadCommandsSegment(NULL), fLargestAtomSize(1),
+ fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
+ fSeenFollowOnReferences(false)
+{
+ 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 writeable 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);
+ fFileDescriptor = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
+ if ( fFileDescriptor == -1 ) {
+ throw "can't open file for writing";
+ }
+
+ switch ( fOptions.outputKind() ) {
+ case Options::kDynamicExecutable:
+ case Options::kStaticExecutable:
+ fWriterSynthesizedAtoms.push_back(new PageZeroAtom<A>(*this));
+ if ( fOptions.outputKind() == Options::kDynamicExecutable )
+ fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
+ if ( fOptions.outputKind() == Options::kDynamicExecutable )
+ fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
+ if ( fOptions.hasCustomStack() )
+ fWriterSynthesizedAtoms.push_back(new CustomStackAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
+ break;
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
+ // fall through
+ case Options::kObjectFile:
+ fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
+ if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
+ fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom<A>(*this));
+ if ( fOptions.initFunctionName() != NULL )
+ fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom<A>(*this));
+ }
+ fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
+ break;
+ case Options::kDyld:
+ fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
+ break;
+ }
+
+ // add extra commmands
+ uint8_t ordinal = 1;
+ switch ( fOptions.outputKind() ) {
+ case Options::kDynamicExecutable:
+ 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];
+ if ( dylibInfo.indirect ) {
+ // find ordinal of direct reader
+ if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) {
+ bool found = false;
+ for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
+ if ( it->first == dylibInfo.directReader ) {
+ //fprintf(stderr, "ordinal %d for indirect %s\n", it->second, dylibInfo.reader->getPath());
+ fLibraryToOrdinal[dylibInfo.reader] = it->second;
+ found = true;
+ break;
+ }
+ }
+ if ( ! found )
+ fprintf(stderr, "ld64 warning: ordinal not found for %s, parent %s\n", dylibInfo.reader->getPath(), dylibInfo.directReader != NULL ? dylibInfo.directReader->getPath() : NULL);
+ }
+ }
+ else {
+ // see if a DylibLoadCommandsAtom has already been created for this install path
+ bool newDylib = true;
+ const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
+ if ( dylibInfo.options.fInstallPathOverride != NULL )
+ dylibInstallPath = dylibInfo.options.fInstallPathOverride;
+ for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
+ ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
+ if ( !seenDylibInfo.indirect ) {
+ const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
+ if ( seenDylibInfo.options.fInstallPathOverride != NULL )
+ seenDylibInstallPath = dylibInfo.options.fInstallPathOverride;
+ if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
+ fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
+ newDylib = false;
+ break;
+ }
+ }
+ }
+
+ if ( newDylib ) {
+ // assign new ordinal and check for other paired load commands
+ fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
+ fWriterSynthesizedAtoms.push_back(new DylibLoadCommandsAtom<A>(*this, dylibInfo));
+ if ( dylibInfo.options.fReExport ) {
+ // 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<A>(*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<A>(*this, nameStart, len));
+ }
+ }
+ }
+ }
+ }
+ // add umbrella command if needed
+ if ( fOptions.umbrellaName() != NULL ) {
+ fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom<A>(*this, fOptions.umbrellaName()));
+ }
+ std::vector<const char*>& allowableClients = fOptions.allowableClients();
+ if ( allowableClients.size() != 0 ) {
+ for (std::vector<const char*>::iterator it=allowableClients.begin();
+ it != allowableClients.end();
+ it++)
+ fWriterSynthesizedAtoms.push_back(new AllowableClientLoadCommandsAtom<A>(*this, *it));
+ }
+ }
+ break;
+ case Options::kStaticExecutable:
+ case Options::kObjectFile:
+ case Options::kDyld:
+ break;
+ }
+
+ //fprintf(stderr, "ordinals table:\n");
+ //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
+ // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
+ //}
+}
+
+template <typename A>
+Writer<A>::~Writer()
+{
+ if ( fFilePath != NULL )
+ free((void*)fFilePath);
+ if ( fSymbolTable != NULL )
+ delete [] fSymbolTable;
+}
+
+
+template <typename A>
+ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
+{
+ if ( (fOptions.outputKind() == Options::kObjectFile)
+ || (fOptions.undefinedTreatment() != Options::kUndefinedError) )
+ return new UndefinedSymbolProxyAtom<A>(*this, name);
+ else
+ return NULL;
+}
+
+template <typename A>
+uint8_t Writer<A>::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<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
+ if ( pos != fLibraryToOrdinal.end() )
+ return pos->second;
+
+ throw "can't find ordinal for imported symbol";
+}
+
+
+template <typename A>
+uint64_t Writer<A>::write(std::vector<class ObjectFile::Atom*>& atoms,
+ std::vector<class ObjectFile::Reader::Stab>& stabs,
+ class ObjectFile::Atom* entryPointAtom, class ObjectFile::Atom* dyldHelperAtom,
+ bool createUUID)
+{
+ fAllAtoms = &atoms;
+ fStabs = &stabs;
+ fEntryPoint = entryPointAtom;
+ fDyldHelper = dyldHelperAtom;
+
+ // Set for create UUID
+ if (createUUID)
+ fUUIDAtom->emit();
+
+ // 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 everything
+ return writeAtoms();
+}
+
+template <typename A>
+void Writer<A>::buildLinkEdit()
+{
+ this->collectExportedAndImportedAndLocalAtoms();
+ this->buildSymbolTable();
+ this->buildFixups();
+ this->adjustLinkEditSections();
+}
+
+
+
+template <typename A>
+uint64_t Writer<A>::getAtomLoadAddress(const ObjectFile::Atom* atom)
+{
+ return atom->getAddress();
+// SectionInfo* info = (SectionInfo*)atom->getSection();
+// return info->getBaseAddress() + atom->getSectionOffset();
+}
+
+template <typename A>
+void Writer<A>::setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
+{
+ // set n_type
+ 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 ( (fOptions.outputKind() == Options::kDynamicExecutable) && (sectionIndex==0)
+ && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ))
+ entry->set_n_type(N_EXT | N_ABS);
+
+ // set n_desc
+ uint16_t desc = 0;
+ 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 )
+ entry->set_n_value(this->getAtomLoadAddress(atom));
+}
+
+template <typename A>
+void Writer<A>::setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
+{
+ // set n_type
+ entry->set_n_type(N_UNDF | N_EXT);
+ if ( fOptions.keepPrivateExterns()
+ && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
+ && (fOptions.outputKind() == Options::kObjectFile) )
+ entry->set_n_type(N_UNDF | N_EXT | N_PEXT);
+
+ // 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 )
+ desc = REFERENCE_FLAG_UNDEFINED_LAZY; // FIXME
+ try {
+ uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
+ SET_LIBRARY_ORDINAL(desc, ordinal);
+ }
+ catch (const char* msg) {
+ throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
+ }
+ }
+ 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 <typename A>
+void Writer<A>::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
+{
+ // set n_type
+ uint8_t type = N_SECT;
+ 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 <mach-o/ldsyms.h> 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;
+ entry->set_n_desc(desc);
+
+ // 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));
+}
+
+
+template <typename A>
+void Writer<A>::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
+{
+ macho_nlist<P>* entry = &fSymbolTable[startIndex];
+ for (uint32_t i=0; i < count; ++i, ++entry) {
+ ObjectFile::Atom* atom = atoms[i];
+ entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
+ if ( &atoms == &fExportedAtoms ) {
+ this->setExportNlist(atom, entry);
+ }
+ else if ( &atoms == &fImportedAtoms ) {
+ this->setImportNlist(atom, entry);
+ }
+ else {
+ this->setLocalNlist(atom, entry);
+ }
+ }
+}
+
+template <typename A>
+void Writer<A>::buildSymbolTable()
+{
+ fSymbolTableStabsStartIndex = 0;
+ fSymbolTableStabsCount = fStabs->size();
+ fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
+ fSymbolTableLocalCount = fLocalSymbolAtoms.size();
+ fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
+ fSymbolTableExportCount = fExportedAtoms.size();
+ fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount;
+ fSymbolTableImportCount = fImportedAtoms.size();
+
+ // allocate symbol table
+ fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
+ fSymbolTable = new macho_nlist<P>[fSymbolTableCount];
+
+ // fill in symbol table and string pool (do stabs last so strings are at end of pool)
+ setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex, fSymbolTableLocalCount);
+ setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fSymbolTableExportCount);
+ setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount);
+ addStabs(fSymbolTableStabsStartIndex);
+}
+
+
+
+template <typename A>
+bool Writer<A>::shouldExport(const ObjectFile::Atom& atom) const
+{
+ if ( atom.getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
+ return false;
+ switch ( atom.getScope() ) {
+ case ObjectFile::Atom::scopeGlobal:
+ return true;
+ case ObjectFile::Atom::scopeLinkageUnit:
+ return ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() );
+ default:
+ return false;
+ }
+}
+
+template <typename A>
+void Writer<A>::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 (int i=0; i < atomCount; ++i) {
+ ObjectFile::Atom* atom = (*fAllAtoms)[i];
+ // only named atoms go in symbol table
+ if ( atom->getName() != NULL ) {
+ // put atom into correct bucket: imports, exports, locals
+ //printf("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 ) {
+ fImportedAtoms.push_back(atom);
+ break;
+ }
+ // else fall into
+ case ObjectFile::Atom::kRegularDefinition:
+ case ObjectFile::Atom::kWeakDefinition:
+ if ( this->shouldExport(*atom) )
+ fExportedAtoms.push_back(atom);
+ else if ( !fOptions.stripLocalSymbols()
+ && (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) )
+ fLocalSymbolAtoms.push_back(atom);
+ break;
+ }
+ }
+ }
+
+ // sort exported atoms by name
+ std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), ExportSorter());
+ // sort imported atoms by name (not required by runtime, but helps make generated files binary diffable)
+ std::sort(fImportedAtoms.begin(), fImportedAtoms.end(), ExportSorter());
+}
+
+
+template <typename A>
+uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
+{
+ switch ( stab.type ) {
+ case N_FUN:
+ if ( stab.other == 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:
+ return 0;
+ default:
+ return stab.value;
+ }
+}
+
+template <typename A>
+uint32_t Writer<A>::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 <typename A>
+uint8_t Writer<A>::sectionIndexForStab(const ObjectFile::Reader::Stab& stab)
+{
+ if ( stab.atom != NULL )
+ return stab.atom->getSection()->getIndex();
+ else
+ return stab.other;
+}
+
+template <typename A>
+void Writer<A>::addStabs(uint32_t startIndex)
+{
+ macho_nlist<P>* entry = &fSymbolTable[startIndex];
+ for(std::vector<ObjectFile::Reader::Stab>::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 <typename A>
+uint32_t Writer<A>::symbolIndex(ObjectFile::Atom& atom)
+{
+ // search imports
+ int i = 0;
+ for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
+ if ( &atom == *it )
+ return i + fSymbolTableImportStartIndex;
+ ++i;
+ }
+
+ // search locals
+ i = 0;
+ for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
+ if ( &atom == *it )
+ return i + fSymbolTableLocalStartIndex;
+ ++i;
+ }
+
+ // search exports
+ i = 0;
+ for(std::vector<ObjectFile::Atom*>::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 <typename A>
+void Writer<A>::buildFixups()
+{
+ if ( fOptions.outputKind() == Options::kObjectFile ) {
+ this->buildObjectFileFixups();
+ }
+ else {
+ if ( fOptions.keepRelocations() )
+ this->buildObjectFileFixups();
+ this->buildExecutableFixups();
+ }
+}
+
+
+template <>
+uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
+{
+ ObjectFile::Atom& target = ref->getTarget();
+ bool isExtern = false;
+ switch ( target.getDefinitionKind() ) {
+ case ObjectFile::Atom::kRegularDefinition:
+ isExtern = false;
+ break;
+ case ObjectFile::Atom::kWeakDefinition:
+ case ObjectFile::Atom::kTentativeDefinition:
+ case ObjectFile::Atom::kExternalDefinition:
+ case ObjectFile::Atom::kExternalWeakDefinition:
+ isExtern = shouldExport(target);
+ break;
+ }
+ 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<P> reloc1;
+ macho_relocation_info<P> reloc2;
+ macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
+ macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
+ x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind();
+
+ switch ( kind ) {
+ case x86::kNoFixUp:
+ case x86::kFollowOn:
+ return 0;
+
+ case x86::kPointer:
+ case x86::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(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.insert(fSectionRelocs.begin(), reloc1);
+ return 1;
+
+ case x86::kPointerDiff:
+ {
+ pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
+ 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(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(2);
+ sreloc2->set_r_type(PPC_RELOC_PAIR);
+ sreloc2->set_r_address(0);
+ sreloc2->set_r_value(fromAddr);
+ fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
+ fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
+ return 2;
+ }
+
+ case x86::kPCRel32WeakImport:
+ case x86::kPCRel32:
+ 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(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(2);
+ reloc1.set_r_extern(isExtern);
+ reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+ }
+ fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
+ return 1;
+
+ }
+ return 0;
+}
+
+
+
+template <>
+uint8_t Writer<ppc>::getRelocPointerSize()
+{
+ return 2;
+}
+
+template <>
+uint8_t Writer<ppc64>::getRelocPointerSize()
+{
+ return 3;
+}
+
+template <>
+uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
+{
+ return addObjectRelocs_powerpc(atom, ref);
+}
+
+template <>
+uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
+{
+ return addObjectRelocs_powerpc(atom, ref);
+}
+
+//
+// addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
+// they use a common addObjectRelocs_powerpc() method.
+//
+template <typename A>
+uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
+{
+ ObjectFile::Atom& target = ref->getTarget();
+ bool isExtern = false;
+ switch ( target.getDefinitionKind() ) {
+ case ObjectFile::Atom::kRegularDefinition:
+ isExtern = false;
+ break;
+ case ObjectFile::Atom::kWeakDefinition:
+ case ObjectFile::Atom::kTentativeDefinition:
+ case ObjectFile::Atom::kExternalDefinition:
+ case ObjectFile::Atom::kExternalWeakDefinition:
+ isExtern = shouldExport(target);
+ break;
+ }
+
+ 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<P> reloc1;
+ macho_relocation_info<P> reloc2;
+ macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
+ macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
+ typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind();
+
+ switch ( kind ) {
+ case A::kNoFixUp:
+ case A::kFollowOn:
+ 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.insert(fSectionRelocs.begin(), reloc1);
+ return 1;
+
+ case A::kPointerDiff32:
+ case A::kPointerDiff64:
+ {
+ pint_t toAddr = target.getAddress() + ref->getTargetOffset();
+ pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
+ sreloc1->set_r_scattered(true);
+ sreloc1->set_r_pcrel(false);
+ sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : 3);
+ sreloc1->set_r_type(ref->getTargetOffset() != 0 ? PPC_RELOC_LOCAL_SECTDIFF : PPC_RELOC_SECTDIFF);
+ sreloc1->set_r_address(address);
+ sreloc1->set_r_value(toAddr);
+ sreloc2->set_r_scattered(true);
+ sreloc2->set_r_pcrel(false);
+ sreloc2->set_r_length( (kind == A::kPointerDiff32) ? 2 : 3);
+ sreloc2->set_r_type(PPC_RELOC_PAIR);
+ sreloc2->set_r_address(0);
+ sreloc2->set_r_value(fromAddr);
+ fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
+ fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
+ return 2;
+ }
+
+ case A::kBranch24WeakImport:
+ case A::kBranch24:
+ 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.insert(fSectionRelocs.begin(), 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.insert(fSectionRelocs.begin(), 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));
+ sreloc2->set_r_value(fromAddr);
+ fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
+ fSectionRelocs.insert(fSectionRelocs.begin(), 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.insert(fSectionRelocs.begin(), reloc2);
+ fSectionRelocs.insert(fSectionRelocs.begin(), 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.insert(fSectionRelocs.begin(), reloc2);
+ fSectionRelocs.insert(fSectionRelocs.begin(), 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.insert(fSectionRelocs.begin(), reloc2);
+ fSectionRelocs.insert(fSectionRelocs.begin(), 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.insert(fSectionRelocs.begin(), reloc2);
+ fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
+ return 2;
+ }
+
+ }
+ return 0;
+}
+
+
+template <typename A>
+void Writer<A>::buildObjectFileFixups()
+{
+ uint32_t relocIndex = 0;
+ std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
+ const int segCount = segmentInfos.size();
+ for(int i=0; i < segCount; ++i) {
+ SegmentInfo* curSegment = segmentInfos[i];
+ std::vector<SectionInfo*>& 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<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
+ if ( ! curSection->fAllZeroFill ) {
+ if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || 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<ObjectFile::Reference*>& refs = atom->getReferences();
+ const int refCount = refs.size();
+ for (int l=0; l < refCount; ++l) {
+ ObjectFile::Reference* ref = refs[l];
+ if ( ref->getKind() == A::kFollowOn )
+ fSeenFollowOnReferences = true;
+ if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || 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
+ && (ref->getTarget().getScope() == ObjectFile::Atom::scopeLinkageUnit)
+ && !fOptions.keepPrivateExterns() )
+ undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
+ else
+ undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
+ }
+ 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 ) {
+ fprintf(stderr, "lazy pointer %s missing initial binding\n", atom->getDisplayName());
+ }
+ else {
+ bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
+ || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition))
+ && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) );
+ macho_relocation_info<P> 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.insert(fSectionRelocs.begin(), reloc1);
+ ++relocIndex;
+ }
+ }
+ else if ( curSection->fAllStubs ) {
+ relocIndex += this->addObjectRelocs(atom, ref);
+ }
+ }
+ else {
+ relocIndex += this->addObjectRelocs(atom, ref);
+ }
+ }
+ }
+ curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
+ }
+ }
+ }
+
+ // now reverse reloc entries
+ for(int i=0; i < segCount; ++i) {
+ SegmentInfo* curSegment = segmentInfos[i];
+ std::vector<SectionInfo*>& 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<ppc>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
+{
+ switch ( kind ) {
+ case ppc::kAbsLow16:
+ case ppc::kAbsLow14:
+ case ppc::kAbsHigh16:
+ case ppc::kAbsHigh16AddLow:
+ if ( slideable )
+ return true;
+ }
+ return false;
+}
+
+
+template <>
+bool Writer<ppc64>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
+{
+ switch ( kind ) {
+ case ppc::kAbsLow16:
+ case ppc::kAbsLow14:
+ case ppc::kAbsHigh16:
+ case ppc::kAbsHigh16AddLow:
+ if ( slideable )
+ return true;
+ }
+ return false;
+}
+
+template <>
+bool Writer<x86>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
+{
+ return false;
+}
+
+
+
+template <typename A>
+typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
+{
+ const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
+
+ switch ( target.getDefinitionKind() ) {
+ case ObjectFile::Atom::kTentativeDefinition:
+ case ObjectFile::Atom::kRegularDefinition:
+ // for flat-namespace or interposable two-level-namespace
+ // all references to exported symbols get indirected
+ if ( this->shouldExport(target) &&
+ ((fOptions.nameSpace() == Options::kFlatNameSpace)
+ || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
+ || fOptions.interposable()) )
+ return kRelocExternal;
+ else if ( slideable )
+ 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 ( slideable )
+ return kRelocInternal;
+ else
+ return kRelocNone;
+ case ObjectFile::Atom::kExternalDefinition:
+ case ObjectFile::Atom::kExternalWeakDefinition:
+ return kRelocExternal;
+ }
+ return kRelocNone;
+}
+
+template <typename A>
+void Writer<A>::buildExecutableFixups()
+{
+ const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
+ fIndirectTableAtom->fTable.reserve(50); // minimize reallocations
+ std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
+ const int segCount = segmentInfos.size();
+ for(int i=0; i < segCount; ++i) {
+ SegmentInfo* curSegment = segmentInfos[i];
+ std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
+ const int sectionCount = sectionInfos.size();
+ for(int j=0; j < sectionCount; ++j) {
+ SectionInfo* curSection = sectionInfos[j];
+ //fprintf(stderr, "starting section %p\n", curSection->fSectionName);
+ std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
+ if ( ! curSection->fAllZeroFill ) {
+ if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || 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<ObjectFile::Reference*>& 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 ) {
+ // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
+ if ( atom->getSize() != sizeof(pint_t) ) {
+ printf("wrong size pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
+ }
+ ObjectFile::Atom* pointerTarget = &(ref->getTarget());
+ if ( curSection->fAllLazyPointers ) {
+ pointerTarget = ((LazyPointerAtom<A>*)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.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
+ fIndirectTableAtom->fTable.push_back(entry);
+ if ( slideable && curSection->fAllLazyPointers ) {
+ // if this is a dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
+ macho_relocation_info<P> pblaReloc;
+ 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);
+ pblaReloc.set_r_address(atom->getAddress()-fOptions.baseAddress());
+ pblaReloc.set_r_symbolnum(sectionNum);
+ pblaReloc.set_r_pcrel(false);
+ pblaReloc.set_r_length();
+ pblaReloc.set_r_extern(false);
+ pblaReloc.set_r_type(GENERIC_RELOC_VANILLA);
+ fInternalRelocs.push_back(pblaReloc);
+ }
+ }
+ else if ( ref->getKind() == A::kPointer ) {
+ if ( slideable && ((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<P> 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(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
+ 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<P> externalReloc;
+ externalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
+ 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->getKind(), slideable) ) {
+ throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
+ }
+ }
+ if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
+ ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
+ uint32_t undefinedSymbolIndex = this->symbolIndex(*stubTarget);
+ 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);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+template <>
+void Writer<ppc>::writeNoOps(uint32_t from, uint32_t to)
+{
+ uint32_t ppcNop;
+ OSWriteBigInt32(&ppcNop, 0, 0x60000000);
+ for (uint32_t p=from; p < to; p += 4)
+ ::pwrite(fFileDescriptor, &ppcNop, 4, p);
+}
+
+template <>
+void Writer<ppc64>::writeNoOps(uint32_t from, uint32_t to)
+{
+ uint32_t ppcNop;
+ OSWriteBigInt32(&ppcNop, 0, 0x60000000);
+ for (uint32_t p=from; p < to; p += 4)
+ ::pwrite(fFileDescriptor, &ppcNop, 4, p);
+}
+
+template <>
+void Writer<x86>::writeNoOps(uint32_t from, uint32_t to)
+{
+ uint8_t x86Nop = 0x90;
+ for (uint32_t p=from; p < to; ++p)
+ ::pwrite(fFileDescriptor, &x86Nop, 1, p);
+}
+
+
+template <typename A>
+uint64_t Writer<A>::writeAtoms()
+{
+ uint32_t end = 0;
+ uint8_t* buffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
+ std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
+ const int segCount = segmentInfos.size();
+ for(int i=0; i < segCount; ++i) {
+ SegmentInfo* curSegment = segmentInfos[i];
+ bool isTextSeg = ((curSegment->fInitProtection & VM_PROT_EXECUTE) != 0);
+ std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
+ const int sectionCount = sectionInfos.size();
+ for(int j=0; j < sectionCount; ++j) {
+ SectionInfo* curSection = sectionInfos[j];
+ std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
+ //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
+ //fprintf(stderr, "writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName);
+ if ( ! curSection->fAllZeroFill ) {
+ const int atomCount = sectionAtoms.size();
+ end = curSection->fFileOffset;
+ bool needsNops = isTextSeg && (strcmp(curSection->fSectionName, "__cstring") != 0);
+ for (int k=0; k < atomCount; ++k) {
+ ObjectFile::Atom* atom = sectionAtoms[k];
+ if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
+ && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition) ) {
+ uint32_t offset = curSection->fFileOffset + atom->getSectionOffset();
+ if ( offset != end ) {
+ if ( needsNops ) {
+ // fill gaps with no-ops
+ writeNoOps(end, offset);
+ }
+ else {
+ // zero fill gaps
+ if ( (offset-end) == 4 ) {
+ uint32_t zero = 0;
+ ::pwrite(fFileDescriptor, &zero, 4, end);
+ }
+ else {
+ uint8_t zero = 0x00;
+ for (uint32_t p=end; p < offset; ++p)
+ ::pwrite(fFileDescriptor, &zero, 1, p);
+ }
+ }
+ }
+ uint64_t atomSize = atom->getSize();
+ if ( atomSize > fLargestAtomSize ) {
+ throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX",
+ atom->getDisplayName(), atomSize, fLargestAtomSize);
+ }
+ end = offset+atomSize;
+ // copy raw bytes
+ atom->copyRawContent(buffer);
+ // apply any fix-ups
+ try {
+ std::vector<ObjectFile::Reference*>& references = atom->getReferences();
+ for (std::vector<ObjectFile::Reference*>::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\n", offset, end, atom->getAddress(), atom->getSize(), atom->getDisplayName());
+ // write out
+ ::pwrite(fFileDescriptor, buffer, atom->getSize(), offset);
+ }
+ }
+ }
+ }
+ }
+ delete [] buffer;
+ return end;
+}
+
+
+template <>
+void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
+{
+ uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
+ switch ( (x86::ReferenceKinds)(ref->getKind()) ) {
+ case x86::kNoFixUp:
+ case x86::kFollowOn:
+ // do nothing
+ break;
+ case x86::kPointerWeakImport:
+ case x86::kPointer:
+ {
+ if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition ) {
+ // external realocation ==> pointer contains addend
+ LittleEndian::set32(*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::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
+ }
+ }
+ break;
+ case x86::kPointerDiff:
+ LittleEndian::set32(*fixUp,
+ (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
+ break;
+ case x86::kPCRel32WeakImport:
+ case x86::kPCRel32:
+ int64_t 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;
+ }
+ const int64_t bl_twoGigLimit = 0x7FFFFFFF;
+ if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_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(*fixUp, (int32_t)displacement);
+ break;
+ }
+}
+
+template <>
+void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
+{
+ uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
+ bool isExternal = ( (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
+ && shouldExport(ref->getTarget()) );
+ switch (ref->getKind()) {
+ case x86::kNoFixUp:
+ case x86::kFollowOn:
+ // do nothing
+ break;
+ case x86::kPointer:
+ {
+ if ( isExternal ) {
+ // external realocation ==> pointer contains addend
+ LittleEndian::set32(*fixUp, ref->getTargetOffset());
+ }
+ else {
+ // internal relocation
+ if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
+ // pointer contains target address
+ LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
+ }
+ else {
+ // pointer contains addend
+ LittleEndian::set32(*fixUp, ref->getTargetOffset());
+ }
+ }
+ }
+ break;
+ case x86::kPointerDiff:
+ LittleEndian::set32(*fixUp,
+ (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
+ break;
+ case x86::kPCRel32:
+ int64_t displacement = 0;
+ if ( isExternal )
+ displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
+ else
+ displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
+ const int64_t bl_twoGigLimit = 0x7FFFFFFF;
+ if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_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(*fixUp, (int32_t)displacement);
+ break;
+ }
+}
+
+
+template <>
+void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
+{
+ fixUpReference_powerpc(ref, inAtom, buffer, true);
+}
+
+template <>
+void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
+{
+ fixUpReference_powerpc(ref, inAtom, buffer, true);
+}
+
+template <>
+void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
+{
+ fixUpReference_powerpc(ref, inAtom, buffer, false);
+}
+
+template <>
+void Writer<ppc64>::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 <typename A>
+void Writer<A>::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 = ref->getTarget().getAddress() + ref->getTargetOffset();
+ 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;
+
+ if ( finalLinkedImage )
+ relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
+ else
+ relocateableExternal = ( (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
+ && shouldExport(ref->getTarget()) );
+
+ const int64_t picbase_twoGigLimit = 0x80000000;
+
+ switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
+ case A::kNoFixUp:
+ case A::kFollowOn:
+ // 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 ) {
+ // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
+ if ( fDyldHelper == NULL )
+ throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
+ P::setP(*fixUpPointer, fDyldHelper->getAddress());
+ }
+ else if ( relocateableExternal ) {
+ // external realocation ==> 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", target.getDisplayName(), target.getAddress());
+ 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::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 in %s to %s in %s",
+ displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
+ ref->getTarget().getDisplayName(), 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:
+ {
+ //fprintf(stderr, "bc fixup %p to %s+0x%08X == 0x%08llX\n", this, ref->getTarget().getDisplayName(), ref->getTargetOffset(), targetAddr);
+ 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 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("bc 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, "bc 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 = inAtom->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 = inAtom->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 = inAtom->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 )
+ 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 )
+ 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 )
+ 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 )
+ targetAddr -= ref->getTarget().getAddress();
+ if ( targetAddr & 0x00008000 )
+ targetAddr += 0x00010000;
+ instruction = BigEndian::get32(*fixUp);
+ newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
+ BigEndian::set32(*fixUp, newInstruction);
+ break;
+ }
+}
+
+template <>
+bool Writer<ppc>::stubableReferenceKind(uint8_t kind)
+{
+ return (kind == ppc::kBranch24 || kind == ppc::kBranch24WeakImport);
+}
+
+template <>
+bool Writer<ppc64>::stubableReferenceKind(uint8_t kind)
+{
+ return (kind == ppc64::kBranch24 || kind == ppc64::kBranch24WeakImport);
+}
+
+template <>
+bool Writer<x86>::stubableReferenceKind(uint8_t kind)
+{
+ return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
+}
+
+
+template <>
+bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
+{
+ return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
+}
+
+template <>
+bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
+{
+ return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
+}
+
+template <>
+bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
+{
+ return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
+}
+
+
+
+template <>
+bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
+{
+ return false;
+}
+
+template <>
+bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
+{
+ return false;
+}
+
+template <>
+bool Writer<x86>::GOTReferenceKind(uint8_t kind)
+{
+ return false;
+}
+
+
+
+template <typename A>
+void Writer<A>::synthesizeStubs()
+{
+ switch ( fOptions.outputKind() ) {
+ case Options::kStaticExecutable:
+ case Options::kDyld:
+ case Options::kObjectFile:
+ // these output kinds never have stubs
+ return;
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kDynamicExecutable:
+ // try to synthesize stubs for these
+ break;
+ }
+
+ // walk every atom and reference
+ for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
+ ObjectFile::Atom* atom = *it;
+ std::vector<ObjectFile::Reference*>& references = atom->getReferences();
+ for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
+ ObjectFile::Reference* ref = *rit;
+ 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());
+ std::map<const ObjectFile::Atom*,bool>::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;
+ }
+ }
+ }
+ }
+ // create stubs as needed
+ if ( this->stubableReferenceKind(ref->getKind())
+ && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
+ ObjectFile::Atom* stub = NULL;
+ std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
+ if ( pos == fStubsMap.end() ) {
+ stub = new StubAtom<A>(*this, target);
+ fStubsMap[&target] = stub;
+ }
+ else {
+ stub = pos->second;
+ }
+ // alter reference to use stub instead
+ ref->setTarget(*stub, 0);
+ }
+ // create GOT slots (non-lazy pointers) as needed
+ else if ( this->GOTReferenceKind(ref->getKind()) ) {
+ ObjectFile::Atom* nlp = NULL;
+ std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
+ if ( pos == fGOTMap.end() ) {
+ nlp = new NonLazyPointerAtom<A>(*this, target);
+ fGOTMap[&target] = nlp;
+ }
+ else {
+ nlp = pos->second;
+ }
+ // alter reference to use non lazy pointer instead
+ ref->setTarget(*nlp, 0);
+ }
+ }
+ }
+
+ // sort stubs
+
+ // sort lazy pointers
+
+ // add stubs to fAllAtoms
+ if ( fAllSynthesizedStubs.size() != 0 ) {
+ std::vector<ObjectFile::Atom*>* stubs = (std::vector<ObjectFile::Atom*>*)&fAllSynthesizedStubs;
+ std::vector<ObjectFile::Atom*> mergedStubs;
+ if ( fAllSynthesizedStubHelpers.size() != 0 ) {
+ // when we have stubs and helpers, insert both into fAllAtoms
+ mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
+ mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
+ stubs = &mergedStubs;
+ }
+ ObjectFile::Section* curSection = NULL;
+ ObjectFile::Atom* prevAtom = NULL;
+ for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
+ ObjectFile::Atom* atom = *it;
+ ObjectFile::Section* nextSection = atom->getSection();
+ if ( nextSection != curSection ) {
+ // HACK HACK for i386 where stubs are not in _TEXT segment
+ if ( strcmp(fAllSynthesizedStubs[0]->getSegment().getName(), "__IMPORT") == 0 ) {
+ 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, fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
+ break;
+ }
+ }
+ else {
+ if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) {
+ // found end of __text section, insert stubs here
+ fAllAtoms->insert(it, stubs->begin(), stubs->end());
+ break;
+ }
+ }
+ curSection = nextSection;
+ }
+ prevAtom = atom;
+ }
+ }
+
+
+ // add lazy pointers to fAllAtoms
+ if ( fAllSynthesizedLazyPointers.size() != 0 ) {
+ ObjectFile::Section* curSection = NULL;
+ ObjectFile::Atom* prevAtom = NULL;
+ bool inserted = false;
+ for (std::vector<ObjectFile::Atom*>::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<ObjectFile::Atom*>::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, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
+ inserted = true;
+ break;
+ }
+ curSection = nextSection;
+ }
+ prevAtom = atom;
+ }
+ if ( !inserted ) {
+ throw "can't insert non-lazy pointers, __dyld section not found";
+ }
+ }
+}
+
+
+template <typename A>
+void Writer<A>::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;
+ 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();
+ currentSectionInfo->fAllZeroFill = atom->isZeroFill();
+ currentSectionInfo->fVirtualSection = ( (currentSectionInfo->fSectionName[0] == '.') || (oneSegmentCommand && (atom->getDefinitionKind()==ObjectFile::Atom::kTentativeDefinition)) );
+ if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
+ currentSectionInfo->setIndex(sectionIndex++);
+ currentSegmentInfo->fSections.push_back(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;
+ currentSegmentInfo->fInitProtection = initprot;
+ if ( initprot == 0 )
+ currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
+ else
+ currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+ currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
+ currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
+ 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();
+ // check for -sectalign override
+ std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
+ for(std::vector<Options::SectionAlignment>::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, "__nl_symbol_ptr") == 0) )
+ currentSectionInfo->fAllNonLazyPointers = true;
+ if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 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, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) )
+ currentSectionInfo->fAllSelfModifyingStubs = true;
+ curSection = atom->getSection();
+ }
+ // 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();
+ if ( currentSectionInfo->fAlignment < atomAlign )
+ currentSectionInfo->fAlignment = atomAlign;
+ // calculate section offset for this atom
+ uint64_t offset = currentSectionInfo->fSize;
+ uint64_t alignment = 1 << atomAlign;
+ offset = ( (offset+alignment-1) & (-alignment) );
+ 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;
+ }
+}
+
+
+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<ppc>::addBranchIslands()
+{
+ return this->addPPCBranchIslands();
+}
+
+template <>
+bool Writer<ppc64>::addBranchIslands()
+{
+ return this->addPPCBranchIslands();
+}
+
+template <>
+bool Writer<x86>::addBranchIslands()
+{
+ // x86 branches can reach entire 4G address space, so no need for branch islands
+ return false;
+}
+
+
+template <>
+inline uint8_t Writer<ppc>::branch24Reference()
+{
+ return ppc::kBranch24;
+}
+
+template <>
+inline uint8_t Writer<ppc64>::branch24Reference()
+{
+ return ppc64::kBranch24;
+}
+
+//
+// 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 <typename A>
+bool Writer<A>::addPPCBranchIslands()
+{
+ bool result = false;
+ // Can only possibly need branch islands if __TEXT segment > 16M
+ if ( fLoadCommandsSegment->fSize > 16000000 ) {
+ //fprintf(stderr, "ld64: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
+ const uint32_t kBetweenRegions = 15000000; // place regions of islands every 15MB in __text section
+ SectionInfo* textSection = NULL;
+ for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
+ if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
+ textSection = *it;
+ //fprintf(stderr, "ld64: checking for branch islands, __text section size=%llu\n", textSection->fSize);
+ break;
+ }
+ }
+ const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
+ typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
+ AtomToIsland regionsMap[kIslandRegionsCount];
+ std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
+ unsigned int islandCount = 0;
+
+ // create islands for branch references that are out of range
+ for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
+ ObjectFile::Atom* atom = *it;
+ std::vector<ObjectFile::Reference*>& references = atom->getReferences();
+ for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
+ ObjectFile::Reference* ref = *rit;
+ if ( ref->getKind() == this->branch24Reference() ) {
+ ObjectFile::Atom& target = ref->getTarget();
+ int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
+ int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
+ int64_t displacement = dstAddr - srcAddr;
+ const int64_t kFifteenMegLimit = kBetweenRegions;
+ if ( (displacement > kFifteenMegLimit) || (displacement < (-kFifteenMegLimit)) ) {
+ for (int i=0; i < kIslandRegionsCount; ++i) {
+ AtomToIsland* region=®ionsMap[i];
+ int64_t islandRegionAddr = kBetweenRegions * (i+1);
+ if ( ((srcAddr < islandRegionAddr) && (dstAddr > islandRegionAddr))
+ ||((dstAddr < islandRegionAddr) && (srcAddr > islandRegionAddr)) ) {
+ TargetAndOffset islandTarget = { &target, ref->getTargetOffset() };
+ AtomToIsland::iterator pos = region->find(islandTarget);
+ if ( pos == region->end() ) {
+ BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, target, ref->getTargetOffset());
+ island->setSection(textSection);
+ (*region)[islandTarget] = island;
+ regionsIslands[i].push_back(island);
+ ++islandCount;
+ ref->setTarget(*island, 0);
+ }
+ else {
+ ref->setTarget(*(pos->second), 0);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // insert islands into __text section and adjust section offsets
+ if ( islandCount > 0 ) {
+ //fprintf(stderr, "ld64: %u branch islands required\n", islandCount);
+ std::vector<ObjectFile::Atom*> newAtomList;
+ newAtomList.reserve(textSection->fAtoms.size()+islandCount);
+ uint64_t islandRegionAddr = kBetweenRegions;
+ int regionIndex = 0;
+ uint64_t sectionOffset = 0;
+ for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
+ ObjectFile::Atom* atom = *it;
+ newAtomList.push_back(atom);
+ if ( atom->getAddress() > islandRegionAddr ) {
+ std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
+ for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
+ ObjectFile::Atom* islandAtom = *rit;
+ newAtomList.push_back(islandAtom);
+ uint64_t alignment = 1 << (islandAtom->getAlignment());
+ sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
+ islandAtom->setSectionOffset(sectionOffset);
+ sectionOffset += islandAtom->getSize();
+ }
+ ++regionIndex;
+ islandRegionAddr += kBetweenRegions;
+ }
+ uint64_t alignment = 1 << (atom->getAlignment());
+ sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
+ atom->setSectionOffset(sectionOffset);
+ sectionOffset += atom->getSize();
+ }
+ // put any remaining islands at end of __text section
+ if ( regionIndex < kIslandRegionsCount ) {
+ sectionOffset = textSection->fSize;
+ std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
+ for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
+ ObjectFile::Atom* islandAtom = *rit;
+ newAtomList.push_back(islandAtom);
+ uint64_t alignment = 1 << (islandAtom->getAlignment());
+ sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
+ islandAtom->setSectionOffset(sectionOffset);
+ sectionOffset += islandAtom->getSize();
+ }
+ }
+
+ textSection->fAtoms = newAtomList;
+ textSection->fSize = sectionOffset;
+ result = true;
+ }
+
+ }
+ return result;
+}
+
+
+template <typename A>
+void Writer<A>::adjustLoadCommandsAndPadding()
+{
+ fSegmentCommands->computeSize();
+
+ // recompute load command section offsets
+ uint64_t offset = 0;
+ std::vector<class ObjectFile::Atom*>& 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();
+ 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<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
+ const int sectionCount = sectionInfos.size();
+ 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
+ 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;
+ }
+ 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 {
+ // calculate max padding to keep segment size same, but all free space at end of load commands
+ uint64_t totalSize = 0;
+ uint64_t worstCaseAlignmentPadding = 0;
+ for(int j=0; j < sectionCount; ++j) {
+ SectionInfo* curSection = sectionInfos[j];
+ totalSize += curSection->fSize;
+ if ( j != 0 ) // don't count aligment of mach_header which is page-aligned
+ worstCaseAlignmentPadding += (1 << curSection->fAlignment) - 1;
+ }
+ uint64_t segmentSize = ((totalSize+worstCaseAlignmentPadding+4095) & (-4096));
+ // don't know exactly how it will layout, but we can inflate padding atom this big and still keep aligment constraints
+ paddingSize = segmentSize - (totalSize+worstCaseAlignmentPadding);
+
+ // if command line requires more padding than this
+ if ( paddingSize < fOptions.minimumHeaderPad() ) {
+ int extraPages = (fOptions.minimumHeaderPad() - 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 <typename A>
+void Writer<A>::assignFileOffsets()
+{
+ bool finalLinkedImage = (fOptions.outputKind() != Options::kObjectFile);
+ bool haveFixedSegments = false;
+ uint64_t fileOffset = 0;
+ uint64_t nextContiguousAddress = fOptions.baseAddress();
+
+ // Run through the segments and each segment's sections to assign addresses
+ for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
+ SegmentInfo* curSegment = *segit;
+
+ 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<SectionInfo*>& sectionInfos = curSegment->fSections;
+
+ for (std::vector<SectionInfo*>::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 ) {
+ fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
+ }
+
+ // update section info
+ curSection->fFileOffset = fileOffset;
+ curSection->setBaseAddress(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
+ address += curSection->fSize;
+ fileOffset += curSection->fSize;
+
+ // 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->fBaseAddress == nextContiguousAddress )
+ nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
+ }
+ }
+
+ // 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 {
+ 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);
+ }
+ }
+ }
+ }
+ }
+}
+
+template <typename A>
+void Writer<A>::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 sectionCount = lastSeg->fSections.size();
+ uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
+ uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
+ for (unsigned int i=firstLinkEditSectionIndex; i < sectionCount; ++i) {
+ std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
+ const unsigned int atomCount = atoms.size();
+ uint64_t sectionOffset = 0;
+ lastSeg->fSections[i]->fFileOffset = fileOffset;
+ lastSeg->fSections[i]->setBaseAddress(address);
+ for (unsigned int j=0; j < atomCount; ++j) {
+ ObjectFile::Atom* atom = atoms[j];
+ uint64_t alignment = 1 << atom->getAlignment();
+ sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
+ atom->setSectionOffset(sectionOffset);
+ uint64_t size = atom->getSize();
+ sectionOffset += size;
+ if ( size > fLargestAtomSize )
+ fLargestAtomSize = size;
+ }
+ 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 <typename A>
+ObjectFile::Atom::Scope MachHeaderAtom<A>::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 <typename A>
+ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
+{
+ switch ( fWriter.fOptions.outputKind() ) {
+ case Options::kDynamicExecutable:
+ case Options::kStaticExecutable:
+ return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
+ 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 <typename A>
+const char* MachHeaderAtom<A>::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 <typename A>
+const char* MachHeaderAtom<A>::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 <typename A>
+void MachHeaderAtom<A>::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.fSeenFollowOnReferences )
+ 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.hasExecutableStack() )
+ flags |= MH_ALLOW_STACK_EXECUTION;
+ }
+
+ // get commands info
+ uint32_t commandsSize = 0;
+ uint32_t commandsCount = 0;
+
+ std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
+ const unsigned int atomCount = loadCommandAtoms.size();
+ for (unsigned int i=0; i < atomCount; ++i) {
+ ObjectFile::Atom* atom = loadCommandAtoms[i];
+ 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<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
+ setHeaderInfo(*mh);
+ mh->set_filetype(fileType);
+ mh->set_ncmds(commandsCount);
+ mh->set_sizeofcmds(commandsSize);
+ mh->set_flags(flags);
+}
+
+template <>
+void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
+{
+ header.set_magic(MH_MAGIC);
+ header.set_cputype(CPU_TYPE_POWERPC);
+ header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
+}
+
+template <>
+void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
+{
+ header.set_magic(MH_MAGIC_64);
+ header.set_cputype(CPU_TYPE_POWERPC64);
+ header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
+ header.set_reserved(0);
+}
+
+template <>
+void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
+{
+ header.set_magic(MH_MAGIC);
+ header.set_cputype(CPU_TYPE_I386);
+ header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
+}
+
+
+template <typename A>
+CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
+ : WriterAtom<A>(writer, Segment::fgStackSegment)
+{
+ if ( stackGrowsDown() )
+ Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
+ else
+ Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
+}
+
+
+template <>
+bool CustomStackAtom<ppc>::stackGrowsDown()
+{
+ return true;
+}
+
+template <>
+bool CustomStackAtom<ppc64>::stackGrowsDown()
+{
+ return true;
+}
+
+template <>
+bool CustomStackAtom<x86>::stackGrowsDown()
+{
+ return true;
+}
+
+
+template <typename A>
+void SegmentLoadCommandsAtom<A>::computeSize()
+{
+ uint64_t size = 0;
+ std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
+ const int segCount = segmentInfos.size();
+ for(int i=0; i < segCount; ++i) {
+ size += sizeof(macho_segment_command<P>);
+ std::vector<SectionInfo*>& 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<P>);
+ }
+ }
+ fSize = size;
+ fCommandCount = segCount;
+}
+
+template <>
+uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
+{
+ return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
+}
+
+template <>
+uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
+{
+ return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
+}
+
+template <>
+uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
+{
+ return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
+}
+
+
+
+template <typename A>
+void SegmentLoadCommandsAtom<A>::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<SegmentInfo*>& 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<P>* cmd = (macho_segment_command<P>*)p;
+ cmd->set_cmd(macho_segment_command<P>::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<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
+ unsigned int sectionsEmitted = 0;
+ for (int j=0; j < sectionCount; ++j) {
+ SectionInfo* sectInfo = segInfo->fSections[j];
+ if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
+ macho_section<P>* 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<P>) + 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->fAllNonLazyPointers ) {
+ sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
+ sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
+ }
+ else if ( sectInfo->fAllStubs ) {
+ sect->set_flags(S_SYMBOL_STUBS);
+ 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);
+ }
+ 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, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
+ sect->set_flags(S_LITERAL_POINTERS);
+ }
+ }
+ }
+ p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
+ cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
+ cmd->set_nsects(sectionsEmitted);
+ }
+}
+
+
+template <typename A>
+SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
+ : LoadCommandAtom<A>(writer, Segment::fgTextSegment)
+{
+ bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
+ bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
+ writer.fSymbolTableCommands = this;
+}
+
+template <typename A>
+uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
+{
+ if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable )
+ return this->alignedSize(sizeof(macho_symtab_command<P>));
+ else
+ return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
+}
+
+template <typename A>
+void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ // build LC_DYSYMTAB command
+ macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)buffer;
+ bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
+ symbolTableCmd->set_cmd(LC_SYMTAB);
+ symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
+ 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 ( fWriter.fOptions.outputKind() != Options::kStaticExecutable ) {
+ macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
+ bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
+ dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
+ dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
+ 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);
+ 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 <typename A>
+unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
+{
+ return (fWriter.fOptions.outputKind() == Options::kStaticExecutable) ? 1 : 2;
+}
+
+template <typename A>
+uint64_t DyldLoadCommandsAtom<A>::getSize() const
+{
+ return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
+}
+
+template <typename A>
+void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ uint64_t size = this->getSize();
+ bzero(buffer, size);
+ macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)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<P>)], "/usr/lib/dyld");
+}
+
+template <typename A>
+uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
+{
+ return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
+}
+
+template <typename A>
+void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ uint64_t size = this->getSize();
+
+ bzero(buffer, size);
+ macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
+ cmd->set_cmd(LC_SUB_CLIENT);
+ cmd->set_cmdsize(size);
+ cmd->set_client_offset();
+ strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
+
+}
+
+template <typename A>
+uint64_t DylibLoadCommandsAtom<A>::getSize() const
+{
+ const char* path = fInfo.reader->getInstallPath();
+ if ( fInfo.options.fInstallPathOverride != NULL )
+ path = fInfo.options.fInstallPathOverride;
+ return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
+}
+
+template <typename A>
+void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ uint64_t size = this->getSize();
+ bzero(buffer, size);
+ const char* path = fInfo.reader->getInstallPath();
+ if ( fInfo.options.fInstallPathOverride != NULL )
+ path = fInfo.options.fInstallPathOverride;
+ macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
+ if ( fInfo.options.fWeakImport )
+ cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
+ else
+ cmd->set_cmd(LC_LOAD_DYLIB);
+ cmd->set_cmdsize(this->getSize());
+ cmd->set_timestamp(fInfo.reader->getTimestamp());
+ 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<P>)], path);
+}
+
+
+
+template <typename A>
+uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
+{
+ return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
+}
+
+template <typename A>
+void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ struct timeval currentTime = { 0 , 0 };
+ gettimeofday(¤tTime, NULL);
+ time_t timestamp = currentTime.tv_sec;
+ uint64_t size = this->getSize();
+ bzero(buffer, size);
+ macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
+ cmd->set_cmd(LC_ID_DYLIB);
+ cmd->set_cmdsize(this->getSize());
+ cmd->set_name_offset();
+ cmd->set_timestamp(timestamp);
+ cmd->set_current_version(fWriter.fOptions.currentVersion());
+ cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
+ strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
+}
+
+
+template <typename A>
+void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
+ bzero(buffer, sizeof(macho_routines_command<P>));
+ macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
+ cmd->set_cmd(macho_routines_command<P>::CMD);
+ cmd->set_cmdsize(this->getSize());
+ cmd->set_init_address(initAddr);
+}
+
+
+template <typename A>
+uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
+{
+ return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
+}
+
+template <typename A>
+void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ uint64_t size = this->getSize();
+ bzero(buffer, size);
+ macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)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<P>)], fName);
+}
+
+template <typename A>
+void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ if (fEmit) {
+ uint64_t size = this->getSize();
+ bzero(buffer, size);
+ macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
+ cmd->set_cmd(LC_UUID);
+ cmd->set_cmdsize(this->getSize());
+ cmd->set_uuid((uint8_t*)fUUID);
+ }
+}
+
+template <typename A>
+uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
+{
+ return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
+}
+
+template <typename A>
+void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ uint64_t size = this->getSize();
+ bzero(buffer, size);
+ macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)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<P>)], fNameStart, fNameLength);
+ buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
+}
+
+template <typename A>
+uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
+{
+ return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
+}
+
+template <typename A>
+void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ uint64_t size = this->getSize();
+ bzero(buffer, size);
+ macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
+ cmd->set_cmd(LC_SUB_FRAMEWORK);
+ cmd->set_cmdsize(this->getSize());
+ cmd->set_umbrella_offset();
+ strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
+}
+
+template <>
+uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
+{
+ return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
+}
+
+template <>
+uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
+{
+ return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
+}
+
+template <>
+uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
+{
+ return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
+}
+
+
+template <>
+void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
+{
+ uint64_t size = this->getSize();
+ uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
+ bzero(buffer, size);
+ macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)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<ppc64>::copyRawContent(uint8_t buffer[]) const
+{
+ uint64_t size = this->getSize();
+ uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
+ bzero(buffer, size);
+ macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)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(6, fWriter.fOptions.customStackAddr()); // r1
+}
+
+template <>
+void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
+{
+ uint64_t size = this->getSize();
+ uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
+ bzero(buffer, size);
+ macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)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(15, fWriter.fOptions.customStackAddr()); // uesp
+}
+
+
+
+
+template <typename A>
+void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ bzero(buffer, fSize);
+}
+
+template <typename A>
+void LoadCommandsPaddingAtom<A>::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 <typename A>
+uint64_t LinkEditAtom<A>::getFileOffset() const
+{
+ return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
+}
+
+
+template <typename A>
+uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
+{
+ return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
+}
+
+template <typename A>
+void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
+}
+
+
+template <typename A>
+uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
+{
+ return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
+}
+
+template <typename A>
+void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
+}
+
+
+
+template <typename A>
+uint64_t SymbolTableLinkEditAtom<A>::getSize() const
+{
+ return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
+}
+
+template <typename A>
+void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ memcpy(buffer, fWriter.fSymbolTable, this->getSize());
+}
+
+template <typename A>
+uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
+{
+ return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
+}
+
+template <typename A>
+void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
+}
+
+
+
+template <typename A>
+uint64_t IndirectTableLinkEditAtom<A>::getSize() const
+{
+ return fTable.size() * sizeof(uint32_t);
+}
+
+template <typename A>
+void IndirectTableLinkEditAtom<A>::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<IndirectEntry>::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 <typename A>
+StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
+ : LinkEditAtom<A>(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 <typename A>
+uint64_t StringsLinkEditAtom<A>::getSize() const
+{
+ return kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
+}
+
+template <typename A>
+void StringsLinkEditAtom<A>::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);
+}
+
+template <typename A>
+int32_t StringsLinkEditAtom<A>::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 <typename A>
+int32_t StringsLinkEditAtom<A>::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 <typename A>
+BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
+ : WriterAtom<A>(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<ppc>::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<ppc64>::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<ppc>::getSize() const
+{
+ return 4;
+}
+
+template <>
+uint64_t BranchIslandAtom<ppc64>::getSize() const
+{
+ return 4;
+}
+
+
+template <>
+bool StubAtom<ppc64>::pic() const
+{
+ // no-pic stubs for ppc64 don't work if lazy pointer is above low 2GB.
+ // This usually only happens when a large zero-page is requested
+ switch ( fWriter.fOptions.outputKind() ) {
+ case Options::kDynamicExecutable:
+ return (fWriter.fOptions.zeroPageSize() > 4096);
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ return true;
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kStaticExecutable:
+ break;
+ }
+ throw "internal ld64 error: file type does not use stubs";
+}
+
+template <>
+bool StubAtom<ppc>::pic() const
+{
+ return ( fWriter.fOptions.outputKind() != Options::kDynamicExecutable );
+}
+
+
+template <>
+StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target)
+ : WriterAtom<ppc>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
+{
+ writer.fAllSynthesizedStubs.push_back(this);
+
+ LazyPointerAtom<ppc>* lp = new LazyPointerAtom<ppc>(writer, target);
+ if ( pic() ) {
+ // picbase is 8 bytes into atom
+ fReferences.push_back(new WriterReference<ppc>(12, ppc::kPICBaseHigh16, lp, 0, NULL, 8));
+ fReferences.push_back(new WriterReference<ppc>(20, ppc::kPICBaseLow16, lp, 0, NULL, 8));
+ }
+ else {
+ fReferences.push_back(new WriterReference<ppc>(0, ppc::kAbsHigh16AddLow, lp));
+ fReferences.push_back(new WriterReference<ppc>(4, ppc::kAbsLow16, lp));
+ }
+}
+
+template <>
+StubAtom<ppc64>::StubAtom(Writer<ppc64>& writer, ObjectFile::Atom& target)
+ : WriterAtom<ppc64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
+{
+ writer.fAllSynthesizedStubs.push_back(this);
+
+ LazyPointerAtom<ppc64>* lp = new LazyPointerAtom<ppc64>(writer, target);
+ if ( pic() ) {
+ // picbase is 8 bytes into atom
+ fReferences.push_back(new WriterReference<ppc64>(12, ppc64::kPICBaseHigh16, lp, 0, NULL, 8));
+ fReferences.push_back(new WriterReference<ppc64>(20, ppc64::kPICBaseLow14, lp, 0, NULL, 8));
+ }
+ else {
+ fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
+ fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
+ }
+}
+
+// specialize to put x86 fast stub in __IMPORT segment with no lazy pointer
+template <>
+StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target)
+ : WriterAtom<x86>(writer, Segment::fgImportSegment), fName(stubName(target.getName())), fTarget(target)
+{
+ writer.fAllSynthesizedStubs.push_back(this);
+}
+
+
+template <typename A>
+const char* StubAtom<A>::stubName(const char* name)
+{
+ char* buf;
+ asprintf(&buf, "%s$stub", name);
+ return buf;
+}
+
+template <>
+uint64_t StubAtom<ppc>::getSize() const
+{
+ return ( pic() ? 32 : 16 );
+}
+
+template <>
+uint64_t StubAtom<ppc64>::getSize() const
+{
+ return ( pic() ? 32 : 16 );
+}
+
+template <>
+uint64_t StubAtom<x86>::getSize() const
+{
+ return 5;
+}
+
+
+template <>
+uint8_t StubAtom<x86>::getAlignment() const
+{
+ // special case x86 fast stubs to be byte aligned
+ return 0;
+}
+
+template <>
+void StubAtom<ppc64>::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<ppc>::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<x86>::copyRawContent(uint8_t buffer[]) const
+{
+ buffer[0] = 0xF4;
+ buffer[1] = 0xF4;
+ buffer[2] = 0xF4;
+ buffer[3] = 0xF4;
+ buffer[4] = 0xF4;
+}
+
+
+template <>
+const char* StubAtom<ppc>::getSectionName() const
+{
+ return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
+}
+
+template <>
+const char* StubAtom<ppc64>::getSectionName() const
+{
+ return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
+}
+
+template <>
+const char* StubAtom<x86>::getSectionName() const
+{
+ return "__jump_table";
+}
+
+
+
+
+
+template <typename A>
+LazyPointerAtom<A>::LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
+ : WriterAtom<A>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target)
+{
+ writer.fAllSynthesizedLazyPointers.push_back(this);
+
+ fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
+}
+
+
+
+template <typename A>
+const char* LazyPointerAtom<A>::lazyPointerName(const char* name)
+{
+ char* buf;
+ asprintf(&buf, "%s$lazy_pointer", name);
+ return buf;
+}
+
+template <typename A>
+void LazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ bzero(buffer, getSize());
+}
+
+
+template <typename A>
+NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
+ : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(target.getName())), fTarget(target)
+{
+ writer.fAllSynthesizedNonLazyPointers.push_back(this);
+
+ fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
+}
+
+template <typename A>
+const char* NonLazyPointerAtom<A>::nonlazyPointerName(const char* name)
+{
+ char* buf;
+ asprintf(&buf, "%s$non_lazy_pointer", name);
+ return buf;
+}
+
+template <typename A>
+void NonLazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ bzero(buffer, getSize());
+}
+
+
+
+}; // namespace executable
+}; // namespace mach_o
+
+
+#endif // __EXECUTABLE_MACH_O__
+++ /dev/null
-/*
- * 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 <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <fcntl.h>
-#include <mach-o/loader.h>
-#include <mach-o/fat.h>
-#include <mach-o/stab.h>
-
-
-#include "ObjectFile.h"
-#include "ObjectFileMachO-all.h"
-
- __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;
-}
-
-static void dumpStabs(std::vector<ObjectFile::StabsInfo>* stabs)
-{
- // debug info
- const int stabCount = stabs->size();
- printf("stabs: (%u)\n", stabCount);
- for (int i=0; i < stabCount; ++i) {
- ObjectFile::StabsInfo& stab = (*stabs)[i];
- 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_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(" %08X %02X %04X %s %s\n", (uint32_t)stab.atomOffset, stab.other, stab.desc, code, stab.string);
- }
-}
-
-
-static void dumpAtom(ObjectFile::Atom* atom)
-{
- //printf("atom: %p\n", atom);
-
- // name
- printf("name: %s\n", atom->getDisplayName());
-
- // scope
- 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");
- }
-
- // segment and section
- printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
-
- // attributes
- printf("attrs: ");
- if ( atom->isWeakDefinition() )
- printf("weak ");
- if ( atom->isCoalesableByName() )
- printf("coalesce-by-name ");
- if ( atom->isCoalesableByValue() )
- printf("coalesce-by-value ");
- if ( atom->dontDeadStrip() )
- printf("dont-dead-strip ");
- if ( atom->isZeroFill() )
- printf("zero-fill ");
- printf("\n");
-
- // size
- printf("size: 0x%012llX\n", atom->getSize());
-
- // alignment
- printf("align: %d\n", atom->getAlignment());
-
- // content
- uint64_t size = atom->getSize();
- if ( size < 4096 ) {
- uint8_t content[size];
- atom->copyRawContent(content);
- printf("content: ");
- if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
- printf("\"%s\"", content);
- }
- else {
- for (unsigned int i=0; i < size; ++i)
- printf("%02X ", content[i]);
- }
- }
- printf("\n");
-
- // references
- std::vector<ObjectFile::Reference*>& 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());
- }
-
- // debug info
- std::vector<ObjectFile::StabsInfo>* stabs = atom->getStabsDebugInfo();
- if ( stabs != NULL )
- dumpStabs(stabs);
-}
-
-
-static void dumpFile(ObjectFile::Reader* reader)
-{
-#if 0
- // debug info
- std::vector<ObjectFile::StabsInfo>* stabs = reader->getStabsDebugInfo();
- if ( stabs != NULL )
- dumpStabs(stabs);
-#endif
- // atom content
- std::vector<ObjectFile::Atom*> atoms = reader->getAtoms();
- const int atomCount = atoms.size();
- for(int i=0; i < atomCount; ++i) {
- dumpAtom(atoms[i]);
- printf("\n");
- }
-}
-
-
-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 )
- throw "cannot open file";
- ::fstat(fd, &stat_buf);
- char* p = (char*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE, 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 < fh->nfat_arch; ++i) {
- if ( archs[i].cputype == CPU_TYPE_POWERPC64 ) {
- p = p + archs[i].offset;
- mh = (struct mach_header*)p;
- }
- }
- }
- if ( mh->magic == MH_MAGIC ) {
- if ( mh->filetype == MH_OBJECT ) {
- switch ( mh->cputype ) {
- case CPU_TYPE_I386:
- return i386::ObjectFileMachO::MakeReader((class i386::macho_header*)mh, path, options);
- case CPU_TYPE_POWERPC:
- return ppc::ObjectFileMachO::MakeReader((class ppc::macho_header*)mh, path, options);
- case CPU_TYPE_POWERPC64:
- return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
- default:
- throw "unknown mach-o cpu type";
- }
- }
- if ( mh->filetype == MH_DYLIB )
- return ppc::ObjectFileDylibMachO::MakeReader((class ppc::macho_header*)mh, path, options);
- throw "unknown mach-o file type";
- }
- else if ( mh->magic == MH_MAGIC_64 ) {
- if ( mh->filetype == MH_OBJECT )
- return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
- if ( mh->filetype == MH_DYLIB )
- return ppc64::ObjectFileDylibMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
- throw "unknown mach-o file type";
- }
- else if ( mh->magic == OSSwapInt32(MH_MAGIC) ) {
- if ( mh->filetype == OSSwapInt32(MH_OBJECT) ) {
- switch ( OSSwapInt32(mh->cputype) ) {
- case CPU_TYPE_I386:
- return i386::ObjectFileMachO::MakeReader((class i386::macho_header*)mh, path, options);
- case CPU_TYPE_POWERPC:
- return ppc::ObjectFileMachO::MakeReader((class ppc::macho_header*)mh, path, options);
- case CPU_TYPE_POWERPC64:
- return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
- default:
- throw "unknown mach-o cpu type";
- }
- }
- if ( mh->filetype == OSSwapInt32(MH_DYLIB) )
- return ppc::ObjectFileDylibMachO::MakeReader((class ppc::macho_header*)mh, path, options);
- throw "unknown mach-o file type";
- }
- else if ( mh->magic == OSSwapInt32(MH_MAGIC_64) ) {
- if ( mh->filetype == OSSwapInt32(MH_OBJECT) )
- return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
- if ( mh->filetype == OSSwapInt32(MH_DYLIB) )
- return ppc64::ObjectFileDylibMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
- throw "unknown mach-o file type";
- }
- throw "unknown file type";
-}
-
-
-int main(int argc, const char* argv[])
-{
- ObjectFile::ReaderOptions options;
- //const char* path = argv[1];
- //ObjectFile::Reader* reader = ObjectFile::Reader::createReader(path);
- try {
- ObjectFile::Reader* reader = createReader("/tmp/gcov-1.o", options);
-
- dumpFile(reader);
- }
- catch (const char* msg) {
- fprintf(stderr, "ObjDump failed: %s\n", msg);
- }
-
- return 0;
-}
-
-
-
--- /dev/null
+/* -*- 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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <fcntl.h>
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+#include <mach-o/stab.h>
+
+#include "MachOReaderRelocatable.hpp"
+
+static bool sDumpContent= true;
+static bool sDumpStabs = false;
+static bool sSort = true;
+static cpu_type_t sPreferredArch = CPU_TYPE_POWERPC64;
+
+
+ __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;
+}
+
+static void dumpStabs(std::vector<ObjectFile::Reader::Stab>* stabs)
+{
+ // debug info
+ printf("stabs: (%lu)\n", stabs->size());
+ for (std::vector<ObjectFile::Reader::Stab>::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 dumpAtom(ObjectFile::Atom* atom)
+{
+ //printf("atom: %p\n", atom);
+
+ // name
+ printf("name: %s\n", atom->getDisplayName());
+
+ // scope
+ 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
+ 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;
+ default:
+ printf("scope: unknown\n");
+ }
+
+ // segment and section
+ printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
+
+ // attributes
+ printf("attrs: ");
+ if ( atom->dontDeadStrip() )
+ printf("dont-dead-strip ");
+ if ( atom->isZeroFill() )
+ printf("zero-fill ");
+ printf("\n");
+
+ // size
+ printf("size: 0x%012llX\n", atom->getSize());
+
+ // alignment
+ printf("align: %d\n", atom->getAlignment());
+
+ // content
+ if ( 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("\"%s\"", content);
+ }
+ else {
+ for (unsigned int i=0; i < size; ++i)
+ printf("%02X ", content[i]);
+ }
+ }
+ printf("\n");
+ }
+
+ // references
+ std::vector<ObjectFile::Reference*>& 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
+ std::vector<ObjectFile::LineInfo>* lineInfo = atom->getLineInfo();
+ if ( (lineInfo != NULL) && (lineInfo->size() > 0) ) {
+ printf("line info: (%lu)\n", lineInfo->size());
+ for (std::vector<ObjectFile::LineInfo>::iterator it = lineInfo->begin(); it != lineInfo->end(); ++it) {
+ printf(" offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName);
+ }
+ }
+
+}
+
+struct AtomSorter
+{
+ bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
+ {
+ 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<ObjectFile::Reader::Stab>* stabs = reader->getStabs();
+ if ( stabs != NULL )
+ dumpStabs(stabs);
+ }
+
+ // get all atoms
+ std::vector<ObjectFile::Atom*> atoms = reader->getAtoms();
+
+ // make copy of vector and sort (so output is canonical)
+ std::vector<ObjectFile::Atom*> sortedAtoms(atoms);
+ if ( sSort )
+ std::sort(sortedAtoms.begin(), sortedAtoms.end(), AtomSorter());
+
+ for(std::vector<ObjectFile::Atom*>::iterator it=sortedAtoms.begin(); it != sortedAtoms.end(); ++it) {
+ dumpAtom(*it);
+ printf("\n");
+ }
+}
+
+
+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, 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 < fh->nfat_arch; ++i) {
+ if ( archs[i].cputype == sPreferredArch ) {
+ p = p + archs[i].offset;
+ mh = (struct mach_header*)p;
+ }
+ }
+ }
+ if ( mach_o::relocatable::Reader<x86>::validFile(p) )
+ return mach_o::relocatable::Reader<x86>::make(p, path, 0, options);
+ else if ( mach_o::relocatable::Reader<ppc>::validFile(p) )
+ return mach_o::relocatable::Reader<ppc>::make(p, path, 0, options);
+ else if ( mach_o::relocatable::Reader<ppc64>::validFile(p) )
+ return mach_o::relocatable::Reader<ppc64>::make(p, path, 0, options);
+ throwf("not a mach-o object file: %s", path);
+}
+
+
+int main(int argc, const char* argv[])
+{
+ 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, "-stabs") == 0 ) {
+ sDumpStabs = true;
+ }
+ else if ( strcmp(arg, "-no_sort") == 0 ) {
+ sSort = false;
+ }
+ else if ( strcmp(arg, "-arch") == 0 ) {
+ const char* arch = argv[++i];
+ if ( strcmp(arch, "ppc64") == 0 )
+ sPreferredArch = CPU_TYPE_POWERPC64;
+ else if ( strcmp(arch, "ppc") == 0 )
+ sPreferredArch = CPU_TYPE_POWERPC;
+ else if ( strcmp(arch, "i386") == 0 )
+ sPreferredArch = CPU_TYPE_I386;
+ else
+ throwf("unknown architecture %s", arch);
+ }
+ else {
+ throwf("unknown option: %s\n", arg);
+ }
+ }
+ else {
+ ObjectFile::Reader* reader = createReader(arg, options);
+ dumpFile(reader);
+ }
+ }
+ }
+ catch (const char* msg) {
+ fprintf(stderr, "ObjDump failed: %s\n", msg);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * 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,
* FITNESS FOR A PARTICULAR PURPOSE, 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 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 StabsInfo
+
+struct LineInfo
{
- uint64_t atomOffset;
- const char* string;
- uint8_t type;
- uint8_t other;
- uint16_t desc;
+ uint32_t atomOffset;
+ const char* fileName;
+ uint32_t lineNumber;
};
+
class ReaderOptions
{
public:
- ReaderOptions() : fFullyLoadArchives(false), fLoadObjcClassesInArchives(false), fFlatNamespace(false),
- fStripDebugInfo(false), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false) {}
+ ReaderOptions() : fFullyLoadArchives(false), fLoadObjcClassesInArchives(false), fFlatNamespace(false),
+ fDebugInfoStripping(kDebugInfoFull), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false), fTraceOutputFile(NULL) {}
+ enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull };
bool fFullyLoadArchives;
bool fLoadObjcClassesInArchives;
bool fFlatNamespace;
- bool fStripDebugInfo;
+ DebugInfoStripping fDebugInfoStripping;
bool fTraceDylibs;
bool fTraceIndirectDylibs;
bool fTraceArchives;
+ const char* fTraceOutputFile;
};
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;
+ };
+
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<class Atom*>& getAtoms() = 0;
virtual std::vector<class Atom*>* getJustInTimeAtomsFor(const char* name) = 0;
- virtual std::vector<StabsInfo>* getStabsDebugInfo() = 0;
-
+ virtual std::vector<Stab>* getStabs() = 0;
+ unsigned int getSortOrder() const { return fSortOrder; }
+ void setSortOrder(unsigned int order) { fSortOrder=order; }
+
// For Dynamic Libraries only
virtual const char* getInstallPath() { return NULL; }
virtual uint32_t getTimestamp() { return 0; }
virtual uint32_t getCompatibilityVersion() { return 0; }
virtual std::vector<const char*>* getDependentLibraryPaths() { return NULL; }
virtual bool reExports(Reader*) { return false; }
- virtual bool isDefinitionWeak(const Atom&){ return false; }
-
-
-
+ virtual const char* parentUmbrella() { return NULL; }
+ virtual std::vector<const char*>* getAllowableClients() { return NULL; }
+
protected:
- Reader() {}
+ Reader() : fSortOrder(0) {}
virtual ~Reader() {}
+
+ unsigned int fSortOrder;
};
class Segment
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; }
class Reference;
-class Section
+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;
};
-class ContentWriter
-{
-public:
- virtual void write(uint64_t atomOffset, const void* buffer, uint64_t size) = 0;
-protected:
- ContentWriter() {}
- virtual ~ContentWriter() {}
-};
-class Atom
+//
+// 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)
+//
+class Atom
{
public:
enum Scope { scopeTranslationUnit, scopeLinkageUnit, scopeGlobal };
- enum WeakImportSetting { kWeakUnset, kWeakImport, kNonWeakImport };
-
+ enum DefinitionKind { kRegularDefinition, kWeakDefinition, kTentativeDefinition, kExternalDefinition, kExternalWeakDefinition };
+ enum SymbolTableInclusion { kSymbolTableNotIn, kSymbolTableIn, kSymbolTableInAndNeverStrip };
+
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 bool isTentativeDefinition() const = 0;
- virtual bool isWeakDefinition() const = 0;
- virtual bool isCoalesableByName() const = 0;
- virtual bool isCoalesableByValue() const = 0;
+ virtual DefinitionKind getDefinitionKind() const = 0;
+ virtual SymbolTableInclusion getSymbolTableInclusion() const = 0;
virtual bool isZeroFill() const = 0;
- virtual bool dontDeadStrip() const = 0;
- virtual bool dontStripName() const = 0; // referenced dynamically
- virtual bool isImportProxy() const = 0;
virtual uint64_t getSize() const = 0;
virtual std::vector<ObjectFile::Reference*>& getReferences() const = 0;
virtual bool mustRemainInSection() const = 0;
virtual Segment& getSegment() const = 0;
virtual bool requiresFollowOnAtom() const = 0;
virtual Atom& getFollowOnAtom() const = 0;
- virtual std::vector<StabsInfo>* getStabsDebugInfo() const = 0;
+ virtual std::vector<LineInfo>* getLineInfo() const = 0;
virtual uint8_t getAlignment() const = 0;
- virtual WeakImportSetting getImportWeakness() const = 0;
virtual void copyRawContent(uint8_t buffer[]) const = 0;
- virtual void writeContent(bool finalLinkedImage, ContentWriter&) const = 0;
virtual void setScope(Scope) = 0;
- virtual void setImportWeakness(bool weakImport) = 0;
-
+
uint64_t getSectionOffset() const { return fSectionOffset; }
uint64_t getSegmentOffset() const { return fSegmentOffset; }
uint64_t getAddress() const { return fSection->getBaseAddress() + fSectionOffset; }
unsigned int getSortOrder() const { return fSortOrder; }
class Section* getSection() const { return fSection; }
+ bool dontDeadStrip() const { return fDontDeadStrip; }
void setSegmentOffset(uint64_t offset) { fSegmentOffset = offset; }
void setSectionOffset(uint64_t offset) { fSectionOffset = offset; }
- void setSection(class Section* sect) { fSection = sect; }
+ void setSection(class Section* sect) { fSection = sect; }
unsigned int setSortOrder(unsigned int order); // recursively sets follow-on atoms
+ void setDontDeadStrip() { fDontDeadStrip = true; }
protected:
- Atom() : fSegmentOffset(0), fSectionOffset(0), fSortOrder(0), fSection(NULL) {}
+ Atom() : fSegmentOffset(0), fSectionOffset(0), fSortOrder(0), fSection(NULL), fDontDeadStrip(false) {}
virtual ~Atom() {}
-
+
uint64_t fSegmentOffset;
uint64_t fSectionOffset;
unsigned int fSortOrder;
class Section* fSection;
+ bool fDontDeadStrip;
};
+//
+// 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 Kind { noFixUp, pointer, ppcFixupBranch24, ppcFixupBranch14,
- ppcFixupPicBaseLow16, ppcFixupPicBaseLow14, ppcFixupPicBaseHigh16,
- ppcFixupAbsLow16, ppcFixupAbsLow14, ppcFixupAbsHigh16, ppcFixupAbsHigh16AddLow,
- pointer32Difference, pointer64Difference, x86FixupBranch32 };
virtual bool isTargetUnbound() const = 0;
virtual bool isFromTargetUnbound() const = 0;
- virtual bool requiresRuntimeFixUp(bool slideable) const = 0;
- virtual bool isWeakReference() const = 0;
- virtual bool isLazyReference() const = 0;
- virtual Kind getKind() 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 void setTarget(Atom&, uint64_t offset) = 0;
virtual void setFromTarget(Atom&) = 0;
virtual const char* getDescription() const = 0;
-
+
protected:
Reference() {}
virtual ~Reference() {}
#endif // __OBJECTFILE__
-
-
-
-
-
-
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+/* -*- 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,
* FITNESS FOR A PARTICULAR PURPOSE, 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 <sys/types.h>
#include <sys/stat.h>
+#include <math.h>
#include <fcntl.h>
#include <vector>
#include "Options.h"
- __attribute__((noreturn))
-void throwf(const char* format, ...)
+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(CPU_TYPE_POWERPC64), fOutputKind(kDynamicExecutable), fBindAtLoad(false),
- fStripLocalSymbols(false), fKeepPrivateExterns(false),
- fInterposable(false), fIgnoreOtherArchFiles(false), fForceSubtypeAll(false), fNameSpace(kTwoLevelNameSpace),
- fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fEntryName("start"), fBaseAddress(0),
- fExportMode(kExportDefault), fLibrarySearchMode(kSearchAllDirsForDylibsThenAllDirsForArchives),
- fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(false), fPICTreatment(kPICError),
- fWeakReferenceMismatchTreatment(kWeakReferenceMismatchError),
- fUmbrellaName(NULL), fInitFunctionName(NULL), fZeroPageSize(0x1000), fStackSize(0), fStackAddr(0), fMinimumHeaderPad(0),
- fCommonsMode(kCommonsIgnoreDylibs), fWarnCommons(false), fVerbose(false)
+ : fOutputFile("a.out"), fArchitecture(0), fOutputKind(kDynamicExecutable), fBindAtLoad(false),
+ fStripLocalSymbols(false), fKeepPrivateExterns(false),
+ fInterposable(false), fIgnoreOtherArchFiles(false), fForceSubtypeAll(false), fDeadStrip(kDeadStripOff),
+ fVersionMin(k10_1),fNameSpace(kTwoLevelNameSpace),
+ fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fEntryName("start"), fBaseAddress(0),
+ fExportMode(kExportDefault), fLibrarySearchMode(kSearchAllDirsForDylibsThenAllDirsForArchives),
+ fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(false), fPICTreatment(kError),
+ fWeakReferenceMismatchTreatment(kWeakReferenceMismatchError), fMultiplyDefinedDynamic(kWarning),
+ fMultiplyDefinedUnused(kSuppress), fWarnOnMultiplyDefined(false), fClientName(NULL),
+ fUmbrellaName(NULL), fInitFunctionName(NULL), fDotOutputFile(NULL), fExecutablePath(NULL),
+ fZeroPageSize(0x1000), fStackSize(0), fStackAddr(0), fExecutableStack(false), fMinimumHeaderPad(0),
+ fCommonsMode(kCommonsIgnoreDylibs), fWarnCommons(false), fVerbose(false), fKeepRelocations(false),
+ fEmitUUID(true),fWarnStabs(false),
+ fTraceDylibSearching(false), fPause(false), fStatistics(false), fPrintOptions(false)
{
this->parsePreCommandLineEnvironmentSettings();
this->parse(argc, argv);
{
}
-
-ObjectFile::ReaderOptions& Options::readerOptions()
+const ObjectFile::ReaderOptions& Options::readerOptions()
{
return fReaderOptions;
}
return fArchitecture;
}
-
const char* Options::getOutputFilePath()
{
return fOutputFile;
}
-
std::vector<Options::FileInfo>& Options::getInputFiles()
{
return fInputFiles;
return fStripLocalSymbols;
}
-bool Options::stripDebugInfo()
+bool Options::bindAtLoad()
{
- return fReaderOptions.fStripDebugInfo;
+ return fBindAtLoad;
}
-bool Options::bindAtLoad()
+bool Options::prebind()
{
- return fBindAtLoad;
+ return fPrebind;
}
bool Options::fullyLoadArchives()
const char* Options::installPath()
{
- if ( fDylibInstallName != NULL )
+ if ( fDylibInstallName != NULL )
return fDylibInstallName;
else
return fOutputFile;
return fUndefinedTreatment;
}
+Options::VersionMin Options::macosxVersionMin()
+{
+ return fVersionMin;
+}
+
Options::WeakReferenceMismatchTreatment Options::weakReferenceMismatchTreatment()
{
return fWeakReferenceMismatchTreatment;
}
+Options::Treatment Options::multipleDefinitionsInDylibs()
+{
+ return fMultiplyDefinedDynamic;
+}
+
+Options::Treatment Options::overridingDefinitionInDependentDylib()
+{
+ return fMultiplyDefinedUnused;
+}
+
+bool Options::warnOnMultipleDefinitionsInObjectFiles()
+{
+ return fWarnOnMultiplyDefined;
+}
+
const char* Options::umbrellaName()
{
return fUmbrellaName;
}
+std::vector<const char*>& Options::allowableClients()
+{
+ return fAllowableClients;
+}
+
+const char* Options::clientName()
+{
+ return fClientName;
+}
+
uint64_t Options::zeroPageSize()
{
return fZeroPageSize;
{
return (fStackSize != 0);
}
-
+
uint64_t Options::customStackSize()
{
return fStackSize;
return fStackAddr;
}
+bool Options::hasExecutableStack()
+{
+ return fExecutableStack;
+}
+
std::vector<const char*>& Options::initialUndefines()
{
return fInitialUndefines;
}
+std::vector<const char*>& Options::traceSymbols()
+{
+ return fTraceSymbols;
+}
+
const char* Options::initFunctionName()
{
return fInitFunctionName;
}
+const char* Options::dotOutputFile()
+{
+ return fDotOutputFile;
+}
+
bool Options::hasExportRestrictList()
{
return (fExportMode != kExportDefault);
return fSectionAlignments;
}
-
Options::CommonsMode Options::commonsMode()
{
return fCommonsMode;
return fWarnCommons;
}
+bool Options::keepRelocations()
+{
+ return fKeepRelocations;
+}
+
+bool Options::emitUUID()
+{
+ return fEmitUUID;
+}
+
+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) {
throw "internal error";
}
-
void Options::parseArch(const char* architecture)
{
if ( architecture == NULL )
fArchitecture = CPU_TYPE_POWERPC64;
else if ( strcmp(architecture, "i386") == 0 )
fArchitecture = CPU_TYPE_I386;
- else
+ else
throw "-arch followed by unknown architecture name";
}
bool Options::checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result)
{
struct stat statBuffer;
- char possiblePath[strlen(dir)+strlen(rootName)+20];
+ char possiblePath[strlen(dir)+strlen(rootName)+strlen(format)+8];
sprintf(possiblePath, format, dir, rootName);
- if ( stat(possiblePath, &statBuffer) == 0 ) {
+ 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)
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<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
+ for (std::vector<const char*>::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:
+ case kSearchAllDirsForDylibsThenAllDirsForArchives:
// first look in all directories for just for dylibs
if ( lookForDylibs ) {
- for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
+ for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+ it != fLibrarySearchPaths.end();
+ it++) {
const char* dir = *it;
if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) )
return result;
}
}
// next look in all directories for just for archives
- for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
+ for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+ it != fLibrarySearchPaths.end();
+ it++) {
const char* dir = *it;
if ( checkForFile("%s/lib%s.a", dir, rootName, result) )
return result;
case kSearchDylibAndArchiveInEachDir:
// look in each directory for just for a dylib then for an archive
- for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
+ for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+ it != fLibrarySearchPaths.end();
+ it++) {
const char* dir = *it;
if ( lookForDylibs && checkForFile("%s/lib%s.dylib", dir, rootName, result) )
return result;
{
struct stat statBuffer;
const int rootNameLen = strlen(rootName);
- for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin(); it != fFrameworkSearchPaths.end(); it++) {
+ for (std::vector<const char*>::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[strlen(dir)+2*rootNameLen+20];
strcpy(possiblePath, dir);
strcat(possiblePath, rootName);
strcat(possiblePath, ".framework/");
strcat(possiblePath, rootName);
- if ( stat(possiblePath, &statBuffer) == 0 ) {
+ 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;
}
}
{
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<const char*>::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];
if ( stat(possiblePath, &statBuffer) == 0 ) {
result.path = strdup(possiblePath);
result.fileLen = statBuffer.st_size;
+ result.modTime = statBuffer.st_mtime;
return result;
}
}
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);
}
void Options::loadFileList(const char* fileOfPaths)
{
FILE* file = fopen(fileOfPaths, "r");
- if ( file == NULL )
+ if ( file == NULL )
throwf("-filelist file not found: %s\n", fileOfPaths);
-
+
char path[1024];
while ( fgets(path, 1024, file) != NULL ) {
path[1023] = '\0';
char* eol = strchr(path, '\n');
if ( eol != NULL )
*eol = '\0';
-
+
fInputFiles.push_back(findFile(path));
}
fclose(file);
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 = '\0';
- // removing any trailing spaces
- char* last = s-1;
- while ( isspace(*last) ) {
- *last = '\0';
- --last;
- }
- set.insert(symbolStart);
- symbolStart = NULL;
- state = lineStart;
+ case lineStart:
+ if ( *s =='#' ) {
+ state = inComment;
+ }
+ else if ( !isspace(*s) ) {
+ state = inSymbol;
+ symbolStart = s;
+ }
+ break;
+ case inSymbol:
+ if ( *s == '\n' ) {
+ *s = '\0';
+ // removing any trailing spaces
+ char* last = s-1;
+ while ( isspace(*last) ) {
+ *last = '\0';
+ --last;
}
- break;
- case inComment:
- if ( *s == '\n' )
- state = lineStart;
- break;
+ set.insert(symbolStart);
+ symbolStart = NULL;
+ state = lineStart;
+ }
+ break;
+ case inComment:
+ if ( *s == '\n' )
+ state = lineStart;
+ break;
+ }
+ }
+ if ( state == inSymbol ) {
+ fprintf(stderr, "ld64 warning: missing line-end at end of file \"%s\"\n", 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::setUndefinedTreatment(const char* treatment)
{
- if ( treatment == NULL )
+ if ( treatment == NULL )
throw "-undefined missing [ warning | error | suppress | dynamic_lookup ]";
if ( strcmp(treatment, "warning") == 0 )
throw "invalid option to -undefined [ warning | error | suppress | dynamic_lookup ]";
}
-void Options::setReadOnlyRelocTreatment(const char* treatment)
+Options::Treatment Options::parseTreatment(const char* treatment)
{
- if ( treatment == NULL )
- throw "-read_only_relocs missing [ warning | error | suppress ]";
+ if ( treatment == NULL )
+ return kNULL;
if ( strcmp(treatment, "warning") == 0 )
- throw "-read_only_relocs warning not supported";
+ return kWarning;
+ else if ( strcmp(treatment, "error") == 0 )
+ return kError;
else if ( strcmp(treatment, "suppress") == 0 )
- throw "-read_only_relocs suppress not supported";
- else if ( strcmp(treatment, "error") != 0 )
- throw "invalid option to -read_only_relocs [ warning | error | suppress | dynamic_lookup ]";
+ return kSuppress;
+ else
+ return kInvalid;
}
-void Options::setPICTreatment(const char* treatment)
-{
- if ( treatment == NULL )
- throw "-sect_diff_relocs missing [ warning | error | suppress ]";
-
- if ( strcmp(treatment, "warning") == 0 )
- fPICTreatment = kPICWarning;
- else if ( strcmp(treatment, "error") == 0 )
- fPICTreatment = kPICError;
- else if ( strcmp(treatment, "suppress") == 0 )
- fPICTreatment = kPICSuppress;
+void Options::setVersionMin(const char* version)
+{
+ if ( version == NULL )
+ throw "-macosx_version_min argument missing";
+
+ if ( strcmp(version, "10.1") == 0 )
+ fVersionMin = k10_1;
+ else if ( strcmp(version, "10.2") == 0)
+ fVersionMin = k10_2;
+ else if ( strcmp(version, "10.3") == 0)
+ fVersionMin = k10_3;
+ else if ( strcmp(version, "10.4") == 0)
+ fVersionMin = k10_4;
+ else if ( strcmp(version, "10.5") == 0)
+ fVersionMin = k10_5;
else
- throw "invalid option to -sect_diff_relocs [ warning | error | suppress ]";
+ fprintf(stderr, "ld64: unknown option to -macosx_version_min");
}
void Options::setWeakReferenceMismatchTreatment(const char* treatment)
{
- if ( treatment == NULL )
+ if ( treatment == NULL )
throw "-weak_reference_mismatches missing [ error | weak | non-weak ]";
if ( strcmp(treatment, "error") == 0 )
Options::CommonsMode Options::parseCommonsTreatment(const char* mode)
{
- if ( mode == NULL )
+ if ( mode == NULL )
throw "-commons missing [ ignore_dylibs | use_dylibs | error ]";
if ( strcmp(mode, "ignore_dylibs") == 0 )
throw "invalid option to -commons [ ignore_dylibs | use_dylibs | error ]";
}
-
void Options::setDylibInstallNameOverride(const char* paths)
{
}
-void Options::setExecutablePath(const char* path)
-{
-
-
-}
-
-
-
-
uint64_t Options::parseAddress(const char* addr)
{
char* endptr;
return result;
}
-
-
//
-// Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz
+// 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)
{
if ( strlen(segment) > 16 )
throw "-seccreate segment name max 16 chars";
- if ( strlen(section) > 16 )
- throw "-seccreate section name max 16 chars";
+ if ( strlen(section) > 16 ) {
+ char* tmp = strdup(section);
+ tmp[16] = '\0';
+ fprintf(stderr, "ld64 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 ( 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);
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";
- uint8_t alignment = 0;
- for(unsigned long x=value; x != 1; x >>= 1)
- ++alignment;
- if ( (unsigned long)(1 << alignment) != value )
- throw "argument for -sectalign is not a power of two";
+ if ( value == 0 ) {
+ fprintf(stderr, "ld64 warning: zero is not a valid -sectalign\n");
+ value = 1;
+ }
+
+ // alignment is power of 2 (e.g. page alignment = 12)
+ uint8_t alignment = (uint8_t)log2(value);
+
+ if ( (unsigned long)(1 << alignment) != value ) {
+ fprintf(stderr, "ld64 warning: alignment for -sectalign %s %s is not a power of two, using 0x%X\n",
+ segment, section, 1 << alignment);
+ }
SectionAlignment info = { segment, section, alignment };
fSectionAlignments.push_back(info);
}
-
+//
+// 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()
}
else if ( arg[1] == 'l' ) {
fInputFiles.push_back(findLibrary(&arg[2]));
}
- else if ( strcmp(arg, "-weak-l") == 0 ) {
- FileInfo info = 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;
fInputFiles.push_back(info);
}
+ // Avoid lazy binding.
+ // ??? Deprecate.
else if ( strcmp(arg, "-bind_at_load") == 0 ) {
fBindAtLoad = true;
}
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;
}
+ // Similar to --whole-archive, but for all ObjC classes.
else if ( strcmp(arg, "-ObjC") == 0 ) {
fReaderOptions.fLoadObjcClassesInArchives = true;
}
+ // Library versioning.
else if ( strcmp(arg, "-dylib_compatibility_version") == 0 ) {
fDylibCompatVersion = parseVersionNumber(argv[++i]);
}
parseSectionOrderFile(argv[i+1], argv[i+2], argv[i+3]);
i += 3;
}
+ // ??? Deprecate segcreate.
+ // -sectcreate puts whole files into a section in the output.
else if ( (strcmp(arg, "-sectcreate") == 0) || (strcmp(arg, "-segcreate") == 0) ) {
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) ) {
fDylibInstallName = argv[++i];
}
+ // Sets the base address of the output.
else if ( strcmp(arg, "-seg1addr") == 0 ) {
fBaseAddress = parseAddress(argv[++i]);
}
else if ( strcmp(arg, "-e") == 0 ) {
fEntryName = argv[++i];
}
+ // Same as -@ from the FSF linker.
else if ( strcmp(arg, "-filelist") == 0 ) {
loadFileList(argv[++i]);
}
else if ( strcmp(arg, "-keep_private_externs") == 0 ) {
fKeepPrivateExterns = true;
}
+ // ??? Deprecate
else if ( strcmp(arg, "-final_output") == 0 ) {
++i;
// ignore for now
}
+ // 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)) {
fInterposable = true;
}
+ // Default for -interposable/-multi_module/-single_module.
else if ( strcmp(arg, "-single_module") == 0 ) {
fInterposable = false;
}
fExportMode = kDontExportSome;
loadExportFile(argv[++i], "-unexported_symbols_list", fDontExportSymbols);
}
+ // ??? 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;
info.options.fWeakImport = true;
fInputFiles.push_back(info);
}
+ // ??? Deprecate when we get -Bstatic/-Bdynamic.
else if ( strcmp(arg, "-search_paths_first") == 0 ) {
fLibrarySearchMode = kSearchDylibAndArchiveInEachDir;
}
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 ) {
- setReadOnlyRelocTreatment(argv[++i]);
+ Treatment temp = parseTreatment(argv[++i]);
+
+ if ( temp == kNULL )
+ throw "-read_only_relocs missing [ warning | error | suppress ]";
+ else if ( temp == kInvalid )
+ throw "invalid option to -read_only_relocs [ warning | error | suppress ]";
}
+ // Specifies whether or not there are intra section
+ // relocations and what to do when found. Could be
+ // errors, warnings, or suppressed.
else if ( strcmp(arg, "-sect_diff_relocs") == 0 ) {
- setPICTreatment(argv[++i]);
+ fPICTreatment = parseTreatment(argv[++i]);
+
+ if ( fPICTreatment == kNULL )
+ throw "-sect_diff_relocs missing [ warning | error | suppress ]";
+ else if ( fPICTreatment == kInvalid )
+ throw "invalid option to -sect_diff_relocs [ warning | error | suppress ]";
}
+ // 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 ) {
- // FIX FIX
+ fPrebind = true;
}
else if ( strcmp(arg, "-noprebind") == 0 ) {
- // FIX FIX
+ fPrebind = false;
}
+ // ??? Deprecate
else if ( strcmp(arg, "-prebind_allow_overlap") == 0 ) {
- // FIX FIX
+ // Do not handle and suppress warnings always.
}
+ // ??? Deprecate
else if ( strcmp(arg, "-prebind_all_twolevel_modules") == 0 ) {
- // FIX FIX
+ // Ignore.
}
+ // ??? Deprecate
else if ( strcmp(arg, "-noprebind_all_twolevel_modules") == 0 ) {
- // FIX FIX
+ // Ignore.
}
+ // Sets a bit in the main executable only that causes fix_prebinding
+ // not to run. This is always set.
else if ( strcmp(arg, "-nofixprebinding") == 0 ) {
- // FIX FIX
+ // Ignore.
}
+ // This should probably be deprecated when we respect -L and -F
+ // when searching for libraries.
else if ( strcmp(arg, "-dylib_file") == 0 ) {
setDylibInstallNameOverride(argv[++i]);
}
+ // Allows us to rewrite full paths to be relocatable based on
+ // the path name of the executable.
else if ( strcmp(arg, "-executable_path") == 0 ) {
- setExecutablePath(argv[++i]);
+ fExecutablePath = argv[++i];
+ if ( (fExecutablePath == NULL) || (fExecutablePath[0] == '-') )
+ throw "-executable_path missing <path>";
}
+ // ??? Deprecate
+ // Aligns all segments to the power of 2 boundary specified.
else if ( strcmp(arg, "-segalign") == 0 ) {
- // FIX FIX
- ++i;
+ // Ignore.
+ ++i;
}
+ // Puts a specified segment at a particular address that must
+ // be a multiple of the segment alignment.
else if ( strcmp(arg, "-segaddr") == 0 ) {
// FIX FIX
- i += 2;
+ i += 2;
}
+ // ??? Deprecate when we deprecate split-seg.
else if ( strcmp(arg, "-segs_read_only_addr") == 0 ) {
- // FIX FIX
- ++i;
+ // Ignore.
+ ++i;
}
+ // ??? Deprecate when we deprecate split-seg.
else if ( strcmp(arg, "-segs_read_write_addr") == 0 ) {
- // FIX FIX
- ++i;
+ // Ignore.
+ ++i;
}
+ // ??? Deprecate when we get rid of basing at build time.
else if ( strcmp(arg, "-seg_addr_table") == 0 ) {
- // FIX FIX
- ++i;
+ // Ignore.
+ ++i;
}
+ // ??? Deprecate.
else if ( strcmp(arg, "-seg_addr_table_filename") == 0 ) {
- // FIX FIX
- ++i;
+ // Ignore.
+ ++i;
}
else if ( strcmp(arg, "-segprot") == 0 ) {
// FIX FIX
- i += 3;
+ i += 3;
}
else if ( strcmp(arg, "-pagezero_size") == 0 ) {
fZeroPageSize = parseAddress(argv[++i]);
else if ( strcmp(arg, "-stack_size") == 0 ) {
fStackSize = parseAddress(argv[++i]);
}
+ else if ( strcmp(arg, "-allow_stack_execute") == 0 ) {
+ fExecutableStack = true;
+ }
else if ( strcmp(arg, "-sectalign") == 0 ) {
addSectionAlignment(argv[i+1], argv[i+2], argv[i+3]);
i += 3;
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 ) {
- // This flag isn't needed yet, so just ignore it.
- ++i;
+ setVersionMin(argv[++i]);
}
+ // This option (unlike -m below) only affects how we warn
+ // on multiple definitions inside dynamic libraries.
else if ( strcmp(arg, "-multiply_defined") == 0 ) {
- // FIX FIX
- ++i;
+ fMultiplyDefinedDynamic = parseTreatment(argv[++i]);
+
+ if ( fMultiplyDefinedDynamic == kNULL )
+ throw "-multiply_defined missing [ warning | error | suppress ]";
+ else if ( fMultiplyDefinedDynamic == kInvalid )
+ throw "invalid option to -multiply_defined [ warning | error | suppress ]";
}
else if ( strcmp(arg, "-multiply_defined_unused") == 0 ) {
- // FIX FIX
- ++i;
+ fMultiplyDefinedUnused = parseTreatment(argv[++i]);
+
+ if ( fMultiplyDefinedUnused == kNULL )
+ throw "-multiply_defined_unused missing [ warning | error | suppress ]";
+ else if ( fMultiplyDefinedUnused == kInvalid )
+ throw "invalid option to -multiply_defined_unused [ warning | error | suppress ]";
}
else if ( strcmp(arg, "-nomultidefs") == 0 ) {
// FIX FIX
}
- else if ( arg[1] == 'y' ) {
- // FIX FIX
+ // Display each file in which the argument symbol appears and whether
+ // the file defines or references it. This option takes an argument
+ // as -y<symbol> note that there is no space.
+ else if ( strncmp(arg, "-y", 2) == 0 ) {
+ const char* name = &arg[2];
+
+ if ( name == NULL )
+ throw "-y missing argument";
+
+ fTraceSymbols.push_back(name);
}
+ // Same output as -y, but output <arg> number of undefined symbols only.
else if ( strcmp(arg, "-Y") == 0 ) {
- ++i;
- // FIX FIX
+ char* endptr;
+ fLimitUndefinedSymbols = strtoul (argv[++i], &endptr, 10);
+
+ if(*endptr != '\0')
+ throw "invalid argument for -Y [decimal number]";
}
+ // This option affects all objects linked into the final result.
else if ( strcmp(arg, "-m") == 0 ) {
- // FIX FIX
+ fWarnOnMultiplyDefined = true;
}
else if ( strcmp(arg, "-whyload") == 0 ) {
// FIX FIX
throw "-u missing argument";
fInitialUndefines.push_back(name);
}
- else if ( strcmp(arg, "-i") == 0 ) {
- // FIX FIX
- }
else if ( strcmp(arg, "-U") == 0 ) {
// FIX FIX
- ++i;
+ ++i;
}
else if ( strcmp(arg, "-s") == 0 ) {
- // FIX FIX
+ fStripLocalSymbols = true;
+ fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoNone;
}
else if ( strcmp(arg, "-x") == 0 ) {
- // FIX FIX
+ fStripLocalSymbols = true;
}
else if ( strcmp(arg, "-S") == 0 ) {
- // FIX FIX
+ fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoNone;
}
else if ( strcmp(arg, "-X") == 0 ) {
// FIX FIX
}
else if ( strcmp(arg, "-Si") == 0 ) {
- // FIX FIX
+ fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoFull;
}
else if ( strcmp(arg, "-b") == 0 ) {
// FIX FIX
}
else if ( strcmp(arg, "-Sn") == 0 ) {
- // FIX FIX
+ fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoFull;
+ }
+ else if ( strcmp(arg, "-Sp") == 0 ) {
+ fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoMinimal;
}
else if ( strcmp(arg, "-dead_strip") == 0 ) {
- // FIX FIX
- fprintf(stderr, "ld64: warning -dead_strip not yet supported for 64-bit code\n");
+ //fDeadStrip = kDeadStripOnPlusUnusedInits;
+ fprintf(stderr, "ld64: warning -dead_strip not yet supported in ld64\n");
+ }
+ else if ( strcmp(arg, "-no_dead_strip_inits_and_terms") == 0 ) {
+ //fDeadStrip = kDeadStripOn;
+ fprintf(stderr, "ld64: warning -dead_strip not yet supported in ld64\n");
}
else if ( strcmp(arg, "-w") == 0 ) {
// FIX FIX
}
else if ( strcmp(arg, "-A") == 0 ) {
// FIX FIX
- ++i;
+ ++i;
}
else if ( strcmp(arg, "-umbrella") == 0 ) {
const char* name = argv[++i];
fUmbrellaName = name;
}
else if ( strcmp(arg, "-allowable_client") == 0 ) {
- // FIX FIX
- ++i;
+ const char* name = argv[++i];
+
+ if ( name == NULL )
+ throw "-allowable_client missing argument";
+
+ fAllowableClients.push_back(name);
}
else if ( strcmp(arg, "-client_name") == 0 ) {
- // FIX FIX
- ++i;
+ 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];
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, "-v") == 0 ) {
// previously handled by buildSearchPaths()
}
++i;
// previously handled by buildSearchPaths()
}
+ else if ( strcmp(arg, "-no_uuid") == 0 ) {
+ fEmitUUID = false;
+ }
+ // put this last so that it does not interfer with other options starting with 'i'
+ else if ( strncmp(arg, "-i", 2) == 0 ) {
+ fprintf(stderr, "ld64: -i option (indirect symbols) not supported\n");
+ }
else {
- fprintf(stderr, "unknown option: %s\n", arg);
+ throwf("unknown option: %s", arg);
}
}
else {
}
}
-
-
-//
-// -syslibroot <path> is used for SDK support.
+//
+// -syslibroot <path> 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<const char*> libraryPaths;
std::vector<const char*> 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') )
if ( addStandardLibraryDirectories ) {
libraryPaths.push_back("/usr/lib");
libraryPaths.push_back("/usr/local/lib");
-
+
frameworkPaths.push_back("/Library/Frameworks/");
frameworkPaths.push_back("/Network/Library/Frameworks/");
frameworkPaths.push_back("/System/Library/Frameworks/");
}
-
+
// now merge sdk and library paths to make real search paths
+ fLibrarySearchPaths.reserve(libraryPaths.size()*(fSDKPaths.size()+1));
for (std::vector<const char*>::iterator it = libraryPaths.begin(); it != libraryPaths.end(); it++) {
const char* libDir = *it;
bool sdkOverride = false;
char betterLibDir[PATH_MAX];
if ( strstr(libDir, "/..") != NULL ) {
if ( realpath(libDir, betterLibDir) != NULL )
- libDir = betterLibDir;
+ libDir = strdup(betterLibDir);
}
const int libDirLen = strlen(libDir);
for (std::vector<const char*>::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];
}
}
}
- if ( !sdkOverride )
+ 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<const char*>::iterator it = frameworkPaths.begin(); it != frameworkPaths.end(); it++) {
const char* frameworkDir = *it;
bool sdkOverride = false;
char betterFrameworkDir[PATH_MAX];
if ( strstr(frameworkDir, "/..") != NULL ) {
if ( realpath(frameworkDir, betterFrameworkDir) != NULL )
- frameworkDir = betterFrameworkDir;
+ frameworkDir = strdup(betterFrameworkDir);
}
const int frameworkDirLen = strlen(frameworkDir);
for (std::vector<const char*>::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];
}
}
}
- if ( !sdkOverride )
+ if ( !sdkOverride )
fFrameworkSearchPaths.push_back(frameworkDir);
}
-
+
if ( fVerbose ) {
fprintf(stderr,"Library search paths:\n");
- for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++)
+ for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+ it != fLibrarySearchPaths.end();
+ it++)
fprintf(stderr,"\t%s\n", *it);
fprintf(stderr,"Framework search paths:\n");
- for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin(); it != fFrameworkSearchPaths.end(); it++)
+ for (std::vector<const char*>::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("RC_TRACE_ARCHIVES") != NULL)
+ if ((getenv("LD_TRACE_ARCHIVES") != NULL)
+ || (getenv("RC_TRACE_ARCHIVES") != NULL))
fReaderOptions.fTraceArchives = true;
-
- if ( getenv("RC_TRACE_DYLIBS") != NULL) {
+
+ 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");
}
// 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;
+ }
}
void Options::checkIllegalOptionCombinations()
throw "can't use -undefined warning or suppress with -twolevel_namespace";
break;
}
-
+
// unify -sub_umbrella with dylibs
for (std::vector<const char*>::iterator it = fSubUmbellas.begin(); it != fSubUmbellas.end(); it++) {
const char* subUmbrella = *it;
if ( ! found )
fprintf(stderr, "ld64 warning: -sub_umbrella %s does not match a supplied dylib\n", subUmbrella);
}
-
+
// unify -sub_library with dylibs
for (std::vector<const char*>::iterator it = fSubLibraries.begin(); it != fSubLibraries.end(); it++) {
const char* subLibrary = *it;
if ( ! found )
fprintf(stderr, "ld64 warning: -sub_library %s does not match a supplied dylib\n", subLibrary);
}
-
+
// sync reader options
if ( fNameSpace != kTwoLevelNameSpace )
fReaderOptions.fFlatNamespace = true;
// check -stack_addr
- if ( fStackAddr != 0 ) {
+ if ( fStackAddr != 0 ) {
switch (fArchitecture) {
case CPU_TYPE_I386:
case CPU_TYPE_POWERPC:
- if ( fStackAddr > 0xFFFFFFFF )
+ if ( fStackAddr > 0xFFFFFFFF )
throw "-stack_addr must be < 4G for 32-bit processes";
break;
case CPU_TYPE_POWERPC64:
if ( fStackSize == 0 )
throw "-stack_addr must be used with -stack_size";
}
-
+
// check -stack_size
- if ( fStackSize != 0 ) {
+ if ( fStackSize != 0 ) {
switch (fArchitecture) {
case CPU_TYPE_I386:
case CPU_TYPE_POWERPC:
- if ( fStackSize > 0xFFFFFFFF )
+ if ( fStackSize > 0xFFFFFFFF )
throw "-stack_size must be < 4G for 32-bit processes";
if ( fStackAddr == 0 ) {
fprintf(stderr, "ld64 warning: -stack_addr not specified, using the default 0xC0000000\n");
switch ( fOutputKind ) {
case Options::kDynamicExecutable:
case Options::kStaticExecutable:
- // custom stack size only legeal when building main executable
+ // custom stack size only legal when building main executable
break;
case Options::kDynamicLibrary:
case Options::kDynamicBundle:
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 -bundle is specified
+ if ( (fClientName != NULL) && (fOutputKind != Options::kDynamicBundle) )
+ 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";
-
- // make sure all required exported symbols exist
- for (NameSet::iterator it=fExportSymbols.begin(); it != fExportSymbols.end(); it++)
- fInitialUndefines.push_back(*it);
-
-}
+ // make sure all required exported symbols exist
+ for (NameSet::iterator it=fExportSymbols.begin(); it != fExportSymbols.end(); it++) {
+ const char* name = *it;
+ // never export .eh symbols
+ if ( strcmp(&name[strlen(name)-3], ".eh") != 0 )
+ fInitialUndefines.push_back(name);
+ }
+}
+++ /dev/null
-/* -*- 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 <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <vector>
-
-
-#include "Options.h"
-
- __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;
-}
-
-
-Options::Options(int argc, const char* argv[])
- : fOutputFile("a.out"), fArchitecture(CPU_TYPE_POWERPC64), fOutputKind(kDynamicExecutable), fBindAtLoad(false),
- fStripLocalSymbols(false), fKeepPrivateExterns(false),
- fInterposable(false), fIgnoreOtherArchFiles(false), fForceSubtypeAll(false), fNameSpace(kTwoLevelNameSpace),
- fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fEntryName("start"), fBaseAddress(0),
- fExportMode(kExportDefault), fLibrarySearchMode(kSearchAllDirsForDylibsThenAllDirsForArchives),
- fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(false), fPICTreatment(kPICError),
- fWeakReferenceMismatchTreatment(kWeakReferenceMismatchError),
- fUmbrellaName(NULL), fInitFunctionName(NULL), fZeroPageSize(0x1000), fStackSize(0), fStackAddr(0), fMinimumHeaderPad(0),
- fCommonsMode(kCommonsIgnoreDylibs), fWarnCommons(false), fVerbose(false)
-{
- this->parsePreCommandLineEnvironmentSettings();
- this->parse(argc, argv);
- this->parsePostCommandLineEnvironmentSettings();
- this->checkIllegalOptionCombinations();
-}
-
-Options::~Options()
-{
-}
-
-
-ObjectFile::ReaderOptions& Options::readerOptions()
-{
- return fReaderOptions;
-}
-
-cpu_type_t Options::architecture()
-{
- return fArchitecture;
-}
-
-
-const char* Options::getOutputFilePath()
-{
- return fOutputFile;
-}
-
-
-std::vector<Options::FileInfo>& Options::getInputFiles()
-{
- return fInputFiles;
-}
-
-Options::OutputKind Options::outputKind()
-{
- return fOutputKind;
-}
-
-bool Options::stripLocalSymbols()
-{
- return fStripLocalSymbols;
-}
-
-bool Options::stripDebugInfo()
-{
- return fReaderOptions.fStripDebugInfo;
-}
-
-bool Options::bindAtLoad()
-{
- return fBindAtLoad;
-}
-
-bool Options::fullyLoadArchives()
-{
- return fReaderOptions.fFullyLoadArchives;
-}
-
-Options::NameSpace Options::nameSpace()
-{
- return fNameSpace;
-}
-
-const char* Options::installPath()
-{
- if ( fDylibInstallName != NULL )
- return fDylibInstallName;
- 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()
-{
- return fInterposable;
-}
-
-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;
-}
-
-Options::WeakReferenceMismatchTreatment Options::weakReferenceMismatchTreatment()
-{
- return fWeakReferenceMismatchTreatment;
-}
-
-const char* Options::umbrellaName()
-{
- return fUmbrellaName;
-}
-
-uint64_t Options::zeroPageSize()
-{
- return fZeroPageSize;
-}
-
-bool Options::hasCustomStack()
-{
- return (fStackSize != 0);
-}
-
-uint64_t Options::customStackSize()
-{
- return fStackSize;
-}
-
-uint64_t Options::customStackAddr()
-{
- return fStackAddr;
-}
-
-std::vector<const char*>& Options::initialUndefines()
-{
- return fInitialUndefines;
-}
-
-const char* Options::initFunctionName()
-{
- return fInitFunctionName;
-}
-
-bool Options::hasExportRestrictList()
-{
- return (fExportMode != kExportDefault);
-}
-
-uint32_t Options::minimumHeaderPad()
-{
- return fMinimumHeaderPad;
-}
-
-std::vector<Options::ExtraSection>& Options::extraSections()
-{
- return fExtraSections;
-}
-
-std::vector<Options::SectionAlignment>& Options::sectionAlignments()
-{
- return fSectionAlignments;
-}
-
-
-Options::CommonsMode Options::commonsMode()
-{
- return fCommonsMode;
-}
-
-bool Options::warnCommons()
-{
- return fWarnCommons;
-}
-
-bool Options::shouldExport(const char* symbolName)
-{
- switch (fExportMode) {
- case kExportSome:
- return ( fExportSymbols.find(symbolName) != fExportSymbols.end() );
- case kDontExportSome:
- return ( fDontExportSymbols.find(symbolName) == fDontExportSymbols.end() );
- case kExportDefault:
- return true;
- }
- 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;
- else if ( strcmp(architecture, "ppc64") == 0 )
- fArchitecture = CPU_TYPE_POWERPC64;
- else if ( strcmp(architecture, "i386") == 0 )
- fArchitecture = CPU_TYPE_I386;
- else
- throw "-arch followed by unknown architecture name";
-}
-
-bool Options::checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result)
-{
- struct stat statBuffer;
- char possiblePath[strlen(dir)+strlen(rootName)+20];
- sprintf(possiblePath, format, dir, rootName);
- if ( stat(possiblePath, &statBuffer) == 0 ) {
- result.path = strdup(possiblePath);
- result.fileLen = statBuffer.st_size;
- return true;
- }
- return false;
-}
-
-
-Options::FileInfo Options::findLibrary(const char* rootName)
-{
- 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<const char*>::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<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
- const char* dir = *it;
- if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) )
- return result;
- }
- }
- // next look in all directories for just for archives
- for (std::vector<const char*>::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<const char*>::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 ( 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* rootName)
-{
- struct stat statBuffer;
- const int rootNameLen = strlen(rootName);
- for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin(); it != fFrameworkSearchPaths.end(); it++) {
- const char* dir = *it;
- char possiblePath[strlen(dir)+2*rootNameLen+20];
- strcpy(possiblePath, dir);
- strcat(possiblePath, "/");
- strcat(possiblePath, rootName);
- strcat(possiblePath, ".framework/");
- strcat(possiblePath, rootName);
- if ( stat(possiblePath, &statBuffer) == 0 ) {
- FileInfo result;
- result.path = strdup(possiblePath);
- result.fileLen = statBuffer.st_size;
- return result;
- }
- }
- 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<const char*>::iterator it = fSDKPaths.begin(); it != fSDKPaths.end(); it++) {
- 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;
- return result;
- }
- }
- }
- // try raw path
- if ( stat(path, &statBuffer) == 0 ) {
- result.path = strdup(path);
- result.fileLen = statBuffer.st_size;
- return result;
- }
- // not found
- throwf("file not found: %s", path);
-}
-
-
-void Options::loadFileList(const char* fileOfPaths)
-{
- FILE* file = fopen(fileOfPaths, "r");
- if ( file == NULL )
- throwf("-filelist file not found: %s\n", fileOfPaths);
-
- char path[1024];
- while ( fgets(path, 1024, file) != NULL ) {
- path[1023] = '\0';
- char* eol = strchr(path, '\n');
- if ( eol != NULL )
- *eol = '\0';
-
- fInputFiles.push_back(findFile(path));
- }
- fclose(file);
-}
-
-
-void Options::loadExportFile(const char* fileOfExports, const char* option, NameSet& 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 = '\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' )
- state = lineStart;
- break;
- }
- }
- // Note: we do not free() the malloc buffer, because the strings are used by the export-set hash table
-}
-
-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 ]";
-}
-
-void Options::setReadOnlyRelocTreatment(const char* treatment)
-{
- if ( treatment == NULL )
- throw "-read_only_relocs missing [ warning | error | suppress ]";
-
- if ( strcmp(treatment, "warning") == 0 )
- throw "-read_only_relocs warning not supported";
- else if ( strcmp(treatment, "suppress") == 0 )
- throw "-read_only_relocs suppress not supported";
- else if ( strcmp(treatment, "error") != 0 )
- throw "invalid option to -read_only_relocs [ warning | error | suppress | dynamic_lookup ]";
-}
-
-void Options::setPICTreatment(const char* treatment)
-{
- if ( treatment == NULL )
- throw "-sect_diff_relocs missing [ warning | error | suppress ]";
-
- if ( strcmp(treatment, "warning") == 0 )
- fPICTreatment = kPICWarning;
- else if ( strcmp(treatment, "error") == 0 )
- fPICTreatment = kPICError;
- else if ( strcmp(treatment, "suppress") == 0 )
- fPICTreatment = kPICSuppress;
- else
- throw "invalid option to -sect_diff_relocs [ warning | error | suppress ]";
-}
-
-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::setDylibInstallNameOverride(const char* paths)
-{
-
-
-}
-
-void Options::setExecutablePath(const char* path)
-{
-
-
-}
-
-
-
-
-uint64_t Options::parseAddress(const char* addr)
-{
- char* endptr;
- uint64_t result = strtoull(addr, &endptr, 16);
- 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;
-}
-
-void Options::parseSectionOrderFile(const char* segment, const char* section, const char* path)
-{
- fprintf(stderr, "ld64: warning -sectorder not yet supported for 64-bit code\n");
-}
-
-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 )
- throw "-seccreate section name max 16 chars";
-
- // 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";
-
- 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";
- uint8_t alignment = 0;
- for(unsigned long x=value; x != 1; x >>= 1)
- ++alignment;
- if ( (unsigned long)(1 << alignment) != value )
- throw "argument for -sectalign is not a power of two";
-
- SectionAlignment info = { segment, section, alignment };
- fSectionAlignments.push_back(info);
-}
-
-
-void Options::parse(int argc, const char* argv[])
-{
- // pass one builds search list from -L and -F options
- this->buildSearchPaths(argc, argv);
-
- // pass two parse all other options
- for(int i=1; i < argc; ++i) {
- const char* arg = argv[i];
-
- if ( arg[0] == '-' ) {
- if ( (arg[1] == 'L') || (arg[1] == 'F') ) {
- // previously handled by buildSearchPaths()
- }
- else if ( strcmp(arg, "-arch") == 0 ) {
- parseArch(argv[++i]);
- }
- else if ( strcmp(arg, "-dynamic") == 0 ) {
- // default
- }
- else if ( strcmp(arg, "-static") == 0 ) {
- fOutputKind = kStaticExecutable;
- }
- 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' ) {
- fInputFiles.push_back(findLibrary(&arg[2]));
- }
- else if ( strcmp(arg, "-weak-l") == 0 ) {
- FileInfo info = findLibrary(&arg[2]);
- info.options.fWeakImport = true;
- fInputFiles.push_back(info);
- }
- 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;
- }
- else if ( strcmp(arg, "-force_flat_namespace") == 0 ) {
- fNameSpace = kForceFlatNameSpace;
- }
- else if ( strcmp(arg, "-all_load") == 0 ) {
- fReaderOptions.fFullyLoadArchives = true;
- }
- else if ( strcmp(arg, "-ObjC") == 0 ) {
- fReaderOptions.fLoadObjcClassesInArchives = true;
- }
- else if ( strcmp(arg, "-dylib_compatibility_version") == 0 ) {
- fDylibCompatVersion = parseVersionNumber(argv[++i]);
- }
- else if ( strcmp(arg, "-dylib_current_version") == 0 ) {
- fDylibCurrentVersion = parseVersionNumber(argv[++i]);
- }
- else if ( strcmp(arg, "-sectorder") == 0 ) {
- parseSectionOrderFile(argv[i+1], argv[i+2], argv[i+3]);
- i += 3;
- }
- else if ( (strcmp(arg, "-sectcreate") == 0) || (strcmp(arg, "-segcreate") == 0) ) {
- addSection(argv[i+1], argv[i+2], argv[i+3]);
- i += 3;
- }
- else if ( (strcmp(arg, "-dylib_install_name") == 0) || (strcmp(arg, "-dylinker_install_name") == 0) ) {
- fDylibInstallName = argv[++i];
- }
- else if ( strcmp(arg, "-seg1addr") == 0 ) {
- fBaseAddress = parseAddress(argv[++i]);
- }
- else if ( strcmp(arg, "-e") == 0 ) {
- fEntryName = argv[++i];
- }
- else if ( strcmp(arg, "-filelist") == 0 ) {
- loadFileList(argv[++i]);
- }
- else if ( strcmp(arg, "-keep_private_externs") == 0 ) {
- fKeepPrivateExterns = true;
- }
- else if ( strcmp(arg, "-final_output") == 0 ) {
- ++i;
- // ignore for now
- }
- else if ( (strcmp(arg, "-interposable") == 0) || (strcmp(arg, "-multi_module") == 0)) {
- fInterposable = true;
- }
- else if ( strcmp(arg, "-single_module") == 0 ) {
- fInterposable = false;
- }
- 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 -exported_symbols_list and -unexported_symbols_list";
- fExportMode = kDontExportSome;
- loadExportFile(argv[++i], "-unexported_symbols_list", fDontExportSymbols);
- }
- else if ( strcmp(arg, "-no_arch_warnings") == 0 ) {
- fIgnoreOtherArchFiles = true;
- }
- else if ( strcmp(arg, "-force_cpusubtype_ALL") == 0 ) {
- fForceSubtypeAll = true;
- }
- else if ( strcmp(arg, "-weak_library") == 0 ) {
- FileInfo info = findFile(argv[++i]);
- info.options.fWeakImport = true;
- fInputFiles.push_back(info);
- }
- else if ( strcmp(arg, "-framework") == 0 ) {
- fInputFiles.push_back(findFramework(argv[++i]));
- }
- else if ( strcmp(arg, "-weak_framework") == 0 ) {
- FileInfo info = findFramework(argv[++i]);
- info.options.fWeakImport = true;
- fInputFiles.push_back(info);
- }
- else if ( strcmp(arg, "-search_paths_first") == 0 ) {
- fLibrarySearchMode = kSearchDylibAndArchiveInEachDir;
- }
- else if ( strcmp(arg, "-undefined") == 0 ) {
- setUndefinedTreatment(argv[++i]);
- }
- else if ( strcmp(arg, "-arch_multiple") == 0 ) {
- fMessagesPrefixedWithArchitecture = true;
- }
- else if ( strcmp(arg, "-read_only_relocs") == 0 ) {
- setReadOnlyRelocTreatment(argv[++i]);
- }
- else if ( strcmp(arg, "-sect_diff_relocs") == 0 ) {
- setPICTreatment(argv[++i]);
- }
- else if ( strcmp(arg, "-weak_reference_mismatches") == 0 ) {
- setWeakReferenceMismatchTreatment(argv[++i]);
- }
- else if ( strcmp(arg, "-prebind") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-noprebind") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-prebind_allow_overlap") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-prebind_all_twolevel_modules") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-noprebind_all_twolevel_modules") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-nofixprebinding") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-dylib_file") == 0 ) {
- setDylibInstallNameOverride(argv[++i]);
- }
- else if ( strcmp(arg, "-executable_path") == 0 ) {
- setExecutablePath(argv[++i]);
- }
- else if ( strcmp(arg, "-segalign") == 0 ) {
- // FIX FIX
- ++i;
- }
- else if ( strcmp(arg, "-segaddr") == 0 ) {
- // FIX FIX
- i += 2;
- }
- else if ( strcmp(arg, "-segs_read_only_addr") == 0 ) {
- // FIX FIX
- ++i;
- }
- else if ( strcmp(arg, "-segs_read_write_addr") == 0 ) {
- // FIX FIX
- ++i;
- }
- else if ( strcmp(arg, "-seg_addr_table") == 0 ) {
- // FIX FIX
- ++i;
- }
- else if ( strcmp(arg, "-seg_addr_table_filename") == 0 ) {
- // FIX FIX
- ++i;
- }
- else if ( strcmp(arg, "-segprot") == 0 ) {
- // FIX FIX
- i += 3;
- }
- else if ( strcmp(arg, "-pagezero_size") == 0 ) {
- fZeroPageSize = parseAddress(argv[++i]);
- fZeroPageSize &= (-4096); // page align
- }
- else if ( strcmp(arg, "-stack_addr") == 0 ) {
- fStackAddr = parseAddress(argv[++i]);
- }
- else if ( strcmp(arg, "-stack_size") == 0 ) {
- fStackSize = parseAddress(argv[++i]);
- }
- else if ( strcmp(arg, "-sectalign") == 0 ) {
- addSectionAlignment(argv[i+1], argv[i+2], argv[i+3]);
- i += 3;
- }
- else if ( strcmp(arg, "-sectorder_detail") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-sectobjectsymbols") == 0 ) {
- // FIX FIX
- i += 2;
- }
- else if ( strcmp(arg, "-bundle_loader") == 0 ) {
- // FIX FIX
- ++i;
- }
- else if ( strcmp(arg, "-private_bundle") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-twolevel_namespace_hints") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-multiply_defined") == 0 ) {
- // FIX FIX
- ++i;
- }
- else if ( strcmp(arg, "-multiply_defined_unused") == 0 ) {
- // FIX FIX
- ++i;
- }
- else if ( strcmp(arg, "-nomultidefs") == 0 ) {
- // FIX FIX
- }
- else if ( arg[1] == 'y' ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-Y") == 0 ) {
- ++i;
- // FIX FIX
- }
- else if ( strcmp(arg, "-m") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-whyload") == 0 ) {
- // FIX FIX
- }
- 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, "-i") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-U") == 0 ) {
- // FIX FIX
- ++i;
- }
- else if ( strcmp(arg, "-s") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-x") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-S") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-X") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-Si") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-b") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-Sn") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-dead_strip") == 0 ) {
- // FIX FIX
- fprintf(stderr, "ld64: warning -dead_strip not yet supported for 64-bit code\n");
- }
- else if ( strcmp(arg, "-w") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-arch_errors_fatal") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-M") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-whatsloaded") == 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 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-t") == 0 ) {
- // FIX FIX
- }
- else if ( strcmp(arg, "-A") == 0 ) {
- // FIX FIX
- ++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 ) {
- // FIX FIX
- ++i;
- }
- else if ( strcmp(arg, "-client_name") == 0 ) {
- // FIX FIX
- ++i;
- }
- 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, "-warn_commons") == 0 ) {
- fWarnCommons = true;
- }
- else if ( strcmp(arg, "-commons") == 0 ) {
- fCommonsMode = parseCommonsTreatment(argv[++i]);
- }
- 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 {
- fprintf(stderr, "unknown option: %s\n", arg);
- }
- }
- else {
- fInputFiles.push_back(findFile(arg));
- }
- }
-}
-
-
-
-//
-// -syslibroot <path> 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<const char*> libraryPaths;
- std::vector<const char*> frameworkPaths;
- // 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 ld64VersionString[];
- fprintf(stderr, "%s", ld64VersionString);
- // if only -v specified, exit cleanly
- if ( argc == 2 )
- 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);
- }
- }
- if ( addStandardLibraryDirectories ) {
- libraryPaths.push_back("/usr/lib");
- libraryPaths.push_back("/usr/local/lib");
-
- frameworkPaths.push_back("/Library/Frameworks/");
- frameworkPaths.push_back("/Network/Library/Frameworks/");
- frameworkPaths.push_back("/System/Library/Frameworks/");
- }
-
- // now merge sdk and library paths to make real search paths
- for (std::vector<const char*>::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 = betterLibDir;
- }
- const int libDirLen = strlen(libDir);
- for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) {
- 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
- for (std::vector<const char*>::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 = betterFrameworkDir;
- }
- const int frameworkDirLen = strlen(frameworkDir);
- for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) {
- 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<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++)
- fprintf(stderr,"\t%s\n", *it);
- fprintf(stderr,"Framework search paths:\n");
- for (std::vector<const char*>::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("RC_TRACE_ARCHIVES") != NULL)
- fReaderOptions.fTraceArchives = true;
-
- if ( getenv("RC_TRACE_DYLIBS") != NULL) {
- fReaderOptions.fTraceDylibs = true;
- fReaderOptions.fTraceIndirectDylibs = true;
- }
-}
-
-// this is run after the command line is parsed
-void Options::parsePostCommandLineEnvironmentSettings()
-{
-
-}
-
-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<const char*>::iterator it = fSubUmbellas.begin(); it != fSubUmbellas.end(); it++) {
- const char* subUmbrella = *it;
- bool found = false;
- for (std::vector<Options::FileInfo>::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 )
- fprintf(stderr, "ld64 warning: -sub_umbrella %s does not match a supplied dylib\n", subUmbrella);
- }
-
- // unify -sub_library with dylibs
- for (std::vector<const char*>::iterator it = fSubLibraries.begin(); it != fSubLibraries.end(); it++) {
- const char* subLibrary = *it;
- bool found = false;
- for (std::vector<Options::FileInfo>::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, '.');
- 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 )
- fprintf(stderr, "ld64 warning: -sub_library %s does not match a supplied dylib\n", 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:
- if ( fStackAddr > 0xFFFFFFFF )
- throw "-stack_addr must be < 4G for 32-bit processes";
- break;
- case CPU_TYPE_POWERPC64:
- 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 ) {
- fprintf(stderr, "ld64 warning: -stack_addr not specified, using the default 0xC0000000\n");
- fStackAddr = 0xC0000000;
- }
- break;
- case CPU_TYPE_POWERPC64:
- if ( fStackAddr == 0 ) {
- fprintf(stderr, "ld64 warning: -stack_addr not specified, using the default 0x0008000000000000\n");
- fStackAddr = 0x0008000000000000LL;
- }
- 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 legeal 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 -init is only used when building a dylib
- if ( (fInitFunctionName != NULL) && (fOutputKind != Options::kDynamicLibrary) )
- throw "-init can only be used with -dynamiclib";
-
- // make sure all required exported symbols exist
- for (NameSet::iterator it=fExportSymbols.begin(); it != fExportSymbols.end(); it++)
- fInitialUndefines.push_back(*it);
-
-}
-
-
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+/* -*- 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,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
- *
+ *
* @APPLE_LICENSE_HEADER_END@
*/
#include <stdint.h>
#include <mach/machine.h>
-#ifndef CPU_TYPE_POWERPC64
-#define CPU_TYPE_POWERPC64 0x1000012
-#endif
-
-
#include <vector>
#include <ext/hash_set>
#include "ObjectFile.h"
-extern __attribute__((noreturn)) void throwf(const char* format, ...);
-
+void throwf (const char* format, ...) __attribute__ ((noreturn));
-class DynamicLibraryOptions
+class DynamicLibraryOptions
{
public:
- DynamicLibraryOptions() : fWeakImport(false), fReExport(false), fInstallPathOverride(NULL) {}
-
+ DynamicLibraryOptions() : fWeakImport(false), fReExport(false), fInstallPathOverride(NULL) {}
+
bool fWeakImport;
bool fReExport;
const char* fInstallPathOverride;
};
-
+//
+// 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();
+ 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 PICTreatment { kPICError, kPICWarning, kPICSuppress };
- enum WeakReferenceMismatchTreatment { kWeakReferenceMismatchError, kWeakReferenceMismatchWeak, kWeakReferenceMismatchNonWeak };
+ enum WeakReferenceMismatchTreatment { kWeakReferenceMismatchError, kWeakReferenceMismatchWeak,
+ kWeakReferenceMismatchNonWeak };
enum CommonsMode { kCommonsIgnoreDylibs, kCommonsOverriddenByDylibs, kCommonsConflictsDylibsError };
+ enum DeadStripMode { kDeadStripOff, kDeadStripOn, kDeadStripOnPlusUnusedInits };
+ enum VersionMin { k10_1, k10_2, k10_3, k10_4, k10_5 };
struct FileInfo {
const char* path;
uint64_t fileLen;
+ time_t modTime;
DynamicLibraryOptions options;
};
-
+
struct ExtraSection {
const char* segmentName;
const char* sectionName;
const uint8_t* data;
uint64_t dataLen;
};
-
+
struct SectionAlignment {
const char* segmentName;
const char* sectionName;
uint8_t alignment;
};
- ObjectFile::ReaderOptions& readerOptions();
- const char* getOutputFilePath();
- std::vector<FileInfo>& getInputFiles();
-
+ const ObjectFile::ReaderOptions& readerOptions();
+ const char* getOutputFilePath();
+ std::vector<FileInfo>& getInputFiles();
+
cpu_type_t architecture();
OutputKind outputKind();
bool stripLocalSymbols();
- bool stripDebugInfo();
+ bool prebind();
bool bindAtLoad();
bool fullyLoadArchives();
NameSpace nameSpace();
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 interposable(); // only for kDynamicLibrary
+ bool interposable(); // only for kDynamicLibrary
bool hasExportRestrictList();
bool shouldExport(const char*);
bool ignoreOtherArchInputFiles();
bool forceCpuSubtypeAll();
bool traceDylibs();
bool traceArchives();
+ DeadStripMode deadStrip();
UndefinedTreatment undefinedTreatment();
+ VersionMin macosxVersionMin();
bool messagesPrefixedWithArchitecture();
- PICTreatment picTreatment();
+ Treatment picTreatment();
WeakReferenceMismatchTreatment weakReferenceMismatchTreatment();
+ Treatment multipleDefinitionsInDylibs();
+ Treatment overridingDefinitionInDependentDylib();
+ bool warnOnMultipleDefinitionsInObjectFiles();
const char* umbrellaName();
+ std::vector<const char*>& 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<const char*>& initialUndefines();
uint32_t minimumHeaderPad();
std::vector<ExtraSection>& extraSections();
std::vector<SectionAlignment>& sectionAlignments();
CommonsMode commonsMode();
bool warnCommons();
+ bool keepRelocations();
+ std::vector<const char*>& traceSymbols();
FileInfo findFile(const char* path);
+ bool emitUUID();
+ bool warnStabs();
+ bool pauseAtEnd() { return fPause; }
+ bool printStatistics() { return fStatistics; }
private:
class CStringEquals
void parseArch(const char* architecture);
FileInfo findLibrary(const char* rootName);
FileInfo findFramework(const char* rootName);
- bool checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result);
+ 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 addSection(const char* segment, const char* section, const char* path);
void parsePreCommandLineEnvironmentSettings();
void parsePostCommandLineEnvironmentSettings();
void setUndefinedTreatment(const char* treatment);
- void setPICTreatment(const char* treatment);
- void setReadOnlyRelocTreatment(const char* treatment);
+ void setVersionMin(const char* version);
void setWeakReferenceMismatchTreatment(const char* treatment);
void setDylibInstallNameOverride(const char* paths);
- void setExecutablePath(const char* path);
void addSectionAlignment(const char* segment, const char* section, const char* alignment);
CommonsMode parseCommonsTreatment(const char* mode);
-
-
+ Treatment parseTreatment(const char* treatment);
+
+
ObjectFile::ReaderOptions fReaderOptions;
const char* fOutputFile;
std::vector<Options::FileInfo> fInputFiles;
cpu_type_t fArchitecture;
OutputKind fOutputKind;
+ bool fPrebind;
bool fBindAtLoad;
bool fStripLocalSymbols;
bool fKeepPrivateExterns;
bool fInterposable;
bool fIgnoreOtherArchFiles;
bool fForceSubtypeAll;
+ DeadStripMode fDeadStrip;
+ VersionMin fVersionMin;
NameSpace fNameSpace;
uint32_t fDylibCompatVersion;
uint32_t fDylibCurrentVersion;
LibrarySearchMode fLibrarySearchMode;
UndefinedTreatment fUndefinedTreatment;
bool fMessagesPrefixedWithArchitecture;
- PICTreatment fPICTreatment;
+ Treatment fPICTreatment;
WeakReferenceMismatchTreatment fWeakReferenceMismatchTreatment;
+ Treatment fMultiplyDefinedDynamic;
+ Treatment fMultiplyDefinedUnused;
+ bool fWarnOnMultiplyDefined;
std::vector<const char*> fSubUmbellas;
std::vector<const char*> fSubLibraries;
+ std::vector<const char*> fAllowableClients;
+ const char* fClientName;
const char* fUmbrellaName;
const char* fInitFunctionName;
+ const char* fDotOutputFile;
+ const char* fExecutablePath;
uint64_t fZeroPageSize;
uint64_t fStackSize;
uint64_t fStackAddr;
+ bool fExecutableStack;
uint32_t fMinimumHeaderPad;
CommonsMode fCommonsMode;
bool fWarnCommons;
bool fVerbose;
+ bool fKeepRelocations;
+ bool fEmitUUID;
+ bool fWarnStabs;
+ bool fTraceDylibSearching;
+ bool fPause;
+ bool fStatistics;
+ bool fPrintOptions;
std::vector<const char*> fInitialUndefines;
+ std::vector<const char*> fTraceSymbols;
+ unsigned long fLimitUndefinedSymbols;
std::vector<ExtraSection> fExtraSections;
std::vector<SectionAlignment> fSectionAlignments;
-
+
std::vector<const char*> fLibrarySearchPaths;
std::vector<const char*> fFrameworkSearchPaths;
std::vector<const char*> fSDKPaths;
+ bool fAllowStackExecute;
};
#endif // __OPTIONS__
-
-
-
-
-
-
-
-
-
-
-
+++ /dev/null
-/* -*- 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@
- */
-
-
-
-namespace ObjectFileArchiveMachO {
-
-class Reader : public ObjectFile::Reader
-{
-public:
- Reader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
- virtual ~Reader();
-
- virtual const char* getPath();
- virtual std::vector<class ObjectFile::Atom*>& getAtoms();
- virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name);
- virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo();
-
-private:
- class Entry : ar_hdr
- {
- public:
- const char* getName() const;
- const uint8_t* getContent() const;
- uint32_t getContentSize() const;
- const Entry* getNext() const;
- private:
- bool hasLongName() const;
- unsigned int getLongNameSpace() const;
-
- };
-
- const struct ranlib* ranlibBinarySearch(const char* name);
- const struct ranlib* ranlibLinearSearch(const char* name);
- ObjectFile::Reader* makeObjectReaderForMember(const Entry* member);
- void dumpTableOfContents();
-
- const char* fPath;
- const ObjectFile::ReaderOptions& fOptions;
- const uint8_t* fFileContent;
- uint64_t fFileLength;
- const struct ranlib* fTableOfContents;
- uint32_t fTableOfContentCount;
- bool fSorted;
- const char* fStringPool;
- std::vector<class ObjectFile::Atom*> fAllAtoms;
- std::set<const class Entry*> fInstantiatedEntries;
-
- static std::vector<class ObjectFile::Atom*> fgEmptyList;
-};
-
-std::vector<class ObjectFile::Atom*> Reader::fgEmptyList;
-
-#undef SwapArchToHostInt32
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- #define SwapArchToHostInt32(value) OSSwapBigToHostInt32(value)
-#elif defined(ARCH_I386)
- #define SwapArchToHostInt32(value) OSSwapLittleToHostInt32(value)
-#endif
-
-
-
-bool Reader::Entry::hasLongName() const
-{
- return ( strncmp(this->ar_name, AR_EFMT1, strlen(AR_EFMT1)) == 0 );
-}
-
-unsigned int Reader::Entry::getLongNameSpace() const
-{
- char* endptr;
- long result = strtol(&this->ar_name[strlen(AR_EFMT1)], &endptr, 10);
- return result;
-}
-
-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;
- }
-}
-
-
-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);
-}
-
-
-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;
-}
-
-const 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 (Reader::Entry*)p;
-}
-
-
-
-Reader::Reader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options)
- : fPath(NULL), fOptions(options), fFileContent(NULL), fTableOfContents(NULL), fTableOfContentCount(0),
- fSorted(false), fStringPool(NULL)
-{
- fPath = strdup(path);
- fFileContent = fileContent;
- fFileLength = fileLength;
-
- if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
- throw "not an archive";
-
- if ( !options.fFullyLoadArchives ) {
- const Entry* const firstMember = (Entry*)&fFileContent[8];
- if ( strcmp(firstMember->getName(), SYMDEF_SORTED) == 0 )
- fSorted = true;
- else if ( strcmp(firstMember->getName(), SYMDEF) == 0 )
- fSorted = false;
- else
- throw "archive has no table of contents";
- const uint8_t* contents = firstMember->getContent();
- uint32_t ranlibArrayLen = SwapArchToHostInt32(*((uint32_t*)contents));
- fTableOfContents = (const struct ranlib*)&contents[4];
- fTableOfContentCount = ranlibArrayLen / sizeof(struct ranlib);
- fStringPool = (const char*)&contents[ranlibArrayLen+8];
- }
-
- if ( options.fTraceArchives )
- printf("[Logging for Build & Integration] Used static archive: %s\n", fPath);
-}
-
-Reader::~Reader()
-{
-}
-
-
-
-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 {
- return ObjectFileMachO::MakeReader((class macho_header*)member->getContent(), memberPath, fOptions);
- }
- catch (const char* msg) {
- throwf("in %s, %s", memberPath, msg);
- }
-}
-
-const char* Reader::getPath()
-{
- return fPath;
-}
-
-std::vector<class ObjectFile::Atom*>& 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) )
- continue;
- ObjectFile::Reader* r = this->makeObjectReaderForMember(p);
- std::vector<class ObjectFile::Atom*>& atoms = r->getAtoms();
- fAllAtoms.insert(fAllAtoms.end(), atoms.begin(), atoms.end());
- }
- return fAllAtoms;
- }
- else {
- // return nonthing for now, getJustInTimeAtomsFor() will return atoms as needed
- return fgEmptyList;
- }
-}
-
-
-const struct ranlib* Reader::ranlibBinarySearch(const char* key)
-{
- const struct ranlib* base = fTableOfContents;
- for (uint32_t n = fTableOfContentCount; n > 0; n /= 2) {
- const struct ranlib* pivot = &base[n/2];
- const char* pivotStr = &fStringPool[SwapArchToHostInt32(pivot->ran_un.ran_strx)];
- int cmp = strcmp(key, pivotStr);
- if ( cmp == 0 )
- return pivot;
- if ( cmp > 0 ) {
- // key > pivot
- // move base to symbol after pivot
- base = &pivot[1];
- --n;
- }
- else {
- // key < pivot
- // keep same base
- }
- }
- return NULL;
-}
-
-const struct ranlib* Reader::ranlibLinearSearch(const char* key)
-{
- for (uint32_t i = 0; i < fTableOfContentCount; ++i) {
- const struct ranlib* entry = &fTableOfContents[i];
- const char* entryName = &fStringPool[SwapArchToHostInt32(entry->ran_un.ran_strx)];
- if ( strcmp(key, entryName) == 0 )
- return entry;
- }
- return NULL;
-}
-
-
-void Reader::dumpTableOfContents()
-{
- for (unsigned int i=0; i < fTableOfContentCount; ++i) {
- const struct ranlib* e = &fTableOfContents[i];
- printf("%s in %s\n", &fStringPool[SwapArchToHostInt32(e->ran_un.ran_strx)], ((Entry*)&fFileContent[SwapArchToHostInt32(e->ran_off)])->getName());
- }
-}
-
-std::vector<class ObjectFile::Atom*>* Reader::getJustInTimeAtomsFor(const char* name)
-{
- if ( fOptions.fFullyLoadArchives ) {
- return NULL;
- }
- else {
- const struct ranlib* result = NULL;
- if ( fSorted ) {
- // do a binary search of table of contents looking for requested symbol
- result = ranlibBinarySearch(name);
- }
- else {
- // do a linear search of table of contents looking for requested symbol
- result = ranlibLinearSearch(name);
- }
- if ( result != NULL ) {
- const Entry* member = (Entry*)&fFileContent[SwapArchToHostInt32(result->ran_off)];
- if ( fInstantiatedEntries.count(member) == 0 ) {
- // only return these atoms once
- fInstantiatedEntries.insert(member);
- ObjectFile::Reader* r = makeObjectReaderForMember(member);
- //fprintf(stderr, "%s found in %s\n", name, member->getName());
- return new std::vector<class ObjectFile::Atom*>(r->getAtoms());
- }
- }
- //fprintf(stderr, "%s NOT found in archive %s\n", name, fPath);
- return NULL;
- }
-}
-
-
-std::vector<ObjectFile::StabsInfo>* Reader::getStabsDebugInfo()
-{
- return NULL;
-}
-
-
-
-Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options)
-{
- return new Reader(fileContent, fileLength, path, options);
-}
-
-
-
-};
-
-
-
-
-
-
-
+++ /dev/null
-/* -*- 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@
- */
-
-
-
-namespace ObjectFileDylibMachO {
-
-class Reader : public ObjectFile::Reader
-{
-public:
- Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options);
- virtual ~Reader();
-
- virtual const char* getPath();
- virtual std::vector<class ObjectFile::Atom*>& getAtoms();
- virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name);
- virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo();
- virtual const char* getInstallPath();
- virtual uint32_t getTimestamp();
- virtual uint32_t getCurrentVersion();
- virtual uint32_t getCompatibilityVersion();
- virtual std::vector<const char*>* getDependentLibraryPaths();
- virtual bool reExports(ObjectFile::Reader*);
- virtual bool isDefinitionWeak(const ObjectFile::Atom&);
-
-private:
- struct CStringComparor
- {
- bool operator()(const char* left, const char* right) { return (strcmp(left, right) > 0); }
- };
- typedef std::map<const char*, ObjectFile::Atom*, CStringComparor> Mapper;
-
-
- void init(const macho_header* header,const char* path);
- const macho_nlist* binarySearchWithToc(const char* key, const char stringPool[], const macho_nlist symbols[], const struct dylib_table_of_contents toc[], uint32_t symbolCount);
- const macho_nlist* binarySearch(const char* key, const char stringPool[], const macho_nlist symbols[], uint32_t symbolCount);
- bool hasExport(const char* name);
- const macho_nlist* findExport(const char* name);
-
- const char* fPath;
- const macho_header* fHeader;
- const char* fStrings;
- const macho_dysymtab_command* fDynamicInfo;
- const macho_dylib_command* fDylibID;
- const macho_nlist* fSymbols;
- uint32_t fSymbolCount;
- Mapper fAtoms;
- std::vector<Reader*> fReExportedDylibs;
-
- static std::vector<class ObjectFile::Atom*> fEmptyAtomList;
-};
-
-std::vector<class ObjectFile::Atom*> Reader::fEmptyAtomList;
-
-
-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;
-};
-
-
-class ExportAtom : public ObjectFile::Atom
-{
-public:
- virtual ObjectFile::Reader* getFile() const { return &fOwner; }
- virtual const char* getName() const { return fName; }
- virtual const char* getDisplayName() const;
- virtual Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
- virtual bool isTentativeDefinition() const { return false; }
- virtual bool isWeakDefinition() const { return false; }
- virtual bool isCoalesableByName() const { return false; }
- virtual bool isCoalesableByValue() const { return false; }
- virtual bool isZeroFill() const { return false; }
- virtual bool dontDeadStrip() const { return false; }
- virtual bool dontStripName() const { return false; }
- virtual bool isImportProxy() const { return true; }
- virtual uint64_t getSize() const { return 0; }
- virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
- virtual bool mustRemainInSection() const { return false; }
- virtual const char* getSectionName() const { return "._imports"; }
- virtual Segment& getSegment() const { return fgImportSegment; }
- virtual bool requiresFollowOnAtom() const{ return false; }
- virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
- virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo() const { return NULL; }
- virtual uint8_t getAlignment() const { return 0; }
- virtual WeakImportSetting getImportWeakness() const { return fWeakImportSetting; }
- virtual void copyRawContent(uint8_t buffer[]) const {}
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
-
- virtual void setScope(Scope) { }
- virtual void setImportWeakness(bool weakImport) { fWeakImportSetting = weakImport ? kWeakImport : kNonWeakImport; }
-
-protected:
- friend class Reader;
-
- ExportAtom(Reader& owner, const char* name) : fOwner(owner), fName(name), fWeakImportSetting(kWeakUnset) {}
- virtual ~ExportAtom() {}
-
- Reader& fOwner;
- const char* fName;
- WeakImportSetting fWeakImportSetting;
-
- static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
- static Segment fgImportSegment;
-};
-
-Segment ExportAtom::fgImportSegment("__LINKEDIT");
-std::vector<ObjectFile::Reference*> ExportAtom::fgEmptyReferenceList;
-
-const char* ExportAtom::getDisplayName() const
-{
- static char temp[300];
- strcpy(temp, fName);
- strcat(temp, "$import");
- return temp;
-}
-
-
-
-Reader::Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options)
- : fHeader(header), fStrings(NULL), fDylibID(NULL), fSymbols(NULL), fSymbolCount(0)
-{
- typedef std::pair<const macho_dylib_command*, bool> DylibAndReExportFlag;
- std::vector<DylibAndReExportFlag> dependentDylibs;
-
- fPath = strdup(path);
- const uint32_t cmd_count = header->ncmds();
- const macho_load_command* const cmds = (macho_load_command*)((char*)header + macho_header::size);
- // get all dylib load commands
- const macho_load_command* cmd = cmds;
- for (uint32_t i = 0; i < cmd_count; ++i) {
- switch (cmd->cmd()) {
- case LC_LOAD_DYLIB:
- case LC_LOAD_WEAK_DYLIB:
- {
- DylibAndReExportFlag info;
- info.first = (struct macho_dylib_command*)cmd;
- info.second = options.fFlatNamespace;
- dependentDylibs.push_back(info);
- }
- break;
- }
- cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
- }
-
- // cache interesting pointers
- 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;
- fSymbolCount = symtab->nsyms();
- fSymbols = (const macho_nlist*)((char*)header + symtab->symoff());
- fStrings = (char*)header + symtab->stroff();
- }
- break;
- case LC_DYSYMTAB:
- fDynamicInfo = (macho_dysymtab_command*)cmd;
- break;
- case LC_ID_DYLIB:
- fDylibID = (macho_dylib_command*)cmd;
- break;
- case LC_SUB_UMBRELLA:
- if ( !options.fFlatNamespace ) {
- const char* frameworkLeafName = ((macho_sub_umbrella_command*)cmd)->name();
- for (std::vector<DylibAndReExportFlag>::iterator it = dependentDylibs.begin(); it != dependentDylibs.end(); it++) {
- const char* dylibName = it->first->name();
- const char* lastSlash = strrchr(dylibName, '/');
- if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
- it->second = true;
- }
- }
- break;
- case LC_SUB_LIBRARY:
- if ( !options.fFlatNamespace ) {
- const char* dylibBaseName = ((macho_sub_library_command*)cmd)->name();
- for (std::vector<DylibAndReExportFlag>::iterator it = dependentDylibs.begin(); it != dependentDylibs.end(); it++) {
- const char* dylibName = it->first->name();
- 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->second = true;
- }
- }
- break;
- }
- cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
- }
-
- // load dylibs we need to re-export
- for (std::vector<DylibAndReExportFlag>::iterator it = dependentDylibs.begin(); it != dependentDylibs.end(); it++) {
- if ( it->second ) {
- // printf("%s need to re-export %s\n", path, it->first->name());
- //fReExportedDylibs.push_back(
- }
- }
-}
-
-
-Reader::~Reader()
-{
-}
-
-const char* Reader::getPath()
-{
- return fPath;
-}
-
-
-std::vector<class ObjectFile::Atom*>& Reader::getAtoms()
-{
- return fEmptyAtomList;
-}
-
-
-
-const macho_nlist* Reader::binarySearchWithToc(const char* key, const char stringPool[], const macho_nlist symbols[],
- const struct dylib_table_of_contents toc[], uint32_t symbolCount)
-{
- int32_t high = symbolCount-1;
- int32_t mid = symbolCount/2;
-
- for (int32_t low = 0; low <= high; mid = (low+high)/2) {
- const uint32_t index = ENDIAN_READ32(toc[mid].symbol_index);
- const macho_nlist* pivot = &symbols[index];
- const char* pivotStr = &stringPool[pivot->n_strx()];
- int cmp = strcmp(key, pivotStr);
- if ( cmp == 0 )
- return pivot;
- if ( cmp > 0 ) {
- // key > pivot
- low = mid + 1;
- }
- else {
- // key < pivot
- high = mid - 1;
- }
- }
- return NULL;
-}
-
-
-const macho_nlist* Reader::binarySearch(const char* key, const char stringPool[], const macho_nlist symbols[], uint32_t symbolCount)
-{
- const macho_nlist* base = symbols;
- for (uint32_t n = symbolCount; n > 0; n /= 2) {
- const macho_nlist* pivot = &base[n/2];
- const char* pivotStr = &stringPool[pivot->n_strx()];
- int cmp = strcmp(key, pivotStr);
- if ( cmp == 0 )
- return pivot;
- if ( cmp > 0 ) {
- // key > pivot
- // move base to symbol after pivot
- base = &pivot[1];
- --n;
- }
- else {
- // key < pivot
- // keep same base
- }
- }
- return NULL;
-}
-
-const macho_nlist* Reader::findExport(const char* name)
-{
- if ( fDynamicInfo->tocoff() == 0 )
- return binarySearch(name, fStrings, &fSymbols[fDynamicInfo->iextdefsym()], fDynamicInfo->nextdefsym());
- else {
- return binarySearchWithToc(name, fStrings, fSymbols, (dylib_table_of_contents*)((char*)fHeader + fDynamicInfo->tocoff()),
- fDynamicInfo->nextdefsym());
- }
-}
-
-bool Reader::hasExport(const char* name)
-{
- return ( findExport(name) != NULL );
-}
-
-std::vector<class ObjectFile::Atom*>* Reader::getJustInTimeAtomsFor(const char* name)
-{
- std::vector<class ObjectFile::Atom*>* atoms = NULL;
- // search exports
- if ( this->hasExport(name) ) {
- // see if this atom already synthesized
- ObjectFile::Atom* atom = NULL;
- Mapper::iterator pos = fAtoms.find(name);
- if ( pos != fAtoms.end() ) {
- atom = pos->second;
- }
- else {
- atom = new ExportAtom(*this, name);
- fAtoms[name] = atom;
- }
- // return a vector of one atom
- atoms = new std::vector<class ObjectFile::Atom*>;
- atoms->push_back(atom);
- return atoms;
- }
-
- // check re-exports
- for (std::vector<Reader*>::iterator it = fReExportedDylibs.begin(); it != fReExportedDylibs.end(); it++) {
- Reader* reExportedReader = *it;
- atoms = reExportedReader->getJustInTimeAtomsFor(name);
- if ( atoms != NULL )
- return atoms;
- }
-
- return NULL;
-}
-
-
-std::vector<ObjectFile::StabsInfo>* Reader::getStabsDebugInfo()
-{
- return NULL;
-}
-
-const char* Reader::getInstallPath()
-{
- return fDylibID->name();
-}
-
-uint32_t Reader::getTimestamp()
-{
- return fDylibID->timestamp();
-}
-
-uint32_t Reader::getCurrentVersion()
-{
- return fDylibID->current_version();
-}
-
-uint32_t Reader::getCompatibilityVersion()
-{
- return fDylibID->compatibility_version();
-}
-
-std::vector<const char*>* Reader::getDependentLibraryPaths()
-{
- std::vector<const char*>* result = new std::vector<const char*>;
- const uint32_t cmd_count = fHeader->ncmds();
- const macho_load_command* const cmds = (macho_load_command*)((char*)fHeader + macho_header::size);
- const macho_load_command* cmd = cmds;
- for (uint32_t i = 0; i < cmd_count; ++i) {
- switch (cmd->cmd()) {
- case LC_LOAD_DYLIB:
- case LC_LOAD_WEAK_DYLIB:
- {
- result->push_back(((struct macho_dylib_command*)cmd)->name());
- }
- break;
- }
- cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
- }
- return result;
-}
-
-bool Reader::reExports(ObjectFile::Reader* child)
-{
- // A dependent dylib is re-exported under two conditions:
- // 1) parent contains LC_SUB_UMBRELLA or LC_SUB_LIBRARY with child name
- {
- const uint32_t cmd_count = fHeader->ncmds();
- const macho_load_command* const cmds = (macho_load_command*)((char*)fHeader + macho_header::size);
- const macho_load_command* cmd = cmds;
- for (uint32_t i = 0; i < cmd_count; ++i) {
- switch (cmd->cmd()) {
- case LC_SUB_UMBRELLA:
- {
- const char* frameworkLeafName = ((macho_sub_umbrella_command*)cmd)->name();
- const char* dylibName = child->getPath();
- const char* lastSlash = strrchr(dylibName, '/');
- if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
- return true;
- }
- break;
- case LC_SUB_LIBRARY:
- {
- const char* dylibBaseName = ((macho_sub_library_command*)cmd)->name();
- const char* dylibName = child->getPath();
- 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 )
- return true;
- }
- break;
- }
- cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
- }
- }
-
- // 2) child contains LC_SUB_FRAMEWORK with parent name
- {
- const uint32_t cmd_count = ((Reader*)child)->fHeader->ncmds();
- const macho_load_command* const cmds = (macho_load_command*)((char*)(((Reader*)child)->fHeader) + macho_header::size);
- const macho_load_command* cmd = cmds;
- for (uint32_t i = 0; i < cmd_count; ++i) {
- switch (cmd->cmd()) {
- case LC_SUB_FRAMEWORK:
- {
- const char* frameworkLeafName = ((macho_sub_framework_command*)cmd)->name();
- const char* parentName = this->getPath();
- const char* lastSlash = strrchr(parentName, '/');
- if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
- return true;
- }
- break;
- }
- cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
- }
- }
-
-
- return false;
-}
-
-bool Reader::isDefinitionWeak(const ObjectFile::Atom& atom)
-{
- const macho_nlist* sym = findExport(atom.getName());
- if ( sym != NULL ) {
- if ( (sym->n_desc() & N_WEAK_DEF) != 0 )
- return true;
- }
- return false;
-}
-
-
-
-Reader* MakeReader(const macho_header* mh, const char* path, const ObjectFile::ReaderOptions& options)
-{
- return new Reader(mh, path, options);
-}
-
-
-
-};
-
-
-
-
-
-
-
+++ /dev/null
-/*
- * 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 <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <math.h>
-#include <ar.h>
-
-#include <algorithm>
-#include <vector>
-#include <set>
-
-#include <mach-o/loader.h>
-#include <mach-o/nlist.h>
-#include <mach-o/reloc.h>
-#include <mach-o/ppc/reloc.h>
-#include <mach-o/ranlib.h>
-#include <mach-o/stab.h>
-
-#include "ObjectFile.h"
-#include "Options.h"
-
-
-
-
-// buiild Writer for -arch ppc64
-#undef MACHO_32_SAME_ENDIAN
-#undef MACHO_32_OPPOSITE_ENDIAN
-#undef MACHO_64_SAME_ENDIAN
-#undef MACHO_64_OPPOSITE_ENDIAN
-#if __ppc__ || __ppc64__
- #define MACHO_64_SAME_ENDIAN
-#elif __i386__
- #define MACHO_64_OPPOSITE_ENDIAN
-#else
- #error unknown architecture
-#endif
-namespace ppc64 {
- #undef ARCH_PPC
- #define ARCH_PPC64
- #undef ARCH_I386
- #include "MachOAbstraction.h"
- #include "ObjectFileMachO.cpp"
- #include "ObjectFileDylibMachO.cpp"
- #include "ObjectFileArchiveMachO.cpp"
-};
-
-// buiild Writer for -arch ppc
-#undef MACHO_32_SAME_ENDIAN
-#undef MACHO_32_OPPOSITE_ENDIAN
-#undef MACHO_64_SAME_ENDIAN
-#undef MACHO_64_OPPOSITE_ENDIAN
-#if __ppc__ || __ppc64__
- #define MACHO_32_SAME_ENDIAN
-#elif __i386__
- #define MACHO_32_OPPOSITE_ENDIAN
-#else
- #error unknown architecture
-#endif
-namespace ppc {
- #define ARCH_PPC
- #undef ARCH_PPC64
- #undef ARCH_I386
- #include "MachOAbstraction.h"
- #include "ObjectFileMachO.cpp"
- #include "ObjectFileDylibMachO.cpp"
- #include "ObjectFileArchiveMachO.cpp"
-};
-
-
-// buiild Writer for -arch i386
-#undef MACHO_32_SAME_ENDIAN
-#undef MACHO_32_OPPOSITE_ENDIAN
-#undef MACHO_64_SAME_ENDIAN
-#undef MACHO_64_OPPOSITE_ENDIAN
-#if __ppc__ || __ppc64__
- #define MACHO_32_OPPOSITE_ENDIAN
-#elif __i386__
- #define MACHO_32_SAME_ENDIAN
-#else
- #error unknown architecture
-#endif
-#undef i386 // compiler sometimes #defines this
-namespace i386 {
- #undef ARCH_PPC
- #undef ARCH_PPC64
- #define ARCH_I386
- #include "MachOAbstraction.h"
- #include "ObjectFileMachO.cpp"
- #include "ObjectFileDylibMachO.cpp"
- #include "ObjectFileArchiveMachO.cpp"
-};
-
-
+++ /dev/null
-/*
- * 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 __OBJECTFILEMACHO__
-#define __OBJECTFILEMACHO__
-
-class Options;
-
-namespace ppc {
- class macho_header;
- namespace ObjectFileMachO {
- extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
- };
- namespace ObjectFileDylibMachO {
- extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
- };
- namespace ObjectFileArchiveMachO {
- extern class ObjectFile::Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
- };
-};
-
-namespace ppc64 {
- class macho_header;
- namespace ObjectFileMachO {
- extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
- };
- namespace ObjectFileDylibMachO {
- extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
- };
- namespace ObjectFileArchiveMachO {
- extern class ObjectFile::Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
- };
-};
-
-#undef i386 // compiler sometimes #defines this
-namespace i386 {
- class macho_header;
- namespace ObjectFileMachO {
- extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
- };
- namespace ObjectFileDylibMachO {
- extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
- };
- namespace ObjectFileArchiveMachO {
- extern class ObjectFile::Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
- };
-};
-
-
-
-#endif // __OBJECTFILEMACHO__
-
-
-
+++ /dev/null
-/* -*- 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@
- */
-
-
-namespace ObjectFileMachO {
-
-class Reference : public ObjectFile::Reference
-{
-public:
- Reference(macho_uintptr_t fixUpOffset, Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
- Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
- Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, class Atom& fromTarget, uint64_t offsetInFromTarget);
- virtual ~Reference();
-
-
- virtual bool isTargetUnbound() const;
- virtual bool isFromTargetUnbound() const;
- virtual bool isWeakReference() const;
- virtual bool requiresRuntimeFixUp(bool slideable) const;
- virtual bool isLazyReference() const;
- virtual Kind getKind() const;
- virtual uint64_t getFixUpOffset() const;
- virtual const char* getTargetName() const;
- virtual ObjectFile::Atom& getTarget() const;
- virtual uint64_t getTargetOffset() const;
- virtual bool hasFromTarget() const;
- virtual ObjectFile::Atom& getFromTarget() const;
- virtual const char* getFromTargetName() const;
- virtual void setTarget(ObjectFile::Atom&, uint64_t offset);
- virtual void setFromTarget(ObjectFile::Atom&);
- virtual void setFromTargetName(const char*);
- virtual void setFromTargetOffset(uint64_t);
- virtual const char* getDescription() const;
- virtual uint64_t getFromTargetOffset() const;
-
- void setLazy(bool);
- void setWeak(bool);
-private:
- ObjectFile::Atom* fTarget;
- ObjectFile::Atom* fFromTarget;
- const char* fTargetName;
- const char* fFromTargetName;
- macho_uintptr_t fTargetOffset;
- macho_uintptr_t fFromTargetOffset;
- macho_uintptr_t fFixUpOffsetInSrc;
- Kind fKind;
- bool fLazy;
- bool fWeak;
-};
-
-
-
-class Reader : public ObjectFile::Reader
-{
-public:
- Reader(const char* path);
- Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options);
- virtual ~Reader();
-
- virtual const char* getPath();
- virtual std::vector<class ObjectFile::Atom*>& getAtoms();
- virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name);
- virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo(); // stabs info not associated with an atom
-
-
-private:
- friend class Atom;
- void init(const macho_header* header, const char* path);
- void buildOffsetsSet(const macho_relocation_info* reloc, const macho_section* sect, std::set<uint32_t>& offsets, std::set<uint32_t>& dontUse);
- void addRelocReference(const macho_section* sect, const macho_relocation_info* reloc);
- Atom* findAtomCoveringOffset(uint32_t offset);
- uint32_t findAtomIndex(const Atom& atom);
- void addFixUp(uint32_t srcAddr, uint32_t dstAddr, Reference::Kind kind, uint32_t picBaseAddr);
- class Segment* makeSegmentFromSection(const macho_section*);
- macho_uintptr_t commonsOffset();
- void insertOffsetIfText(std::set<uint32_t>& offsets, uint32_t value);
- void insertOffsetIfNotText(std::set<uint32_t>& offsets, uint32_t value);
- const macho_section* findSectionCoveringOffset(uint32_t offset);
- void addCallSiteReference(Atom& src, uint32_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint32_t picBaseOffset, uint32_t offsetInTargetAtom);
- void deadStub(Atom& target);
-
- const char* fPath;
- 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<class Atom*> fAtoms;
- std::vector<class Segment*> fSegments;
- std::set<class ObjectFile::Atom*> fDeadAtoms;
- uint32_t fNonAtomStabsStartIndex;
- uint32_t fNonAtomStabsCount;
- std::vector<uint32_t> fNonAtomExtras;
-};
-
-class Segment : public ObjectFile::Segment
-{
-public:
- virtual const char* getName() const;
- virtual bool isContentReadable() const;
- virtual bool isContentWritable() const;
- virtual bool isContentExecutable() const;
-protected:
- Segment(const macho_section*);
- friend class Reader;
-private:
- const macho_section* fSection;
-};
-
-class Atom : public ObjectFile::Atom
-{
-public:
- virtual ObjectFile::Reader* getFile() const;
- virtual const char* getName() const;
- virtual const char* getDisplayName() const;
- virtual Scope getScope() const;
- virtual bool isTentativeDefinition() const;
- virtual bool isWeakDefinition() const;
- virtual bool isCoalesableByName() const;
- virtual bool isCoalesableByValue() const;
- virtual bool isZeroFill() const;
- virtual bool dontDeadStrip() const;
- virtual bool dontStripName() const; // referenced dynamically
- virtual bool isImportProxy() const;
- virtual uint64_t getSize() const;
- virtual std::vector<ObjectFile::Reference*>& getReferences() const;
- virtual bool mustRemainInSection() const;
- virtual const char* getSectionName() const;
- virtual Segment& getSegment() const;
- virtual bool requiresFollowOnAtom() const;
- virtual ObjectFile::Atom& getFollowOnAtom() const;
- virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo() const;
- virtual uint8_t getAlignment() const;
- virtual WeakImportSetting getImportWeakness() const { return ObjectFile::Atom::kWeakUnset; }
- virtual void copyRawContent(uint8_t buffer[]) const;
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
- virtual void setScope(Scope);
- virtual void setImportWeakness(bool weakImport) { }
-
- bool isLazyStub();
-
-protected:
- friend class Reader;
- Atom(Reader&, const macho_nlist*);
- Atom(Reader&, uint32_t offset);
- virtual ~Atom();
-
- const macho_section* findSectionFromOffset(uint32_t offset);
- const macho_section* getCommonsSection();
- void setSize(macho_uintptr_t);
- void setFollowOnAtom(Atom&);
- static bool atomCompare(const Atom* lhs, const Atom* rhs);
- Reference* addDirectReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
- Reference* addByNameReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
- Reference* addDifferenceReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, Atom& fromTarget, uint64_t offsetInFromTarget);
- Reference* addReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
-
- Reader& fOwner;
- const macho_nlist* fSymbol;
- macho_uintptr_t fOffset;
- macho_uintptr_t fSize;
- const macho_section* fSection;
- Segment* fSegment;
- const char* fSynthesizedName;
- std::vector<class Reference*> fReferences;
- ObjectFile::Atom::Scope fScope;
- uint32_t fStabsStartIndex;
- uint32_t fStabsCount;
-
- static macho_section fgCommonsSection; // for us by tentative definitions
-};
-
-
-Reader* MakeReader(const macho_header* mh, const char* path, const ObjectFile::ReaderOptions& options)
-{
- return new Reader(mh, path, options);
-}
-
-
-Reader::Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options)
- : fPath(NULL), fOptions(options), fHeader(NULL), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL)
-{
- init(header, path);
-}
-
-Reader::Reader(const char* path)
- : fPath(NULL), fOptions(*(new ObjectFile::ReaderOptions())), fHeader(NULL), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL),
- fIndirectTable(NULL), fNonAtomStabsStartIndex(0), fNonAtomStabsCount(0)
-{
- struct stat stat_buf;
-
- int fd = ::open(path, O_RDONLY, 0);
- ::fstat(fd, &stat_buf);
- void* p = ::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE, fd, 0);
- ::close(fd);
- if ( ((macho_header*)p)->magic() == MH_MAGIC ) {
- init((macho_header*)p, path);
- return;
- }
- throw "add fat handling";
-}
-
-
-Reader::~Reader()
-{
-}
-
-
-bool Atom::atomCompare(const Atom* lhs, const Atom* rhs)
-{
- return lhs->fOffset < rhs->fOffset;
-}
-
-
-
-void Reader::init(const macho_header* header, const char* path)
-{
- // sanity check
-#if defined(ARCH_PPC)
- if ( (header->magic() != MH_MAGIC) || (header->cputype() != CPU_TYPE_POWERPC) )
- throw "not a valid ppc mach-o file";
-#elif defined(ARCH_I386)
- if ( (header->magic() != MH_MAGIC) || (header->cputype() != CPU_TYPE_I386) )
- throw "not a valid i386 mach-o file";
-#elif defined(ARCH_PPC64)
- if ( (header->magic() != MH_MAGIC_64) || (header->cputype() != CPU_TYPE_POWERPC64) )
- throw "not a valid ppc64 mach-o file";
-#endif
-
- // cache intersting pointers
- fPath = strdup(path);
- fHeader = header;
- const uint32_t cmd_count = header->ncmds();
- const macho_load_command* const cmds = (macho_load_command*)((char*)header + macho_header::size);
- 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;
- fSymbolCount = symtab->nsyms();
- fSymbols = (const macho_nlist*)((char*)header + symtab->symoff());
- fStrings = (char*)header + symtab->stroff();
- }
- break;
- case LC_DYSYMTAB:
- {
- const macho_dysymtab_command* dsymtab = (struct macho_dysymtab_command*)cmd;
- fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
- }
- break;
- default:
- if ( cmd->cmd() == macho_segment_command::command ) {
- fSegment= (macho_segment_command*)cmd;
- }
- break;
- }
- cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
- }
-
- // add all atoms that have entries in symbol table
- std::set<uint32_t> symbolAtomOffsets;
- for (uint32_t i=0; i < fSymbolCount; ++i) {
- const macho_nlist& sym = fSymbols[i];
- if ( (sym.n_type() & N_STAB) == 0 ) {
- uint8_t type = (sym.n_type() & N_TYPE);
- if ( (type == N_SECT) || ((type == N_UNDF) && (sym.n_value() != 0)) ) {
- // real definition or "tentative definition"
- Atom* newAtom = new Atom(*this, &sym);
- fAtoms.push_back(newAtom);
- symbolAtomOffsets.insert(newAtom->fOffset);
- }
- }
- }
-
- // add all points referenced in relocations
- const macho_section* const sectionsStart = (macho_section*)((char*)fSegment + sizeof(macho_segment_command));
- const macho_section* const sectionsEnd = §ionsStart[fSegment->nsects()];
- std::set<uint32_t> cleavePoints;
- std::set<uint32_t> dontCleavePoints;
- for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
- const macho_relocation_info* relocs = (macho_relocation_info*)((char*)(fHeader) + sect->reloff());
- const uint32_t relocCount = sect->nreloc();
- for (uint32_t r = 0; r < relocCount; ++r) {
- buildOffsetsSet(&relocs[r], sect, cleavePoints, dontCleavePoints);
- }
- }
- // add all stub functions and (non)lazy pointers
- std::set<uint32_t> deadStubOffsets;
- for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
- uint8_t type (sect->flags() & SECTION_TYPE);
- switch ( type ) {
- case S_SYMBOL_STUBS:
- {
- const uint32_t stubSize = sect->reserved2();
- // TVector glue sections are marked as S_SYMBOL_STUBS but are only 8 bytes
- if ( stubSize > 8 ) {
- for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += stubSize) {
- uint32_t stubAddr = sect->addr() + sectOffset;
- if ( cleavePoints.count(stubAddr) == 0 ) {
- cleavePoints.insert(stubAddr);
- deadStubOffsets.insert(stubAddr);
- }
- }
- }
- }
- break;
- case S_NON_LAZY_SYMBOL_POINTERS:
- case S_LAZY_SYMBOL_POINTERS:
- for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += sizeof(macho_uintptr_t)) {
- uint32_t pointerAddr = sect->addr() + sectOffset;
- cleavePoints.insert(pointerAddr);
- }
- break;
- }
- // also make sure each section break is a cleave point
- if ( sect->size() != 0 )
- cleavePoints.insert(sect->addr());
- }
-
- for (std::set<uint32_t>::iterator it=cleavePoints.begin(); it != cleavePoints.end(); it++) {
- uint32_t cleavePoint = *it;
- //printf("cleave offset 0x%08X, don't cleave=%d, isSymbol=%d\n", cleavePoint, dontCleavePoints.count(cleavePoint), symbolAtomOffsets.count(cleavePoint));
- // only create an atom if it is not a don't-cleave point and there is not already an atom at this offset
- if ( (dontCleavePoints.count(cleavePoint) == 0) && (symbolAtomOffsets.count(cleavePoint) == 0) )
- fAtoms.push_back(new Atom(*this, cleavePoint));
- }
-
- const uint32_t atomCount = fAtoms.size();
- if ( atomCount > 0 ) {
- // sort the atoms so the occur in source file order
- std::sort(fAtoms.begin(), fAtoms.end(), Atom::atomCompare);
-
- // tell each atom its size and follow on
- const bool dontDeadStrip = ((fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0);
- Atom* lastAtom = fAtoms[0];
- for (uint32_t i=1; i < atomCount; ++i) {
- Atom* thisAtom = fAtoms[i];
- if ( lastAtom->getSize() == 0 ) {
- if ( lastAtom->fSection == thisAtom->fSection )
- lastAtom->setSize(thisAtom->fOffset - lastAtom->fOffset);
- else
- lastAtom->setSize(lastAtom->fSection->addr() + lastAtom->fSection->size() - lastAtom->fOffset);
- }
- if ( dontDeadStrip )
- lastAtom->setFollowOnAtom(*thisAtom);
- lastAtom = thisAtom;
- }
- lastAtom = fAtoms[atomCount-1];
- if ( lastAtom->getSize() == 0 )
- lastAtom->setSize(lastAtom->fSection->addr() + lastAtom->fSection->size() - lastAtom->fOffset);
-
- // add relocation based references
- for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
- const macho_relocation_info* relocs = (macho_relocation_info*)((char*)(fHeader) + sect->reloff());
- const uint32_t relocCount = sect->nreloc();
- for (uint32_t r = 0; r < relocCount; ++r) {
- addRelocReference(sect, &relocs[r]);
- }
- }
-
- // add dead stubs to list to delete
- for (std::set<uint32_t>::iterator it=deadStubOffsets.begin(); it != deadStubOffsets.end(); it++) {
- Atom* deadStub = findAtomCoveringOffset(*it);
- this->deadStub(*deadStub);
- }
-
- // remove dead stubs and lazy pointers
- for (std::set<ObjectFile::Atom*>::iterator deadIt=fDeadAtoms.begin(); deadIt != fDeadAtoms.end(); deadIt++) {
- for (std::vector<Atom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
- if ( *deadIt == *it ) {
- fAtoms.erase(it);
- break;
- }
- }
- }
-
- }
-
- // process stabs debugging info
- if ( ! fOptions.fStripDebugInfo ) {
- // scan symbol table for stabs entries
- fNonAtomStabsStartIndex = 0xFFFFFFFF;
- fNonAtomStabsCount = 0;
- uint32_t possibleStart = 0;
- Atom* atom = NULL;
- const uint32_t atomCount = fAtoms.size();
- enum { start, inBeginEnd, foundFirst, inFunction } state = start;
- for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) {
- const macho_nlist* sym = &fSymbols[symbolIndex];
- uint8_t type = sym->n_type();
- if ( (type & N_STAB) != 0 ) {
- if ( fNonAtomStabsStartIndex == 0xFFFFFFFF )
- fNonAtomStabsStartIndex = symbolIndex;
- switch (state) {
- case start:
- if ( (type == N_SLINE) || (type == N_SOL) ) {
- possibleStart = symbolIndex;
- state = foundFirst;
- }
- else if ( type == N_BNSYM ) {
- macho_uintptr_t targetAddr = sym->n_value();
- atom = this->findAtomCoveringOffset(targetAddr);
- if ( (atom != NULL) || (atom->fOffset == targetAddr) ) {
- atom->fStabsStartIndex = symbolIndex;
- if ( fNonAtomStabsCount == 0 )
- fNonAtomStabsCount = symbolIndex - fNonAtomStabsStartIndex;
- }
- else {
- fprintf(stderr, "can't find atom for stabs 0x%02X at %08X in %s\n", type, targetAddr, path);
- atom = NULL;
- }
- state = inBeginEnd;
- }
- else if ( (type == N_STSYM) || (type == N_LCSYM) ) {
- macho_uintptr_t targetAddr = sym->n_value();
- atom = this->findAtomCoveringOffset(targetAddr);
- if ( (atom != NULL) || (atom->fOffset == targetAddr) ) {
- atom->fStabsStartIndex = symbolIndex;
- atom->fStabsCount = 1;
- if ( fNonAtomStabsCount == 0 )
- fNonAtomStabsCount = symbolIndex - fNonAtomStabsStartIndex;
- }
- else {
- fprintf(stderr, "can't find atom for stabs 0x%02X at %08X in %s\n", type, targetAddr, path);
- atom = NULL;
- }
- }
- else if ( type == N_GSYM ) {
- // n_value field is NOT atom address ;-(
- // need to find atom by name match
- const char* symString = &fStrings[sym->n_strx()];
- const char* colon = strchr(symString, ':');
- bool found = false;
- if ( colon != NULL ) {
- int nameLen = colon - symString;
- for (uint32_t searchIndex = 0; searchIndex < atomCount; ++searchIndex) {
- const char* atomName = fAtoms[searchIndex]->getName();
- if ( (atomName != NULL) && (strncmp(&atomName[1], symString, nameLen) == 0) ) {
- atom = fAtoms[searchIndex];
- atom->fStabsStartIndex = symbolIndex;
- atom->fStabsCount = 1;
- if ( fNonAtomStabsCount == 0 )
- fNonAtomStabsCount = symbolIndex - fNonAtomStabsStartIndex;
- found = true;
- break;
- }
- }
- }
- if ( !found ) {
- fprintf(stderr, "can't find atom for N_GSYM stabs %s in %s\n", symString, path);
- atom = NULL;
- }
- }
- else if ( type == N_LSYM ) {
- if ( fNonAtomStabsCount != 0 ) {
- // built with -gfull and some type definition not at start of source
- fNonAtomExtras.push_back(symbolIndex);
- }
- }
- break;
- case inBeginEnd:
- if ( type == N_ENSYM ) {
- state = start;
- if ( atom != NULL )
- atom->fStabsCount = symbolIndex - atom->fStabsStartIndex + 1;
- }
- break;
- case foundFirst:
- if ( (type == N_FUN) && (sym->n_sect() != 0) ) {
- state = inFunction;
- macho_uintptr_t targetAddr = sym->n_value();
- atom = this->findAtomCoveringOffset(targetAddr);
- if ( (atom == NULL) || (atom->fOffset != targetAddr) ) {
- fprintf(stderr, "can't find atom for stabs FUN index: %d at 0x%08llX in %s\n", symbolIndex, (uint64_t)targetAddr, path);
- atom = NULL;
- }
- else {
- atom->fStabsStartIndex = possibleStart;
- if ( fNonAtomStabsCount == 0 )
- fNonAtomStabsCount = possibleStart - fNonAtomStabsStartIndex;
- }
- }
- else if ( (type == N_FUN) && (sym->n_sect() == 0) ) {
- fprintf(stderr, "end stab FUN found without start FUN, index=%d in %s\n", symbolIndex, path);
- state = start;
- }
- break;
- case inFunction:
- if ( (type == N_FUN) && (sym->n_sect() == 0) ) {
- state = start;
- if ( atom != NULL )
- atom->fStabsCount = symbolIndex - atom->fStabsStartIndex + 1;
- }
- break;
- }
- }
- }
-
- }
-}
-
-
-void Reader::addRelocReference(const macho_section* sect, const macho_relocation_info* reloc)
-{
- uint32_t srcAddr;
- uint32_t dstAddr;
- Atom* src;
- Atom* dst;
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- uint32_t instruction;
-#endif
- uint32_t* fixUpPtr;
- if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
- fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- const macho_relocation_info* nextReloc = &reloc[1];
-#endif
- switch ( reloc->r_type() ) {
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- case PPC_RELOC_BR24:
- {
- if ( reloc->r_extern() ) {
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- int32_t displacement = (instruction & 0x03FFFFFC);
- if ( (displacement & 0x02000000) != 0 )
- displacement |= 0xFC000000;
- uint32_t offsetInTarget = sect->addr() + reloc->r_address() + displacement;
- srcAddr = sect->addr() + reloc->r_address();
- src = findAtomCoveringOffset(srcAddr);
- const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
- const char* targetName = &fStrings[targetSymbol->n_strx()];
- src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupBranch24, targetName, offsetInTarget, 0);
- }
- else {
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- if ( (instruction & 0x4C000000) == 0x48000000 ) {
- int32_t displacement = (instruction & 0x03FFFFFC);
- if ( (displacement & 0x02000000) != 0 )
- displacement |= 0xFC000000;
- srcAddr = sect->addr() + reloc->r_address();
- dstAddr = srcAddr + displacement;
- src = findAtomCoveringOffset(srcAddr);
- dst = findAtomCoveringOffset(dstAddr);
- this->addCallSiteReference(*src, srcAddr - src->fOffset, Reference::ppcFixupBranch24, *dst, 0, dstAddr - dst->fOffset);
- }
- }
- }
- break;
- case PPC_RELOC_BR14:
- {
- if ( reloc->r_extern() ) {
- srcAddr = sect->addr() + reloc->r_address();
- src = findAtomCoveringOffset(srcAddr);
- const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
- const char* targetName = &fStrings[targetSymbol->n_strx()];
- src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupBranch14, targetName, 0, 0);
- }
- else {
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- int32_t displacement = (instruction & 0x0000FFFC);
- if ( (displacement & 0x00008000) != 0 )
- displacement |= 0xFFFF0000;
- srcAddr = sect->addr() + reloc->r_address();
- dstAddr = srcAddr + displacement;
- src = findAtomCoveringOffset(srcAddr);
- dst = findAtomCoveringOffset(dstAddr);
- this->addCallSiteReference(*src, srcAddr - src->fOffset, Reference::ppcFixupBranch14, *dst, 0, dstAddr - dst->fOffset);
- }
- }
- break;
- case PPC_RELOC_PAIR:
- // skip, processed by a previous look ahead
- break;
- case PPC_RELOC_LO16:
- {
- if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
- printf("PPC_RELOC_LO16 missing following pair\n");
- break;
- }
- srcAddr = sect->addr() + reloc->r_address();
- if ( reloc->r_extern() ) {
- const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
- const char* targetName = &fStrings[targetSymbol->n_strx()];
- src = findAtomCoveringOffset(srcAddr);
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFF);
- src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow16, targetName, dstAddr, 0);
- }
- else {
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- int16_t lowBits = (instruction & 0xFFFF);
- dstAddr = (nextReloc->r_address() << 16) + (int32_t)lowBits;
- if ( (lowBits & 0x8000) != 0 )
- dstAddr += 0x10000;
- addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsLow16, 0);
- }
- }
- break;
- case PPC_RELOC_LO14:
- {
- if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
- printf("PPC_RELOC_LO14 missing following pair\n");
- break;
- }
- srcAddr = sect->addr() + reloc->r_address();
- if ( reloc->r_extern() ) {
- const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
- const char* targetName = &fStrings[targetSymbol->n_strx()];
- src = findAtomCoveringOffset(srcAddr);
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC);
- src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow14, targetName, dstAddr, 0);
- }
- else {
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC);
- addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsLow14, 0);
- }
- }
- break;
- case PPC_RELOC_HI16:
- {
- if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
- printf("PPC_RELOC_HI16 missing following pair\n");
- break;
- }
- srcAddr = sect->addr() + reloc->r_address();
- if ( reloc->r_extern() ) {
- const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
- const char* targetName = &fStrings[targetSymbol->n_strx()];
- src = findAtomCoveringOffset(srcAddr);
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
- src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsHigh16, targetName, dstAddr, 0);
- }
- else {
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
- addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsHigh16, 0);
- }
- }
- break;
- case PPC_RELOC_HA16:
- {
- if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
- printf("PPC_RELOC_HA16 missing following pair\n");
- break;
- }
- srcAddr = sect->addr() + reloc->r_address();
- if ( reloc->r_extern() ) {
- const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
- const char* targetName = &fStrings[targetSymbol->n_strx()];
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF);
- dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
- src = findAtomCoveringOffset(srcAddr);
- src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsHigh16AddLow, targetName, dstAddr, 0);
- }
- else {
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF);
- dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
- addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsHigh16AddLow, 0);
- }
- }
- break;
- case GENERIC_RELOC_VANILLA:
- {
- srcAddr = sect->addr() + reloc->r_address();
- Atom* srcAtom = findAtomCoveringOffset(srcAddr);
- uint32_t offsetInSrcAtom = srcAddr - srcAtom->fOffset;
- macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
- if ( reloc->r_extern() ) {
- const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
- uint8_t type = targetSymbol->n_type() & N_TYPE;
- if ( type == N_UNDF ) {
- const char* targetName = &fStrings[targetSymbol->n_strx()];
- macho_uintptr_t addend = pointerValue;
- // ppc lazy pointers have initial reference to dyld_stub_binding_helper
- if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
- std::vector<ObjectFile::Reference*>& refs = srcAtom->getReferences();
- if ( refs.size() > 0 ) {
- Reference* ref = (Reference*)refs[0];
- #if defined(ARCH_PPC64)
- // hack to work around bad crt1.o in Mac OS X 10.4
- targetName = "dyld_stub_binding_helper";
- #endif
- ref->setFromTargetName(targetName);
- }
- else {
- fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", srcAtom->getDisplayName(), refs.size());
- }
- }
- #if defined(ARCH_PPC64)
- // hack to work around bad crt1.o in Mac OS X 10.4
- else if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) {
- // ignore extra relocation
- }
- #endif
- else {
- srcAtom->addByNameReference(offsetInSrcAtom, Reference::pointer, targetName, addend, 0);
- }
- }
- else {
- dstAddr = targetSymbol->n_value();
- Atom* dstAtom = findAtomCoveringOffset(dstAddr);
- macho_uintptr_t addend = pointerValue;
- // ppc lazy pointers have initial reference to dyld_stub_binding_helper
- if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
- std::vector<ObjectFile::Reference*>& refs = srcAtom->getReferences();
- if ( refs.size() > 0 ) {
- Reference* ref = (Reference*)refs[0];
- ref->setFromTarget(*dstAtom);
- ref->setFromTargetOffset(dstAddr - dstAtom->fOffset);
- }
- else {
- fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", srcAtom->getDisplayName(), refs.size());
- }
- }
- else {
- srcAtom->addReference(offsetInSrcAtom, Reference::pointer, *dstAtom, addend, 0);
- }
- }
- }
- else {
- Atom* dstAtom = findAtomCoveringOffset(pointerValue);
- // lazy pointers have references to dyld_stub_binding_helper which need to be ignored
- if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
- std::vector<ObjectFile::Reference*>& refs = srcAtom->getReferences();
- if ( refs.size() > 0 ) {
- Reference* ref = (Reference*)refs[0];
- ref->setFromTarget(*dstAtom);
- ref->setFromTargetOffset(pointerValue - dstAtom->fOffset);
- }
- else {
- fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", srcAtom->getDisplayName(), refs.size());
- }
- }
- else {
- srcAtom->addReference(offsetInSrcAtom, Reference::pointer, *dstAtom, pointerValue-dstAtom->fOffset, 0);
- }
- }
- }
- break;
- case PPC_RELOC_JBSR:
- // ignore for now
- break;
-#endif
-#if defined(ARCH_I386)
- case GENERIC_RELOC_VANILLA:
- {
- srcAddr = sect->addr() + reloc->r_address();
- src = findAtomCoveringOffset(srcAddr);
- if ( reloc->r_length() != 2 )
- throw "bad vanilla relocation length";
- Reference::Kind kind;
- macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
- if ( reloc->r_pcrel() ) {
- kind = Reference::x86FixupBranch32;
- pointerValue += srcAddr + sizeof(macho_uintptr_t);
- }
- else {
- kind = Reference::pointer;
- }
- uint32_t offsetInSrcAtom = srcAddr - src->fOffset;
- if ( reloc->r_extern() ) {
- const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
- uint8_t type = targetSymbol->n_type() & N_TYPE;
- if ( type == N_UNDF ) {
- const char* targetName = &fStrings[targetSymbol->n_strx()];
- macho_uintptr_t addend = pointerValue;
- src->addByNameReference(offsetInSrcAtom, kind, targetName, addend, 0);
- }
- else {
- dstAddr = targetSymbol->n_value();
- dst = findAtomCoveringOffset(dstAddr);
- macho_uintptr_t addend = pointerValue - dstAddr;
- src->addReference(offsetInSrcAtom, kind, *dst, addend, 0);
- }
- }
- else {
- dst = findAtomCoveringOffset(pointerValue);
- // lazy pointers have references to dyld_stub_binding_helper which need to be ignored
- if ( (src->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
- std::vector<ObjectFile::Reference*>& refs = src->getReferences();
- if ( refs.size() == 1 ) {
- Reference* ref = (Reference*)refs[0];
- ref->setFromTarget(*dst);
- ref->setFromTargetOffset(pointerValue - dst->fOffset);
- }
- else {
- fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", src->getDisplayName(), refs.size());
- }
- }
- else if ( ((uint8_t*)fixUpPtr)[-1] == 0xE8 ) // special case call instruction
- this->addCallSiteReference(*src, offsetInSrcAtom, kind, *dst, 0, pointerValue - dst->fOffset);
- else
- src->addReference(offsetInSrcAtom, kind, *dst, 0, 0);
- }
- }
- break;
-#endif
-
- default:
- printf("unknown relocation type %d\n", 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];
- // 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();
- }
- }
- else {
- if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
- nextRelocIsPair = true;
- nextRelocAddress = nextSReloc->r_address();
- nextRelocValue = nextSReloc->r_value();
- }
- }
- switch (sreloc->r_type()) {
- case GENERIC_RELOC_VANILLA:
- {
- macho_uintptr_t betterDstAddr = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)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)
- Atom* src = findAtomCoveringOffset(srcAddr);
- Atom* dst = findAtomCoveringOffset(dstAddr);
- src->addReference(srcAddr - src->fOffset, Reference::pointer, *dst, betterDstAddr - dst->fOffset, 0);
- }
- break;
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- case PPC_RELOC_BR24:
- {
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- if ( (instruction & 0x4C000000) == 0x48000000 ) {
- int32_t displacement = (instruction & 0x03FFFFFC);
- if ( (displacement & 0x02000000) != 0 )
- displacement |= 0xFC000000;
- srcAddr = sect->addr() + sreloc->r_address();
- dstAddr = sreloc->r_value();
- src = findAtomCoveringOffset(srcAddr);
- dst = findAtomCoveringOffset(dstAddr);
- this->addCallSiteReference(*src, srcAddr - src->fOffset, Reference::ppcFixupBranch24, *dst, 0, srcAddr + displacement - sreloc->r_value());
- }
- }
- break;
- case PPC_RELOC_LO16_SECTDIFF:
- {
- if ( ! nextRelocIsPair) {
- printf("PPC_RELOC_LO16_SECTDIFF missing following PAIR\n");
- break;
- }
- src = findAtomCoveringOffset(srcAddr);
- dst = findAtomCoveringOffset(dstAddr);
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- int16_t lowBits = (instruction & 0xFFFF);
- int32_t displacement = (nextRelocAddress << 16) + (int32_t)lowBits;
- if ( (lowBits & 0x8000) != 0 )
- displacement += 0x10000;
- uint32_t picBaseOffset = nextRelocValue - src->fOffset;
- int64_t dstOffset = src->fOffset + picBaseOffset + displacement - dst->fOffset;
- src->addReference(srcAddr - src->fOffset, Reference::ppcFixupPicBaseLow16, *dst, dstOffset, picBaseOffset);
- }
- break;
- case PPC_RELOC_LO14_SECTDIFF:
- {
- if ( ! nextRelocIsPair) {
- printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
- break;
- }
- src = findAtomCoveringOffset(srcAddr);
- dst = findAtomCoveringOffset(dstAddr);
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- int16_t lowBits = (instruction & 0xFFFC);
- int32_t displacement = (nextRelocAddress << 16) + (int32_t)lowBits;
- if ( (lowBits & 0x8000) != 0 )
- displacement += 0x10000;
- uint32_t picBaseOffset = nextRelocValue - src->fOffset;
- int64_t dstOffset = src->fOffset + picBaseOffset + displacement - dst->fOffset;
- src->addReference(srcAddr - src->fOffset, Reference::ppcFixupPicBaseLow14, *dst, dstOffset, picBaseOffset);
- }
- break;
- case PPC_RELOC_HA16_SECTDIFF:
- {
- if ( ! nextRelocIsPair) {
- printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
- break;
- }
- src = findAtomCoveringOffset(srcAddr);
- dst = findAtomCoveringOffset(dstAddr);
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- int16_t lowBits = (nextRelocAddress & 0x0000FFFF);
- int32_t displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
- uint32_t picBaseOffset = nextRelocValue - src->fOffset;
- int64_t dstOffset = src->fOffset + picBaseOffset + displacement - dst->fOffset;
- src->addReference(srcAddr - src->fOffset, Reference::ppcFixupPicBaseHigh16, *dst, dstOffset, picBaseOffset);
- }
- break;
- case PPC_RELOC_LO14:
- {
- if ( ! nextRelocIsPair) {
- printf("PPC_RELOC_LO14 missing following PAIR\n");
- break;
- }
- src = findAtomCoveringOffset(srcAddr);
- dst = findAtomCoveringOffset(dstAddr);
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- int16_t lowBits = (instruction & 0xFFFC);
- uint32_t betterDstAddr = (nextRelocAddress << 16) + (int32_t)lowBits;
- if ( (lowBits & 0x8000) != 0 )
- betterDstAddr += 0x10000;
- src->addReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow14, *dst, betterDstAddr - dst->fOffset, 0);
- }
- break;
- case PPC_RELOC_LO16:
- {
- if ( ! nextRelocIsPair) {
- printf("PPC_RELOC_LO16 missing following PAIR\n");
- break;
- }
- src = findAtomCoveringOffset(srcAddr);
- dst = findAtomCoveringOffset(dstAddr);
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- int16_t lowBits = (instruction & 0xFFFF);
- uint32_t betterDstAddr = (nextRelocAddress << 16) + (int32_t)lowBits;
- if ( (lowBits & 0x8000) != 0 )
- betterDstAddr += 0x10000;
- src->addReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow16, *dst, betterDstAddr - dst->fOffset, 0);
- }
- break;
- case PPC_RELOC_HA16:
- {
- if ( ! nextRelocIsPair) {
- printf("PPC_RELOC_HA16 missing following PAIR\n");
- break;
- }
- src = findAtomCoveringOffset(srcAddr);
- dst = findAtomCoveringOffset(dstAddr);
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- int16_t lowBits = (nextRelocAddress & 0xFFFF);
- uint32_t betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
- src->addReference(srcAddr - src->fOffset, Reference::ppcFixupAbsHigh16AddLow, *dst, betterDstAddr - dst->fOffset, 0);
- }
- break;
- case PPC_RELOC_SECTDIFF:
- case PPC_RELOC_LOCAL_SECTDIFF:
- {
- const macho_scattered_relocation_info* nextReloc = &sreloc[1];
- if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
- printf("PPC_RELOC_SECTDIFF missing following pair\n");
- break;
- }
- srcAddr = sect->addr() + sreloc->r_address();
- uint32_t toAddr = sreloc->r_value();
- uint32_t fromAddr = nextReloc->r_value();
- src = findAtomCoveringOffset(srcAddr);
- Atom* to = findAtomCoveringOffset(toAddr);
- Atom* from = findAtomCoveringOffset(fromAddr);
- //macho_intptr_t pointerValue = *(macho_intptr_t*)fixUpPtr;
- //uint64_t toOffset = to->fOffset;
- //uint64_t fromOffset = from->fOffset;
- //int64_t pointerValue64 = pointerValue;
- //uint64_t addend = pointerValue64 - (toOffset - fromOffset);
- Reference::Kind kind = Reference::pointer32Difference;
- if ( sreloc->r_length() == 3 )
- kind = Reference::pointer64Difference;
- src->addDifferenceReference(srcAddr - src->fOffset, kind, *to, toAddr - to->fOffset, *from, fromAddr - from->fOffset);
- }
- break;
- case PPC_RELOC_PAIR:
- break;
- case PPC_RELOC_HI16_SECTDIFF:
- printf("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF\n");
- break;
-#endif
-#if defined(ARCH_I386)
- case GENERIC_RELOC_SECTDIFF:
- case GENERIC_RELOC_LOCAL_SECTDIFF:
- {
- if ( nextSReloc->r_type() != GENERIC_RELOC_PAIR ) {
- printf("GENERIC_RELOC_SECTDIFF missing following pair\n");
- break;
- }
- srcAddr = sect->addr() + sreloc->r_address();
- uint32_t toAddr = sreloc->r_value();
- uint32_t fromAddr = nextSReloc->r_value();
- src = findAtomCoveringOffset(srcAddr);
- Atom* to = findAtomCoveringOffset(toAddr);
- Atom* from = findAtomCoveringOffset(fromAddr);
- Reference::Kind kind = Reference::pointer32Difference;
- if ( sreloc->r_length() != 2 )
- throw "bad length for GENERIC_RELOC_SECTDIFF";
- src->addDifferenceReference(srcAddr - src->fOffset, kind, *to, toAddr - to->fOffset, *from, fromAddr - from->fOffset);
- }
- break;
- case GENERIC_RELOC_PAIR:
- // do nothing, already used via a look ahead
- break;
-#endif
- default:
- printf("unknown scattered relocation type %d\n", sreloc->r_type());
- }
-
- }
-}
-
-
-void Reader::addFixUp(uint32_t srcAddr, uint32_t dstAddr, Reference::Kind kind, uint32_t picBaseAddr)
-{
- Atom* src = findAtomCoveringOffset(srcAddr);
- Atom* dst = findAtomCoveringOffset(dstAddr);
- src->addReference(srcAddr - src->fOffset, kind, *dst, dstAddr - dst->fOffset, picBaseAddr - src->fOffset);
-}
-
-Atom* Reader::findAtomCoveringOffset(uint32_t offset)
-{
-#if 1
- // binary search of sorted atoms
- Atom** base = &fAtoms[0];
- for (uint32_t n = fAtoms.size(); n > 0; n /= 2) {
- Atom** pivot = &base[n/2];
- Atom* pivotAtom = *pivot;
- if ( pivotAtom->fOffset <= offset ) {
- if ( offset < (pivotAtom->fOffset + pivotAtom->fSize) )
- return pivotAtom;
- // key > pivot
- // move base to symbol after pivot
- base = &pivot[1];
- --n;
- }
- else {
- // key < pivot
- // keep same base
- }
- }
- // possible that last atom is zero length
- Atom* lastAtom = fAtoms.back();
- if ( (lastAtom->fOffset == offset) && (lastAtom->fSize == 0) )
- return lastAtom;
-#else
- const uint32_t atomCount = fAtoms.size();
- for (uint32_t i=0; i < atomCount; ++i) {
- Atom* atom = fAtoms[i];
- if ( (atom->fOffset <= offset) && (offset < (atom->fOffset + atom->fSize)) )
- return atom;
- }
-#endif
- throwf("address 0x%08X is not in any atom", offset);
-}
-
-uint32_t Reader::findAtomIndex(const Atom& atom)
-{
- const Atom* target = &atom;
- const uint32_t atomCount = fAtoms.size();
- for (uint32_t i=0; i < atomCount; ++i) {
- Atom* anAtom = fAtoms[i];
- if ( anAtom == target )
- return i;
- }
- return 0xffffffff;
-}
-
-static void insertOffset(std::set<uint32_t>& offsets, uint32_t value)
-{
- //fprintf(stderr, "cleave point at 0x%08X\n", value);
- offsets.insert(value);
-}
-
-void Reader::insertOffsetIfNotText(std::set<uint32_t>& offsets, uint32_t value)
-{
- const macho_section* sect = findSectionCoveringOffset(value);
- if ( (sect == NULL) || (strcmp(sect->segname(),"__TEXT") != 0) || (strncmp(sect->sectname(),"__text", 6) != 0) ) {
- offsets.insert(value);
- }
-}
-
-void Reader::insertOffsetIfText(std::set<uint32_t>& offsets, uint32_t value)
-{
- const macho_section* sect = findSectionCoveringOffset(value);
- if ( (sect != NULL) && (strcmp(sect->segname(),"__TEXT") == 0) && (strncmp(sect->sectname(),"__text", 6) == 0) ) {
- //fprintf(stderr, "don't cleave point at 0x%08X\n", value);
- offsets.insert(value);
- }
-}
-
-const macho_section* Reader::findSectionCoveringOffset(uint32_t offset)
-{
- const macho_section* const sectionsStart = (macho_section*)((char*)fSegment + sizeof(macho_segment_command));
- const macho_section* const sectionsEnd = §ionsStart[fSegment->nsects()];
- for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
- if ( (sect->addr() <= offset) && (offset < (sect->addr() + sect->size())) )
- return sect;
- }
- return NULL;
-}
-
-
-void Reader::buildOffsetsSet(const macho_relocation_info* reloc, const macho_section* sect, std::set<uint32_t>& cleavePoints, std::set<uint32_t>& dontCleavePoints)
-{
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- uint32_t targetAddr;
-#endif
- if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
- uint32_t* fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- uint32_t instruction;
-#endif
- switch ( reloc->r_type() ) {
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- case PPC_RELOC_BR14:
- // do nothing. local branch should not cleave
- break;
- case PPC_RELOC_BR24:
- {
- if ( ! reloc->r_extern() ) {
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- if ( (instruction & 0x4C000000) == 0x48000000 ) {
- int32_t displacement = (instruction & 0x03FFFFFC);
- if ( (displacement & 0x02000000) != 0 )
- displacement |= 0xFC000000;
- //cleavePoints.insert(reloc->r_address() + displacement);
- insertOffset(cleavePoints, sect->addr() + reloc->r_address() + displacement);
- }
- }
- }
- break;
- case PPC_RELOC_PAIR:
- // skip, processed by a look ahead
- break;
- case PPC_RELOC_LO16:
- {
- const macho_relocation_info* nextReloc = &reloc[1];
- if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
- printf("PPC_RELOC_LO16 missing following pair\n");
- break;
- }
- if ( ! reloc->r_extern() ) {
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- targetAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFF);
- //cleavePoints.insert(targetAddr);
- insertOffset(cleavePoints, (targetAddr));
- }
- }
- break;
- case PPC_RELOC_LO14:
- {
- const macho_relocation_info* nextReloc = &reloc[1];
- if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
- printf("PPC_RELOC_LO14 missing following pair\n");
- break;
- }
- if ( ! reloc->r_extern() ) {
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- targetAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC);
- //cleavePoints.insert(targetAddr);
- insertOffset(cleavePoints, (targetAddr));
- }
- }
- break;
- case PPC_RELOC_HI16:
- {
- const macho_relocation_info* nextReloc = &reloc[1];
- if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
- printf("PPC_RELOC_HI16 missing following pair\n");
- break;
- }
- if ( ! reloc->r_extern() ) {
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- targetAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
- //cleavePoints.insert(targetAddr);
- insertOffset(cleavePoints, targetAddr);
- }
- }
- break;
- case PPC_RELOC_HA16:
- {
- const macho_relocation_info* nextReloc = &reloc[1];
- if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
- printf("PPC_RELOC_HA16 missing following pair\n");
- break;
- }
- if ( ! reloc->r_extern() ) {
- instruction = OSSwapBigToHostInt32(*fixUpPtr);
- int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF);
- targetAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
- //cleavePoints.insert(targetAddr);
- insertOffset(cleavePoints, targetAddr);
- }
- }
- break;
- case PPC_RELOC_JBSR:
- // ignore for now
- break;
-#endif
- case GENERIC_RELOC_VANILLA:
- {
-#if defined(ARCH_PPC64)
- if ( reloc->r_length() != 3 )
- throw "vanilla pointer relocation found that is not 8-bytes";
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
- if ( reloc->r_length() != 2 )
- throw "vanilla pointer relocation found that is not 4-bytes";
-#endif
- //fprintf(stderr, "addr=0x%08X, pcrel=%d, len=%d, extern=%d, type=%d\n", reloc->r_address(), reloc->r_pcrel(), reloc->r_length(), reloc->r_extern(), reloc->r_type());
- if ( !reloc->r_extern() ) {
- macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
-#if defined(ARCH_I386)
- // i386 stubs have internal relocs that should not cause a cleave
- if ( (sect->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS )
- break;
-#endif
- if ( reloc->r_pcrel() )
- pointerValue += reloc->r_address() + sect->addr() + sizeof(macho_uintptr_t);
- // a pointer into code does not cleave the code (gcc always pointers to labels)
- insertOffsetIfNotText(cleavePoints, pointerValue);
- }
- }
- break;
- default:
- printf("unknown relocation type %d\n", reloc->r_type());
- }
- }
- else {
- const macho_scattered_relocation_info* sreloc = (macho_scattered_relocation_info*)reloc;
- switch (sreloc->r_type()) {
- case GENERIC_RELOC_VANILLA:
- insertOffset(cleavePoints, sreloc->r_value());
- break;
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- case PPC_RELOC_BR24:
- insertOffset(cleavePoints, sreloc->r_value());
- break;
- case PPC_RELOC_HA16:
- case PPC_RELOC_HI16:
- case PPC_RELOC_LO16:
- case PPC_RELOC_LO14:
- case PPC_RELOC_LO16_SECTDIFF:
- case PPC_RELOC_LO14_SECTDIFF:
- case PPC_RELOC_HA16_SECTDIFF:
- case PPC_RELOC_HI16_SECTDIFF:
- //cleavePoints.insert(sreloc->r_value());
- insertOffset(cleavePoints, sreloc->r_value());
- insertOffsetIfText(dontCleavePoints, sreloc->r_value());
- break;
- case PPC_RELOC_SECTDIFF:
- case PPC_RELOC_LOCAL_SECTDIFF:
- // these do not cleave up a .o file
- // a SECTDIFF in __TEXT probably means a jump table, and should prevent a cleave
- {
- const macho_scattered_relocation_info* nextReloc = &sreloc[1];
- if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
- printf("PPC_RELOC_SECTDIFF missing following pair\n");
- break;
- }
- insertOffsetIfText(dontCleavePoints, sreloc->r_value());
- insertOffsetIfText(dontCleavePoints, nextReloc->r_value());
- }
- break;
- case PPC_RELOC_PAIR:
- // do nothing, already used via a look ahead
- break;
-#endif
-#if defined(ARCH_I386)
- case GENERIC_RELOC_SECTDIFF:
- case GENERIC_RELOC_LOCAL_SECTDIFF:
- // these do not cleave up a .o file
- // a SECTDIFF in __TEXT probably means a jump table, and should prevent a cleave
- {
- const macho_scattered_relocation_info* nextReloc = &sreloc[1];
- if ( nextReloc->r_type() != GENERIC_RELOC_PAIR ) {
- printf("GENERIC_RELOC_SECTDIFF missing following pair\n");
- break;
- }
- insertOffsetIfText(dontCleavePoints, sreloc->r_value());
- insertOffsetIfText(dontCleavePoints, nextReloc->r_value());
- }
- break;
- case GENERIC_RELOC_PAIR:
- // do nothing, already used via a look ahead
- break;
-#endif
- default:
- printf("unknown relocation type %d\n", sreloc->r_type());
- }
-
- }
-}
-
-
-Segment* Reader::makeSegmentFromSection(const macho_section* sect)
-{
- // make segment object if one does not already exist
- const uint32_t segmentCount = fSegments.size();
- for (uint32_t i=0; i < segmentCount; ++i) {
- Segment* seg = fSegments[i];
- if ( strcmp(sect->segname(), seg->getName()) == 0 )
- return seg;
- }
- Segment* seg = new Segment(sect);
- fSegments.push_back(seg);
- return seg;
-}
-
-macho_uintptr_t Reader::commonsOffset()
-{
- return fSegment->vmsize();
-}
-
-const char* Reader::getPath()
-{
- return fPath;
-}
-
-std::vector<class ObjectFile::Atom*>& Reader::getAtoms()
-{
- return (std::vector<class ObjectFile::Atom*>&)(fAtoms);
-}
-
-std::vector<class ObjectFile::Atom*>* Reader::getJustInTimeAtomsFor(const char* name)
-{
- // object files have no just-in-time atoms
- return NULL;
-}
-
-
-std::vector<ObjectFile::StabsInfo>* Reader::getStabsDebugInfo()
-{
- if ( fNonAtomStabsCount == 0 )
- return NULL;
-
- std::vector<ObjectFile::StabsInfo>* stabs = new std::vector<ObjectFile::StabsInfo>();
- stabs->reserve(fNonAtomStabsCount);
-
- for (uint32_t i=0; i < fNonAtomStabsCount; ++i) {
- const macho_nlist* sym = &fSymbols[fNonAtomStabsStartIndex+i];
- if ( (sym->n_type() & N_STAB) != 0 ) {
- ObjectFile::StabsInfo stab;
- stab.atomOffset = sym->n_value();
- stab.string = &fStrings[sym->n_strx()];
- stab.type = sym->n_type();
- stab.other = sym->n_sect();
- stab.desc = sym->n_desc();
- // for N_SO n_value is offset of first atom, but our gdb ignores this, so we omit that calculation
- if ( stab.type == N_SO )
- stab.atomOffset = 0;
- stabs->push_back(stab);
- }
- }
-
- // add any extra N_LSYM's not at start of symbol table
- for (std::vector<uint32_t>::iterator it=fNonAtomExtras.begin(); it != fNonAtomExtras.end(); ++it) {
- const macho_nlist* sym = &fSymbols[*it];
- ObjectFile::StabsInfo stab;
- stab.atomOffset = sym->n_value();
- stab.string = &fStrings[sym->n_strx()];
- stab.type = sym->n_type();
- stab.other = sym->n_sect();
- stab.desc = sym->n_desc();
- stabs->push_back(stab);
- }
-
- return stabs;
-}
-
-void Reader::deadStub(Atom& target)
-{
- // remove stub
- fDeadAtoms.insert(&target);
-
- // remove lazy pointer
- const int stubNameLen = strlen(target.fSynthesizedName);
- char lazyName[stubNameLen+8];
- strcpy(lazyName, target.fSynthesizedName);
- strcpy(&lazyName[stubNameLen-5], "$lazy_ptr");
- const uint32_t atomCount = fAtoms.size();
- for (uint32_t i=1; i < atomCount; ++i) {
- Atom* atom = fAtoms[i];
- if ( (atom->fSynthesizedName != NULL) && (strcmp(atom->fSynthesizedName, lazyName) == 0) ) {
- fDeadAtoms.insert(atom);
- break;
- }
- }
-}
-
-
-void Reader::addCallSiteReference(Atom& src, uint32_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint32_t picBaseOffset, uint32_t offsetInTargetAtom)
-{
- // the compiler some times produces stub to static functions and then calls the stubs
- // we need to skip the stub if a static function exists with the same name and remove the stub
- if ( target.isLazyStub() ) {
- const macho_section* section = target.fSection;
- uint32_t index = (target.fOffset - section->addr()) / section->reserved2();
- uint32_t indirectTableIndex = section->reserved1() + index;
- uint32_t symbolIndex = ENDIAN_READ32(fIndirectTable[indirectTableIndex]);
- if ( (symbolIndex & INDIRECT_SYMBOL_LOCAL) == 0 ) {
- const macho_nlist* sym = &fSymbols[symbolIndex];
- if ( (sym->n_value() != 0) && ((sym->n_type() & N_EXT) == 0) ) {
- Atom* betterTarget = this->findAtomCoveringOffset(sym->n_value());
- if ( (betterTarget != NULL) && (betterTarget->getScope() == ObjectFile::Atom::scopeTranslationUnit) ) {
- // use direct reference to static function
- src.addDirectReference(offsetInSrcAtom, kind, *betterTarget, offsetInTargetAtom, picBaseOffset);
-
- // remove stub and lazy pointer
- this->deadStub(target);
- return;
- }
- }
- }
- }
-
- // fall through to general case
- src.addReference(offsetInSrcAtom, kind, target, offsetInTargetAtom, picBaseOffset);
-}
-
-
-Atom::Atom(Reader& owner, const macho_nlist* symbol)
- : fOwner(owner), fSymbol(symbol), fOffset(0), fSize(0), fSection(NULL), fSegment(NULL), fSynthesizedName(NULL),
- fStabsStartIndex(0), fStabsCount(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
- const macho_section* sections = (macho_section*)((char*)fOwner.fSegment + sizeof(macho_segment_command));
- fSection = §ions[fSymbol->n_sect()-1];
- fSegment = owner.makeSegmentFromSection(fSection);
- fOffset = fSymbol->n_value();
- uint8_t type = fSection->flags() & SECTION_TYPE;
- switch ( type ) {
- case S_LAZY_SYMBOL_POINTERS:
- case S_NON_LAZY_SYMBOL_POINTERS:
- {
- // get target name out of indirect symbol table
- uint32_t index = (fOffset - fSection->addr()) / sizeof(macho_uintptr_t);
- index += fSection->reserved1();
- uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]);
- uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx();
- const char* name = &fOwner.fStrings[strOffset];
- Reference* ref = this->addByNameReference(0, Reference::pointer, name, 0, 0);
- if ( type == S_LAZY_SYMBOL_POINTERS ) {
- ref->setLazy(true);
- }
- }
- break;
- }
- }
- else if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) {
- // tentative definition
- fSize = symbol->n_value();
- fSection = getCommonsSection();
- fSegment = owner.makeSegmentFromSection(fSection);
- fOffset = owner.commonsOffset();
- }
- else {
- printf("unknown symbol type: %d\n", type);
- }
-}
-
-Atom::Atom(Reader& owner, uint32_t offset)
- : fOwner(owner), fSymbol(NULL), fOffset(offset), fSize(0), fSection(NULL), fSegment(NULL), fSynthesizedName(NULL),
- fStabsStartIndex(0), fStabsCount(0)
-{
- fSection = findSectionFromOffset(offset);
- fScope = ObjectFile::Atom::scopeLinkageUnit;
- fSegment = owner.makeSegmentFromSection(fSection);
- uint8_t type = fSection->flags() & SECTION_TYPE;
- switch ( type ) {
- case S_SYMBOL_STUBS:
- {
- uint32_t index = (offset - fSection->addr()) / fSection->reserved2();
- index += fSection->reserved1();
- uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]);
- uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx();
- const char* name = &fOwner.fStrings[strOffset];
- char* str = new char[strlen(name)+8];
- strcpy(str, name);
- strcat(str, "$stub");
- fSynthesizedName = str;
- }
- break;
- case S_LAZY_SYMBOL_POINTERS:
- case S_NON_LAZY_SYMBOL_POINTERS:
- {
- uint32_t index = (offset - fSection->addr()) / sizeof(macho_uintptr_t);
- index += fSection->reserved1();
- uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]);
- uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx();
- const char* name = &fOwner.fStrings[strOffset];
- 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;
- Reference* ref = this->addByNameReference(0, Reference::pointer, name, 0, 0);
- if ( type == S_LAZY_SYMBOL_POINTERS ) {
- ref->setLazy(true);
- }
- const macho_nlist* sym = &fOwner.fSymbols[symbolIndex];
- if ( (sym->n_type() & N_TYPE) == N_UNDF ) {
- if ( (sym->n_desc() & N_WEAK_REF) != 0 )
- ref->setWeak(true);
- }
- }
- break;
- }
-}
-
-
-Atom::~Atom()
-{
-}
-
-macho_section Atom::fgCommonsSection;
-
-
-bool Atom::isLazyStub()
-{
- return ( (fSection->flags() & SECTION_TYPE) == S_SYMBOL_STUBS);
-}
-
-const macho_section* Atom::getCommonsSection() {
- if ( strcmp(fgCommonsSection.sectname(), "__common") != 0 ) {
- fgCommonsSection.set_sectname("__common");
- fgCommonsSection.set_segname("__DATA");
- fgCommonsSection.set_flags(S_ZEROFILL);
- }
- return &fgCommonsSection;
-}
-
-ObjectFile::Reader* Atom::getFile() const
-{
- return &fOwner;
-}
-
-
-const char* Atom::getName() const
-{
- if ( fSymbol != NULL )
- return &fOwner.fStrings[fSymbol->n_strx()];
- else
- return fSynthesizedName;
-}
-
-const char* Atom::getDisplayName() const
-{
- if ( fSymbol != NULL )
- return &fOwner.fStrings[fSymbol->n_strx()];
-
- if ( fSynthesizedName != NULL )
- return fSynthesizedName;
-
- static char temp[32];
- sprintf(temp, "atom #%u", fOwner.findAtomIndex(*this));
- return temp;
-}
-
-ObjectFile::Atom::Scope Atom::getScope() const
-{
- return fScope;
-}
-
-void Atom::setScope(ObjectFile::Atom::Scope newScope)
-{
- fScope = newScope;
-}
-
-
-bool Atom::isWeakDefinition() const
-{
- if ( isTentativeDefinition() )
- return true;
- if ( fSymbol != NULL )
- return ( (fSymbol->n_desc() & N_WEAK_DEF) != 0 );
- uint8_t type = fSection->flags() & SECTION_TYPE;
- switch ( type ) {
- case S_SYMBOL_STUBS:
- case S_LAZY_SYMBOL_POINTERS:
- case S_NON_LAZY_SYMBOL_POINTERS:
- return true;
- }
- return false;
-}
-
-bool Atom::isTentativeDefinition() const
-{
- return (fSection == &fgCommonsSection);
-}
-
-bool Atom::isCoalesableByName() const
-{
- uint8_t type = fSection->flags() & SECTION_TYPE;
- switch ( type ) {
- case S_SYMBOL_STUBS:
- case S_COALESCED:
- return true;
- };
- if ( isTentativeDefinition() )
- return true;
- return false;
-}
-
-bool Atom::isCoalesableByValue() const
-{
- uint8_t type = fSection->flags() & SECTION_TYPE;
- switch ( type ) {
- case S_CSTRING_LITERALS:
- case S_4BYTE_LITERALS:
- case S_8BYTE_LITERALS:
- return true;
- };
- return false;
-}
-
-bool Atom::isZeroFill() const
-{
- return ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL);
-}
-
-bool Atom::dontDeadStrip() const
-{
- if ( fSymbol != NULL )
- return ( (fSymbol->n_desc() & N_NO_DEAD_STRIP) != 0 );
- return false;
-}
-
-
-bool Atom::dontStripName() const
-{
- if ( fSymbol != NULL )
- return ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0 );
- return false;
-}
-
-bool Atom::isImportProxy() const
-{
- return false;
-}
-
-
-uint64_t Atom::getSize() const
-{
- //return fOffset;
- return fSize;
-}
-
-
-std::vector<ObjectFile::Reference*>& Atom::getReferences() const
-{
- return (std::vector<ObjectFile::Reference*>&)(fReferences);
-}
-
-bool Atom::mustRemainInSection() const
-{
- return true;
-}
-
-const char* Atom::getSectionName() const
-{
- if ( strlen(fSection->sectname()) > 15 ) {
- static char temp[18];
- strncpy(temp, fSection->sectname(), 16);
- temp[17] = '\0';
- return temp;
- }
- return fSection->sectname();
-}
-
-Segment& Atom::getSegment() const
-{
- return *fSegment;
-}
-
-bool Atom::requiresFollowOnAtom() const
-{
- // requires follow-on if built with old compiler and not the last atom
- if ( (fOwner.fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0) {
- if ( fOwner.findAtomIndex(*this) < (fOwner.fAtoms.size()-1) )
- return true;
- }
- return false;
-}
-
-ObjectFile::Atom& Atom::getFollowOnAtom() const
-{
- uint32_t myIndex = fOwner.findAtomIndex(*this);
- return *fOwner.fAtoms[myIndex+1];
-}
-
-std::vector<ObjectFile::StabsInfo>* Atom::getStabsDebugInfo() const
-{
- if ( fStabsCount == 0 )
- return NULL;
-
- std::vector<ObjectFile::StabsInfo>* stabs = new std::vector<ObjectFile::StabsInfo>();
- stabs->reserve(fStabsCount);
-
- for (uint32_t i=0; i < fStabsCount; ++i) {
- const macho_nlist* sym = &fOwner.fSymbols[fStabsStartIndex+i];
- if ( (sym->n_type() & N_STAB) != 0 ) {
- ObjectFile::StabsInfo stab;
- stab.atomOffset = sym->n_value();
- stab.string = &fOwner.fStrings[sym->n_strx()];
- stab.type = sym->n_type();
- stab.other = sym->n_sect();
- stab.desc = sym->n_desc();
- switch ( stab.type ) {
- case N_FUN:
- if ( stab.other == 0 )
- break;
- // end of function N_FUN has size (not address) so should not be adjusted
- // fall through
- case N_BNSYM:
- case N_ENSYM:
- case N_LBRAC:
- case N_RBRAC:
- case N_SLINE:
- case N_STSYM:
- case N_LCSYM:
- // all these stab types need their value changed from an absolute address to the atom offset
- stab.atomOffset -= fOffset;
- break;
- }
- stabs->push_back(stab);
- }
- }
-
- return stabs;
-}
-
-uint8_t Atom::getAlignment() const
-{
- // mach-o file format has no alignment information for atoms - just whole sections
- if ( fSection != NULL ) {
- if ( isTentativeDefinition() ) {
- // common symbols align to their size
- // that is, a 4-byte common aligns to 4-bytes
- // to be safe, odd size commons align to the next power-of-2 size
- uint8_t alignment = (uint8_t)ceil(log2(this->getSize()));
- // limit alignment of extremely large commons to 2^15 bytes (8-page)
- if ( alignment < 15 )
- return alignment;
- else
- return 15;
- }
- else {
- // so we assume every atom requires the same alignment as the whole section
- return fSection->align();
- }
- }
- else {
- return 2;
- }
-}
-
-void Atom::copyRawContent(uint8_t buffer[]) const
-{
- // copy base bytes
- if ( isZeroFill() )
- bzero(buffer, fSize);
- else {
- uint32_t fileOffset = fSection->offset() - fSection->addr() + fOffset;
- memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
- }
-}
-
-void Atom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- const uint32_t referencesCount = fReferences.size();
-
- // skip copy if no fix-ups
- if ( referencesCount == 0 ) {
- uint32_t fileOffset = fSection->offset() - fSection->addr() + fOffset;
- writer.write(0, (char*)(fOwner.fHeader)+fileOffset, fSize);
- return;
- }
-
- // copy base bytes
- uint8_t buffer[this->getSize()];
- this->copyRawContent(buffer);
-
- // apply any fix-ups
- for (uint32_t i=0; i < referencesCount; ++i) {
- Reference* ref = fReferences[i];
- uint32_t offset = ref->getFixUpOffset();
- uint32_t* instructionPtr = (uint32_t*)&buffer[offset];
- ObjectFile::Atom& target = ref->getTarget();
- if ( &target == NULL ) {
- if ( finalLinkedImage )
- throw "target not found";
- else
- continue;
- }
- uint32_t instruction;
- uint32_t newInstruction;
- switch ( ref->getKind() ) {
- case Reference::noFixUp:
- break;
- case Reference::pointer:
- {
- //fprintf(stderr, "writeContent: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
- if ( ref->isLazyReference() && finalLinkedImage ) {
- // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
- *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getFromTarget().getAddress());
- }
- else if ( target.isImportProxy() ) {
- // external realocation ==> pointer contains addend
- *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getTargetOffset());
- }
- else {
- // internal relocation
- if ( finalLinkedImage || (strcmp(target.getSectionName(), "__common") != 0) ) {
- // pointer contains target address
- //printf("Atom::writeContent() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
- *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(target.getAddress() + ref->getTargetOffset());
- }
- else {
- // pointer contains addend
- *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getTargetOffset());
- }
- }
- }
- break;
- case Reference::ppcFixupBranch24:
- {
- //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
- int64_t displacement = (target.getAddress() + ref->getTargetOffset() ) - (this->getAddress() + offset);
- if ( !finalLinkedImage && target.isImportProxy() ) {
- // 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 -= target.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 in %s to %s in %s", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
- }
- }
- instruction = OSReadBigInt32(instructionPtr, 0);
- newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
- //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
- OSWriteBigInt32(instructionPtr, 0, newInstruction);
- }
- break;
- case Reference::ppcFixupBranch14:
- break;
- case Reference::ppcFixupPicBaseLow16:
- {
- uint64_t targetAddr = target.getAddress() + ref->getTargetOffset();
- uint64_t picBaseAddr = this->getAddress() + ref->getFromTargetOffset();
- int64_t displacement = targetAddr - picBaseAddr;
- const int64_t picbase_twoGigLimit = 0x80000000;
- if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
- throw "32-bit pic-base out of range";
- uint16_t instructionLowHalf = (displacement & 0xFFFF);
- instruction = OSReadBigInt32(instructionPtr, 0);
- newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
- OSWriteBigInt32(instructionPtr, 0, newInstruction);
- }
- break;
- case Reference::ppcFixupPicBaseLow14:
- {
- uint64_t targetAddr = target.getAddress() + ref->getTargetOffset();
- uint64_t picBaseAddr = this->getAddress() + ref->getFromTargetOffset();
- int64_t displacement = targetAddr - picBaseAddr;
- const int64_t picbase_twoGigLimit = 0x80000000;
- if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
- throw "32-bit pic-base out of range";
- uint16_t instructionLowHalf = (displacement & 0xFFFF);
- if ( (instructionLowHalf & 0x3) != 0 )
- throw "bad address for lo14 instruction fix-up";
- instruction = OSReadBigInt32(instructionPtr, 0);
- newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
- OSWriteBigInt32(instructionPtr, 0, newInstruction);
- }
- break;
- case Reference::ppcFixupPicBaseHigh16:
- {
- uint64_t targetAddr = target.getAddress() + ref->getTargetOffset();
- uint64_t picBaseAddr = this->getAddress() + ref->getFromTargetOffset();
- int64_t displacement = targetAddr - picBaseAddr;
- const int64_t picbase_twoGigLimit = 0x80000000;
- if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
- throw "32-bit pic-base out of range";
- uint16_t instructionLowHalf = displacement >> 16;
- if ( (displacement & 0x00008000) != 0 )
- ++instructionLowHalf;
- instruction = OSReadBigInt32(instructionPtr, 0);
- newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
- OSWriteBigInt32(instructionPtr, 0, newInstruction);
- }
- break;
- case Reference::ppcFixupAbsLow16:
- {
- int64_t addr = target.getAddress() + ref->getTargetOffset();
- if ( !finalLinkedImage && target.isImportProxy() )
- addr -= target.getAddress() ;
- uint16_t instructionLowHalf = (addr & 0xFFFF);
- instruction = OSReadBigInt32(instructionPtr, 0);
- newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
- OSWriteBigInt32(instructionPtr, 0, newInstruction);
- }
- break;
- case Reference::ppcFixupAbsLow14:
- {
- int64_t addr = target.getAddress() + ref->getTargetOffset();
- if ( !finalLinkedImage && target.isImportProxy() )
- addr -= target.getAddress() ;
- uint16_t instructionLowHalf = (addr & 0xFFFF);
- if ( (instructionLowHalf & 0x3) != 0 )
- throw "bad address for lo14 instruction fix-up";
- instruction = OSReadBigInt32(instructionPtr, 0);
- newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
- OSWriteBigInt32(instructionPtr, 0, newInstruction);
- }
- break;
- case Reference::ppcFixupAbsHigh16:
- {
- int64_t addr = target.getAddress() + ref->getTargetOffset();
- if ( !finalLinkedImage && target.isImportProxy() )
- addr -= target.getAddress() ;
- uint16_t hi16 = (addr >> 16);
- instruction = OSReadBigInt32(instructionPtr, 0);
- newInstruction = (instruction & 0xFFFF0000) | hi16;
- OSWriteBigInt32(instructionPtr, 0, newInstruction);
- }
- break;
- case Reference::ppcFixupAbsHigh16AddLow:
- {
- int64_t addr = target.getAddress() + ref->getTargetOffset();
- if ( !finalLinkedImage && target.isImportProxy() )
- addr -= target.getAddress() ;
- if ( addr & 0x00008000 )
- addr += 0x00010000;
- instruction = OSReadBigInt32(instructionPtr, 0);
- newInstruction = (instruction & 0xFFFF0000) | (addr >> 16);
- OSWriteBigInt32(instructionPtr, 0, newInstruction);
- }
- break;
- case Reference::pointer32Difference:
- ENDIAN_WRITE32(*instructionPtr, target.getAddress() + ref->getTargetOffset() - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()));
- break;
- case Reference::pointer64Difference:
- *((uint64_t*)instructionPtr) = ENDIAN_SWAP64(target.getAddress() + ref->getTargetOffset() - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()));
- break;
- case Reference::x86FixupBranch32:
- {
- int64_t displacement = target.getAddress() - (this->getAddress() + offset);
- if ( target.isImportProxy() ) {
- displacement = 0;
- }
- else {
- const int64_t bl_twoGigLimit = 0x7FFFFFFF;
- if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_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 "call out of range";
- }
- }
- OSWriteLittleInt32(instructionPtr, 0, (int32_t)displacement);
- }
- break;
- }
- }
-
- // write out
- writer.write(0, buffer, getSize());
-}
-
-
-
-const macho_section* Atom::findSectionFromOffset(uint32_t offset)
-{
- const macho_section* const sectionsStart = (const macho_section*)( (char*)fOwner.fSegment + sizeof(macho_segment_command) );
- const macho_section* const sectionsEnd = §ionsStart[fOwner.fSegment->nsects()];
- for (const macho_section* s = sectionsStart; s < sectionsEnd; ++s) {
- if ( (s->addr() <= offset) && (offset < (s->addr()+s->size())) )
- return s;
- }
- throwf("address 0x%08X is not in any section", offset);
-}
-
-void Atom::setSize(macho_uintptr_t size)
-{
- fSize = size;
-}
-
-
-void Atom::setFollowOnAtom(Atom&)
-{
-
-}
-
-Reference* Atom::addReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
-{
- if ( (target.getScope() != ObjectFile::Atom::scopeTranslationUnit) && ((target.fSymbol != NULL) || (target.fSynthesizedName != NULL)) )
- return this->addByNameReference(offsetInSrcAtom, kind, target.getName(), offsetInTarget, offsetInFromTarget);
- else
- return this->addDirectReference(offsetInSrcAtom, kind, target, offsetInTarget, offsetInFromTarget);
-}
-
-
-Reference* Atom::addDirectReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
-{
- Reference* ref = new Reference(offsetInSrcAtom, kind, target, offsetInTarget, offsetInFromTarget);
- // in rare cases, there may already be a by-name reference to the same atom. If so, replace with this direct reference
- for (std::vector<Reference*>::iterator it=fReferences.begin(); it != fReferences.end(); it++) {
- ObjectFile::Reference* aRef = *it;
- if ( (aRef->getFixUpOffset() == offsetInSrcAtom) && (aRef->getKind() == kind) ) {
- *it = ref;
- return ref;
- }
- }
-
- // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file
- fReferences.insert(fReferences.begin(), ref);
- return ref;
-}
-
-Reference* Atom::addByNameReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
-{
- Reference* ref = new Reference(offsetInSrcAtom, kind, targetName, offsetInTarget, offsetInFromTarget);
- // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file
- fReferences.insert(fReferences.begin(), ref);
- return ref;
-}
-
-Reference* Atom::addDifferenceReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, Atom& fromTarget, uint64_t offsetInFromTarget)
-{
- Reference* ref = new Reference(offsetInSrcAtom, kind, target, offsetInTarget, fromTarget, offsetInFromTarget);
- // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file
- fReferences.insert(fReferences.begin(), ref);
- return ref;
-}
-
-
-Segment::Segment(const macho_section* sect)
- : fSection(sect)
-{
-}
-
-const char* Segment::getName() const
-{
- return fSection->segname();
-}
-
-bool Segment::isContentReadable() const
-{
- return true;
-}
-
-bool Segment::isContentWritable() const
-{
- if ( strcmp(fSection->segname(), "__DATA") == 0 )
- return true;
- if ( strcmp(fSection->segname(), "__OBJC") == 0 )
- return true;
- return false;
-}
-
-bool Segment::isContentExecutable() const
-{
- return ( strcmp(fSection->segname(), "__TEXT") == 0 );
-}
-
-
-Reference::Reference(macho_uintptr_t fixUpOffset, Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
- : fTarget(NULL), fFromTarget(NULL), fTargetName(targetName), fFromTargetName(NULL), fTargetOffset(offsetInTarget), fFromTargetOffset(offsetInFromTarget),
- fFixUpOffsetInSrc(fixUpOffset), fKind(kind), fLazy(false), fWeak(false)
-{
-}
-
-Reference::Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
- : fTarget(&target), fFromTarget(NULL), fTargetName(NULL), fFromTargetName(NULL), fTargetOffset(offsetInTarget), fFromTargetOffset(offsetInFromTarget),
- fFixUpOffsetInSrc(fixUpOffset), fKind(kind), fLazy(false), fWeak(false)
-{
-}
-
-Reference::Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, class Atom& fromTarget, uint64_t offsetInFromTarget)
- : fTarget(&target), fFromTarget(&fromTarget), fTargetName(NULL), fFromTargetName(NULL), fTargetOffset(offsetInTarget), fFromTargetOffset(offsetInFromTarget),
- fFixUpOffsetInSrc(fixUpOffset), fKind(kind), fLazy(false), fWeak(false)
-{
- // assure no direct references to something that might be coalesced
- if ( (target.isWeakDefinition() || target.isCoalesableByName()) && (target.getScope() != ObjectFile::Atom::scopeTranslationUnit) && (target.getName() != NULL) ) {
- //fprintf(stderr, "change TO direct reference to by-name: from %s to %s in %p\n", fromTarget.getDisplayName(), target.getName(), this);
- fTargetName = target.getName();
- fTarget = NULL;
- }
-// Note: We should also allow by-name from references, but many other chunks of code assume from targets are always direct//
-// if ( (fromTarget.isWeakDefinition() || fromTarget.isCoalesableByName()) && (fromTarget.getScope() != ObjectFile::Atom::scopeTranslationUnit) && (fromTarget.getName() != NULL)) {
-// fprintf(stderr, "change FROM direct reference to by-name: from %s to %s in %p\n", fromTarget.getDisplayName(), target.getName(), this);
-// fFromTargetName = fromTarget.getName();
-// fFromTarget = NULL;
-// }
-}
-
-
-
-Reference::~Reference()
-{
-}
-
-bool Reference::isTargetUnbound() const
-{
- return ( fTarget == NULL );
-}
-
-bool Reference::isFromTargetUnbound() const
-{
- return ( fFromTarget == NULL );
-}
-
-bool Reference::isWeakReference() const
-{
- return fWeak;
-}
-
-bool Reference::requiresRuntimeFixUp(bool slideable) const
-{
- // This static linker only supports pure code (no code fixups are runtime)
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- // Only data can be fixed up, and the codegen assures only "pointers" need runtime fixups
- return ( (fKind == Reference::pointer) && (fTarget->isImportProxy() || fTarget->isWeakDefinition() || slideable) );
-#elif defined(ARCH_I386)
- // For i386, Reference::pointer is used for both data pointers and instructions with 32-bit absolute operands
- if ( fKind == Reference::pointer ) {
- if ( fTarget->isImportProxy() )
- return true;
- else
- return slideable;
- }
- return false;
-#else
- #error
-#endif
-}
-
-bool Reference::isLazyReference() const
-{
- return fLazy;
-}
-
-ObjectFile::Reference::Kind Reference::getKind() const
-{
- return fKind;
-}
-
-uint64_t Reference::getFixUpOffset() const
-{
- return fFixUpOffsetInSrc;
-}
-
-const char* Reference::getTargetName() const
-{
- if ( fTargetName != NULL )
- return fTargetName;
- return fTarget->getName();
-}
-
-ObjectFile::Atom& Reference::getTarget() const
-{
- return *fTarget;
-}
-
-void Reference::setTarget(ObjectFile::Atom& target, uint64_t offset)
-{
- fTarget = ⌖
- fTargetOffset = offset;
-}
-
-
-ObjectFile::Atom& Reference::getFromTarget() const
-{
- return *fFromTarget;
-}
-
-bool Reference::hasFromTarget() const
-{
- return ( (fFromTarget != NULL) || (fFromTargetName != NULL) );
-}
-
-const char* Reference::getFromTargetName() const
-{
- if ( fFromTargetName != NULL )
- return fFromTargetName;
- return fFromTarget->getName();
-}
-
-void Reference::setFromTarget(ObjectFile::Atom& target)
-{
- fFromTarget = ⌖
-}
-
-void Reference::setFromTargetName(const char* name)
-{
- fFromTargetName = name;
-}
-
-void Reference::setFromTargetOffset(uint64_t offset)
-{
- fFromTargetOffset = offset;
-}
-
-uint64_t Reference::getTargetOffset() const
-{
- return fTargetOffset;
-}
-
-
-uint64_t Reference::getFromTargetOffset() const
-{
- return fFromTargetOffset;
-}
-
-void Reference::setLazy(bool lazy)
-{
- fLazy = lazy;
-}
-
-void Reference::setWeak(bool weak)
-{
- fWeak = weak;
-}
-
-const char* Reference::getDescription() const
-{
- static char temp[256];
- if ( fKind == pointer32Difference ) {
- // by-name references have quoted names
- bool targetByName = ( &(this->getTarget()) == NULL );
- bool fromByName = ( &(this->getFromTarget()) == NULL );
- const char* targetQuotes = targetByName ? "\"" : "";
- const char* fromQuotes = fromByName ? "\"" : "";
- sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %lld) - (&%s%s%s + %lld)",
- this->getFixUpOffset(), targetQuotes, this->getTargetName(), targetQuotes, this->getTargetOffset(),
- fromQuotes, this->getFromTargetName(), fromQuotes, this->getFromTargetOffset() );
- }
- else if ( fKind == pointer64Difference ) {
- // by-name references have quoted names
- bool targetByName = ( &(this->getTarget()) == NULL );
- bool fromByName = ( &(this->getFromTarget()) == NULL );
- const char* targetQuotes = targetByName ? "\"" : "";
- const char* fromQuotes = fromByName ? "\"" : "";
- sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %lld) - (&%s%s%s + %lld)",
- this->getFixUpOffset(), targetQuotes, this->getTargetName(), targetQuotes, this->getTargetOffset(),
- fromQuotes, this->getFromTargetName(), fromQuotes, this->getFromTargetOffset() );
- }
- else {
- switch( fKind ) {
- case noFixUp:
- sprintf(temp, "reference to ");
- break;
- case pointer:
- {
- const char* weak = "";
- if ( fWeak )
- weak = "weak ";
- const char* lazy = "";
- if ( fLazy )
- lazy = "lazy ";
- sprintf(temp, "offset 0x%04llX, %s%spointer to ", this->getFixUpOffset(), weak, lazy);
- }
- break;
- case ppcFixupBranch14:
- case ppcFixupBranch24:
- sprintf(temp, "offset 0x%04llX, bl pc-rel fixup to ", this->getFixUpOffset());
- break;
- case ppcFixupPicBaseLow16:
- sprintf(temp, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
- break;
- case ppcFixupPicBaseLow14:
- sprintf(temp, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
- break;
- case ppcFixupPicBaseHigh16:
- sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
- break;
- case ppcFixupAbsLow16:
- sprintf(temp, "offset 0x%04llX, low 16 fixup to absolute address of ", this->getFixUpOffset());
- break;
- case ppcFixupAbsLow14:
- sprintf(temp, "offset 0x%04llX, low 14 fixup to absolute address of ", this->getFixUpOffset());
- break;
- case ppcFixupAbsHigh16:
- sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", this->getFixUpOffset());
- break;
- case ppcFixupAbsHigh16AddLow:
- sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", this->getFixUpOffset());
- break;
- case pointer32Difference:
- case pointer64Difference:
- // handled above
- break;
- case x86FixupBranch32:
- sprintf(temp, "offset 0x%04llX, pc-rel fixup to ", this->getFixUpOffset());
- break;
- }
- // always quote by-name references
- if ( fTargetName != NULL ) {
- strcat(temp, "\"");
- strcat(temp, fTargetName);
- strcat(temp, "\"");
- }
- else if ( fTarget != NULL ) {
- strcat(temp, fTarget->getDisplayName());
- }
- else {
- strcat(temp, "NULL target");
- }
- if ( fTargetOffset != 0 )
- sprintf(&temp[strlen(temp)], " plus 0x%08llX", this->getTargetOffset());
- if ( (fKind==pointer) && fLazy ) {
- strcat(temp, " initially bound to \"");
- if ( (fFromTarget != NULL) || (fFromTargetName != NULL) ) {
- strcat(temp, this->getFromTargetName());
- strcat(temp, "\"");
- if ( this->getFromTargetOffset() != 0 )
- sprintf(&temp[strlen(temp)], " plus 0x%08llX", this->getFromTargetOffset());
- }
- else {
- strcat(temp, "\" << missing >>");
- }
- }
- }
- return temp;
-}
-
-};
-
-
-
-
-
-
-
-/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
virtual ~Reader();
virtual const char* getPath() { return fPath; }
+ virtual time_t getModificationTime() { return 0; }
+ virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; }
virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return fAtoms; }
virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
- virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo() { return NULL; }
+ virtual std::vector<Stab>* getStabs() { return NULL; }
private:
const char* fPath;
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 NULL; }
virtual const char* getDisplayName() const;
virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
- virtual bool isTentativeDefinition() const { return false; }
- virtual bool isWeakDefinition() const { return false; }
- virtual bool isCoalesableByName() const { return false; }
- virtual bool isCoalesableByValue() const { return false; }
+ virtual DefinitionKind getDefinitionKind() const { return kRegularDefinition; }
+ virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
virtual bool isZeroFill() const { return false; }
- virtual bool dontDeadStrip() const { return true; }
- virtual bool dontStripName() const { return false; }
- virtual bool isImportProxy() const { return false; }
virtual uint64_t getSize() const { return fFileLength; }
virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
virtual bool mustRemainInSection() const { return false; }
virtual Segment& getSegment() const { return fSegment; }
virtual bool requiresFollowOnAtom() const{ return false; }
virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
- virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo() const { return NULL; }
+ virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
virtual uint8_t getAlignment() const { return 4; }
- virtual WeakImportSetting getImportWeakness() const { return ObjectFile::Atom::kWeakUnset; }
virtual void copyRawContent(uint8_t buffer[]) const;
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
virtual void setScope(Scope) { }
- virtual void setImportWeakness(bool) { }
protected:
friend class Reader;
Atom(Reader& owner, Segment& segment, const char* sectionName, const uint8_t fileContent[], uint64_t fileLength)
- : fOwner(owner), fSegment(segment), fSectionName(sectionName), fFileContent(fileContent), fFileLength(fileLength) {}
+ : fOwner(owner), fSegment(segment), fSectionName(sectionName), fFileContent(fileContent), fFileLength(fileLength) { setDontDeadStrip(); }
virtual ~Atom() {}
Reader& fOwner;
memcpy(buffer, fFileContent, fFileLength);
}
-void Atom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- writer.write(0, fFileContent, fFileLength);
-}
-
-
Reader* MakeReader(const char* segmentName, const char* sectionName, const char* path, const uint8_t fileContent[], uint64_t fileLength)
{
return new Reader(segmentName, sectionName, path, fileContent, fileLength);
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
+++ /dev/null
-/*
- * 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 <stdint.h>
-#include <stddef.h>
-#include <fcntl.h>
-#include <sys/time.h>
-#include <mach-o/loader.h>
-#include <mach-o/nlist.h>
-#include <mach-o/reloc.h>
-#include <mach-o/ppc/reloc.h>
-#include <mach-o/stab.h>
-
-#include <vector>
-#include <algorithm>
-#include <map>
-#include <set>
-
-#include "ObjectFile.h"
-#include "ExecutableFile.h"
-#include "Options.h"
-
-// buiild Writer for -arch ppc64
-#undef MACHO_32_SAME_ENDIAN
-#undef MACHO_32_OPPOSITE_ENDIAN
-#undef MACHO_64_SAME_ENDIAN
-#undef MACHO_64_OPPOSITE_ENDIAN
-#if __ppc__ || __ppc64__
- #define MACHO_64_SAME_ENDIAN
-#elif __i386__
- #define MACHO_64_OPPOSITE_ENDIAN
-#else
- #error unknown architecture
-#endif
-namespace ppc64 {
- #undef ARCH_PPC
- #define ARCH_PPC64
- #undef ARCH_I386
- #include "MachOAbstraction.h"
- #include "ExecutableFileMachO.cpp"
-};
-
-// buiild Writer for -arch ppc
-#undef MACHO_32_SAME_ENDIAN
-#undef MACHO_32_OPPOSITE_ENDIAN
-#undef MACHO_64_SAME_ENDIAN
-#undef MACHO_64_OPPOSITE_ENDIAN
-#if __ppc__ || __ppc64__
- #define MACHO_32_SAME_ENDIAN
-#elif __i386__
- #define MACHO_32_OPPOSITE_ENDIAN
-#else
- #error unknown architecture
-#endif
-namespace ppc {
- #define ARCH_PPC
- #undef ARCH_PPC64
- #undef ARCH_I386
- #include "MachOAbstraction.h"
- #include "ExecutableFileMachO.cpp"
-};
-
-// buiild Writer for -arch i386
-#undef MACHO_32_SAME_ENDIAN
-#undef MACHO_32_OPPOSITE_ENDIAN
-#undef MACHO_64_SAME_ENDIAN
-#undef MACHO_64_OPPOSITE_ENDIAN
-#if __ppc__ || __ppc64__
- #define MACHO_32_OPPOSITE_ENDIAN
-#elif __i386__
- #define MACHO_32_SAME_ENDIAN
-#else
- #error unknown architecture
-#endif
-#undef i386 // compiler sometimes #defines this
-namespace i386 {
- #undef ARCH_PPC
- #undef ARCH_PPC64
- #define ARCH_I386
- #include "MachOAbstraction.h"
- #include "ExecutableFileMachO.cpp"
-};
-
-
+++ /dev/null
-/*
- * 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 __EXECUTABLEFILEMACHO__
-#define __EXECUTABLEFILEMACHO__
-
-class Options;
-
-namespace ppc {
- namespace ExecutableFileMachO {
- extern class ExecutableFile::Writer* MakeWriter(const char* path, Options&, std::vector<ExecutableFile::DyLibUsed>&);
- }
-};
-
-namespace ppc64 {
- namespace ExecutableFileMachO {
- extern class ExecutableFile::Writer* MakeWriter(const char* path, Options&, std::vector<ExecutableFile::DyLibUsed>&);
- }
-};
-
-#undef i386 // compiler sometimes #defines this
-namespace i386 {
- namespace ExecutableFileMachO {
- extern class ExecutableFile::Writer* MakeWriter(const char* path, Options&, std::vector<ExecutableFile::DyLibUsed>&);
- }
-};
-
-
-
-#endif // __EXECUTABLEFILEMACHO__
-
-
-
+++ /dev/null
-/* -*- 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@
- */
-
-
-
-namespace ExecutableFileMachO {
-
-class Writer : public ExecutableFile::Writer
-{
-public:
- Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries);
- virtual ~Writer();
-
- virtual const char* getPath();
- virtual std::vector<class ObjectFile::Atom*>& getAtoms();
- virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name);
- virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo();
-
- virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name);
- virtual void write(std::vector<class ObjectFile::Atom*>& atoms, class ObjectFile::Atom* entryPointAtom);
-
-private:
- void assignFileOffsets();
- void partitionIntoSections();
- bool addBranchIslands();
- void adjustLoadCommandsAndPadding();
- void createDynamicLinkerCommand();
- void createDylibCommands();
- void buildLinkEdit();
- void writeAtoms();
- void collectExportedAndImportedAndLocalAtoms();
- void setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
- void buildSymbolTable();
- 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);
- uint64_t getAtomLoadAddress(const ObjectFile::Atom* atom);
- uint8_t ordinalForLibrary(ObjectFile::Reader* file);
- bool shouldExport(ObjectFile::Atom& atom);
- void buildFixups();
- void adjustLinkEditSections();
- void buildObjectFileFixups();
- void buildExecutableFixups();
- uint32_t symbolIndex(ObjectFile::Atom& atom);
- uint32_t addRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
- unsigned int collectStabs();
- macho_uintptr_t valueForStab(const ObjectFile::StabsInfo& stab, const ObjectFile::Atom* atom);
- void addStabs(uint32_t startIndex, uint32_t count);
-
-
- class SectionInfo : public ObjectFile::Section {
- public:
- SectionInfo();
- void setIndex(unsigned int index) { fIndex=index; }
- std::vector<ObjectFile::Atom*> 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 fAllNonLazyPointers;
- bool fAllZeroFill;
- bool fVirtualSection;
- };
-
- class SegmentInfo
- {
- public:
- SegmentInfo();
- std::vector<class SectionInfo*> fSections;
- char fName[20];
- uint32_t fInitProtection;
- uint32_t fMaxProtection;
- uint64_t fFileOffset;
- uint64_t fFileSize;
- uint64_t fBaseAddress;
- uint64_t fSize;
- bool fFixedAddress;
- };
-
-
- struct DirectLibrary {
- class ObjectFile::Reader* fLibrary;
- bool fWeak;
- bool fReExport;
- };
-
- struct IndirectEntry {
- uint32_t indirectIndex;
- uint32_t symbolIndex;
- };
-
- struct StabChunks {
- ObjectFile::Atom* fAtom;
- ObjectFile::Reader* fReader;
- unsigned int fReaderOrder;
- unsigned int fOrderInReader;
- std::vector<ObjectFile::StabsInfo>* fStabs;
- };
-
- static bool stabChunkCompare(const StabChunks& lhs, const StabChunks& rhs);
-
- friend class WriterAtom;
- friend class PageZeroAtom;
- friend class CustomStackAtom;
- friend class MachHeaderAtom;
- friend class SegmentLoadCommandsAtom;
- friend class SymbolTableLoadCommandsAtom;
- friend class ThreadsLoadCommandsAtom;
- friend class DylibIDLoadCommandsAtom;
- friend class RoutinesLoadCommandsAtom;
- friend class DyldLoadCommandsAtom;
- friend class LinkEditAtom;
- friend class LocalRelocationsLinkEditAtom;
- friend class ExternalRelocationsLinkEditAtom;
- friend class SymbolTableLinkEditAtom;
- friend class IndirectTableLinkEditAtom;
- friend class StringsLinkEditAtom;
-
- const char* fFilePath;
- Options& fOptions;
- int fFileDescriptor;
- std::vector<class ObjectFile::Atom*>* fAllAtoms;
- class SectionInfo* fLoadCommandsSection;
- class SegmentInfo* fLoadCommandsSegment;
- class SegmentLoadCommandsAtom* fSegmentCommands;
- class SymbolTableLoadCommandsAtom* fSymbolTableCommands;
- class LoadCommandsPaddingAtom* fHeaderPadding;
- std::vector<class ObjectFile::Atom*> fWriterSynthesizedAtoms;
- std::vector<SegmentInfo*> fSegmentInfos;
- class ObjectFile::Atom* fEntryPoint;
- std::vector<DirectLibrary> fDirectLibraries;
- std::map<class ObjectFile::Reader*, uint32_t> fLibraryToOrdinal;
- std::vector<StabChunks> fStabChunks;
- std::vector<class ObjectFile::Atom*> fExportedAtoms;
- std::vector<class ObjectFile::Atom*> fImportedAtoms;
- std::vector<class ObjectFile::Atom*> fLocalSymbolAtoms;
- LocalRelocationsLinkEditAtom* fLocalRelocationsAtom;
- ExternalRelocationsLinkEditAtom* fExternalRelocationsAtom;
- SymbolTableLinkEditAtom* fSymbolTableAtom;
- IndirectTableLinkEditAtom* fIndirectTableAtom;
- StringsLinkEditAtom* fStringsAtom;
- macho_nlist* fSymbolTable;
- //char* fStringPool;
- //uint32_t fStringPoolUsed;
- //uint32_t fStringPoolSize;
- std::vector<macho_relocation_info> fInternalRelocs;
- std::vector<macho_relocation_info> fExternalRelocs;
- std::vector<IndirectEntry> fIndirectSymbolTable;
- 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;
- bool fEmitVirtualSections;
- bool fHasWeakExports;
- bool fReferencesWeakImports;
-};
-
-
-class WriterAtom : public ObjectFile::Atom
-{
-protected:
- class Segment;
-public:
- enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
- WriterAtom(Writer& writer, class WriterAtom::Segment& segment) : fWriter(writer), fSegment(segment) {}
-
- virtual ObjectFile::Reader* getFile() const { return &fWriter; }
- virtual const char* getName() const { return NULL; }
- virtual const char* getDisplayName() const { return this->getName(); }
- virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
- virtual bool isTentativeDefinition() const { return false; }
- virtual bool isWeakDefinition() const { return false; }
- virtual bool isCoalesableByName() const { return false; }
- virtual bool isCoalesableByValue() const { return false; }
- virtual bool isZeroFill() const { return false; }
- virtual bool dontDeadStrip() const { return true; }
- virtual bool dontStripName() const { return false; }
- virtual bool isImportProxy() const { return false; }
- virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
- virtual bool mustRemainInSection() const { return true; }
- virtual ObjectFile::Segment& getSegment() const { return fSegment; }
- virtual bool requiresFollowOnAtom() const { return false; }
- virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
- virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo() const { return NULL; }
- virtual uint8_t getAlignment() const { return 2; }
- virtual WeakImportSetting getImportWeakness() const { return Atom::kWeakUnset; }
- virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
- virtual void setScope(Scope) { }
- virtual void setImportWeakness(bool weakImport) { }
-
-
-protected:
- virtual ~WriterAtom() {}
-
- 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; }
- private:
- const char* fName;
- const bool fReadable;
- const bool fWritable;
- const bool fExecutable;
- const bool fFixedAddress;
- };
-
- static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
- static Segment fgTextSegment;
- static Segment fgPageZeroSegment;
- static Segment fgLinkEditSegment;
- static Segment fgStackSegment;
-
-
- Writer& fWriter;
- Segment& fSegment;
-};
-
-
-WriterAtom::Segment WriterAtom::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
-WriterAtom::Segment WriterAtom::fgTextSegment("__TEXT", true, false, true, false);
-WriterAtom::Segment WriterAtom::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
-WriterAtom::Segment WriterAtom::fgStackSegment("__UNIXSTACK", true, true, false, true);
-std::vector<ObjectFile::Reference*> WriterAtom::fgEmptyReferenceList;
-
-class PageZeroAtom : public WriterAtom
-{
-public:
- PageZeroAtom(Writer& writer) : WriterAtom(writer, fgPageZeroSegment) {}
- virtual const char* getDisplayName() const { return "page zero content"; }
- virtual bool isZeroFill() const { return true; }
- virtual uint64_t getSize() const { return fWriter.fOptions.zeroPageSize(); }
- virtual const char* getSectionName() const { return "._zeropage"; }
- virtual uint8_t getAlignment() const { return 12; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
-};
-
-class MachHeaderAtom : public WriterAtom
-{
-public:
- MachHeaderAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
- virtual const char* getName() const;
- virtual const char* getDisplayName() const;
- virtual Scope getScope() const;
- virtual bool dontStripName() const;
- virtual uint64_t getSize() const;
- virtual uint8_t getAlignment() const { return 12; }
- virtual const char* getSectionName() const { return "._mach_header"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-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 uint8_t getAlignment() const { return 12; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
-};
-
-class SegmentLoadCommandsAtom : public WriterAtom
-{
-public:
- SegmentLoadCommandsAtom(Writer& writer) : WriterAtom(writer, 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 uint8_t getAlignment() const { return 2; }
- virtual const char* getSectionName() const { return "._load_commands"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-
- void computeSize();
- void setup();
- unsigned int commandCount() { return fCommandCount; }
- void assignFileOffsets();
-private:
- unsigned int fCommandCount;
- uint32_t fSize;
-};
-
-class SymbolTableLoadCommandsAtom : public WriterAtom
-{
-public:
- SymbolTableLoadCommandsAtom(Writer&);
- virtual const char* getDisplayName() const { return "symbol table load commands"; }
- virtual uint64_t getSize() const;
- virtual uint8_t getAlignment() const { return 2; }
- virtual const char* getSectionName() const { return "._load_commands"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-
-private:
- macho_symtab_command fSymbolTable;
- macho_dysymtab_command fDynamicSymbolTable;
-};
-
-class ThreadsLoadCommandsAtom : public WriterAtom
-{
-public:
- ThreadsLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
- virtual const char* getDisplayName() const { return "thread load commands"; }
- virtual uint64_t getSize() const;
- virtual uint8_t getAlignment() const { return 2; }
- virtual const char* getSectionName() const { return "._load_commands"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-private:
- uint8_t* fBuffer;
- uint32_t fBufferSize;
-};
-
-class DyldLoadCommandsAtom : public WriterAtom
-{
-public:
- DyldLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
- virtual const char* getDisplayName() const { return "dyld load command"; }
- virtual uint64_t getSize() const;
- virtual uint8_t getAlignment() const { return 2; }
- virtual const char* getSectionName() const { return "._load_commands"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-class DylibLoadCommandsAtom : public WriterAtom
-{
-public:
- DylibLoadCommandsAtom(Writer& writer, ExecutableFile::DyLibUsed& info) : WriterAtom(writer, fgTextSegment), fInfo(info) {}
- virtual const char* getDisplayName() const { return "dylib load command"; }
- virtual uint64_t getSize() const;
- virtual uint8_t getAlignment() const { return 2; }
- virtual const char* getSectionName() const { return "._load_commands"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-private:
- ExecutableFile::DyLibUsed& fInfo;
-};
-
-class DylibIDLoadCommandsAtom : public WriterAtom
-{
-public:
- DylibIDLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
- virtual const char* getDisplayName() const { return "dylib ID load command"; }
- virtual uint64_t getSize() const;
- virtual uint8_t getAlignment() const { return 2; }
- virtual const char* getSectionName() const { return "._load_commands"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-class RoutinesLoadCommandsAtom : public WriterAtom
-{
-public:
- RoutinesLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
- virtual const char* getDisplayName() const { return "routines load command"; }
- virtual uint64_t getSize() const;
- virtual uint8_t getAlignment() const { return 2; }
- virtual const char* getSectionName() const { return "._load_commands"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-class SubUmbrellaLoadCommandsAtom : public WriterAtom
-{
-public:
- SubUmbrellaLoadCommandsAtom(Writer& writer, const char* name) : WriterAtom(writer, fgTextSegment), fName(name) {}
- virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
- virtual uint64_t getSize() const;
- virtual uint8_t getAlignment() const { return 2; }
- virtual const char* getSectionName() const { return "._load_commands"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-private:
- const char* fName;
-};
-
-class SubLibraryLoadCommandsAtom : public WriterAtom
-{
-public:
- SubLibraryLoadCommandsAtom(Writer& writer, const char* nameStart, int nameLen)
- : WriterAtom(writer, fgTextSegment), fNameStart(nameStart), fNameLength(nameLen) {}
- virtual const char* getDisplayName() const { return "sub-library load command"; }
- virtual uint64_t getSize() const;
- virtual uint8_t getAlignment() const { return 2; }
- virtual const char* getSectionName() const { return "._load_commands"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-private:
- const char* fNameStart;
- int fNameLength;
-};
-
-class UmbrellaLoadCommandsAtom : public WriterAtom
-{
-public:
- UmbrellaLoadCommandsAtom(Writer& writer, const char* name)
- : WriterAtom(writer, fgTextSegment), fName(name) {}
- virtual const char* getDisplayName() const { return "umbrella load command"; }
- virtual uint64_t getSize() const;
- virtual uint8_t getAlignment() const { return 2; }
- virtual const char* getSectionName() const { return "._load_commands"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-private:
- const char* fName;
-};
-
-class LoadCommandsPaddingAtom : public WriterAtom
-{
-public:
- LoadCommandsPaddingAtom(Writer& writer)
- : WriterAtom(writer, fgTextSegment), fSize(0) {}
- virtual const char* getDisplayName() const { return "header padding"; }
- virtual uint64_t getSize() const;
- virtual uint8_t getAlignment() const { return 2; }
- virtual const char* getSectionName() const { return "._load_cmds_pad"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-
- void setSize(uint64_t newSize) { fSize = newSize; }
-private:
- uint64_t fSize;
-};
-
-class LinkEditAtom : public WriterAtom
-{
-public:
- LinkEditAtom(Writer& writer) : WriterAtom(writer, fgLinkEditSegment) {}
- uint64_t getFileOffset() const;
-};
-
-class LocalRelocationsLinkEditAtom : public LinkEditAtom
-{
-public:
- LocalRelocationsLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
- virtual const char* getDisplayName() const { return "local relocations"; }
- virtual uint64_t getSize() const;
- virtual uint8_t getAlignment() const { return 3; }
- virtual const char* getSectionName() const { return "._local_relocs"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-class SymbolTableLinkEditAtom : public LinkEditAtom
-{
-public:
- SymbolTableLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
- virtual const char* getDisplayName() const { return "symbol table"; }
- virtual uint64_t getSize() const;
- virtual uint8_t getAlignment() const { return 2; }
- virtual const char* getSectionName() const { return "._symbol_table"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-class ExternalRelocationsLinkEditAtom : public LinkEditAtom
-{
-public:
- ExternalRelocationsLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
- virtual const char* getDisplayName() const { return "external relocations"; }
- virtual uint64_t getSize() const;
- virtual uint8_t getAlignment() const { return 3; }
- virtual const char* getSectionName() const { return "._extern_relocs"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-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 uint8_t getAlignment() const { return 2; }
- virtual const char* getSectionName() const { return "._indirect_syms"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-class StringsLinkEditAtom : public LinkEditAtom
-{
-public:
- StringsLinkEditAtom(Writer& writer);
- virtual const char* getDisplayName() const { return "string pool"; }
- virtual uint64_t getSize() const;
- virtual uint8_t getAlignment() const { return 2; }
- virtual const char* getSectionName() const { return "._string_pool"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-
- int32_t add(const char* name);
- int32_t emptyString();
-
-private:
- enum { kBufferSize = 0x01000000 };
-
- std::vector<char*> fFullBuffers;
- char* fCurrentBuffer;
- uint32_t fCurrentBufferUsed;
-};
-
-
-
-class UndefinedSymbolProxyAtom : public WriterAtom
-{
-public:
- UndefinedSymbolProxyAtom(Writer& writer, const char* name) : WriterAtom(writer, fgLinkEditSegment), fName(name), fWeakImportSetting(Atom::kWeakUnset) {}
- virtual const char* getName() const { return fName; }
- virtual Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
- virtual uint64_t getSize() const { return 0; }
- virtual bool isWeakDefinition() const { return true; }
- virtual bool isImportProxy() const { return true; }
- virtual const char* getSectionName() const { return "._imports"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
- virtual WeakImportSetting getImportWeakness() const { return fWeakImportSetting; }
- virtual void setImportWeakness(bool weakImport) { fWeakImportSetting = weakImport ? kWeakImport : kNonWeakImport; }
-private:
- const char* fName;
- WeakImportSetting fWeakImportSetting;
-};
-
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-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 Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
- virtual uint64_t getSize() const { return 4; }
- virtual const char* getSectionName() const { return "__text"; }
- virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-private:
- const char* fName;
- ObjectFile::Atom& fTarget;
- uint32_t fTargetOffset;
-};
-#endif
-
-struct ExportSorter
-{
- bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
- {
- return (strcmp(left->getName(), right->getName()) < 0);
- }
-};
-
-
-ExecutableFile::Writer* MakeWriter(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
-{
- return new Writer(path, options, dynamicLibraries);
-}
-
-Writer::SectionInfo::SectionInfo()
- : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0), fIndirectSymbolOffset(0), fAlignment(0),
- fAllLazyPointers(false), fAllNonLazyPointers(false), fAllZeroFill(false), fVirtualSection(false)
-{
- fSegmentName[0] = '\0';
- fSectionName[0] = '\0';
-}
-
-Writer::SegmentInfo::SegmentInfo()
- : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0), fBaseAddress(0), fSize(0), fFixedAddress(false)
-{
- fName[0] = '\0';
-}
-
-
-Writer::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
- : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options), fLoadCommandsSection(NULL),
- fLoadCommandsSegment(NULL),
- //fStringPool(NULL), fStringPoolUsed(0), fStringPoolSize(0),
- fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false)
-{
- 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 writeable 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);
- fFileDescriptor = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
- if ( fFileDescriptor == -1 ) {
- throw "can't open file for writing";
- }
-
- switch ( fOptions.outputKind() ) {
- case Options::kDynamicExecutable:
- case Options::kStaticExecutable:
- fWriterSynthesizedAtoms.push_back(new PageZeroAtom(*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(new ThreadsLoadCommandsAtom(*this));
- if ( fOptions.hasCustomStack() )
- fWriterSynthesizedAtoms.push_back(new CustomStackAtom(*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;
- case Options::kDynamicLibrary:
- case Options::kDynamicBundle:
- 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(new SymbolTableLoadCommandsAtom(*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;
- case Options::kDyld:
- 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(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
- uint8_t ordinal = 1;
- switch ( fOptions.outputKind() ) {
- case Options::kDynamicExecutable:
- 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];
- if ( dylibInfo.indirect ) {
- // find ordinal of direct reader
- if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) {
- bool found = false;
- for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
- if ( it->first == dylibInfo.directReader ) {
- //fprintf(stderr, "ordinal %d for indirect %s\n", it->second, dylibInfo.reader->getPath());
- fLibraryToOrdinal[dylibInfo.reader] = it->second;
- found = true;
- break;
- }
- }
- if ( ! found )
- fprintf(stderr, "ld64 warning: ordinal not found for %s, parent %s\n", dylibInfo.reader->getPath(), dylibInfo.directReader != NULL ? dylibInfo.directReader->getPath() : NULL);
- }
- }
- else {
- // see if a DylibLoadCommandsAtom has already been created for this install path
- bool newDylib = true;
- const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
- if ( dylibInfo.options.fInstallPathOverride != NULL )
- dylibInstallPath = dylibInfo.options.fInstallPathOverride;
- for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
- ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
- if ( !seenDylibInfo.indirect ) {
- const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
- if ( seenDylibInfo.options.fInstallPathOverride != NULL )
- seenDylibInstallPath = dylibInfo.options.fInstallPathOverride;
- if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
- fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
- newDylib = false;
- break;
- }
- }
- }
-
- if ( newDylib ) {
- // assign new ordinal and check for other paired load commands
- fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
- fWriterSynthesizedAtoms.push_back(new DylibLoadCommandsAtom(*this, dylibInfo));
- if ( dylibInfo.options.fReExport ) {
- // 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()));
- }
- }
- break;
- case Options::kStaticExecutable:
- case Options::kObjectFile:
- case Options::kDyld:
- break;
- }
-
- //fprintf(stderr, "ordinals table:\n");
- //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
- // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
- //}
-}
-
-Writer::~Writer()
-{
- if ( fFilePath != NULL )
- free((void*)fFilePath);
- if ( fSymbolTable != NULL )
- delete [] fSymbolTable;
- //if ( fStringPool != NULL )
- // delete [] fStringPool;
-}
-
-const char* Writer::getPath()
-{
- return fFilePath;
-}
-
-
-std::vector<class ObjectFile::Atom*>& Writer::getAtoms()
-{
- return fWriterSynthesizedAtoms;
-}
-
-std::vector<class ObjectFile::Atom*>* Writer::getJustInTimeAtomsFor(const char* name)
-{
- return NULL;
-}
-
-std::vector<ObjectFile::StabsInfo>* Writer::getStabsDebugInfo()
-{
- return NULL;
-}
-
-ObjectFile::Atom* Writer::getUndefinedProxyAtom(const char* name)
-{
- if ( (fOptions.outputKind() == Options::kObjectFile)
- || (fOptions.undefinedTreatment() != Options::kUndefinedError) )
- return new UndefinedSymbolProxyAtom(*this, name);
- else
- return NULL;
-}
-
-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<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
- if ( pos != fLibraryToOrdinal.end() )
- return pos->second;
-
- throw "can't find ordinal for imported symbol";
-}
-
-
-void Writer::write(std::vector<class ObjectFile::Atom*>& atoms, class ObjectFile::Atom* entryPointAtom)
-{
- fAllAtoms = &atoms;
- fEntryPoint = entryPointAtom;
-
- // 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 everything
- writeAtoms();
-}
-
-void Writer::buildLinkEdit()
-{
- this->collectExportedAndImportedAndLocalAtoms();
- this->buildSymbolTable();
- this->buildFixups();
- this->adjustLinkEditSections();
-}
-
-
-
-uint64_t Writer::getAtomLoadAddress(const ObjectFile::Atom* atom)
-{
- return atom->getAddress();
-// SectionInfo* info = (SectionInfo*)atom->getSection();
-// return info->getBaseAddress() + atom->getSectionOffset();
-}
-
-void Writer::setExportNlist(const ObjectFile::Atom* atom, macho_nlist* entry)
-{
- // set n_type
- entry->set_n_type(N_EXT | N_SECT);
- if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && fOptions.keepPrivateExterns() && (fOptions.outputKind() == Options::kObjectFile) )
- 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 ( (fOptions.outputKind() == Options::kDynamicExecutable) && (sectionIndex==0) && atom->dontStripName())
- entry->set_n_type(N_EXT | N_ABS);
-
- // set n_desc
- uint16_t desc = 0;
- if ( atom->dontStripName() )
- desc |= REFERENCED_DYNAMICALLY;
- if ( atom->isWeakDefinition() && (strcmp(atom->getSectionName(), "__common") != 0) ) {
- 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 )
- entry->set_n_value(this->getAtomLoadAddress(atom));
-}
-
-void Writer::setImportNlist(const ObjectFile::Atom* atom, macho_nlist* entry)
-{
- // set n_type
- 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 )
- desc = REFERENCE_FLAG_UNDEFINED_LAZY; // FIXME
- try {
- uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
- SET_LIBRARY_ORDINAL(desc, ordinal);
- }
- catch (const char* msg) {
- throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
- }
- }
- if ( atom->dontStripName() )
- desc |= REFERENCED_DYNAMICALLY;
- // an import proxy is always weak (overridden by definition in .o files)
- // so we ask its reader if the exported symbol in its dylib is weak
- if ( ( fOptions.outputKind() != Options::kObjectFile) && atom->getFile()->isDefinitionWeak(*atom) ) {
- desc |= N_REF_TO_WEAK;
- fReferencesWeakImports = true;
- }
- // set weak_import attribute
- if ( atom->getImportWeakness() == ObjectFile::Atom::kWeakImport )
- 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());
-}
-
-void Writer::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist* entry)
-{
- // set n_type
- uint8_t type = N_SECT;
- 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 <mach-o/ldsyms.h> 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->isWeakDefinition() && (strcmp(atom->getSectionName(), "__common") != 0) ) // commons on not weak
- desc |= N_WEAK_DEF;
- entry->set_n_desc(desc);
-
- // 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));
-}
-
-
-void Writer::setNlistRange(std::vector<class ObjectFile::Atom*>& 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];
- entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
- if ( &atoms == &fExportedAtoms ) {
- this->setExportNlist(atom, entry);
- }
- else if ( &atoms == &fImportedAtoms ) {
- this->setImportNlist(atom, entry);
- }
- else {
- this->setLocalNlist(atom, entry);
- }
- }
-}
-
-void Writer::buildSymbolTable()
-{
- fSymbolTableStabsStartIndex = 0;
- fSymbolTableStabsCount = this->collectStabs();
- fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
- fSymbolTableLocalCount = fLocalSymbolAtoms.size();
- fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
- fSymbolTableExportCount = fExportedAtoms.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, fSymbolTableLocalCount);
- setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fSymbolTableExportCount);
- setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount);
- addStabs(fSymbolTableStabsStartIndex, fSymbolTableStabsCount);
-}
-
-
-
-bool Writer::shouldExport(ObjectFile::Atom& atom)
-{
- switch ( atom.getScope() ) {
- case ObjectFile::Atom::scopeGlobal:
- return true;
- case ObjectFile::Atom::scopeLinkageUnit:
- return ( fOptions.keepPrivateExterns() && (fOptions.outputKind() == Options::kObjectFile) );
- default:
- return false;
- }
-}
-
-void Writer::collectExportedAndImportedAndLocalAtoms()
-{
- const int atomCount = fAllAtoms->size();
- for (int i=0; i < atomCount; ++i) {
- ObjectFile::Atom* atom = (*fAllAtoms)[i];
- // only named atoms go in symbol table
- if ( atom->getName() != NULL ) {
- // put atom into correct bucket: imports, exports, locals
- //printf("collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
- if ( atom->isImportProxy() || ((fOptions.outputKind() == Options::kObjectFile) && (strcmp(atom->getSectionName(), "__common") == 0)) )
- fImportedAtoms.push_back(atom);
- else if ( this->shouldExport(*atom) )
- fExportedAtoms.push_back(atom);
- else if ( !fOptions.stripLocalSymbols() )
- fLocalSymbolAtoms.push_back(atom);
- }
- }
-
- // sort exported atoms by name
- std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), ExportSorter());
-}
-
-
-bool Writer::stabChunkCompare(const struct StabChunks& lhs, const struct StabChunks& rhs)
-{
- if ( lhs.fReader != rhs.fReader ) {
- return lhs.fReaderOrder < rhs.fReaderOrder;
- }
- return lhs.fOrderInReader < rhs.fOrderInReader;
-}
-
-unsigned int Writer::collectStabs()
-{
- unsigned int count = 0;
-
- // collect all stabs chunks
- std::set<ObjectFile::Reader*> seenReaders;
- std::map<ObjectFile::Reader*, unsigned int> readerOrdinals;
- const int atomCount = fAllAtoms->size();
- for (int i=0; i < atomCount; ++i) {
- ObjectFile::Atom* atom = (*fAllAtoms)[i];
- ObjectFile::Reader* atomsReader = atom->getFile();
- unsigned int readerOrder = 0;
- if ( atomsReader != NULL ) {
- std::map<ObjectFile::Reader*, unsigned int>::iterator pos = readerOrdinals.find(atomsReader);
- if ( pos == readerOrdinals.end() ) {
- readerOrder = readerOrdinals.size();
- readerOrdinals[atomsReader] = readerOrder;
- std::vector<ObjectFile::StabsInfo>* readerStabs = atomsReader->getStabsDebugInfo();
- if ( readerStabs != NULL ) {
- StabChunks chunk;
- chunk.fAtom = NULL;
- chunk.fReader = atomsReader;
- chunk.fReaderOrder = readerOrder;
- chunk.fOrderInReader = 0;
- chunk.fStabs = readerStabs;
- fStabChunks.push_back(chunk);
- count += readerStabs->size() + 1; // extra one is for trailing N_SO
- }
- }
- else {
- readerOrder = pos->second;
- }
- }
- std::vector<ObjectFile::StabsInfo>* atomStabs = atom->getStabsDebugInfo();
- if ( atomStabs != NULL ) {
- StabChunks chunk;
- chunk.fAtom = atom;
- chunk.fReader = atomsReader;
- chunk.fReaderOrder = readerOrder;
- chunk.fOrderInReader = atom->getSortOrder();
- chunk.fStabs = atomStabs;
- fStabChunks.push_back(chunk);
- count += atomStabs->size();
- }
- }
-
- // sort stabs: group by .o file
- std::sort(fStabChunks.begin(), fStabChunks.end(), stabChunkCompare);
-
- //fprintf(stderr, "Sorted stabs:\n");
- //for (std::vector<StabChunks>::iterator it=fStabChunks.begin(); it != fStabChunks.end(); it++) {
- // ObjectFile::Atom* atom = (*it).fAtom;
- // if ( atom != NULL )
- // fprintf(stderr, "\t%s\n", (*it).fAtom->getDisplayName());
- // else
- // fprintf(stderr, "\t%s\n", (*it).fReader->getPath());
- //}
-
- return count;
-}
-
-macho_uintptr_t Writer::valueForStab(const ObjectFile::StabsInfo& stab, const ObjectFile::Atom* atom)
-{
- switch ( stab.type ) {
- case N_FUN:
- if ( stab.other == 0 )
- break;
- // end of function N_FUN has size (not address) so should not be adjusted
- // fall through
- case N_BNSYM:
- case N_ENSYM:
- case N_LBRAC:
- case N_RBRAC:
- case N_SLINE:
- case N_STSYM:
- case N_LCSYM:
- // all these stab types need their value changed from an offset in the atom to an address
- if ( atom != NULL )
- return getAtomLoadAddress(atom) + stab.atomOffset;
- }
- return stab.atomOffset;
-}
-
-
-void Writer::addStabs(uint32_t startIndex, uint32_t count)
-{
- macho_nlist* entry = &fSymbolTable[startIndex];
- const int chunkCount = fStabChunks.size();
- for (int i=0; i < chunkCount; ++i ) {
- const StabChunks& chunk = fStabChunks[i];
- const int stabCount = chunk.fStabs->size();
- for (int j=0; j < stabCount; ++j ) {
- const ObjectFile::StabsInfo& stab = (*chunk.fStabs)[j];
- entry->set_n_type(stab.type);
- entry->set_n_sect(stab.other);
- entry->set_n_desc(stab.desc);
- entry->set_n_value(valueForStab(stab, chunk.fAtom));
- entry->set_n_strx(this->fStringsAtom->add(stab.string));
- ++entry;
- }
- if ( (i == chunkCount-1) || (fStabChunks[i+1].fReader != chunk.fReader) ) {
- // need to add empty SO at end of each file
- entry->set_n_type(N_SO);
- entry->set_n_sect(1);
- entry->set_n_desc(0);
- entry->set_n_value(0);
- entry->set_n_strx(this->fStringsAtom->emptyString());
- ++entry;
- }
- }
-}
-
-
-
-uint32_t Writer::symbolIndex(ObjectFile::Atom& atom)
-{
- // search imports
- int i = 0;
- for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
- if ( &atom == *it )
- return i + fSymbolTableImportStartIndex;
- ++i;
- }
-
- // search locals
- i = 0;
- for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
- if ( &atom == *it )
- return i + fSymbolTableLocalStartIndex;
- ++i;
- }
-
- // search exports
- i = 0;
- for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
- if ( &atom == *it )
- return i + fSymbolTableExportStartIndex;
- ++i;
- }
-
- fprintf(stderr, "symbolIndex(%s)\n", atom.getDisplayName());
- fprintf(stderr, "from %s\n", atom.getFile()->getPath());
- throw "atom not found";
-}
-
-void Writer::buildFixups()
-{
- if ( fOptions.outputKind() == Options::kObjectFile )
- this->buildObjectFileFixups();
- else
- this->buildExecutableFixups();
-}
-
-uint32_t Writer::addRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
-{
- ObjectFile::Atom& target = ref->getTarget();
- bool isExtern = target.isImportProxy() || ( strcmp(target.getSectionName(), "__common") == 0 );
- 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;
-
- switch ( ref->getKind() ) {
- case ObjectFile::Reference::noFixUp:
- return 0;
-
- case ObjectFile::Reference::pointer:
- 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(macho_relocation_info::pointer_length);
- reloc1.set_r_extern(isExtern);
- reloc1.set_r_type(GENERIC_RELOC_VANILLA);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
- return 1;
-
- case ObjectFile::Reference::ppcFixupBranch24:
- 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());
- }
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
- return 1;
-
- case ObjectFile::Reference::ppcFixupBranch14:
- reloc1.set_r_address(address);
- reloc1.set_r_symbolnum(sectionNum);
- reloc1.set_r_pcrel(true);
- reloc1.set_r_length(2);
- reloc1.set_r_extern(false);
- reloc1.set_r_type(PPC_RELOC_BR14);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
- return 1;
-
- case ObjectFile::Reference::ppcFixupPicBaseLow14:
- case ObjectFile::Reference::ppcFixupPicBaseLow16:
- {
- macho_uintptr_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
- macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
- uint32_t overflow = 0;
- if ( ((toAddr-fromAddr) & 0x00008000) != 0 )
- overflow = 1;
- sreloc1->set_r_scattered(true);
- sreloc1->set_r_pcrel(false);
- sreloc1->set_r_length(2);
- if ( ref->getKind() == ObjectFile::Reference::ppcFixupPicBaseLow16 )
- sreloc1->set_r_type(PPC_RELOC_LO16_SECTDIFF);
- else
- sreloc1->set_r_type(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));
- sreloc2->set_r_value(fromAddr);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
- return 2;
- }
-
- case ObjectFile::Reference::ppcFixupPicBaseHigh16:
- {
- macho_uintptr_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
- macho_uintptr_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);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
- return 2;
- }
-
- case ObjectFile::Reference::ppcFixupAbsLow14:
- case ObjectFile::Reference::ppcFixupAbsLow16:
- {
- macho_uintptr_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);
- if ( ref->getKind() == ObjectFile::Reference::ppcFixupAbsLow16 )
- reloc1.set_r_type(PPC_RELOC_LO16);
- else
- reloc1.set_r_type(PPC_RELOC_LO14);
- }
- else {
- sreloc1->set_r_scattered(true);
- sreloc1->set_r_pcrel(false);
- sreloc1->set_r_length(2);
- if ( ref->getKind() == ObjectFile::Reference::ppcFixupAbsLow16 )
- sreloc1->set_r_type(PPC_RELOC_LO16);
- else
- sreloc1->set_r_type(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);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
- return 2;
- }
-
- case ObjectFile::Reference::ppcFixupAbsHigh16:
- {
- macho_uintptr_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);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
- return 2;
- }
-
- case ObjectFile::Reference::ppcFixupAbsHigh16AddLow:
- {
- macho_uintptr_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);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
- return 2;
- }
-
- case ObjectFile::Reference::pointer32Difference:
- case ObjectFile::Reference::pointer64Difference:
- {
- macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
- macho_uintptr_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
- sreloc1->set_r_scattered(true);
- sreloc1->set_r_pcrel(false);
- if ( ref->getKind() == ObjectFile::Reference::pointer64Difference )
- sreloc1->set_r_length(3);
- else
- sreloc1->set_r_length(2);
- if ( ref->getTargetOffset() != 0 )
- 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(toAddr);
- sreloc2->set_r_scattered(true);
- sreloc2->set_r_pcrel(false);
- sreloc2->set_r_length(macho_relocation_info::pointer_length);
- sreloc2->set_r_type(PPC_RELOC_PAIR);
- sreloc2->set_r_address(0);
- sreloc2->set_r_value(fromAddr);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
- return 2;
- }
-
- case ObjectFile::Reference::x86FixupBranch32:
- reloc1.set_r_address(address);
- reloc1.set_r_symbolnum(sectionNum);
- reloc1.set_r_pcrel(true);
- reloc1.set_r_length(2);
- reloc1.set_r_extern(false);
- reloc1.set_r_type(GENERIC_RELOC_VANILLA);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
- return 1;
-
- }
- return 0;
-}
-
-
-void Writer::buildObjectFileFixups()
-{
- uint32_t relocIndex = 0;
- std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
- const int segCount = segmentInfos.size();
- for(int i=0; i < segCount; ++i) {
- SegmentInfo* curSegment = segmentInfos[i];
- std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
- const int sectionCount = sectionInfos.size();
- for(int j=0; j < sectionCount; ++j) {
- SectionInfo* curSection = sectionInfos[j];
- std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
- if ( ! curSection->fAllZeroFill ) {
- if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers )
- curSection->fIndirectSymbolOffset = fIndirectSymbolTable.size();
- curSection->fRelocOffset = relocIndex;
- const int atomCount = sectionAtoms.size();
- for (int k=0; k < atomCount; ++k) {
- ObjectFile::Atom* atom = sectionAtoms[k];
- std::vector<ObjectFile::Reference*>& 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 ) {
- uint32_t offsetInSection = atom->getSectionOffset();
- uint32_t indexInSection = offsetInSection / sizeof(macho_uintptr_t);
- uint32_t undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
- uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
- IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
- //printf("fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
- fIndirectSymbolTable.push_back(entry);
- if ( curSection->fAllLazyPointers ) {
- ObjectFile::Atom& target = ref->getTarget();
- ObjectFile::Atom& fromTarget = ref->getFromTarget();
- if ( &fromTarget == NULL ) {
- fprintf(stderr, "lazy pointer %s missing initial binding\n", atom->getDisplayName());
- }
- else {
- bool isExtern = target.isImportProxy();
- uint32_t symbolIndex = 0;
- if ( isExtern )
- symbolIndex = this->symbolIndex(target);
- uint32_t sectionNum = target.getSection()->getIndex();
- uint32_t address = atom->getSectionOffset();
- macho_relocation_info reloc1;
- 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(macho_relocation_info::pointer_length);
- reloc1.set_r_extern(isExtern);
- reloc1.set_r_type(GENERIC_RELOC_VANILLA);
- fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
- ++relocIndex;
- }
- }
- }
- else {
- relocIndex += this->addRelocs(atom, ref);
- }
- }
- }
- curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
- }
- }
- }
-
- // now reverse reloc entries
- for(int i=0; i < segCount; ++i) {
- SegmentInfo* curSegment = segmentInfos[i];
- std::vector<SectionInfo*>& 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;
- }
- }
-
-}
-
-
-void Writer::buildExecutableFixups()
-{
- const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
- std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
- const int segCount = segmentInfos.size();
- for(int i=0; i < segCount; ++i) {
- SegmentInfo* curSegment = segmentInfos[i];
- std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
- const int sectionCount = sectionInfos.size();
- for(int j=0; j < sectionCount; ++j) {
- SectionInfo* curSection = sectionInfos[j];
- std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
- if ( ! curSection->fAllZeroFill ) {
- if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers )
- curSection->fIndirectSymbolOffset = fIndirectSymbolTable.size();
- const int atomCount = sectionAtoms.size();
- for (int k=0; k < atomCount; ++k) {
- ObjectFile::Atom* atom = sectionAtoms[k];
- std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
- const int refCount = refs.size();
- //printf("atom %s has %d references\n", atom->getDisplayName(), refCount);
- for (int l=0; l < refCount; ++l) {
- ObjectFile::Reference* ref = refs[l];
- if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
- // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
- if ( atom->getSize() != sizeof(macho_uintptr_t) ) {
- printf("wrong size pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
- }
- uint32_t offsetInSection = atom->getSectionOffset();
- uint32_t indexInSection = offsetInSection / sizeof(macho_uintptr_t);
- uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
- //fprintf(stderr,"indirect pointer atom %p %s section offset = %d\n", atom, atom->getDisplayName(), offsetInSection);
- if ( ref->getTarget().isImportProxy()
- || ref->getTarget().isWeakDefinition()
- || (fOptions.interposable() && fOptions.shouldExport(ref->getTarget().getName()))
- || (fOptions.nameSpace() == Options::kFlatNameSpace)
- || (fOptions.nameSpace() == Options::kForceFlatNameSpace) ) {
- undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
- }
- uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
- IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
- //fprintf(stderr,"fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
- fIndirectSymbolTable.push_back(entry);
- if ( slideable && curSection->fAllLazyPointers ) {
- // if this is a dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
- macho_relocation_info pblaReloc;
- SectionInfo* sectInfo = (SectionInfo*)ref->getFromTarget().getSection();
- uint32_t sectionNum = sectInfo->getIndex();
- pblaReloc.set_r_address(atom->getAddress()-fOptions.baseAddress());
- pblaReloc.set_r_symbolnum(sectionNum);
- pblaReloc.set_r_pcrel(false);
- pblaReloc.set_r_length(macho_relocation_info::pointer_length);
- pblaReloc.set_r_extern(false);
- pblaReloc.set_r_type(GENERIC_RELOC_VANILLA);
- fInternalRelocs.push_back(pblaReloc);
- }
- }
- else if ( ref->requiresRuntimeFixUp(slideable) ) {
- if ( ! atom->getSegment().isContentWritable() )
- throwf("relocations in read-only segments not supported. %s in %s reference to %s", atom->getDisplayName(), atom->getFile()->getPath(), ref->getTarget().getDisplayName());
- if ( ref->getTarget().isImportProxy() ) {
- // if import is to antoher dylib, this is encoded as an external relocation
- macho_relocation_info externalReloc;
- externalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
- externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
- externalReloc.set_r_pcrel(false);
- externalReloc.set_r_length(macho_relocation_info::pointer_length);
- externalReloc.set_r_extern(true);
- externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
- fExternalRelocs.push_back(externalReloc);
- }
- else {
- // if this is a dylib/bundle, need fix-up encoded as an internal relocation
- 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(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
- internalReloc.set_r_symbolnum(sectionNum);
- internalReloc.set_r_pcrel(false);
- internalReloc.set_r_length(macho_relocation_info::pointer_length);
- internalReloc.set_r_extern(false);
- internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
- fInternalRelocs.push_back(internalReloc);
- }
- }
- }
- }
- }
- }
- }
-}
-
-class ContentWriter : public ObjectFile::ContentWriter
-{
-public:
- ContentWriter(int fd, uint64_t fileOffset) : fFileDescriptor(fd), fFileOffset(fileOffset) {}
- virtual void write(uint64_t atomOffset, const void* buffer, uint64_t size) {
- ::pwrite(fFileDescriptor, buffer, size, fFileOffset+atomOffset);
- }
-private:
- int fFileDescriptor;
- uint64_t fFileOffset;
-};
-
-
-void Writer::writeAtoms()
-{
- const bool requireAllFixUps = (fOptions.outputKind() != Options::kObjectFile);
-
- std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
- const int segCount = segmentInfos.size();
- for(int i=0; i < segCount; ++i) {
- SegmentInfo* curSegment = segmentInfos[i];
- bool isText = ((curSegment->fInitProtection & VM_PROT_EXECUTE) != 0);
- std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
- const int sectionCount = sectionInfos.size();
- for(int j=0; j < sectionCount; ++j) {
- SectionInfo* curSection = sectionInfos[j];
- std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
- //printf("writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName);
- if ( ! curSection->fAllZeroFill ) {
- const int atomCount = sectionAtoms.size();
- uint32_t end = curSection->fFileOffset;
- for (int k=0; k < atomCount; ++k) {
- ObjectFile::Atom* atom = sectionAtoms[k];
- if ( !atom->isImportProxy() ) {
- uint32_t offset = curSection->fFileOffset + atom->getSectionOffset();
- if ( isText && (offset != end) ) {
- // fill gaps with no-ops
- #if defined(ARCH_PPC) || defined(ARCH_PPC64)
- uint32_t ppcNop;
- OSWriteBigInt32(&ppcNop, 0, 0x60000000);
- for (uint32_t p=end; p < offset; p += 4)
- ::pwrite(fFileDescriptor, &ppcNop, 4, p);
- #else defined(ARCH_I386)
- uint8_t x86Nop = 0x90;
- for (uint32_t p=end; p < offset; ++p)
- ::pwrite(fFileDescriptor, &x86Nop, 1, p);
- #endif
- }
- end = offset+atom->getSize();
- //fprintf(stderr, "writing 0x%08X -> 0x%08X, atom %s\n", offset, end, atom->getDisplayName());
- ContentWriter writer(fFileDescriptor, offset);
- atom->writeContent(requireAllFixUps, writer);
- }
- }
- }
- }
- }
-}
-
-
-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;
- unsigned int sectionIndex = 1;
- for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
- ObjectFile::Atom* atom = (*fAllAtoms)[i];
- if ( atom->getSection() != curSection ) {
- 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();
- currentSectionInfo->fAllZeroFill = atom->isZeroFill();
- currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
- if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
- currentSectionInfo->setIndex(sectionIndex++);
- currentSegmentInfo->fSections.push_back(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;
- currentSegmentInfo->fInitProtection = initprot;
- if ( initprot == 0 )
- currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
- else
- currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
- currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
- currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
- this->fSegmentInfos.push_back(currentSegmentInfo);
- }
- currentSectionInfo = new SectionInfo();
- strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
- strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
- currentSectionInfo->fAlignment = atom->getAlignment();
- // check for -sectalign override
- std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
- for(std::vector<Options::SectionAlignment>::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, "__nl_symbol_ptr") == 0) )
- currentSectionInfo->fAllNonLazyPointers = true;
- curSection = atom->getSection();
- }
- // 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();
- if ( currentSectionInfo->fAlignment < atomAlign )
- currentSectionInfo->fAlignment = atomAlign;
- // calculate section offset for this atom
- uint64_t offset = currentSectionInfo->fSize;
- uint64_t alignment = 1 << atomAlign;
- offset = ( (offset+alignment-1) & (-alignment) );
- atom->setSectionOffset(offset);
- currentSectionInfo->fSize = offset + atom->getSize();
- // add atom to section vector
- currentSectionInfo->fAtoms.push_back(atom);
- }
-}
-
-
-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 );
- }
-};
-
-//
-// 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.
-//
-bool Writer::addBranchIslands()
-{
- bool result = false;
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- // Can only possibly need branch islands if __TEXT segment > 16M
- if ( fLoadCommandsSegment->fSize > 16000000 ) {
- const uint32_t kBetweenRegions = 15000000; // place regions of islands every 15MB in __text section
- SectionInfo* textSection = NULL;
- for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
- if ( strcmp((*it)->fSectionName, "__text") == 0 )
- textSection = *it;
- }
- const int kIslandRegionsCount = textSection->fSize / kBetweenRegions;
- typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
- AtomToIsland regionsMap[kIslandRegionsCount];
- std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
- unsigned int islandCount = 0;
-
- // create islands for branch references that are out of range
- for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
- ObjectFile::Atom* atom = *it;
- std::vector<ObjectFile::Reference*>& references = atom->getReferences();
- for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
- ObjectFile::Reference* ref = *rit;
- if ( ref->getKind() == ObjectFile::Reference::ppcFixupBranch24 ) {
- ObjectFile::Atom& target = ref->getTarget();
- int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
- int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
- int64_t displacement = dstAddr - srcAddr;
- const int64_t kFifteenMegLimit = kBetweenRegions;
- if ( (displacement > kFifteenMegLimit) || (displacement < (-kFifteenMegLimit)) ) {
- for (int i=0; i < kIslandRegionsCount; ++i) {
- AtomToIsland* region=®ionsMap[i];
- int64_t islandRegionAddr = kBetweenRegions * (i+1);
- if ( ((srcAddr < islandRegionAddr) && (dstAddr > islandRegionAddr))
- ||((dstAddr < islandRegionAddr) && (srcAddr > islandRegionAddr)) ) {
- TargetAndOffset islandTarget = { &target, ref->getTargetOffset() };
- AtomToIsland::iterator pos = region->find(islandTarget);
- if ( pos == region->end() ) {
- BranchIslandAtom* island = new BranchIslandAtom(*this, target.getDisplayName(), i, target, ref->getTargetOffset());
- (*region)[islandTarget] = island;
- regionsIslands[i].push_back(island);
- ++islandCount;
- ref->setTarget(*island, 0);
- }
- else {
- ref->setTarget(*(pos->second), 0);
- }
- }
- }
- }
- }
- }
- }
-
- // insert islands into __text section and adjust section offsets
- if ( islandCount > 0 ) {
- std::vector<ObjectFile::Atom*> newAtomList;
- newAtomList.reserve(textSection->fAtoms.size()+islandCount);
- uint64_t islandRegionAddr = kBetweenRegions;
- int regionIndex = 0;
- uint64_t sectionOffset = 0;
- for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
- ObjectFile::Atom* atom = *it;
- newAtomList.push_back(atom);
- if ( atom->getAddress() > islandRegionAddr ) {
- std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
- for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
- ObjectFile::Atom* islandAtom = *rit;
- newAtomList.push_back(islandAtom);
- islandAtom->setSection(textSection);
- uint64_t alignment = 1 << (islandAtom->getAlignment());
- sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
- islandAtom->setSectionOffset(sectionOffset);
- sectionOffset += islandAtom->getSize();
- }
- ++regionIndex;
- islandRegionAddr += kBetweenRegions;
- }
- uint64_t alignment = 1 << (atom->getAlignment());
- sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
- atom->setSectionOffset(sectionOffset);
- sectionOffset += atom->getSize();
- }
- textSection->fAtoms = newAtomList;
- textSection->fSize = sectionOffset;
- result = true;
- }
-
- }
-#endif
- return result;
-}
-
-
-void Writer::adjustLoadCommandsAndPadding()
-{
- fSegmentCommands->computeSize();
-
- // recompute load command section offsets
- uint64_t offset = 0;
- std::vector<class ObjectFile::Atom*>& 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();
- offset = ( (offset+alignment-1) & (-alignment) );
- atom->setSectionOffset(offset);
- offset += atom->getSize();
- fLoadCommandsSection->fSize = offset;
- }
-
- std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
- const int sectionCount = sectionInfos.size();
- 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
- 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;
- }
- paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
- }
- else {
- // calculate max padding to keep segment size same, but all free space at end of load commands
- uint64_t totalSize = 0;
- uint64_t worstCaseAlignmentPadding = 0;
- for(int j=0; j < sectionCount; ++j) {
- SectionInfo* curSection = sectionInfos[j];
- totalSize += curSection->fSize;
- if ( j != 0 ) // don't count aligment of mach_header which is page-aligned
- worstCaseAlignmentPadding += (1 << curSection->fAlignment) - 1;
- }
- uint64_t segmentSize = ((totalSize+worstCaseAlignmentPadding+4095) & (-4096));
- // don't know exactly how it will layout, but we can inflate padding atom this big and still keep aligment constraints
- paddingSize = segmentSize - totalSize;
-
- // if command line requires more padding than this
- if ( paddingSize < fOptions.minimumHeaderPad() ) {
- int extraPages = (fOptions.minimumHeaderPad() - 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
-void Writer::assignFileOffsets()
-{
- bool haveFixedSegments = false;
- uint64_t fileOffset = 0;
- uint64_t nextContiguousAddress = 0;
- bool baseAddressUsed = false;
- std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
- const int segCount = segmentInfos.size();
- for(int i=0; i < segCount; ++i) {
- SegmentInfo* curSegment = segmentInfos[i];
- fileOffset = (fileOffset+4095) & (-4096);
- curSegment->fFileOffset = fileOffset;
- if ( curSegment->fFixedAddress ) {
- // segment has fixed address already set
- haveFixedSegments = true;
- }
- else {
- // segment uses next address
- if ( !baseAddressUsed ) {
- baseAddressUsed = true;
- if ( fOptions.baseAddress() != 0 )
- nextContiguousAddress = fOptions.baseAddress();
- }
- curSegment->fBaseAddress = nextContiguousAddress;
- }
- uint64_t address = curSegment->fBaseAddress;
- std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
- const int sectionCount = sectionInfos.size();
- for(int j=0; j < sectionCount; ++j) {
- SectionInfo* curSection = sectionInfos[j];
- uint64_t alignment = 1 << curSection->fAlignment;
- fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
- address = ( (address+alignment-1) & (-alignment) );
- curSection->fFileOffset = fileOffset;
- curSection->setBaseAddress(address);
- //printf("assignFileOffsets(): setBaseAddress(%s, 0x%08llX)\n", curSection->fSectionName, address);
- curSegment->fSize = curSection->getBaseAddress() + curSection->fSize - curSegment->fBaseAddress;
- if ( (fOptions.outputKind() != Options::kObjectFile) || ! curSection->fVirtualSection )
- address += curSection->fSize;
- if ( !curSection->fAllZeroFill ) {
- curSegment->fFileSize = curSegment->fSize;
- fileOffset += curSection->fSize;
- }
- }
- // page align segment size
- curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096);
- curSegment->fSize = (curSegment->fSize+4095) & (-4096);
- if ( curSegment->fBaseAddress == nextContiguousAddress )
- nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
- }
-
- // check for segment overlaps
- if ( haveFixedSegments ) {
- for(int i=0; i < segCount; ++i) {
- SegmentInfo* segment1 = segmentInfos[i];
- for(int j=0; j < segCount; ++j) {
- if ( i != j ) {
- SegmentInfo* segment2 = segmentInfos[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 {
- 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);
- }
- }
- }
- }
- }
-}
-
-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 sectionCount = lastSeg->fSections.size();
- uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
- uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
- for (unsigned int i=firstLinkEditSectionIndex; i < sectionCount; ++i) {
- std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
- const unsigned int atomCount = atoms.size();
- uint64_t sectionOffset = 0;
- lastSeg->fSections[i]->fFileOffset = fileOffset;
- lastSeg->fSections[i]->setBaseAddress(address);
- for (unsigned int j=0; j < atomCount; ++j) {
- ObjectFile::Atom* atom = atoms[j];
- uint64_t alignment = 1 << atom->getAlignment();
- sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
- atom->setSectionOffset(sectionOffset);
- sectionOffset += atom->getSize();
- }
- 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);
- }
-}
-
-
-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";
-}
-
-bool MachHeaderAtom::dontStripName() const
-{
- switch ( fWriter.fOptions.outputKind() ) {
- case Options::kDynamicExecutable:
- case Options::kStaticExecutable:
- return true;
- case Options::kDynamicLibrary:
- case Options::kDynamicBundle:
- case Options::kDyld:
- case Options::kObjectFile:
- return false;
- }
- throw "unknown header type";
-}
-
-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";
-}
-
-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";
-}
-
-uint64_t MachHeaderAtom::getSize() const
-{
- return macho_header::size;
-}
-
-void MachHeaderAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- macho_header mh;
-
- // 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 ) {
- flags = MH_SUBSECTIONS_VIA_SYMBOLS;
- }
- 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;
- }
-
- // get commands info
- uint32_t commandsSize = 0;
- uint32_t commandsCount = 0;
-
- std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
- const unsigned int atomCount = loadCommandAtoms.size();
- for (unsigned int i=0; i < atomCount; ++i) {
- ObjectFile::Atom* atom = loadCommandAtoms[i];
- 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 += 2;
- else
- ++commandsCount;
- }
-
- // fill out mach_header
- mh.set_magic(macho_header::magic_value);
- mh.set_cputype(fWriter.fOptions.architecture());
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
- mh.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
-#elif defined(ARCH_I386)
- mh.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
-#else
- #error unknown architecture
-#endif
- mh.set_filetype(fileType);
- mh.set_ncmds(commandsCount);
- mh.set_sizeofcmds(commandsSize);
- mh.set_flags(flags);
- mh.set_reserved();
-
- // write it
- writer.write(0, &mh, macho_header::size);
-}
-
-
-CustomStackAtom::CustomStackAtom(Writer& writer)
- : WriterAtom(writer, fgStackSegment)
-{
-#if defined(ARCH_PPC) || defined(ARCH_PPC64) || defined(ARCH_I386)
- // stack grows down for these architectures
- fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
-#else
- #error unknown architecture
-#endif
-}
-
-
-void SegmentLoadCommandsAtom::computeSize()
-{
- uint64_t size = 0;
- std::vector<Writer::SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
- const int segCount = segmentInfos.size();
- for(int i=0; i < segCount; ++i) {
- size += macho_segment_command::size;
- std::vector<Writer::SectionInfo*>& sectionInfos = segmentInfos[i]->fSections;
- const int sectionCount = sectionInfos.size();
- for(int j=0; j < sectionCount; ++j) {
- if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
- size += macho_section::content_size;
- }
- }
- fSize = size;
- fCommandCount = segCount;
-}
-
-
-
-void SegmentLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- uint64_t size = this->getSize();
- uint8_t buffer[size];
- const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
- bzero(buffer, fSize);
- uint8_t* p = buffer;
- std::vector<Writer::SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
- const int segCount = segmentInfos.size();
- for(int i=0; i < segCount; ++i) {
- Writer::SegmentInfo* segInfo = segmentInfos[i];
- const int sectionCount = segInfo->fSections.size();
- macho_segment_command* cmd = (macho_segment_command*)p;
- cmd->set_cmd(macho_segment_command::command);
- 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[macho_segment_command::size];
- unsigned int sectionsEmitted = 0;
- for (int j=0; j < sectionCount; ++j) {
- Writer::SectionInfo* sectInfo = segInfo->fSections[j];
- if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
- macho_section* sect = §ions[sectionsEmitted++];
- if ( oneSegment ) {
- // .o files have weird segment range
- if ( sectionsEmitted == 1 ) {
- cmd->set_vmaddr(sectInfo->getBaseAddress());
- cmd->set_fileoff(sectInfo->fFileOffset);
- cmd->set_filesize(segInfo->fFileSize-sectInfo->fFileOffset);
- }
- 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 * macho_relocation_info::size + fWriter.fLocalRelocationsAtom->getFileOffset());
- sect->set_nreloc(sectInfo->fRelocCount);
- }
- if ( sectInfo->fAllZeroFill ) {
- sect->set_flags(S_ZEROFILL);
- }
- else if ( sectInfo->fAllLazyPointers ) {
- sect->set_flags(S_LAZY_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 ( (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, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
- sect->set_flags(S_COALESCED);
- }
- }
- }
- p = &p[macho_segment_command::size + sectionsEmitted*macho_section::content_size];
- cmd->set_cmdsize(macho_segment_command::size + sectionsEmitted*macho_section::content_size);
- cmd->set_nsects(sectionsEmitted);
- }
- writer.write(0, buffer, size);
-}
-
-
-SymbolTableLoadCommandsAtom::SymbolTableLoadCommandsAtom(Writer& writer)
- : WriterAtom(writer, fgTextSegment)
-{
- bzero(&fSymbolTable, macho_symtab_command::size);
- bzero(&fDynamicSymbolTable, macho_dysymtab_command::size);
- writer.fSymbolTableCommands = this;
-}
-
-uint64_t SymbolTableLoadCommandsAtom::getSize() const
-{
- return macho_symtab_command::size + macho_dysymtab_command::size;
-}
-
-void SymbolTableLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- // build LC_DYSYMTAB command
- macho_symtab_command symbolTableCmd;
- bzero(&symbolTableCmd, macho_symtab_command::size);
- symbolTableCmd.set_cmd(LC_SYMTAB);
- symbolTableCmd.set_cmdsize(macho_symtab_command::size);
- symbolTableCmd.set_nsyms(fWriter.fSymbolTableCount);
- symbolTableCmd.set_symoff(fWriter.fSymbolTableAtom->getFileOffset());
- symbolTableCmd.set_stroff(fWriter.fStringsAtom->getFileOffset());
- symbolTableCmd.set_strsize(fWriter.fStringsAtom->getSize());
- writer.write(0, &symbolTableCmd, macho_symtab_command::size);
-
- // build LC_DYSYMTAB command
- macho_dysymtab_command dynamicSymbolTableCmd;
- bzero(&dynamicSymbolTableCmd, macho_dysymtab_command::size);
- dynamicSymbolTableCmd.set_cmd(LC_DYSYMTAB);
- dynamicSymbolTableCmd.set_cmdsize(macho_dysymtab_command::size);
- 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);
- dynamicSymbolTableCmd.set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
- dynamicSymbolTableCmd.set_nindirectsyms(fWriter.fIndirectSymbolTable.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());
- }
- writer.write(macho_symtab_command::size, &dynamicSymbolTableCmd, macho_dysymtab_command::size);
-}
-
-uint64_t DyldLoadCommandsAtom::getSize() const
-{
- uint32_t len = macho_dylinker_command::name_offset + strlen("/usr/lib/dyld");
- len = (len+7) & (-8); // 8-byte align
- return len;
-}
-
-void DyldLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- uint64_t size = this->getSize();
- uint8_t buffer[size];
- 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[macho_dylinker_command::name_offset], "/usr/lib/dyld");
- writer.write(0, buffer, size);
-}
-
-
-
-uint64_t DylibLoadCommandsAtom::getSize() const
-{
- const char* path = fInfo.reader->getInstallPath();
- if ( fInfo.options.fInstallPathOverride != NULL )
- path = fInfo.options.fInstallPathOverride;
- uint32_t len = macho_dylib_command::name_offset + strlen(path);
- len = (len+7) & (-8); // 8-byte align
- return len;
-}
-
-void DylibLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- uint64_t size = this->getSize();
- uint8_t buffer[size];
- bzero(buffer, size);
- const char* path = fInfo.reader->getInstallPath();
- if ( fInfo.options.fInstallPathOverride != NULL )
- path = fInfo.options.fInstallPathOverride;
- macho_dylib_command* cmd = (macho_dylib_command*)buffer;
- if ( fInfo.options.fWeakImport )
- cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
- else
- cmd->set_cmd(LC_LOAD_DYLIB);
- cmd->set_cmdsize(this->getSize());
- cmd->set_timestamp(fInfo.reader->getTimestamp());
- cmd->set_current_version(fInfo.reader->getCurrentVersion());
- cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
- cmd->set_name_offset();
- strcpy((char*)&buffer[macho_dylib_command::name_offset], path);
- writer.write(0, buffer, size);
-}
-
-
-
-uint64_t DylibIDLoadCommandsAtom::getSize() const
-{
- uint32_t len = macho_dylib_command::name_offset + strlen(fWriter.fOptions.installPath());
- len = (len+7) & (-8); // 8-byte align
- return len;
-}
-
-void DylibIDLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- struct timeval currentTime = { 0 , 0 };
- gettimeofday(¤tTime, NULL);
- time_t timestamp = currentTime.tv_sec;
- uint64_t size = this->getSize();
- uint8_t buffer[size];
- 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(timestamp);
- cmd->set_current_version(fWriter.fOptions.currentVersion());
- cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
- strcpy((char*)&buffer[macho_dylib_command::name_offset], fWriter.fOptions.installPath());
- writer.write(0, buffer, size);
-}
-
-
-uint64_t RoutinesLoadCommandsAtom::getSize() const
-{
- return macho_routines_command::size;
-}
-
-void RoutinesLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
- uint8_t buffer[macho_routines_command::size];
- bzero(buffer, macho_routines_command::size);
- macho_routines_command* cmd = (macho_routines_command*)buffer;
- cmd->set_cmd(macho_routines_command::command);
- cmd->set_cmdsize(this->getSize());
- cmd->set_init_address(initAddr);
- writer.write(0, buffer, macho_routines_command::size);
-}
-
-
-uint64_t SubUmbrellaLoadCommandsAtom::getSize() const
-{
- uint32_t len = macho_sub_umbrella_command::name_offset + strlen(fName);
- len = (len+7) & (-8); // 8-byte align
- return len;
-}
-
-void SubUmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- uint64_t size = this->getSize();
- uint8_t buffer[size];
- 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_name_offset();
- strcpy((char*)&buffer[macho_sub_umbrella_command::name_offset], fName);
- writer.write(0, buffer, size);
-}
-
-
-uint64_t SubLibraryLoadCommandsAtom::getSize() const
-{
- uint32_t len = macho_sub_library_command::name_offset + fNameLength + 1;
- len = (len+7) & (-8); // 8-byte align
- return len;
-}
-
-void SubLibraryLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- uint64_t size = this->getSize();
- uint8_t buffer[size];
- 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_name_offset();
- strncpy((char*)&buffer[macho_sub_library_command::name_offset], fNameStart, fNameLength);
- buffer[macho_sub_library_command::name_offset+fNameLength] = '\0';
- writer.write(0, buffer, size);
-}
-
-uint64_t UmbrellaLoadCommandsAtom::getSize() const
-{
- uint32_t len = macho_sub_framework_command::name_offset + strlen(fName);
- len = (len+7) & (-8); // 8-byte align
- return len;
-}
-
-void UmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- uint64_t size = this->getSize();
- uint8_t buffer[size];
- 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_name_offset();
- strcpy((char*)&buffer[macho_sub_framework_command::name_offset], fName);
- writer.write(0, buffer, size);
-}
-
-uint64_t ThreadsLoadCommandsAtom::getSize() const
-{
-#if defined(ARCH_PPC)
- uint32_t stateSize = 40; // PPC_THREAD_STATE_COUNT;
-#elif defined(ARCH_PPC64)
- uint32_t stateSize = 76; // PPC_THREAD_STATE64_COUNT;
-#elif defined(ARCH_I386)
- uint32_t stateSize = 16; // i386_THREAD_STATE_COUNT;
-#else
- #error unknown architecture
-#endif
- return macho_thread_command::size + stateSize*4;
-}
-
-void ThreadsLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- uint64_t size = this->getSize();
- uint8_t buffer[size];
- 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);
-#if defined(ARCH_PPC)
- cmd->set_flavor(1); // PPC_THREAD_STATE
- cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
- cmd->set_threadState32(0, start);
- if ( fWriter.fOptions.hasCustomStack() )
- cmd->set_threadState32(3, fWriter.fOptions.customStackAddr()); // r1
-#elif defined(ARCH_PPC64)
- cmd->set_flavor(5); // PPC_THREAD_STATE64
- cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
- cmd->set_threadState64(0, start);
- if ( fWriter.fOptions.hasCustomStack() )
- cmd->set_threadState64(6, fWriter.fOptions.customStackAddr()); // r1
-#elif defined(ARCH_I386)
- cmd->set_flavor(0xFFFFFFFF); // i386_THREAD_STATE
- cmd->set_count(16); // i386_THREAD_STATE_COUNT;
- cmd->set_threadState32(0, start);
- if ( fWriter.fOptions.hasCustomStack() )
- cmd->set_threadState32(15, fWriter.fOptions.customStackAddr()); // uesp
-#else
- #error unknown architecture
-#endif
- writer.write(0, buffer, size);
-}
-
-
-
-uint64_t LoadCommandsPaddingAtom::getSize() const
-{
- return fSize;
-}
-
-void LoadCommandsPaddingAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- uint8_t buffer[fSize];
- bzero(buffer, fSize);
- writer.write(0, buffer, fSize);
-}
-
-
-uint64_t LinkEditAtom::getFileOffset() const
-{
- return ((Writer::SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
-}
-
-
-uint64_t LocalRelocationsLinkEditAtom::getSize() const
-{
- return fWriter.fInternalRelocs.size() * macho_relocation_info::size;
-}
-
-void LocalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- writer.write(0, &fWriter.fInternalRelocs[0], this->getSize());
-}
-
-
-
-uint64_t SymbolTableLinkEditAtom::getSize() const
-{
- return fWriter.fSymbolTableCount * macho_nlist::size;
-}
-
-void SymbolTableLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- writer.write(0, fWriter.fSymbolTable, this->getSize());
-}
-
-uint64_t ExternalRelocationsLinkEditAtom::getSize() const
-{
- return fWriter.fExternalRelocs.size() * macho_relocation_info::size;
-}
-
-void ExternalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- writer.write(0, &fWriter.fExternalRelocs[0], this->getSize());
-}
-
-
-
-uint64_t IndirectTableLinkEditAtom::getSize() const
-{
- return fWriter.fIndirectSymbolTable.size() * sizeof(uint32_t);
-}
-
-void IndirectTableLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- uint64_t size = this->getSize();
- uint8_t buffer[size];
- bzero(buffer, size);
- const uint32_t indirectTableSize = fWriter.fIndirectSymbolTable.size();
- uint32_t* indirectTable = (uint32_t*)buffer;
- for (uint32_t i=0; i < indirectTableSize; ++i) {
- Writer::IndirectEntry& entry = fWriter.fIndirectSymbolTable[i];
- if ( entry.indirectIndex < indirectTableSize ) {
- ENDIAN_WRITE32(indirectTable[entry.indirectIndex], entry.symbolIndex);
- }
- else {
- throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, entry.indirectIndex);
- }
- }
- writer.write(0, buffer, size);
-}
-
-
-
-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';
-}
-
-uint64_t StringsLinkEditAtom::getSize() const
-{
- return kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
-}
-
-void StringsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- uint64_t offset = 0;
- for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
- writer.write(offset, fFullBuffers[i], kBufferSize);
- offset += kBufferSize;
- }
- writer.write(offset, fCurrentBuffer, fCurrentBufferUsed);
-}
-
-int32_t StringsLinkEditAtom::add(const char* name)
-{
- int lenNeeded = strlen(name)+1;
- while ( lenNeeded + fCurrentBufferUsed >= kBufferSize ) {
- // first part of string fits in current buffer
- int firstLen = kBufferSize - fCurrentBufferUsed;
- memcpy(&fCurrentBuffer[fCurrentBufferUsed], name, firstLen);
- // alloc next buffer
- fFullBuffers.push_back(fCurrentBuffer);
- fCurrentBuffer = new char[kBufferSize];
- fCurrentBufferUsed = 0;
- // advance name to second part
- name += firstLen;
- lenNeeded -= firstLen;
- }
- //fprintf(stderr, "StringsLinkEditAtom::add(): lenNeeded=%d, fCurrentBuffer=%d, fCurrentBufferUsed=%d\n", lenNeeded, fCurrentBuffer, fCurrentBufferUsed);
- // string all fits in current buffer
- strcpy(&fCurrentBuffer[fCurrentBufferUsed], name);
- int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
- fCurrentBufferUsed += lenNeeded;
- return offset;
-}
-
-// returns the index of an empty string
-int32_t StringsLinkEditAtom::emptyString()
-{
- return 1;
-}
-
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-BranchIslandAtom::BranchIslandAtom(Writer& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
- : WriterAtom(writer, 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;
-}
-
-
-void BranchIslandAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
- int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
- uint8_t instruction[4];
- int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
- OSWriteBigInt32(&instruction, 0, branchInstruction);
- writer.write(0, &instruction, 4);
-}
-
-
-#endif
-
-
-};
-
-
-
--- /dev/null
+/*
+ * 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 <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdio.h>
+#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 */
+
--- /dev/null
+/*
+ * 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 <stdint.h>
+#include <stddef.h>
+
+#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
+
--- /dev/null
+/*
+ * 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
+};
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * 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,
* FITNESS FOR A PARTICULAR PURPOSE, 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 <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
+#include <sys/sysctl.h>
#include <fcntl.h>
#include <errno.h>
-#include <mach-o/loader.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
#include <mach-o/fat.h>
+
#include <string>
#include <set>
#include <string>
#include "Options.h"
#include "ObjectFile.h"
-#include "ObjectFileMachO-all.h"
-#include "ExecutableFile.h"
-#include "ExecutableFileMachO-all.h"
+#include "MachOReaderRelocatable.hpp"
+#include "MachOReaderArchive.hpp"
+#include "MachOReaderDylib.hpp"
+#include "MachOWriterExecutable.hpp"
#include "SectCreate.h"
static void dumpAtom(ObjectFile::Atom* atom)
{
//printf("atom: %p\n", atom);
-
+
// name
printf("name: %s\n", atom->getDisplayName());
-
+
// scope
switch ( atom->getScope() ) {
case ObjectFile::Atom::scopeTranslationUnit:
default:
printf("scope: unknown\n");
}
-
+
+ // kind
+ switch ( atom->getDefinitinonKind() ) {
+ 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;
+ default:
+ printf("scope: unknown\n");
+ }
+
// segment and section
printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
// attributes
printf("attrs: ");
- if ( atom->isTentativekDefinition() )
- printf("tentative ");
- else if ( atom->isWeakDefinition() )
- printf("weak ");
- if ( atom->isCoalesableByName() )
- printf("coalesce-by-name ");
- if ( atom->isCoalesableByValue() )
- printf("coalesce-by-value ");
if ( atom->dontDeadStrip() )
printf("dont-dead-strip ");
if ( atom->isZeroFill() )
printf("zero-fill ");
printf("\n");
-
+
// size
printf("size: 0x%012llX\n", atom->getSize());
-
+
// content
uint8_t content[atom->getSize()];
atom->copyRawContent(content);
printf("%02X ", content[i]);
}
printf("\n");
-
+
// references
std::vector<ObjectFile::Reference*>& references = atom->getReferences();
const int refCount = references.size();
ObjectFile::Reference* ref = references[i];
printf(" %s\n", ref->getDescription());
}
-
+
// attributes
-
+
}
#endif
Section* Section::find(const char* sectionName, const char* segmentName, bool zeroFill)
{
-#if 0
- std::pair<NameToSection::iterator, NameToSection::iterator> range = fgMapping.equal_range(sectionName);
- for (NameToSection::iterator it=range.first; it != range.second; it++) {
- if ( strcmp(it->second->fSegmentName, segmentName) == 0 )
- return it->second;
- }
-#endif
NameToSection::iterator pos = fgMapping.find(sectionName);
if ( pos != fgMapping.end() ) {
if ( strcmp(pos->second->fSegmentName, segmentName) == 0 )
return *it;
}
}
-
+
// does not exist, so make a new one
Section* sect = new Section(sectionName, segmentName, zeroFill);
sect->fIndex = fgMapping.size();
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);
+ }
+
return sect;
}
return 4;
if ( strcmp(segName, "__LINKEDIT") == 0 )
return INT_MAX; // linkedit segment should always sort last
- else
+ else
return 5;
}
// 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<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++)
+ for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++)
(*it)->fIndex = newOrder++;
//printf("sorted:\n");
void addInputFile(ObjectFile::Reader* reader);
void setOutputFile(ExecutableFile::Writer* writer);
void link();
-
-
+
+
private:
ObjectFile::Reader* createReader(const Options::FileInfo&);
void addAtom(ObjectFile::Atom& atom);
void deadStrip();
void sortAtoms();
void tweakLayout();
+ void writeDotOutput();
+ static bool minimizeStab(ObjectFile::Reader::Stab& stab);
+ static const char* truncateStabString(const char* str);
+ void collectStabs();
void writeOutput();
-
+ ObjectFile::Atom* entryPoint();
+ ObjectFile::Atom* dyldHelper();
+ const char* assureFullPath(const char* path);
+ void markLive(ObjectFile::Atom* atom, std::set<ObjectFile::Atom*>& liveAtoms);
+ void collectStabs(ObjectFile::Reader* reader);
+ void synthesizeStabs(ObjectFile::Reader* reader);
+ 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 resolve(ObjectFile::Reference* reference);
void resolveFrom(ObjectFile::Reference* reference);
void addJustInTimeAtoms(const char* name);
-
- void addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info);
+
+ 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 addIndirectLibraries(ObjectFile::Reader* reader);
bool haveIndirectLibrary(const char* path, ObjectFile::Reader* reader);
bool haveDirectLibrary(const char* path);
-
+
+ void logTraceInfo(const char* format, ...);
class SymbolTable
{
public:
unsigned int getRequireCount() { return fRequireCount; }
void getNeededNames(bool andWeakDefintions, std::vector<const char*>& undefines);
private:
- typedef std::map<const char*, ObjectFile::Atom*, CStringComparor> Mapper;
+ typedef __gnu_cxx::hash_map<const char*, ObjectFile::Atom*, __gnu_cxx::hash<const char*>, CStringEquals> Mapper;
Linker& fOwner;
Mapper fTable;
unsigned int fRequireCount;
};
-
+
struct AtomSorter
{
bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right);
};
-
+
typedef std::map<const char*, uint32_t, CStringComparor> SectionOrder;
-
+
struct IndirectLibrary {
const char* path;
uint64_t fileLen;
ObjectFile::Reader* reader;
std::set<ObjectFile::Reader*> parents;
- ObjectFile::Reader* reExportParent;
+ ObjectFile::Reader* reExportedViaDirectLibrary;
};
-
+
+ ObjectFile::Reader* findDirectLibraryWhichReExports(struct IndirectLibrary& indirectLib);
+
Options fOptions;
SymbolTable fGlobalSymbolTable;
unsigned int fWeakSymbolsAddedCount;
ExecutableFile::Writer* fOutputFile;
std::vector<ExecutableFile::DyLibUsed> fDynamicLibraries;
std::list<IndirectLibrary> fIndirectDynamicLibraries;
+ std::vector<class ObjectFile::Reader*> fReadersThatHaveSuppliedAtoms;
std::vector<class ObjectFile::Atom*> fAllAtoms;
std::set<class ObjectFile::Atom*> fDeadAtoms;
+ std::vector<class ObjectFile::Reader::Stab> fStabs;
+ bool fCreateUUID;
SectionOrder fSectionOrder;
unsigned int fNextSortOrder;
+ unsigned int fNextObjectFileOrder;
+ cpu_type_t fArchitecture;
bool fDirectLibrariesComplete;
+ uint64_t fOutputFileSize;
+ uint64_t fStartTime;
+ uint64_t fStartCreateReadersTime;
+ uint64_t fStartCreateWriterTime;
+ uint64_t fStartBuildAtomsTime;
+ uint64_t fStartLoadUndefinesTime;
+ uint64_t fStartResolveTime;
+ uint64_t fStartSortTime;
+ 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;
};
-
Linker::Linker(int argc, const char* argv[])
- : fOptions(argc, argv), fGlobalSymbolTable(*this), fOutputFile(NULL), fNextSortOrder(1), fDirectLibrariesComplete(false)
+ : fOptions(argc, argv), fGlobalSymbolTable(*this), fOutputFile(NULL), fCreateUUID(false), fNextSortOrder(1),
+ fNextObjectFileOrder(1), fArchitecture(0), fDirectLibrariesComplete(false), fOutputFileSize(0), fTotalObjectSize(0),
+ fTotalArchiveSize(0), fTotalObjectLoaded(0), fTotalArchivesLoaded(0), fTotalDylibsLoaded(0)
{
+ 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();
+ }
}
+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<Options::FileInfo>& files = fOptions.getInputFiles();
+ for (std::vector<Options::FileInfo>::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<ppc>::validFile(buffer) ) {
+ fprintf(stderr, "ld64 warning: -arch not used, infering -arch ppc based on %s\n", it->path);
+ return CPU_TYPE_POWERPC;
+ }
+ else if ( mach_o::relocatable::Reader<ppc64>::validFile(buffer) ) {
+ fprintf(stderr, "ld64 warning: -arch not used, infering -arch ppc64 based on %s\n", it->path);
+ return CPU_TYPE_POWERPC64;
+ }
+ else if ( mach_o::relocatable::Reader<x86>::validFile(buffer) ) {
+ fprintf(stderr, "ld64 warning: -arch not used, infering -arch i386 based on %s\n", it->path);
+ return CPU_TYPE_I386;
+ }
+ }
+ }
+ }
+
+ // no thin .o files found, so default to same architecture this was built as
+ fprintf(stderr, "ld64 warning: -arch not specified\n");
+#if __ppc__
+ return CPU_TYPE_POWERPC;
+#elif __i386__
+ return CPU_TYPE_I386;
+#elif __ppc64__
+ return CPU_TYPE_POWERPC64;
+#else
+ #error unknown default architecture
+#endif
+}
+
+
void Linker::addInputFile(ObjectFile::Reader* reader)
{
+ reader->setSortOrder(fNextObjectFileOrder++);
fInputFiles.push_back(reader);
}
}
void Linker::link()
-{
+{
this->buildAtomList();
this->loadUndefines();
this->resolveReferences();
this->deadStrip();
this->sortAtoms();
this->tweakLayout();
+ this->writeDotOutput();
+ this->collectStabs();
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 = 1000000000LL * 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("ld64 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", fStartLoadUndefinesTime - fStartBuildAtomsTime, totalTime);
+ printTime(" load undefines", fStartResolveTime - fStartLoadUndefinesTime, totalTime);
+ printTime(" resolve references", fStartSortTime - fStartResolveTime, totalTime);
+ printTime(" sort output", fStartWriteTime - fStartSortTime, 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);
-
+
// add atom's references's names to symbol table as to-be-resolved-later
std::vector<class ObjectFile::Reference*>& references = atom.getReferences();
for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
if ( reference->hasFromTarget() && reference->isFromTargetUnbound() )
fGlobalSymbolTable.require(reference->getFromTargetName());
}
-
+
// 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) ) {
fGlobalSymbolTable.add(atom);
-
+
// update scope based on export list (possible that globals are downgraded to private_extern)
if ( (scope == ObjectFile::Atom::scopeGlobal) && fOptions.hasExportRestrictList() ) {
bool doExport = fOptions.shouldExport(name);
}
}
}
-
+
// record section orders so output file can have same order
atom.setSection(Section::find(atom.getSectionName(), atom.getSegment().getName(), atom.isZeroFill()));
-
+
// assign order in which this atom was originally seen
if ( atom.getSortOrder() == 0 )
fNextSortOrder = atom.setSortOrder(fNextSortOrder);
inline void Linker::addAtoms(std::vector<class ObjectFile::Atom*>& atoms)
{
+ bool first = true; // assume all atoms are from same reader
for (std::vector<ObjectFile::Atom*>::iterator it=atoms.begin(); it != atoms.end(); it++) {
+ if ( first ) {
+ // update fReadersThatHaveSuppliedAtoms
+ ObjectFile::Reader* reader = (*it)->getFile();
+ if ( std::find(fReadersThatHaveSuppliedAtoms.begin(), fReadersThatHaveSuppliedAtoms.end(), reader)
+ == fReadersThatHaveSuppliedAtoms.end() ) {
+ fReadersThatHaveSuppliedAtoms.push_back(reader);
+ }
+ }
this->addAtom(**it);
+ first = false;
}
}
void Linker::buildAtomList()
{
+ fStartBuildAtomsTime = mach_absolute_time();
// add initial undefines from -u option
std::vector<const char*>& initialUndefines = fOptions.initialUndefines();
for (std::vector<const char*>::iterator it=initialUndefines.begin(); it != initialUndefines.end(); it++) {
fGlobalSymbolTable.require(*it);
}
-
- // writer can contribute atoms
+
+ // writer can contribute atoms
this->addAtoms(fOutputFile->getAtoms());
-
+
// each reader contributes atoms
const int readerCount = fInputFiles.size();
for (int i=0; i < readerCount; ++i) {
this->addAtoms(fInputFiles[i]->getAtoms());
}
-
+
// extra command line section always at end
std::vector<Options::ExtraSection>& extraSections = fOptions.extraSections();
for( std::vector<Options::ExtraSection>::iterator it=extraSections.begin(); it != extraSections.end(); ++it) {
}
}
+static const char* pathLeafName(const char* path)
+{
+ const char* shortPath = strrchr(path, '/');
+ if ( shortPath == NULL )
+ return path;
+ else
+ return &shortPath[1];
+}
+
void Linker::loadUndefines()
{
+ fStartLoadUndefinesTime = mach_absolute_time();
// keep looping until no more undefines were added in last loop
unsigned int undefineCount = 0xFFFFFFFF;
while ( undefineCount != fGlobalSymbolTable.getRequireCount() ) {
undefineCount = fGlobalSymbolTable.getRequireCount();
std::vector<const char*> undefineNames;
- fGlobalSymbolTable.getNeededNames(true, undefineNames);
- const int undefineCount = undefineNames.size();
- for (int i=0; i < undefineCount; ++i) {
- const char* name = undefineNames[i];
+ fGlobalSymbolTable.getNeededNames(false, undefineNames);
+ for(std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
+ const char* name = *it;
ObjectFile::Atom* possibleAtom = fGlobalSymbolTable.find(name);
- if ( (possibleAtom == NULL) || (possibleAtom->isWeakDefinition() && (fOptions.outputKind() != Options::kObjectFile)) )
+ if ( (possibleAtom == NULL)
+ || ((possibleAtom->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition) && (fOptions.outputKind() != Options::kObjectFile) && (possibleAtom->getScope() == ObjectFile::Atom::scopeGlobal)) )
this->addJustInTimeAtoms(name);
}
}
-
+
if ( fOptions.outputKind() != Options::kObjectFile ) {
// error out on any remaining undefines
bool doPrint = true;
fprintf(stderr, "can't resolve symbols:\n");
for (int i=0; i < unresolvableCount; ++i) {
const char* name = unresolvableUndefines[i];
- const unsigned int nameLen = strlen(name);
fprintf(stderr, " %s, referenced from:\n", name);
- char stubName[nameLen+6];
- strcpy(stubName, name);
- strcat(stubName, "$stub");
- char nonLazyName[nameLen+16];
- strcpy(nonLazyName, name);
- strcat(nonLazyName, "$non_lazy_ptr");
- ObjectFile::Atom* lastStubAtomWithUnresolved = NULL;
- ObjectFile::Atom* lastNonLazyAtomWithUnresolved = NULL;
// scan all atoms for references
bool foundAtomReference = false;
for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
ObjectFile::Reference* reference = *rit;
if ( reference->isTargetUnbound() ) {
- if ( (atom != lastStubAtomWithUnresolved) && (strcmp(reference->getTargetName(), stubName) == 0) ) {
- const char* path = atom->getFile()->getPath();
- const char* shortPath = strrchr(path, '/');
- if ( shortPath == NULL )
- shortPath = path;
- else
- shortPath = &shortPath[1];
- fprintf(stderr, " %s in %s\n", atom->getDisplayName(), shortPath);
- lastStubAtomWithUnresolved = atom;
- foundAtomReference = true;
- }
- else if ( (atom != lastNonLazyAtomWithUnresolved) && (strcmp(reference->getTargetName(), nonLazyName) == 0) ) {
- const char* path = atom->getFile()->getPath();
- const char* shortPath = strrchr(path, '/');
- if ( shortPath == NULL )
- shortPath = path;
- else
- shortPath = &shortPath[1];
- fprintf(stderr, " %s in %s\n", atom->getDisplayName(), shortPath);
- lastNonLazyAtomWithUnresolved = atom;
+ if ( strcmp(reference->getTargetName(), name) == 0 ) {
+ fprintf(stderr, " %s in %s\n", atom->getDisplayName(), pathLeafName(atom->getFile()->getPath()));
foundAtomReference = true;
}
}
if ( reference->hasFromTarget() && reference->isFromTargetUnbound() ) {
- if ( (atom != lastStubAtomWithUnresolved) && (strcmp(reference->getFromTargetName(), stubName) == 0) ) {
- const char* path = atom->getFile()->getPath();
- const char* shortPath = strrchr(path, '/');
- if ( shortPath == NULL )
- shortPath = path;
- else
- shortPath = &shortPath[1];
- fprintf(stderr, " %s in %s\n", atom->getDisplayName(), shortPath);
- lastStubAtomWithUnresolved = atom;
- foundAtomReference = true;
- }
- else if ( (atom != lastNonLazyAtomWithUnresolved) && (strcmp(reference->getFromTargetName(), nonLazyName) == 0) ) {
- const char* path = atom->getFile()->getPath();
- const char* shortPath = strrchr(path, '/');
- if ( shortPath == NULL )
- shortPath = path;
- else
- shortPath = &shortPath[1];
- fprintf(stderr, " %s in %s\n", atom->getDisplayName(), shortPath);
- lastNonLazyAtomWithUnresolved = atom;
+ if ( strcmp(reference->getFromTargetName(), name) == 0 ) {
+ fprintf(stderr, " %s in %s\n", atom->getDisplayName(), pathLeafName(atom->getFile()->getPath()));
foundAtomReference = true;
}
}
if ( doError && (unresolvableCount > unresolvableExportsCount) ) // last check should be removed. It exists so broken projects still build
throw "symbol(s) not found";
}
-
+
// now verify that -init routine exists
if ( fOptions.initFunctionName() != NULL ) {
if ( fGlobalSymbolTable.find(fOptions.initFunctionName()) == NULL )
void Linker::addJustInTimeAtoms(const char* name)
{
- // when creating final linked image, write gets first chance
+ // when creating final linked image, writer gets first chance
if ( fOptions.outputKind() != Options::kObjectFile ) {
- ObjectFile::Atom* atom = fOutputFile->getUndefinedProxyAtom(name);
- if ( atom != NULL ) {
- this->addAtom(*atom);\
- return;
- }
- }
-
- // give direct readers a chance
- const int readerCount = fInputFiles.size();
- for (int i=0; i < readerCount; ++i) {
- // 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.
- std::vector<class ObjectFile::Atom*>* atoms = fInputFiles[i]->getJustInTimeAtomsFor(name);
+ std::vector<class ObjectFile::Atom*>* atoms = fOutputFile->getJustInTimeAtomsFor(name);
if ( atoms != NULL ) {
this->addAtoms(*atoms);
delete atoms;
+ //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fOutputFile->getPath() );
return; // found a definition, no need to search anymore
- //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file #%d\n", name, i);
}
}
-
+
+ // give direct readers a chance
+ for (std::vector<class ObjectFile::Reader*>::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.
+ std::vector<class ObjectFile::Atom*>* atoms = reader->getJustInTimeAtomsFor(name);
+ if ( atoms != NULL ) {
+ this->addAtoms(*atoms);
+ delete atoms;
+ //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fInputFiles[i]->getPath() );
+ return; // found a definition, no need to search anymore
+ }
+ }
+ }
+
// give indirect readers a chance
for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
ObjectFile::Reader* reader = it->reader;
std::vector<class ObjectFile::Atom*>* atoms = reader->getJustInTimeAtomsFor(name);
if ( atoms != NULL ) {
this->addAtoms(*atoms);
+ //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
delete atoms;
- break;
- //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file #%d\n", name, i);
+ return; // found a definition, no need to search anymore
}
}
}
-
+
// when creating .o file, writer goes last (this is so any static archives will be searched above)
- if ( fOptions.outputKind() == Options::kObjectFile ) {
+ if ( (fOptions.outputKind() == Options::kObjectFile) || (fOptions.undefinedTreatment() != Options::kUndefinedError) ) {
ObjectFile::Atom* atom = fOutputFile->getUndefinedProxyAtom(name);
if ( atom != NULL ) {
this->addAtom(*atom);
return;
}
}
-
+ //fprintf(stderr, "addJustInTimeAtoms(%s) => not found\n", name);
}
void Linker::resolve(ObjectFile::Reference* reference)
{
- ObjectFile::Atom* target = NULL;
- const char* targetName = reference->getTargetName();
- const int targetNameLen = strlen(targetName);
- if ( (targetNameLen > 5) && (strcmp(&targetName[targetNameLen-5], "$stub") == 0) ) {
- // when looking up "_foo$stub", first look for "_foo"
- char nonStubTarget[targetNameLen+1];
- strcpy(nonStubTarget, targetName);
- nonStubTarget[targetNameLen-5] = '\0';
- // unless interposing and the symbol is exported
- if ( !fOptions.interposable() || !fOptions.shouldExport(nonStubTarget) ) {
- target = fGlobalSymbolTable.find(nonStubTarget);
- // also need indirection to all exported weak symbols for C++ support
- if ( (target != NULL) && !target->isImportProxy() && (!target->isWeakDefinition() || (target->getScope() != ObjectFile::Atom::scopeGlobal)) ) {
- reference->setTarget(*target, reference->getTargetOffset());
- // mark stub as no longer being needed
- ObjectFile::Atom* stub = fGlobalSymbolTable.find(targetName);
- if ( stub != NULL ) {
- char lazySymbol[targetNameLen+8];
- strcpy(lazySymbol, nonStubTarget);
- strcat(lazySymbol, "$lazy_ptr");
- ObjectFile::Atom* lazyPtr = fGlobalSymbolTable.find(lazySymbol);
- fDeadAtoms.insert(stub);
- if ( lazyPtr != NULL )
- fDeadAtoms.insert(lazyPtr);
- }
- return;
- }
- }
- }
-
// look in global symbol table
- target = fGlobalSymbolTable.find(targetName);
+ const char* targetName = reference->getTargetName();
+ ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
if ( target == NULL ) {
fprintf(stderr, "can't resolve: %s\n", targetName);
}
reference->setTarget(*target, reference->getTargetOffset());
-
- // handle weak-imports
- if ( target->isImportProxy() ) {
- bool mismatch = false;
- if ( reference->isWeakReference() ) {
- switch(target->getImportWeakness()) {
- case ObjectFile::Atom::kWeakUnset:
- target->setImportWeakness(true);
- break;
- case ObjectFile::Atom::kWeakImport:
- break;
- case ObjectFile::Atom::kNonWeakImport:
- mismatch = true;
- break;
- }
- }
- else {
- switch(target->getImportWeakness()) {
- case ObjectFile::Atom::kWeakUnset:
- target->setImportWeakness(false);
- break;
- case ObjectFile::Atom::kWeakImport:
- mismatch = true;
- break;
- case ObjectFile::Atom::kNonWeakImport:
- break;
- }
- }
- if ( mismatch ) {
- switch ( fOptions.weakReferenceMismatchTreatment() ) {
- case Options::kWeakReferenceMismatchError:
- throwf("mismatching weak references for symbol: %s", target->getName());
- case Options::kWeakReferenceMismatchWeak:
- target->setImportWeakness(true);
- break;
- case Options::kWeakReferenceMismatchNonWeak:
- target->setImportWeakness(false);
- break;
- }
- }
- }
}
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);
void Linker::resolveReferences()
{
+ fStartResolveTime = mach_absolute_time();
// 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<class ObjectFile::Reference*>& references = atom->getReferences();
for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
ObjectFile::Reference* reference = *it;
- if ( reference->isTargetUnbound() )
+ if ( reference->isTargetUnbound() )
this->resolve(reference);
- if ( reference->hasFromTarget() && reference->isFromTargetUnbound() )
+ if ( reference->hasFromTarget() && reference->isFromTargetUnbound() )
this->resolveFrom(reference);
}
}
{
public:
InSet(std::set<ObjectFile::Atom*>& deadAtoms) : fDeadAtoms(deadAtoms) {}
-
- bool operator()(ObjectFile::Atom*& atom) const {
+
+ bool operator()(ObjectFile::Atom*& atom) const {
return ( fDeadAtoms.count(atom) != 0 );
}
-
+
private:
std::set<ObjectFile::Atom*>& fDeadAtoms;
};
+// used to remove stabs associated with atoms that won't be in output file
+class NotInSet
+{
+public:
+ NotInSet(std::set<ObjectFile::Atom*>& 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<ObjectFile::Atom*>& fSet;
+};
+
+
+class DeadStrippable
+{
+public:
+ DeadStrippable() {}
+
+ bool operator()(ObjectFile::Atom*& atom) const {
+ //if ( ! atom->dontDeadStrip() )
+ // fprintf(stderr, "dead strip %s\n", atom->getDisplayName());
+ return ( ! atom->dontDeadStrip() );
+ }
+};
+
+void Linker::markLive(ObjectFile::Atom* atom, std::set<ObjectFile::Atom*>& liveAtoms)
+{
+ if ( liveAtoms.count(atom) == 0 ) {
+ // this atom is live
+ liveAtoms.insert(atom);
+ // so don't dead strip
+ atom->setDontDeadStrip();
+
+ // and all atoms it references
+ std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
+ for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
+ ObjectFile::Reference* reference = *it;
+ // mark target of reference as live
+ this->markLive(&reference->getTarget(), liveAtoms);
+ // mark from-target (if it exists) as live
+ if ( reference->hasFromTarget() )
+ this->markLive(&reference->getFromTarget(), liveAtoms);
+ }
+ }
+}
void Linker::deadStrip()
{
- //printf("Stripping atoms:\n");
- //for (std::set<ObjectFile::Atom*>::iterator it=fDeadAtoms.begin(); it != fDeadAtoms.end(); it++) {
- // printf("\t%s\n", (*it)->getDisplayName());
- //}
+ if ( fOptions.deadStrip() != Options::kDeadStripOff ) {
+ std::set<ObjectFile::Atom*> liveAtoms;
+
+ // mark main() and all atoms reachable from it as live
+ ObjectFile::Atom* entryPoint = this->entryPoint();
+ if ( entryPoint != NULL )
+ markLive(entryPoint, liveAtoms);
+
+ ObjectFile::Atom* dyldHelper = this->dyldHelper();
+ if ( dyldHelper != NULL )
+ markLive(dyldHelper, liveAtoms);
+
+ // mark initializers and all atoms reachable from them as live
+ // mark all exported atoms and atoms reachable from them as live
+ Section* initSection = Section::find("__mod_init_func", "__DATA", false);
+ Section* termSection = Section::find("__mod_term_func", "__DATA", false);
+ const bool globalsAreRoots = ( fOptions.outputKind() != Options::kDynamicExecutable );
+ for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
+ ObjectFile::Atom* atom = *it;
+ //fprintf(stderr,"%d %s\n", atom->dontDeadStrip(), atom->getDisplayName());
+ if ( (globalsAreRoots && (atom->getScope() == ObjectFile::Atom::scopeGlobal))
+ || (atom->getSection() == initSection) || (atom->getSection() == termSection) )
+ markLive(atom, liveAtoms);
+ }
+
+ // now remove dead strippable atoms from fAllAtoms
+ fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), DeadStrippable()), fAllAtoms.end());
+ }
+ else {
+ //printf("Stripping atoms:\n");
+ //for (std::set<ObjectFile::Atom*>::iterator it=fDeadAtoms.begin(); it != fDeadAtoms.end(); it++) {
+ // printf("\t%s\n", (*it)->getDisplayName());
+ //}
- // for now, just remove atoms weak atoms that have been overridden
- fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), InSet(fDeadAtoms)), fAllAtoms.end());
+ // if not dead stripping, just remove atoms weak atoms that have been overridden
+ fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), InSet(fDeadAtoms)), fAllAtoms.end());
+ }
}
void Linker::sortAtoms()
{
+ fStartSortTime = mach_absolute_time();
Section::assignIndexes();
std::sort(fAllAtoms.begin(), fAllAtoms.end(), Linker::AtomSorter());
//fprintf(stderr, "Sorted atoms:\n");
{
}
-void Linker::writeOutput()
+
+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<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
+ ObjectFile::Atom* atom = *it;
+ if ( atom->getFile() != fOutputFile ) {
+ const char* name = atom->getDisplayName();
+ // don't create nodes for stubs, lazy pointers or non-lazy pointers
+ const char* lastDollar = strrchr(name, '$');
+ if ( lastDollar != NULL ) {
+ if ( (strcmp(lastDollar, "$stub") == 0) || (strcmp(lastDollar, "$lazy_ptr") == 0) || (strcmp(lastDollar, "$non_lazy_ptr") == 0) )
+ continue;
+ }
+ if ( (atom->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
+ || (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
+ char temp[strlen(name)+2];
+ strcpy(temp, name);
+ temp[strlen(name)-7] = '\0'; // strip trailing "$import"
+ fprintf(out, "\t%s [ shape = plaintext ];\n", temp);
+ }
+ 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<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
+ ObjectFile::Atom* fromAtom = *it;
+ if ( fromAtom->getFile() != fOutputFile ) {
+ std::vector<ObjectFile::Reference*>& references = fromAtom->getReferences();
+ std::set<ObjectFile::Atom*> seenTargets;
+ for (std::vector<ObjectFile::Reference*>::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);
+ const char* toName = toAtom->getDisplayName();
+ const char* lastDollar = strrchr(toName, '$');
+ if ( (lastDollar != NULL) && (strcmp(lastDollar, "$stub") == 0) ) {
+ char temp[strlen(toName)+2];
+ strcpy(temp, toName);
+ temp[strlen(toName)-5] = '\0'; // strip trailing "$stub"
+ fprintf(out, "\taddr%p -> %s;\n", fromAtom, temp);
+ }
+ else if ( lastDollar != NULL && (strcmp(lastDollar, "$non_lazy_ptr") == 0) ) {
+ ObjectFile::Atom* nonLazyTargetAtom = &(toAtom->getReferences()[0]->getTarget());
+ if ( (nonLazyTargetAtom->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
+ || (nonLazyTargetAtom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
+ char temp[strlen(toName)+2];
+ strcpy(temp, toName);
+ temp[strlen(toName)-13] = '\0'; // strip trailing "$non_lazy_ptr"
+ fprintf(out, "\taddr%p -> %s;\n", fromAtom, temp);
+ }
+ else {
+ fprintf(out, "\taddr%p -> addr%p;\n", fromAtom, nonLazyTargetAtom);
+ }
+ }
+ else {
+ // don't list references from stubs, lazy pointers or non-lazy pointers
+ const char* name = fromAtom->getDisplayName();
+ const char* lastDollar = strrchr(name, '$');
+ if ( lastDollar != NULL ) {
+ if ( (strcmp(lastDollar, "$stub") == 0) || (strcmp(lastDollar, "$lazy_ptr") == 0) || (strcmp(lastDollar, "$non_lazy_ptr") == 0) )
+ continue;
+ }
+ 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<ObjectFile::Atom*>::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) ) {
+ const char* name = atom->getDisplayName();
+ char temp[strlen(name)+2];
+ strcpy(temp, name);
+ temp[strlen(name)-7] = '\0'; // strip trailing "$import"
+ fprintf(out, "%s; ", temp);
+ }
+ }
+ fprintf(out, "};\n ");
+
+ // print footer
+ fprintf(out, "}\n");
+ fclose(out);
+ }
+ else {
+ fprintf(stderr, "ld64 warning: could not write dot output file: %s\n", dotOutFilePath);
+ }
+ }
+}
+
+ObjectFile::Atom* Linker::entryPoint()
{
// if main executable, find entry point atom
ObjectFile::Atom* entryPoint = NULL;
entryPoint = NULL;
break;
}
+ return entryPoint;
+}
+
+ObjectFile::Atom* Linker::dyldHelper()
+{
+ return fGlobalSymbolTable.find("dyld_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:
+// <name> ':' <type-code> <number-pari>
+// but the <name> contain a colon.
+// For C++ <name> 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<ObjectFile::Reader::Stab>::iterator begin;
+ std::vector<ObjectFile::Reader::Stab>::iterator end;
+ int parentRangeIndex;
+ uint32_t sum;
+ bool sumPrecomputed;
+ bool useEXCL;
+ bool cannotEXCL; // because of SLINE, etc stabs
+};
+
+
+typedef __gnu_cxx::hash_map<const char*, std::vector<uint32_t>, __gnu_cxx::hash<const char*>, 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)
+{
+ bool log = false;
+ bool minimal = ( fOptions.readerOptions().fDebugInfoStripping == ObjectFile::ReaderOptions::kDebugInfoMinimal );
+ std::vector<class ObjectFile::Reader::Stab>* readerStabs = reader->getStabs();
+ if ( readerStabs == NULL )
+ return;
+
+ if ( log ) fprintf(stderr, "processesing %lu stabs for %s\n", readerStabs->size(), reader->getPath());
+ // Find all (possibly nested) BINCL/EINCL ranges and their checksums
+ std::vector<HeaderRange> ranges;
+ int curRangeIndex = -1;
+ int count = 0;
+ for(std::vector<class ObjectFile::Reader::Stab>::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 ) {
+ fprintf(stderr, "ld64 warning: EINCL missing BINCL in %s\n", 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:
+ 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() )
+ fprintf(stderr, "ld64: cannot do BINCL/EINCL optimzation because of stabs kinds in %s for %s\n", ranges[curRangeIndex].begin->string, reader->getPath());
+ }
+ break;
+ 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 )
+ fprintf(stderr, "ld64 warning: BINCL (%s) missing EINCL in %s\n", ranges[curRangeIndex].begin->string, reader->getPath());
+
+ // if no BINCLs
+ if ( ranges.size() == 0 ) {
+ if ( minimal ) {
+ // only copy minimal stabs
+ for(std::vector<ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
+ if ( minimizeStab(*it) )
+ fStabs.push_back(*it);
+ }
+ }
+ else {
+ // copy all stabs
+ fStabs.insert(fStabs.end(), readerStabs->begin(), readerStabs->end());
+ }
+ return;
+ }
+
+ //fprintf(stderr, "BINCL/EINCL info for %s\n", reader->getPath());
+ //for(std::vector<HeaderRange>::iterator it=ranges.begin(); it != ranges.end(); ++it) {
+ // fprintf(stderr, "%08X %s\n", it->sum, it->begin->string);
+ //}
- // tell writer about each segment's atoms
- fOutputFile->write(fAllAtoms, entryPoint);
+ // see if any of these BINCL/EINCL ranges have already been seen and therefore can be replaced with EXCL
+ for(std::vector<HeaderRange>::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<uint32_t>& sums = pos->second;
+ for(std::vector<uint32_t>::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<uint32_t> 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();
+ for(std::vector<ObjectFile::Reader::Stab>::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 ) {
+ if ( !minimal || minimizeStab(*it) )
+ fStabs.push_back(*it);
+ }
+ }
+ }
+
}
+void Linker::synthesizeStabs(ObjectFile::Reader* reader)
+{
+ // synthesize "debug notes" and add them to master stabs vector
+ const char* dirPath = NULL;
+ const char* filename = NULL;
+ bool wroteStartSO = false;
+ std::vector<const char*> seenFiles;
+ for (std::vector<class ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); ++it) {
+ ObjectFile::Atom* atom = *it;
+ if ( atom->getFile() == reader ) {
+ const char* name = atom->getName();
+ if ( (name != NULL) && (name[0] == '_' ) && (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) ) {
+ const char* newDirPath;
+ const char* newFilename;
+ if ( atom->getTranslationUnitSource(&newDirPath, &newFilename) ) {
+ // need SO's whenever the translation unit source file changes
+ if ( newFilename != filename ) {
+ 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 = reader->getModificationTime();
+ objStab.string = assureFullPath(reader->getPath());
+ fStabs.push_back(objStab);
+ wroteStartSO = true;
+ }
+ filename = newFilename;
+ dirPath = newDirPath;
+ seenFiles.push_back(filename);
+ 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 = name;
+ fStabs.push_back(startFun);
+ // Synthesize any SOL stabs needed
+ std::vector<ObjectFile::LineInfo>* lineInfo = atom->getLineInfo();
+ if ( lineInfo != NULL ) {
+ // might be nice to set the source file path to seenFiles so it does not show up in SOLs
+ const char* curFile = NULL;
+ for (std::vector<ObjectFile::LineInfo>::iterator it = lineInfo->begin(); it != lineInfo->end(); ++it) {
+ if ( it->fileName != curFile ) {
+ bool alreadySeen = false;
+ for (std::vector<const char*>::iterator sit = seenFiles.begin(); sit != seenFiles.end(); ++sit) {
+ if ( strcmp(it->fileName, *sit) == 0 ) {
+ alreadySeen = true;
+ break;
+ }
+ }
+ if ( ! alreadySeen ) {
+ seenFiles.push_back(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 {
+ ObjectFile::Reader::Stab globalsStab;
+ if ( atom->getScope() == ObjectFile::Atom::scopeTranslationUnit ) {
+ // Synthesize STSYM stab for statics
+ const char* name = atom->getName();
+ if ( name[0] == '_' ) {
+ 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 (but not .eh exception frame symbols)
+ const char* name = atom->getName();
+ if ( (name[0] == '_') && (strcmp(atom->getSectionName(), "__eh_frame") != 0) ) {
+ 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::collectStabs()
+{
+ if ( fOptions.readerOptions().fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone ) {
+ fStabs.reserve(1024); // try to minimize re-allocations
+ // get stabs from each reader, in command line order
+ for (std::vector<class ObjectFile::Reader*>::iterator it=fReadersThatHaveSuppliedAtoms.begin();
+ it != fReadersThatHaveSuppliedAtoms.end();
+ it++) {
+ ObjectFile::Reader* reader = *it;
+ if ( reader != NULL ) {
+ switch ( reader->getDebugInfoKind() ) {
+ case ObjectFile::Reader::kDebugInfoNone:
+ // do nothing
+ break;
+ case ObjectFile::Reader::kDebugInfoStabs:
+ collectStabs(reader);
+ break;
+ case ObjectFile::Reader::kDebugInfoDwarf:
+ synthesizeStabs(reader);
+ fCreateUUID = true;
+ break;
+ case ObjectFile::Reader::kDebugInfoStabsUUID:
+ collectStabs(reader);
+ fCreateUUID = true;
+ break;
+ default:
+ throw "Unhandled type of debug information";
+ }
+ }
+ }
+ // remove stabs associated with atoms that won't be in output
+ std::set<class ObjectFile::Atom*> allAtomsSet;
+ allAtomsSet.insert(fAllAtoms.begin(), fAllAtoms.end());
+ fStabs.erase(std::remove_if(fStabs.begin(), fStabs.end(), NotInSet(allAtomsSet)), fStabs.end());
+ }
+}
+void Linker::writeOutput()
+{
+ fStartWriteTime = mach_absolute_time();
+ // tell writer about each segment's atoms
+ fOutputFileSize = fOutputFile->write(fAllAtoms, fStabs, this->entryPoint(), this->dyldHelper(), (fCreateUUID && fOptions.emitUUID()));
+}
ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
{
throwf("can't open file, errno=%d", errno);
if ( info.fileLen < 20 )
throw "file too small";
-
- char* p = (char*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
- if ( p == (char*)(-1) )
+
+ 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);
- ::close(fd);
-
+
// if fat file, skip to architecture we want
- const mach_header* mh = (mach_header*)p;
- if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+ const fat_header* fh = (fat_header*)p;
+ if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
// Fat header is always big-endian
- 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)fOptions.architecture() ) {
- mh = (struct mach_header*)((char*)p + OSSwapBigToHostInt32(archs[i].offset));
+ if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)fArchitecture ) {
+ uint32_t fileOffset = OSSwapBigToHostInt32(archs[i].offset);
len = OSSwapBigToHostInt32(archs[i].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];
+ }
break;
}
}
}
-
- if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+ ::close(fd);
+
+ switch (fArchitecture) {
+ case CPU_TYPE_POWERPC:
+ if ( mach_o::relocatable::Reader<ppc>::validFile(p) )
+ return this->addObject(mach_o::relocatable::Reader<ppc>::make(p, info.path, info.modTime, fOptions.readerOptions()), info, len);
+ else if ( mach_o::dylib::Reader<ppc>::validFile(p) )
+ return this->addDylib(mach_o::dylib::Reader<ppc>::make(p, len, info.path, fOptions.readerOptions()), info, len);
+ else if ( mach_o::archive::Reader<ppc>::validFile(p, len) )
+ return this->addArchive(mach_o::archive::Reader<ppc>::make(p, len, info.path, info.modTime, fOptions.readerOptions()), info, len);
+ break;
+ case CPU_TYPE_POWERPC64:
+ if ( mach_o::relocatable::Reader<ppc64>::validFile(p) )
+ return this->addObject(mach_o::relocatable::Reader<ppc64>::make(p, info.path, info.modTime, fOptions.readerOptions()), info, len);
+ else if ( mach_o::dylib::Reader<ppc64>::validFile(p) )
+ return this->addDylib(mach_o::dylib::Reader<ppc64>::make(p, len, info.path, fOptions.readerOptions()), info, len);
+ else if ( mach_o::archive::Reader<ppc64>::validFile(p, len) )
+ return this->addArchive(mach_o::archive::Reader<ppc64>::make(p, len, info.path, info.modTime, fOptions.readerOptions()), info, len);
+ break;
+ case CPU_TYPE_I386:
+ if ( mach_o::relocatable::Reader<x86>::validFile(p) )
+ return this->addObject(mach_o::relocatable::Reader<x86>::make(p, info.path, info.modTime, fOptions.readerOptions()), info, len);
+ else if ( mach_o::dylib::Reader<x86>::validFile(p) )
+ return this->addDylib(mach_o::dylib::Reader<x86>::make(p, len, info.path, fOptions.readerOptions()), info, len);
+ else if ( mach_o::archive::Reader<x86>::validFile(p, len) )
+ return this->addArchive(mach_o::archive::Reader<x86>::make(p, len, info.path, info.modTime, fOptions.readerOptions()), info, len);
+ break;
+ }
+
+ // error handling
+ if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
const char* archName = "unknown";
- switch (fOptions.architecture()) {
+ switch (fArchitecture) {
case CPU_TYPE_POWERPC:
archName = "ppc";
break;
}
throwf("missing required architecture %s in fat file", archName);
}
-
- // pull out cpu-type and file-type in endian-safe way
- cpu_type_t cpuType = 0;
- uint32_t fileType = 0;
- if ( mh->magic == MH_MAGIC ) {
- fileType = mh->filetype;
- cpuType = mh->cputype;
- }
- else if ( mh->magic == OSSwapInt32(MH_MAGIC) ) {
- fileType = OSSwapInt32(mh->filetype);
- cpuType = OSSwapInt32(mh->cputype);
- }
- else if ( mh->magic == MH_MAGIC_64 ) {
- fileType = ((mach_header_64*)mh)->filetype;
- cpuType = ((mach_header_64*)mh)->cputype;
- }
- else if ( mh->magic == OSSwapInt32(MH_MAGIC_64) ) {
- fileType = OSSwapInt32(((mach_header_64*)mh)->filetype);
- cpuType = OSSwapInt32(((mach_header_64*)mh)->cputype);
- }
- else if ( strncmp((const char*)mh, "!<arch>\n", 8) == 0 ) {
- // is static archive
- switch ( fOptions.architecture() ) {
- case CPU_TYPE_POWERPC:
- return ppc::ObjectFileArchiveMachO::MakeReader((const uint8_t*)mh, len, info.path, fOptions.readerOptions());
- case CPU_TYPE_POWERPC64:
- return ppc64::ObjectFileArchiveMachO::MakeReader((const uint8_t*)mh, len, info.path, fOptions.readerOptions());
- case CPU_TYPE_I386:
- return i386::ObjectFileArchiveMachO::MakeReader((const uint8_t*)mh, len, info.path, fOptions.readerOptions());
- }
- throw "no matching archive reader";
- }
else {
- throw "unknown file type";
- }
-
- // bail out if cpu-type does not match requrired architecture
- if ( fOptions.architecture() == cpuType ) {
- // make appropriate reader object
- if ( fileType == MH_OBJECT ) {
- switch ( cpuType ) {
- case CPU_TYPE_POWERPC:
- return ppc::ObjectFileMachO::MakeReader((class ppc::macho_header*)mh, info.path, fOptions.readerOptions());
- case CPU_TYPE_POWERPC64:
- return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, info.path, fOptions.readerOptions());
- case CPU_TYPE_I386:
- return i386::ObjectFileMachO::MakeReader((class i386::macho_header*)mh, info.path, fOptions.readerOptions());
- default:
- throw "wrong architecture in object file";
- }
- }
- else if ( (fileType == MH_DYLIB) || (fileType == MH_DYLIB_STUB) ) {
- ObjectFile::Reader* dylibReader = NULL;
- switch ( cpuType ) {
- case CPU_TYPE_POWERPC:
- dylibReader = ppc::ObjectFileDylibMachO::MakeReader((class ppc::macho_header*)mh, info.path, fOptions.readerOptions());
- break;
- case CPU_TYPE_POWERPC64:
- dylibReader = ppc64::ObjectFileDylibMachO::MakeReader((class ppc64::macho_header*)mh, info.path, fOptions.readerOptions());
- break;
- case CPU_TYPE_I386:
- dylibReader = i386::ObjectFileDylibMachO::MakeReader((class i386::macho_header*)mh, info.path, fOptions.readerOptions());
- break;
- default:
- throw "wrong architecture in dylib";
- }
- this->addDylib(dylibReader, info);
- return dylibReader;
- }
- throw "unknown mach-o file type";
+ throw "file is not of required architecture";
}
- else {
- throw "file does not contain requested architecture";
- }
-
}
void Linker::createReaders()
{
+ fStartCreateReadersTime = mach_absolute_time();
std::vector<Options::FileInfo>& files = fOptions.getInputFiles();
const int count = files.size();
if ( count == 0 )
}
}
}
-
+
// add first level of indirect dylibs
fDirectLibrariesComplete = true;
for (std::vector<ExecutableFile::DyLibUsed>::iterator it=fDynamicLibraries.begin(); it != fDynamicLibraries.end(); it++) {
this->addIndirectLibraries(it->reader);
}
-
+
// indirect handling depends on namespace
switch ( fOptions.nameSpace() ) {
case Options::kFlatNameSpace:
for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
try {
it->reader = this->createReader(fOptions.findFile(it->path));
+ it->reader->setSortOrder(fNextObjectFileOrder++);
}
catch (const char* msg) {
fprintf(stderr, "ld64 warning: indirect library %s could not be loaded: %s\n", it->path, msg);
}
}
break;
-
+
case Options::kTwoLevelNameSpace:
// with two-level namespace we only want to use indirect libraries that are re-exported through a library that is used
{
if ( it->reader == NULL ) {
try {
it->reader = this->createReader(fOptions.findFile(it->path));
+ it->reader->setSortOrder(fNextObjectFileOrder++);
indirectAdded = true;
}
catch (const char* msg) {
}
}
// if an indirect library does not have an assigned parent, look for one
- if ( (it->reader != NULL) && (it->reExportParent == NULL) ) {
- // ask each parent if they re-export this dylib
- for (std::set<ObjectFile::Reader*>::iterator pit=it->parents.begin(); pit != it->parents.end(); pit++) {
- if ( (*pit)->reExports(it->reader) ) {
- it->reExportParent = *pit;
- break;
- }
- }
+ if ( (it->reader != NULL) && (it->reExportedViaDirectLibrary == NULL) ) {
+ it->reExportedViaDirectLibrary = this->findDirectLibraryWhichReExports(*it);
}
}
}
}
break;
}
-
+
// add relevant indirect libraries to the end of fDynamicLibraries
for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
- if ( (it->reExportParent != NULL) || (fOptions.nameSpace() != Options::kTwoLevelNameSpace) ) {
+ if ( (it->reader != NULL) && (it->reExportedViaDirectLibrary != NULL) || (fOptions.nameSpace() != Options::kTwoLevelNameSpace) ) {
ExecutableFile::DyLibUsed dylibInfo;
dylibInfo.reader = it->reader;
dylibInfo.options.fWeakImport = false;
dylibInfo.options.fReExport = false;
dylibInfo.options.fInstallPathOverride = NULL;
dylibInfo.indirect = true;
- dylibInfo.directReader = it->reExportParent;
+ dylibInfo.directReader = it->reExportedViaDirectLibrary;
fDynamicLibraries.push_back(dylibInfo);
- if ( fOptions.readerOptions().fTraceIndirectDylibs )
- printf("[Logging for Build & Integration] Used indirect dynamic library: %s\n", it->reader->getPath());
+ if ( fOptions.readerOptions().fTraceIndirectDylibs ) {
+ const char* fullPath = it->reader->getPath();
+ char realName[MAXPATHLEN];
+ if ( realpath(fullPath, realName) != NULL )
+ fullPath = realName;
+ logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath);
+ }
+ }
+ }
+}
+
+
+ObjectFile::Reader* Linker::findDirectLibraryWhichReExports(IndirectLibrary& indirectLib)
+{
+ // ask each parent if they re-export this dylib
+ for (std::set<ObjectFile::Reader*>::iterator pit=indirectLib.parents.begin(); pit != indirectLib.parents.end(); pit++) {
+ if ( (*pit)->reExports(indirectLib.reader) ) {
+ ObjectFile::Reader* lib = *pit;
+ // first check if we found a direct library, if so return it
+ for (std::vector<ExecutableFile::DyLibUsed>::iterator dit=fDynamicLibraries.begin(); dit != fDynamicLibraries.end(); dit++) {
+ if ( dit->reader == lib && dit->indirect == false )
+ return lib;
+ }
+ // otherwise search indirects for parent and see how it is reexported
+ for (std::list<IndirectLibrary>::iterator iit=fIndirectDynamicLibraries.begin(); iit != fIndirectDynamicLibraries.end(); iit++) {
+ if ( iit->reader == lib ) {
+ ObjectFile::Reader* lib2 = this->findDirectLibraryWhichReExports(*iit);
+ if ( lib2 != NULL )
+ return lib2;
+ }
+ }
}
}
+ return NULL;
}
-void Linker::addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info)
+ObjectFile::Reader* Linker::addArchive(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
{
+ if (fOptions.readerOptions().fTraceArchives) {
+ 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);
+ }
+
+ // update stats
+ fTotalArchiveSize += mappedLen;
+ ++fTotalArchivesLoaded;
+ return reader;
+}
+
+ObjectFile::Reader* Linker::addObject(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
+{
+ // update stats
+ fTotalObjectSize += mappedLen;
+ ++fTotalObjectLoaded;
+ return reader;
+}
+
+ObjectFile::Reader* Linker::addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
+{
+ if ( reader->getInstallPath() == NULL ) {
+ // this is a "blank" stub
+ // silently ignore it
+ return reader;
+ }
+
if ( fDirectLibrariesComplete ) {
this->addIndirectLibraries(reader);
}
else {
- if ( fOptions.readerOptions().fTraceDylibs )
- printf("[Logging for Build & Integration] Used dynamic library: %s\n", reader->getPath());
+ if ( fOptions.readerOptions().fTraceDylibs ) {
+ const char* fullPath = reader->getPath();
+ char realName[MAXPATHLEN];
+ if ( realpath(fullPath, realName) != NULL )
+ fullPath = realName;
+ logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath);
+ }
ExecutableFile::DyLibUsed dylibInfo;
dylibInfo.reader = reader;
dylibInfo.options = info.options;
dylibInfo.indirect = false;
dylibInfo.directReader = NULL;
fDynamicLibraries.push_back(dylibInfo);
+
+
+ // Verify that a client is allowed to link to this dylib. There are three cases.
+ bool okToLink = true;
+ const char* outputFilePath = fOptions.installPath();
+ const char* outputFilePathLastSlash = strrchr(outputFilePath, '/');
+ if ( reader->parentUmbrella() != NULL ) {
+ // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella
+ okToLink = ( (outputFilePathLastSlash != NULL) && (strcmp(&outputFilePathLastSlash[1], reader->parentUmbrella()) == 0) );
+ }
+
+ if ( !okToLink && (reader->parentUmbrella() != NULL) ) {
+ // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent
+ okToLink = ( (outputFilePathLastSlash != NULL)
+ && (fOptions.umbrellaName() != NULL)
+ && (strcmp(fOptions.umbrellaName(), reader->parentUmbrella()) == 0) );
+ }
+
+ std::vector<const char*>* clients = reader->getAllowableClients();
+ if ( !okToLink && (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.A.dylib --> foo, Bar.framework/Bar --> Bar)
+ clientName = outputFilePath;
+ // starts after last slash
+ if ( outputFilePathLastSlash != NULL )
+ clientName = &outputFilePathLastSlash[1];
+ if ( strncmp(clientName, "lib", 3) == 0 )
+ clientName = &clientName[3];
+ // up to first dot
+ const char* firstDot = strchr(clientName, '.');
+ if ( firstDot == NULL )
+ clientNameLen = strlen(clientName);
+ else
+ clientNameLen = firstDot - clientName;
+ }
+
+ // Use clientName to check if this dylib is able to link against the allowable clients.
+ for (std::vector<const char*>::iterator it = clients->begin(); it != clients->end(); it++) {
+ if ( strncmp(*it, clientName, clientNameLen) == 0 )
+ okToLink = true;
+ }
+ }
+
+ // error out if we are not allowed to link
+ if ( ! okToLink )
+ //throwf("'%s' is a subframework. Link against the umbrella framework '%s.framework' instead.",
+ fprintf(stderr, "'%s' is a subframework. Link against the umbrella framework '%s.framework' instead.",
+ reader->getPath(), reader->parentUmbrella());
}
+
+ // update stats
+ ++fTotalDylibsLoaded;
+
+ return reader;
}
indirectLib.fileLen = 0;
indirectLib.reader = NULL;
indirectLib.parents.insert(reader);
- indirectLib.reExportParent = NULL;
+ indirectLib.reExportedViaDirectLibrary = NULL;
fIndirectDynamicLibraries.push_back(indirectLib);
//fprintf(stderr, "add indirect library: %s\n", *it);
}
return false;
}
+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\n", 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();
const char* path = fOptions.getOutputFilePath();
- switch ( fOptions.architecture() ) {
+ switch ( fArchitecture ) {
case CPU_TYPE_POWERPC:
- this->setOutputFile(ppc::ExecutableFileMachO::MakeWriter(path, fOptions, fDynamicLibraries));
+ this->setOutputFile(new mach_o::executable::Writer<ppc>(path, fOptions, fDynamicLibraries));
break;
case CPU_TYPE_POWERPC64:
- this->setOutputFile(ppc64::ExecutableFileMachO::MakeWriter(path, fOptions, fDynamicLibraries));
+ this->setOutputFile(new mach_o::executable::Writer<ppc64>(path, fOptions, fDynamicLibraries));
break;
case CPU_TYPE_I386:
- this->setOutputFile(i386::ExecutableFileMachO::MakeWriter(path, fOptions, fDynamicLibraries));
+ this->setOutputFile(new mach_o::executable::Writer<x86>(path, fOptions, fDynamicLibraries));
break;
default:
throw "unknown architecture";
}
}
-bool Linker::SymbolTable::add(ObjectFile::Atom& atom)
+// convenience labels for 2-dimensional switch statement
+enum {
+ 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,
+ 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,
+ 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,
+ 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,
+ 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
+};
+
+bool Linker::SymbolTable::add(ObjectFile::Atom& newAtom)
{
- const bool log = false;
- const char* name = atom.getName();
- //fprintf(stderr, "map.add(%p: %s => %p)\n", &fTable, name, &atom);
+ bool useNew = true;
+ const char* name = newAtom.getName();
+ //fprintf(stderr, "map.add(%s => %p from %s)\n", name, &newAtom, newAtom.getFile()->getPath());
Mapper::iterator pos = fTable.find(name);
- if ( pos != fTable.end() ) {
- ObjectFile::Atom* existingAtom = pos->second;
- if ( existingAtom != NULL ) {
- if ( existingAtom->isTentativeDefinition() ) {
- if ( atom.isTentativeDefinition() ) {
- if ( atom.getSize() > existingAtom->getSize() ) {
- // replace common-symbol atom with another larger common-symbol
- if ( fOwner.fOptions.warnCommons() )
- fprintf(stderr, "ld64: replacing common symbol %s size %lld from %s with larger symbol size %lld from %s\n",
- existingAtom->getName(), existingAtom->getSize(), existingAtom->getFile()->getPath(), atom.getSize(), atom.getFile()->getPath());
- fOwner.fDeadAtoms.insert(existingAtom);
- fTable[name] = &atom;
- return true;
- }
- else {
- // keep existing common-symbol atom
- if ( fOwner.fOptions.warnCommons() ) {
- if ( atom.getSize() == existingAtom->getSize() )
- fprintf(stderr, "ld64: ignoring common symbol %s from %s because already have common from %s with same size\n",
- atom.getName(), atom.getFile()->getPath(), existingAtom->getFile()->getPath());
- else
- fprintf(stderr, "ld64: ignoring common symbol %s size %lld from %s because already have larger symbol size %lld from %s\n",
- atom.getName(), atom.getSize(), atom.getFile()->getPath(), existingAtom->getSize(), existingAtom->getFile()->getPath());
- }
- fOwner.fDeadAtoms.insert(&atom);
- return false;
- }
+ ObjectFile::Atom* existingAtom = NULL;
+ if ( pos != fTable.end() )
+ existingAtom = pos->second;
+ if ( existingAtom != NULL ) {
+ // already have atom with same name in symbol table
+ switch ( (existingAtom->getDefinitionKind() << 3) | newAtom.getDefinitionKind() ) {
+ case kRegAndReg:
+ throwf("duplicate symbol %s in %s and %s\n", 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;
+ 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 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() > existingAtom->getAlignment() );
+ 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 kTentAndReg:
+ // replace existing tentative atom with regular one
+ break;
+ case kTentAndWeak:
+ // replace existing tentative atom with weak one ???
+ break;
+ case kTentAndTent:
+ // use largest
+ if ( newAtom.getSize() < existingAtom->getSize() ) {
+ useNew = false;
}
- else {
- // have common symbol, now found true defintion
- if ( atom.isImportProxy() ) {
- // definition is in a dylib, so commons-mode decides how to handle
- switch ( fOwner.fOptions.commonsMode() ) {
- case Options::kCommonsIgnoreDylibs:
- if ( fOwner.fOptions.warnCommons() )
- fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
- existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
- fOwner.fDeadAtoms.insert(&atom);
- return false;
- case Options::kCommonsOverriddenByDylibs:
- if ( fOwner.fOptions.warnCommons() )
- fprintf(stderr, "ld64: replacing common symbol %s from %s with true definition from %s\n",
- existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
- fOwner.fDeadAtoms.insert(existingAtom);
- fTable[name] = &atom;
- return true;
- case Options::kCommonsConflictsDylibsError:
- throwf("common symbol %s from %s conflicts with defintion from dylib %s",
- existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
- }
- }
- else {
- // replace common-symbol atom with true definition from .o file
- if ( fOwner.fOptions.warnCommons() ) {
- if ( atom.getSize() < existingAtom->getSize() )
- fprintf(stderr, "ld64: warning: replacing common symbol %s size %lld from %s with smaller true definition size %lld from %s\n",
- existingAtom->getName(), existingAtom->getSize(), existingAtom->getFile()->getPath(), atom.getSize(), atom.getFile()->getPath());
- else
- fprintf(stderr, "ld64: replacing common symbol %s from %s with true definition from %s\n",
- existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
- }
- fOwner.fDeadAtoms.insert(existingAtom);
- fTable[name] = &atom;
- return true;
- }
+ 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() )
+ fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
+ existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
+ useNew = false;
+ break;
+ case Options::kCommonsOverriddenByDylibs:
+ if ( fOwner.fOptions.warnCommons() )
+ fprintf(stderr, "ld64: replacing common symbol %s from %s with true definition from dylib %s\n",
+ 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());
}
- }
- else if ( atom.isTentativeDefinition() ) {
- // keep existing true definition, ignore new tentative definition
- if ( fOwner.fOptions.warnCommons() ) {
- if ( atom.getSize() > existingAtom->getSize() )
- fprintf(stderr, "ld64: warning: ignoring common symbol %s size %lld from %s because already have definition from %s size %lld, even though definition is smaller\n",
- atom.getName(), atom.getSize(), atom.getFile()->getPath(), existingAtom->getFile()->getPath(), existingAtom->getSize());
- else
- fprintf(stderr, "ld64: ignoring common symbol %s from %s because already have definition from %s\n",
- atom.getName(), atom.getFile()->getPath(), existingAtom->getFile()->getPath());
+ 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() )
+ fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
+ newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
+ break;
+ case Options::kCommonsOverriddenByDylibs:
+ if ( fOwner.fOptions.warnCommons() )
+ fprintf(stderr, "ld64: replacing defintion of %s from dylib %s with common symbol from %s\n",
+ 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());
}
- fOwner.fDeadAtoms.insert(&atom);
- return false;
- }
- else {
- // neither existing nor new atom are tentative definitions
- // if existing is weak, we may replace it
- if ( existingAtom->isWeakDefinition() ) {
- if ( atom.isImportProxy() ) {
- // keep weak definition even though one exists in a dylib, because coalescing means dylib's copy may not be used
- if ( log ) fprintf(stderr, "keep weak atom even though also in a dylib: %s\n", atom.getName());
- fOwner.fDeadAtoms.insert(&atom);
- return false;
- }
- else if ( atom.isWeakDefinition() ) {
- // have another weak atom, use existing, mark new as dead
- if ( log ) fprintf(stderr, "already have weak atom: %s\n", atom.getName());
- fOwner.fDeadAtoms.insert(&atom);
- return false;
- }
- else {
- // replace weak atom with non-weak atom
- if ( log ) fprintf(stderr, "replacing weak atom %p from %s with %p from %s: %s\n", existingAtom, existingAtom->getFile()->getPath(), &atom, atom.getFile()->getPath(), atom.getName());
- fOwner.fDeadAtoms.insert(existingAtom);
- fTable[name] = &atom;
- return true;
- }
+ 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 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() )
+ fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
+ newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
+ break;
+ case Options::kCommonsOverriddenByDylibs:
+ if ( fOwner.fOptions.warnCommons() )
+ fprintf(stderr, "ld64: replacing defintion of %s from dylib %s with common symbol from %s\n",
+ 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());
}
- }
- if ( atom.isWeakDefinition() ) {
- // ignore new weak atom, because we already have a non-weak one
- return false;
- }
- if ( atom.isCoalesableByName() && existingAtom->isCoalesableByName() ) {
- // both coalesable, so ignore duplicate
- return false;
- }
- fprintf(stderr, "duplicate symbol %s in %s and %s\n", name, atom.getFile()->getPath(), existingAtom->getFile()->getPath());
+ break;
+ case kExternWeakAndExtern:
+ // replace existing weak external with external
+ break;
+ case kExternWeakAndExternWeak:
+ // keep existing external weak
+ useNew = false;
+ break;
}
}
- fTable[name] = &atom;
- return true;
+ if ( useNew ) {
+ fTable[name] = &newAtom;
+ if ( existingAtom != NULL )
+ fOwner.fDeadAtoms.insert(existingAtom);
+ }
+ else {
+ fOwner.fDeadAtoms.insert(&newAtom);
+ }
+ return useNew;
}
+
+
ObjectFile::Atom* Linker::SymbolTable::find(const char* name)
{
Mapper::iterator pos = fTable.find(name);
void Linker::SymbolTable::getNeededNames(bool andWeakDefintions, std::vector<const char*>& undefines)
{
for (Mapper::iterator it=fTable.begin(); it != fTable.end(); it++) {
- if ( (it->second == NULL) || (andWeakDefintions && it->second->isWeakDefinition()) ) {
+ if ( (it->second == NULL) || (andWeakDefintions && (it->second->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition)) ) {
undefines.push_back(it->first);
}
}
unsigned int rightSectionIndex = right->getSection()->getIndex();
if ( leftSectionIndex != rightSectionIndex)
return (leftSectionIndex < rightSectionIndex);
-
- // with a section, sort by original atom order (.o file order and atom order in .o files)
+
+ // then sort by .o file order
+ ObjectFile::Reader* leftReader = left->getFile();
+ ObjectFile::Reader* rightReader = right->getFile();
+ if ( leftReader != rightReader )
+ return leftReader->getSortOrder() < rightReader->getSortOrder();
+
+ // lastly sort by atom within a .o file
return left->getSortOrder() < right->getSortOrder();
}
try {
// create linker object given command line arguments
Linker ld(argc, argv);
-
+
// open all input files
ld.createReaders();
-
+
// open output file
ld.createWriter();
-
+
// do linking
ld.link();
}
fprintf(stderr, "ld64 failed: %s\n", msg);
return 1;
}
-
- return 0;
-}
-
-
-
-
-
+ return 0;
+}
--- /dev/null
+/* -*- 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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+#include <mach-o/stab.h>
+
+#include <vector>
+
+#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 <typename A>
+class MachOChecker
+{
+public:
+ static bool validFile(const uint8_t* fileContent);
+ static MachOChecker<A>* make(const uint8_t* fileContent, uint32_t fileLength, const char* path)
+ { return new MachOChecker<A>(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;
+
+ MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path);
+ void checkMachHeader();
+ void checkLoadCommands();
+ void checkSection(const macho_segment_command<P>* segCmd, const macho_section<P>* sect);
+ uint8_t loadCommandSizeMask();
+ void checkIndirectSymbolTable();
+
+ const char* fPath;
+ const macho_header<P>* fHeader;
+ uint32_t fLength;
+ const char* fStrings;
+ const char* fStringsEnd;
+ const macho_nlist<P>* fSymbols;
+ uint32_t fSymbolCount;
+ const uint32_t* fIndirectTable;
+ uint32_t fIndirectTableCount;
+
+};
+
+
+
+template <>
+bool MachOChecker<ppc>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_POWERPC )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ return true;
+ }
+ return false;
+}
+
+template <>
+bool MachOChecker<ppc64>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_POWERPC64 )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ return true;
+ }
+ return false;
+}
+
+template <>
+bool MachOChecker<x86>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_I386 )
+ 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<ppc>::loadCommandSizeMask() { return 0x03; }
+template <> uint8_t MachOChecker<ppc64>::loadCommandSizeMask() { return 0x07; }
+template <> uint8_t MachOChecker<x86>::loadCommandSizeMask() { return 0x03; }
+
+
+template <typename A>
+MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path)
+ : fHeader(NULL), fLength(fileLength), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fIndirectTableCount(0)
+{
+ // sanity check
+ if ( ! validFile(fileContent) )
+ throw "not a mach-o file that can be checked";
+
+ fPath = strdup(path);
+ fHeader = (const macho_header<P>*)fileContent;
+
+ // sanity check header
+ checkMachHeader();
+
+ // check load commands
+ checkLoadCommands();
+
+ checkIndirectSymbolTable();
+
+}
+
+
+template <typename A>
+void MachOChecker<A>::checkMachHeader()
+{
+ if ( (fHeader->sizeofcmds() + sizeof(macho_header<P>)) > fLength )
+ throw "sizeofcmds in mach_header is larger than file";
+
+ uint32_t flags = fHeader->flags();
+ uint32_t invalidBits = MH_INCRLINK | MH_LAZY_INIT | 0xFFFC0000;
+ if ( flags & invalidBits )
+ throw "invalid bits in mach_header flags";
+
+}
+
+template <typename A>
+void MachOChecker<A>::checkLoadCommands()
+{
+ // check that all load commands fit within the load command space file
+ const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
+ const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const macho_load_command<P>* 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<P>::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<P>::CMD:
+ case LC_SUB_FRAMEWORK:
+ case LC_SUB_UMBRELLA:
+ case LC_SUB_CLIENT:
+ case LC_TWOLEVEL_HINTS:
+ case LC_PREBIND_CKSUM:
+ case LC_LOAD_WEAK_DYLIB:
+ case LC_UUID:
+ break;
+ default:
+ throwf("load command #%d is an unknown kind 0x%X", i, cmd->cmd());
+ }
+ cmd = (const macho_load_command<P>*)endOfCmd;
+ }
+
+ // check segments
+ cmd = cmds;
+ std::vector<std::pair<pint_t, pint_t> > segmentAddressRanges;
+ std::vector<std::pair<pint_t, pint_t> > segmentFileOffsetRanges;
+ const macho_segment_command<P>* linkEditSegment = NULL;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+ if ( segCmd->cmdsize() != (sizeof(macho_segment_command<P>) + segCmd->nsects() * sizeof(macho_section_content<P>)) )
+ 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<std::pair<pint_t, pint_t> >::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<pint_t, pint_t>(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<std::pair<pint_t, pint_t> >::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<pint_t, pint_t>(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;
+
+ // check section ranges
+ const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+ const macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()];
+ for(const macho_section<P>* 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 ) {
+ 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<P>*)(((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<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+ if ( isStaticExecutable ) {
+ if ( fHeader->flags() != MH_NOUNDEFS )
+ throw "invalid bits in mach_header flags for static executable";
+ }
+ }
+
+ // check LC_SYMTAB and LC_DYSYMTAB
+ cmd = cmds;
+ bool foundDynamicSymTab = false;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch ( cmd->cmd() ) {
+ case LC_SYMTAB:
+ {
+ const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
+ fSymbolCount = symtab->nsyms();
+ fSymbols = (const macho_nlist<P>*)((char*)fHeader + symtab->symoff());
+ if ( symtab->symoff() < linkEditSegment->fileoff() )
+ throw "symbol table not in __LINKEDIT";
+ if ( (symtab->symoff() + fSymbolCount*sizeof(macho_nlist<P>*)) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+ throw "symbol table end not in __LINKEDIT";
+ 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";
+ }
+ break;
+ case LC_DYSYMTAB:
+ {
+ if ( isStaticExecutable )
+ throw "LC_DYSYMTAB should not be used in static executable";
+ foundDynamicSymTab = true;
+ const macho_dysymtab_command<P>* dsymtab = (struct macho_dysymtab_command<P>*)cmd;
+ fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
+ fIndirectTableCount = dsymtab->nindirectsyms();
+ if ( dsymtab->indirectsymoff() < linkEditSegment->fileoff() )
+ throw "indirect symbol table not in __LINKEDIT";
+ if ( (dsymtab->indirectsymoff()+fIndirectTableCount*8) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+ throw "indirect symbol table not in __LINKEDIT";
+ }
+ break;
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+ if ( !isStaticExecutable && !foundDynamicSymTab )
+ throw "missing dynamic symbol table";
+ if ( fStrings == NULL )
+ throw "missing symbol table";
+
+
+
+}
+
+template <typename A>
+void MachOChecker<A>::checkSection(const macho_segment_command<P>* segCmd, const macho_section<P>* 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 <typename A>
+void MachOChecker<A>::checkIndirectSymbolTable()
+{
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+ const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+ const macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()];
+ for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+ // make sure all magic sections that use indirect symbol table fit within it
+ uint32_t 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<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+}
+
+
+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, 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 < fh->nfat_arch; ++i) {
+ if ( archs[i].cputype == CPU_TYPE_POWERPC ) {
+ if ( MachOChecker<ppc>::validFile(p + archs[i].offset) )
+ MachOChecker<ppc>::make(p + archs[i].offset, archs[i].size, path);
+ else
+ throw "in universal file, ppc slice does not contain ppc mach-o";
+ }
+ else if ( archs[i].cputype == CPU_TYPE_I386 ) {
+ if ( MachOChecker<x86>::validFile(p + archs[i].offset) )
+ MachOChecker<x86>::make(p + archs[i].offset, archs[i].size, path);
+ else
+ throw "in universal file, i386 slice does not contain i386 mach-o";
+ }
+ else if ( archs[i].cputype == CPU_TYPE_POWERPC64 ) {
+ if ( MachOChecker<ppc64>::validFile(p + archs[i].offset) )
+ MachOChecker<ppc64>::make(p + archs[i].offset, archs[i].size, path);
+ else
+ throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
+ }
+ else {
+ throw "in universal file, unknown architecture slice";
+ }
+ }
+ }
+ else if ( MachOChecker<x86>::validFile(p) ) {
+ MachOChecker<x86>::make(p, length, path);
+ }
+ else if ( MachOChecker<ppc>::validFile(p) ) {
+ MachOChecker<ppc>::make(p, length, path);
+ }
+ else if ( MachOChecker<ppc64>::validFile(p) ) {
+ MachOChecker<ppc64>::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;
+}
+
+
+
--- /dev/null
+
+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
+
+
+
+
--- /dev/null
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+# ${PASS_UNLESS} "test name" command
+#
+
+use strict;
+
+my $string = shift @ARGV;
+
+if(0 == system(@ARGV))
+{
+ printf("FAIL $string\n");
+}
+else
+{
+ printf("PASS $string\n");
+}
+exit 0;
+
--- /dev/null
+#!/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;
+}
+else
+{
+ exit 0;
+}
+
+
+
--- /dev/null
+#!/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;
+}
+else
+{
+ exit 0;
+}
--- /dev/null
+#!/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 0;
--- /dev/null
+#!/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 )
+{
+
+}
+else
+{
+ printf("FAIL $test_name\n");
+}
+exit 0;
--- /dev/null
+#!/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};
+}
+
+if(0 == system(@ARGV))
+{
+ printf("FAIL $test_name\n");
+}
+else
+{
+ printf("PASS $test_name\n");
+}
+exit 0;
+
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+use Data::Dumper;
+use File::Find;
+use Cwd qw(realpath);
+
+my @args = @ARGV;
+
+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, "</tmp/unit-tests-stdout") || die("$!");
+ while(<OUT>)
+ {
+ &print_line("stdout", "$_");
+ }
+ close(OUT) || die("$!");
+ unlink("/tmp/unit-tests-stdout");
+
+ open(ERR, "</tmp/unit-tests-stderr") || die("$!");
+ while(<ERR>)
+ {
+ &print_line("stderr", "$_");
+ }
+ close(ERR) || die("$!");
+ }
+ unlink("/tmp/unit-tests-stderr");
+}
--- /dev/null
+#!/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("PASS $test_name\n");
+}
+else
+{
+ printf("FAIL $test_name\n");
+}
+exit 0;
+
--- /dev/null
+#!/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");
+}
+else
+{
+ printf("FAIL $test_name\n");
+}
+exit 0;
+
--- /dev/null
+#!/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");
+}
+else
+{
+ printf("PASS $test_name\n");
+}
+exit 0;
+
--- /dev/null
+#!/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).+/)
+ {
+ printf "%-40s %s\n", $test_name, $line;
+ $total_count++;
+ if($line =~ m/^PASS.+/)
+ {
+ $pass_count++;
+ }
+ $seen_result = 1;
+ }
+ }
+ if(!$seen_result)
+ {
+ printf "%-40s AMBIGIOUS missing [X]PASS/[X]FAIL\n", $test_name;
+ $total_count++;
+ }
+}
--- /dev/null
+# 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"
+
+# if run within Xcode, add the just built tools to the command path
+ifdef BUILT_PRODUCTS_DIR
+ PATH := ${BUILT_PRODUCTS_DIR}:${PATH}
+endif
+
+LD = ld
+OBJECTDUMP = ObjectDump
+MACHOCHECK = machocheck
+
+OTOOL = otool
+ifeq (${ARCH},ppc64)
+OTOOL = otool64
+endif
+
+
+CC = gcc-4.0 -arch ${ARCH}
+CCFLAGS = -Wall -g -std=c99
+ASMFLAGS =
+
+CXX = g++-4.0 -arch ${ARCH}
+CXXFLAGS = -Wall -g
+
+RM = rm
+RMFLAGS = -rf
+
+# utilites for Makefiles
+PASS_IFF = ${TESTROOT}/bin/pass-iff-exit-zero.pl
+PASS_IFF_EMPTY = ${TESTROOT}/bin/pass-iff-no-stdin.pl
+PASS_IFF_STDIN = ${TESTROOT}/bin/pass-iff-stdin.pl
+PASS_IFF_GOOD_MACHO = ${TESTROOT}/bin/pass-iff-exit-zero.pl ${MACHOCHECK}
+FAIL_IFF = ${TESTROOT}/bin/fail-iff-exit-zero.pl
+FAIL_IF_BAD_MACHO = ${TESTROOT}/bin/fail-if-exit-non-zero.pl ${MACHOCHECK}
+FAIL_IF_SUCCESS = ${TESTROOT}/bin/fail-if-exit-zero.pl
+FAIL_IF_EMPTY = ${TESTROOT}/bin/fail-if-no-stdin.pl
+FAIL_IF_STDIN = ${TESTROOT}/bin/fail-if-stdin.pl
--- /dev/null
+#include <stdarg.h>
+#include <stdio.h>
+
+#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);
--- /dev/null
+#!/bin/sh
+
+# cd into test-cases directory
+cd `echo "$0" | sed 's/run-all-unit-tests/test-cases/'`
+
+all_archs="ppc ppc64 i386"
+
+for arch in $all_archs
+do
+ echo ""
+ echo " * * * Running all unit tests for architecture $arch * * *"
+
+ # build architecture
+ ../bin/make-recursive.pl ARCH=$arch VALID_ARCHS="$all_archs" | ../bin/result-filter.pl
+
+ # clean up so svn is happy
+ ../bin/make-recursive.pl ARCH=$arch clean > /dev/null
+
+ echo ""
+done
+
+
+
--- /dev/null
+##
+# 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-${ARCH}
--- /dev/null
+int main (void)
+{
+ return 0;
+}
--- /dev/null
+##
+# 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
+
+# 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 -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 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}
+
+
+# print final pass
+ ${PASS_IFF_GOOD_MACHO} foo.${ARCH}.dylib
+
+clean:
+
+ rm -rf *.${ARCH}.dylib *.${ARCH}.bundle main.${ARCH} fail.log foo.framework bar.framework main.dylib
--- /dev/null
+extern int foo ();
+
+int bar (void)
+{
+ return foo();
+}
--- /dev/null
+extern int foo ();
+
+int bar (void)
+{
+ return foo();
+}
--- /dev/null
+int foo (void)
+{
+ return 1;
+}
--- /dev/null
+extern int foo ();
+
+int main (void)
+{
+ return foo();
+}
--- /dev/null
+##
+# 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
+ ${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} -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-${ARCH} foo-${ARCH}.o bar-${ARCH}.o libfoobar-${ARCH}.a
+
+
--- /dev/null
+int bar() { return 0; }
--- /dev/null
+int foo() { return 1; }
--- /dev/null
+/* -*- 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 <stdio.h>
+
+extern int foo();
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ return foo();
+}
\ No newline at end of file
--- /dev/null
+##
+# 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
+ ${CC} ${CCFLAGS} bar.c -c -o bar-${ARCH}.o
+ ${CC} ${CCFLAGS} baz.c -c -o 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-${ARCH} foo-${ARCH}.o bar-${ARCH}.o baz-${ARCH}.o libfoobar-${ARCH}.a
+
+
--- /dev/null
+int bar() { return 0; }
--- /dev/null
+
+
+
+// intentionally not-weak
+int baz()
+{
+ return 1;
+}
+
+
+
--- /dev/null
+
+
+void collisionChecker() { }
+
+
+int __attribute__((weak)) foo()
+{
+ collisionChecker();
+ return 1;
+}
+
+
+
--- /dev/null
+/* -*- 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 <stdio.h>
+
+extern int foo();
+extern int bar();
+
+// intentionally weak
+int __attribute__((weak)) baz()
+{
+ return 1;
+}
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ return foo() + bar() + baz();
+}
+
+
+
--- /dev/null
+##
+# 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 check that ld
+# can figure out which architecture is needed
+# by looking at the .o files when -arch is not used.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} hello.c -c -o hello.o -mmacosx-version-min=10.4
+ ${LD} -lcrt1.o hello.o -o hello -lSystem 2> fail.log
+ ${FAIL_IF_BAD_MACHO} hello
+ file hello | grep ${ARCH} | ${PASS_IFF_STDIN}
+
+clean:
+ rm hello.o hello fail.log
+
+
--- /dev/null
+/* -*- 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 <stdio.h>
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+}
--- /dev/null
+##
+# 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
+ ${CC} `echo ${ALL_ARCH_OPTIONS}` -dynamiclib foo.c -o libfoo.dylib -install_name libfoo.dylib
+ lipo libfoo.dylib -remove ${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
+
\ No newline at end of file
--- /dev/null
+int foo (void)
+{
+ return 1;
+}
--- /dev/null
+
+int main (void)
+{
+ return 0;
+}
--- /dev/null
+##
+# 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 crt1.o
+ ${CXX} ${CCXXFLAGS} -gdwarf-2 hello.o other.o -o dwarf-hello-${ARCH} -L.
+ ${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 hello.o -mdynamic-no-pic
+
+other.o : other.cxx
+ ${CXX} ${CCXXFLAGS} -gdwarf-2 other.cxx -c -o other.o -mdynamic-no-pic
+
+# don't want any stabs in crt1.o to effect output, so my private stripped copy
+crt1.o : /usr/lib/crt1.o
+ strip -S /usr/lib/crt1.o -o crt1.o
+
+clean:
+ rm -rf dwarf-hello-${ARCH} hello.o other.o crt1.o dwarf-hello-${ARCH}.stabs
+
+
--- /dev/null
+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 GSYM _init
+0000 STSYM __ZZ3bariE8bar_init
+0000 GSYM _uninit
+0000 STSYM _sinit
+0000 STSYM _suninit
+0000 STSYM __ZZ3bariE10bar_uninit
+0000 SO
--- /dev/null
+
+
+inline int foo(int x)
+{
+ return x + 10;
+}
+
+extern int bar(int x);
\ No newline at end of file
--- /dev/null
+/* -*- 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 <stdio.h>
+
+#include "header.h"
+
+
+int main()
+{
+ foo(bar(3));
+ fprintf(stdout, "hello\n");
+}
\ No newline at end of file
--- /dev/null
+
+#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);
+}
+
+
--- /dev/null
+#!/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";
+ }
+}
+
+
--- /dev/null
+##
+# 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-${ARCH}
+
+
--- /dev/null
+/* -*- 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 <stdio.h>
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+}
\ No newline at end of file
--- /dev/null
+##
+# 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}
+ ${FAIL_IF_BAD_MACHO} dwarf-hello-${ARCH}
+ nm -ap dwarf-hello-${ARCH} | grep -e "-" | ${PASS_IFF_EMPTY}
+
+clean:
+ rm -rf dwarf-hello-${ARCH}
+
+
--- /dev/null
+/* -*- 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 <stdio.h>
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+}
\ No newline at end of file
--- /dev/null
+##
+# 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-${ARCH}
+
+
--- /dev/null
+/* -*- 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 <stdio.h>
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+}
--- /dev/null
+##
+# 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-${ARCH}
+
+
--- /dev/null
+/* -*- 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 <stdio.h>
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+}
\ No newline at end of file
--- /dev/null
+##
+# 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
+ ${CC} ${ASMFLAGS} cstring-align-3.s -c -o cstring-align-3-${ARCH}.o
+ ${LD} -arch ${ARCH} -r cstring-align-0-${ARCH}.o cstring-align-3-${ARCH}.o -o cstring-r-${ARCH}.o
+ ${OBJECTDUMP} cstring-align-3-${ARCH}.o | grep 'align:' > align-3
+ ${OBJECTDUMP} cstring-r-${ARCH}.o | grep 'align:' > align-r
+ ${PASS_IFF} diff align-3 align-r
+
+clean:
+ rm -rf cstring-align-0-${ARCH}.o cstring-align-3-${ARCH}.o cstring-r-${ARCH}.o align-3 align-r
+
+
+
--- /dev/null
+/*
+ * 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"
--- /dev/null
+/*
+ * 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"
--- /dev/null
+##
+# 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
+ ${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
+ ${OBJECTDUMP} literals-r-${ARCH}.o | grep 'name:' | uniq -d | ${PASS_IFF_EMPTY}
+
+clean:
+ rm -rf literals-${ARCH}.o -o literals-r-${ARCH}.o
+
+
+
--- /dev/null
+/*
+ * 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"
--- /dev/null
+##
+# 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
+ ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
+ ${OBJECTDUMP} -no_sort test.${ARCH}.o > test.${ARCH}.o.dump
+ ${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 test.${ARCH}.o test-r.${ARCH}.o test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+
+
--- /dev/null
+/*
+ * 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
+
+
+
+_bar:
+ nop
+
+
+ .globl _xx
+ .globl __xx
+_xx:
+__xx:
+ nop
+
+
+_ok:
+ nop
+
--- /dev/null
+##
+# 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 with dwarf-2
+ ${CC} ${CCFLAGS} foo.c -o foo-${ARCH} -gdwarf-2
+ ${FAIL_IF_BAD_MACHO} foo-${ARCH}
+ ${OTOOL} -hlv foo-${ARCH} | grep LC_UUID | ${FAIL_IF_EMPTY}
+ rm -f foo-${ARCH}
+
+# Test with stabs
+ ${CC} ${CCFLAGS} foo.c -o foo-${ARCH} -gfull
+ ${FAIL_IF_BAD_MACHO} foo-${ARCH}
+ ${OTOOL} -hlv foo-${ARCH} | grep LC_UUID | ${FAIL_IF_STDIN}
+
+# Test with two files one with UUID
+ ${CC} ${CCFLAGS} bar.c -c -gdwarf-2
+ ${LD} -arch ${ARCH} bar.o -r -o bar-${ARCH}.o -no_uuid
+ ${CC} ${CCFLAGS} foo.c -c -gdwarf-2
+ ${LD} -arch ${ARCH} foo.o -r -o foo-${ARCH}.o
+ ${CC} ${CCFLAGS} foo-${ARCH}.o bar-${ARCH}.o -o temp-${ARCH}
+ ${FAIL_IF_BAD_MACHO} temp-${ARCH}
+ ${OTOOL} -hlv temp-${ARCH} | grep LC_UUID | ${FAIL_IF_EMPTY}
+ rm -f foo.o bar.o foo-${ARCH}.o bar-${ARCH}.o temp-${ARCH}
+
+# Test with with the flag disabling uuid
+ ${CC} ${CCFLAGS} foo.c -o foo-${ARCH} -Wl,-no_uuid -gdwarf-2
+ ${FAIL_IF_BAD_MACHO} foo-${ARCH}
+ ${OTOOL} -hlv foo-${ARCH} | grep LC_UUID | ${PASS_IFF_EMPTY}
+
+clean:
+ rm -rf foo-${ARCH} bar-${ARCH}.dylib temp-${ARCH}.dylib
--- /dev/null
+int bar (void)
+{
+ return 1;
+}
--- /dev/null
+int main (void)
+{
+ return 0;
+}
--- /dev/null
+##
+# 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
+ ${CC} ${CCFLAGS} -c bar.c -o bar.o
+ ${LD} -r foo.o bar.o -o foobar.o -arch ${ARCH}
+ ${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
+ ${CC} ${CCFLAGS} hello.c foobar2.o -o hello2
+ ${PASS_IFF_GOOD_MACHO} hello2
+
+clean:
+ rm foo.o bar.o foobar.o hello foobar2.o hello2
+
+
--- /dev/null
+
+int __attribute__((visibility("hidden"))) foo = 0;
+
--- /dev/null
+
+
+extern int foo;
+
+int getfoo() { return foo; }
+
+
--- /dev/null
+/* -*- 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 <stdio.h>
+
+extern int getfoo();
+
+int main()
+{
+ return getfoo();
+}
--- /dev/null
+##
+# 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
+# will fail to link a dylib compiled with -mdynamic-no-pic
+#
+
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+run: all
+
+all:
+ ${FAIL_IFF} ${CC} ${CCFLAGS} test.c -mdynamic-no-pic -dynamiclib -o test-${ARCH}.dylib 2> fail.log
+
+clean:
+ rm test-${ARCH}.dylib fail.log
+
+
--- /dev/null
+/* -*- 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;
+
+int foo(void)
+{
+ return a;
+}
--- /dev/null
+##
+# 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
+ ${LD} -arch ${ARCH} -r -keep_private_externs relocs-asm.${ARCH}.o -o relocs-asm-r.${ARCH}.o
+ ${OBJECTDUMP} -no_content relocs-asm.${ARCH}.o > relocs-asm.${ARCH}.o.dump
+ ${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 relocs-asm.${ARCH}.o relocs-asm-r.${ARCH}.o relocs-asm.${ARCH}.o.dump relocs-asm-r.${ARCH}.o.dump
+
+
+
--- /dev/null
+/*
+ * 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@
+ */
+
+#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)
+
+ ; 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)
+
+ ; 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
+#endif
+
+
+
+ # test that pointer-diff relocs are preserved
+ .text
+_test_diffs:
+ .align 2
+Llocal2:
+ .long 0
+ .long Llocal2-_test_branches
+#if __ppc64__
+ .quad Llocal2-_test_branches
+#endif
+
+
+ .data
+_a:
+ .long 0
+
+_b:
+#if __ppc__ || __i386__
+ .long _test_calls
+ .long _test_calls+16
+ .long _external
+ .long _external+16
+#elif __ppc64__
+ .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
+
--- /dev/null
+##
+# 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
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.c -c -o test.${ARCH}.o
+ ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
+ ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump
+ grep "plus" test.${ARCH}.o.dump | ${FAIL_IF_STDIN}
+ ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump
+ grep "plus" test-r.${ARCH}.o.dump | ${FAIL_IF_STDIN}
+ ${PASS_IFF} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+clean:
+ rm -rf test.${ARCH}.o test-r.${ARCH}.o test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+
--- /dev/null
+/* -*- 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; }
+
--- /dev/null
+##
+# 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
+ ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
+ ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump
+ ${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 test.${ARCH}.o test-r.${ARCH}.o test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+
--- /dev/null
+/* -*- 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; }
+
--- /dev/null
+##
+# 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
+ ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
+ ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump
+ ${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 test.${ARCH}.o test-r.${ARCH}.o test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+
--- /dev/null
+/* -*- 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 <Foundation/Foundation.h>
+
+
+@interface Foo : NSObject
+{
+ int ivar;
+}
+- (id) init;
+- (void) foo;
+@end
+
+
+@implementation Foo
+
+- (id) init
+{
+ self = [super init];
+ return self;
+}
+
+- (void) foo
+{
+ [self class];
+}
+
+@end
+
--- /dev/null
+##
+# 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} -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} -gused hello.cxx -c -o hello.o
+
+other.o : other.cxx
+ ${CXX} ${CCXXFLAGS} -gused other.cxx -c -o other.o
+
+clean:
+ rm -rf stabs-hello-${ARCH} hello.o other.o stabs-hello-${ARCH}.stabs stabs-hello-foo-count one
+
+
--- /dev/null
+/* -*- 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);
--- /dev/null
+/* -*- 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 <stdio.h>
+
+#include "header.h"
+
+
+int main()
+{
+ foo(bar(3));
+ fprintf(stdout, "hello\n");
+}
\ No newline at end of file
--- /dev/null
+/* -*- 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);
+}
+
+
--- /dev/null
+##
+# 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:
+ ${CC} ${CCFLAGS} test.c -static -o test-${ARCH} -L/usr/local/lib/system -lc_static -lm_static
+ ${PASS_IFF_GOOD_MACHO} test-${ARCH}
+
+clean:
+ rm test-${ARCH}
+
+
--- /dev/null
+/* -*- 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;
+}
--- /dev/null
+##
+# 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
+ ${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
+ ${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 libfoo-${ARCH}.dylib main-${ARCH} main-${ARCH}.dylib
--- /dev/null
+
+
+#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
+
--- /dev/null
+
+
+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));
+
+
+
--- /dev/null
+
+#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;
+}
+
--- /dev/null
+##
+# 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 test-${ARCH}
+
+
--- /dev/null
+/* -*- 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 <stdio.h>
+
+// 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;
+}
+