------ Tagged ld64-59.4
+2006-09-22 Nick Kledzik <kledzik@apple.com>
+
+ ld64.xcodeproj/project.pbxproj: change install name back to ld64
+ src/Options.cpp: remove support for rolling over to ld_classic
+ src/ld.cpp: remove support for rolling over to ld_classic
+
+
+----- Tagged ld64-62
+
+2006-08-15 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4681062> wrong error message when symbol is found in unused indirect library
+ src/ld.cpp: remove indirect libraries if they are not re-exported
+ unit-tests/test-cases/indirect-dylib: added test case
+
+
+2006-08-15 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/3930461> alignment needs to be richer
+ src/ObjectFile.h: define ObjectFile::Alignment class for tracking rich alignment info
+ src/ld.cpp: modify SymbolTable::add() to work with new Alignment type
+ src/MachOReaderRelocatable.hpp: use new Alignment type. Remove alignAtLeast() and handleAnonymousNonLazyPointers()
+ src/MachOWriterExecutable.hpp: update for new Alignment type, use modulus when calculating layout address
+ src/ObjectDump.cpp: print richer Alignment info
+ unit-tests/test-cases/align-modulus: added test case
+
+
+2006-08-11 Nick Kledzik <kledzik@apple.com>
+
+ remove OPEN_SOURCE conditionals around x86_64 support
+
+
+2006-07-31 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4654131> ld64 while linking cc1 [ when dead_strip is ON]
+ src/ld.cpp: Add ivar fAtomsWithUnresolvedReferences to track atoms not initially resolvable
+ unit-tests/test-cases/dead_strip-archive: added test case
+
+
+2006-07-31 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4656617> x86_64: instructions with immediate and rip-relative operands need to use new relocation types
+ src/MachOWriterExecutable.hpp: generate new reloc types in -r mode
+ src/MachOReaderRelocatable.hpp: parse new reloc types
+ unit-tests/test-cases/relocs-asm/relocs-asm.s: add test cases for new reloc type
+
+
+2006-07-18 Nick Kledzik <kledzik@apple.com>
+
+ src/MachOReaderRelocatable.hpp: suppress warning about dwarf info parsing for one benign no-op case
+ the compiler emits when there are not functions in the __text section
+
+
+2006-07-17 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4634840> faster debug note generateion
+ src/ld.cpp: rework collectDebugInfo() to produce all debug notes in one pass, intead of a
+ pass per .o file. Added timing info for collectDebugInfo() to -print_statistics
+ unit-tests/test-cases/dwarf-debug-notes-r/Makefile: add expliced -arch to ld -r
+ unit-tests/test-cases/dwarf-debug-notes-r/expected-stabs: alter for new debug notes order
+
+
+2006-07-17 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4623994> ld64 VSIZE is 1.18GB when building Finder ppc64
+ src/ld.cpp: fixed typo in createReader() that prevented dylibs from being unmapped
+
+----- Tagged ld64-61.1
2006-07-11 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4622049> ld64-61: gcc DejaGnu tests failing due to -arch followed by unknown architecture name
+ src/Options.cpp: map ppc750, ppc7400, ppc7450, and ppc970 to ppc. Improve error message
- remove conditionals around x86_64 support
+2006-07-11 Nick Kledzik <kledzik@apple.com>
------ Tagged ld64-59.3
+ <rdar://problem/4622769> If -arch is missing, rollover to ld_classic does not happen
+ src/Options.h: make gotoClassicLinker() public
+ src/ld.cpp: call gotoClassicLinker() if the inferred architecture is ppc or i386
-2006-07-02 Nick Kledzik <kledzik@apple.com>
+----- Tagged ld64-61
- <rdar://problem/4664607> x86_64: instructions with immediate and rip-relative operands need to use new relocation types
- back port fix for 4656617 to Inca branch
+2006-06-29 Nick Kledzik <kledzik@apple.com>
------ Tagged ld64-59.2
+ <rdar://problem/4606628> ld64 should be renamed to ld
+ src/Options.cpp: exec() ld_classic if -arch ppc or -arch i386 is seen
+ src/ld.cpp: alter version string
+ ld64.xcodeproj/project.pbxproj: change install location to /usr/bin/ld, add symlink from /usr/bin/ld64
+ doc/man/man1/ld.1: added
+
+----- Tagged ld64-60
+
+2006-06-28 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4604539> Can't link large ppc64 program: ld64 says "bl out of range"
+ MachOWriterExecutable.hpp: fix branch island generation to work for weak_import functions
+ and properly chain together branch islands
+ MachOReaderRelocatable.hpp: improve performance of huge .o file reading by sorted references
+ only when done
2006-06-28 Nick Kledzik <kledzik@apple.com>
<rdar://problem/4603454> MySQL-36 fails to build with ld64-59
- back port fix to Inca branch
+ src/MachOReaderRelocatable.hpp: back out fix for 4585335
+ src/MachOWriterExecutable.hpp: back out fix for 4585335
+
+2006-06-27 Nick Kledzik <kledzik@apple.com>
+
+ src/MachOReaderRelocatable.hpp: handle N_GSYM without ending :G() since that is how
+ dwarf debug notes are formed.
+
+2006-06-23 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4599239 objc class with no superclass causes bad undefined symbol
+ src/MachOReaderRelocatable.hpp: handle NULL superclass in objc_class
+ unit-tests/test-cases/relocs-objc/test.m: add case with no super class
+
+
+2006-06-23 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/4313369> ld64 doesn't support variant linking -framework fw,_debug
+ src/Options.cpp: enhance findFramework() to support suffixes
----- Tagged ld64-59
2006-06-22 Nick Kledzik <kledzik@apple.com>
<rdar://problem/4596726> ld64 lost DWARF debug notes
- MachOReaderRelocatable.hpp: add fHasUUID so kDebugInfoStabsUUID can be set later
+ src/MachOReaderRelocatable.hpp: add fHasUUID so kDebugInfoStabsUUID can be set later
unit-tests/test-cases/dwarf-debug-notes-r: added test case
2006-06-21 Nick Kledzik <kledzik@apple.com>
2006-06-21 Nick Kledzik <kledzik@apple.com>
<rdar://problem/4535036> ld64 seems to offset things incorrectly when using -r
- src/MachOWriterExecutable.hpp: in -r mode, virtual sections don't increment address
+ src/MachOWriterExecutable.hpp: in -r mode, virtual sections should not increment address
----- Tagged ld64-58
2006-06-15 Nick Kledzik <kledzik@apple.com>
<rdar://problem/4569407> ld64 bogus duplicate symbol name linking GNU libobjc
- src/MachOReaderRelocatable.hpp: only special case Apple's objc runtime objc classes
+ src/MachOReaderRelocatable.hpp: only special case Apple objc runtime objc classes
2006-06-15 Nick Kledzik <kledzik@apple.com>
<rdar://problem/4585335> jump table into middle of weak symbol causes error
src/MachOReaderRelocatable.hpp: create direct references to the interior of weak symbols
- src/MachOWriterExecutable.hpp: don't error on absolute references to interior of weak symbols
+ src/MachOWriterExecutable.hpp: do not error on absolute references to interior of weak symbols
2006-06-13 Nick Kledzik <kledzik@apple.com>
* src/MachOReaderRelocatable.cpp: mark non-lazy-pointer atoms as scopeTranslationUnit if targetting a static symbol
-2006-04-27 Nick Kledzik <kledzik@apple.com>
-
- <rdar://problem/4498971> dyld crashes ungracefully on x86_64 when there is an internal exception
- * src/MachOWriterExecutable.cpp: allow non-zero PCRELGOT addends (used by C++ eh frames)
2006-04-21 Nick Kledzik <kledzik@apple.com>
----- Tagged ld64-50
-2006-03-29 Nick Kledzik <kledzik@apple.com>
-
- * src/MachOWriterExecutable.hpp: fix x86_64 addends when -multi_module forces an external relocation
2006-03-29 Nick Kledzik <kledzik@apple.com>
* src/Options.cpp: setup ReaderOptions.fForFinalLinkedImage
* src/MachOReaderRelocatable.hpp: mark .eh symbols kSymbolTableNotIn when building final linked image
-2006-03-21 Nick Kledzik <kledzik@apple.com>
-
- <rdar://problem/4475928> Inca ld64-45 fatal error with C++ and asm() renaming
- * src/MachOReaderRelocatable.hpp: fix Reader<x86_64>::makeReferenceToEH(() to walk relocations to find
- target of eh symbol, rather assume target name is eh symbol name less .eh
-
2006-03-21 Nick Kledzik <kledzik@apple.com>
<rdar://problem/4473742> ld64 does not parse optional second argument to -filelist
* unit-tests/test-cases/filelist: added
* src/Options.cpp: in Options::loadFileList() handle comma option
-2006-03-21 Nick Kledzik <kledzik@apple.com>
-
- <rdar://problem/4483625> 32-bit pointer difference out of range for cxx eh frame
- * src/MachOReaderRelocatable.hpp: x86_64 doesn't have anonymous non-lazy-pointers
- * src/machochecker.cpp: fix validFile() for x86_64
- * unit-tests/run-all-unit-tests: add x86_64
- * unit-tests/include/common.makefile: don't add -g to all compilers
- * unit-tests/test-cases/relocs-asm/relocs-asm.s: add x86_64 test cases
- * unit-tests/test-cases/relocs-c/Makefile: fix to work with x86_64
- * src/ld.cpp: add hack to use i386 dylibs if x86_64 don't exist
-
-2006-03-19 Nick Kledzik <kledzik@apple.com>
-
- <rdar://problem/4483330> ld64 crashes whenever I try to link with dylib1.o
- * src/MachOReaderRelocatable.hpp: in Reader<x86_64>::addRelocReference() fix local relocations
----- Tagged ld64-47.1
-2006-03-16 Nick Kledzik <kledzik@apple.com>
-
- <rdar://problem/4459633> ld64-41 in Leopard doesn't have x86_64 support
- * ld64.xcodeproj/project.pbxproj: enable x86_64 for Leopard
----- Tagged ld64-47
-2006-03-14 Nick Kledzik <kledzik@apple.com>
-
- * src/Architectures.hpp: redo x86_64 relocation types
- * src/MachOReaderRelocatable.hpp: redo x86_64 relocation types, make some section type illegal for x86_64
- * src/MachOWriterExecutable.hpp: redo x86_64 relocation types
-
-2006-03-13 Nick Kledzik <kledzik@apple.com>
-
- <rdar://problem/4467122> ld64 -r does not handle internal relocations for x86_64
- * src/MachOWriterExecutable.hpp: handle internal relocations in Writer<x86_64>::fixUpReferenceRelocatable()
- and Writer<x86_64>::addObjectRelocs().
----- Tagged ld64-46
----- Tagged ld64-45
-2006-03-06 Nick Kledzik <kledzik@apple.com>
-
- <rdar://problem/4466930> <rdar://problem/4467982> ld64 failed: rel32 out of range when linking a dylib
- * src/MachOWriterExecutable.cpp: in Writer<x86_64>::fixUpReferenceFinal add (int32_t) cast
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
-2006-03-06 Nick Kledzik <kledzik@apple.com>
-
- <rdar://problem/4457818> x86_THREAD_STATE64_COUNT will change, ld64 must adapt
- * src/MachOWriterExecutable.hpp: update ThreadsLoadCommandsAtom<x86_64> for new thread status layout
----- Tagged ld64-44
----- Tagged ld64-43
-2006-03-03 Nick Kledzik <kledzik@apple.com>
-
- <rdar://problem/4465443> RIP-relative offsets aren't handled properly when the instruction has immediate operands
- * src/Architectures.hpp: add x86_64::kPCRel32_*
- * src/MachOReaderRelocatable.hpp: generate x86_64::kPCRel32_*
- * src/MachOWriterExecutable.hpp: process x86_64::kPCRel32_*
2006-03-02 Nick Kledzik <kledzik@apple.com>
--- /dev/null
+.TH LD 1 "March 18, 2006" "Apple Computer, Inc."
+.SH NAME
+ld \- Mach object file link editor
+.SH SYNOPSIS
+.B ld
+[
+.I "option \&..."
+] [
+.I "file \&..."
+]
+.SH DESCRIPTION
+The
+.I ld
+command combines several Mach-O (Mach object) files into one by combining like sections
+in like segments from all the object files, resolving external references, and
+searching libraries. In the simplest case several object
+.I files
+are given, and
+.I ld
+combines them, producing an object file which can either be executed or
+become the input for a further
+.I ld
+run. (In the latter case, the
+.B \-r
+option must be given to preserve the relocation information.) Unless an output
+file is specified,
+.I ld
+produces a file named
+.BR a.out .
+This file is made executable only if no errors occurred during the link editing
+and there are no undefined symbols.
+.SH "UNIVERSAL FILE SUPPORT"
+The link editor accepts ``universal'' (multiple-architecture) input files, but
+always creates a ``thin'' (single-architecture), standard Mach-O output file.
+The architecture is specified using the
+.B \-arch
+.I " arch_type"
+option. If this option is not used,
+.IR ld (1)
+attempts to determine the output architecture by examining the first object
+file encountered on the command line. If it is a ``thin''
+file, its architecture determines that of the output file. If the first input
+file is a ``universal'' file, the ``best'' architecture for the host is used.
+(See the explanation of the
+.B \-arch
+option, below.)
+.PP
+The compiler driver
+.IR cc (1)
+handles creating universal executables by calling
+.IR ld (1)
+multiple times and using
+.IR lipo (1)
+to create a ``universal'' file from the results of the
+.IR ld (1)
+executions.
+.SH "OUTPUT FILE LAYOUT"
+.PP
+The object files are loaded in the order in which they are specified on the
+command line. The segments and the
+sections in those segments will appear in the output file in the order they are
+encountered in the object files being linked. All zero fill sections will appear
+after all non-zero fill sections in their segments.
+.PP
+Sections created from files with the
+.B \-sectcreate
+option will appear in the output file last. Section names for sections created
+from files are not allowed to overlap with a section name in the same segment
+as a section coming from an object file. Sections created from files may be in
+a segment which has sections from object files and if so will be loaded at the
+end of the non-zero fill sections for that segment.
+.PP
+If the option
+.B \-seglinkedit
+is specified, the segment it creates is the last segment in the output file.
+.PP
+The address of each segment can be specified with
+.B \-segaddr,
+which takes the segment's name as an argument.
+The address of the first segment can alternatively be specified using
+.B \-seg1addr,
+in which case a segment name is not used.
+Segments that do not have a specified
+address will be assigned addresses in the order in which they appear
+in the output file. A segment's address will be assigned
+based on the ending address of the previous segment.
+If the address of the
+first segment has not been specified by name,
+its assigned address will be
+the specified (via
+.BR \-seg1addr )
+or default first segment address.
+If neither flag is used to specify the first segment's address, its
+default address is zero
+for all formats except the demand-paged executable format
+.SM (MH_EXECUTE),
+in which case the default first address is the value of the segment alignment.
+.PP
+For demand-paged executable format
+.SM (MH_EXECUTE)
+output files,
+if none of the segments' addresses covers address zero through
+the value of the segment alignment, a segment with no access protection
+will be created to cover those addresses. This segment, named
+.SM "``_\|_PAGEZERO'',"
+is created so that any attempt to dereference a NULL pointer will cause a
+memory exception.
+.PP
+The entry point of the output file is the beginning of
+the first section in the first segment (unless the
+.B \-e
+option is specified).
+.SH STATIC ARCHIVE LIBRARIES
+.PP
+.I ld
+supports two types of libraries: static archive libraries and dynamic shared
+libraries. Searching for undefined symbols is performed differently for dynamic
+shared libraries than it is for static archive libraries. The searching of
+dynamic shared libraries is described later.
+.PP
+When a static archive library is specified as an argument to
+.IR ld ,
+it is searched exactly once, at the
+point it is encountered in the argument list. Only those members defining an unresolved external
+reference, as defined by the static archive library's table of contents,
+are loaded. To produce the table of contents, all static archive libraries must be processed by
+.IR ranlib (1).
+.PP
+Generally, a static archive library does not have multiple members that define
+the same symbol. For these types of libraries, the order of the members is not important, so
+the table of contents can be sorted for faster link editing using the
+.B \-s
+option to
+.IR ranlib (1).
+The first member
+of the static archive library is named
+.SM "``\_\^\_.SYMDEF SORTED'',"
+which is understood to be a sorted table of contents.
+.PP
+If the static archive library does have multiple members that define
+the same symbol, the table of contents that
+.IR ranlib (1)
+produces can't be sorted. Instead, it follows the order in which the members
+appear in the static archive library. The link editor searches the table of
+contents iteratively, loading members until no further references are
+satisfied. In the unsorted case, the first member of the static archive
+library is named
+.SM "``\_\^\_.SYMDEF'',"
+which is understood to be a table of contents in
+the order of the archive members.
+.PP
+Static archive library members can also be loaded in response to
+the
+.B \-ObjC
+and
+.B \-all_load
+flags. See their descriptions below.
+
+.SH DYNAMIC SHARED LIBRARIES
+.PP
+When a dynamic shared library or an object file that was linked against a
+dynamic shared library is specified as an argument to
+.IR ld ,
+that library is placed in the dynamic shared library search list. The order of
+the search list is always the same order the libraries were encountered on the
+command line. When linking -flat_namespace, all dynamic libraries that the
+dynamic libraries are dependent upon are added to the end of the search list.
+.PP
+Once the search list is constructed, the static link editor checks for undefined
+symbols by simulating the way the dynamic linker will search for undefined
+symbols at runtime. For each undefined symbol, the static link editor searches
+each library in the search list until it finds a module that defines the symbol.
+With each undefined symbol, the search starts with the first library in the
+list. This is different than for static archive libraries, where each library
+is searched exactly once for all undefined symbols.
+.PP
+The static link editor simulates dynamic linking as if all the undefined
+symbols are to be bound at program launch time. The dynamic linker actually
+binds undefined symbols as they are encountered during execution instead of at
+program launch. However, the static link editor always produces the same linking
+as the dynamic linker as long as none of the dynamic shared libraries define the
+same symbol. Different linking can occur only when there is more than one
+definition of a symbol and the library modules that contain the definitions for
+that symbol do not define and reference exactly the same symbols. In this case,
+even different executions of the same program can produce different linking
+because the dynamic linker binds undefined functions as they are called, and
+this affects the order in which undefined symbols are bound. Because it can
+produce different dynamic linking, using dynamic shared libraries that define
+the same symbols in the same program is strongly discouraged.
+.PP
+If a static archive library appears after a dynamic shared library on the
+command line, the static library is placed in the dynamic library search list
+and is searched as a dynamic library. In this way, when a dynamic library has
+undefined symbols, it will cause the appropriate members of the static libraries
+to be loaded into the output. Searching static libraries as dynamic libraries
+can cause problems if the dynamic library later changes to reference symbols
+from the static library that it did not previously reference. In this case when
+the program runs, the dynamic linker will report these symbols as undefined
+because the members for these symbols were not loaded into the output.
+
+.SH TWO-LEVEL AND FLAT NAMESPACES
+.PP
+Two-level and flat namespaces refer to how references to symbols in dynamic
+libraries are resolved to a definition in specific dynamic library. For
+two-level namespace that resolution is done at static link time when each
+image (program, bundle and shared library) is built. When a program is using
+images built with two-level namespace there may be different global symbols
+with the same name being used by different images in the program (this is now
+the default). When a program is using all flat namespace images then only one
+global symbol for each global symbol name is used by all images of the program
+(this was the default in MacOS X 10.0).
+.PP
+When creating an output file with the static link editor that links against
+dynamic libraries, the references to symbols in those libraries can be recorded
+at static link time to bind to a specific library definition (two-level
+namespace) or left to be bound at execution time to the first library in the
+search order of the program (flat namespace). A program, its dynamic libraries
+and its bundles may each be either two-level or flat namespace images. The
+dynamic linker will bind each image according to how it was built.
+.PP
+When creating an output file with the static link editor when
+.B \-twolevel_namespace
+is in effect (now the default) all undefined references must be satisfied at
+static link time. The flags to allow undefined references,
+.BI \-U symbol_name,
+.BI \-undefined " warning"
+and
+.BI \-undefined " suppress"
+can't be used.
+When the environment variable
+.B MACOSX_DEPLOYMENT_TARGET
+is set to
+.B 10.3
+or higher then
+.BI \-undefined " dynamic_lookup"
+can also be used. The specific library definition recorded
+for each reference is the first library that has a definition as listed on the
+link line. Listing an umbrella framework implies all of its sub-frameworks,
+sub-umbrellas and sub-libraries. For any reference to a definition found in
+an umbrella framework's sub-framework, sub-umbrella or sub-library will be
+recorded as coming from the umbrella framework. Then at execution time the
+dynamic linker will search that umbrella framework's sub-frameworks,
+sub-umbrellas and sub-libraries for those references.
+Also when two-level namespace is in effect only those frameworks listed on the
+link line (and sub-frameworks, sub-umbrellas and sub-libraries of umbrella
+frameworks) are searched. Other dependent libraries which are not
+sub-frameworks, sub-umbrellas or sub-libraries of umbrella frameworks are not
+searched.
+.RS
+.PP
+When creating bundles (MH_BUNDLE outputs) with the static link editor when
+two-level namespace is in effect (now the default) and the bundle has
+references to symbols
+expected to be defined in the program loading the bundle, then the
+.BI \-bundle_loader " executable"
+must be used.
+.PP
+When creating a output file with the static link editor when
+.B \-flat_namespace
+is in effect (the MacOS X 10.0 default) all undefined references must be
+satisfied at static link time when
+.BI \-undefined " error"
+(the default) is used. The static
+link editor checks the undefined references by searching all the libraries
+listed on the link line then all dependent libraries. The undefined symbols
+in the created output file are left to be resolved at execution time by the
+dynamic link editor in the dynamic libraries in the search order of the program.
+
+.SH MULTIPLY DEFINED SYMBOLS
+.PP
+If there are multiply defined symbols in the object files being linked into
+the output file being created this always results in a multiply defined
+symbol error.
+.PP
+When the static link editor links symbols in from a dynamic library that result
+in multiply defined symbols the handling depends on the type of name space of
+output file being created and possibly the type of name space of the dynamic
+library.
+.PP
+When the static link editor is creating a two-level namespace image and a
+there is a multiply defined symbol from dynamic library then that generates a
+multiply defined symbol warning (by default), where the treatment of this
+warning can be changed with the
+.B \-multiply_defined
+flag.
+.PP
+When the static link editor is creating a flat namespace image and a there is
+a multiply defined symbol from dynamic library, if the library is a flat
+namespace image then that generates a multiply defined symbol error. If the
+library is a two-level namespace image then that generates a multiply defined
+symbol warning (by default), where the treatment of this warning can be changed
+with the
+.B \-multiply_defined
+flag.
+
+.SH "USING THE DYNAMIC LINK EDITOR AND DYNAMIC SHARED LIBRARIES"
+.PP
+The option
+.B \-dynamic
+must be specified in order to use dynamic shared libraries (and any of the features used to implement them) and/or the dynamic link editor.
+To make sure that the output is not using any features that would
+require the dynamic link editor, the flag
+.B \-static
+can be specified.
+Only one of these flags can be specified.
+
+.SH "LINK EDITOR DEFINED SYMBOLS"
+.PP
+There is a group of link editor defined symbols for the
+.SM MH_EXECUTE,
+.SM MH_DYLIB
+and
+.SM MH_PRELOAD
+file types (see the header file <mach-o/ldsyms.h>). Link editor symbols are
+reserved; it is an error if an input object file defines such a symbol.
+Only those link editor symbols that are referenced by the object file
+appear in the output file's symbol table.
+.PP
+The link editor defined symbol `\_\^\_mh_execute_header'
+(`\_mh_execute_header' in C) is reserved when the output file format is
+.SM MH_EXECUTE.
+This symbol is the address of the Mach header in a Mach-O executable (a
+file of type
+.SM MH_EXECUTE).
+It does not appear in
+any other Mach-O file type. It can be used to get to the addresses and
+sizes of all the segments and sections in the executable. This can be done by parsing the headers
+and load commands (see
+.IR Mach-O (5)).
+.PP
+The link editor defined symbol `\_\^\_mh_dylib_header'
+(`\_mh_dylib_header' in C) is reserved when the output file format is
+.SM MH_DYLIB.
+This symbol is the address of the Mach header in a Mach-O dynamic shared library
+(a file of type
+.SM MH_DYLIB)
+and is a private external symbol.
+It does not appear in
+any other Mach-O file type. It can be used to get to the addresses and
+sizes of all the segments and sections in a dynamic shared library. The
+addresses, however, must have the value
+.IR _dyld_get_image_vmaddr_slide (3)
+added to them.
+.PP
+The
+.SM MH_PRELOAD
+file type has link editor defined symbols for the
+beginning and ending of each segment, and for the
+beginning and ending of each section within a segment.
+These names are provided for use in a Mach-O preloaded file,
+since it does not have its headers loaded as part of the first segment.
+The names of the symbols for a segment's beginning and end
+have the form: \_\^\_SEGNAME\_\^\_begin and \_\^\_SEGNAME\_\^\_end,
+where \_\^\_SEGNAME is the name of the segment. Similarly, the symbols for
+a section have the form:
+\_\^\_SEGNAME\_\^\_sectname\_\^\_begin and \_\^\_SEGNAME\_\^\_sectname\_\^\_end,
+where \_\^\_sectname is the name of the section in the segment \_\^\_SEGNAME.
+These symbols' types are those of the section that the names refer to.
+(A symbol that refers to the end of a section actually has, as its value, the beginning address of the next section, but the symbol's type is still that of the section mentioned in the symbol's name.)
+.SH OPTIONS
+.PP
+.I Ld
+understands several options. Filenames and
+options that refer to libraries (such as
+.B \-l
+and
+.BR \-framework ),
+as well as options that create symbols (such as
+.B \-u
+and
+.BR \-i ),
+are position-dependent: They define the load order and affect what gets
+loaded from libraries.
+Some
+.I ld
+options overlap with compiler options. If the compiler driver
+.IR cc (1)
+is used to invoke
+.I ld ,
+it maybe necessary to pass the
+.IR ld (1)
+options to
+.IR cc (1)
+using
+.BR \-Wl,\-option,argument1,argument2 .
+
+In this release of the static link editor, 64-bit code (-arch ppc64) are processed by a separate
+tool /usr/bin/ld64. Not all of the ld command line options are recognized by this tool.
+The options not currently support for building 64-bit binaries are flagged
+.BR "(32-bit only)" .
+
+The most common option is:
+.TP
+.BI \-o " name"
+The output file is named
+.IR name ,
+instead of
+.BR a.out .
+
+.PP
+The following flags are related to architectures:
+.TP
+.BI \-arch " arch_type"
+Specifies the architecture,
+.I arch_type,
+for the output file. ``Universal'' input files that do not contain this
+specified architecture are ignored. Only one
+.BI \-arch " arch_type"
+can be specified. See
+.IR arch (3)
+for the currently known
+.IR arch_type s.
+If
+.I " arch_type"
+specifies a certain implementation of an architecture (such as
+.BI \-arch " m68040"
+or
+.BI \-arch " i486"
+), the resulting object file has that specific CPU subtype, and it is an
+error if any input file has a CPU subtype that will not combine to the CPU subtype
+for
+.IR " arch_type" .
+.IP
+The default output file architecture is determined by the first object file to
+be linked. If it is a ``thin'' (standard Mach-O) file, or a ``universal'' file
+that contains only one architecture, the output file will have the same
+architecture. Otherwise, if it is a ``universal'' file
+containing an architecture that would execute on the host, then the ``best''
+architecture is used, as defined by what the kernel exec(2) would select.
+Otherwise, it is an error, and a
+.BI \-arch " arch_type"
+must be specified.
+.TP
+.B \-arch_multiple
+This flag is used by the
+.IR cc (1)
+driver program when it is run with multiple
+.BI \-arch " arch_type"
+flags. It instructs programs like
+.IR ld (1)
+to precede any displayed message with a line stating
+the program name, in this case
+.IR ld ,
+and the architecture (from the
+.BI \-arch " arch_type"
+flag). This helps distinguish which architecture the error messages refer to.
+.TP
+.B \-force_cpusubtype_ALL
+The
+.B \-force_cpusubtype_ALL
+flag causes the CPU subtype to remain the
+.SM ALL
+CPU subtype and not to be combined or
+changed. This flag has precedence over any
+.BI \-arch " arch_type"
+flag for a specific implementation.
+This is the default for all x86 architectures.
+.PP
+The following flags are related to using the dynamic link editor and/or
+dynamic shared libraries (and any of the features used to implement them):
+.TP
+.B \-dynamic
+Allows use of the features associated with dynamic link editor. The default is
+.B \-dynamic.
+.TP
+.B \-static
+Causes those features associated with dynamic link editor to be treated as
+an error. (The description for the options that will cause an error if you use them in conjunction with
+.B \-static
+are marked with the statement "when
+.B \-dynamic
+ is used").
+.TP
+.BI \-read_only_relocs " treatment"
+Specifies how relocation entries in read-only sections are to be treated when
+.B \-dynamic
+is used.
+To get the best possible sharing, the read-only sections should not have any
+relocation entries.
+If they do, the dynamic linker will write on the section.
+Having relocation entries appear in read-only sections is normally avoided by compiling with the option
+.B \-dynamic.
+But in such cases non-converted assembly code
+or objects not compiled with
+.B \-dynamic
+relocation entries will appear in read-only sections.
+The
+.I treatment
+can be:
+.I error,
+.I warning,
+or
+.I suppress.
+Which cause the treatment of relocation entries in read-only sections as either,
+errors, warnings, or suppressed messages.
+The default is to treat these as errors.
+.TP
+.BI \-sect_diff_relocs " treatment"
+Specifies how section difference relocation enries are to be treated when
+.B \-dynamic
+and
+.B \-execute
+are used.
+To get the best possible code generation the compiler should not generate code
+for executables (MH_EXECUTE format outputs) that have any section difference
+relocation entries. The
+.IR gcc (1)
+compiler has the
+.B \-mdynamic-no-pic
+flag for generating code for executables. The default treatment is
+.I suppress,
+where no message is printed. The other treatments are
+.I error
+or
+.I warning.
+This option can also be specified by setting the environment variable
+.SM LD_SECT_DIFF_RELOCS
+to the treatment values.
+.TP
+.BI \-weak_reference_mismatches " treatment"
+Specifies how to treat mismatches of symbol references in the the object files
+being linked. Normally the all the undefined symbol references of the object
+files being linked should be consistent for each undefined symbol. That is all
+undefined symbols should either be weak or non-weak references. The default
+treatment is
+.I error,
+where the link fails with an error message. The other treatments are
+.I weak
+or
+.I non-weak,
+which makes mismatched undefined symbol references either weak or non-weak
+in the output, respectively. Care must be taken when using the treatment
+.I weak
+as the use of the non-weak symbol references in an object file may cause the
+program to crash when the symbol is not present at execution time.
+.TP
+.B \-prebind (32-bit only)
+Have the static linker,
+.IR ld (1),
+prebind an executable's or dynamic shared library's undefined symbols to the
+addresses of the dynamic libraries it is being linked with.
+This optimization can only be done if the libraries don't overlap and
+no symbols are overridden.
+When the resulting program is run and the same libraries are used to run the
+program as when the program was linked, the dynamic linker can use the prebound
+addresses.
+If not, the dynamic linker undoes the prebinding and binds normally.
+This option can also be specified by setting the environment variable
+.SM LD_PREBIND.
+If the environment variable
+.SM LD_FORCE_NO_PREBIND
+is set both the option
+.B \-prebind
+.SM LD_PREBIND
+environment variable are ignore and the output is not prebound.
+Or if the environment variable
+.B MACOSX_DEPLOYMENT_TARGET
+is set to 10.4 or greater and the output is not a split a dynamic library the
+output is not prebound.
+.TP
+.B \-noprebind (32-bit only)
+Do not have the static linker,
+.IR ld (1),
+prebind the output. If this is specified the environment variable
+.SM LD_PREBIND
+is ignored.
+.TP
+.B \-prebind_allow_overlap (32-bit only)
+Have the static linker,
+.IR ld (1),
+prebind the output even if the addresses of the dynamic libraries it uses
+overlap. The resulting output can then have
+.IR redo_prebinding (1)
+run on it to fix up the prebinding after the overlapping dynamic libraries
+have been rebuilt. This option can also be specified by setting the
+environment variable
+.SM LD_PREBIND_ALLOW_OVERLAP.
+.TP
+.B \-prebind_all_twolevel_modules (32-bit only)
+Have the static linker,
+.IR ld (1),
+mark all modules from prebound two-level namespace dynamic libraries as used
+by the program even if they are not statically referenced. This can provide
+improved launch time for programs like Objective-C programs that use symbols
+indirectly through NIB files. This option can also be specified by setting the
+environment variable
+.SM LD_PREBIND_ALL_TWOLEVEL_MODULES.
+.TP
+.B \-noprebind_all_twolevel_modules (32-bit only)
+Don't have the static linker,
+.IR ld (1),
+mark all modules from prebound two-level namespace dynamic libraries as used
+by the program. This flag overrides the setting of the
+environment variable
+.SM LD_PREBIND_ALL_TWOLEVEL_MODULES.
+.TP
+.B \-nofixprebinding (32-bit only)
+Have the static linker,
+.IR ld (1),
+mark the executable so that the dynamic linker will never notify the prebinding
+agent if this launched and its prebinding is out of date. This is used when
+building the prebinding agent itself.
+.PP
+The following flags are related to libraries:
+.TP
+.BI \-l x
+This
+option is an abbreviation for the library name
+.RI `lib x .a',
+where
+.I x
+is a string.
+If
+.B \-dynamic
+is specified the abbreviation for the library name is first search as
+.RI `lib x .dylib'
+and then
+.RI `lib x .a'
+is searched for.
+.I ld
+searches for libraries first in any directories
+specified with
+.B \-L
+options, then in any directories specified in the colon separated set of paths
+in the environment variable LD_LIBRARY_PATH, then the standard directories
+.BR /lib ,
+.BR /usr/lib ,
+and
+.BR "/usr/local/lib" .
+A library is searched when its name is encountered,
+so the placement of the
+.B \-l
+flag is significant. If string
+.I x
+is of the form
+.IR x .o,
+then that file is searched for in the same places, but without prepending
+`lib' or appending `.a' or `.dylib' to the filename.
+.TP
+.BI \-weak-l x
+This is the same as the
+.BI \-l x
+but forces the library and all references to it to be marked as weak imports.
+Care must be taken when using this as the use of the non-weak symbol references
+in an object file may cause the program to crash when the symbol or library is
+not present at execution time.
+.TP
+.BI \-weak_library " file_name_path_to_library"
+This is the same as listing a file name path to a library on the link line
+except that it forces the library and all references to it to be marked as
+weak imports.
+Care must be taken when using this as the use of the non-weak symbol references
+in an object file may cause the program to crash when the symbol or library is
+not present at execution time.
+.TP
+.BI \-L dir
+Add
+.I dir
+to the list of directories in which to search for libraries.
+Directories specified with
+.B \-L
+are searched before the standard directories.
+.TP
+.B \-Z
+Do not search the standard directories when searching for libraries.
+.TP
+.BI "\-syslibroot " rootdir " (32-bit only)"
+Prepend
+.I rootdir
+to the standard directories when searching for libraries or frameworks.
+.TP
+.B \-search_paths_first
+By default when the
+.B \-dynamic
+flag is in effect, the
+.BI \-l x
+and
+.BI \-weak-l x
+options first search for a file of the form
+.RI `lib x .dylib'
+in each directory in the library search path, then a file of the form
+.RI `lib x .a'
+is searched for in the library search paths.
+This option changes it so that in each path
+.RI `lib x .dylib'
+is searched for then
+.RI `lib x .a'
+before the next path in the library search path is searched.
+.TP
+.BI "\-framework " name[,suffix]
+Specifies a framework to link against. Frameworks are dynamic shared libraries,
+but they are stored in different locations, and therefore must be searched for
+differently. When this option is specified,
+.I ld
+searches for framework `\fIname\fR.framework/\fIname\fR'
+first in any directories
+specified with the
+.B \-F
+option, then in the standard framework directories
+.BR /Library/Frameworks ,
+.BR /Network/Library/Frameworks ,
+and
+.BR "/System/Library/Frameworks" .
+The placement of the
+.B \-framework
+option is significant, as it determines when and how the framework is searched.
+If the optional suffix is specified the framework is first searched for the
+name with the suffix and then without.
+.TP
+.BI "\-weak_framework " name[,suffix]
+This is the same as the
+.BI "\-framework " name[,suffix]
+but forces the framework and all references to it to be marked as weak imports.
+Care must be taken when using this as the use of the non-weak symbol references
+in an object file may cause the program to crash when the symbol or framework is
+not present at execution time.
+.TP
+.BI \-F dir
+Add
+.I dir
+to the list of directories in which to search for frameworks.
+Directories specified with
+.B \-F
+are searched before the standard framework directories.
+.TP
+.B \-ObjC
+Loads all members of static archive libraries that define an Objective C class or a category. This option does not apply to dynamic shared libraries.
+.TP
+.B \-all_load
+Loads all members of static archive libraries.
+This option does not apply to dynamic shared
+libraries.
+.TP
+.BI \-dylib_file " install_name:file_name" (32-bit only)
+Specifies that a dynamic shared library is in a different location than its standard location. Use this option when you link with a library that is dependent on a dynamic library, and the dynamic library is in a location other than its default location.
+.I install_name
+specifies the path where the library normally resides.
+.I file_name
+specifies the path of the library you want to use instead.
+For example, if you link to a library that depends upon the dynamic library libsys and you have libsys installed in a nondefault location, you would use this option:
+\fB\-dylib_file /lib/libsys_s.A.dylib:/me/lib/libsys_s.A.dylib\fR.
+.TP
+.BI \-executable_path " path_name" (32-bit only)
+Specifies that
+.I path_name
+is used to replace
+.I @executable_path
+for dependent libraries.
+
+.PP
+The following options specify the output file format (the file type):
+.TP
+.B "\-execute"
+Produce a Mach-O demand-paged executable format file. The headers are placed
+in the first segment, and all segments are padded to the segment alignment.
+This has a file type of
+.SM MH_EXECUTE.
+This is the default. If no segment address is specified at address zero, a
+segment with no protection (no read, write, or execute permission) is created
+at address zero.
+This segment, whose size is that of the segment
+alignment, is named
+.SM ``_\|_PAGEZERO''.
+This option was previously named
+.BR "\-Mach" ,
+which will continue to be recognized.
+.TP
+.B \-object (32-bit only)
+Produce a Mach-O file in the relocatable object file format that is
+intended for execution. This differs from using the
+.B \-r
+option in that it defines common symbols, does not allow undefined symbols and
+does not preserve relocation entries. This has a file type of
+.SM MH_OBJECT.
+In this format all sections are placed in one unnamed segment with all
+protections (read, write, execute) allowed on that segment. This is intended
+for extremely small programs that would otherwise be large due to segment
+padding. In this format, and all
+.SM non-MH_EXECUTE
+formats, the link editor
+defined symbol ``\_\^\_mh_execute_header'' is not defined since the headers are
+not part of the segment. This format file can't be used with the dynamic
+linker.
+.TP
+.B \-preload (32-bit only)
+Produce a Mach-O preloaded executable format file. The headers are not placed
+in any segment. All sections are placed in their proper segments and they are
+padded to the segment alignment. This has a file type of
+.SM MH_PRELOAD.
+This option was previously
+.BR "\-p" ,
+which will continue to be recognized.
+.TP
+.B "\-dylib"
+Produce a Mach-O dynamically linked shared library format file. The headers are
+placed in the first segment. All sections are placed in their proper segments
+and they are padded to the segment alignment. This has a file type of
+.SM MH_DYLIB.
+This option is used by
+.IR libtool (1)
+when its
+.B \-dynamic
+option is specified.
+.TP
+.B "\-bundle"
+Produce a Mach-O bundle format file. The headers are placed in the first
+segment. All sections are placed in their proper segments
+and they are padded to the segment alignment. This has a file type of
+.SM MH_BUNDLE.
+.TP
+.B "\-dylinker"
+Produces a Mach-O dynamic link editor format file. The headers are placed in the
+first segment. All sections are placed in their proper segments, and they are
+padded to the segment alignment. This has a file type of
+.SM MH_DYLINKER.
+.TP
+.B \-fvmlib (32-bit only)
+Produce a Mach-O fixed VM shared library format file. The headers are placed
+in the first segment but the first section in that segment will be placed on
+the next segment alignment boundary in that segment. All sections are placed
+in their proper segments and they are padded to the segment alignment.
+This has a file type of
+.SM MH_FVMLIB.
+
+.PP
+The following flags affect the contents of the output file:
+.TP
+.B \-r
+Save the relocation information in the output file
+so that it can be the subject of another
+.I ld
+run. The resulting file type is a Mach-O relocatable file
+.SM (MH_OBJECT)
+if not otherwise specified.
+This flag also prevents final definitions from being
+given to common symbols,
+and suppresses the `undefined symbol' diagnostics.
+.TP
+.B \-d (32-bit only)
+Force definition of common storage even if the
+.B \-r
+option is present. This option also forces link editor defined symbols to be defined.
+This option is assumed when there is a dynamic link editor load command in the input
+and
+.B \-r
+is not specified.
+
+.PP
+The following flags support segment specifications:
+.TP
+.BI "\-segalign" " value" " (32-bit only)"
+Specifies the segment alignment.
+.I value
+is a hexadecimal number that must be an integral power of 2.
+The default is the target pagesize (currently 1000 hex for the PowerPC and
+i386).
+.TP
+.BI "\-seg1addr" " addr"
+Specifies the starting address of the first segment in the output file.
+.I addr
+is a hexadecimal number and must be a multiple of the segment alignment.
+This option can also be specified as
+.B "\-image_base."
+.TP
+.BI "\-segaddr" " name addr" " (32-bit only)"
+Specifies the starting address of the segment named
+.I name
+to be
+.I addr.
+The address must be a hexadecimal number that is a multiple of the segment alignment.
+.TP
+.BI "\-segs_read_only_addr" " addr" " (32-bit only)"
+Specifies the starting address of the read-only segments in a dynamic shared
+library. When this option is used the dynamic shared library is built such
+that the read-only and read-write segments are split into separate address
+ranges. By default the read-write segments are 256meg (0x10000000) after
+the read-only segments.
+.I addr
+is a hexadecimal number and must be a multiple of the segment alignment.
+.TP
+.BI "\-segs_read_write_addr" " addr" " (32-bit only)"
+Specifies the starting address of the read-write segments in a dynamic shared
+library. When this option is used the
+.B \-segs_read_only_addr
+must also be used (see above).
+.I addr
+is a hexadecimal number and must be a multiple of the segment alignment.
+.TP
+.BI "\-seg_addr_table" " filename" " (32-bit only)"
+For dynamic shared libraries the
+.B "\-seg1addr"
+or the pair of
+.B "\-segs_read_only_addr"
+and
+.B "\-segs_read_write_addr"
+are specified by an entry in the segment address table in
+.I filename
+that matches the install name of the library.
+The entries in the table are lines containing either a single hex address and an
+install name or two hex addresses and an install name. In the first form the
+single hex address is used as the
+.B "\-seg1addr".
+In the second form the first address is used as the
+.B "\-segs_read_only_addr"
+address and the second address is used as the
+.B "\-segs_read_write_addr"
+address.
+This option can also be specified by setting the environment variable
+.SM LD_SEG_ADDR_TABLE.
+If the environment variable is set then any
+.BR "\-seg1addr" ,
+.BR "\-segs_read_only_addr" ,
+.B "\-segs_read_write_addr"
+and
+.B "\-seg_addr_table"
+options are ignored and a warning is printed.
+.TP
+.BI "\-seg_addr_table_filename" " pathname" " (32-bit only)"
+Use
+.B pathname
+instead of the install name of the library for matching an entry in the segment
+address table.
+.TP
+.BI "\-segprot" " name max init" " (32-bit only)"
+Specifies the maximum and initial virtual memory protection of the named
+segment,
+.I name,
+to be
+.I max
+and
+.I init
+,respectively. The values for
+.I max
+and
+.I init
+are any combination of the characters `r' (for read), `w' (for write),
+`x' (for execute) and '\-' (no access). The default is `rwx' for the maximum
+protection for all segments for PowerPC architecures and `rw` for the all Intel
+architecures.
+The default for the initial protection for all segments is `rw' unless the
+segment contains a section which contains some machine instructions, in which
+case the default for the initial protection is `rwx' (and for Intel
+architecures it also sets the maximum protection to `rwx' in this case).
+The default for the initial protection for the
+.SM "``_\|_TEXT''"
+segment is `rx' (not writable).
+.TP
+.B \-seglinkedit (32-bit only)
+Create the link edit segment, named
+.SM "``_\|_LINKEDIT''"
+(this is the default).
+This segment contains all the link edit information (relocation information,
+symbol table, string table, etc.) in the object file. If the segment protection
+for this segment is not specified, the initial protection is not writable.
+This can only be specified when the output file type is not
+.SM MH_OBJECT
+and
+.SM MH_PRELOAD
+output file types. To get at the contents of this section, the Mach header
+and load commands must be parsed from the link editor defined symbols like
+`\_\^\_mh_execute_header' (see
+.IR Mach-O (5)).
+.TP
+.B \-noseglinkedit (32-bit only)
+Do not create the link edit segment (see
+.B \-seglinkedit
+above).
+.TP
+.BI "\-pagezero_size" " value"
+Specifies the segment size of _\|_PAGEZERO to be of size
+.IR value ,
+where
+.I value
+is a hexadecimal number rounded to the segment alignment.
+The default is the target pagesize (currently, 1000 hexadecimal for the PowerPC
+and for i386).
+.TP
+.BI "\-stack_addr" " value"
+Specifies the initial address of the stack pointer
+.IR value ,
+where
+.I value
+is a hexadecimal number rounded to the segment alignment.
+The default segment alignment is the target pagesize (currently, 1000
+hexadecimal for the PowerPC and for i386).
+If
+.B \-stack_size
+is specified and
+.B \-stack_addr
+is not, a default stack address specific for the architecture being linked will
+be used and its value printed as a warning message.
+This creates a segment named _\|_UNIXSTACK. Note that the initial stack address
+will be either at the high address of the segment or the low address of the
+segment depending on which direction the stack grows for the architecture being
+linked.
+.TP
+.BI "\-stack_size" " value"
+Specifies the size of the stack segment
+.IR value ,
+where
+.I value
+is a hexadecimal number rounded to the segment alignment.
+The default segment alignment is the target pagesize (currently, 1000
+hexadecimal for the PowerPC and for i386).
+If
+.B \-stack_addr
+is specified and
+.B \-stack_size
+is not, a default stack size specific for the architecture being linked will be
+used and its value printed as a warning message.
+This creates a segment named _\|_UNIXSTACK .
+.TP
+.B \-allow_stack_execute
+Marks executable so that all stacks in the task will be given stack execution
+privilege. This includes pthread stacks.
+
+.PP
+The following flags support section specifications:
+.TP
+.BI "\-sectcreate" " segname sectname file"
+The section
+.I sectname
+in the segment
+.I segname
+is created from the contents of
+.I file.
+The combination of
+.I segname
+and
+.I sectname
+must be unique; there cannot already be a section
+.I (segname,sectname)
+in any input object file.
+This option was previously called
+.BR "\-segcreate" ,
+which will continue to be recognized.
+.TP
+.BI "\-sectalign" " segname sectname value"
+The section named
+.I sectname
+in the segment
+.I segname
+will have its alignment set to
+.IR value ,
+where
+.I value
+is a hexadecimal number that must be an integral power of 2.
+This can be used to set the alignment of a section created from a file, or to
+increase the alignment of a section from an object file, or to set the maximum
+alignment of the
+.SM (_\|_DATA,_\|_common)
+section, where common symbols are defined
+by the link editor. Setting the alignment of a literal section causes the
+individual literals to be aligned on that boundary. If the section
+alignment is not specified by a section header in an object file or on the
+command line, it defaults to 10 (hex), indicating 16-byte alignment.
+.TP
+.BI "\-sectorder" " segname sectname orderfile" (32-bit only)
+The section
+.I sectname
+in the segment
+.I segname
+of the input files will be broken up into blocks associated with
+symbols in the section. The output section will be created by ordering
+the blocks as specified by the lines in the
+.I orderfile.
+These blocks are aligned to the output file's section alignment for this
+section. Any section can be ordered in the output file except symbol pointer and symbol stub sections.
+.IP
+For non-literal sections, each line of the
+.I orderfile
+contains an object name and a symbol name, separated by a single colon (':').
+Lines that start with # are ignored and treated as comments.
+If the object file is
+in an archive, the archive name, followed by a single colon, must precede the
+object file name. The object file names and archive names should be exactly the
+names as seen by the link editor, but if not, the link editor attempts to match
+up the names the best it can.
+For non-literal sections, the easiest way to generate an order file is
+with the ``\f3\-jonls +\f2segname sectname\f1'' options to
+.IR nm (1).
+.IP
+The format of the
+.I orderfile
+for literal sections is specific to each type of literal section. For C
+string literal sections, each line of the order file contains one literal C
+string, which may include ANSI C escape sequences. For four-byte literal
+sections, the order file format is one 32-bit hex number with a leading 0x
+per
+line, with the rest of the line treated as a comment. For eight-byte literal
+sections, the order file has two 32-bit hex numbers per line; each number
+has a leading 0x, the two numbers are separated by white
+space, and the rest of the line is treated as a comment.
+For literal pointer sections, the lines in the order file represent
+pointers, one per line. A literal pointer is represented by the name of
+the segment that contains the literal being pointed to, followed by the
+section name, followed by the literal. These three strings are separated
+by colons with no extra white space.
+For all the literal sections, each line in the the order file is simply entered
+into the literal section and will appear in the output file in the same order
+as in the
+order file. There is no check to see whether the literal is present
+in the loaded objects.
+For literal sections, the easiest way to generate an order file is with
+the ``\f3\-X \-v \-s \f2segname sectname\f1'' options to
+.IR otool (1).
+.TP
+.B \-sectorder_detail (32-bit only)
+When using the
+.B \-sectorder
+option, any pairs of object file names and symbol names that are found in
+the loaded objects, but not specified in the
+.IR orderfile ,
+are placed last in the output file's section. These pairs are ordered by
+object file (as the filenames appear
+on the command line), with the different symbols from a given object
+file being ordered by
+increasing symbol address (that is, the order
+in which the symbols occurred in the object file,
+not their order in the symbol table). By default, the link editor displays a summary
+that simply shows the number
+of symbol names found in the loaded objects but not in the
+.IR orderfile ,
+as well as the number of symbol names listed in the
+.I orderfile
+but not found in the loaded objects. (The summary is omitted if both values
+are zero.) To instead produce a detailed list of these symbols, use the
+.B \-sectorder_detail
+flag. If an object file-symbol name pair is listed multiple times, a
+warning is generated, and the first occurrence is used.
+.TP
+.BI "\-sectobjectsymbols" " segname sectname" " (32-bit only)"
+This causes the link editor to generate local symbols in the section
+.I sectname
+in the segment
+.IR segname .
+Each object file that has one of these sections will have a local
+symbol created
+whose name is that of the object file, or of the member of the archive.
+The symbol's value will be the first address where that object file's section
+was loaded. The symbol has the type N_SECT and its section number is the
+the same as that of the section
+.I (segname,sectname)
+in the output file.
+This symbol will be placed in the symbol table just before all other local
+symbols
+for the object file. This feature is typically used where the section is
+.SM (\_\^\_TEXT,\_\^\_text),
+in order to help the debugger debug object files produced by old versions of
+the compiler or by non-Apple compilers.
+
+.PP
+The following flags are related to name spaces:
+.TP
+.B \-twolevel_namespace
+Specifies the output to be built as a two-level namespace image.
+This option can also be specified by setting the environment variable
+.SM LD_TWOLEVEL_NAMESPACE.
+This is the default.
+.TP
+.B \-flat_namespace
+Specifies the output to be built as a flat namespace image.
+This is not the default (but was the default in MacOS X 10.0).
+.TP
+.B \-force_flat_namespace
+Specifies the executable output to be built and executed treating all its
+dynamic libraries as flat namespace images. This marks the executable so that
+the dynamic link editor treats all dynamic libraries as flat namespace
+images when the program is executed.
+.TP
+.BI \-bundle_loader " executable" " (32-bit only)"
+This specifies the
+.I executable
+that will be loading the bundle output file being linked. Undefined symbols
+from the bundle are checked against the specified executable like it was one of
+the dynamic libraries the bundle was linked with. If the bundle being created
+with
+.B \-twolevel_namespace
+in effect then the searching of the executable for
+symbols is based on the placement of the
+.B \-bundle_loader
+flag relative to the dynamic libraries. If the the bundle being created with
+.B \-flat_namespace
+then the searching of the executable is done before all dynamic libraries.
+.TP
+.B \-private_bundle (32-bit only)
+This allows symbols defined in the output to also be defined in executable in
+the
+.B \-bundle_loader
+argument
+when
+.B \-flat_namespace
+is in effect.
+This implies that the bundle output file being created is going to be loaded by
+the executable with the
+.B NSLINKMODULE_OPTION_PRIVATE
+option to
+.IR NSLinkModule (3).
+.TP
+.B \-twolevel_namespace_hints (32-bit only)
+Specifies to create the output with the two-level namespace hints table to be
+used by the dynamic linker. This is the default except when the
+.B \-bundle
+flag is specified. If this is used when the
+.B \-bundle
+flag is specified the bundle will fail to load on a MacOS X 10.0 system with a
+malformed object error.
+.TP
+.BI \-multiply_defined " treatment" " (32-bit only)"
+Specifies how multiply defined symbols in dynamic libraries when
+.B \-twolevel_namespace
+is in effect are to be treated.
+.I treatment
+can be:
+.I error,
+.I warning,
+or
+.I suppress.
+Which cause the treatment of multiply defined symbols in dynamic libraries
+as either, errors, warnings, or suppresses the checking of multiply symbols
+from dynamic libraries when
+.B \-twolevel_namespace
+is in effect.
+The default is to treat multiply defined symbols in dynamic libraries as
+warnings when
+.B \-twolevel_namespace
+is in effect.
+.TP
+.BI \-multiply_defined_unused " treatment" " (32-bit only)"
+Specifies how unused multiply defined symbols in dynamic libraries when
+.B \-twolevel_namespace
+is in effect are to be treated.
+An unused multiply defined symbol is one in which there is a symbol defined in
+the output that is also defined in the dynamic libraries the output is linked
+with but the symbol in the dynamic library is not used by any reference in the
+output.
+.I treatment
+can be:
+.I error,
+.I warning,
+or
+.I suppress.
+The default for unused multiply defined symbols is to suppress these messages.
+.TP
+.B -nomultidefs (32-bit only)
+specifying this flag marks the umbrella being created such that the dynamic
+linker is guaranteed that no multiple definitions of symbols in the umbrella's
+sub-images will ever exist. This allows the dynamic linker to always use the
+two-level namespace lookup hints even if the timestamps of the sub-images
+do not match. This flag implies
+.BI \-multiply_defined " error".
+
+.PP
+The following flags are related to symbols. These flags' arguments
+are external symbols whose names have `_' prepended to the C,
+.SM FORTRAN,
+or Pascal variable name.
+.TP
+.BI \-y sym " (32-bit only)"
+Display each file in which
+.I sym
+appears, its type, and whether the file defines or references it. Any
+multiply defined symbols are automatically
+traced. Like most of the other symbol-related flags,
+.B \-y
+takes only one argument; the flag may be specified more than once in the
+command line to trace more than one symbol.
+.TP
+.BI \-Y " number" " (32-bit only)"
+For the first
+.I number
+undefined symbols, displays each file in which the symbol appears, its type and whether the file defines or references it (that is, the same style of output produced by the
+.B \-y
+option). To keep the output manageable, this option displays at most
+.I number
+references.
+.TP
+.B \-keep_private_externs
+Don't turn private external symbols into static symbols, but rather leave them
+as private external in the resulting output file.
+.TP
+.B \-m (32-bit only)
+Don't treat multiply defined symbols from the linked objects as a hard error;
+instead, simply print a warning. The first linked object defining such a symbol
+is used for linking; its value is used for the symbol in the symbol table. The
+code and data for all such symbols are copied into the output. The duplicate
+symbols other than the first symbol may still end up being used in the resulting
+output file through local references. This can still produce a resulting output
+file that is in error. This flag's use is strongly discouraged!
+.TP
+.B \-whyload (32-bit only)
+Indicate why each member of a library is loaded. In other words, indicate
+which currently undefined symbol is being resolved, causing that
+member to be loaded. This in combination with the above
+.BI \-y sym
+flag can help determine exactly why a link edit is failing due to multiply
+defined symbols.
+.B
+.TP
+.BI \-u " sym"
+Enter the argument
+.I sym
+into the symbol table as an undefined symbol. This is useful
+for loading wholly from a library, since initially the symbol
+table is empty and an unresolved reference is needed
+to force the loading of the first object file.
+.TP
+.BI \-e " sym"
+The argument
+.I sym
+is taken to be the symbol name of the entry point of
+the resulting file. By default, the entry point is the address of the
+first section in the first segment.
+.TP
+.BI \-i definition:indirect " (32-bit only)"
+Create an indirect symbol for the symbol name
+.I definition
+which is defined to be the same as the symbol name
+.I indirect
+(which is taken to be undefined). When a definition of the symbol named
+.I indirect
+is linked, both symbols will take on the defined type and value.
+.IP
+This option overlaps with a compiler option.
+If you use the compiler driver
+.IR cc (1)
+to invoke \fIld\fR,
+invoke this option in this way:
+.BI \-Wl,\-i definition:indirect.
+
+.TP
+.BI \-undefined " treatment"
+Specifies how undefined symbols are to be treated.
+.I treatment
+can be:
+.I error,
+.I warning,
+or
+.I suppress.
+Which cause the treatment of undefined symbols as either, errors, warnings, or
+suppresses the checking of undefined symbols.
+The default is to treat undefined symbols as errors.
+When the environment variable
+.B MACOSX_DEPLOYMENT_TARGET
+is set to
+.B 10.3
+or higher then
+.BI \-undefined " dynamic_lookup"
+can also be used to allow any undefined symbols to be looked up dynamically at
+runtime. Use of a binary built with this flag requires a system with a dynamic
+linker from Mac OS X 10.3 or later.
+The flag
+.BI \-undefined " define_a_way"
+can also be used to cause the static linker to create a private definition for
+all undefined symbols. This flag should only be used if it is known that the
+undefined symbols are not referenced as any use of them may cause a crash.
+.TP
+.BI \-U " sym"
+Allow the symbol
+.I sym
+to be undefined, even if the
+.B \-r
+flag is not given. Produce an executable file if the only undefined
+symbols are those specified with
+.BR \-U.
+.IP
+This option overlaps with a compiler option.
+If you use the compiler driver
+.IR cc (1)
+to invoke \fIld\fR,
+invoke this option in this way:
+.BI \-Wl,\-U, sym.
+.TP
+.B \-bind_at_load
+Causes the output file to be marked such that the dynamic linker will bind all
+undefined references when the file is loaded or launched.
+.TP
+.BI \-commons " treatment" " (64-bit only)"
+Specifies how common symbols (tentative defintions) from object files interact with dynamic libraries.
+.I treatment
+can be:
+.I ignore_dylibs,
+.I use_dylibs,
+or
+.I error.
+The default is ignore_dylibs
+which means the static linker will use a common defintion from an object file even if a true definition
+exisits in a dynamic library. If you want your code to use a dynamic library definition, then add
+the extern keyword to your tentative definition (e.g. change
+.I int foo;
+to
+.I extern int foo;
+). The treatment use_dylibs means a definition form a dynamic library should override a common symbol
+in an object file. Note, the 32-bit linker always uses this treatment.
+The treatment error means the linker should abort whenever if finds a common symbol in
+an object file and an external definition with the same name in a dynamic library.
+.TP
+.B \-warn_commons (64-bit only)
+Causes the static linker to write a diagnostic line about how common symbols were processed. This is
+useful for debugging problems with common symbols.
+
+.PP
+The following flags are related to stripping link edit information.
+This information can also be removed by
+.IR strip (1),
+which uses the same options. (The
+exception is the
+.B \-s
+flag below, but this is the same as
+.IR strip (1)
+with no arguments.)
+The following flags are listed in decreasing level of stripping.
+.TP
+.B \-s (32-bit only)
+Completely strip the output; that is, remove the symbol table
+and relocation information.
+.TP
+.B \-x (32-bit only)
+Strips the non-global symbols; only saves external symbols.
+.IP
+This option overlaps with a compiler option.
+If you use the compiler driver
+.IR cc (1)
+to invoke \fIld\fR,
+invoke this option in this way:
+.B \-Wl,\-x.
+.TP
+.B \-S (32-bit only)
+Strip debugging symbols; only save local and global symbols.
+.TP
+.B \-X (32-bit only)
+Strip local symbols whose names begin with `L'; save all other symbols.
+(The compiler and assembler currently strip these internally-generated
+labels by default, so they generally do not appear in object files
+seen by the link editor.)
+.TP
+.B \-Sp
+Strip, edit and add debugging symbols so the debugger can used most of the
+debugging symbols from the object files.
+.TP
+.B \-Si (32-bit only)
+Strip duplicate debugging symbols from include files. This is
+the default.
+.TP
+.B \-b (32-bit only)
+Strip the base file's symbols from the output file. (The base file
+is given as the argument to the
+.B \-A
+option.)
+.IP
+This option overlaps with a compiler option.
+If you use the compiler driver
+.IR cc (1)
+to invoke \fIld\fR,
+invoke this option in this way:
+.B \-Wl,\-b.
+.TP
+.B \-Sn (32-bit only)
+Don't strip any symbols.
+.TP
+.BI \-exported_symbols_list " filename"
+The specified
+.I filename
+contains lists of global symbol names that will remain as global symbols in the
+output file. All other global symbols will be treated as if they were marked as
+.I __private_extern__
+and will not be global in the output file. The symbol names listed in
+.I filename
+must be one per line. Leading and trailing white space are not part of the
+symbol name. Lines starting with # are ignored, as are lines with only white
+space.
+.TP
+.BI \-unexported_symbols_list " filename"
+The specified
+.I filename
+contains lists of global symbol names that will not remain as global symbols in
+the output file. The symbols will be treated as if they were marked as
+.I __private_extern__
+and will not be global in the output file. The symbol names listed in
+.I filename
+must be one per line. Leading and trailing white space are not part of the
+symbol name. Lines starting with # are ignored, as are lines with only white
+space.
+.TP
+.BI \-no_uuid
+Do not emit an LC_UUID load command in the linked output file.
+
+.TP
+.B -dead_strip (32-bit only)
+Remove blocks of code and data that are unreachable by the entry point or
+exported symbols.
+.TP
+.B -no_dead_strip_inits_and_terms (32-bit only)
+When specified along with
+.B -dead_strip
+cause all constructors and destructors to never be dead stripped.
+
+.PP
+The remaining options are infrequently used:
+.TP
+.B \-v
+Print the version of the linker.
+.TP
+.B \-w (32-bit only)
+Suppresses all warning messages.
+.TP
+.B \-no_arch_warnings
+Suppresses warning messages about files that have the wrong architecture for the
+.B \-arch
+flag.
+.TP
+.B \-arch_errors_fatal (32-bit only)
+Cause the errors having to do with files that have the wrong architecture to be
+fatal and stop the link editor.
+.TP
+.B \-M (32-bit only)
+Produce a load map, listing all the segments and sections. The list
+includes the address where each input file's section appears in the
+output file, as well as the section's size.
+.IP
+This option overlaps with a compiler option.
+If you use the compiler driver
+.IR cc (1)
+to invoke \fIld\fR,
+invoke this option in this way:
+.B \-Wl,\-M.
+.TP
+.B \-whatsloaded (32-bit only)
+Display a single line listing each object file that is
+loaded. Names of objects in archives have the form libfoo.a(bar.o).
+.TP
+.BI \-filelist " listfile[,dirname]"
+Specifies that the linker should link the files listed in
+.I listfile .
+This is an alternative to listing the files on the command line. The file names are listed one per line separated
+only by newlines. (Spaces and tabs are assumed to be part of the file name.)
+If the optional directory name,
+.I dirname
+is specified, it is prepended to each name in the list file.
+.TP
+.BI "\-headerpad" " value"
+Specifies the minimum amount of space ("padding") following
+the headers for the
+.SM MH_EXECUTE
+format and all output file types with the dynamic linker.
+.I value
+is a hexadecimal number.
+When a segment's size is rounded up to the segment alignment, there
+is extra space left over, which is placed between the headers and the sections, rather than at the end of the segment. The
+.B headerpad
+option specifies the minimum size of this padding,
+which can be useful if the headers will be altered later.
+The default value is the larger of 2 * sizeof(struct section) so the program
+/usr/bin/objcunique can always add two section headers, or if the output is an
+MH_EXECUTE filetype and
+.B \-prebind
+is specified 3 times the size of the LC_PREBOUND_DYLIB load commands.
+The actual amount of pad will be as large as the amount of the first
+segment's round-off.
+(That is, take the total size of the first segments'
+headers and non-zerofill sections, round this size
+up to the segment alignment,
+and use the difference between the rounded
+and unrounded sizes as the minimum amount of padding.)
+.TP
+.B \-headerpad_max_install_names (32-bit only)
+Add to the header padding enough space to allow changing all dynamic shared
+library paths recorded in the output file to be changed to MAXPATHLEN in length.
+.TP
+.B \-t
+Trace the progress of the link editor; display the name of each file
+that is
+loaded as it is processed in the first and second pass of the link
+editor.
+.TP
+.BI \-A " basefile" " (32-bit only)"
+Incremental loading: linking is to be done in a manner
+that lets the resulting object be read into an already executing
+program, the
+.IR basefile .
+.I basefile
+is the name of a file whose symbol table will be taken as a basis
+on which to define additional symbols.
+Only newly linked material will be entered into the
+.BR a.out
+file, but the new symbol table will reflect
+every symbol defined in the base file and the newly linked files.
+Option(s) to specify the addresses of the segments are typically
+needed, since
+the default addresses tend to overlap with the
+.I basefile.
+The default format of the object file is
+.SM MH_OBJECT.
+Note: It is strongly recommended that this option NOT be used,
+because the dyld package described in
+.IR dyld (3)
+is a much easier alternative.
+.TP
+.BI \-dylib_install_name " name"
+For dynamic shared library files, specifies the name of the file
+the library will be installed in for programs that use it. If this is not
+specified, the name specified in the
+.BI \-o " name"
+option will be used.
+This option is used as the
+.IR libtool (1)
+.BI \-install_name " name"
+option when its
+.B \-dynamic
+option is specified.
+.TP
+.BI \-umbrella " framework_name"
+Specifies this is a subframework where
+.I framework_name
+is the name of the umbrella framework this subframework is a part of. Where
+.I framework_name
+is the same as the argument to the
+.BI \-framework " framework_name"
+option. This subframework can then only be linked into the umbrella framework
+with the same
+.I framework_name
+or another subframework with the same umbrella framework name. Any other
+attempt to statically link this subframework directly will result in an error
+stating to link with the umbrella framework instead. When building the umbrella
+framework that uses this subframework no additional options are required.
+However the install name of the umbrella framework, required to be specified
+with
+.BR \-dylib_install_name ,
+must have the proper format for an install name of a framework for the
+.I framework_name
+of the umbrella framework to be determined.
+.TP
+.BI \-allowable_client " client_name" " (32-bit only)"
+Specifies that for this subframework the
+.I client_name
+can link with this subframework without error even though it is not part of
+the umbrella framework that this subframework is part of. The
+.I client_name
+can be another framework name or a name used by bundles (see the
+.BI \-client_name " client_name"
+option below).
+.TP
+.BI \-client_name " client_name" " (32-bit only)"
+Specifies the
+.I client_name
+of a bundle for checking of allowable clients of subframeworks (see the
+.BI \-allowable_client " client_name"
+option above).
+.TP
+.BI \-sub_umbrella " framework_name"
+Specifies that the
+.I framework_name
+being linked by a dynamic library is to be treated as one of the
+subframeworks with respect to twolevel namespace.
+.TP
+.BI \-sub_library " library_name"
+Specifies that the
+.I library_name
+being linked by a dynamic library is to be treated as one of the
+sublibraries with respect to twolevel namespace. For example the
+.I library_name
+for
+.I /usr/lib/libobjc_profile.A.dylib
+would be
+.I libobjc.
+.TP
+.BI \-init " sym"
+The argument
+.I sym
+is taken to be the symbol name of the dynamic shared library initialization
+routine. If any module is used from the dynamic library the library
+initialization routine is called before any symbol is used from the library
+including C++ static initializers (and #pragma CALL_ON_LOAD routines).
+.TP
+.B \-run_init_lazily (32-bit only)
+This option is obsolete.
+.TP
+.BI \-dylib_compatibility_version " number"
+For dynamic shared library files, this specifies the compatibility version number
+of the library. When a library is used by a program, the compatibility version is checked
+and if the program's version is greater that the library's version, it is an error.
+The format of
+.I number
+is
+.I X[.Y[.Z]]
+where
+.I X
+must be a positive non-zero number less than or equal to 65535, and
+.I .Y
+and
+.I .Z
+are optional and if present must be non-negative numbers less than or
+equal to 255.
+If the compatibility version number is not specified, it has a
+value of 0 and no checking is done when the library is used.
+This option is used as the
+.IR libtool (1)
+.BI \-compatibility_version " number"
+option
+when its
+.B \-dynamic
+option is set.
+.TP
+.BI \-dylib_current_version " number"
+For dynamic shared library files, specifies the current version number
+of the library. The current version of the library can be obtained
+programmatically by the user of the library so it can determine exactly which version of the library it is using.
+The format of
+.I number
+is
+.I X[.Y[.Z]]
+where
+.I X
+must be a positive non-zero number less than or equal to 65535, and
+.I .Y
+and
+.I .Z
+are optional and if present must be non-negative numbers less than or
+equal to 255.
+If the version number is not specified, it has a
+value of 0.
+This option is used as the
+.IR libtool (1)
+.BI \-current_version " number"
+option when its
+.B \-dynamic
+option is set.
+.TP
+.BI \-single_module
+When building a dynamic library build the library so that it contains only
+one module.
+.TP
+.BI \-multi_module (32-bit only)
+When building a dynamic library build the library so that it contains one
+module for each object file linked in. This is the default.
+.TP
+.BI \-dylinker_install_name " name"
+For dynamic link editor files, specifies the name of the file
+the dynamic link editor will be installed in for programs that use it.
+.TP
+.BI \-macosx_version_min " version"
+This overrides the
+.B MACOSX_DEPLOYMENT_TARGET
+environment variable (see below). Unlike other linker options, this one may
+be specified multiple times; only the last occurrence is effective.
+.PP
+The following environment variable is used to control the use of incompatible
+features in the output with respect to Mac OS X releases.
+.TP
+.B MACOSX_DEPLOYMENT_TARGET
+This is set to indicate the oldest Mac OS X version that that the output is to
+be used on. When this is set to a release that is older than the current
+release features that are incompatible with that release will be disabled. If
+a feature is seen in the input that can't be in the output due to this setting
+a warning is issued. The current allowable values for this are
+.B 10.1,
+.B 10.2
+.B 10.3,
+and
+.B 10.4
+with the default being
+.B 10.4
+for the i386 architecture and
+.B 10.1
+for all other architectures.
+.PP
+The following environment variables are used by Apple's Build and Integration
+team:
+.TP
+.B LD_TRACE_ARCHIVES
+When this is set it causes a message of the form ``[Logging for XBS]
+Used static archive:
+.I filename''
+for each static archive that has members linked into the output.
+.TP
+.B LD_TRACE_DYLIBS
+When this is set it causes a message of the form ``[Logging for XBS]
+Used dynamic library:
+.I filename''
+for each dynamic library linked into the output.
+.TP
+.B RC_TRACE_PREBINDING_DISABLED
+When this is set it causes a message of the form ``[Logging for XBS
+prebinding disabled for
+.I filename
+because
+.I reason''.
+Where
+.I filename
+is the value of the
+.B \-final_output
+argument if specified or the value of the
+.B \-o
+argument.
+.TP
+.BI \-final_output " filename"
+The argument
+.I filename
+is used in the above message when RC_TRACE_PREBINDING_DISABLED is set.
+.TP
+.B LD_TRACE_FILE
+When this is set, messages displayed due to the
+.B LD_TRACE_ARCHIVES
+,
+.B LD_TRACE_DYLIBS
+, and
+.B LD_TRACE_PREBINDING_DISABLED
+environment variables are printed to the file whose path is specified
+by this variable instead of stdout.
+.TP
+.B LD_SPLITSEGS_NEW_LIBRARIES
+When set and
+.B MACOSX_DEPLOYMENT_TARGET
+is set to 10.4 or greater and the output is a dynamic library, and if the
+install name of the library is not listed the segment address table, and if the
+environment variable
+.B LD_UNPREBOUND_LIBRARIES
+is set with a file name with a list of library install names and the install
+name is not listed, then this is built as a split shared library.
+
+.PP
+Options available in early versions of the Mach-O link editor
+may no longer be supported.
+
+.SH FILES
+.ta \w'/Network/Library/Frameworks/*.framework/*\ \ 'u
+/lib/lib*.{a,dylib} libraries
+.br
+/usr/lib/lib*.{a,dylib}
+.br
+/usr/local/lib/lib*.{a,dylib}
+.br
+/Library/Frameworks/*.framework/* framework libraries
+.br
+/Network/Library/Frameworks/*.framework/* framework libraries
+.br
+/System/Library/Frameworks/*.framework/* framework libraries
+.br
+a.out output file
+.SH "SEE ALSO"
+as(1), ar(1), cc(1), libtool(1), ranlib(1), nm(1), otool(1) lipo(1),
+arch(3), dyld(3), Mach-O(5), strip(1), redo_prebinding(1)
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 */; };
F9B1A2640A3A563E00DA8FAB /* rebase.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = F9B1A2580A3A448800DA8FAB /* rebase.1 */; };
F9C0D4BD06DD28D2001C7193 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9C0D48A06DD1E1B001C7193 /* Options.cpp */; };
F9EA72D5097454FF008B4F1D /* machochecker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9EA72D4097454FF008B4F1D /* machochecker.cpp */; };
F9EA7584097882F3008B4F1D /* debugline.c in Sources */ = {isa = PBXBuildFile; fileRef = F9EA7582097882F3008B4F1D /* debugline.c */; };
F9EA75BC09788857008B4F1D /* debugline.c in Sources */ = {isa = PBXBuildFile; fileRef = F9EA7582097882F3008B4F1D /* debugline.c */; };
F9EC78060A2F8674002A3E39 /* rebase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9EC78050A2F8674002A3E39 /* rebase.cpp */; };
+ F9FCC3F20A54A75600CEB866 /* ld64.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = F9FCC3F10A54A75600CEB866 /* ld64.1 */; };
/* End PBXBuildFile section */
/* Begin PBXBuildRule section */
isa = PBXContainerItemProxy;
containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = F9EC77ED0A2F85F6002A3E39 /* rebase */;
+ remoteGlobalIDString = F9EC77ED0A2F85F6002A3E39;
remoteInfo = rebase;
};
F96D5369094A275D008E9EE8 /* PBXContainerItemProxy */ = {
dstPath = /usr/share/man/man1;
dstSubfolderSpec = 0;
files = (
- F97F5029070D0BB200B9FCD7 /* ld64.1 in CopyFiles */,
+ F9FCC3F20A54A75600CEB866 /* ld64.1 in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 1;
};
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>"; };
+ F97F5028070D0BB200B9FCD7 /* ld.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = ld.1; path = doc/man/man1/ld.1; sourceTree = "<group>"; };
F9B1A2580A3A448800DA8FAB /* rebase.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = rebase.1; path = doc/man/man1/rebase.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>"; };
F9EA7583097882F3008B4F1D /* debugline.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = debugline.h; path = src/debugline.h; sourceTree = "<group>"; };
F9EC77EE0A2F85F6002A3E39 /* rebase */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rebase; sourceTree = BUILT_PRODUCTS_DIR; };
F9EC78050A2F8674002A3E39 /* rebase.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = rebase.cpp; path = src/rebase.cpp; sourceTree = "<group>"; };
+ F9FCC3F10A54A75600CEB866 /* ld64.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = ld64.1; path = doc/man/man1/ld64.1; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
F9EA72D4097454FF008B4F1D /* machochecker.cpp */,
F971EED706D5AD240041D381 /* ObjectDump.cpp */,
F9EC78050A2F8674002A3E39 /* rebase.cpp */,
- F97F5028070D0BB200B9FCD7 /* ld64.1 */,
+ F97F5028070D0BB200B9FCD7 /* ld.1 */,
+ F9FCC3F10A54A75600CEB866 /* ld64.1 */,
F9B1A2580A3A448800DA8FAB /* rebase.1 */,
F9023C3A06D5A23E001BBF46 /* Products */,
);
F9023C3006D5A227001BBF46 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = F933D92309291AC90083EAC8 /* Build configuration list for PBXProject "ld64" */;
+ compatibilityVersion = "Xcode 2.4";
hasScannedForEncodings = 0;
mainGroup = F9023C2C06D5A227001BBF46;
productRefGroup = F9023C3A06D5A23E001BBF46 /* Products */;
projectDirPath = "";
+ projectRoot = "";
+ shouldCheckCompatibility = 1;
targets = (
F9B1A2670A3A567B00DA8FAB /* all */,
F9023C3806D5A23E001BBF46 /* ld */,
);
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";
+ shellScript = "# Let tests set MACOSX_DEPLOYMENT_TARGET as they need\nunsetenv MACOSX_DEPLOYMENT_TARGET\n\n# always use new linker\nsetenv LD_NO_CLASSIC_LINKER\n\n# run full test suite\n$SRCROOT/unit-tests/run-all-unit-tests\n\nexit 0";
};
/* End PBXShellScriptBuildPhase section */
INSTALL_PATH = /usr/bin;
OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
OTHER_LDFLAGS = "";
+ PREBINDING = NO;
PRODUCT_NAME = ld64;
SECTORDER_FLAGS = "";
VERSIONING_SYSTEM = "apple-generic";
INSTALL_PATH = /usr/bin;
OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
OTHER_LDFLAGS = "";
+ PREBINDING = NO;
PRODUCT_NAME = ld64;
SECTORDER_FLAGS = "";
VALID_ARCHS = "i386 ppc";
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 ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
virtual void copyRawContent(uint8_t buffer[]) const {}
virtual void setScope(Scope) { }
+class ReferenceSorter
+{
+public:
+ bool operator()(const ObjectFile::Reference* left, const ObjectFile::Reference* right)
+ {
+ return ( left->getFixUpOffset() < right->getFixUpOffset() );
+ }
+};
+
+
// forward reference
template <typename A> class Reader;
template <typename A> class SymbolAtomSorter;
virtual void setSize(uint64_t size) = 0;
virtual void addReference(ObjectFile::Reference* ref) = 0;
+ virtual void sortReferences() = 0;
virtual void addLineInfo(const ObjectFile::LineInfo& info) = 0;
- virtual void alignAtLeast(uint8_t align) = 0;
uint32_t fStabsStartIndex;
uint32_t fStabsCount;
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 ObjectFile::Alignment getAlignment() const { return fAlignment; }
virtual void copyRawContent(uint8_t buffer[]) const;
virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
- virtual void setSize(uint64_t size);
- virtual void addReference(ObjectFile::Reference* ref) { fReferences.insert(fReferences.begin(), (Reference<A>*)ref); }
+ virtual void setSize(uint64_t size) { fSize = size; }
+ virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
+ virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
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;
std::vector<ObjectFile::LineInfo> fLineInfo;
ObjectFile::Atom::Scope fScope;
SymbolTableInclusion fSymbolTableInclusion;
- uint8_t fAlignment;
+ ObjectFile::Alignment fAlignment;
};
else {
fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
}
-}
-
-
-template <typename A>
-void SymbolAtom<A>::setSize(uint64_t size)
-{
- fSize = size;
-
- if ( fSection->flags() & S_ATTR_SOME_INSTRUCTIONS ) {
- // For code, the aligment is based just on the section alignment and code address
- if ( fAddress == 0 )
- fAlignment = fSection->align();
- else
- fAlignment = std::min((uint8_t)__builtin_ctz(fAddress), (uint8_t)fSection->align());
- }
- else {
- // For data, 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);
- }
+ // compute alignment
+ fAlignment = ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
}
}
}
-
template <typename A>
class SymbolAtomSorter
{
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 ObjectFile::Alignment getAlignment() const;
virtual void copyRawContent(uint8_t buffer[]) const;
virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
virtual void setSize(uint64_t size) { }
virtual void addReference(ObjectFile::Reference* ref) { throw "ld64: can't add references"; }
+ virtual void sortReferences() { }
virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld64: can't add line info to tentative definition"; }
- virtual void alignAtLeast(uint8_t align) { }
protected:
typedef typename A::P P;
template <typename A>
-uint8_t TentativeAtom<A>::getAlignment() const
+ObjectFile::Alignment TentativeAtom<A>::getAlignment() const
{
// common symbols align to their size
// that is, a 4-byte common aligns to 4-bytes
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;
+ return ObjectFile::Alignment(alignment);
else
- return 15;
+ return ObjectFile::Alignment(15);
}
template <typename A>
virtual bool requiresFollowOnAtom() const;
virtual ObjectFile::Atom& getFollowOnAtom() const;
virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
- virtual uint8_t getAlignment() const;
+ virtual ObjectFile::Alignment getAlignment() const;
virtual void copyRawContent(uint8_t buffer[]) const;
virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
virtual void setSize(uint64_t size) { fSize = size; }
- virtual void addReference(ObjectFile::Reference* ref) { fReferences.insert(fReferences.begin(), (Reference<A>*)ref); }
+ virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
+ virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
virtual void addLineInfo(const ObjectFile::LineInfo& info) { fprintf(stderr, "ld64: can't add line info to anonymous symbol %s from %s\n", this->getDisplayName(), this->getFile()->getPath()); }
- virtual void alignAtLeast(uint8_t align) { }
BaseAtom* redirectTo() { return fRedirect; }
bool isWeakImportStub() { return fWeakImportStub; }
BaseAtom* fRedirect;
bool fDontDeadStrip;
bool fWeakImportStub;
- bool fReallyNonLazyPointer; // HACK until compiler stops emitting anonymous non-lazy pointers
ObjectFile::Atom::SymbolTableInclusion fSymbolTableInclusion;
ObjectFile::Atom::Scope fScope;
};
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), fDontDeadStrip(true),
- fWeakImportStub(false), fReallyNonLazyPointer(false), fSymbolTableInclusion(ObjectFile::Atom::kSymbolTableNotIn),
+ fWeakImportStub(false), fSymbolTableInclusion(ObjectFile::Atom::kSymbolTableNotIn),
fScope(ObjectFile::Atom::scopeTranslationUnit)
{
fSegment = new Segment<A>(fSection);
template <typename A>
ObjectFile::Atom::Scope AnonymousAtom<A>::getScope() const
{
- if ( fReallyNonLazyPointer )
- return ObjectFile::Atom::scopeTranslationUnit;
- else
- return fScope;
+ return fScope;
}
template <typename A>
ObjectFile::Atom::DefinitionKind AnonymousAtom<A>::getDefinitionKind() const
{
- if ( fReallyNonLazyPointer )
- return ObjectFile::Atom::kRegularDefinition;
// in order for literals to be coalesced they must be weak
switch ( fSection->flags() & SECTION_TYPE ) {
case S_CSTRING_LITERALS:
}
template <typename A>
-uint8_t AnonymousAtom<A>::getAlignment() const
+ObjectFile::Alignment AnonymousAtom<A>::getAlignment() const
{
- if ( fReallyNonLazyPointer )
- return (uint8_t)log2(sizeof(pint_t));
switch ( fSection->flags() & SECTION_TYPE ) {
case S_4BYTE_LITERALS:
- return 2;
+ return ObjectFile::Alignment(2);
case S_8BYTE_LITERALS:
- return 3;
+ return ObjectFile::Alignment(3);
case S_16BYTE_LITERALS:
- return 4;
+ return ObjectFile::Alignment(4);
case S_NON_LAZY_SYMBOL_POINTERS:
- return (uint8_t)log2(sizeof(pint_t));
+ return ObjectFile::Alignment((uint8_t)log2(sizeof(pint_t)));
default:
- return fSection->align();
+ return ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
}
}
Reference<A>* makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect);
Reference<A>* makeReferenceToSymbol(Kinds kind, uint32_t atAddr, const macho_nlist<P>* toSymbol, uint32_t toOffset);
void validSectionType(uint8_t type);
- void handleAnonymousNonLazyPointers(const macho_section<P>* sect);
BaseAtom* findAtomByName(const char*);
bool fAppleObjc;
};
-// usually do nothing
-template <typename A> void Reader<A>::handleAnonymousNonLazyPointers(const macho_section<P>* sect) { }
-
-// HACK for ppc64, need to split of anonymous non-lazy-pointers because they must be 8-byte aligned to work with ld instruction
-template <> void
-Reader<ppc64>::handleAnonymousNonLazyPointers(const macho_section<P>* dataSect) {
- if ( (dataSect->size() >= sizeof(pint_t))
- && (dataSect->align() >= log2(sizeof(pint_t)))
- && (strcmp(dataSect->sectname(), "__data") == 0)
- && (strcmp(dataSect->segname(), "__DATA") == 0) ) {
- std::set<uint32_t> lo14targets;
- 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()];
- for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
- if ( strncmp(sect->sectname(), "__text", 6) == 0 ) {
- 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 ) {
- const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)r;
- if ( sreloc->r_type() == PPC_RELOC_LO14_SECTDIFF ) {
- lo14targets.insert(sreloc->r_value());
- }
- }
- }
- }
- }
- // walk backwards so that newly created anonymous atoms do not mask misalignmented
- for (std::set<uint32_t>::reverse_iterator it=lo14targets.rbegin(); it != lo14targets.rend(); it++) {
- uint32_t targetOfLO14 = *it;
- AtomAndOffset found = this->findAtomAndOffset(targetOfLO14);
- if ( (found.offset & 0x7) != 0 ) {
- AnonymousAtom<ppc64>* newAtom = new AnonymousAtom<ppc64>(*this, dataSect, targetOfLO14, sizeof(pint_t));
- newAtom->fReallyNonLazyPointer = true;
- fAtoms.push_back(newAtom);
- fAddrToAtom[targetOfLO14] = newAtom;
- }
- }
- }
-}
-
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),
case S_REGULAR:
case S_ZEROFILL:
case S_COALESCED:
- // HACK until compiler stops generated anonymous non-lazy pointers rdar://problem/4513414
- handleAnonymousNonLazyPointers(sect);
// if there is not an atom already at the start of this section, add an anonymous one
uint32_t previousAtomAddr = 0;
BaseAtom* previousAtom = NULL;
uint32_t classSize = ((12 * sizeof(pint_t)) + align-1) & (-align);
for (uint32_t offset = 0; offset < sect->size(); offset += classSize) {
// add by-name reference to super class
- uint32_t superClassNameAddr = P::getP(*(pint_t*)(((uint8_t*)fHeader) + sect->offset() + offset + sizeof(pint_t)));
- const char* superStr = (char*)(fHeader) + sect->offset() + superClassNameAddr - sect->addr();
- const char* superClassName;
- asprintf((char**)&superClassName, ".objc_class_name_%s", superStr);
- makeByNameReference(A::kNoFixUp, sect->addr()+offset+sizeof(pint_t), superClassName, 0);
+ pint_t superClassNameAddr = P::getP(*(pint_t*)(((uint8_t*)fHeader) + sect->offset() + offset + sizeof(pint_t)));
+ if ( superClassNameAddr != 0 ) {
+ const char* superStr = (char*)(fHeader) + sect->offset() + superClassNameAddr - sect->addr();
+ const char* superClassName;
+ asprintf((char**)&superClassName, ".objc_class_name_%s", superStr);
+ makeByNameReference(A::kNoFixUp, sect->addr()+offset+sizeof(pint_t), superClassName, 0);
+ }
}
}
else if ( (strcmp(sect->sectname(), "__cls_refs") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) {
uint32_t curAtomAddress = 0;
uint32_t curAtomSize = 0;
while ( line_next (lines, &result, line_stop_pc) ) {
+ // work around weird debug line table compiler generates if no functions in __text section
+ if ( (curAtom == NULL) && (result.pc == 0) && result.end_of_sequence && (result.file == 1))
+ continue;
// for performance, see if in next pc is in current atom
if ( (curAtom != NULL) && (curAtomAddress <= result.pc) && (result.pc < (curAtomAddress+curAtomSize)) ) {
curAtomOffset = result.pc - curAtomAddress;
stab.string = symString;
}
}
+ else {
+ // might be a debug-note without trailing :G()
+ currentAtom = findAtomByName(symString);
+ if ( currentAtom != NULL ) {
+ stab.atom = currentAtom;
+ stab.string = symString;
+ }
+ }
if ( stab.atom == NULL ) {
fprintf(stderr, "can't find atom for N_GSYM stabs %s in %s\n", symString, path);
useStab = false;
}
}
-
+ // sort references in each atom
+ for (std::vector<ObjectFile::Atom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
+ BaseAtom* atom = (BaseAtom*)(*it);
+ atom->sortReferences();
+ }
+
#if 0
// special case precompiled header .o file (which has no content) to have one empty atom
if ( fAtoms.size() == 0 ) {
}
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(3);
+ makeReference(A::kAbsLow14, srcAddr, dstAddr);
}
}
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(3);
+ makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
}
break;
case PPC_RELOC_HA16_SECTDIFF:
uint64_t dstAddr = 0;
uint64_t addend;
uint32_t* fixUpPtr;
- x86_64::ReferenceKinds kind;
+ x86_64::ReferenceKinds kind = x86_64::kNoFixUp;
bool result = false;
const macho_nlist<P>* targetSymbol = NULL;
const char* targetName = NULL;
case X86_64_RELOC_SIGNED_2:
case X86_64_RELOC_SIGNED_4:
if ( ! reloc->r_pcrel() )
- throw "not pcrel and X86_64_RELOC_SIGNED not supported";
+ throw "not pcrel and X86_64_RELOC_SIGNED* not supported";
if ( reloc->r_length() != 2 )
- throw "length != 2 and X86_64_RELOC_SIGNED not supported";
- kind = x86_64::kPCRel32;
- dstAddr = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
- switch ( reloc->r_type() ) {
- case X86_64_RELOC_SIGNED:
- if ( reloc->r_extern() ) {
- // Support older relocations
- if ( dstAddr == (uint64_t)(-1) ) {
+ throw "length != 2 and X86_64_RELOC_SIGNED* not supported";
+ addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
+ if ( reloc->r_extern() ) {
+ switch ( reloc->r_type() ) {
+ case X86_64_RELOC_SIGNED:
+ kind = x86_64::kPCRel32;
+ // begin support for old .o files before X86_64_RELOC_SIGNED_1 was created
+ if ( addend == (uint64_t)(-1) ) {
+ addend = 0;
kind = x86_64::kPCRel32_1;
- dstAddr = 0;
}
- else if ( dstAddr == (uint64_t)(-2) ) {
+ else if ( addend == (uint64_t)(-2) ) {
+ addend = 0;
kind = x86_64::kPCRel32_2;
- dstAddr = 0;
}
- else if ( dstAddr == (uint64_t)(-4) ) {
+ else if ( addend == (uint64_t)(-4) ) {
+ addend = 0;
kind = x86_64::kPCRel32_4;
- dstAddr = 0;
}
- }
- break;
- case X86_64_RELOC_SIGNED_1:
- if ( reloc->r_extern() ) {
- dstAddr = 0;
- } else {
- dstAddr += 1;
- }
- kind = x86_64::kPCRel32_1;
- break;
- case X86_64_RELOC_SIGNED_2:
- if ( reloc->r_extern() ) {
- dstAddr = 0;
- } else {
- dstAddr += 2;
- }
- kind = x86_64::kPCRel32_2;
- break;
- case X86_64_RELOC_SIGNED_4:
- if ( reloc->r_extern() ) {
- dstAddr = 0;
- } else {
- dstAddr += 4;
- }
- kind = x86_64::kPCRel32_4;
- break;
- default:
- break;
+ break;
+ // end support for old .o files before X86_64_RELOC_SIGNED_1 was created
+ case X86_64_RELOC_SIGNED_1:
+ kind = x86_64::kPCRel32_1;
+ addend += 1;
+ break;
+ case X86_64_RELOC_SIGNED_2:
+ kind = x86_64::kPCRel32_2;
+ addend += 2;
+ break;
+ case X86_64_RELOC_SIGNED_4:
+ kind = x86_64::kPCRel32_4;
+ addend += 4;
+ break;
+ }
+ makeReferenceToSymbol(kind, srcAddr, targetSymbol, addend);
}
- if ( reloc->r_extern() )
- makeReferenceToSymbol(kind, srcAddr, targetSymbol, dstAddr);
else {
- makeReference(kind, srcAddr, srcAddr+4+dstAddr);
- }
+ uint64_t ripRelativeOffset = addend;
+ switch ( reloc->r_type() ) {
+ case X86_64_RELOC_SIGNED:
+ dstAddr = srcAddr + 4 + ripRelativeOffset;
+ kind = x86_64::kPCRel32;
+ break;
+ case X86_64_RELOC_SIGNED_1:
+ dstAddr = srcAddr + 5 + ripRelativeOffset;
+ kind = x86_64::kPCRel32_1;
+ break;
+ case X86_64_RELOC_SIGNED_2:
+ dstAddr = srcAddr + 6 + ripRelativeOffset;
+ kind = x86_64::kPCRel32_2;
+ break;
+ case X86_64_RELOC_SIGNED_4:
+ dstAddr = srcAddr + 8 + ripRelativeOffset;
+ kind = x86_64::kPCRel32_4;
+ break;
+ }
+ makeReference(kind, srcAddr, dstAddr);
+ }
break;
case X86_64_RELOC_BRANCH:
if ( ! reloc->r_pcrel() )
void partitionIntoSections();
bool addBranchIslands();
bool addPPCBranchIslands();
- uint8_t branch24Reference();
+ bool isBranch24Reference(uint8_t kind);
void adjustLoadCommandsAndPadding();
void createDynamicLinkerCommand();
void createDylibCommands();
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 ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(2); }
virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
virtual void setScope(Scope) { }
virtual bool isZeroFill() const { return true; }
virtual uint64_t getSize() const { return fSize; }
virtual const char* getSectionName() const { return "._zeropage"; }
- virtual uint8_t getAlignment() const { return 12; }
+ virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
void setSize(uint64_t size) { fSize = size; }
private:
using WriterAtom<A>::fWriter;
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 ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
virtual const char* getSectionName() const { return "._mach_header"; }
virtual void copyRawContent(uint8_t buffer[]) 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 ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
virtual const char* getSectionName() const { return "._mach_header"; }
virtual void copyRawContent(uint8_t buffer[]) const;
private:
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 ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
private:
using WriterAtom<A>::fWriter;
typedef typename A::P P;
{
protected:
LoadCommandAtom(Writer<A>& writer, Segment& segment) : WriterAtom<A>(writer, segment) {}
+ virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
+ virtual const char* getSectionName() const { return "._load_commands"; }
static uint64_t alignedSize(uint64_t size);
};
{ 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();
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();
: 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;
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;
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;
: 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;
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;
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;
: 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;
: 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;
: 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;
: 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:
: 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;
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 ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(3); }
virtual const char* getSectionName() const { return "._section_relocs"; }
virtual void copyRawContent(uint8_t buffer[]) const;
private:
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 ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(3); }
virtual const char* getSectionName() const { return "._local_relocs"; }
virtual void copyRawContent(uint8_t buffer[]) const;
private:
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:
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 ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(3); }
virtual const char* getSectionName() const { return "._extern_relocs"; }
virtual void copyRawContent(uint8_t buffer[]) const;
private:
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;
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;
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 ObjectFile::Alignment getAlignment() 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;
StubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target, ObjectFile::Atom& lazyPointer);
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 "__stub_helper"; }
virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
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), fPadSegmentInfo(NULL), fPageZeroAtom(NULL), fLargestAtomSize(1),
+ fLoadCommandsSegment(NULL), fPadSegmentInfo(NULL), fPageZeroAtom(NULL), fSymbolTableCount(0), fLargestAtomSize(1),
fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
fSeenFollowOnReferences(false), fWritableSegmentPastFirst4GB(false), fFirstWritableSegment(NULL)
{
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
+ // It also handles the case where fFilePath file is not writable but its directory is
// And it means we don't have to truncate the file when done writing (in case new is smaller than old)
(void)unlink(fFilePath);
fFileDescriptor = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
//fprintf(stderr, "found -mdyanmic-no-pic codegen in %s in %s\n", atom->getDisplayName(), atom->getFile()->getPath());
// shrink page-zero and add pad segment to compensate
fPadSegmentInfo = new SegmentInfo();
- strcpy(fPadSegmentInfo->fName, "__4BGFILL");
+ strcpy(fPadSegmentInfo->fName, "__4GBFILL");
fPageZeroAtom->setSize(0x1000);
return;
}
currentSectionInfo = new SectionInfo();
strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
- currentSectionInfo->fAlignment = atom->getAlignment();
+ currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
currentSectionInfo->fAllZeroFill = atom->isZeroFill();
currentSectionInfo->fVirtualSection = ( (currentSectionInfo->fSectionName[0] == '.') ||
(oneSegmentCommand && (atom->getDefinitionKind()==ObjectFile::Atom::kTentativeDefinition)) && !fOptions.makeTentativeDefinitionsReal() );
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();
+ currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
// check for -sectalign override
std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
// 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();
+ uint8_t atomAlign = atom->getAlignment().powerOf2;
if ( currentSectionInfo->fAlignment < atomAlign )
currentSectionInfo->fAlignment = atomAlign;
// calculate section offset for this atom
uint64_t offset = currentSectionInfo->fSize;
uint64_t alignment = 1 << atomAlign;
- offset = ( (offset+alignment-1) & (-alignment) );
+ uint64_t currentModulus = (offset % alignment);
+ uint64_t requiredModulus = atom->getAlignment().modulus;
+ if ( currentModulus != requiredModulus ) {
+ if ( requiredModulus > currentModulus )
+ offset += requiredModulus-currentModulus;
+ else
+ offset += requiredModulus+alignment-currentModulus;
+ }
atom->setSectionOffset(offset);
uint64_t curAtomSize = atom->getSize();
currentSectionInfo->fSize = offset + curAtomSize;
template <>
-inline uint8_t Writer<ppc>::branch24Reference()
+bool Writer<ppc>::isBranch24Reference(uint8_t kind)
{
- return ppc::kBranch24;
+ switch (kind) {
+ case ppc::kBranch24:
+ case ppc::kBranch24WeakImport:
+ return true;
+ }
+ return false;
}
template <>
-inline uint8_t Writer<ppc64>::branch24Reference()
+bool Writer<ppc64>::isBranch24Reference(uint8_t kind)
{
- return ppc64::kBranch24;
+ switch (kind) {
+ case ppc64::kBranch24:
+ case ppc64::kBranch24WeakImport:
+ return true;
+ }
+ return false;
}
//
template <typename A>
bool Writer<A>::addPPCBranchIslands()
{
+ bool log = false;
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);
+ if ( log) 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);
+ if ( log) fprintf(stderr, "ld64: checking for branch islands, __text section size=%llu\n", textSection->fSize);
break;
}
}
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() ) {
+ if ( this->isBranch24Reference(ref->getKind()) ) {
ObjectFile::Atom& target = ref->getTarget();
int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
int64_t displacement = dstAddr - srcAddr;
+ TargetAndOffset finalTargetAndOffset = { &target, ref->getTargetOffset() };
const int64_t kFifteenMegLimit = kBetweenRegions;
- if ( (displacement > kFifteenMegLimit) || (displacement < (-kFifteenMegLimit)) ) {
- for (int i=0; i < kIslandRegionsCount; ++i) {
- AtomToIsland* region=®ionsMap[i];
+ if ( displacement > kFifteenMegLimit ) {
+ // create forward branch chain
+ ObjectFile::Atom* nextTarget = ⌖
+ uint64_t nextTargetOffset = ref->getTargetOffset();
+ for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
+ AtomToIsland* region = ®ionsMap[i];
int64_t islandRegionAddr = kBetweenRegions * (i+1);
- if ( ((srcAddr < islandRegionAddr) && (dstAddr > islandRegionAddr))
- ||((dstAddr < islandRegionAddr) && (srcAddr > islandRegionAddr)) ) {
- TargetAndOffset islandTarget = { &target, ref->getTargetOffset() };
- AtomToIsland::iterator pos = region->find(islandTarget);
+ if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) {
+ AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
if ( pos == region->end() ) {
- BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, target, ref->getTargetOffset());
+ BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *nextTarget, nextTargetOffset);
island->setSection(textSection);
- (*region)[islandTarget] = island;
+ (*region)[finalTargetAndOffset] = island;
+ if (log) fprintf(stderr, "added island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
regionsIslands[i].push_back(island);
++islandCount;
- ref->setTarget(*island, 0);
+ nextTarget = island;
+ nextTargetOffset = 0;
}
else {
- ref->setTarget(*(pos->second), 0);
+ nextTarget = pos->second;
+ nextTargetOffset = 0;
}
}
}
+ if (log) fprintf(stderr, "using island %s for %s\n", nextTarget->getDisplayName(), atom->getDisplayName());
+ ref->setTarget(*nextTarget, nextTargetOffset);
+ }
+ else if ( displacement < (-kFifteenMegLimit) ) {
+ // create back branching chain
+ ObjectFile::Atom* prevTarget = ⌖
+ uint64_t prevTargetOffset = ref->getTargetOffset();
+ for (int i=0; i < kIslandRegionsCount ; ++i) {
+ AtomToIsland* region = ®ionsMap[i];
+ int64_t islandRegionAddr = kBetweenRegions * (i+1);
+ if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) {
+ AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
+ if ( pos == region->end() ) {
+ BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *prevTarget, prevTargetOffset);
+ island->setSection(textSection);
+ (*region)[finalTargetAndOffset] = island;
+ if (log) fprintf(stderr, "added back island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
+ regionsIslands[i].push_back(island);
+ ++islandCount;
+ prevTarget = island;
+ prevTargetOffset = 0;
+ }
+ else {
+ prevTarget = pos->second;
+ prevTargetOffset = 0;
+ }
+ }
+ }
+ if (log) fprintf(stderr, "using back island %s for %s\n", prevTarget->getDisplayName(), atom->getDisplayName());
+ ref->setTarget(*prevTarget, prevTargetOffset);
}
}
}
// insert islands into __text section and adjust section offsets
if ( islandCount > 0 ) {
- //fprintf(stderr, "ld64: %u branch islands required\n", islandCount);
+ if ( log) fprintf(stderr, "ld64: %u branch islands required\n", islandCount);
std::vector<ObjectFile::Atom*> newAtomList;
newAtomList.reserve(textSection->fAtoms.size()+islandCount);
uint64_t islandRegionAddr = kBetweenRegions;
+ uint64_t textSectionAlignment = (1 << textSection->fAlignment);
int regionIndex = 0;
+ uint64_t atomSlide = 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 ) {
+ uint64_t islandStartOffset = atom->getSectionOffset();
+ sectionOffset = islandStartOffset + atomSlide;
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());
+ uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
islandAtom->setSectionOffset(sectionOffset);
sectionOffset += islandAtom->getSize();
}
++regionIndex;
islandRegionAddr += kBetweenRegions;
+ uint64_t islandRegionAlignmentBlocks = (sectionOffset - islandStartOffset + textSectionAlignment - 1) / textSectionAlignment;
+ atomSlide += (islandRegionAlignmentBlocks * textSectionAlignment);
}
- uint64_t alignment = 1 << (atom->getAlignment());
- sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
- atom->setSectionOffset(sectionOffset);
- sectionOffset += atom->getSize();
+ if ( atomSlide != 0 )
+ atom->setSectionOffset(atom->getSectionOffset()+atomSlide);
}
// put any remaining islands at end of __text section
if ( regionIndex < kIslandRegionsCount ) {
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());
+ uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
islandAtom->setSectionOffset(sectionOffset);
sectionOffset += islandAtom->getSize();
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();
+ uint64_t alignment = 1 << atom->getAlignment().powerOf2;
offset = ( (offset+alignment-1) & (-alignment) );
atom->setSectionOffset(offset);
uint32_t atomSize = atom->getSize();
lastSeg->fSections[i]->setBaseAddress(address);
for (unsigned int j=0; j < atomCount; ++j) {
ObjectFile::Atom* atom = atoms[j];
- uint64_t alignment = 1 << atom->getAlignment();
+ uint64_t alignment = 1 << atom->getAlignment().powerOf2;
sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
atom->setSectionOffset(sectionOffset);
uint64_t size = atom->getSize();
return ( fWriter.fOptions.outputKind() != Options::kDynamicExecutable );
}
+template <>
+ObjectFile::Alignment StubAtom<ppc>::getAlignment() const
+{
+ return 2;
+}
+
+template <>
+ObjectFile::Alignment StubAtom<ppc64>::getAlignment() const
+{
+ return 2;
+}
template <>
StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target)
}
template <>
-uint8_t StubAtom<x86>::getAlignment() const
+ObjectFile::Alignment StubAtom<x86>::getAlignment() const
{
// special case x86 fast stubs to be byte aligned
return 0;
// x86_64 stubs are 7 bytes and need no alignment
template <>
-uint8_t StubAtom<x86_64>::getAlignment() const
+ObjectFile::Alignment StubAtom<x86_64>::getAlignment() const
{
return 0;
}
printf("size: 0x%012llX\n", atom->getSize());
// alignment
- printf("align: %d\n", atom->getAlignment());
+ printf("align: %u mod %u\n", atom->getAlignment().modulus, (1 << atom->getAlignment().powerOf2) );
// content
if ( sDumpContent ) {
};
+struct Alignment
+{
+ Alignment(int p2, int m=0) : powerOf2(p2), modulus(m) {}
+ uint8_t leadingZeros() const { return (modulus==0) ? powerOf2 : __builtin_clz(modulus); }
+ uint16_t powerOf2;
+ uint16_t modulus;
+};
//
// An atom is the fundamental unit of linking. A C function or global variable is an atom.
virtual bool requiresFollowOnAtom() const = 0;
virtual Atom& getFollowOnAtom() const = 0;
virtual std::vector<LineInfo>* getLineInfo() const = 0;
- virtual uint8_t getAlignment() const = 0;
+ virtual Alignment getAlignment() const = 0;
virtual void copyRawContent(uint8_t buffer[]) const = 0;
virtual void setScope(Scope) = 0;
fArchitecture = CPU_TYPE_I386;
else if ( strcmp(architecture, "x86_64") == 0 )
fArchitecture = CPU_TYPE_X86_64;
+ // compatibility support for cpu-sub-types
+ else if ( (strcmp(architecture, "ppc750") == 0)
+ || (strcmp(architecture, "ppc7400") == 0)
+ || (strcmp(architecture, "ppc7450") == 0)
+ || (strcmp(architecture, "ppc970") == 0) )
+ fArchitecture = CPU_TYPE_POWERPC;
else
- throw "-arch followed by unknown architecture name";
+ throwf(" unknown/unsupported architecture name for: -arch %s", architecture);
}
bool Options::checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result)
throwf("library not found for -l%s", rootName);
}
+Options::FileInfo Options::findFramework(const char* frameworkName)
+{
+ if ( frameworkName == NULL )
+ throw "-frameowrk missing next argument";
+ char temp[strlen(frameworkName)+1];
+ strcpy(temp, frameworkName);
+ const char* name = temp;
+ const char* suffix = NULL;
+ char* comma = strchr(temp, ',');
+ if ( comma != NULL ) {
+ *comma = '\0';
+ suffix = &comma[1];
+ }
+ return findFramework(name, suffix);
+}
-Options::FileInfo Options::findFramework(const char* rootName)
+Options::FileInfo Options::findFramework(const char* rootName, const char* suffix)
{
struct stat statBuffer;
- const int rootNameLen = strlen(rootName);
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];
+ char possiblePath[PATH_MAX];
strcpy(possiblePath, dir);
strcat(possiblePath, "/");
strcat(possiblePath, rootName);
strcat(possiblePath, ".framework/");
strcat(possiblePath, rootName);
+ if ( suffix != NULL ) {
+ char realPath[PATH_MAX];
+ // no symlink in framework to suffix variants, so follow main symlink
+ if ( realpath(possiblePath, realPath) != NULL ) {
+ strcpy(possiblePath, realPath);
+ strcat(possiblePath, suffix);
+ }
+ }
bool found = (stat(possiblePath, &statBuffer) == 0);
if ( fTraceDylibSearching )
printf("[Logging for XBS]%sfound framework: '%s'\n",
return result;
}
}
- throwf("framework not found %s", rootName);
+ // try without suffix
+ if ( suffix != NULL )
+ return findFramework(rootName, NULL);
+ else
+ throwf("framework not found %s", rootName);
}
Options::FileInfo Options::findFile(const char* path)
throw "-r and -dead_strip cannot be used together\n";
}
+
+
+
+
void buildSearchPaths(int argc, const char* argv[]);
void parseArch(const char* architecture);
FileInfo findLibrary(const char* rootName);
- FileInfo findFramework(const char* rootName);
+ FileInfo findFramework(const char* frameworkName);
+ FileInfo findFramework(const char* rootName, const char* suffix);
bool checkForFile(const char* format, const char* dir, const char* rootName,
FileInfo& result);
uint32_t parseVersionNumber(const char*);
void reconfigureDefaults();
-
ObjectFile::ReaderOptions fReaderOptions;
const char* fOutputFile;
std::vector<Options::FileInfo> fInputFiles;
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 4; }
+ virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(4); }
virtual void copyRawContent(uint8_t buffer[]) const;
virtual void setScope(Scope) { }
#include <string>
+#include <map>
#include <set>
#include <string>
#include <vector>
void writeDotOutput();
static bool minimizeStab(ObjectFile::Reader::Stab& stab);
static const char* truncateStabString(const char* str);
- void collectStabs();
+ void collectDebugInfo();
void writeOutput();
ObjectFile::Atom* entryPoint();
ObjectFile::Atom* dyldHelper();
const char* assureFullPath(const char* path);
void markLive(ObjectFile::Atom& atom, Linker::WhyLiveBackChain* previous);
- void collectStabs(ObjectFile::Reader* reader, std::map<class ObjectFile::Atom*, uint32_t>& atomOrdinals);
- void synthesizeStabs(ObjectFile::Reader* reader);
+ void collectStabs(ObjectFile::Reader* reader, std::map<const class ObjectFile::Atom*, uint32_t>& atomOrdinals);
+ void synthesizeDebugNotes(std::vector<class ObjectFile::Atom*>& allAtomsByReader);
void printStatistics();
void printTime(const char* msg, uint64_t partTime, uint64_t totalTime);
char* commatize(uint64_t in, char* out);
std::set<ObjectFile::Atom*> fLiveAtoms;
std::set<ObjectFile::Atom*> fLiveRootAtoms;
std::vector<class ObjectFile::Reader::Stab> fStabs;
+ std::vector<class ObjectFile::Atom*> fAtomsWithUnresolvedReferences;
bool fCreateUUID;
SectionOrder fSectionOrder;
unsigned int fNextSortOrder;
uint64_t fStartLoadUndefinesTime;
uint64_t fStartResolveTime;
uint64_t fStartSortTime;
+ uint64_t fStartDebugTime;
uint64_t fStartWriteTime;
uint64_t fEndTime;
uint64_t fTotalObjectSize;
this->sortAtoms();
this->tweakLayout();
this->writeDotOutput();
- this->collectStabs();
+ this->collectDebugInfo();
this->writeOutput();
this->printStatistics();
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(" sort output", fStartDebugTime - fStartSortTime, totalTime);
+ printTime(" process debug info", fStartWriteTime - fStartDebugTime, totalTime);
printTime(" write output", fEndTime - fStartWriteTime, totalTime);
fprintf(stderr, "pageins=%u, pageouts=%u, faults=%u\n", endVMInfo.pageins-fStartVMInfo.pageins,
endVMInfo.pageouts-fStartVMInfo.pageouts, endVMInfo.faults-fStartVMInfo.faults);
// give indirect readers a chance
for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
ObjectFile::Reader* reader = it->reader;
- if ( reader != NULL ) {
+ // for two-level namespace, only search re-exported indirect libraries
+ if ( (reader != NULL) && ((it->reExportedViaDirectLibrary != NULL) || (fOptions.nameSpace() != Options::kTwoLevelNameSpace)) ) {
std::vector<class ObjectFile::Atom*>* atoms = reader->getJustInTimeAtomsFor(name);
if ( atoms != NULL ) {
this->addAtoms(*atoms);
}
else {
// mark as undefined, for later error processing
+ fAtomsWithUnresolvedReferences.push_back(&atom);
fGlobalSymbolTable.require(targetName);
}
}
markLive(**it, &rootChain);
}
+ // it is possible that there are unresolved references that can be resolved now
+ // this can happen if the first reference to a common symbol in an archive.
+ // common symbols are not in the archive TOC, but the .o could have been pulled in later.
+ // <rdar://problem/4654131> ld64 while linking cc1 [ when dead_strip is ON]
+ for (std::vector<ObjectFile::Atom*>::iterator it=fAtomsWithUnresolvedReferences.begin(); it != fAtomsWithUnresolvedReferences.end(); it++) {
+ std::vector<class ObjectFile::Reference*>& references = (*it)->getReferences();
+ for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
+ ObjectFile::Reference* reference = *rit;
+ if ( reference->isTargetUnbound() ) {
+ ObjectFile::Atom* target = fGlobalSymbolTable.find(reference->getTargetName());
+ if ( target != NULL ) {
+ reference->setTarget(*target, reference->getTargetOffset());
+ fLiveAtoms.insert(target);
+ // by just adding this atom to fLiveAtoms set, we are assuming it has no
+ // references, which is true for commons.
+ if ( target->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition )
+ fprintf(stderr, "warning: ld64 internal error %s is not a tentative definition\n", target->getDisplayName());
+ }
+ }
+ if ( reference->hasFromTarget() && reference->isFromTargetUnbound() ) {
+ ObjectFile::Atom* target = fGlobalSymbolTable.find(reference->getFromTargetName());
+ if ( target != NULL ) {
+ reference->setFromTarget(*target);
+ fLiveAtoms.insert(target);
+ // by just adding this atom to fLiveAtoms set, we are assuming it has no
+ // references, which is true for commons.
+ if ( target->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition )
+ fprintf(stderr, "warning: ld64 internal error %s is not a tentative definition\n", target->getDisplayName());
+ }
+ }
+ }
+ }
+
// now remove all non-live atoms from fAllAtoms
fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), NotLive(fLiveAtoms)), fAllAtoms.end());
}
}
-
// make sure given addresses are within reach of branches, etc
void Linker::tweakLayout()
{
static PathToSums sKnownBINCLs;
-void Linker::collectStabs(ObjectFile::Reader* reader, std::map<class ObjectFile::Atom*, uint32_t>& atomOrdinals)
+void Linker::collectStabs(ObjectFile::Reader* reader, std::map<const class ObjectFile::Atom*, uint32_t>& atomOrdinals)
{
bool log = false;
bool minimal = ( fOptions.readerOptions().fDebugInfoStripping == ObjectFile::ReaderOptions::kDebugInfoMinimal );
break;
case N_FUN:
{
- std::map<class ObjectFile::Atom*, uint32_t>::iterator pos = atomOrdinals.find(it->atom);
+ std::map<const class ObjectFile::Atom*, uint32_t>::iterator pos = atomOrdinals.find(it->atom);
if ( pos != atomOrdinals.end() ) {
uint32_t ordinal = pos->second;
if ( ordinal > highestOrdinal ) {
}
-void Linker::synthesizeStabs(ObjectFile::Reader* reader)
+// used to prune out atoms that don't need debug notes generated
+class NoDebugNoteAtom
+{
+public:
+ NoDebugNoteAtom(const std::map<class ObjectFile::Reader*, uint32_t>& readersWithDwarfOrdinals)
+ : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals) {}
+
+ bool operator()(const ObjectFile::Atom* atom) const {
+ if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
+ return true;
+ if ( atom->getName() == NULL )
+ return true;
+ if ( fReadersWithDwarfOrdinals.find(atom->getFile()) == fReadersWithDwarfOrdinals.end() )
+ return true;
+ return false;
+ }
+
+private:
+ const std::map<class ObjectFile::Reader*, uint32_t>& fReadersWithDwarfOrdinals;
+};
+
+// used to sort atoms with debug notes
+class ReadersWithDwarfSorter
+{
+public:
+ ReadersWithDwarfSorter(const std::map<class ObjectFile::Reader*, uint32_t>& readersWithDwarfOrdinals,
+ const std::map<const class ObjectFile::Atom*, uint32_t>& atomOrdinals)
+ : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals), fAtomOrdinals(atomOrdinals) {}
+
+ bool operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right) const
+ {
+ // first sort by reader
+ unsigned int leftReaderIndex = fReadersWithDwarfOrdinals.find(left->getFile())->second;
+ unsigned int rightReaderIndex = fReadersWithDwarfOrdinals.find(right->getFile())->second;
+ if ( leftReaderIndex != rightReaderIndex )
+ return (leftReaderIndex < rightReaderIndex);
+
+ // then sort by atom ordinal
+ unsigned int leftAtomIndex = fAtomOrdinals.find(left)->second;
+ unsigned int rightAtomIndex = fAtomOrdinals.find(right)->second;
+ return leftAtomIndex < rightAtomIndex;
+ }
+
+private:
+ const std::map<class ObjectFile::Reader*, uint32_t>& fReadersWithDwarfOrdinals;
+ const std::map<const class ObjectFile::Atom*, uint32_t>& fAtomOrdinals;
+};
+
+
+
+
+
+void Linker::synthesizeDebugNotes(std::vector<class ObjectFile::Atom*>& allAtomsByReader)
{
// 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) {
+ __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> seenFiles;
+ for (std::vector<ObjectFile::Atom*>::iterator it=allAtomsByReader.begin(); it != allAtomsByReader.end(); it++) {
ObjectFile::Atom* atom = *it;
- if ( atom->getFile() == reader ) {
- const char* name = atom->getName();
- if ( (name != NULL) && (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) ) {
- const char* newDirPath;
- const char* newFilename;
- if ( atom->getTranslationUnitSource(&newDirPath, &newFilename) ) {
- // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
- if ( (newDirPath != NULL) && (strlen(newDirPath) > 1 ) && (newDirPath[strlen(newDirPath)-1] != '/') )
- asprintf((char**)&newDirPath, "%s/", newDirPath);
- // 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;
- }
+ const char* newDirPath;
+ const char* newFilename;
+ //fprintf(stderr, "debug note for %s\n", atom->getDisplayName());
+ if ( atom->getTranslationUnitSource(&newDirPath, &newFilename) ) {
+ // need SO's whenever the translation unit source file changes
+ if ( newFilename != filename ) {
+ // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
+ if ( (newDirPath != NULL) && (strlen(newDirPath) > 1 ) && (newDirPath[strlen(newDirPath)-1] != '/') )
+ asprintf((char**)&newDirPath, "%s/", newDirPath);
+ if ( filename != NULL ) {
+ // translation unit change, emit ending SO
+ ObjectFile::Reader::Stab endFileStab;
+ endFileStab.atom = NULL;
+ endFileStab.type = N_SO;
+ endFileStab.other = 1;
+ endFileStab.desc = 0;
+ endFileStab.value = 0;
+ endFileStab.string = "";
+ fStabs.push_back(endFileStab);
+ }
+ // new translation unit, emit start SO's
+ ObjectFile::Reader::Stab dirPathStab;
+ dirPathStab.atom = NULL;
+ dirPathStab.type = N_SO;
+ dirPathStab.other = 0;
+ dirPathStab.desc = 0;
+ dirPathStab.value = 0;
+ dirPathStab.string = newDirPath;
+ fStabs.push_back(dirPathStab);
+ ObjectFile::Reader::Stab fileStab;
+ fileStab.atom = NULL;
+ fileStab.type = N_SO;
+ fileStab.other = 0;
+ fileStab.desc = 0;
+ fileStab.value = 0;
+ fileStab.string = newFilename;
+ fStabs.push_back(fileStab);
+ // Synthesize OSO for start of file
+ ObjectFile::Reader::Stab objStab;
+ objStab.atom = NULL;
+ objStab.type = N_OSO;
+ objStab.other = 0;
+ objStab.desc = 1;
+ objStab.value = atom->getFile()->getModificationTime();
+ objStab.string = assureFullPath(atom->getFile()->getPath());
+ fStabs.push_back(objStab);
+ wroteStartSO = true;
+ // add the source file path to seenFiles so it does not show up in SOLs
+ seenFiles.insert(newFilename);
+ }
+ filename = newFilename;
+ dirPath = newDirPath;
+ if ( atom->getSegment().isContentExecutable() && (strncmp(atom->getSectionName(), "__text", 6) == 0) ) {
+ // Synthesize BNSYM and start FUN stabs
+ ObjectFile::Reader::Stab beginSym;
+ beginSym.atom = atom;
+ beginSym.type = N_BNSYM;
+ beginSym.other = 1;
+ beginSym.desc = 0;
+ beginSym.value = 0;
+ beginSym.string = "";
+ fStabs.push_back(beginSym);
+ ObjectFile::Reader::Stab startFun;
+ startFun.atom = atom;
+ startFun.type = N_FUN;
+ startFun.other = 1;
+ startFun.desc = 0;
+ startFun.value = 0;
+ startFun.string = atom->getName();
+ fStabs.push_back(startFun);
+ // Synthesize any SOL stabs needed
+ std::vector<ObjectFile::LineInfo>* lineInfo = atom->getLineInfo();
+ if ( lineInfo != NULL ) {
+ const char* curFile = NULL;
+ for (std::vector<ObjectFile::LineInfo>::iterator it = lineInfo->begin(); it != lineInfo->end(); ++it) {
+ if ( it->fileName != curFile ) {
+ if ( seenFiles.count(it->fileName) == 0 ) {
+ seenFiles.insert(it->fileName);
+ ObjectFile::Reader::Stab sol;
+ sol.atom = 0;
+ sol.type = N_SOL;
+ sol.other = 0;
+ sol.desc = 0;
+ sol.value = 0;
+ sol.string = it->fileName;
+ fStabs.push_back(sol);
}
+ curFile = it->fileName;
}
- // Synthesize end FUN and ENSYM stabs
- ObjectFile::Reader::Stab endFun;
- endFun.atom = atom;
- endFun.type = N_FUN;
- endFun.other = 0;
- endFun.desc = 0;
- endFun.value = 0;
- endFun.string = "";
- fStabs.push_back(endFun);
- ObjectFile::Reader::Stab endSym;
- endSym.atom = atom;
- endSym.type = N_ENSYM;
- endSym.other = 1;
- endSym.desc = 0;
- endSym.value = 0;
- endSym.string = "";
- fStabs.push_back(endSym);
}
- else {
- 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);
- }
- }
+ }
+ // 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;
}
}
-void Linker::collectStabs()
+
+
+
+void Linker::collectDebugInfo()
{
+ std::map<const class ObjectFile::Atom*, uint32_t> atomOrdinals;
+ fStartDebugTime = mach_absolute_time();
if ( fOptions.readerOptions().fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone ) {
- // make mapping from atoms to ordinal
- std::map<class ObjectFile::Atom*, uint32_t> atomOrdinals;
- uint32_t ordinal = 1;
- for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
- atomOrdinals[*it] = ordinal++;
- }
-
- fStabs.reserve(1024); // try to minimize re-allocations
- // get stabs from each reader, in command line order
+ // determine mixture of stabs and dwarf
+ bool someStabs = false;
+ bool someDwarf = false;
for (std::vector<class ObjectFile::Reader*>::iterator it=fReadersThatHaveSuppliedAtoms.begin();
it != fReadersThatHaveSuppliedAtoms.end();
it++) {
if ( reader != NULL ) {
switch ( reader->getDebugInfoKind() ) {
case ObjectFile::Reader::kDebugInfoNone:
- // do nothing
break;
case ObjectFile::Reader::kDebugInfoStabs:
- collectStabs(reader, atomOrdinals);
+ someStabs = true;
break;
case ObjectFile::Reader::kDebugInfoDwarf:
- synthesizeStabs(reader);
+ someDwarf = true;
fCreateUUID = true;
break;
case ObjectFile::Reader::kDebugInfoStabsUUID:
- collectStabs(reader, atomOrdinals);
+ someStabs = true;
fCreateUUID = true;
break;
default:
}
}
}
- // 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());
+
+ if ( someDwarf || someStabs ) {
+ // try to minimize re-allocations
+ fStabs.reserve(1024);
+
+ // make mapping from atoms to ordinal
+ uint32_t ordinal = 1;
+ for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
+ atomOrdinals[*it] = ordinal++;
+ }
+ }
+
+ // process all dwarf .o files as a batch
+ if ( someDwarf ) {
+ // make mapping from readers with dwarf to ordinal
+ std::map<class ObjectFile::Reader*, uint32_t> readersWithDwarfOrdinals;
+ uint32_t readerOrdinal = 1;
+ for (std::vector<class ObjectFile::Reader*>::iterator it=fReadersThatHaveSuppliedAtoms.begin();
+ it != fReadersThatHaveSuppliedAtoms.end();
+ it++) {
+ ObjectFile::Reader* reader = *it;
+ if ( (reader != NULL) && (reader->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoDwarf) ) {
+ readersWithDwarfOrdinals[reader] = readerOrdinal++;
+ }
+ }
+
+ // make a vector of atoms
+ std::vector<class ObjectFile::Atom*> allAtomsByReader(fAllAtoms.begin(), fAllAtoms.end());
+ // remove those not from a reader that has dwarf
+ allAtomsByReader.erase(std::remove_if(allAtomsByReader.begin(), allAtomsByReader.end(),
+ NoDebugNoteAtom(readersWithDwarfOrdinals)), allAtomsByReader.end());
+ // sort by reader then atom ordinal
+ std::sort(allAtomsByReader.begin(), allAtomsByReader.end(), ReadersWithDwarfSorter(readersWithDwarfOrdinals, atomOrdinals));
+ // add debug notes for each atom
+ this->synthesizeDebugNotes(allAtomsByReader);
+ }
+
+ // process all stabs .o files one by one
+ if ( someStabs ) {
+ // get stabs from each reader, in command line order
+ for (std::vector<class ObjectFile::Reader*>::iterator it=fReadersThatHaveSuppliedAtoms.begin();
+ it != fReadersThatHaveSuppliedAtoms.end();
+ it++) {
+ ObjectFile::Reader* reader = *it;
+ if ( reader != NULL ) {
+ switch ( reader->getDebugInfoKind() ) {
+ case ObjectFile::Reader::kDebugInfoDwarf:
+ case ObjectFile::Reader::kDebugInfoNone:
+ // do nothing
+ break;
+ case ObjectFile::Reader::kDebugInfoStabs:
+ case ObjectFile::Reader::kDebugInfoStabsUUID:
+ collectStabs(reader, atomOrdinals);
+ break;
+ default:
+ throw "Unhandled type of debug information";
+ }
+ }
+ }
+ // remove stabs associated with atoms that won't be in output
+ std::set<class ObjectFile::Atom*> allAtomsSet;
+ allAtomsSet.insert(fAllAtoms.begin(), fAllAtoms.end());
+ fStabs.erase(std::remove_if(fStabs.begin(), fStabs.end(), NotInSet(allAtomsSet)), fStabs.end());
+ }
}
}
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 ) {
+ if ( (fileOffset & 0x00000FFF) == 0 ) {
// unmap whole file
munmap((caddr_t)p, info.fileLen);
// re-map just part we need
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() );
+ useNew = ( newAtom.getAlignment().leadingZeros() > existingAtom->getAlignment().leadingZeros() );
break;
case kWeakAndTent:
// replace existing weak atom with tentative one ???
// use largest
if ( newAtom.getSize() < existingAtom->getSize() ) {
useNew = false;
+ } else {
+ if ( newAtom.getAlignment().leadingZeros() < existingAtom->getAlignment().leadingZeros() )
+ fprintf(stderr, "ld64 warning: alignment lost in merging tentative definition %s\n", newAtom.getDisplayName());
}
break;
case kTentAndExtern:
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->flags() &SECTION_TYPE) != S_ZEROFILL) && (segCmd->filesize() != 0) ) {
if ( sect->offset() < startOffset )
throwf("section %s file offset not within segment", sect->sectname());
if ( (sect->offset()+sect->size()) > endOffset )
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";
+ if ( fIndirectTableCount != 0 ) {
+ 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";
+ }
fLocalRelocationsCount = dsymtab->nlocrel();
if ( fLocalRelocationsCount != 0 ) {
fLocalRelocations = (const macho_relocation_info<P>*)((char*)fHeader + dsymtab->locreloff());
if ( entry->n_sect() != NO_SECT )
entry->set_n_value(entry->n_value() + fSlide);
}
+
+ // FIXME ¥¥¥ adjust dylib_module if it exists
}
template <typename 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 that the modules of
+# symbol _b is maintained. The address for _b must be
+# 3 mod 16. Therefore the last hexdigit of the address
+# must be 3.
+
+run: all
+
+all:
+ ${CC} ${ASMFLAGS} -dynamiclib -single_module -dead_strip foo.c align.s -exported_symbols_list foo.exp -o foo.${ARCH}.dylib
+ nm foo.${ARCH}.dylib | grep "3 d _b" | ${PASS_IFF_STDIN}
+
+
+clean:
+ rm -rf foo.${ARCH}.dylib
+
+
+
--- /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@
+ */
+
+ .data
+ .align 0
+_a: .byte 3
+ .byte 3
+ .byte 3
+ .globl _b
+_b: .byte 4 ;# address is 3
+ .align 4
+L1: .quad 0
+_c: .long 8
+
+ .subsections_via_symbols
+
--- /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@
+ */
+
+extern char b;
+int my = 2;
+
+char foo()
+{
+ return my+b;
+}
+
+
--- /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 that -dead_strip removes unreference code/data from archives
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ libtool -static foo.o -o libfoo.a
+ ${CC} ${CCFLAGS} main.c -mdynamic-no-pic -Os libfoo.a -dead_strip -o main
+ ${FAIL_IF_BAD_MACHO} main
+ nm -j main | grep dead_wood | ${PASS_IFF_EMPTY}
+
+
+clean:
+ rm -rf main libfoo.a foo.o
+
+
--- /dev/null
+
+
+void foo() {}
+
+
+int my_common;
+
--- /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@
+ */
+
+extern void foo();
+extern int my_common;
+
+int main()
+{
+ // the reference to the common symbol has to be first
+ my_common += 1;
+ // refrence to foo is next
+ foo();
+ return 0;
+}
+
+
${PASS_IFF} diff dwarf-test-${ARCH}.stabs expected-stabs
foobar.o : foo.o bar.o
- ${LD} -r foo.o bar.o -o foobar.o
+ ${LD} -r -arch ${ARCH} foo.o bar.o -o foobar.o
foo.o : foo.cxx
${CXX} ${CCXXFLAGS} -gdwarf-2 foo.cxx -c -o foo.o -mdynamic-no-pic
0000 SO CWD/
+0000 SO main.cxx
+0001 OSO CWD/main.o
+0000 BNSYM
+0000 FUN _main
+0000 FUN
+0000 ENSYM
+0000 SO
+0000 SO CWD/
0000 SO foo.cxx
0001 OSO CWD/foo.o
0000 BNSYM
0000 FUN
0000 ENSYM
0000 SO
-0000 SO CWD/
-0000 SO main.cxx
-0001 OSO CWD/main.o
-0000 BNSYM
-0000 FUN _main
-0000 FUN
-0000 ENSYM
-0000 SO
--- /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 sanity check that an indirect
+# library is not accidentally searched for symbols.
+#
+# <rdar://problem/4681062> wrong error message when symbol is found in unused indirect library#
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib
+ ${CC} ${CCFLAGS} foo.c libbar.dylib -dynamiclib -o libfoo.dylib
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -o main libfoo.dylib 2> fail.log
+ grep ordinal fail.log | ${PASS_IFF_EMPTY}
+
+clean:
+ rm libfoo.dylib libbar.dylib main 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@
+ */
+
+
+// function called by a loaded bundle
+int bar()
+{
+ 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 bar();
+
+int foo()
+{
+ return bar();
+}
--- /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 void bar();
+
+int main()
+{
+ bar();
+ return 0;
+}
+
# 1-byte store
movb $0x12, _a(%rip)
+ movb $0x12, _a+2(%rip)
+ movb $0x12, L0(%rip)
# 4-byte store
movl $0x12345678, _a(%rip)
+ movl $0x12345678, _a+4(%rip)
+ movl $0x12345678, L0(%rip)
# test local labels
-# lea L1(%rip), %rax ### assembler bug
-# movl L0(%rip), %eax ### assembler bug
+ lea L1(%rip), %rax
+ movl L0(%rip), %eax
ret
L1: .quad _test_branches - _test_diffs
.quad _test_branches - _test_diffs + 4
.long _test_branches - _test_diffs
-# .long LCL0-. ### assembler bug: content value should be (address(LCL0) - 0x24)
+# .long LCL0-. ### assembler bug: should SUB/UNSIGNED with content= LCL0-24, or single pc-rel SIGNED reloc with content = LCL0-.+4
.quad L1
-# .quad L0 ### assembler bug: should be internal reloc to L0
+ .quad L0
.quad _test_branches - .
.quad _test_branches - L1
.quad L1 - _prev
@implementation Foo
-
- (id) init
{
self = [super init];
{
[self class];
}
+@end
+
+
+@interface Base
@end
+
+@implementation Base
+@end
+
+
+