--- /dev/null
+APPLE PUBLIC SOURCE LICENSE
+Version 2.0 - August 6, 2003
+
+Please read this License carefully before downloading this software.
+By downloading or using this software, you are agreeing to be bound by
+the terms of this License. If you do not or cannot agree to the terms
+of this License, please do not download or use the software.
+
+1. General; Definitions. This License applies to any program or other
+work which Apple Computer, Inc. ("Apple") makes publicly available and
+which contains a notice placed by Apple identifying such program or
+work as "Original Code" and stating that it is subject to the terms of
+this Apple Public Source License version 2.0 ("License"). As used in
+this License:
+
+1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is
+the grantor of rights, (i) claims of patents that are now or hereafter
+acquired, owned by or assigned to Apple and (ii) that cover subject
+matter contained in the Original Code, but only to the extent
+necessary to use, reproduce and/or distribute the Original Code
+without infringement; and (b) in the case where You are the grantor of
+rights, (i) claims of patents that are now or hereafter acquired,
+owned by or assigned to You and (ii) that cover subject matter in Your
+Modifications, taken alone or in combination with Original Code.
+
+1.2 "Contributor" means any person or entity that creates or
+contributes to the creation of Modifications.
+
+1.3 "Covered Code" means the Original Code, Modifications, the
+combination of Original Code and any Modifications, and/or any
+respective portions thereof.
+
+1.4 "Externally Deploy" means: (a) to sublicense, distribute or
+otherwise make Covered Code available, directly or indirectly, to
+anyone other than You; and/or (b) to use Covered Code, alone or as
+part of a Larger Work, in any way to provide a service, including but
+not limited to delivery of content, through electronic communication
+with a client other than You.
+
+1.5 "Larger Work" means a work which combines Covered Code or portions
+thereof with code not governed by the terms of this License.
+
+1.6 "Modifications" mean any addition to, deletion from, and/or change
+to, the substance and/or structure of the Original Code, any previous
+Modifications, the combination of Original Code and any previous
+Modifications, and/or any respective portions thereof. When code is
+released as a series of files, a Modification is: (a) any addition to
+or deletion from the contents of a file containing Covered Code;
+and/or (b) any new file or other representation of computer program
+statements that contains any part of Covered Code.
+
+1.7 "Original Code" means (a) the Source Code of a program or other
+work as originally made available by Apple under this License,
+including the Source Code of any updates or upgrades to such programs
+or works made available by Apple under this License, and that has been
+expressly identified by Apple as such in the header file(s) of such
+work; and (b) the object code compiled from such Source Code and
+originally made available by Apple under this License.
+
+1.8 "Source Code" means the human readable form of a program or other
+work that is suitable for making modifications to it, including all
+modules it contains, plus any associated interface definition files,
+scripts used to control compilation and installation of an executable
+(object code).
+
+1.9 "You" or "Your" means an individual or a legal entity exercising
+rights under this License. For legal entities, "You" or "Your"
+includes any entity which controls, is controlled by, or is under
+common control with, You, where "control" means (a) the power, direct
+or indirect, to cause the direction or management of such entity,
+whether by contract or otherwise, or (b) ownership of fifty percent
+(50%) or more of the outstanding shares or beneficial ownership of
+such entity.
+
+2. Permitted Uses; Conditions & Restrictions. Subject to the terms
+and conditions of this License, Apple hereby grants You, effective on
+the date You accept this License and download the Original Code, a
+world-wide, royalty-free, non-exclusive license, to the extent of
+Apple's Applicable Patent Rights and copyrights covering the Original
+Code, to do the following:
+
+2.1 Unmodified Code. You may use, reproduce, display, perform,
+internally distribute within Your organization, and Externally Deploy
+verbatim, unmodified copies of the Original Code, for commercial or
+non-commercial purposes, provided that in each instance:
+
+(a) You must retain and reproduce in all copies of Original Code the
+copyright and other proprietary notices and disclaimers of Apple as
+they appear in the Original Code, and keep intact all notices in the
+Original Code that refer to this License; and
+
+(b) You must include a copy of this License with every copy of Source
+Code of Covered Code and documentation You distribute or Externally
+Deploy, and You may not offer or impose any terms on such Source Code
+that alter or restrict this License or the recipients' rights
+hereunder, except as permitted under Section 6.
+
+2.2 Modified Code. You may modify Covered Code and use, reproduce,
+display, perform, internally distribute within Your organization, and
+Externally Deploy Your Modifications and Covered Code, for commercial
+or non-commercial purposes, provided that in each instance You also
+meet all of these conditions:
+
+(a) You must satisfy all the conditions of Section 2.1 with respect to
+the Source Code of the Covered Code;
+
+(b) You must duplicate, to the extent it does not already exist, the
+notice in Exhibit A in each file of the Source Code of all Your
+Modifications, and cause the modified files to carry prominent notices
+stating that You changed the files and the date of any change; and
+
+(c) If You Externally Deploy Your Modifications, You must make
+Source Code of all Your Externally Deployed Modifications either
+available to those to whom You have Externally Deployed Your
+Modifications, or publicly available. Source Code of Your Externally
+Deployed Modifications must be released under the terms set forth in
+this License, including the license grants set forth in Section 3
+below, for as long as you Externally Deploy the Covered Code or twelve
+(12) months from the date of initial External Deployment, whichever is
+longer. You should preferably distribute the Source Code of Your
+Externally Deployed Modifications electronically (e.g. download from a
+web site).
+
+2.3 Distribution of Executable Versions. In addition, if You
+Externally Deploy Covered Code (Original Code and/or Modifications) in
+object code, executable form only, You must include a prominent
+notice, in the code itself as well as in related documentation,
+stating that Source Code of the Covered Code is available under the
+terms of this License with information on how and where to obtain such
+Source Code.
+
+2.4 Third Party Rights. You expressly acknowledge and agree that
+although Apple and each Contributor grants the licenses to their
+respective portions of the Covered Code set forth herein, no
+assurances are provided by Apple or any Contributor that the Covered
+Code does not infringe the patent or other intellectual property
+rights of any other entity. Apple and each Contributor disclaim any
+liability to You for claims brought by any other entity based on
+infringement of intellectual property rights or otherwise. As a
+condition to exercising the rights and licenses granted hereunder, You
+hereby assume sole responsibility to secure any other intellectual
+property rights needed, if any. For example, if a third party patent
+license is required to allow You to distribute the Covered Code, it is
+Your responsibility to acquire that license before distributing the
+Covered Code.
+
+3. Your Grants. In consideration of, and as a condition to, the
+licenses granted to You under this License, You hereby grant to any
+person or entity receiving or distributing Covered Code under this
+License a non-exclusive, royalty-free, perpetual, irrevocable license,
+under Your Applicable Patent Rights and other intellectual property
+rights (other than patent) owned or controlled by You, to use,
+reproduce, display, perform, modify, sublicense, distribute and
+Externally Deploy Your Modifications of the same scope and extent as
+Apple's licenses under Sections 2.1 and 2.2 above.
+
+4. Larger Works. You may create a Larger Work by combining Covered
+Code with other code not governed by the terms of this License and
+distribute the Larger Work as a single product. In each such instance,
+You must make sure the requirements of this License are fulfilled for
+the Covered Code or any portion thereof.
+
+5. Limitations on Patent License. Except as expressly stated in
+Section 2, no other patent rights, express or implied, are granted by
+Apple herein. Modifications and/or Larger Works may require additional
+patent licenses from Apple which Apple may grant in its sole
+discretion.
+
+6. Additional Terms. You may choose to offer, and to charge a fee for,
+warranty, support, indemnity or liability obligations and/or other
+rights consistent with the scope of the license granted herein
+("Additional Terms") to one or more recipients of Covered Code.
+However, You may do so only on Your own behalf and as Your sole
+responsibility, and not on behalf of Apple or any Contributor. You
+must obtain the recipient's agreement that any such Additional Terms
+are offered by You alone, and You hereby agree to indemnify, defend
+and hold Apple and every Contributor harmless for any liability
+incurred by or claims asserted against Apple or such Contributor by
+reason of any such Additional Terms.
+
+7. Versions of the License. Apple may publish revised and/or new
+versions of this License from time to time. Each version will be given
+a distinguishing version number. Once Original Code has been published
+under a particular version of this License, You may continue to use it
+under the terms of that version. You may also choose to use such
+Original Code under the terms of any subsequent version of this
+License published by Apple. No one other than Apple has the right to
+modify the terms applicable to Covered Code created under this
+License.
+
+8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in
+part pre-release, untested, or not fully tested works. The Covered
+Code may contain errors that could cause failures or loss of data, and
+may be incomplete or contain inaccuracies. You expressly acknowledge
+and agree that use of the Covered Code, or any portion thereof, is at
+Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND
+WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND
+APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE
+PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
+ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF
+MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR
+PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD
+PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST
+INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE
+FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS,
+THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
+ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO
+ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE
+AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.
+You acknowledge that the Covered Code is not intended for use in the
+operation of nuclear facilities, aircraft navigation, communication
+systems, or air traffic control machines in which case the failure of
+the Covered Code could lead to death, personal injury, or severe
+physical or environmental damage.
+
+9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
+EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL,
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING
+TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR
+ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY,
+TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF
+APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY
+REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF
+INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY
+TO YOU. In no event shall Apple's total liability to You for all
+damages (other than as may be required by applicable law) under this
+License exceed the amount of fifty dollars ($50.00).
+
+10. Trademarks. This License does not grant any rights to use the
+trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS",
+"QuickTime", "QuickTime Streaming Server" or any other trademarks,
+service marks, logos or trade names belonging to Apple (collectively
+"Apple Marks") or to any trademark, service mark, logo or trade name
+belonging to any Contributor. You agree not to use any Apple Marks in
+or as part of the name of products derived from the Original Code or
+to endorse or promote products derived from the Original Code other
+than as expressly permitted by and in strict compliance at all times
+with Apple's third party trademark usage guidelines which are posted
+at http://www.apple.com/legal/guidelinesfor3rdparties.html.
+
+11. Ownership. Subject to the licenses granted under this License,
+each Contributor retains all rights, title and interest in and to any
+Modifications made by such Contributor. Apple retains all rights,
+title and interest in and to the Original Code and any Modifications
+made by or on behalf of Apple ("Apple Modifications"), and such Apple
+Modifications will not be automatically subject to this License. Apple
+may, at its sole discretion, choose to license such Apple
+Modifications under this License, or on different terms from those
+contained in this License or may choose not to license them at all.
+
+12. Termination.
+
+12.1 Termination. This License and the rights granted hereunder will
+terminate:
+
+(a) automatically without notice from Apple if You fail to comply with
+any term(s) of this License and fail to cure such breach within 30
+days of becoming aware of such breach;
+
+(b) immediately in the event of the circumstances described in Section
+13.5(b); or
+
+(c) automatically without notice from Apple if You, at any time during
+the term of this License, commence an action for patent infringement
+against Apple; provided that Apple did not first commence
+an action for patent infringement against You in that instance.
+
+12.2 Effect of Termination. Upon termination, You agree to immediately
+stop any further use, reproduction, modification, sublicensing and
+distribution of the Covered Code. All sublicenses to the Covered Code
+which have been properly granted prior to termination shall survive
+any termination of this License. Provisions which, by their nature,
+should remain in effect beyond the termination of this License shall
+survive, including but not limited to Sections 3, 5, 8, 9, 10, 11,
+12.2 and 13. No party will be liable to any other for compensation,
+indemnity or damages of any sort solely as a result of terminating
+this License in accordance with its terms, and termination of this
+License will be without prejudice to any other right or remedy of
+any party.
+
+13. Miscellaneous.
+
+13.1 Government End Users. The Covered Code is a "commercial item" as
+defined in FAR 2.101. Government software and technical data rights in
+the Covered Code include only those rights customarily provided to the
+public as defined in this License. This customary commercial license
+in technical data and software is provided in accordance with FAR
+12.211 (Technical Data) and 12.212 (Computer Software) and, for
+Department of Defense purchases, DFAR 252.227-7015 (Technical Data --
+Commercial Items) and 227.7202-3 (Rights in Commercial Computer
+Software or Computer Software Documentation). Accordingly, all U.S.
+Government End Users acquire Covered Code with only those rights set
+forth herein.
+
+13.2 Relationship of Parties. This License will not be construed as
+creating an agency, partnership, joint venture or any other form of
+legal association between or among You, Apple or any Contributor, and
+You will not represent to the contrary, whether expressly, by
+implication, appearance or otherwise.
+
+13.3 Independent Development. Nothing in this License will impair
+Apple's right to acquire, license, develop, have others develop for
+it, market and/or distribute technology or products that perform the
+same or similar functions as, or otherwise compete with,
+Modifications, Larger Works, technology or products that You may
+develop, produce, market or distribute.
+
+13.4 Waiver; Construction. Failure by Apple or any Contributor to
+enforce any provision of this License will not be deemed a waiver of
+future enforcement of that or any other provision. Any law or
+regulation which provides that the language of a contract shall be
+construed against the drafter will not apply to this License.
+
+13.5 Severability. (a) If for any reason a court of competent
+jurisdiction finds any provision of this License, or portion thereof,
+to be unenforceable, that provision of the License will be enforced to
+the maximum extent permissible so as to effect the economic benefits
+and intent of the parties, and the remainder of this License will
+continue in full force and effect. (b) Notwithstanding the foregoing,
+if applicable law prohibits or restricts You from fully and/or
+specifically complying with Sections 2 and/or 3 or prevents the
+enforceability of either of those Sections, this License will
+immediately terminate and You must immediately discontinue any use of
+the Covered Code and destroy all copies of it that are in your
+possession or control.
+
+13.6 Dispute Resolution. Any litigation or other dispute resolution
+between You and Apple relating to this License shall take place in the
+Northern District of California, and You and Apple hereby consent to
+the personal jurisdiction of, and venue in, the state and federal
+courts within that District with respect to this License. The
+application of the United Nations Convention on Contracts for the
+International Sale of Goods is expressly excluded.
+
+13.7 Entire Agreement; Governing Law. This License constitutes the
+entire agreement between the parties with respect to the subject
+matter hereof. This License shall be governed by the laws of the
+United States and the State of California, except that body of
+California law concerning conflicts of law.
+
+Where You are located in the province of Quebec, Canada, the following
+clause applies: The parties hereby confirm that they have requested
+that this License and all related documents be drafted in English. Les
+parties ont exige que le present contrat et tous les documents
+connexes soient rediges en anglais.
+
+EXHIBIT A.
+
+"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
+Reserved.
+
+This file contains Original Code and/or Modifications of Original Code
+as defined in and that are subject to the Apple Public Source License
+Version 2.0 (the 'License'). You may not use this file except in
+compliance with the License. Please obtain a copy of the License at
+http://www.opensource.apple.com/apsl/ and read it before using this
+file.
+
+The Original Code and all software distributed under the License are
+distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+Please see the License for the specific language governing rights and
+limitations under the License."
--- /dev/null
+#!/bin/csh
+
+# Attempt to find the architecture.
+# First look through the command line args.
+set arch=unknown
+set link_cmd=(`cat link_command`)
+while ( $#link_cmd > 0 )
+ if ( "$link_cmd[1]" == "-arch" ) then
+ set arch=$link_cmd[2]
+ endif
+ shift link_cmd
+end
+
+# look for an explicit arch file
+if ( "$arch" == "unknown" ) then
+ if ( -e arch ) then
+ set arch=`cat arch`
+ endif
+endif
+
+if ( "$arch" == "unknown" ) then
+echo "***** Unable to determine architecture."
+exit 1
+endif
+
+# Create .dylibs for each file in the dylib_stubs directory.
+if ( -e dylib_stubs ) then
+ set files=`cd dylib_stubs ; echo *`
+ mkdir -p dylibs
+ foreach file ($files)
+ if ( ! -e dylibs/$file ) then
+ clang -arch $arch -c -fno-builtin -o tmp_object.o -x c dylib_stubs/$file
+ ld -arch $arch -dylib -macosx_version_min 10.1 -no_version_load_command -o dylibs/$file tmp_object.o
+ endif
+ end
+endif
+
+# Create .frameworks for each file in the framework_stubs directory.
+if ( -e framework_stubs ) then
+ set files=`cd framework_stubs ; echo *`
+ foreach file ($files)
+ if ( ! -e frameworks/$file.framework ) then
+ clang -arch $arch -c -fno-builtin -o tmp_object.o -x c framework_stubs/$file
+ mkdir -p frameworks/$file.framework
+ ld -arch $arch -dylib -macosx_version_min 10.1 -no_version_load_command -o frameworks/$file.framework/$file tmp_object.o
+ endif
+ end
+endif
+
+# Clean up.
+rm -f tmp_object.o
--- /dev/null
+<html>
+<head>
+ <title>Linker</title>
+</head>
+<body>
+
+
+<h1>
+ Inside the Linker
+</h1>
+<div class="doc_author">
+ <p>Written by <a href="mailto:kledzik@apple.com">Nick Kledzik</a></p>
+</div>
+
+
+<h2>
+ <a name="introduction">Introduction</a>
+</h2>
+
+<p>The Darwin linker is a new generation of linker. It is not "section" based
+like traditional linkers which mostly just interlace sections from multiple
+object files into the output file. The Darwin linker is based on "Atoms".
+Traditional section based linking work well for simple linking, but their model
+makes advanced linking features difficult to implement. Features like dead code
+stripping, reordering functions for locality, and C++ coalescing require the
+linker to work at a finer grain.
+</p>
+
+<p>An atom is an indivisible chunk of code or data. An atom has a set of
+attributes, such as: name, scope, content-type, alignment, etc. An atom also
+has a list of Fixups. A Fixup contains: a kind, an optional offset, an optional
+addend, and an optional target atom.</p>
+
+<p>The Atom model allows the linker to use standard graph theory models for
+linking data structures. Each atom is a node, and each Fixup is an edge.
+The feature of dead code stripping is implemented by following edges to mark
+all live atoms, and then delete the non-live atoms.</p>
+<br>
+<h2>
+ <a name="Atom model">Atom model</a>
+</h2>
+
+<p>An atom is an indivisible chuck of code or data. Typically each user
+written function or global variable is an atom. In addition, the compiler may
+emit other atoms, such as for literal c-strings or floating point constants, or
+for runtime data structures like dwarf unwind info or pointers to initializers.
+</p>
+
+<p>A simple "hello world" object file would be modeled like this:</p>
+<img src="hello.png" alt="hello world graphic"/>
+<p>There are two atoms: main and an anonymous atom containing the c-string
+literal "hello world". The Atom "main" has two fixups. One is the call site
+for the call to printf, and the other is a fixup for the instruction that loads
+the address of the c-string literal. </p>
+
+<br>
+<h2>
+ <a name="File model">File model</a>
+</h2>
+
+<p>The linker views the input files as basically containers of Atoms and Fixups,
+ and just a few attributes of their own. The linker works with three kinds
+of files: object files, static libraries, and dynamic libraries. Each kind
+of file has reader object which presents the file in the model expected by
+the linker.</p>
+<h4> <a>Object File</a>
+</h4>
+An object file is just a container of atoms. When linking with
+an object file, all atoms are added to the initial graph of atoms.
+
+<h4> <a>Static Library (Archive)</a>
+</h4>
+This is the traditional unix static archive which is just a collection of
+object files with a "table of contents". When linking with a static library,
+by default nothing is added to the initial graph of atoms. Instead, if there
+are unresolved references (dangling edges) in the master graph of all atoms,
+and the table of contents for a static library says that one of the object files
+in the library defines one of the missing symbols (dangling edge),
+the set of atoms from the specified object file in the static library is added
+to the master graph of atoms.
+
+<h4> <a>Dynamic Library (Shared Object)</a>
+</h4>
+Dynamic libraries are unique in that the don't directly add add any atoms.
+Their purpose is to check at build time that all references are resolved and
+provide a list of dynamic libraries (SO_NEEDED) that will be needed at runtime.
+The way this is modeled in the linker is that a dynamic library contributes
+no atoms to the initial graph of atoms. Instead, (like static libraries) if
+there are unresolved references (dangling edges) in the master graph of all atoms,
+if a dynamic library exports a required symbol, then a "proxy" atom is
+instantiated by the linker. The proxy atom allows the master atom graph to have
+all edges resolved and also records from which dynamic library a symbol came.</p>
+
+<br>
+<h2>
+ <a name="Linking Steps">Linking Steps</a>
+</h2>
+<p>Through the use of abstract Atoms, the core of linking is architecture
+independent and file format independent. All command line parsing is factored
+out into a separate "options" abstraction which enables the linker to be driven
+with different command line sets.</p>
+<p>The overall steps in linking are:<p>
+<ol>
+ <li>Command line processing</li>
+ <li>Parsing input files</li>
+ <li>Resolving</li>
+ <li>Passes/Optimizations</li>
+ <li>Generate output file</li>
+</ol>
+
+<p>The Resolving and Passes steps are done purely on the master graph of atoms,
+so they have no notion of file formats such as mach-o or ELF.</p>
+
+<h4> <a>Resolving</a>
+</h4>
+<p>The resolving step takes all the atoms graphs from each object file and
+combines them into one master object graph. Unfortunately, it is not as simple
+as appending the atom list from each file into one big list. There are many
+cases where atoms need to be coalesced. That is, two or more atoms need to
+be coalesced into one atom. This is necessary to support: C language
+ "tentative definitions", C++ weak symbols for templates and inlines defined
+in headers, and for merging copies of constants like c-strings and floating
+point constants.</p>
+
+<p>The linker support coalescing by-name and by-content. By-name is used for
+tentative definitions and weak symbols. By-content is used for constant data
+that can be merged. </p>
+
+<p>When one atom has a reference (FixUp) to another atom, there is also a binding
+type: by-name, direct, or indirect. A Fixup contains a tagged union that if
+the binding type is by-name, the union field is a pointer to a c-string. If
+the binding type is direct, the union is a pointer to an Atom. If the binding
+type is indirect, the union is a index into a table of pointers to Atoms. Below
+is a graphical representation of the binding types:</p>
+<img src="bindings.png" alt="binding types graphic"/>
+
+<p>Input file Atoms contain only direct and by-name references. Direct
+references are used for atoms defined in the same object file for which the
+target atom is either unnamed or cannot change. For instance, calling
+a static function in a translation unit will result in a direct reference
+to the static functions's atom. Also the FDE (dwarf unwind info) for a function
+has a direct reference to its function. On the other hand references to
+global symbols (e.g. call to printf) use by-name binding in object files.
+</p>
+
+<p>The resolving process maintains some global linking "state", including:
+a "symbol table" which is a map from c-string to Atom*, an indirect symbol
+table which is a growable array of Atom*, and for each kind of coalesable
+constants there is a content to Atom* map. With these data structures,
+the linker walks all atoms in all input files. For each
+atom, it checks if the atom should be in one symbol table or one of the
+coalescing tables. If so, it attempts to add the atom. If there already is
+a matching atom in that table, that means the current atom needs to be
+coalesced with the found atom.
+</p>
+
+<p>To support coalescing, all references to coalesable atoms are changed to
+indirect binding and an entry is added to the indirect table which points
+to the current chosen atom. When all input atoms have been processed by
+the resolver, there should be only direct and indirect bindings left. If
+there are any NULL entries in the indirect table, that means there are
+undefined references. The linker then looks to the supplied libraries (both
+static and dynamic) to resolve those references.
+</p>
+
+<p>Dead code stripping (if requested) is done at the end of resolving. The
+linker does a simple mark-and-sweep. It starts with "root" atoms (like "main"
+in a main executable) and follows each references and marks each Atom that
+it visits as "live". When done, all atoms not marked "live" are removed.
+</p>
+
+<h4> <a>Passes</a>
+</h4>
+<p>The Passes step
+is an open ended set of routines that each get a change to modify or enhance
+the master graph of atoms. Passes are only run if the master graph of
+atoms is completely resolved (no dangling edges).
+The current set of Passes in the Darwin linker are:</p>
+<ul>
+ <li>Objective-C optimizations (Apple)</li>
+ <li>stub (PLT) generation</li>
+ <li>GOT instantiation</li>
+ <li>TLV instantiation (Apple)</li>
+ <li>order_file optimization</li>
+ <li>branch island generation</li>
+ <li>branch shim generation</li>
+ <li>dtrace probe processing (Apple)</li>
+ <li>compact unwind encoding (Apple)</li>
+</ul>
+<p>Some of these passes are specific to Apple's runtime environments. But many
+of the passes are applicable to any OS (such as generating branch island for
+out of range branch instructions).</p>
+
+<p>The general structure of a pass is to walk the master graph inspecting each
+atom and doing something. For instance, the stub pass, walks the graph looking
+for atoms with call sites to proxy atoms (e.g. call to printf). It then
+instantiates a "stub" atom (PLT entry) and a "lazy pointer" atom for each
+proxy atom needed, and these new atoms are added to the master graph. Next
+all the noted call sites to proxy atoms are replaced with calls to the
+corresponding stub atom.</p>
+
+<h4><a>Generate Output File</a>
+</h4>
+<p>Once the passes are done, the output file generator is given a sorted list
+of atoms. Its job is to create the executable content file wrapper and place
+the content of the atoms into it.
+</p>
+
+
+<h2>
+ <a name="Future Directions">Future Directions</a>
+</h2>
+
+<h4><a>Sections</a>
+</h4>
+<p>The current use of sections in mach-o .o files over-constrains the linker.
+By default, the linker should preserve the section an atom is in. But since
+all sections must be contiguous in the output, that limits the ability of
+the linker to order atoms for locality. It would be helpful to enrich the
+object file with with reason something is in the section it is. For instance,
+is the section found at runtime? Or was the use of a section just a quick
+way to group some content together?
+</p>
+<p>The ELF model for sections is a little better than mach-o because ELF
+sections have write and execute bits, whereas mach-o sections must be in some
+segment and the segment has the write and execute bits.
+</p>
+
+<h4><a>Mach-o Object File Format</a>
+</h4>
+<p>
+The messiest part of the linker is the mach-o parser. This is because mach-o
+is a traditional section and symbols based file format. The parser must infer
+atom boundaries using two approaches. The first is that some section types have
+well defined content which the linker can parse into atoms (e.g. __cstring,
+__eh_frame). The other approach is a naming convention (which the compiler follows)
+by which the linker breaks sections into atoms at any non-local (not starting
+with 'L') symbol. The processing the linker has to do parse mach-o .o files is a
+significant part of the link time.
+</p>
+
+<p>Given that the assembler writes object files once, whereas the linker reads
+them many times (during development), it would make sense to optimize the object
+file format to be something the linker can read/parse efficiently.</p>
+
+<h4><a>New Object File Model</a>
+</h4>
+<p>LLVM has a nice model for its IR. There are three representations:
+the binary bit code file, the in-memory object model, and a textual
+representation. LLVM contains utility possible code for converting between these
+representations. The same model makes sense for atoms too. There should be
+three representations for atoms: binary file, in-memory, and textual. The Darwin
+linker already has an in-memory C++ object model for Atoms. All we need is a
+textual representation and binary file format.
+</p>
+<p>Note: in the darwin linker the binary format for input object files is
+independent of the output executable format. That is, we could have one
+universal object file format which the linker could use as input to produce
+mach-o, ELF, or PE executables.</p>
+<p>
+The object file binary format should be designed to instantiate into atoms
+as fast as possible. The obvious way to do that is that the
+file format would be an array of atoms. The linker just mmaps in the file and
+looks at the header to see how many atoms there and instantiate that many atoms
+with the atom attribute information coming from that array. The trick is
+designing this in a way that can be extended as the Atom mode evolves and new
+attributes are added.
+</p>
+<p>
+In designing a textual format we want something easy for humans to read and
+easy for the linker to parse. Since an atom has lots of attributes most of
+which are usually just the default, we should define default values for
+every attribute so that those can be omitted from the text representation.
+One possile format is YAML. Here is the atoms for a simple hello world
+program expressed in YAML.
+</p>
+<pre>
+---
+target-triple: x86_64-apple-darwin11
+source:
+
+atoms:
+ - name: _main
+ scope: linkage-unit
+ type: code
+ alignment:
+ power: 4
+ content: [ 55, 48, 89, e5, 48, 8d, 3d, 00, 00, 00, 00, 30, c0, e8, 00, 00,
+ 00, 00, 31, c0, 5d, c3 ]
+ fixups:
+ - offset: 07
+ kind: pcrel32
+ target: 2
+ - offset: 0E
+ kind: call32
+ target: _fprintf
+
+ - type: c-string
+ merge: by-content
+ content: [ 73, 5A, 00 ]
+
+...
+</pre>
+
+<p>One big use for the textual format will be writing test cases. The Darwin
+linker test suite test cases are written mostly in C/C++ and a few assembly
+files. The use of C means the same test case can be compiled for different
+architectures. But writing test cases in C is problematic because the compiler
+may vary its output over time for its own optimization reasons which my
+inadvertently disable or break the linker feature trying to be tested. By
+writing test cases in the linkers own textual format, we can exactly specify
+every attribute of every atom and thus target specific linker logic.
+</p>
+
+<h4><a>Debug Info</a>
+</h4>
+<p>Around 2005 when Apple switched from using STABS to using DWARF for debug
+information, we made a design decision to have the linker ignore DWARF in
+.o files. This improves linking performance because the linker is not
+copying tons of debug info. Instead, the linker adds "debug notes" into
+output binary that contain the paths of the original .o files. During development
+the Darwin debugger will notice the debug notes and the load the dwarf
+debug information from the original object files. For release builds,
+a tool named dsymutil is run on the program. It finds the debug notes and
+then the original object files, then reads, merges and optimizes all the dwarf
+debug information into one .dSYM file which can be loaded by the debugger
+if needed.</p>
+
+<p>The current way DWARF is generated is that all debug information for all
+functions in a translation unit are merged and optimized into sections based
+on debug info kind. For instance the mapping of instructions to source line
+numbers for all functions is compressed and put in one section. This does not
+play well in an Atom based file format. One idea is to have the compiler
+emit some intermediate representation debug information (one which is
+partitioned per atom) into the Atom based file format. The linker could
+then have code to convert that intermediate debug into to final dwarf.
+This is still an open question.</p>
+
+<h4><a>Extending Atom attributes to ELF and XCOFF</a>
+</h4>
+<p>The current set of attributes defined for Atoms in the darwin linker
+were chosen to meet the requirements of developing code to run on iOS and
+Mac OS X. Below is a list of the attributes and their possible values.
+It may just require adding more values to support ELF and XCOFF. Or there
+may need to be new attributes added to capture new functionality.
+</p>
+<ul>
+ <li>Name</li>
+ <li>Size</li>
+ <li>Section (I'd like to get rid of this)</li>
+ <li>ContentType (currently some of this comes from section)</li>
+ <ul>
+ <li>code</li>
+ <li>stub</li>
+ <li>data</li>
+ <li>zeroFill</li>
+ <li>initializerPointer</li>
+ <li>objc1Class</li>
+ <li>objc2Class</li>
+ <li>objcClassPointer</li>
+ <li>objc2CategoryList</li>
+ <li>non-lazy-pointer</li>
+ <li>lazy-pointer</li>
+ <li>constant</li>
+ <li>literal4</li>
+ <li>literal8</li>
+ <li>literal16</li>
+ <li>cstring</li>
+ <li>cstringPointer</li>
+ <li>utf16string</li>
+ <li>CFString</li>
+ <li>CFI</li>
+ <li>LSDA</li>
+ </ul>
+ </li>
+ <li>Scope
+ <ul>
+ <li>translationUnit (static functions)</li>
+ <li>linkageUnit (visibility hidden)</li>
+ <li>global</li>
+ </ul>
+ </li>
+ <li>DefinitionKind
+ <ul>
+ <li>regular</li>
+ <li>tentative (ANSI C feature)</li>
+ <li>absolute (assembly code feature)</li>
+ <li>proxy (stand-in for dynamic library symbol)</li>
+ </ul>
+ </li>
+ <li>Combine
+ <ul>
+ <li>never</li>
+ <li>byName (weak symbols)</li>
+ <li>byContent (simple constants)</li>
+ <li>byContentAndReferences (complex constants)</li>
+ </ul>
+ </li>
+ <li>SymbolTableStatus
+ <ul>
+ <li>In</li>
+ <li>notIn (anonymous)</li>
+ <li>inAsAbsolute (assembly code feature)</li>
+ <li>inAndNeverStrip (tell strip tool to leave)</li>
+ <li>inWithRandomName (mach-o .o feature)</li>
+ </ul>
+ <li>Alignment
+ <ul>
+ <li>powerOfTwo</li>
+ <li>modulus</li>
+ </ul>
+ <li>NeverDeadStrip (boolean)</li>
+ <li>IsThumb (ARM specific)</li>
+</ul>
+<p>Where does dllexport fit in here? Where does visibility protected and
+internal fit? Protected seems like scope=global plus the rule to not
+indirect references to it. Internal is like hidden plus enables some
+compiler optimizations. I'm not sure the linker needs to know about internal.
+</p>
+
+</body>
+</html>
+
--- /dev/null
+.Dd November 10, 2010
+.Dt dyldinfo 1
+.Os Darwin
+.Sh NAME
+.Nm dyldinfo
+.Nd "Displays information used by dyld in an executable"
+.Sh SYNOPSIS
+.Nm
+.Op Fl arch Ar arch-name
+.Op Fl dylibs
+.Op Fl rebase
+.Op Fl bind
+.Op Fl weak_bind
+.Op Fl lazy_bind
+.Op Fl export
+.Op Fl opcodes
+.Op Fl function_starts
+.Ar file(s)
+.Sh DESCRIPTION
+Executables built for Mac OS X 10.6 and later have a new format for the
+information in the __LINKEDIT segment. The dyldinfo tool will display
+that information.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl arch Ar arch
+Only display the specified architecture. Other architectures in a universal image are ignored.
+.It Fl dylibs
+Display the table of dylibs on which this image depends.
+.It Fl rebase
+Display the table of rebasing information. Rebasing is what dyld does when an image is
+not loaded at its preferred address. Typically, this involves updating pointers in the __DATA
+segment which point within the image.
+.It Fl bind
+Display the table of binding information. These are the symbolic fix ups that dyld must
+do when an image is loaded.
+.It Fl weak_bind
+Display the table of weak binding information. Typically, only C++ progams will have any
+weak binding. These are symbols which dyld must unique accross all images.
+.It Fl lazy_bind
+Display the table of lazy binding information. These are symbols which dyld delays binding
+until they are first used. Lazy binding is automatically used for all function calls to
+functions in some external dylib.
+.It Fl export
+Display the table symbols which this image exports.
+.It Fl opcodes
+Display the low level opcodes used to encode all rebase and binding information.
+.It Fl function_starts
+Decodes the list of function start addresses.
+.El
+.Sh SEE ALSO
+.Xr otool 1
+.Xr nm 1
--- /dev/null
+.Dd March 7, 2011
+.Dt ld 1
+.Os Darwin
+.Sh NAME
+.Nm ld
+.Nd "linker"
+.Sh SYNOPSIS
+.Nm
+files...
+.Op options
+.Op Fl o Ar outputfile
+.Sh DESCRIPTION
+The
+.Nm ld
+command combines several object files and libraries, resolves references, and
+produces an ouput file.
+.Nm ld
+can produce a final linked image (executable, dylib, or bundle), or with the -r
+option, produce another object file. If the -o option is not used, the output
+file produced is named "a.out".
+.Ss Universal
+The linker accepts universal (multiple-architecture) input files, but
+always creates a "thin" (single-architecture), standard Mach-O output file.
+The architecture for the output file is specified using the -arch option.
+If this option is not used,
+.Nm ld
+attempts to determine the output architecture by examining the object
+files in command line order. The first "thin"
+architecture determines that of the output file. If no input
+object file is a "thin" file, the native 32-bit architecture for the host is used.
+.Pp
+Usually,
+.Nm ld
+is not used directly. Instead the
+.Xr gcc(1)
+compiler driver invokes
+.Nm ld.
+The compiler driver can be passed multiple -arch options and it will create a
+universal final linked image by invoking
+.Nm ld
+multiple times and then running
+.Xr lipo(1)
+merge the outputs into a universal file.
+.Ss Layout
+The object files are loaded in the order in which they are specified on the
+command line. The segments and the sections in those segments will appear in
+the output file in the order they are encountered in the object files being linked.
+All zero fill sections will appear after all non-zero fill sections in their segments.
+Sections created from files with the -sectcreate option will be laid out at after
+sections from .o files. The use of the -order_file option will alter the layout
+rules above, and move the symbols specified to start of their section.
+.Ss Libraries
+A static library (aka static archive) is a collection of .o files with a table of contents
+that lists the global symbols in the .o files.
+.Nm ld
+will only pull .o files out of a static library if needed to resolve some symbol reference.
+Unlike traditional linkers,
+.Nm ld
+will continually search a static library while linking. There is no need to specify a static
+library multiple times on the command line.
+.Pp
+A dynamic library (aka dylib or framework) is a final linked image. Putting a dynamic
+library on the command line causes two things: 1) The generated final linked image
+will have encoded that it depends on that dynamic library. 2) Exported symbols from the
+dynamic library are used to resolve references.
+.Pp
+Both dynamic and static libraries are searched as they appear on the command line.
+.Ss Search paths
+.Nm ld
+maintains a list of directories to search for a library or framework to use. The default
+library search path is /usr/lib then /usr/local/lib. The -L option will add a new library search
+path. The default framework search path is /Library/Frameworks then /System/Library/Frameworks.
+(Note: previously, /Network/Library/Frameworks was at the end of the default path. If you need
+that functionality, you need to explicitly add -F/Network/Library/Frameworks).
+The -F option will a new framework search path. The -Z option will remove
+the standard search paths. The -syslibroot option will prepend a prefix to all search
+paths.
+.Ss Two-level namespace
+By default all references resolved to a dynamic library record the library to which
+they were resolved. At runtime, dyld uses that information to directly resolve
+symbols. The alternative is to use the -flat_namespace option. With flat namespace,
+the library is not recorded. At runtime, dyld will search each dynamic library in load
+order when resolving symbols. This is slower, but more like how other operating systems
+resolve symbols.
+.Ss Indirect dynamic libraries
+If the command line specifies to link against dylib A, and when dylib A was built it linked
+against dylib B, then B is considered an indirect dylib.
+When linking for two-level namespace, ld does not look at indirect dylibs, except when
+re-exported by a direct dylibs. On the other hand when linking for flat namespace,
+ld does load all indirect dylibs and uses them to resolve references.
+Even though indirect dylibs are specified via a full path,
+.Nm ld
+first uses the specified search paths to locate each indirect dylib. If one cannot
+be found using the search paths, the full path is used.
+.Ss Dynamic libraries undefines
+When linking for two-level namespace,
+.Nm ld
+does not verify that undefines in dylibs actually
+exist. But when linking for flat namespace,
+.Nm ld
+does check that all undefines from all loaded dylibs have a matching definition.
+This is sometimes used to force selected functions to be loaded from a static library.
+.Sh OPTIONS
+.Ss Options that control the kind of output
+.Bl -tag
+.It Fl execute
+The default. Produce a mach-o main executable that has file type MH_EXECUTE.
+.It Fl dylib
+Produce a mach-o shared library that has file type MH_DYLIB.
+.It Fl bundle
+Produce a mach-o bundle that has file type MH_BUNDLE.
+.It Fl r
+Merges object files to produce another mach-o object file with file type MH_OBJECT.
+.It Fl dylinker
+Produce a mach-o dylinker that has file type MH_DYLINKER. Only used when building dyld.
+.It Fl dynamic
+The default. Implied by -dylib, -bundle, or -execute
+.It Fl static
+Produces a mach-o file that does not use the dyld. Only used building the kernel.
+.It Fl arch Ar arch_name
+Specifies which architecture (e.g. ppc, ppc64, i386, x86_64) the output file should be.
+.It Fl o Ar path
+Specifies the name and location of the output file. If not specified, `a.out' is used.
+.El
+.Ss Options that control libraries
+.Bl -tag
+.It Fl l Ns x
+This option tells the linker to search for libx.dylib or libx.a in the library search path.
+If string x is of the form y.o, then that file is searched for in the same places, but without
+prepending `lib' or appending `.a' or `.dylib' to the filename.
+.It Fl weak-l Ns Ar x
+This is the same as the -lx but forces the library and all references to it to be marked as weak imports.
+That is, the library is allowed to be missing at runtime.
+.It Fl weak_library Ar path_to_library
+This is the same as listing a file name path to a library on the link line except that it forces the
+library and all references to it to be marked as weak imports.
+.It Fl reexport-l Ns Ar x
+This is the same as the -lx but specifies that the all symbols in library x should be available to
+clients linking to the library being created. This was previously done with a separate -sub_library option.
+.It Fl reexport_library Ar path_to_library
+This is the same as listing a file name path to a library on the link line and it specifies that the
+all symbols in library path should be available to clients linking to the library being created.
+This was previously done with a separate -sub_library option.
+.It Fl lazy-l Ns Ar x
+This is the same as the -lx but it is only for shared libraries and the linker
+will construct glue code so that the shared library is not loaded until
+the first function in it is called.
+.It Fl lazy_library Ar path_to_library
+This is the same as listing a file name path to a shared library on the link line
+except that the linker will construct glue code so that the shared library is not
+loaded until the first function in it is called.
+.It Fl upward-l Ns Ar x
+This is the same as the -lx but specifies that the dylib is an upward dependency.
+.It Fl upward_library Ar path_to_library
+This is the same as listing a file name path to a library on the link line but also marks
+the dylib as an upward dependency.
+.It Fl L Ns dir
+Add
+.Ar dir
+to the list of directories in which to search for libraries.
+Directories specified with -L are searched in the order they appear on the command line
+and before the default search path. In Xcode4 and later, there can be a space between
+the -L and directory.
+.It Fl Z
+Do not search the standard directories when searching for libraries and frameworks.
+.It Fl syslibroot Ar rootdir
+Prepend
+.Ar rootdir
+to all search paths when searching for libraries or frameworks.
+.It Fl search_paths_first
+This is now the default (in Xcode4 tools). When processing -lx the linker now searches each directory
+in its library search paths for `libx.dylib' then `libx.a' before the moving on to the next path
+in the library search path.
+.It Fl search_dylibs_first
+Changes the searching behavior for libraries. The default is that when processing -lx the linker
+searches each directory in its library search paths for `libx.dylib' then `libx.a'.
+This option changes the behavior to first search for a file of the form `libx.dylib' in each directory
+in the library search path, then a file of the form `libx.a' is searched for in the library search paths.
+This option restores the search behavior of the linker prior to Xcode4.
+.It Fl framework Ar name[,suffix]
+This option tells the linker to search for `name.framework/name' the framework search path.
+If the optional suffix is specified the framework is first searched for the name with the suffix and then without
+(e.g. look for `name.framework/name_suffix' first, if not there try `name.framework/name').
+.It Fl weak_framework Ar name[,suffix]
+This is the same as the -framework name[,suffix] but forces the framework and all
+references to it to be marked as weak imports.
+.It Fl reexport_framework Ar name[,suffix]
+This is the same as the -framework name[,suffix] but also specifies that the
+all symbols in that framework should be available to clients linking to the library being created.
+This was previously done with a separate -sub_umbrella option.
+.It Fl lazy_framework Ar name[,suffix]
+This is the same as the -framework name[,suffix] except that the linker will
+construct glue code so that the framework is not
+loaded until the first function in it is called. You cannot directly access
+data or Objective-C classes in a framework linked this way.
+.It Fl upward_framework Ar name[,suffix]
+This is the same as the -framework name[,suffix] but also specifies that the
+framework is an upward dependency.
+.It Fl F Ns dir
+Add
+.Ar dir
+to the list of directories in which to search for frameworks.
+Directories specified with -F are searched in the order they appear on the command line
+and before the default search path. In Xcode4 and later, there can be a space between
+the -F and directory.
+.It Fl all_load
+Loads all members of static archive libraries.
+.It Fl ObjC
+Loads all members of static archive libraries that implement an Objective-C class or category.
+.It Fl force_load Ar path_to_archive
+Loads all members of the specified static archive library. Note: -all_load forces all members of all
+archives to be loaded. This option allows you to target a specific archive.
+.El
+.Ss Options that control additional content
+.Bl -tag
+.It Fl sectcreate Ar segname sectname file
+The section
+.Ar sectname
+in the segment
+.Ar segname
+is created from the contents of file
+.Ar file.
+The combination of segname and sectname must be unique Ð there cannot already be a section (segname,sectname)
+from any other input.
+.It Fl filelist Ar file[,dirname]
+Specifies that the linker should link the files listed in
+.Ar file .
+This is an alternative to listing the files on the command line.
+The file names are listed one per line separated only by newlines. (Spaces and tabs are assumed to be part of the file name.)
+If the optional directory name,
+.Ar dirname
+is specified, it is prepended to each name in the list file.
+.It Fl dtrace Ar file
+Enables dtrace static probes when producing a final linked image. The file
+.Ar file
+must be a DTrace script which declares the static probes.
+.El
+.Ss Options that control optimizations
+.Bl -tag
+.It Fl dead_strip
+Remove functions and data that are unreachable by the entry point or exported symbols.
+.It Fl order_file Ar file
+Alters the order in which functions and data are laid out. For each section in the output file,
+any symbol in that section that are specified in the order file
+.Ar file
+is moved to the start of its section and laid out in the same order as in the order file
+.Ar file .
+Order files are text files with one symbol name per line. Lines starting with a # are comments.
+A symbol name may be optionally preceded with its object file leaf name and a colon (e.g. foo.o:_foo).
+This is useful for static functions/data that occur in multiple files.
+A symbol name may also be optionally preceded with the architecture (e.g. ppc:_foo or ppc:foo.o:_foo).
+This enables you to have one order file that works for multiple architectures.
+Literal c-strings may be ordered by by quoting the string (e.g. "Hello, world\\n") in the order file.
+.It Fl no_order_inits
+When the -order_file option is not used, the linker lays out functions in object file order and
+it moves all initializer routines to the start of the __text section and terminator routines
+to the end. Use this option to disable the automatic rearrangement of initializers and terminators.
+.It Fl no_order_data
+By default the linker reorders global data in the __DATA segment so that all global variables that
+dyld will need to adjust at launch time will early in the __DATA segment. This reduces the number
+of dirty pages at launch time. This option disables that optimization.
+.It Fl macosx_version_min Ar version
+This is set to indicate the oldest Mac OS X version that that the output is to be used on. Specifying
+a later version enables the linker to assumes features of that OS in the output file. The format of
+.Ar version
+is a Mac OS X version number such as 10.4 or 10.5
+.It Fl ios_version_min Ar version
+This is set to indicate the oldest iOS version that that the output is to be used on. Specifying
+a later version enables the linker to assumes features of that OS in the output file. The format of
+.Ar version
+is an iOS version number such as 3.1 or 4.0
+.It Fl image_base Ar address
+Specifies the perferred load address for a dylib or bundle. The argument
+.Ar address
+is a hexadecimal number with an optional leading 0x. By choosing non-overlapping address for all
+dylibs and bundles that a program loads, launch time can be improved because dyld will not need to
+"rebase" the image (that is, adjust pointers within the image to work at the loaded address).
+It is often easier to not use this option, but instead use the rebase(1) tool, and give it a list of dylibs.
+It will then choose non-overlapping addresses for the list and rebase them all.
+This option is also called -seg1addr for compatibility.
+.It Fl no_implicit_dylibs
+When creating a two-level namespace final linked image, normally the linker will hoist up public dylibs
+that are implicitly linked to make the two-level namespace
+encoding more efficient for dyld. For example, Cocoa re-exports AppKit and AppKit re-exports Foundation.
+If you link with -framework Cocoa and use a symbol from Foundation, the linker will implicitly add a load
+command to load Foundation and encode the symbol as coming from Foundation. If you use this option,
+the linker will not add a load command for Foundation and encode the symbol as coming from Cocoa. Then
+at runtime dyld will have to search Cocoa and AppKit before finding the symbol in Foundation.
+.It Fl exported_symbols_order Ar file
+When targeting Mac OS X 10.6 or later, the format of the exported symbol information can be optimized to
+make lookups of popular symbols faster. This option is used to pass a file containing a list of
+the symbols most frequently used by clients of the dynamic library being built. Not all exported symbols
+need to be listed.
+.It Fl no_zero_fill_sections
+By default the linker moves all zero fill sections to the end of the __DATA segment and configures
+them to use no space on disk. This option suppresses that optimization, so zero-filled data occupies
+space on disk in a final linked image.
+.It Fl merge_zero_fill_sections
+Causes all zero-fill sections in the __DATA segment to be merged into one __zerofill section.
+.El
+.Ss Options when creating a dynamic library (dylib)
+.Bl -tag
+.It Fl install_name Ar name
+Sets an internal "install path" (LC_ID_DYLIB) in a dynamic library. Any clients linked against the library
+will record that path as the way dyld should locate this library. If this option is not specified, then
+the -o path will be used. This option is also called -dylib_install_name for compatibility.
+.It Fl mark_dead_strippable_dylib
+Specifies that the dylib being built can be dead strip by any client. That is, the dylib has
+no initialization side effects. So if a client links against the dylib, but never uses
+any symbol from it, the linker can optimize away the use of the dylib.
+.It Fl compatibility_version Ar number
+Specifies the compatibility version number of the library. When a library is loaded by dyld, the
+compatibility version is checked and if the program's version is greater that the library's version, it is an error.
+The format of
+.Ar number
+is X[.Y[.Z]] where X must be a positive non-zero number less than or equal to 65535,
+and .Y and .Z are optional and if present must be non-negative numbers less than or equal to 255.
+If the compatibility version number is not specified, it has a value of 0 and no checking is done when the library is used.
+This option is also called -dylib_compatibility_version for compatibility.
+.It Fl current_version Ar number
+Specifies the current version number of the library. The current version of the library can be obtained
+programmatically by the user of the library so it can determine exactly which version of the library it is using.
+The format of
+.Ar number
+is X[.Y[.Z]] where X must be a positive non-zero number less than or equal to 65535,
+and .Y and .Z are optional and if present must be non-negative numbers less than or equal to 255.
+If the version number is not specified, it has a value of 0.
+This option is also called -dylib_current_version for compatibility.
+.El
+.Ss Options when creating a main executable
+.Bl -tag
+.It Fl pie
+This makes a special kind of main executable that is position independent (PIE). On Mac OS X 10.5 and later, the OS
+the OS will load a PIE at a random address each time it is executed. You cannot create a PIE from .o files compiled
+with -mdynamic-no-pic. That means the codegen is less optimal, but the address randomization adds some
+security. When targeting Mac OS X 10.7 or later PIE is the default for main executables.
+.It Fl no_pie
+Do not make a position independent executable (PIE). This is the default, when targeting 10.6 and earlier.
+.It Fl pagezero_size Ar size
+By default the linker creates an unreadable segment starting at address zero named __PAGEZERO. Its existence
+will cause a bus error if a NULL pointer is dereferenced. The argument
+.Ar size
+is a hexadecimal number with an optional leading 0x. If
+.Ar size
+is zero, the linker will not generate a page zero segment. By default on 32-bit architectures the page zero size
+is 4KB. On 64-bit architectures, the default size is 4GB. The ppc64 architecture has some special cases. Since Mac
+OS X 10.4 did not support 4GB page zero programs, the default page zero size for ppc64 will be 4KB unless
+-macosx_version_min is 10.5 or later. Also, the -mdynamic-no-pic codegen model for ppc64 will only work if the
+code is placed in the lower 2GB of the address space, so the if the linker detects any such code, the page zero
+size is set to 4KB and then a new unreadable trailing segment is created after the code, filling up the lower 4GB.
+.It Fl stack_size Ar size
+Specifies the maximum stack size for the main thread in a program. Without this option a program has a 8MB stack.
+The argument
+.Ar size
+is a hexadecimal number with an optional leading 0x. The
+.Ar size
+should be an even multiple of 4KB, that is the last three hexadecimal digits should be zero.
+.It Fl allow_stack_execute
+Marks executable so that all stacks in the task will be given stack execution privilege. This includes pthread stacks.
+.El
+.Ss Options when creating a bundle
+.Bl -tag
+.It Fl bundle_loader Ar executable
+This specifies the
+.Ar executable
+that will be loading the bundle output file being linked.
+Undefined symbols from the bundle are checked against the specified
+.Ar executable
+like it was one of the
+dynamic libraries the bundle was linked with.
+.El
+.Ss Options when creating an object file
+.Bl -tag
+.It Fl keep_private_externs
+Don't turn private external (aka visibility=hidden) symbols into static symbols,
+but rather leave them as private external in the resulting object file.
+.It Fl d
+Force definition of common symbols. That is, transform tentative definitions into real definitions.
+.El
+.Ss Options that control symbol resolution
+.Bl -tag
+.It Fl exported_symbols_list Ar filename
+The specified
+.Ar filename
+contains a list of global symbol names that will remain as global symbols in the output file.
+All other global symbols will be treated as if they were marked as __private_extern__ (aka visibility=hidden)
+and will not be global in the output file. The symbol names listed in filename must be one per line.
+Leading and trailing white space are not part of the symbol name.
+Lines starting with # are ignored, as are lines with only white space.
+Some wildcards (similar to shell file matching) are supported. The * matches zero or more characters.
+The ? matches one character. [abc] matches one character which must be an 'a', 'b', or 'c'. [a-z] matches
+any single lower case letter from 'a' to 'z'.
+.It Fl exported_symbol Ar symbol
+The specified
+.Ar symbol
+is added to the list of global symbols names that will remain as global symbols in the output file. This
+option can be used multiple times. For short lists, this can be more convenient than creating a file and using
+-exported_symbols_list.
+.It Fl unexported_symbols_list Ar file
+The specified
+.Ar filename
+contains a list of global symbol names that will not remain as global symbols in the output file.
+The symbols will be treated as if they were marked as __private_extern__ (aka visibility=hidden) and will not be global
+in the output file. The symbol names listed in filename must be one per line.
+Leading and trailing white space are not part of the symbol name.
+Lines starting with # are ignored, as are lines with only white space.
+Some wildcards (similar to shell file matching) are supported. The * matches zero or more characters.
+The ? matches one character. [abc] matches one character which must be an 'a', 'b', or 'c'. [a-z] matches
+any single lower case letter from 'a' to 'z'.
+.It Fl unexported_symbol Ar symbol
+The specified
+.Ar symbol
+is added to the list of global symbols names that will not remain as global symbols in the output file. This
+option can be used multiple times. For short lists, this can be more convenient than creating a file and using
+-unexported_symbols_list.
+.It Fl reexported_symbols_list Ar file
+The specified
+.Ar filename
+contains a list of symbol names that are implemented in a dependent dylib and should be re-exported
+through the dylib being created.
+.It Fl alias Ar symbol_name Ar alternate_symbol_name
+Create an alias named
+.Ar alternate_symbol_name
+for the symbol
+.Ar symbol_name .
+By default the alias symbol has global visibility. This option was previous the -idef:indir option.
+.It Fl alias_list Ar filename
+The specified
+.Ar filename
+contains a list of aliases. The symbol name and its alias are on one line, separated by whitespace.
+Lines starting with # are ignored.
+.It Fl flat_namespace
+Alters how symbols are resolved at build time and runtime. With -two_levelnamespace (the default), the linker
+only searches dylibs on the command line for symbols, and records in which dylib they were found. With -flat_namespace,
+the linker searches all dylibs on the command line and all dylibs those original dylibs depend on. The linker
+does not record which dylib an external symbol came from, so at runtime dyld again searches all images and uses
+the first definition it finds. In addition, any undefines in loaded flat_namespace dylibs must be resolvable
+at build time.
+.It Fl u Ar symbol_name
+Specified that symbol
+.Ar symbol_name
+must be defined for the link to succeed. This is useful to force selected functions to be loaded
+from a static library.
+.It Fl U Ar symbol_name
+Specified that it is ok for
+.Ar symbol_name
+to have no definition. With -two_levelnamespace, the resulting symbol will be marked dynamic_lookup which
+means dyld will search all loaded images.
+.It Fl undefined Ar treatment
+Specifies how undefined symbols are to be treated. Options are: error, warning, suppress, or dynamic_lookup. The
+default is error.
+.It Fl rpath Ar path
+Add
+.Ar path
+to the runpath search path list for image being created. At runtime, dyld uses the runpath when searching
+for dylibs whose load path begins with @rpath/.
+.It Fl commons Ar treatment
+Specifies how commons (aka tentative definitions) are resolved with respect to dylibs. Options are:
+ignore_dylibs, use_dylibs, error. The default is ignore_dylibs which means the linker will turn a tentative
+definition in an object file into a real definition and not even check dylibs for conflicts. The dylibs
+option means the linker should check linked dylibs for definitions and use them to replace tentative definitions
+from object files. The error option means the linker should issue an error whenever a tentative definition in an
+object file conflicts with an external symbol in a linked dylib. See also -warn_commons.
+.El
+.Ss Options for introspecting the linker
+.Bl -tag
+.It Fl why_load
+Log why each object file in a static library is loaded. That is, what symbol was needed. Also called -whyload
+for compatibility.
+.It Fl why_live Ar symbol_name
+Logs a chain of references to
+.Ar symbol_name .
+Only applicable with -dead_strip .
+It can help debug why something that you think should be dead strip removed is not removed.
+.It Fl print_statistics
+Logs information about the amount of memory and time the linker used.
+.It Fl t
+Logs each file (object, archive, or dylib) the linker loads. Useful for debugging problems with search paths where the wrong library is loaded.
+.It Fl whatsloaded
+Logs just object files the linker loads.
+.It Fl order_file_statistics
+Logs information about the processing of a -order_file.
+.It Fl map Ar map_file_path
+Writes a map file to the specified path which details all symbols and their addresses in the output image.
+.El
+.Ss Options for controling symbol table optimizations
+.Bl -tag
+.It Fl S
+Do not put debug information (STABS or DWARF) in the output file.
+.It Fl x
+Do not put non-global symbols in the output file's symbol table. Non-global symbols are useful when debugging and
+getting symbol names in back traces, but are not used at runtime. If -x is used with -r
+non-global symbol names are not removed, but instead replaced with a unique, dummy name
+that will be automatically removed when linked into a final linked image. This
+allows dead code stripping, which uses symbols to break up code and data, to
+work properly and provides the security of having source symbol names removed.
+.It Fl non_global_symbols_strip_list Ar filename
+The specified
+.Ar filename
+contains a list of non-global symbol names that should be removed from the output file's symbol table. All other
+non-global symbol names will remain in the output files symbol table. See -exported_symbols_list for syntax and use
+of wildcards.
+.It Fl non_global_symbols_no_strip_list Ar filename
+The specified
+.Ar filename
+contains a list of non-global symbol names that should be remain in the output file's symbol table. All other
+symbol names will be removed from the output file's symbol table. See -exported_symbols_list for syntax and use
+of wildcards.
+.El
+.Ss Rarely used Options
+.Bl -tag
+.It Fl v
+Prints the version of the linker.
+.It Fl allow_heap_execute
+Normally i386 main executables will be marked so that the Mac OS X 10.7 and later kernel
+will only allow pages with the x-bit to execute instructions. This option overrides that
+behavior and allows instructions on any page to be executed.
+.It Fl fatal_warnings
+Causes the linker to exit with a non-zero value if any warnings were emitted.
+.It Fl no_eh_labels
+Normally in -r mode, the linker produces .eh labels on all FDEs in the __eh_frame section.
+This option suppresses those labels. Those labels are not needed by the Mac OS X 10.6
+linker but are needed by earlier linker tools.
+.It Fl warn_compact_unwind
+When producing a final linked image, the linker processes the __eh_frame section and
+produces an __unwind_info section. Most FDE entries in the __eh_frame can be represented
+by a 32-bit value in the __unwind_info section. The option issues a warning for
+any function whose FDE cannot be expressed in the compact unwind format.
+.It Fl warn_weak_exports
+Issue a warning if the resulting final linked image contains weak external symbols. Such
+symbols require dyld to do extra work at launch time to coalesce those symbols.
+.It Fl objc_gc_compaction
+Marks the Objective-C image info in the final linked image with the bit that says that the
+code was built to work the compacting garbage collection.
+.It Fl objc_gc
+Verifies all code was compiled with -fobjc-gc or -fobjc-gc-only.
+.It Fl objc_gc_only
+Verifies all code was compiled with -fobjc-gc-only.
+.It Fl dead_strip_dylibs
+Remove dylibs that are unreachable by the entry point or exported symbols. That is,
+suppresses the generation of load command commands for dylibs which supplied no
+symbols during the link. This option should not be used when linking against a dylib which
+is required at runtime for some indirect reason such as the dylib has an important initializer.
+.It Fl allow_sub_type_mismatches
+Normally the linker considers different cpu-subtype for ARM (e.g. armv4t and armv6) to be different
+different architectures that cannot be mixed at build time. This option relaxes that requirement,
+allowing you to mix object files compiled for different ARM subtypes.
+.It Fl no_uuid
+Do not generate an LC_UUID load command in the output file.
+.It Fl root_safe
+Sets the MH_ROOT_SAFE bit in the mach header of the output file.
+.It Fl setuid_safe
+Sets the MH_SETUID_SAFE bit in the mach header of the output file.
+.It Fl interposable
+Indirects access to all to exported symbols when creating a dynamic library.
+.It Fl init Ar symbol_name
+The specified symbol_name will be run as the first initializer. Only used when creating a dynamic library.
+.It Fl sub_library Ar library_name
+The specified dylib will be re-exported. For example the library_name for /usr/lib/libobjc_profile.A.dylib would be libobjc.
+Only used when creating a dynamic library.
+.It Fl sub_umbrella Ar framework_name
+The specified framework will be re-exported. Only used when creating a dynamic library.
+.It Fl allowable_client Ar name
+Restricts what can link against the dynamic library being created. By default any code
+can link against any dylib. But if a dylib is supposed to be private to a small
+set of clients, you can formalize that by adding a -allowable_client for each client.
+If a client is libfoo.1.dylib its -allowable_client name would be "foo". If a
+client is Foo.framework its -allowable_client name would be "Foo". For the degenerate
+case where you want no one to ever link against a dylib, you can set the
+-allowable_client to "!".
+.It Fl client_name Ar name
+Enables a bundle to link against a dylib that was built with -allowable_client.
+The name specified must match one of the -allowable_client names specified when the dylib was created.
+.It Fl umbrella Ar framework_name
+Specifies that the dylib being linked is re-exported through an umbrella framework of the specified name.
+.It Fl headerpad Ar size
+Specifies the minimum space for future expansion of the load commands. Only useful if intend to run
+install_name_tool to alter the load commands later. Size is a hexadecimal number.
+.It Fl headerpad_max_install_names
+Automatically adds space for future expansion of load commands such that all paths could expand to MAXPATHLEN.
+Only useful if intend to run install_name_tool to alter the load commands later.
+.It Fl bind_at_load
+Sets a bit in the mach header of the resulting binary which tells dyld to bind all symbols when the binary is loaded, rather than lazily.
+.It Fl force_flat_namespace
+Sets a bit in the mach header of the resulting binary which tells dyld to not only use flat namespace for the binary,
+but force flat namespace binding on all dylibs and bundles loaded in the process. Can only be used when linking main executables.
+.It Fl sectalign Ar segname Ar sectname Ar value
+The section named sectname in the segment segname will have its alignment set to value, where value is a hexadecimal
+number that must be an integral power of 2.
+.It Fl stack_addr Ar address
+Specifies the initial address of the stack pointer value, where value is a hexadecimal number rounded to a page boundary.
+.It Fl segprot Ar segname Ar max_prot Ar init_prot
+Specifies the maximum and initial virtual memory protection of the named segment, name, to be max and init ,respectively.
+The values for max and init are any combination of the characters `r' (for read), `w' (for write), `x' (for execute) and `-' (no access).
+.It Fl seg_addr_table Ar filename
+Specifies a file containing base addresses for dynamic libraries. Each line of the file is a hexadecimal base address
+followed by whitespace then the install name of the corresponding dylib. The # character denotes a comment.
+.It Fl segs_read_write_addr Ar address
+Allows a dynamic library to be built where the read-only and read-write segments are not contiguous. The address
+specified is a hexadecimal number that indicates the base address for the read-write segments.
+.It Fl segs_read_only_addr Ar address
+Allows a dynamic library to be built where the read-only and read-write segments are not contiguous. The address
+specified is a hexadecimal number that indicates the base address for the read-only segments.
+.It Fl segaddr Ar name Ar address
+Specifies the starting address of the segment named name to be address. The address must be a hexadecimal number
+that is a multiple of 4K page size.
+.It Fl seg_page_size Ar name Ar size
+Specifies the page size used by the specified segment. By default the page size is 4096 for all segments.
+The linker will lay out segments such that size of a segment is always an even multiple of its page size.
+.It Fl dylib_file Ar install_name:file_name
+Specifies that a dynamic shared library is in a different location than its standard location. Use this option
+when you link with a library that is dependent on a dynamic library, and the dynamic library is in a location other
+than its default location. install_name specifies the path where the library normally resides. file_name specifies
+the path of the library you want to use instead. For example, if you link to a library that depends upon the dynamic
+library libsys and you have libsys installed in a nondefault location, you would use this option:
+-dylib_file /lib/libsys_s.A.dylib:/me/lib/libsys_s.A.dylib.
+.It Fl prebind
+The created output file will be in the prebound format. This was used in Mac OS X 10.3 and earlier to improve launch performance.
+.It Fl weak_reference_mismatches Ar treatment
+Specifies what to do if a symbol is weak-imported in one object file but not weak-imported in another. The valid
+treatments are: error, weak, or non-weak. The default is non-weak.
+.It Fl read_only_relocs Ar treatment
+Enables the use of relocations which will cause dyld to modify (copy-on-write) read-only pages. The compiler will
+normally never generate such code.
+.It Fl force_cpusubtype_ALL
+The is only applicable with -arch ppc. It tells the linker to ignore the PowerPC cpu requirements (e.g. G3, G4 or G5) encoded
+in the object files and mark the resulting binary as runnable on any PowerPC cpu.
+.It Fl dylinker_install_name Ar path
+Only used when building dyld.
+.It Fl no_arch_warnings
+Suppresses warning messages about files that have the wrong architecture for the -arch flag
+.It Fl arch_errors_fatal
+Turns into errors, warnings about files that have the wrong architecture for the -arch flag.
+.It Fl e Ar symbol_name
+Specifies the entry point of a main executable. By default the entry name is "start" which is found in crt1.o which contains
+the glue code need to set up and call main().
+.It Fl w
+Suppress all warning messages
+.It Fl final_output Ar name
+Specifies the install name of a dylib if -install_name is not used. This option is used by gcc driver when it is invoked
+with multiple -arch arguments.
+.It Fl arch_multiple
+Specifes that the linker should augment error and warning messages with the architecture name. This option is used by gcc
+driver when it is invoked with multiple -arch arguments.
+.It Fl twolevel_namespace_hints
+Specifies that hints should be added to the resulting binary that can help speed up runtime binding by dyld as long as the
+libraries being linked against have not changed.
+.It Fl dot Ar path
+Create a file at the specified path containing a graph of symbol dependencies. The .dot file can be viewed in GraphViz.
+.It Fl keep_relocs
+Add section based relocation records to a final linked image. These relocations are ignored at runtime by dyld.
+.It Fl warn_stabs
+Print a warning when the linker cannot do a BINCL/EINCL optimization because the compiler put a bad stab symbol inside
+a BINCL/EINCL range.
+.It Fl warn_commons
+Print a warning whenever the a tentative definition in an object file is found and a external symbol by the same name
+is also found in a linked dylib. This often means that the extern keyword is missing from a variable declaration
+in a header file.
+.It Fl read_only_stubs
+[i386 only] Makes the __IMPORT segment of a final linked images read-only. This option makes a program slightly more
+secure in that the JMP instructions in the i386 fast stubs cannot be easily overwritten by malicious code. The downside
+is the dyld must use mprotect() to temporarily make the segment writable while it is binding the stubs.
+.It Fl slow_stubs
+[i386 only] Instead of using single JMP instruction stubs, the linker creates code in the __TEXT segment which
+calls through a lazy pointer in the __DATA segment.
+.It Fl interposable_list Ar filename
+The specified
+.Ar filename
+contains a list of global symbol names that should always be accessed indirectly. For instance, if libSystem.dylib
+is linked such that _malloc is interposable, then calls to malloc() from within libSystem will go through a dyld
+stub and could potentially indirected to an alternate malloc. If libSystem.dylib were built without making _malloc
+interposable then if _malloc was interposed at runtime, calls to malloc from with libSystem would be missed
+(not interposed) because they would be direct calls.
+.It Fl no_function_starts
+By default the linker creates a compress table of function start addresses in the LINKEDIT of
+final linked image. This option disables that behavior.
+.It Fl no_version_load_command
+By default the linker creates a load command in final linked images that contains the -macosx_version_min.
+This option disables that behavior.
+.It Fl no_objc_category_merging
+By default when producing final linked image, the linker will optimize Objective-C classes by merging
+any categories on a class into the class. Both the class and its categories must be defined in the image
+being linked for the optimization to occur. Using this option disables that behavior.
+.It Fl object_path_lto Ar filename
+When performing Link Time Optimization (LTO) and a temporary mach-o object file is needed, if this
+option is used, the temporary file will be stored at the specified path and remain after the link
+is complete. Without the option, the linker picks a path and deletes the object file before the linker
+tool completes, thus tools such as the debugger or dsymutil will not be able to access the DWARF debug
+info in the temporary object file.
+.It Fl page_align_data_atoms
+During development, this option can be used to space out all global variables so each is on a separate page.
+This is useful when analyzing dirty and resident pages. The information can then be used to create an
+order file to cluster commonly used/dirty globals onto the same page(s).
+.El
+.Ss Obsolete Options
+.Bl -tag
+.It Fl segalign Ar value
+All segments must be page aligned. This option is obsolete.
+.It Fl seglinkedit
+Object files (MH_OBJECT) with a LINKEDIT segment are no longer supported. This option is obsolete.
+.It Fl noseglinkedit
+This is the default. This option is obsolete.
+.It Fl fvmlib
+Fixed VM shared libraries (MH_FVMLIB) are no longer supported. This option is obsolete.
+.It Fl preload
+Preload executables (MH_PRELOAD) are no longer supported. This option is obsolete.
+.It Fl sectobjectsymbols Ar segname Ar sectname
+Adding a local label at a section start is no longer supported. This option is obsolete.
+.It Fl nofixprebinding
+The MH_NOFIXPREBINDING bit of mach_headers has been ignored since Mac OS X 10.3.9. This option is obsolete.
+.It Fl noprebind_all_twolevel_modules
+Multi-modules in dynamic libraries have been ignored at runtime since Mac OS X 10.4.0. This option is obsolete.
+.It Fl prebind_all_twolevel_modules
+Multi-modules in dynamic libraries have been ignored at runtime since Mac OS X 10.4.0. This option is obsolete.
+.It Fl prebind_allow_overlap
+When using -prebind, the linker allows overlapping by default, so this option is obsolete.
+.It Fl noprebind
+LD_PREBIND is no longer supported as a way to force on prebinding, so there no longer needs to
+be a command line way to override LD_PREBIND. This option is obsolete.
+.It Fl sect_diff_relocs Ar treatment
+This option was an attempt to warn about linking .o files compiled without -mdynamic-no-pic into
+a main executable, but the false positive rate generated too much noise to make the option useful.
+This option is obsolete.
+.It Fl run_init_lazily
+This option was removed in Mac OS X 10.2.
+.It Fl single_module
+This is now the default so does not need to be specified.
+.It Fl multi_module
+Multi-modules in dynamic libraries have been ignored at runtime since Mac OS X 10.4.0. This option is obsolete.
+.It Fl no_dead_strip_inits_and_terms
+The linker never dead strips initialization and termination routines. They are considered "roots" of the dead strip graph.
+.It Fl A Ar basefile
+Obsolete incremental load format. This option is obsolete.
+.It Fl b
+Used with -A option to strip base file's symbols. This option is obsolete.
+..It Fl M
+Obsolete option to produce a load map. Use -map option instead.
+.It Fl Sn
+Don't strip any symbols. This is the default. This option is obsolete.
+.It Fl Si
+Optimize stabs debug symbols to remove duplicates. This is the default. This option is obsolete.
+.It Fl Sp
+Write minimal stabs which causes the debugger to open and read the original .o file for full stabs.
+This style of debugging is obsolete in Mac OS X 10.5. This option is obsolete.
+.It Fl X
+Strip local symbols that begin with 'L'. This is the default. This option is obsolete.
+.It Fl s
+Completely strip the output, including removing the symbol table. This file format variant is no longer supported.
+This option is obsolete.
+.It Fl m
+Don't treat multiple definitions as an error. This is no longer supported. This option is obsolete.
+.It Fl y Ns symbol
+Display each file in which
+.Ar symbol
+is used. This was previously used to debug where an undefined symbol was used, but the linker now
+automatically prints out all usages. The -why_live option can also be used to display what kept
+a symbol from being dead striped. This option is obsolete.
+.It Fl Y Ar number
+Used to control how many occurrences of each symbol specified with -y would be shown. This option is obsolete.
+.It Fl nomultidefs
+Only used when linking an umbrella framework. Sets the MH_NOMULTIDEFS bit in the mach_header. The MH_NOMULTIDEFS
+bit has been obsolete since Mac OS X 10.4. This option is obsolete.
+.It Fl multiply_defined_unused Ar treatment
+Previously provided a way to warn or error if any of the symbol definitions in the output file matched any
+definitions in dynamic library being linked. This option is obsolete.
+.It Fl multiply_defined Ar treatment
+Previously provided a way to warn or error if any of the symbols used from a dynamic library were also
+available in another linked dynamic library. This option is obsolete.
+.It Fl private_bundle
+Previously prevented errors when -flat_namespace, -bundle, and -bundle_loader were used and the bundle
+contained a definition that conflicted with a symbol in the main executable. The linker no longer
+errors on such conflicts. This option is obsolete.
+.It Fl noall_load
+This is the default. This option is obsolete.
+.It Fl seg_addr_table_filename Ar path
+Use
+.Ar path
+instead of the install name of the library for matching an entry in the seg_addr_table. This option is obsolete.
+.It Fl sectorder Ar segname sectname orderfile
+Replaced by more general -order_file option.
+.It Fl sectorder_detail
+Produced extra logging about which entries from a sectorder entries were used. Replaced by -order_file_statistics.
+This option is obsolete.
+.El
+.Sh SEE ALSO
+as(1), ar(1), cc(1), nm(1), otool(1) lipo(1),
+arch(3), dyld(3), Mach-O(5), strip(1), rebase(1)
--- /dev/null
+.so man1/ld.1
--- /dev/null
+.Dd June 6, 2006
+.Dt rebase 1
+.Os Darwin
+.Sh NAME
+.Nm rebase
+.Nd "Changes base address of dylibs and bundles"
+.Sh SYNOPSIS
+.Nm
+.Op Fl low_address Ar addr
+.Op Fl high_address Ar addr
+.Op Fl arch Ar arch
+.Op Fl v
+.Ar file(s)
+.Sh DESCRIPTION
+The base address of an image (dylib or bundle) is the preferred address for it to be loaded. By
+default all images are built with a base address of zero. At runtime, if the
+preferred memory range is already occupied, dyld will "slide" the image to a new address range.
+There is a small cost to the slide, as dyld must do some fix ups.
+The rebase tool takes a list of images and adjust their base address to be non-overlapping. If no
+low or high address is specified, the a suitable address range is choosen for the architecture.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl low_address Ar addr
+Force the base address for the first image to be
+.Ar addr
+(specified in hex). Each subsequent file gets the next available base address.
+.It Fl high_address Ar addr
+Force the base address for the last image to be such that when that image is loaded it occupies
+memory up to
+.Ar addr
+(specified in hex). Each preceeding file gets the previous available base address.
+.It Fl arch Ar arch
+Only rebase the specified architecture. Other architectures in a universal image are left as is.
+.It Fl v
+Verbose. Print information about rebasing done.
+.El
+.Sh SEE ALSO
+.Xr ld 1
--- /dev/null
+.Dd November 7, 2008
+.Dt unwinddump 1
+.Os Darwin
+.Sh NAME
+.Nm unwinddump
+.Nd "Displays compact unwind information in an executable"
+.Sh SYNOPSIS
+.Nm
+.Op Fl arch Ar arch-name
+.Ar file(s)
+.Sh DESCRIPTION
+When a C++ (or x86_64 Objective-C) exception is thrown, the runtime must unwind
+the stack looking for some function to catch the exception. Traditionally,
+the unwind information is stored in the __TEXT/__eh_frame section of each executable
+as Dwarf CFI (call frame information). Beginning in Mac OS X 10.6, the unwind
+information is also encoded in the __TEXT/__unwind_info section using a two-level
+lookup table of compact unwind encodings.
+.Pp
+The unwinddump tool displays the content of the __TEXT/__unwind_info section.
+.Sh SEE ALSO
+.Xr ld 1
+.Xr dwarfdump 1
--- /dev/null
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ F96D5368094A2754008E9EE8 /* unit-tests */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = F96D536D094A2773008E9EE8 /* Build configuration list for PBXAggregateTarget "unit-tests" */;
+ buildPhases = (
+ F96D5367094A2754008E9EE8 /* ShellScript */,
+ );
+ dependencies = (
+ F96D536A094A275D008E9EE8 /* PBXTargetDependency */,
+ F96D536C094A275F008E9EE8 /* PBXTargetDependency */,
+ F96904890A4333AC00B77D2A /* PBXTargetDependency */,
+ F9EA73970974999B008B4F1D /* PBXTargetDependency */,
+ F9B693890EC4D28C00076912 /* PBXTargetDependency */,
+ F9F9AD68116D58AF0028EFAB /* PBXTargetDependency */,
+ );
+ name = "unit-tests";
+ productName = "unit-tests";
+ };
+ F9B1A2670A3A567B00DA8FAB /* all */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = F9B1A26C0A3A568700DA8FAB /* Build configuration list for PBXAggregateTarget "all" */;
+ buildPhases = (
+ F9871A3413340B4600DB3F24 /* Platform install */,
+ );
+ dependencies = (
+ F9B1A2690A3A568200DA8FAB /* PBXTargetDependency */,
+ F9B1A26B0A3A568400DA8FAB /* PBXTargetDependency */,
+ F9C12EEA0ED65765005BC69D /* PBXTargetDependency */,
+ F9B8135D0EC2620E00F94C13 /* PBXTargetDependency */,
+ F9A3DE160ED76D9A00C590B9 /* PBXTargetDependency */,
+ );
+ name = all;
+ productName = all;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ B3B672421406D42800A376BB /* Snapshot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B3B672411406D42800A376BB /* Snapshot.cpp */; };
+ F9023C4E06D5A272001BBF46 /* ld.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9023C3F06D5A254001BBF46 /* ld.cpp */; };
+ F933E3D9092E855B0083EAC8 /* ObjectDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F971EED706D5AD240041D381 /* ObjectDump.cpp */; };
+ F93CB248116E69EB003233B8 /* tlvp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F93CB246116E69EB003233B8 /* tlvp.cpp */; };
+ F97F5029070D0BB200B9FCD7 /* ld.1 in copy man page */ = {isa = PBXBuildFile; fileRef = F97F5028070D0BB200B9FCD7 /* ld.1 */; };
+ F98498A310AE2159009E9878 /* compact_unwind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9BA963310A2545C0097A440 /* compact_unwind.cpp */; };
+ F98498A410AE2159009E9878 /* got.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AB1063107D380700E54C9E /* got.cpp */; };
+ F9849E3610B38EF5009E9878 /* order.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9849E3410B38EF5009E9878 /* order.cpp */; };
+ F984A38210BB4B0D009E9878 /* branch_island.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F984A38010BB4B0D009E9878 /* branch_island.cpp */; };
+ F989D30D106826020014B60C /* OutputFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F989D30B106826020014B60C /* OutputFile.cpp */; };
+ F9A3DDD30ED762E400C590B9 /* PruneTrie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9A3DDD20ED762E400C590B9 /* PruneTrie.cpp */; };
+ F9A3DE1E0ED7738300C590B9 /* prune_trie.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = F9A3DE0F0ED76D1900C590B9 /* prune_trie.h */; };
+ F9A4DB9110F816FF00BD8423 /* objc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9A4DB8F10F816FF00BD8423 /* objc.cpp */; };
+ F9AA44DC1294885F00CB8390 /* branch_shim.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA44DA1294885F00CB8390 /* branch_shim.cpp */; };
+ F9AA65111051BD2B003E3539 /* stubs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA65101051BD2B003E3539 /* stubs.cpp */; };
+ F9AA65891051E750003E3539 /* macho_relocatable_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA65871051E750003E3539 /* macho_relocatable_file.cpp */; };
+ F9AA65DD1051EC4A003E3539 /* archive_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA65D71051EC4A003E3539 /* archive_file.cpp */; };
+ F9AA65DE1051EC4A003E3539 /* lto_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA65D91051EC4A003E3539 /* lto_file.cpp */; };
+ F9AA65DF1051EC4A003E3539 /* macho_dylib_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA65DB1051EC4A003E3539 /* macho_dylib_file.cpp */; };
+ F9AA6786105700C2003E3539 /* opaque_section_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA6784105700C2003E3539 /* opaque_section_file.cpp */; };
+ F9AA67B610570C41003E3539 /* dtrace_dof.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA67B510570C41003E3539 /* dtrace_dof.cpp */; };
+ F9AA687C10572E27003E3539 /* InputFiles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA687A10572E27003E3539 /* InputFiles.cpp */; };
+ F9AA69B610583C0C003E3539 /* SymbolTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA69B410583C0C003E3539 /* SymbolTable.cpp */; };
+ F9AA69C110583E19003E3539 /* Resolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA69BF10583E19003E3539 /* Resolver.cpp */; };
+ F9AA6FF910618CD2003E3539 /* macho_relocatable_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA65871051E750003E3539 /* macho_relocatable_file.cpp */; };
+ F9AE20FF1107D1440007ED5D /* dylibs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AE20FD1107D1440007ED5D /* dylibs.cpp */; };
+ F9AE23291109015E0007ED5D /* lto_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA65D91051EC4A003E3539 /* lto_file.cpp */; };
+ F9B1A2640A3A563E00DA8FAB /* rebase.1 in install man page */ = {isa = PBXBuildFile; fileRef = F9B1A2580A3A448800DA8FAB /* rebase.1 */; };
+ F9B670120DDA17E800E6D0DA /* UnwindDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9B670110DDA17E800E6D0DA /* UnwindDump.cpp */; };
+ F9B813850EC2657800F94C13 /* unwinddump.1 in install man page */ = {isa = PBXBuildFile; fileRef = F9B813810EC2653000F94C13 /* unwinddump.1 */; };
+ F9BA51650ECE58C800D1D62E /* dyldinfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9BA515B0ECE58AA00D1D62E /* dyldinfo.cpp */; };
+ F9BA955E10A233000097A440 /* huge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9BA955C10A233000097A440 /* huge.cpp */; };
+ F9C0D4BD06DD28D2001C7193 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9C0D48A06DD1E1B001C7193 /* Options.cpp */; };
+ F9C12EA30ED63DE7005BC69D /* dyldinfo.1 in install man page */ = {isa = PBXBuildFile; fileRef = F9C12E9F0ED63DB1005BC69D /* dyldinfo.1 */; };
+ F9CC24191461FB4300A92174 /* blob.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9CC24141461FB4300A92174 /* blob.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 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXBuildRule section */
+ F9E8D4BD07FCAF2000FD5801 /* PBXBuildRule */ = {
+ isa = PBXBuildRule;
+ compilerSpec = com.apple.compilers.llvm.clang.1_0;
+ fileType = sourcecode.c;
+ isEditable = 1;
+ outputFiles = (
+ );
+ };
+ F9E8D4BE07FCAF2A00FD5801 /* PBXBuildRule */ = {
+ isa = PBXBuildRule;
+ compilerSpec = com.apple.compilers.llvm.clang.1_0;
+ fileType = sourcecode.cpp;
+ isEditable = 1;
+ outputFiles = (
+ );
+ };
+/* End PBXBuildRule section */
+
+/* Begin PBXContainerItemProxy section */
+ F96904880A4333AC00B77D2A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F9EC77ED0A2F85F6002A3E39;
+ remoteInfo = rebase;
+ };
+ F96D5369094A275D008E9EE8 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F9023C3806D5A23E001BBF46;
+ remoteInfo = ld;
+ };
+ F96D536B094A275F008E9EE8 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F971EED206D5ACF60041D381;
+ remoteInfo = ObjectDump;
+ };
+ F9A3DE150ED76D9A00C590B9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F9A3DDC90ED762B700C590B9;
+ remoteInfo = libprunetrie;
+ };
+ F9B1A2680A3A568200DA8FAB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F9023C3806D5A23E001BBF46;
+ remoteInfo = ld;
+ };
+ F9B1A26A0A3A568400DA8FAB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F9EC77ED0A2F85F6002A3E39;
+ remoteInfo = rebase;
+ };
+ F9B693880EC4D28C00076912 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F9B670010DDA176100E6D0DA;
+ remoteInfo = unwinddump;
+ };
+ F9B8135C0EC2620E00F94C13 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F9B670010DDA176100E6D0DA;
+ remoteInfo = unwinddump;
+ };
+ F9C12EE90ED65765005BC69D /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F9BA51600ECE58BE00D1D62E;
+ remoteInfo = dyldinfo;
+ };
+ F9EA73960974999B008B4F1D /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F9EA72CA097454A6008B4F1D;
+ remoteInfo = machocheck;
+ };
+ F9F9AD67116D58AF0028EFAB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F9BA51600ECE58BE00D1D62E;
+ remoteInfo = dyldinfo;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ F97F5025070D0B6300B9FCD7 /* copy man page */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ F97F5029070D0BB200B9FCD7 /* ld.1 in copy man page */,
+ );
+ name = "copy man page";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ F9A3DE140ED76D7700C590B9 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = "/usr/local/include/mach-o";
+ dstSubfolderSpec = 0;
+ files = (
+ F9A3DE1E0ED7738300C590B9 /* prune_trie.h in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ F9B1A25E0A3A44CB00DA8FAB /* install man page */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ F9B1A2640A3A563E00DA8FAB /* rebase.1 in install man page */,
+ );
+ name = "install man page";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ F9B813870EC2659600F94C13 /* install man page */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ F9B813850EC2657800F94C13 /* unwinddump.1 in install man page */,
+ );
+ name = "install man page";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ F9C12EA50ED63E05005BC69D /* install man page */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ F9C12EA30ED63DE7005BC69D /* dyldinfo.1 in install man page */,
+ );
+ name = "install man page";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ B3B672411406D42800A376BB /* Snapshot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Snapshot.cpp; path = src/ld/Snapshot.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ B3B672441406D44300A376BB /* Snapshot.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = Snapshot.h; path = src/ld/Snapshot.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ B3C7A09914295B9C005FC714 /* compile_stubs */ = {isa = PBXFileReference; lastKnownFileType = text.script.csh; path = compile_stubs; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9023C3906D5A23E001BBF46 /* ld */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ld; sourceTree = BUILT_PRODUCTS_DIR; };
+ F9023C3F06D5A254001BBF46 /* ld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ld.cpp; path = src/ld/ld.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F92D9C2710657AAB00FF369B /* stub_x86_64_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_64_classic.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F933D9460929277C0083EAC8 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FileAbstraction.hpp; path = src/abstraction/FileAbstraction.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOFileAbstraction.hpp; path = src/abstraction/MachOFileAbstraction.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F933DC37092A82480083EAC8 /* Architectures.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Architectures.hpp; path = src/ld/Architectures.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F93CB246116E69EB003233B8 /* tlvp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tlvp.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F93CB247116E69EB003233B8 /* tlvp.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = tlvp.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F971EED306D5ACF60041D381 /* ObjectDump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ObjectDump; sourceTree = BUILT_PRODUCTS_DIR; };
+ F971EED706D5AD240041D381 /* ObjectDump.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ObjectDump.cpp; path = src/other/ObjectDump.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F97F5028070D0BB200B9FCD7 /* ld.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = ld.1; path = doc/man/man1/ld.1; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9849E3410B38EF5009E9878 /* order.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = order.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9849E3510B38EF5009E9878 /* order.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = order.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F984A13B10B614CF009E9878 /* stub_arm_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_arm_classic.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F984A38010BB4B0D009E9878 /* branch_island.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = branch_island.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F984A38110BB4B0D009E9878 /* branch_island.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = branch_island.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F989D0391062E6350014B60C /* stub_x86_64.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_64.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F989D30B106826020014B60C /* OutputFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OutputFile.cpp; path = src/ld/OutputFile.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F989D30C106826020014B60C /* OutputFile.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = OutputFile.h; path = src/ld/OutputFile.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F989D3AA10684F5B0014B60C /* LinkEdit.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; name = LinkEdit.hpp; path = src/ld/LinkEdit.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F989D44B10694F2E0014B60C /* LinkEditClassic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; name = LinkEditClassic.hpp; path = src/ld/LinkEditClassic.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F989D7E91072DEC20014B60C /* HeaderAndLoadCommands.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; name = HeaderAndLoadCommands.hpp; path = src/ld/HeaderAndLoadCommands.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9A3DDCA0ED762B700C590B9 /* libprunetrie.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libprunetrie.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ F9A3DDD20ED762E400C590B9 /* PruneTrie.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PruneTrie.cpp; path = src/other/PruneTrie.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9A3DE0F0ED76D1900C590B9 /* prune_trie.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = prune_trie.h; path = src/other/prune_trie.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9A4DB8F10F816FF00BD8423 /* objc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = objc.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9A4DB9010F816FF00BD8423 /* objc.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = objc.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA44DA1294885F00CB8390 /* branch_shim.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = branch_shim.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA44DB1294885F00CB8390 /* branch_shim.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = branch_shim.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA5FCC103F5CD1003E3539 /* ld.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; name = ld.hpp; path = src/ld/ld.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA650D1051BD2B003E3539 /* make_stubs.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = make_stubs.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA650F1051BD2B003E3539 /* stub_arm.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_arm.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65101051BD2B003E3539 /* stubs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stubs.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65871051E750003E3539 /* macho_relocatable_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_relocatable_file.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65881051E750003E3539 /* macho_relocatable_file.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = macho_relocatable_file.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65D71051EC4A003E3539 /* archive_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = archive_file.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65D81051EC4A003E3539 /* archive_file.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = archive_file.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65D91051EC4A003E3539 /* lto_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lto_file.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65DA1051EC4A003E3539 /* lto_file.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = lto_file.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65DB1051EC4A003E3539 /* macho_dylib_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_dylib_file.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65DC1051EC4A003E3539 /* macho_dylib_file.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = macho_dylib_file.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA6784105700C2003E3539 /* opaque_section_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opaque_section_file.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA6785105700C2003E3539 /* opaque_section_file.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = opaque_section_file.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA67B410570C41003E3539 /* dtrace_dof.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = dtrace_dof.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA67B510570C41003E3539 /* dtrace_dof.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dtrace_dof.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA687A10572E27003E3539 /* InputFiles.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InputFiles.cpp; path = src/ld/InputFiles.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA687B10572E27003E3539 /* InputFiles.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = InputFiles.h; path = src/ld/InputFiles.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA69B410583C0C003E3539 /* SymbolTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SymbolTable.cpp; path = src/ld/SymbolTable.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA69B510583C0C003E3539 /* SymbolTable.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = SymbolTable.h; path = src/ld/SymbolTable.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA69BF10583E19003E3539 /* Resolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Resolver.cpp; path = src/ld/Resolver.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA69C010583E19003E3539 /* Resolver.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = Resolver.h; path = src/ld/Resolver.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AB1063107D380700E54C9E /* got.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = got.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AB1064107D380700E54C9E /* got.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = got.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AE20FD1107D1440007ED5D /* dylibs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dylibs.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AE20FE1107D1440007ED5D /* dylibs.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = dylibs.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9B1A2580A3A448800DA8FAB /* rebase.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = rebase.1; path = doc/man/man1/rebase.1; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9B670080DDA176100E6D0DA /* unwinddump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = unwinddump; sourceTree = BUILT_PRODUCTS_DIR; };
+ F9B670110DDA17E800E6D0DA /* UnwindDump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindDump.cpp; path = src/other/unwinddump.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9B813810EC2653000F94C13 /* unwinddump.1 */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = text.man; name = unwinddump.1; path = doc/man/man1/unwinddump.1; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9B813BF0EC27C6700F94C13 /* MachOTrie.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; name = MachOTrie.hpp; path = src/abstraction/MachOTrie.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9BA515B0ECE58AA00D1D62E /* dyldinfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dyldinfo.cpp; path = src/other/dyldinfo.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9BA51610ECE58BE00D1D62E /* dyldinfo */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dyldinfo; sourceTree = BUILT_PRODUCTS_DIR; };
+ F9BA8A7E1096150F0097A440 /* stub_x86_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_classic.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9BA8A7F1096150F0097A440 /* stub_x86.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9BA955C10A233000097A440 /* huge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = huge.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9BA955D10A233000097A440 /* huge.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = huge.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9BA963310A2545C0097A440 /* compact_unwind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compact_unwind.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9BA963410A2545C0097A440 /* compact_unwind.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = compact_unwind.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9C0D48A06DD1E1B001C7193 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Options.cpp; path = src/ld/Options.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9C0D48B06DD1E1B001C7193 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Options.h; path = src/ld/Options.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9C12E9F0ED63DB1005BC69D /* dyldinfo.1 */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = text.man; name = dyldinfo.1; path = doc/man/man1/dyldinfo.1; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9CC24141461FB4300A92174 /* blob.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blob.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9CC24151461FB4300A92174 /* blob.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = blob.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9CC24161461FB4300A92174 /* endian.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = endian.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9CC24171461FB4300A92174 /* memutils.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = memutils.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9CC24181461FB4300A92174 /* superblob.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = superblob.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9CCF761144CE1AD007CB524 /* create_configure */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = text.script.sh; name = create_configure; path = src/create_configure; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9EA72CB097454A6008B4F1D /* machocheck */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = machocheck; sourceTree = BUILT_PRODUCTS_DIR; };
+ F9EA72D4097454FF008B4F1D /* machochecker.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = machochecker.cpp; path = src/other/machochecker.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9EA7582097882F3008B4F1D /* debugline.c */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.c; name = debugline.c; path = src/ld/debugline.c; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
+ F9EA7583097882F3008B4F1D /* debugline.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = debugline.h; path = src/ld/debugline.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ 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/other/rebase.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ F9023C3706D5A23E001BBF46 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F971EED106D5ACF60041D381 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F9B670040DDA176100E6D0DA /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F9BA515F0ECE58BE00D1D62E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F9EA72C9097454A6008B4F1D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F9EC77EC0A2F85F6002A3E39 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ F9023C2C06D5A227001BBF46 = {
+ isa = PBXGroup;
+ children = (
+ F9B813A80EC27B6300F94C13 /* abstraction */,
+ F9B813AD0EC27B8500F94C13 /* ld */,
+ F9B813B00EC27B9E00F94C13 /* other */,
+ F9B8137E0EC2651200F94C13 /* doc */,
+ F9023C3A06D5A23E001BBF46 /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ F9023C3A06D5A23E001BBF46 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ F9023C3906D5A23E001BBF46 /* ld */,
+ F971EED306D5ACF60041D381 /* ObjectDump */,
+ F9EA72CB097454A6008B4F1D /* machocheck */,
+ F9EC77EE0A2F85F6002A3E39 /* rebase */,
+ F9B670080DDA176100E6D0DA /* unwinddump */,
+ F9BA51610ECE58BE00D1D62E /* dyldinfo */,
+ F9A3DDCA0ED762B700C590B9 /* libprunetrie.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ F9AA650B1051BD2B003E3539 /* passes */ = {
+ isa = PBXGroup;
+ children = (
+ F984A38010BB4B0D009E9878 /* branch_island.cpp */,
+ F984A38110BB4B0D009E9878 /* branch_island.h */,
+ F9AA44DA1294885F00CB8390 /* branch_shim.cpp */,
+ F9AA44DB1294885F00CB8390 /* branch_shim.h */,
+ F9849E3410B38EF5009E9878 /* order.cpp */,
+ F9849E3510B38EF5009E9878 /* order.h */,
+ F9BA963310A2545C0097A440 /* compact_unwind.cpp */,
+ F9BA963410A2545C0097A440 /* compact_unwind.h */,
+ F9AA67B410570C41003E3539 /* dtrace_dof.h */,
+ F9AA67B510570C41003E3539 /* dtrace_dof.cpp */,
+ F9BA955C10A233000097A440 /* huge.cpp */,
+ F9BA955D10A233000097A440 /* huge.h */,
+ F9AB1063107D380700E54C9E /* got.cpp */,
+ F9AB1064107D380700E54C9E /* got.h */,
+ F93CB246116E69EB003233B8 /* tlvp.cpp */,
+ F93CB247116E69EB003233B8 /* tlvp.h */,
+ F9AE20FD1107D1440007ED5D /* dylibs.cpp */,
+ F9AE20FE1107D1440007ED5D /* dylibs.h */,
+ F9A4DB8F10F816FF00BD8423 /* objc.cpp */,
+ F9A4DB9010F816FF00BD8423 /* objc.h */,
+ F9AA650C1051BD2B003E3539 /* stubs */,
+ );
+ name = passes;
+ path = src/ld/passes;
+ sourceTree = "<group>";
+ };
+ F9AA650C1051BD2B003E3539 /* stubs */ = {
+ isa = PBXGroup;
+ children = (
+ F9AA650D1051BD2B003E3539 /* make_stubs.h */,
+ F9AA65101051BD2B003E3539 /* stubs.cpp */,
+ F9AA650F1051BD2B003E3539 /* stub_arm.hpp */,
+ F984A13B10B614CF009E9878 /* stub_arm_classic.hpp */,
+ F9BA8A7F1096150F0097A440 /* stub_x86.hpp */,
+ F9BA8A7E1096150F0097A440 /* stub_x86_classic.hpp */,
+ F989D0391062E6350014B60C /* stub_x86_64.hpp */,
+ F92D9C2710657AAB00FF369B /* stub_x86_64_classic.hpp */,
+ );
+ path = stubs;
+ sourceTree = "<group>";
+ };
+ F9AA65861051E750003E3539 /* parsers */ = {
+ isa = PBXGroup;
+ children = (
+ F9AA6784105700C2003E3539 /* opaque_section_file.cpp */,
+ F9AA6785105700C2003E3539 /* opaque_section_file.h */,
+ F9AA65D71051EC4A003E3539 /* archive_file.cpp */,
+ F9AA65D81051EC4A003E3539 /* archive_file.h */,
+ F9AA65D91051EC4A003E3539 /* lto_file.cpp */,
+ F9AA65DA1051EC4A003E3539 /* lto_file.h */,
+ F9AA65DB1051EC4A003E3539 /* macho_dylib_file.cpp */,
+ F9AA65DC1051EC4A003E3539 /* macho_dylib_file.h */,
+ F9AA65871051E750003E3539 /* macho_relocatable_file.cpp */,
+ F9AA65881051E750003E3539 /* macho_relocatable_file.h */,
+ );
+ name = parsers;
+ path = src/ld/parsers;
+ sourceTree = "<group>";
+ };
+ F9B8137E0EC2651200F94C13 /* doc */ = {
+ isa = PBXGroup;
+ children = (
+ F97F5028070D0BB200B9FCD7 /* ld.1 */,
+ F9B1A2580A3A448800DA8FAB /* rebase.1 */,
+ F9C12E9F0ED63DB1005BC69D /* dyldinfo.1 */,
+ F9B813810EC2653000F94C13 /* unwinddump.1 */,
+ );
+ name = doc;
+ sourceTree = "<group>";
+ };
+ F9B813A80EC27B6300F94C13 /* abstraction */ = {
+ isa = PBXGroup;
+ children = (
+ F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */,
+ F933D9460929277C0083EAC8 /* FileAbstraction.hpp */,
+ F9B813BF0EC27C6700F94C13 /* MachOTrie.hpp */,
+ );
+ name = abstraction;
+ sourceTree = "<group>";
+ };
+ F9B813AD0EC27B8500F94C13 /* ld */ = {
+ isa = PBXGroup;
+ children = (
+ F9AA69BF10583E19003E3539 /* Resolver.cpp */,
+ F9AA69C010583E19003E3539 /* Resolver.h */,
+ F9AA69B410583C0C003E3539 /* SymbolTable.cpp */,
+ F9AA69B510583C0C003E3539 /* SymbolTable.h */,
+ F9AA687A10572E27003E3539 /* InputFiles.cpp */,
+ F9AA687B10572E27003E3539 /* InputFiles.h */,
+ F9AA5FCC103F5CD1003E3539 /* ld.hpp */,
+ F9023C3F06D5A254001BBF46 /* ld.cpp */,
+ F9C0D48A06DD1E1B001C7193 /* Options.cpp */,
+ F9C0D48B06DD1E1B001C7193 /* Options.h */,
+ F989D30B106826020014B60C /* OutputFile.cpp */,
+ F989D30C106826020014B60C /* OutputFile.h */,
+ F989D7E91072DEC20014B60C /* HeaderAndLoadCommands.hpp */,
+ F989D3AA10684F5B0014B60C /* LinkEdit.hpp */,
+ F989D44B10694F2E0014B60C /* LinkEditClassic.hpp */,
+ F9CC24131461FB4300A92174 /* code-sign-blobs */,
+ F9AA650B1051BD2B003E3539 /* passes */,
+ F9AA65861051E750003E3539 /* parsers */,
+ F933DC37092A82480083EAC8 /* Architectures.hpp */,
+ F9EA7582097882F3008B4F1D /* debugline.c */,
+ F9EA7583097882F3008B4F1D /* debugline.h */,
+ B3B672411406D42800A376BB /* Snapshot.cpp */,
+ B3B672441406D44300A376BB /* Snapshot.h */,
+ );
+ name = ld;
+ sourceTree = "<group>";
+ };
+ F9B813B00EC27B9E00F94C13 /* other */ = {
+ isa = PBXGroup;
+ children = (
+ B3C7A09914295B9C005FC714 /* compile_stubs */,
+ F9CCF761144CE1AD007CB524 /* create_configure */,
+ F9EA72D4097454FF008B4F1D /* machochecker.cpp */,
+ F971EED706D5AD240041D381 /* ObjectDump.cpp */,
+ F9BA515B0ECE58AA00D1D62E /* dyldinfo.cpp */,
+ F9B670110DDA17E800E6D0DA /* UnwindDump.cpp */,
+ F9EC78050A2F8674002A3E39 /* rebase.cpp */,
+ F9A3DE0F0ED76D1900C590B9 /* prune_trie.h */,
+ F9A3DDD20ED762E400C590B9 /* PruneTrie.cpp */,
+ );
+ name = other;
+ sourceTree = "<group>";
+ };
+ F9CC24131461FB4300A92174 /* code-sign-blobs */ = {
+ isa = PBXGroup;
+ children = (
+ F9CC24141461FB4300A92174 /* blob.cpp */,
+ F9CC24151461FB4300A92174 /* blob.h */,
+ F9CC24161461FB4300A92174 /* endian.h */,
+ F9CC24171461FB4300A92174 /* memutils.h */,
+ F9CC24181461FB4300A92174 /* superblob.h */,
+ );
+ name = "code-sign-blobs";
+ path = "src/ld/code-sign-blobs";
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ F9023C3806D5A23E001BBF46 /* ld */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F933D91B09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ld" */;
+ buildPhases = (
+ F9E8DB4D11921594007B4D6A /* make configure.h */,
+ B3C7A09714295B60005FC714 /* make compile_stub string */,
+ F9023C3606D5A23E001BBF46 /* Sources */,
+ F9023C3706D5A23E001BBF46 /* Frameworks */,
+ F97F5025070D0B6300B9FCD7 /* copy man page */,
+ );
+ buildRules = (
+ F9E8D4BE07FCAF2A00FD5801 /* PBXBuildRule */,
+ F9E8D4BD07FCAF2000FD5801 /* PBXBuildRule */,
+ );
+ dependencies = (
+ );
+ name = ld;
+ productName = ld64;
+ productReference = F9023C3906D5A23E001BBF46 /* ld */;
+ productType = "com.apple.product-type.tool";
+ };
+ F971EED206D5ACF60041D381 /* ObjectDump */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F933D91F09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ObjectDump" */;
+ buildPhases = (
+ F9CCF773144CE304007CB524 /* make configure.h */,
+ F971EED006D5ACF60041D381 /* Sources */,
+ F971EED106D5ACF60041D381 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ObjectDump;
+ productName = ObjectDump;
+ productReference = F971EED306D5ACF60041D381 /* ObjectDump */;
+ productType = "com.apple.product-type.tool";
+ };
+ F9A3DDC90ED762B700C590B9 /* libprunetrie */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F9A3DDCF0ED762C100C590B9 /* Build configuration list for PBXNativeTarget "libprunetrie" */;
+ buildPhases = (
+ F9CCF781144CE3DF007CB524 /* make configure.h */,
+ F9A3DDC70ED762B700C590B9 /* Sources */,
+ F9A3DE140ED76D7700C590B9 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = libprunetrie;
+ productName = libmachotrie;
+ productReference = F9A3DDCA0ED762B700C590B9 /* libprunetrie.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ F9B670010DDA176100E6D0DA /* unwinddump */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F9B670050DDA176100E6D0DA /* Build configuration list for PBXNativeTarget "unwinddump" */;
+ buildPhases = (
+ F9CCF77C144CE36B007CB524 /* make configure.h */,
+ F9B670020DDA176100E6D0DA /* Sources */,
+ F9B670040DDA176100E6D0DA /* Frameworks */,
+ F9B813870EC2659600F94C13 /* install man page */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = unwinddump;
+ productName = machocheck;
+ productReference = F9B670080DDA176100E6D0DA /* unwinddump */;
+ productType = "com.apple.product-type.tool";
+ };
+ F9BA51600ECE58BE00D1D62E /* dyldinfo */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F9BA516D0ECE58DA00D1D62E /* Build configuration list for PBXNativeTarget "dyldinfo" */;
+ buildPhases = (
+ F9CCF76B144CE2AD007CB524 /* make configure.h */,
+ F9BA515E0ECE58BE00D1D62E /* Sources */,
+ F9BA515F0ECE58BE00D1D62E /* Frameworks */,
+ F9C12EA50ED63E05005BC69D /* install man page */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dyldinfo;
+ productName = dyldinfo;
+ productReference = F9BA51610ECE58BE00D1D62E /* dyldinfo */;
+ productType = "com.apple.product-type.tool";
+ };
+ F9EA72CA097454A6008B4F1D /* machocheck */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F9EA72CF097454D5008B4F1D /* Build configuration list for PBXNativeTarget "machocheck" */;
+ buildPhases = (
+ F9CCF76F144CE2D6007CB524 /* make configure.h */,
+ F9EA72C8097454A6008B4F1D /* Sources */,
+ F9EA72C9097454A6008B4F1D /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = machocheck;
+ productName = machocheck;
+ productReference = F9EA72CB097454A6008B4F1D /* machocheck */;
+ productType = "com.apple.product-type.tool";
+ };
+ F9EC77ED0A2F85F6002A3E39 /* rebase */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F9EC77F00A2F8616002A3E39 /* Build configuration list for PBXNativeTarget "rebase" */;
+ buildPhases = (
+ F9CCF765144CE244007CB524 /* make configure.h */,
+ F9EC77EB0A2F85F6002A3E39 /* Sources */,
+ F9EC77EC0A2F85F6002A3E39 /* Frameworks */,
+ F9B1A25E0A3A44CB00DA8FAB /* install man page */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = rebase;
+ productName = rebase;
+ productReference = F9EC77EE0A2F85F6002A3E39 /* rebase */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ F9023C3006D5A227001BBF46 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ ORGANIZATIONNAME = "Apple Inc.";
+ };
+ buildConfigurationList = F933D92309291AC90083EAC8 /* Build configuration list for PBXProject "ld64" */;
+ compatibilityVersion = "Xcode 2.4";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = F9023C2C06D5A227001BBF46;
+ productRefGroup = F9023C3A06D5A23E001BBF46 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ F9B1A2670A3A567B00DA8FAB /* all */,
+ F9023C3806D5A23E001BBF46 /* ld */,
+ F9EC77ED0A2F85F6002A3E39 /* rebase */,
+ F9B670010DDA176100E6D0DA /* unwinddump */,
+ F971EED206D5ACF60041D381 /* ObjectDump */,
+ F9EA72CA097454A6008B4F1D /* machocheck */,
+ F9BA51600ECE58BE00D1D62E /* dyldinfo */,
+ F9A3DDC90ED762B700C590B9 /* libprunetrie */,
+ F96D5368094A2754008E9EE8 /* unit-tests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ B3C7A09714295B60005FC714 /* make compile_stub string */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/compile_stubs",
+ );
+ name = "make compile_stub string";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/compile_stubs.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/csh;
+ shellScript = "echo \"static const char *compile_stubs = \" > $DERIVED_FILE_DIR/compile_stubs.h\ncat compile_stubs | sed s/\\\"/\\\\\\\\\\\"/g | sed s/^/\\\"/ | sed s/\\$/\\\\\\\\n\\\"/ >> $DERIVED_FILE_DIR/compile_stubs.h\necho \";\" >> $DERIVED_FILE_DIR/compile_stubs.h";
+ showEnvVarsInLog = 0;
+ };
+ F96D5367094A2754008E9EE8 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/csh;
+ shellScript = "# Let tests set MACOSX_DEPLOYMENT_TARGET as they need\nunsetenv MACOSX_DEPLOYMENT_TARGET\n\n# make linker relative libLTO.dylib\nmkdir -p ${BUILD_DIR}/lib\nln -sf /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib ${BUILD_DIR}/lib/libLTO.dylib\n\n# always use new linker\nsetenv LD_NO_CLASSIC_LINKER\nsetenv LD_NO_CLASSIC_LINKER_STATIC\n\n# run full test suite\n\"$SRCROOT\"/unit-tests/run-all-unit-tests\n\nexit 0";
+ showEnvVarsInLog = 0;
+ };
+ F9871A3413340B4600DB3F24 /* Platform install */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Platform install";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "\nif [ -n \"${DT_TOOLCHAIN_DIR}\" ]\nthen\n\tmkdir -p \"${DSTROOT}/${DT_TOOLCHAIN_DIR}\"\n\tmv ${DSTROOT}/usr \"${DSTROOT}/${DT_TOOLCHAIN_DIR}\"\nelse\n\tif [ -n \"${RC_PURPLE}\" ]\n\tthen\n\t\tmkdir -p ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer/\n\t\tmv ${DSTROOT}/usr ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer\n\telse\n\t\tmkdir -p ${DSTROOT}/Developer/usr/bin\n\t\tcp ${DSTROOT}/usr/bin/ld ${DSTROOT}/Developer/usr/bin\n\tfi\nfi\n\n";
+ showEnvVarsInLog = 0;
+ };
+ F9CCF765144CE244007CB524 /* make configure.h */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "make configure.h";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/configure.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "${SRCROOT}/src/create_configure\n";
+ showEnvVarsInLog = 0;
+ };
+ F9CCF76B144CE2AD007CB524 /* make configure.h */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "make configure.h";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/configure.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "${SRCROOT}/src/create_configure\n";
+ showEnvVarsInLog = 0;
+ };
+ F9CCF76F144CE2D6007CB524 /* make configure.h */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "make configure.h";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/configure.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "${SRCROOT}/src/create_configure\n";
+ showEnvVarsInLog = 0;
+ };
+ F9CCF773144CE304007CB524 /* make configure.h */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "make configure.h";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/configure.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "${SRCROOT}/src/create_configure\n";
+ showEnvVarsInLog = 0;
+ };
+ F9CCF77C144CE36B007CB524 /* make configure.h */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "make configure.h";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/configure.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "${SRCROOT}/src/create_configure\n";
+ showEnvVarsInLog = 0;
+ };
+ F9CCF781144CE3DF007CB524 /* make configure.h */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "make configure.h";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/configure.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "${SRCROOT}/src/create_configure\n";
+ showEnvVarsInLog = 0;
+ };
+ F9E8DB4D11921594007B4D6A /* make configure.h */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "make configure.h";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/configure.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/bash;
+ shellScript = "${SRCROOT}/src/create_configure\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ F9023C3606D5A23E001BBF46 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F9C0D4BD06DD28D2001C7193 /* Options.cpp in Sources */,
+ F9023C4E06D5A272001BBF46 /* ld.cpp in Sources */,
+ F9AA65891051E750003E3539 /* macho_relocatable_file.cpp in Sources */,
+ F9AA65DD1051EC4A003E3539 /* archive_file.cpp in Sources */,
+ F9AA65DE1051EC4A003E3539 /* lto_file.cpp in Sources */,
+ F9AA65DF1051EC4A003E3539 /* macho_dylib_file.cpp in Sources */,
+ F9EA7584097882F3008B4F1D /* debugline.c in Sources */,
+ F9AA687C10572E27003E3539 /* InputFiles.cpp in Sources */,
+ F9AA69B610583C0C003E3539 /* SymbolTable.cpp in Sources */,
+ F9AA69C110583E19003E3539 /* Resolver.cpp in Sources */,
+ F989D30D106826020014B60C /* OutputFile.cpp in Sources */,
+ F9AA65111051BD2B003E3539 /* stubs.cpp in Sources */,
+ F9AA6786105700C2003E3539 /* opaque_section_file.cpp in Sources */,
+ F9AA67B610570C41003E3539 /* dtrace_dof.cpp in Sources */,
+ F98498A310AE2159009E9878 /* compact_unwind.cpp in Sources */,
+ F98498A410AE2159009E9878 /* got.cpp in Sources */,
+ F9BA955E10A233000097A440 /* huge.cpp in Sources */,
+ F9849E3610B38EF5009E9878 /* order.cpp in Sources */,
+ F984A38210BB4B0D009E9878 /* branch_island.cpp in Sources */,
+ F9A4DB9110F816FF00BD8423 /* objc.cpp in Sources */,
+ F9AE20FF1107D1440007ED5D /* dylibs.cpp in Sources */,
+ F93CB248116E69EB003233B8 /* tlvp.cpp in Sources */,
+ F9AA44DC1294885F00CB8390 /* branch_shim.cpp in Sources */,
+ B3B672421406D42800A376BB /* Snapshot.cpp in Sources */,
+ F9CC24191461FB4300A92174 /* blob.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F971EED006D5ACF60041D381 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F9AA6FF910618CD2003E3539 /* macho_relocatable_file.cpp in Sources */,
+ F9AE23291109015E0007ED5D /* lto_file.cpp in Sources */,
+ F933E3D9092E855B0083EAC8 /* ObjectDump.cpp in Sources */,
+ F9EA75BC09788857008B4F1D /* debugline.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F9A3DDC70ED762B700C590B9 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F9A3DDD30ED762E400C590B9 /* PruneTrie.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F9B670020DDA176100E6D0DA /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F9B670120DDA17E800E6D0DA /* UnwindDump.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F9BA515E0ECE58BE00D1D62E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F9BA51650ECE58C800D1D62E /* dyldinfo.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F9EA72C8097454A6008B4F1D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F9EA72D5097454FF008B4F1D /* machochecker.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F9EC77EB0A2F85F6002A3E39 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F9EC78060A2F8674002A3E39 /* rebase.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ F96904890A4333AC00B77D2A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F9EC77ED0A2F85F6002A3E39 /* rebase */;
+ targetProxy = F96904880A4333AC00B77D2A /* PBXContainerItemProxy */;
+ };
+ F96D536A094A275D008E9EE8 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F9023C3806D5A23E001BBF46 /* ld */;
+ targetProxy = F96D5369094A275D008E9EE8 /* PBXContainerItemProxy */;
+ };
+ F96D536C094A275F008E9EE8 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F971EED206D5ACF60041D381 /* ObjectDump */;
+ targetProxy = F96D536B094A275F008E9EE8 /* PBXContainerItemProxy */;
+ };
+ F9A3DE160ED76D9A00C590B9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F9A3DDC90ED762B700C590B9 /* libprunetrie */;
+ targetProxy = F9A3DE150ED76D9A00C590B9 /* PBXContainerItemProxy */;
+ };
+ F9B1A2690A3A568200DA8FAB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F9023C3806D5A23E001BBF46 /* ld */;
+ targetProxy = F9B1A2680A3A568200DA8FAB /* PBXContainerItemProxy */;
+ };
+ F9B1A26B0A3A568400DA8FAB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F9EC77ED0A2F85F6002A3E39 /* rebase */;
+ targetProxy = F9B1A26A0A3A568400DA8FAB /* PBXContainerItemProxy */;
+ };
+ F9B693890EC4D28C00076912 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F9B670010DDA176100E6D0DA /* unwinddump */;
+ targetProxy = F9B693880EC4D28C00076912 /* PBXContainerItemProxy */;
+ };
+ F9B8135D0EC2620E00F94C13 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F9B670010DDA176100E6D0DA /* unwinddump */;
+ targetProxy = F9B8135C0EC2620E00F94C13 /* PBXContainerItemProxy */;
+ };
+ F9C12EEA0ED65765005BC69D /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F9BA51600ECE58BE00D1D62E /* dyldinfo */;
+ targetProxy = F9C12EE90ED65765005BC69D /* PBXContainerItemProxy */;
+ };
+ F9EA73970974999B008B4F1D /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F9EA72CA097454A6008B4F1D /* machocheck */;
+ targetProxy = F9EA73960974999B008B4F1D /* PBXContainerItemProxy */;
+ };
+ F9F9AD68116D58AF0028EFAB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F9BA51600ECE58BE00D1D62E /* dyldinfo */;
+ targetProxy = F9F9AD67116D58AF0028EFAB /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ F933D91C09291AC90083EAC8 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ GCC_DYNAMIC_NO_PIC = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
+ GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS = NO;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
+ GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+ GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+ GCC_WARN_MISSING_PARENTHESES = YES;
+ GCC_WARN_NON_VIRTUAL_DESTRUCTOR = NO;
+ GCC_WARN_PEDANTIC = NO;
+ GCC_WARN_SHADOW = NO;
+ GCC_WARN_SIGN_COMPARE = YES;
+ GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_LABEL = YES;
+ GCC_WARN_UNUSED_PARAMETER = NO;
+ GCC_WARN_UNUSED_VALUE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(DT_TOOLCHAIN_DIR)/usr/local/include",
+ "$(DEVELOPER_DIR)/usr/local/include",
+ "$(DEVELOPER_DIR)/usr/include",
+ );
+ INSTALL_PATH = /usr/bin;
+ LINKER_DISPLAYS_MANGLED_NAMES = NO;
+ MACOSX_DEPLOYMENT_TARGET = "";
+ OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
+ OTHER_LDFLAGS = (
+ "@$(DERIVED_SOURCES_DIR)/LTO_option.txt",
+ "-Wl,-exported_symbol,__mh_execute_header",
+ );
+ PREBINDING = NO;
+ PRODUCT_NAME = ld;
+ SECTORDER_FLAGS = "";
+ VERSIONING_SYSTEM = "apple-generic";
+ WARNING_CFLAGS = "-Wall";
+ };
+ name = Debug;
+ };
+ F933D91D09291AC90083EAC8 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_DYNAMIC_NO_PIC = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 3;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_TARGET_1)",
+ NDEBUG,
+ "$(GCC_PREPROCESSOR_DEFINITIONS_$(RC_RELEASE))",
+ );
+ GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_TARGET_1 = "LD_VERS='\"ld64-$(RC_ProjectSourceVersion)\"'";
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
+ GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS = NO;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
+ GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+ GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+ GCC_WARN_MISSING_PARENTHESES = YES;
+ GCC_WARN_NON_VIRTUAL_DESTRUCTOR = NO;
+ GCC_WARN_PEDANTIC = NO;
+ GCC_WARN_SHADOW = NO;
+ GCC_WARN_SIGN_COMPARE = YES;
+ GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_LABEL = YES;
+ GCC_WARN_UNUSED_PARAMETER = NO;
+ GCC_WARN_UNUSED_VALUE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(DT_TOOLCHAIN_DIR)/usr/local/include",
+ "$(DEVELOPER_DIR)/usr/local/include",
+ "$(DEVELOPER_DIR)/usr/include",
+ );
+ INSTALL_PATH = /usr/bin;
+ OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
+ OTHER_LDFLAGS = (
+ "@$(DERIVED_SOURCES_DIR)/LTO_option.txt",
+ "-Wl,-exported_symbol,__mh_execute_header",
+ );
+ PREBINDING = NO;
+ PRODUCT_NAME = ld;
+ SECTORDER_FLAGS = "";
+ STRIP_INSTALLED_PRODUCT = YES;
+ STRIP_STYLE = debugging;
+ VALID_ARCHS = "x86_64 i386 ppc";
+ VERSIONING_SYSTEM = "apple-generic";
+ WARNING_CFLAGS = "-Wall";
+ };
+ name = Release;
+ };
+ F933D92009291AC90083EAC8 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
+ GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+ GCC_WARN_SHADOW = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VALUE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/src/ld",
+ "$(DEVELOPER_DIR)/usr/local/include",
+ );
+ INSTALL_PATH = "$(HOME)/bin";
+ OTHER_LDFLAGS = "@$(DERIVED_SOURCES_DIR)/LTO_option.txt";
+ OTHER_REZFLAGS = "";
+ PREBINDING = NO;
+ PRODUCT_NAME = ObjectDump;
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = (
+ "-Wmost",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ );
+ };
+ name = Debug;
+ };
+ F933D92109291AC90083EAC8 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = s;
+ GCC_PREPROCESSOR_DEFINITIONS = NDEBUG;
+ HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/src/ld",
+ "$(DEVELOPER_DIR)/usr/local/include",
+ );
+ INSTALL_PATH = "$(HOME)/bin";
+ OTHER_LDFLAGS = "@$(DERIVED_SOURCES_DIR)/LTO_option.txt";
+ OTHER_REZFLAGS = "";
+ PREBINDING = NO;
+ PRODUCT_NAME = ObjectDump;
+ WARNING_CFLAGS = (
+ "-Wmost",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ );
+ };
+ name = Release;
+ };
+ F933D92409291AC90083EAC8 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1)";
+ ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ };
+ name = Debug;
+ };
+ F933D92509291AC90083EAC8 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1)";
+ ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ };
+ name = Release;
+ };
+ F96D536E094A2773008E9EE8 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ PRODUCT_NAME = "unit-tests";
+ };
+ name = Debug;
+ };
+ F96D536F094A2773008E9EE8 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ PRODUCT_NAME = "unit-tests";
+ };
+ name = Release;
+ };
+ F9849FF810B5DE8E009E9878 /* Release-assert */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1)";
+ ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ };
+ name = "Release-assert";
+ };
+ F9849FF910B5DE8E009E9878 /* Release-assert */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ PRODUCT_NAME = all;
+ ZERO_LINK = NO;
+ };
+ name = "Release-assert";
+ };
+ F9849FFA10B5DE8E009E9878 /* Release-assert */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_DYNAMIC_NO_PIC = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 3;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_TARGET_1)",
+ "$(GCC_PREPROCESSOR_DEFINITIONS_$(RC_RELEASE))",
+ );
+ GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_TARGET_1 = "LD_VERS='\"ld64-$(RC_ProjectSourceVersion)\"'";
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
+ GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS = NO;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
+ GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+ GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+ GCC_WARN_MISSING_PARENTHESES = YES;
+ GCC_WARN_NON_VIRTUAL_DESTRUCTOR = NO;
+ GCC_WARN_PEDANTIC = NO;
+ GCC_WARN_SHADOW = NO;
+ GCC_WARN_SIGN_COMPARE = YES;
+ GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_LABEL = YES;
+ GCC_WARN_UNUSED_PARAMETER = NO;
+ GCC_WARN_UNUSED_VALUE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(DT_TOOLCHAIN_DIR)/usr/local/include",
+ "$(DEVELOPER_DIR)/usr/local/include",
+ "$(DEVELOPER_DIR)/usr/include",
+ );
+ INSTALL_PATH = /usr/bin;
+ OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
+ OTHER_LDFLAGS = (
+ "@$(DERIVED_SOURCES_DIR)/LTO_option.txt",
+ "-Wl,-exported_symbol,__mh_execute_header",
+ );
+ PREBINDING = NO;
+ PRODUCT_NAME = ld;
+ SECTORDER_FLAGS = "";
+ STRIP_INSTALLED_PRODUCT = YES;
+ STRIP_STYLE = debugging;
+ VALID_ARCHS = "x86_64 i386 ppc";
+ VERSIONING_SYSTEM = "apple-generic";
+ WARNING_CFLAGS = "-Wall";
+ };
+ name = "Release-assert";
+ };
+ F9849FFB10B5DE8E009E9878 /* Release-assert */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_PREPROCESSOR_DEFINITIONS = "$(GCC_PREPROCESSOR_DEFINITIONS_$(RC_RELEASE))";
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = /usr/bin;
+ OTHER_LDFLAGS = "-Wl,-exported_symbol,__mh_execute_header";
+ PREBINDING = NO;
+ PRODUCT_NAME = rebase;
+ STRIP_INSTALLED_PRODUCT = YES;
+ STRIP_STYLE = debugging;
+ VALID_ARCHS = "i386 ppc x86_64";
+ };
+ name = "Release-assert";
+ };
+ F9849FFC10B5DE8E009E9878 /* Release-assert */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
+ GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = /usr/bin;
+ OTHER_LDFLAGS = "-Wl,-exported_symbol,__mh_execute_header";
+ PREBINDING = NO;
+ PRODUCT_NAME = unwinddump;
+ STRIP_INSTALLED_PRODUCT = YES;
+ STRIP_STYLE = debugging;
+ };
+ name = "Release-assert";
+ };
+ F9849FFD10B5DE8E009E9878 /* Release-assert */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = s;
+ GCC_PREPROCESSOR_DEFINITIONS = NDEBUG;
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
+ HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/src/ld",
+ "$(DEVELOPER_DIR)/usr/local/include",
+ );
+ INSTALL_PATH = "$(HOME)/bin";
+ OTHER_LDFLAGS = "@$(DERIVED_SOURCES_DIR)/LTO_option.txt";
+ OTHER_REZFLAGS = "";
+ PREBINDING = NO;
+ PRODUCT_NAME = ObjectDump;
+ WARNING_CFLAGS = (
+ "-Wmost",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ );
+ };
+ name = "Release-assert";
+ };
+ F9849FFE10B5DE8E009E9878 /* Release-assert */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = G5;
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = "$(HOME)/bin";
+ PREBINDING = NO;
+ PRODUCT_NAME = machocheck;
+ };
+ name = "Release-assert";
+ };
+ F9849FFF10B5DE8E009E9878 /* Release-assert */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/bin;
+ OTHER_LDFLAGS = "-Wl,-exported_symbol,__mh_execute_header";
+ PREBINDING = NO;
+ PRODUCT_NAME = dyldinfo;
+ STRIP_INSTALLED_PRODUCT = YES;
+ STRIP_STYLE = debugging;
+ ZERO_LINK = NO;
+ };
+ name = "Release-assert";
+ };
+ F984A00010B5DE8E009E9878 /* Release-assert */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ INSTALL_PATH = /usr/local/lib;
+ PREBINDING = NO;
+ PRODUCT_NAME = prunetrie;
+ };
+ name = "Release-assert";
+ };
+ F984A00110B5DE8E009E9878 /* Release-assert */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ PRODUCT_NAME = "unit-tests";
+ };
+ name = "Release-assert";
+ };
+ F9A3DDCB0ED762B800C590B9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ INSTALL_PATH = /usr/local/lib;
+ PREBINDING = NO;
+ PRODUCT_NAME = prunetrie;
+ };
+ name = Debug;
+ };
+ F9A3DDCC0ED762B800C590B9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ INSTALL_PATH = /usr/local/lib;
+ PREBINDING = NO;
+ PRODUCT_NAME = prunetrie;
+ };
+ name = Release;
+ };
+ F9B1A26D0A3A568700DA8FAB /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ PRODUCT_NAME = all;
+ };
+ name = Debug;
+ };
+ F9B1A26E0A3A568700DA8FAB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ PRODUCT_NAME = all;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ F9B670060DDA176100E6D0DA /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
+ GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+ INSTALL_PATH = "$(HOME)/bin";
+ PREBINDING = NO;
+ PRODUCT_NAME = unwinddump;
+ };
+ name = Debug;
+ };
+ F9B670070DDA176100E6D0DA /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
+ GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = /usr/bin;
+ OTHER_LDFLAGS = "-Wl,-exported_symbol,__mh_execute_header";
+ PREBINDING = NO;
+ PRODUCT_NAME = unwinddump;
+ STRIP_INSTALLED_PRODUCT = YES;
+ STRIP_STYLE = debugging;
+ };
+ name = Release;
+ };
+ F9BA51630ECE58BF00D1D62E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
+ GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+ GCC_WARN_MISSING_PARENTHESES = YES;
+ GCC_WARN_SHADOW = YES;
+ GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+ GCC_WARN_UNUSED_LABEL = NO;
+ GCC_WARN_UNUSED_VALUE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = dyldinfo;
+ WARNING_CFLAGS = "-Wall";
+ };
+ name = Debug;
+ };
+ F9BA51640ECE58BF00D1D62E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/bin;
+ OTHER_LDFLAGS = "-Wl,-exported_symbol,__mh_execute_header";
+ PREBINDING = NO;
+ PRODUCT_NAME = dyldinfo;
+ STRIP_INSTALLED_PRODUCT = YES;
+ STRIP_STYLE = debugging;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ F9EA72D0097454D5008B4F1D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ INSTALL_PATH = "$(HOME)/bin";
+ PREBINDING = NO;
+ PRODUCT_NAME = machocheck;
+ };
+ name = Debug;
+ };
+ F9EA72D1097454D5008B4F1D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = G5;
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = "$(HOME)/bin";
+ PREBINDING = NO;
+ PRODUCT_NAME = machocheck;
+ };
+ name = Release;
+ };
+ F9EC77F10A2F8616002A3E39 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ INSTALL_PATH = "$(HOME)/bin";
+ PREBINDING = NO;
+ PRODUCT_NAME = rebase;
+ };
+ name = Debug;
+ };
+ F9EC77F20A2F8616002A3E39 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_PREPROCESSOR_DEFINITIONS = "$(GCC_PREPROCESSOR_DEFINITIONS_$(RC_RELEASE))";
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = /usr/bin;
+ OTHER_LDFLAGS = "-Wl,-exported_symbol,__mh_execute_header";
+ PREBINDING = NO;
+ PRODUCT_NAME = rebase;
+ STRIP_INSTALLED_PRODUCT = YES;
+ STRIP_STYLE = debugging;
+ VALID_ARCHS = "i386 ppc x86_64";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ F933D91B09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ld" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F933D91C09291AC90083EAC8 /* Debug */,
+ F933D91D09291AC90083EAC8 /* Release */,
+ F9849FFA10B5DE8E009E9878 /* Release-assert */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Release-assert";
+ };
+ F933D91F09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ObjectDump" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F933D92009291AC90083EAC8 /* Debug */,
+ F933D92109291AC90083EAC8 /* Release */,
+ F9849FFD10B5DE8E009E9878 /* Release-assert */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Release-assert";
+ };
+ F933D92309291AC90083EAC8 /* Build configuration list for PBXProject "ld64" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F933D92409291AC90083EAC8 /* Debug */,
+ F933D92509291AC90083EAC8 /* Release */,
+ F9849FF810B5DE8E009E9878 /* Release-assert */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Release-assert";
+ };
+ F96D536D094A2773008E9EE8 /* Build configuration list for PBXAggregateTarget "unit-tests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F96D536E094A2773008E9EE8 /* Debug */,
+ F96D536F094A2773008E9EE8 /* Release */,
+ F984A00110B5DE8E009E9878 /* Release-assert */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Release-assert";
+ };
+ F9A3DDCF0ED762C100C590B9 /* Build configuration list for PBXNativeTarget "libprunetrie" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F9A3DDCB0ED762B800C590B9 /* Debug */,
+ F9A3DDCC0ED762B800C590B9 /* Release */,
+ F984A00010B5DE8E009E9878 /* Release-assert */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Release-assert";
+ };
+ F9B1A26C0A3A568700DA8FAB /* Build configuration list for PBXAggregateTarget "all" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F9B1A26D0A3A568700DA8FAB /* Debug */,
+ F9B1A26E0A3A568700DA8FAB /* Release */,
+ F9849FF910B5DE8E009E9878 /* Release-assert */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Release-assert";
+ };
+ F9B670050DDA176100E6D0DA /* Build configuration list for PBXNativeTarget "unwinddump" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F9B670060DDA176100E6D0DA /* Debug */,
+ F9B670070DDA176100E6D0DA /* Release */,
+ F9849FFC10B5DE8E009E9878 /* Release-assert */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Release-assert";
+ };
+ F9BA516D0ECE58DA00D1D62E /* Build configuration list for PBXNativeTarget "dyldinfo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F9BA51630ECE58BF00D1D62E /* Debug */,
+ F9BA51640ECE58BF00D1D62E /* Release */,
+ F9849FFF10B5DE8E009E9878 /* Release-assert */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Release-assert";
+ };
+ F9EA72CF097454D5008B4F1D /* Build configuration list for PBXNativeTarget "machocheck" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F9EA72D0097454D5008B4F1D /* Debug */,
+ F9EA72D1097454D5008B4F1D /* Release */,
+ F9849FFE10B5DE8E009E9878 /* Release-assert */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Release-assert";
+ };
+ F9EC77F00A2F8616002A3E39 /* Build configuration list for PBXNativeTarget "rebase" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F9EC77F10A2F8616002A3E39 /* Debug */,
+ F9EC77F20A2F8616002A3E39 /* Release */,
+ F9849FFB10B5DE8E009E9878 /* Release-assert */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Release-assert";
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = F9023C3006D5A227001BBF46 /* Project object */;
+}
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#ifndef __FILE_ABSTRACTION__
+#define __FILE_ABSTRACTION__
+
+
+#include <stdint.h>
+#include <string.h>
+#include <libkern/OSByteOrder.h>
+
+#ifdef __OPTIMIZE__
+#define INLINE __attribute__((always_inline))
+#else
+#define INLINE
+#endif
+
+//
+// This abstraction layer is for use with file formats that have 64-bit/32-bit and Big-Endian/Little-Endian variants
+//
+// For example: to make a utility that handles 32-bit little enidan files use: Pointer32<LittleEndian>
+//
+//
+// get16() read a 16-bit number from an E endian struct
+// set16() write a 16-bit number to an E endian struct
+// get32() read a 32-bit number from an E endian struct
+// set32() write a 32-bit number to an E endian struct
+// get64() read a 64-bit number from an E endian struct
+// set64() write a 64-bit number to an E endian struct
+//
+// getBits() read a bit field from an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
+// setBits() write a bit field to an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
+//
+// getBitsRaw() read a bit field from a struct with native endianness
+// setBitsRaw() write a bit field from a struct with native endianness
+//
+
+class BigEndian
+{
+public:
+ static uint16_t get16(const uint16_t& from) INLINE { return OSReadBigInt16(&from, 0); }
+ static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteBigInt16(&into, 0, value); }
+
+ static uint32_t get32(const uint32_t& from) INLINE { return OSReadBigInt32(&from, 0); }
+ static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteBigInt32(&into, 0, value); }
+
+ static uint64_t get64(const uint64_t& from) INLINE { return OSReadBigInt64(&from, 0); }
+ static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteBigInt64(&into, 0, value); }
+
+ static uint32_t getBits(const uint32_t& from,
+ uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
+ static void setBits(uint32_t& into, uint32_t value,
+ uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
+
+ static uint32_t getBitsRaw(const uint32_t& from,
+ uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> (32-firstBit-bitCount)) & ((1<<bitCount)-1)); }
+ static void setBitsRaw(uint32_t& into, uint32_t value,
+ uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
+ const uint32_t mask = ((1<<bitCount)-1);
+ temp &= ~(mask << (32-firstBit-bitCount));
+ temp |= ((value & mask) << (32-firstBit-bitCount));
+ into = temp; }
+ enum { little_endian = 0 };
+};
+
+
+class LittleEndian
+{
+public:
+ static uint16_t get16(const uint16_t& from) INLINE { return OSReadLittleInt16(&from, 0); }
+ static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteLittleInt16(&into, 0, value); }
+
+ static uint32_t get32(const uint32_t& from) INLINE { return OSReadLittleInt32(&from, 0); }
+ static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteLittleInt32(&into, 0, value); }
+
+ static uint64_t get64(const uint64_t& from) INLINE { return OSReadLittleInt64(&from, 0); }
+ static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteLittleInt64(&into, 0, value); }
+
+ static uint32_t getBits(const uint32_t& from,
+ uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
+ static void setBits(uint32_t& into, uint32_t value,
+ uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
+
+ static uint32_t getBitsRaw(const uint32_t& from,
+ uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> firstBit) & ((1<<bitCount)-1)); }
+ static void setBitsRaw(uint32_t& into, uint32_t value,
+ uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
+ const uint32_t mask = ((1<<bitCount)-1);
+ temp &= ~(mask << firstBit);
+ temp |= ((value & mask) << firstBit);
+ into = temp; }
+ enum { little_endian = 1 };
+};
+
+
+template <typename _E>
+class Pointer32
+{
+public:
+ typedef uint32_t uint_t;
+ typedef int32_t sint_t;
+ typedef _E E;
+
+ static uint64_t getP(const uint_t& from) INLINE { return _E::get32(from); }
+ static void setP(uint_t& into, uint64_t value) INLINE { _E::set32(into, value); }
+};
+
+
+template <typename _E>
+class Pointer64
+{
+public:
+ typedef uint64_t uint_t;
+ typedef int64_t sint_t;
+ typedef _E E;
+
+ static uint64_t getP(const uint_t& from) INLINE { return _E::get64(from); }
+ static void setP(uint_t& into, uint64_t value) INLINE { _E::set64(into, value); }
+};
+
+
+
+
+
+#endif // __FILE_ABSTRACTION__
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+*/
+#ifndef __MACH_O_FILE_ABSTRACTION__
+#define __MACH_O_FILE_ABSTRACTION__
+
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/reloc.h>
+#include <mach-o/fat.h>
+#include <mach-o/stab.h>
+#include <mach-o/reloc.h>
+#include <mach-o/x86_64/reloc.h>
+#include <mach-o/compact_unwind_encoding.h>
+#include <mach/machine.h>
+#include <stddef.h>
+
+#include "FileAbstraction.hpp"
+
+#include "configure.h"
+
+// stuff that will eventually go away once newer cctools headers are widespread
+#ifndef LC_LOAD_UPWARD_DYLIB
+ #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_V5TEJ
+ #define CPU_SUBTYPE_ARM_V5TEJ ((cpu_subtype_t) 7)
+#endif
+#ifndef CPU_SUBTYPE_ARM_XSCALE
+ #define CPU_SUBTYPE_ARM_XSCALE ((cpu_subtype_t) 8)
+#endif
+#ifndef CPU_SUBTYPE_ARM_V7
+ #define CPU_SUBTYPE_ARM_V7 ((cpu_subtype_t) 9)
+#endif
+
+#ifndef N_ARM_THUMB_DEF
+ #define N_ARM_THUMB_DEF 0x0008
+#endif
+#ifndef MH_DEAD_STRIPPABLE_DYLIB
+ #define MH_DEAD_STRIPPABLE_DYLIB 0x400000
+#endif
+#ifndef MH_KEXT_BUNDLE
+ #define MH_KEXT_BUNDLE 11
+#endif
+#ifndef LC_DYLD_INFO
+ #define LC_DYLD_INFO 0x22 /* compressed dyld information */
+ #define LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD) /* compressed dyld information only */
+
+ struct dyld_info_command {
+ uint32_t cmd; /* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */
+ uint32_t cmdsize; /* sizeof(struct dyld_info_command) */
+ uint32_t rebase_off; /* file offset to rebase info */
+ uint32_t rebase_size; /* size of rebase info */
+ uint32_t bind_off; /* file offset to binding info */
+ uint32_t bind_size; /* size of binding info */
+ uint32_t weak_bind_off; /* file offset to weak binding info */
+ uint32_t weak_bind_size; /* size of weak binding info */
+ uint32_t lazy_bind_off; /* file offset to lazy binding info */
+ uint32_t lazy_bind_size; /* size of lazy binding infs */
+ uint32_t export_off; /* file offset to lazy binding info */
+ uint32_t export_size; /* size of lazy binding infs */
+ };
+
+ #define REBASE_TYPE_POINTER 1
+ #define REBASE_TYPE_TEXT_ABSOLUTE32 2
+ #define REBASE_TYPE_TEXT_PCREL32 3
+
+ #define REBASE_OPCODE_MASK 0xF0
+ #define REBASE_IMMEDIATE_MASK 0x0F
+ #define REBASE_OPCODE_DONE 0x00
+ #define REBASE_OPCODE_SET_TYPE_IMM 0x10
+ #define REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x20
+ #define REBASE_OPCODE_ADD_ADDR_ULEB 0x30
+ #define REBASE_OPCODE_ADD_ADDR_IMM_SCALED 0x40
+ #define REBASE_OPCODE_DO_REBASE_IMM_TIMES 0x50
+ #define REBASE_OPCODE_DO_REBASE_ULEB_TIMES 0x60
+ #define REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB 0x70
+ #define REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB 0x80
+
+ #define BIND_TYPE_POINTER 1
+ #define BIND_TYPE_TEXT_ABSOLUTE32 2
+ #define BIND_TYPE_TEXT_PCREL32 3
+
+ #define BIND_SPECIAL_DYLIB_SELF 0
+ #define BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE -1
+ #define BIND_SPECIAL_DYLIB_FLAT_LOOKUP -2
+
+ #define BIND_SYMBOL_FLAGS_WEAK_IMPORT 0x1
+ #define BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION 0x8
+
+ #define BIND_OPCODE_MASK 0xF0
+ #define BIND_IMMEDIATE_MASK 0x0F
+ #define BIND_OPCODE_DONE 0x00
+ #define BIND_OPCODE_SET_DYLIB_ORDINAL_IMM 0x10
+ #define BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB 0x20
+ #define BIND_OPCODE_SET_DYLIB_SPECIAL_IMM 0x30
+ #define BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM 0x40
+ #define BIND_OPCODE_SET_TYPE_IMM 0x50
+ #define BIND_OPCODE_SET_ADDEND_SLEB 0x60
+ #define BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x70
+ #define BIND_OPCODE_ADD_ADDR_ULEB 0x80
+ #define BIND_OPCODE_DO_BIND 0x90
+ #define BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB 0xA0
+ #define BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED 0xB0
+ #define BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0xC0
+
+ #define EXPORT_SYMBOL_FLAGS_KIND_MASK 0x03
+ #define EXPORT_SYMBOL_FLAGS_KIND_REGULAR 0x00
+ #define EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL 0x01
+ #define EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 0x04
+ #define EXPORT_SYMBOL_FLAGS_INDIRECT_DEFINITION 0x08
+ #define EXPORT_SYMBOL_FLAGS_HAS_SPECIALIZATIONS 0x10
+
+#endif
+
+#ifndef S_THREAD_LOCAL_REGULAR
+ #define S_THREAD_LOCAL_REGULAR 0x11
+#endif
+
+#ifndef S_THREAD_LOCAL_ZEROFILL
+ #define S_THREAD_LOCAL_ZEROFILL 0x12
+#endif
+
+#ifndef S_THREAD_LOCAL_VARIABLES
+ #define S_THREAD_LOCAL_VARIABLES 0x13
+#endif
+
+#ifndef S_THREAD_LOCAL_VARIABLE_POINTERS
+ #define S_THREAD_LOCAL_VARIABLE_POINTERS 0x14
+#endif
+
+#ifndef S_THREAD_LOCAL_INIT_FUNCTION_POINTERS
+ #define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 0x15
+#endif
+
+#ifndef MH_HAS_TLV_DESCRIPTORS
+ #define MH_HAS_TLV_DESCRIPTORS 0x800000
+#endif
+
+#ifndef X86_64_RELOC_TLV
+ #define X86_64_RELOC_TLV 9
+#endif
+
+#define GENERIC_RLEOC_TLV 5
+
+#ifndef EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
+ #define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10
+#endif
+
+#ifndef EXPORT_SYMBOL_FLAGS_REEXPORT
+ #define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08
+#endif
+
+// type internal to linker
+#define BIND_TYPE_OVERRIDE_OF_WEAKDEF_IN_DYLIB 0
+
+#ifndef LC_VERSION_MIN_MACOSX
+ #define LC_VERSION_MIN_MACOSX 0x24
+ #define LC_VERSION_MIN_IPHONEOS 0x25
+
+ struct version_min_command {
+ uint32_t cmd; /* LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS */
+ uint32_t cmdsize; /* sizeof(struct min_version_command) */
+ uint32_t version; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
+ uint32_t reserved; /* zero */
+ };
+#endif
+
+#ifndef N_SYMBOL_RESOLVER
+ #define N_SYMBOL_RESOLVER 0x100
+#endif
+
+#ifndef LC_FUNCTION_STARTS
+ #define LC_FUNCTION_STARTS 0x26
+#endif
+
+#ifndef MH_NO_HEAP_EXECUTION
+ #define MH_NO_HEAP_EXECUTION 0x1000000
+#endif
+
+#ifndef LC_DYLD_ENVIRONMENT
+ #define LC_DYLD_ENVIRONMENT 0x27
+#endif
+
+#ifndef LC_DATA_IN_CODE
+ #define LC_DATA_IN_CODE 0x29 /* table of non-instructions in __text */
+ struct data_in_code_entry {
+ uint32_t offset;
+ uint16_t length;
+ uint16_t kind;
+ };
+#endif
+
+#ifndef LC_DYLIB_CODE_SIGN_DRS
+ #define LC_DYLIB_CODE_SIGN_DRS 0x2B
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_V7F
+ #define CPU_SUBTYPE_ARM_V7F ((cpu_subtype_t) 10)
+#endif
+#ifndef CPU_SUBTYPE_ARM_V7K
+ #define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t) 12)
+#endif
+#ifndef CPU_SUBTYPE_ARM_V7S
+ #define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t) 11)
+#endif
+
+
+#ifndef LC_SOURCE_VERSION
+ #define LC_SOURCE_VERSION 0x2A
+ struct source_version_command {
+ uint32_t cmd; /* LC_SOURCE_VERSION */
+ uint32_t cmdsize; /* 16 */
+ uint64_t version; /* A.B.C.D.E packed as a24.b10.c10.d10.e10 */
+ };
+#endif
+
+#ifndef LC_MAIN
+ #define LC_MAIN (0x28|LC_REQ_DYLD) /* replacement for LC_UNIXTHREAD */
+ struct entry_point_command {
+ uint32_t cmd; /* LC_MAIN only used in MH_EXECUTE filetypes */
+ uint32_t cmdsize; /* 24 */
+ uint64_t entryoff; /* file (__TEXT) offset of main() */
+ uint64_t stacksize;/* if not zero, initial stack size */
+ };
+#endif
+
+#ifndef LC_DYLIB_CODE_SIGN_DRS
+ #define LC_DYLIB_CODE_SIGN_DRS 0x2B
+#endif
+
+
+struct ArchInfo {
+ const char* archName;
+ cpu_type_t cpuType;
+ cpu_subtype_t cpuSubType;
+ const char* llvmTriplePrefix;
+ const char* llvmTriplePrefixAlt;
+ bool isSubType;
+ bool supportsThumb2;
+};
+
+static const ArchInfo archInfoArray[] = {
+#if SUPPORT_ARCH_x86_64
+ { "x86_64", CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, "x86_64-", "", false, false },
+#endif
+#if SUPPORT_ARCH_i386
+ { "i386", CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL, "i386-", "", false, false },
+#endif
+#if SUPPORT_ARCH_armv4t
+ { "armv4t", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V4T, "armv4t-", "", true, false },
+ #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv5
+ { "armv5", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V5TEJ, "armv5e-", "", true, false },
+ #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv6
+ { "armv6", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6, "armv6-", "", true, false },
+ #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv7
+ { "armv7", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7, "thumbv7-", "armv7-", true, true },
+ #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv7f
+ { "armv7f", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7F, "thumbv7f-", "", true, true },
+ #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv7k
+ { "armv7k", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7K, "thumbv7k-", "", true, true },
+ #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv7s
+ { "armv7s", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S, "thumbv7s-", "armv7s", true, true },
+ #define SUPPORT_ARCH_arm_any 1
+#endif
+ { NULL, 0, 0, NULL, NULL, false, false }
+};
+
+
+// weird, but this include must wait until after SUPPORT_ARCH_arm_any is set up
+#if SUPPORT_ARCH_arm_any
+#include <mach-o/arm/reloc.h>
+#endif
+
+// hack until newer <mach-o/arm/reloc.h> everywhere
+#define ARM_RELOC_HALF 8
+#define ARM_RELOC_HALF_SECTDIFF 9
+
+
+
+//
+// This abstraction layer makes every mach-o file look like a 64-bit mach-o file with native endianness
+//
+
+
+
+//
+// mach-o file header
+//
+template <typename P> struct macho_header_content {};
+template <> struct macho_header_content<Pointer32<BigEndian> > { mach_header fields; };
+template <> struct macho_header_content<Pointer64<BigEndian> > { mach_header_64 fields; };
+template <> struct macho_header_content<Pointer32<LittleEndian> > { mach_header fields; };
+template <> struct macho_header_content<Pointer64<LittleEndian> > { mach_header_64 fields; };
+
+template <typename P>
+class macho_header {
+public:
+ uint32_t magic() const INLINE { return E::get32(header.fields.magic); }
+ void set_magic(uint32_t value) INLINE { E::set32(header.fields.magic, value); }
+
+ uint32_t cputype() const INLINE { return E::get32(header.fields.cputype); }
+ void set_cputype(uint32_t value) INLINE { E::set32((uint32_t&)header.fields.cputype, value); }
+
+ uint32_t cpusubtype() const INLINE { return E::get32(header.fields.cpusubtype); }
+ void set_cpusubtype(uint32_t value) INLINE { E::set32((uint32_t&)header.fields.cpusubtype, value); }
+
+ uint32_t filetype() const INLINE { return E::get32(header.fields.filetype); }
+ void set_filetype(uint32_t value) INLINE { E::set32(header.fields.filetype, value); }
+
+ uint32_t ncmds() const INLINE { return E::get32(header.fields.ncmds); }
+ void set_ncmds(uint32_t value) INLINE { E::set32(header.fields.ncmds, value); }
+
+ uint32_t sizeofcmds() const INLINE { return E::get32(header.fields.sizeofcmds); }
+ void set_sizeofcmds(uint32_t value) INLINE { E::set32(header.fields.sizeofcmds, value); }
+
+ uint32_t flags() const INLINE { return E::get32(header.fields.flags); }
+ void set_flags(uint32_t value) INLINE { E::set32(header.fields.flags, value); }
+
+ uint32_t reserved() const INLINE { return E::get32(header.fields.reserved); }
+ void set_reserved(uint32_t value) INLINE { E::set32(header.fields.reserved, value); }
+
+ typedef typename P::E E;
+private:
+ macho_header_content<P> header;
+};
+
+
+//
+// mach-o load command
+//
+template <typename P>
+class macho_load_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(command.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(command.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(command.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(command.cmdsize, value); }
+
+ typedef typename P::E E;
+private:
+ load_command command;
+};
+
+
+//
+// mach-o segment load command
+//
+template <typename P> struct macho_segment_content {};
+template <> struct macho_segment_content<Pointer32<BigEndian> > { segment_command fields; enum { CMD = LC_SEGMENT }; };
+template <> struct macho_segment_content<Pointer64<BigEndian> > { segment_command_64 fields; enum { CMD = LC_SEGMENT_64 }; };
+template <> struct macho_segment_content<Pointer32<LittleEndian> > { segment_command fields; enum { CMD = LC_SEGMENT }; };
+template <> struct macho_segment_content<Pointer64<LittleEndian> > { segment_command_64 fields; enum { CMD = LC_SEGMENT_64 }; };
+
+template <typename P>
+class macho_segment_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(segment.fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(segment.fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(segment.fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(segment.fields.cmdsize, value); }
+
+ const char* segname() const INLINE { return segment.fields.segname; }
+ void set_segname(const char* value) INLINE { strncpy(segment.fields.segname, value, 16); }
+
+ uint64_t vmaddr() const INLINE { return P::getP(segment.fields.vmaddr); }
+ void set_vmaddr(uint64_t value) INLINE { P::setP(segment.fields.vmaddr, value); }
+
+ uint64_t vmsize() const INLINE { return P::getP(segment.fields.vmsize); }
+ void set_vmsize(uint64_t value) INLINE { P::setP(segment.fields.vmsize, value); }
+
+ uint64_t fileoff() const INLINE { return P::getP(segment.fields.fileoff); }
+ void set_fileoff(uint64_t value) INLINE { P::setP(segment.fields.fileoff, value); }
+
+ uint64_t filesize() const INLINE { return P::getP(segment.fields.filesize); }
+ void set_filesize(uint64_t value) INLINE { P::setP(segment.fields.filesize, value); }
+
+ uint32_t maxprot() const INLINE { return E::get32(segment.fields.maxprot); }
+ void set_maxprot(uint32_t value) INLINE { E::set32((uint32_t&)segment.fields.maxprot, value); }
+
+ uint32_t initprot() const INLINE { return E::get32(segment.fields.initprot); }
+ void set_initprot(uint32_t value) INLINE { E::set32((uint32_t&)segment.fields.initprot, value); }
+
+ uint32_t nsects() const INLINE { return E::get32(segment.fields.nsects); }
+ void set_nsects(uint32_t value) INLINE { E::set32(segment.fields.nsects, value); }
+
+ uint32_t flags() const INLINE { return E::get32(segment.fields.flags); }
+ void set_flags(uint32_t value) INLINE { E::set32(segment.fields.flags, value); }
+
+ enum {
+ CMD = macho_segment_content<P>::CMD
+ };
+
+ typedef typename P::E E;
+private:
+ macho_segment_content<P> segment;
+};
+
+
+//
+// mach-o section
+//
+template <typename P> struct macho_section_content {};
+template <> struct macho_section_content<Pointer32<BigEndian> > { section fields; };
+template <> struct macho_section_content<Pointer64<BigEndian> > { section_64 fields; };
+template <> struct macho_section_content<Pointer32<LittleEndian> > { section fields; };
+template <> struct macho_section_content<Pointer64<LittleEndian> > { section_64 fields; };
+
+template <typename P>
+class macho_section {
+public:
+ const char* sectname() const INLINE { return section.fields.sectname; }
+ void set_sectname(const char* value) INLINE { strncpy(section.fields.sectname, value, 16); }
+
+ const char* segname() const INLINE { return section.fields.segname; }
+ void set_segname(const char* value) INLINE { strncpy(section.fields.segname, value, 16); }
+
+ uint64_t addr() const INLINE { return P::getP(section.fields.addr); }
+ void set_addr(uint64_t value) INLINE { P::setP(section.fields.addr, value); }
+
+ uint64_t size() const INLINE { return P::getP(section.fields.size); }
+ void set_size(uint64_t value) INLINE { P::setP(section.fields.size, value); }
+
+ uint32_t offset() const INLINE { return E::get32(section.fields.offset); }
+ void set_offset(uint32_t value) INLINE { E::set32(section.fields.offset, value); }
+
+ uint32_t align() const INLINE { return E::get32(section.fields.align); }
+ void set_align(uint32_t value) INLINE { E::set32(section.fields.align, value); }
+
+ uint32_t reloff() const INLINE { return E::get32(section.fields.reloff); }
+ void set_reloff(uint32_t value) INLINE { E::set32(section.fields.reloff, value); }
+
+ uint32_t nreloc() const INLINE { return E::get32(section.fields.nreloc); }
+ void set_nreloc(uint32_t value) INLINE { E::set32(section.fields.nreloc, value); }
+
+ uint32_t flags() const INLINE { return E::get32(section.fields.flags); }
+ void set_flags(uint32_t value) INLINE { E::set32(section.fields.flags, value); }
+
+ uint32_t reserved1() const INLINE { return E::get32(section.fields.reserved1); }
+ void set_reserved1(uint32_t value) INLINE { E::set32(section.fields.reserved1, value); }
+
+ uint32_t reserved2() const INLINE { return E::get32(section.fields.reserved2); }
+ void set_reserved2(uint32_t value) INLINE { E::set32(section.fields.reserved2, value); }
+
+ typedef typename P::E E;
+private:
+ macho_section_content<P> section;
+};
+
+
+//
+// mach-o dylib load command
+//
+template <typename P>
+class macho_dylib_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t name_offset() const INLINE { return E::get32(fields.dylib.name.offset); }
+ void set_name_offset(uint32_t value) INLINE { E::set32(fields.dylib.name.offset, value); }
+
+ uint32_t timestamp() const INLINE { return E::get32(fields.dylib.timestamp); }
+ void set_timestamp(uint32_t value) INLINE { E::set32(fields.dylib.timestamp, value); }
+
+ uint32_t current_version() const INLINE { return E::get32(fields.dylib.current_version); }
+ void set_current_version(uint32_t value) INLINE { E::set32(fields.dylib.current_version, value); }
+
+ uint32_t compatibility_version() const INLINE { return E::get32(fields.dylib.compatibility_version); }
+ void set_compatibility_version(uint32_t value) INLINE { E::set32(fields.dylib.compatibility_version, value); }
+
+ const char* name() const INLINE { return (const char*)&fields + name_offset(); }
+ void set_name_offset() INLINE { set_name_offset(sizeof(fields)); }
+
+ typedef typename P::E E;
+private:
+ dylib_command fields;
+};
+
+
+//
+// mach-o dylinker load command
+//
+template <typename P>
+class macho_dylinker_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t name_offset() const INLINE { return E::get32(fields.name.offset); }
+ void set_name_offset(uint32_t value) INLINE { E::set32(fields.name.offset, value); }
+
+ const char* name() const INLINE { return (const char*)&fields + name_offset(); }
+ void set_name_offset() INLINE { set_name_offset(sizeof(fields)); }
+
+ typedef typename P::E E;
+private:
+ dylinker_command fields;
+};
+
+
+//
+// mach-o sub_framework load command
+//
+template <typename P>
+class macho_sub_framework_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t umbrella_offset() const INLINE { return E::get32(fields.umbrella.offset); }
+ void set_umbrella_offset(uint32_t value) INLINE { E::set32(fields.umbrella.offset, value); }
+
+ const char* umbrella() const INLINE { return (const char*)&fields + umbrella_offset(); }
+ void set_umbrella_offset() INLINE { set_umbrella_offset(sizeof(fields)); }
+
+ typedef typename P::E E;
+private:
+ sub_framework_command fields;
+};
+
+
+//
+// mach-o sub_client load command
+//
+template <typename P>
+class macho_sub_client_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t client_offset() const INLINE { return E::get32(fields.client.offset); }
+ void set_client_offset(uint32_t value) INLINE { E::set32(fields.client.offset, value); }
+
+ const char* client() const INLINE { return (const char*)&fields + client_offset(); }
+ void set_client_offset() INLINE { set_client_offset(sizeof(fields)); }
+
+ typedef typename P::E E;
+private:
+ sub_client_command fields;
+};
+
+
+//
+// mach-o sub_umbrella load command
+//
+template <typename P>
+class macho_sub_umbrella_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t sub_umbrella_offset() const INLINE { return E::get32(fields.sub_umbrella.offset); }
+ void set_sub_umbrella_offset(uint32_t value) INLINE { E::set32(fields.sub_umbrella.offset, value); }
+
+ const char* sub_umbrella() const INLINE { return (const char*)&fields + sub_umbrella_offset(); }
+ void set_sub_umbrella_offset() INLINE { set_sub_umbrella_offset(sizeof(fields)); }
+
+ typedef typename P::E E;
+private:
+ sub_umbrella_command fields;
+};
+
+
+//
+// mach-o sub_library load command
+//
+template <typename P>
+class macho_sub_library_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t sub_library_offset() const INLINE { return E::get32(fields.sub_library.offset); }
+ void set_sub_library_offset(uint32_t value) INLINE { E::set32(fields.sub_library.offset, value); }
+
+ const char* sub_library() const INLINE { return (const char*)&fields + sub_library_offset(); }
+ void set_sub_library_offset() INLINE { set_sub_library_offset(sizeof(fields)); }
+
+ typedef typename P::E E;
+private:
+ sub_library_command fields;
+};
+
+
+//
+// mach-o uuid load command
+//
+template <typename P>
+class macho_uuid_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ const uint8_t* uuid() const INLINE { return fields.uuid; }
+ void set_uuid(const uint8_t u[16]) INLINE { memcpy(&fields.uuid, u, 16); }
+
+ typedef typename P::E E;
+private:
+ uuid_command fields;
+};
+
+
+//
+// mach-o routines load command
+//
+template <typename P> struct macho_routines_content {};
+template <> struct macho_routines_content<Pointer32<BigEndian> > { routines_command fields; enum { CMD = LC_ROUTINES }; };
+template <> struct macho_routines_content<Pointer64<BigEndian> > { routines_command_64 fields; enum { CMD = LC_ROUTINES_64 }; };
+template <> struct macho_routines_content<Pointer32<LittleEndian> > { routines_command fields; enum { CMD = LC_ROUTINES }; };
+template <> struct macho_routines_content<Pointer64<LittleEndian> > { routines_command_64 fields; enum { CMD = LC_ROUTINES_64 }; };
+
+template <typename P>
+class macho_routines_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(routines.fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(routines.fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(routines.fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(routines.fields.cmdsize, value); }
+
+ uint64_t init_address() const INLINE { return P::getP(routines.fields.init_address); }
+ void set_init_address(uint64_t value) INLINE { P::setP(routines.fields.init_address, value); }
+
+ uint64_t init_module() const INLINE { return P::getP(routines.fields.init_module); }
+ void set_init_module(uint64_t value) INLINE { P::setP(routines.fields.init_module, value); }
+
+ uint64_t reserved1() const INLINE { return P::getP(routines.fields.reserved1); }
+ void set_reserved1(uint64_t value) INLINE { P::setP(routines.fields.reserved1, value); }
+
+ uint64_t reserved2() const INLINE { return P::getP(routines.fields.reserved2); }
+ void set_reserved2(uint64_t value) INLINE { P::setP(routines.fields.reserved2, value); }
+
+ uint64_t reserved3() const INLINE { return P::getP(routines.fields.reserved3); }
+ void set_reserved3(uint64_t value) INLINE { P::setP(routines.fields.reserved3, value); }
+
+ uint64_t reserved4() const INLINE { return P::getP(routines.fields.reserved4); }
+ void set_reserved4(uint64_t value) INLINE { P::setP(routines.fields.reserved4, value); }
+
+ uint64_t reserved5() const INLINE { return P::getP(routines.fields.reserved5); }
+ void set_reserved5(uint64_t value) INLINE { P::setP(routines.fields.reserved5, value); }
+
+ uint64_t reserved6() const INLINE { return P::getP(routines.fields.reserved6); }
+ void set_reserved6(uint64_t value) INLINE { P::setP(routines.fields.reserved6, value); }
+
+ typedef typename P::E E;
+ enum {
+ CMD = macho_routines_content<P>::CMD
+ };
+private:
+ macho_routines_content<P> routines;
+};
+
+
+//
+// mach-o symbol table load command
+//
+template <typename P>
+class macho_symtab_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t symoff() const INLINE { return E::get32(fields.symoff); }
+ void set_symoff(uint32_t value) INLINE { E::set32(fields.symoff, value); }
+
+ uint32_t nsyms() const INLINE { return E::get32(fields.nsyms); }
+ void set_nsyms(uint32_t value) INLINE { E::set32(fields.nsyms, value); }
+
+ uint32_t stroff() const INLINE { return E::get32(fields.stroff); }
+ void set_stroff(uint32_t value) INLINE { E::set32(fields.stroff, value); }
+
+ uint32_t strsize() const INLINE { return E::get32(fields.strsize); }
+ void set_strsize(uint32_t value) INLINE { E::set32(fields.strsize, value); }
+
+
+ typedef typename P::E E;
+private:
+ symtab_command fields;
+};
+
+
+//
+// mach-o dynamic symbol table load command
+//
+template <typename P>
+class macho_dysymtab_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t ilocalsym() const INLINE { return E::get32(fields.ilocalsym); }
+ void set_ilocalsym(uint32_t value) INLINE { E::set32(fields.ilocalsym, value); }
+
+ uint32_t nlocalsym() const INLINE { return E::get32(fields.nlocalsym); }
+ void set_nlocalsym(uint32_t value) INLINE { E::set32(fields.nlocalsym, value); }
+
+ uint32_t iextdefsym() const INLINE { return E::get32(fields.iextdefsym); }
+ void set_iextdefsym(uint32_t value) INLINE { E::set32(fields.iextdefsym, value); }
+
+ uint32_t nextdefsym() const INLINE { return E::get32(fields.nextdefsym); }
+ void set_nextdefsym(uint32_t value) INLINE { E::set32(fields.nextdefsym, value); }
+
+ uint32_t iundefsym() const INLINE { return E::get32(fields.iundefsym); }
+ void set_iundefsym(uint32_t value) INLINE { E::set32(fields.iundefsym, value); }
+
+ uint32_t nundefsym() const INLINE { return E::get32(fields.nundefsym); }
+ void set_nundefsym(uint32_t value) INLINE { E::set32(fields.nundefsym, value); }
+
+ uint32_t tocoff() const INLINE { return E::get32(fields.tocoff); }
+ void set_tocoff(uint32_t value) INLINE { E::set32(fields.tocoff, value); }
+
+ uint32_t ntoc() const INLINE { return E::get32(fields.ntoc); }
+ void set_ntoc(uint32_t value) INLINE { E::set32(fields.ntoc, value); }
+
+ uint32_t modtaboff() const INLINE { return E::get32(fields.modtaboff); }
+ void set_modtaboff(uint32_t value) INLINE { E::set32(fields.modtaboff, value); }
+
+ uint32_t nmodtab() const INLINE { return E::get32(fields.nmodtab); }
+ void set_nmodtab(uint32_t value) INLINE { E::set32(fields.nmodtab, value); }
+
+ uint32_t extrefsymoff() const INLINE { return E::get32(fields.extrefsymoff); }
+ void set_extrefsymoff(uint32_t value) INLINE { E::set32(fields.extrefsymoff, value); }
+
+ uint32_t nextrefsyms() const INLINE { return E::get32(fields.nextrefsyms); }
+ void set_nextrefsyms(uint32_t value) INLINE { E::set32(fields.nextrefsyms, value); }
+
+ uint32_t indirectsymoff() const INLINE { return E::get32(fields.indirectsymoff); }
+ void set_indirectsymoff(uint32_t value) INLINE { E::set32(fields.indirectsymoff, value); }
+
+ uint32_t nindirectsyms() const INLINE { return E::get32(fields.nindirectsyms); }
+ void set_nindirectsyms(uint32_t value) INLINE { E::set32(fields.nindirectsyms, value); }
+
+ uint32_t extreloff() const INLINE { return E::get32(fields.extreloff); }
+ void set_extreloff(uint32_t value) INLINE { E::set32(fields.extreloff, value); }
+
+ uint32_t nextrel() const INLINE { return E::get32(fields.nextrel); }
+ void set_nextrel(uint32_t value) INLINE { E::set32(fields.nextrel, value); }
+
+ uint32_t locreloff() const INLINE { return E::get32(fields.locreloff); }
+ void set_locreloff(uint32_t value) INLINE { E::set32(fields.locreloff, value); }
+
+ uint32_t nlocrel() const INLINE { return E::get32(fields.nlocrel); }
+ void set_nlocrel(uint32_t value) INLINE { E::set32(fields.nlocrel, value); }
+
+ typedef typename P::E E;
+private:
+ dysymtab_command fields;
+};
+
+
+
+
+//
+// mach-o module table entry (for compatibility with old ld/dyld)
+//
+template <typename P> struct macho_dylib_module_content {};
+template <> struct macho_dylib_module_content<Pointer32<BigEndian> > { struct dylib_module fields; };
+template <> struct macho_dylib_module_content<Pointer32<LittleEndian> > { struct dylib_module fields; };
+template <> struct macho_dylib_module_content<Pointer64<BigEndian> > { struct dylib_module_64 fields; };
+template <> struct macho_dylib_module_content<Pointer64<LittleEndian> > { struct dylib_module_64 fields; };
+
+template <typename P>
+class macho_dylib_module {
+public:
+ uint32_t module_name() const INLINE { return E::get32(module.fields.module_name); }
+ void set_module_name(uint32_t value) INLINE { E::set32(module.fields.module_name, value); }
+
+ uint32_t iextdefsym() const INLINE { return E::get32(module.fields.iextdefsym); }
+ void set_iextdefsym(uint32_t value) INLINE { E::set32(module.fields.iextdefsym, value); }
+
+ uint32_t nextdefsym() const INLINE { return E::get32(module.fields.nextdefsym); }
+ void set_nextdefsym(uint32_t value) INLINE { E::set32(module.fields.nextdefsym, value); }
+
+ uint32_t irefsym() const INLINE { return E::get32(module.fields.irefsym); }
+ void set_irefsym(uint32_t value) INLINE { E::set32(module.fields.irefsym, value); }
+
+ uint32_t nrefsym() const INLINE { return E::get32(module.fields.nrefsym); }
+ void set_nrefsym(uint32_t value) INLINE { E::set32(module.fields.nrefsym, value); }
+
+ uint32_t ilocalsym() const INLINE { return E::get32(module.fields.ilocalsym); }
+ void set_ilocalsym(uint32_t value) INLINE { E::set32(module.fields.ilocalsym, value); }
+
+ uint32_t nlocalsym() const INLINE { return E::get32(module.fields.nlocalsym); }
+ void set_nlocalsym(uint32_t value) INLINE { E::set32(module.fields.nlocalsym, value); }
+
+ uint32_t iextrel() const INLINE { return E::get32(module.fields.iextrel); }
+ void set_iextrel(uint32_t value) INLINE { E::set32(module.fields.iextrel, value); }
+
+ uint32_t nextrel() const INLINE { return E::get32(module.fields.nextrel); }
+ void set_nextrel(uint32_t value) INLINE { E::set32(module.fields.nextrel, value); }
+
+ uint16_t iinit() const INLINE { return E::get32(module.fields.iinit_iterm) & 0xFFFF; }
+ uint16_t iterm() const INLINE { return E::get32(module.fields.iinit_iterm) > 16; }
+ void set_iinit_iterm(uint16_t init, uint16_t term) INLINE { E::set32(module.fields.iinit_iterm, (term<<16) | (init &0xFFFF)); }
+
+ uint16_t ninit() const INLINE { return E::get32(module.fields.ninit_nterm) & 0xFFFF; }
+ uint16_t nterm() const INLINE { return E::get32(module.fields.ninit_nterm) > 16; }
+ void set_ninit_nterm(uint16_t init, uint16_t term) INLINE { E::set32(module.fields.ninit_nterm, (term<<16) | (init &0xFFFF)); }
+
+ uint64_t objc_module_info_addr() const INLINE { return P::getP(module.fields.objc_module_info_addr); }
+ void set_objc_module_info_addr(uint64_t value) INLINE { P::setP(module.fields.objc_module_info_addr, value); }
+
+ uint32_t objc_module_info_size() const INLINE { return E::get32(module.fields.objc_module_info_size); }
+ void set_objc_module_info_size(uint32_t value) INLINE { E::set32(module.fields.objc_module_info_size, value); }
+
+
+ typedef typename P::E E;
+private:
+ macho_dylib_module_content<P> module;
+};
+
+
+//
+// mach-o dylib_reference entry
+//
+template <typename P>
+class macho_dylib_reference {
+public:
+ uint32_t isym() const INLINE { return E::getBits(fields, 0, 24); }
+ void set_isym(uint32_t value) INLINE { E::setBits(fields, value, 0, 24); }
+
+ uint8_t flags() const INLINE { return E::getBits(fields, 24, 8); }
+ void set_flags(uint8_t value) INLINE { E::setBits(fields, value, 24, 8); }
+
+ typedef typename P::E E;
+private:
+ uint32_t fields;
+};
+
+
+
+//
+// mach-o two-level hints load command
+//
+template <typename P>
+class macho_dylib_table_of_contents {
+public:
+ uint32_t symbol_index() const INLINE { return E::get32(fields.symbol_index); }
+ void set_symbol_index(uint32_t value) INLINE { E::set32(fields.symbol_index, value); }
+
+ uint32_t module_index() const INLINE { return E::get32(fields.module_index); }
+ void set_module_index(uint32_t value) INLINE { E::set32(fields.module_index, value); }
+
+ typedef typename P::E E;
+private:
+ dylib_table_of_contents fields;
+};
+
+
+
+//
+// mach-o two-level hints load command
+//
+template <typename P>
+class macho_twolevel_hints_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t offset() const INLINE { return E::get32(fields.offset); }
+ void set_offset(uint32_t value) INLINE { E::set32(fields.offset, value); }
+
+ uint32_t nhints() const INLINE { return E::get32(fields.nhints); }
+ void set_nhints(uint32_t value) INLINE { E::set32(fields.nhints, value); }
+
+ typedef typename P::E E;
+private:
+ twolevel_hints_command fields;
+};
+
+
+//
+// mach-o threads load command
+//
+template <typename P>
+class macho_thread_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t flavor() const INLINE { return E::get32(fields_flavor); }
+ void set_flavor(uint32_t value) INLINE { E::set32(fields_flavor, value); }
+
+ uint32_t count() const INLINE { return E::get32(fields_count); }
+ void set_count(uint32_t value) INLINE { E::set32(fields_count, value); }
+
+ uint64_t thread_register(uint32_t index) const INLINE { return P::getP(thread_registers[index]); }
+ void set_thread_register(uint32_t index, uint64_t value) INLINE { P::setP(thread_registers[index], value); }
+
+ typedef typename P::E E;
+ typedef typename P::uint_t pint_t;
+private:
+ struct thread_command fields;
+ uint32_t fields_flavor;
+ uint32_t fields_count;
+ pint_t thread_registers[1];
+};
+
+
+//
+// mach-o misc data
+//
+template <typename P>
+class macho_linkedit_data_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t dataoff() const INLINE { return E::get32(fields.dataoff); }
+ void set_dataoff(uint32_t value) INLINE { E::set32(fields.dataoff, value); }
+
+ uint32_t datasize() const INLINE { return E::get32(fields.datasize); }
+ void set_datasize(uint32_t value)INLINE { E::set32(fields.datasize, value); }
+
+
+ typedef typename P::E E;
+private:
+ struct linkedit_data_command fields;
+};
+
+
+//
+// mach-o rpath
+//
+template <typename P>
+class macho_rpath_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t path_offset() const INLINE { return E::get32(fields.path.offset); }
+ void set_path_offset(uint32_t value) INLINE { E::set32(fields.path.offset, value); }
+
+ const char* path() const INLINE { return (const char*)&fields + path_offset(); }
+ void set_path_offset() INLINE { set_path_offset(sizeof(fields)); }
+
+
+ typedef typename P::E E;
+private:
+ struct rpath_command fields;
+};
+
+
+
+//
+// mach-o symbol table entry
+//
+template <typename P> struct macho_nlist_content {};
+template <> struct macho_nlist_content<Pointer32<BigEndian> > { struct nlist fields; };
+template <> struct macho_nlist_content<Pointer64<BigEndian> > { struct nlist_64 fields; };
+template <> struct macho_nlist_content<Pointer32<LittleEndian> > { struct nlist fields; };
+template <> struct macho_nlist_content<Pointer64<LittleEndian> > { struct nlist_64 fields; };
+
+template <typename P>
+class macho_nlist {
+public:
+ uint32_t n_strx() const INLINE { return E::get32(entry.fields.n_un.n_strx); }
+ void set_n_strx(uint32_t value) INLINE { E::set32((uint32_t&)entry.fields.n_un.n_strx, value); }
+
+ uint8_t n_type() const INLINE { return entry.fields.n_type; }
+ void set_n_type(uint8_t value) INLINE { entry.fields.n_type = value; }
+
+ uint8_t n_sect() const INLINE { return entry.fields.n_sect; }
+ void set_n_sect(uint8_t value) INLINE { entry.fields.n_sect = value; }
+
+ uint16_t n_desc() const INLINE { return E::get16(entry.fields.n_desc); }
+ void set_n_desc(uint16_t value) INLINE { E::set16((uint16_t&)entry.fields.n_desc, value); }
+
+ uint64_t n_value() const INLINE { return P::getP(entry.fields.n_value); }
+ void set_n_value(uint64_t value) INLINE { P::setP(entry.fields.n_value, value); }
+
+ typedef typename P::E E;
+private:
+ macho_nlist_content<P> entry;
+};
+
+
+
+//
+// mach-o relocation info
+//
+template <typename P>
+class macho_relocation_info {
+public:
+ uint32_t r_address() const INLINE { return E::get32(address); }
+ void set_r_address(uint32_t value) INLINE { E::set32(address, value); }
+
+ uint32_t r_symbolnum() const INLINE { return E::getBits(other, 0, 24); }
+ void set_r_symbolnum(uint32_t value) INLINE { E::setBits(other, value, 0, 24); }
+
+ bool r_pcrel() const INLINE { return E::getBits(other, 24, 1); }
+ void set_r_pcrel(bool value) INLINE { E::setBits(other, value, 24, 1); }
+
+ uint8_t r_length() const INLINE { return E::getBits(other, 25, 2); }
+ void set_r_length(uint8_t value) INLINE { E::setBits(other, value, 25, 2); }
+
+ bool r_extern() const INLINE { return E::getBits(other, 27, 1); }
+ void set_r_extern(bool value) INLINE { E::setBits(other, value, 27, 1); }
+
+ uint8_t r_type() const INLINE { return E::getBits(other, 28, 4); }
+ void set_r_type(uint8_t value) INLINE { E::setBits(other, value, 28, 4); }
+
+ void set_r_length() INLINE { set_r_length((sizeof(typename P::uint_t)==8) ? 3 : 2); }
+
+ typedef typename P::E E;
+private:
+ uint32_t address;
+ uint32_t other;
+};
+
+
+//
+// mach-o scattered relocation info
+// The bit fields are always in big-endian order (see mach-o/reloc.h)
+//
+template <typename P>
+class macho_scattered_relocation_info {
+public:
+ bool r_scattered() const INLINE { return BigEndian::getBitsRaw(E::get32(other), 0, 1); }
+ void set_r_scattered(bool x) INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 0, 1); E::set32(other, temp); }
+
+ bool r_pcrel() const INLINE { return BigEndian::getBitsRaw(E::get32(other), 1, 1); }
+ void set_r_pcrel(bool x) INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 1, 1); E::set32(other, temp); }
+
+ uint8_t r_length() const INLINE { return BigEndian::getBitsRaw(E::get32(other), 2, 2); }
+ void set_r_length(uint8_t x) INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 2, 2); E::set32(other, temp); }
+
+ uint8_t r_type() const INLINE { return BigEndian::getBitsRaw(E::get32(other), 4, 4); }
+ void set_r_type(uint8_t x) INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 4, 4); E::set32(other, temp); }
+
+ uint32_t r_address() const INLINE { return BigEndian::getBitsRaw(E::get32(other), 8, 24); }
+ void set_r_address(uint32_t x) { if ( x > 0x00FFFFFF ) throw "scattered reloc r_address too large";
+ uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 8, 24); E::set32(other, temp); }
+
+ uint32_t r_value() const INLINE { return E::get32(value); }
+ void set_r_value(uint32_t x) INLINE { E::set32(value, x); }
+
+ uint32_t r_other() const INLINE { return other; }
+
+ void set_r_length() INLINE { set_r_length((sizeof(typename P::uint_t)==8) ? 3 : 2); }
+
+ typedef typename P::E E;
+private:
+ uint32_t other;
+ uint32_t value;
+};
+
+
+
+//
+// mach-o encyrption info load command
+//
+template <typename P>
+class macho_encryption_info_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t cryptoff() const INLINE { return E::get32(fields.cryptoff); }
+ void set_cryptoff(uint32_t value) INLINE { E::set32(fields.cryptoff, value); }
+
+ uint32_t cryptsize() const INLINE { return E::get32(fields.cryptsize); }
+ void set_cryptsize(uint32_t value) INLINE { E::set32(fields.cryptsize, value); }
+
+ uint32_t cryptid() const INLINE { return E::get32(fields.cryptid); }
+ void set_cryptid(uint32_t value) INLINE { E::set32(fields.cryptid, value); }
+
+ typedef typename P::E E;
+private:
+ encryption_info_command fields;
+};
+
+
+//
+// start of __unwind_info section
+//
+template <typename P>
+class macho_unwind_info_section_header {
+public:
+ uint32_t version() const INLINE { return E::get32(fields.version); }
+ void set_version(uint32_t value) INLINE { E::set32(fields.version, value); }
+
+ uint32_t commonEncodingsArraySectionOffset() const INLINE { return E::get32(fields.commonEncodingsArraySectionOffset); }
+ void set_commonEncodingsArraySectionOffset(uint32_t value) INLINE { E::set32(fields.commonEncodingsArraySectionOffset, value); }
+
+ uint32_t commonEncodingsArrayCount() const INLINE { return E::get32(fields.commonEncodingsArrayCount); }
+ void set_commonEncodingsArrayCount(uint32_t value) INLINE { E::set32(fields.commonEncodingsArrayCount, value); }
+
+ uint32_t personalityArraySectionOffset() const INLINE { return E::get32(fields.personalityArraySectionOffset); }
+ void set_personalityArraySectionOffset(uint32_t value) INLINE { E::set32(fields.personalityArraySectionOffset, value); }
+
+ uint32_t personalityArrayCount() const INLINE { return E::get32(fields.personalityArrayCount); }
+ void set_personalityArrayCount(uint32_t value) INLINE { E::set32(fields.personalityArrayCount, value); }
+
+ uint32_t indexSectionOffset() const INLINE { return E::get32(fields.indexSectionOffset); }
+ void set_indexSectionOffset(uint32_t value) INLINE { E::set32(fields.indexSectionOffset, value); }
+
+ uint32_t indexCount() const INLINE { return E::get32(fields.indexCount); }
+ void set_indexCount(uint32_t value) INLINE { E::set32(fields.indexCount, value); }
+
+ typedef typename P::E E;
+private:
+ unwind_info_section_header fields;
+};
+
+
+
+//
+// uwind first level index entry
+//
+template <typename P>
+class macho_unwind_info_section_header_index_entry {
+public:
+ uint32_t functionOffset() const INLINE { return E::get32(fields.functionOffset); }
+ void set_functionOffset(uint32_t value) INLINE { E::set32(fields.functionOffset, value); }
+
+ uint32_t secondLevelPagesSectionOffset() const INLINE { return E::get32(fields.secondLevelPagesSectionOffset); }
+ void set_secondLevelPagesSectionOffset(uint32_t value) INLINE { E::set32(fields.secondLevelPagesSectionOffset, value); }
+
+ uint32_t lsdaIndexArraySectionOffset() const INLINE { return E::get32(fields.lsdaIndexArraySectionOffset); }
+ void set_lsdaIndexArraySectionOffset(uint32_t value) INLINE { E::set32(fields.lsdaIndexArraySectionOffset, value); }
+
+ typedef typename P::E E;
+private:
+ unwind_info_section_header_index_entry fields;
+};
+
+
+//
+// LSDA table entry
+//
+template <typename P>
+class macho_unwind_info_section_header_lsda_index_entry {
+public:
+ uint32_t functionOffset() const INLINE { return E::get32(fields.functionOffset); }
+ void set_functionOffset(uint32_t value) INLINE { E::set32(fields.functionOffset, value); }
+
+ uint32_t lsdaOffset() const INLINE { return E::get32(fields.lsdaOffset); }
+ void set_lsdaOffset(uint32_t value) INLINE { E::set32(fields.lsdaOffset, value); }
+
+ typedef typename P::E E;
+private:
+ unwind_info_section_header_lsda_index_entry fields;
+};
+
+
+//
+// regular second level entry
+//
+template <typename P>
+class macho_unwind_info_regular_second_level_entry {
+public:
+ uint32_t functionOffset() const INLINE { return E::get32(fields.functionOffset); }
+ void set_functionOffset(uint32_t value) INLINE { E::set32(fields.functionOffset, value); }
+
+ uint32_t encoding() const INLINE { return E::get32(fields.encoding); }
+ void set_encoding(uint32_t value) INLINE { E::set32(fields.encoding, value); }
+
+ typedef typename P::E E;
+private:
+ unwind_info_regular_second_level_entry fields;
+};
+
+
+//
+// start of second level regular page
+//
+template <typename P>
+class macho_unwind_info_regular_second_level_page_header {
+public:
+ uint32_t kind() const INLINE { return E::get32(fields.kind); }
+ void set_kind(uint32_t value) INLINE { E::set32(fields.kind, value); }
+
+ uint16_t entryPageOffset() const INLINE { return E::get16(fields.entryPageOffset); }
+ void set_entryPageOffset(uint16_t value) INLINE { E::set16((uint16_t&)fields.entryPageOffset, value); }
+
+ uint16_t entryCount() const INLINE { return E::get16(fields.entryCount); }
+ void set_entryCount(uint16_t value) INLINE { E::set16((uint16_t&)fields.entryCount, value); }
+
+ typedef typename P::E E;
+private:
+ unwind_info_regular_second_level_page_header fields;
+};
+
+
+//
+// start of second level compressed page
+//
+template <typename P>
+class macho_unwind_info_compressed_second_level_page_header {
+public:
+ uint32_t kind() const INLINE { return E::get32(fields.kind); }
+ void set_kind(uint32_t value) INLINE { E::set32(fields.kind, value); }
+
+ uint16_t entryPageOffset() const INLINE { return E::get16(fields.entryPageOffset); }
+ void set_entryPageOffset(uint16_t value) INLINE { E::set16((uint16_t&)fields.entryPageOffset, value); }
+
+ uint16_t entryCount() const INLINE { return E::get16(fields.entryCount); }
+ void set_entryCount(uint16_t value) INLINE { E::set16((uint16_t&)fields.entryCount, value); }
+
+ uint16_t encodingsPageOffset() const INLINE { return E::get16(fields.encodingsPageOffset); }
+ void set_encodingsPageOffset(uint16_t value) INLINE { E::set16((uint16_t&)fields.encodingsPageOffset, value); }
+
+ uint16_t encodingsCount() const INLINE { return E::get16(fields.encodingsCount); }
+ void set_encodingsCount(uint16_t value) INLINE { E::set16((uint16_t&)fields.encodingsCount, value); }
+
+ typedef typename P::E E;
+private:
+ unwind_info_compressed_second_level_page_header fields;
+};
+
+
+//
+// compressed dyld info load command
+//
+template <typename P>
+class macho_dyld_info_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t rebase_off() const INLINE { return E::get32(fields.rebase_off); }
+ void set_rebase_off(uint32_t value) INLINE { E::set32(fields.rebase_off, value); }
+
+ uint32_t rebase_size() const INLINE { return E::get32(fields.rebase_size); }
+ void set_rebase_size(uint32_t value) INLINE { E::set32(fields.rebase_size, value); }
+
+ uint32_t bind_off() const INLINE { return E::get32(fields.bind_off); }
+ void set_bind_off(uint32_t value) INLINE { E::set32(fields.bind_off, value); }
+
+ uint32_t bind_size() const INLINE { return E::get32(fields.bind_size); }
+ void set_bind_size(uint32_t value) INLINE { E::set32(fields.bind_size, value); }
+
+ uint32_t weak_bind_off() const INLINE { return E::get32(fields.weak_bind_off); }
+ void set_weak_bind_off(uint32_t value) INLINE { E::set32(fields.weak_bind_off, value); }
+
+ uint32_t weak_bind_size() const INLINE { return E::get32(fields.weak_bind_size); }
+ void set_weak_bind_size(uint32_t value) INLINE { E::set32(fields.weak_bind_size, value); }
+
+ uint32_t lazy_bind_off() const INLINE { return E::get32(fields.lazy_bind_off); }
+ void set_lazy_bind_off(uint32_t value) INLINE { E::set32(fields.lazy_bind_off, value); }
+
+ uint32_t lazy_bind_size() const INLINE { return E::get32(fields.lazy_bind_size); }
+ void set_lazy_bind_size(uint32_t value) INLINE { E::set32(fields.lazy_bind_size, value); }
+
+ uint32_t export_off() const INLINE { return E::get32(fields.export_off); }
+ void set_export_off(uint32_t value) INLINE { E::set32(fields.export_off, value); }
+
+ uint32_t export_size() const INLINE { return E::get32(fields.export_size); }
+ void set_export_size(uint32_t value) INLINE { E::set32(fields.export_size, value); }
+
+
+ typedef typename P::E E;
+private:
+ dyld_info_command fields;
+};
+
+
+//
+// mach-o version load command
+//
+template <typename P>
+class macho_version_min_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint32_t version() const INLINE { return fields.version; }
+ void set_version(uint32_t value) INLINE { E::set32(fields.version, value); }
+
+#ifdef DICE_KIND_DATA
+ uint32_t sdk() const INLINE { return fields.sdk; }
+ void set_sdk(uint32_t value) INLINE { E::set32(fields.sdk, value); }
+#else
+ uint32_t sdk() const INLINE { return fields.reserved; }
+ void set_sdk(uint32_t value) INLINE { E::set32(fields.reserved, value); }
+#endif
+
+ typedef typename P::E E;
+private:
+ version_min_command fields;
+};
+
+
+//
+// mach-o __LD, __compact_unwind section in object files
+//
+template <typename P>
+class macho_compact_unwind_entry {
+public:
+ typedef typename P::E E;
+ typedef typename P::uint_t pint_t;
+
+ pint_t codeStart() const INLINE { return P::getP(_codeStart); }
+ void set_codeStart(pint_t value) INLINE { P::setP(_codeStart, value); }
+
+ uint32_t codeLen() const INLINE { return E::get32(_codeLen); }
+ void set_codeLen(uint32_t value) INLINE { E::set32(_codeLen, value); }
+
+ uint32_t compactUnwindInfo() const INLINE { return E::get32(_compactUnwindInfo); }
+ void set_compactUnwindInfo(uint32_t value) INLINE { E::set32(_compactUnwindInfo, value); }
+
+ pint_t personality() const INLINE { return P::getP(_personality); }
+ void set_personality(pint_t value) INLINE { P::setP(_personality, value); }
+
+ pint_t lsda() const INLINE { return P::getP(_lsda); }
+ void set_lsda(pint_t value) INLINE { P::setP(_lsda, value); }
+
+ static uint32_t codeStartFieldOffset() INLINE { return offsetof(macho_compact_unwind_entry<P>,_codeStart); }
+ static uint32_t personalityFieldOffset() INLINE { return offsetof(macho_compact_unwind_entry<P>,_personality); }
+ static uint32_t lsdaFieldOffset() INLINE { return offsetof(macho_compact_unwind_entry<P>,_lsda); }
+
+private:
+ pint_t _codeStart;
+ uint32_t _codeLen;
+ uint32_t _compactUnwindInfo;
+ pint_t _personality;
+ pint_t _lsda;
+};
+
+
+//
+// mach-o source version load command
+//
+template <typename P>
+class macho_source_version_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint64_t version() const INLINE { return fields.version; }
+ void set_version(uint64_t value) INLINE { E::set64(fields.version, value); }
+
+ typedef typename P::E E;
+private:
+ source_version_command fields;
+};
+
+
+//
+// mach-o source version load command
+//
+template <typename P>
+class macho_entry_point_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint64_t entryoff() const INLINE { return fields.entryoff; }
+ void set_entryoff(uint64_t value) INLINE { E::set64(fields.entryoff, value); }
+
+ uint64_t stacksize() const INLINE { return fields.stacksize; }
+ void set_stacksize(uint64_t value) INLINE { E::set64(fields.stacksize, value); }
+
+ typedef typename P::E E;
+private:
+ entry_point_command fields;
+};
+
+
+
+template <typename P>
+class macho_data_in_code_entry {
+public:
+ uint32_t offset() const INLINE { return E::get32(fields.offset); }
+ void set_offset(uint32_t value) INLINE { E::set32(fields.offset, value); }
+
+ uint16_t length() const INLINE { return E::get16(fields.length); }
+ void set_length(uint16_t value) INLINE { E::set16((uint16_t&)fields.length, value); }
+
+ uint16_t kind() const INLINE { return E::get16(fields.kind); }
+ void set_kind(uint16_t value) INLINE { E::set16((uint16_t&)fields.kind, value); }
+
+ typedef typename P::E E;
+private:
+ data_in_code_entry fields;
+};
+
+
+#endif // __MACH_O_FILE_ABSTRACTION__
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+*/
+#ifndef __MACH_O_TRIE__
+#define __MACH_O_TRIE__
+
+#include <algorithm>
+#include <assert.h>
+
+#include "MachOFileAbstraction.hpp"
+
+
+namespace mach_o {
+namespace trie {
+
+struct Edge
+{
+ Edge(const char* s, struct Node* n) : fSubString(s), fChild(n) { }
+ ~Edge() { }
+ const char* fSubString;
+ struct Node* fChild;
+
+};
+
+struct Node
+{
+ Node(const char* s) : fCummulativeString(s), fAddress(0), fFlags(0),
+ fOther(0), fImportedName(NULL), fOrdered(false),
+ fHaveExportInfo(false), fTrieOffset(0) {}
+ ~Node() { }
+ const char* fCummulativeString;
+ std::vector<Edge> fChildren;
+ uint64_t fAddress;
+ uint64_t fFlags;
+ uint64_t fOther;
+ const char* fImportedName;
+ bool fOrdered;
+ bool fHaveExportInfo;
+ uint32_t fTrieOffset;
+
+ void addSymbol(const char* fullStr, uint64_t address, uint64_t flags, uint64_t other, const char* importName) {
+ const char* partialStr = &fullStr[strlen(fCummulativeString)];
+ for (std::vector<Edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
+ Edge& e = *it;
+ int subStringLen = strlen(e.fSubString);
+ if ( strncmp(e.fSubString, partialStr, subStringLen) == 0 ) {
+ // already have matching edge, go down that path
+ e.fChild->addSymbol(fullStr, address, flags, other, importName);
+ return;
+ }
+ else {
+ for (int i=subStringLen-1; i > 0; --i) {
+ if ( strncmp(e.fSubString, partialStr, i) == 0 ) {
+ // found a common substring, splice in new node
+ // was A -> C, now A -> B -> C
+ char* bNodeCummStr = strdup(e.fChild->fCummulativeString);
+ bNodeCummStr[strlen(bNodeCummStr)+i-subStringLen] = '\0';
+ //node* aNode = this;
+ Node* bNode = new Node(bNodeCummStr);
+ Node* cNode = e.fChild;
+ char* abEdgeStr = strdup(e.fSubString);
+ abEdgeStr[i] = '\0';
+ char* bcEdgeStr = strdup(&e.fSubString[i]);
+ Edge& abEdge = e;
+ abEdge.fSubString = abEdgeStr;
+ abEdge.fChild = bNode;
+ Edge bcEdge(bcEdgeStr, cNode);
+ bNode->fChildren.push_back(bcEdge);
+ bNode->addSymbol(fullStr, address, flags, other, importName);
+ return;
+ }
+ }
+ }
+ }
+ if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+ assert(importName != NULL);
+ assert(other != 0);
+ }
+ if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
+ assert(other != 0);
+ }
+ // no commonality with any existing child, make a new edge that is this whole string
+ Node* newNode = new Node(strdup(fullStr));
+ Edge newEdge(strdup(partialStr), newNode);
+ fChildren.push_back(newEdge);
+ newNode->fAddress = address;
+ newNode->fFlags = flags;
+ newNode->fOther = other;
+ if ( (flags & EXPORT_SYMBOL_FLAGS_REEXPORT) && (importName != NULL) && (strcmp(fullStr,importName) != 0) )
+ newNode->fImportedName = importName;
+ else
+ newNode->fImportedName = NULL;
+ newNode->fHaveExportInfo = true;
+ }
+
+ void addOrderedNodes(const char* name, std::vector<Node*>& orderedNodes) {
+ if ( !fOrdered ) {
+ orderedNodes.push_back(this);
+ //fprintf(stderr, "ordered %p %s\n", this, fCummulativeString);
+ fOrdered = true;
+ }
+ const char* partialStr = &name[strlen(fCummulativeString)];
+ for (std::vector<Edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
+ Edge& e = *it;
+ int subStringLen = strlen(e.fSubString);
+ if ( strncmp(e.fSubString, partialStr, subStringLen) == 0 ) {
+ // already have matching edge, go down that path
+ e.fChild->addOrderedNodes(name, orderedNodes);
+ return;
+ }
+ }
+ }
+
+ // byte for terminal node size in bytes, or 0x00 if not terminal node
+ // teminal node (uleb128 flags, uleb128 addr [uleb128 other])
+ // byte for child node count
+ // each child: zero terminated substring, uleb128 node offset
+ bool updateOffset(uint32_t& offset) {
+ uint32_t nodeSize = 1; // length of export info when no export info
+ if ( fHaveExportInfo ) {
+ if ( fFlags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+ nodeSize = uleb128_size(fFlags) + uleb128_size(fOther); // ordinal
+ if ( fImportedName != NULL )
+ nodeSize += strlen(fImportedName);
+ ++nodeSize; // trailing zero in imported name
+ }
+ else {
+ nodeSize = uleb128_size(fFlags) + uleb128_size(fAddress);
+ if ( fFlags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
+ nodeSize += uleb128_size(fOther);
+ }
+ // do have export info, overall node size so far is uleb128 of export info + export info
+ nodeSize += uleb128_size(nodeSize);
+ }
+ // add children
+ ++nodeSize; // byte for count of chidren
+ for (std::vector<Edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
+ Edge& e = *it;
+ nodeSize += strlen(e.fSubString) + 1 + uleb128_size(e.fChild->fTrieOffset);
+ }
+ bool result = (fTrieOffset != offset);
+ fTrieOffset = offset;
+ //fprintf(stderr, "updateOffset %p %05d %s\n", this, fTrieOffset, fCummulativeString);
+ offset += nodeSize;
+ // return true if fTrieOffset was changed
+ return result;
+ }
+
+ void appendToStream(std::vector<uint8_t>& out) {
+ if ( fHaveExportInfo ) {
+ if ( fFlags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+ if ( fImportedName != NULL ) {
+ // nodes with re-export info: size, flags, ordinal, string
+ uint32_t nodeSize = uleb128_size(fFlags) + uleb128_size(fOther) + strlen(fImportedName) + 1;
+ out.push_back(nodeSize);
+ append_uleb128(fFlags, out);
+ append_uleb128(fOther, out);
+ append_string(fImportedName, out);
+ }
+ else {
+ // nodes with re-export info: size, flags, ordinal, empty-string
+ uint32_t nodeSize = uleb128_size(fFlags) + uleb128_size(fOther) + 1;
+ out.push_back(nodeSize);
+ append_uleb128(fFlags, out);
+ append_uleb128(fOther, out);
+ out.push_back(0);
+ }
+ }
+ else if ( fFlags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
+ // nodes with export info: size, flags, address, other
+ uint32_t nodeSize = uleb128_size(fFlags) + uleb128_size(fAddress) + uleb128_size(fOther);
+ out.push_back(nodeSize);
+ append_uleb128(fFlags, out);
+ append_uleb128(fAddress, out);
+ append_uleb128(fOther, out);
+ }
+ else {
+ // nodes with export info: size, flags, address
+ uint32_t nodeSize = uleb128_size(fFlags) + uleb128_size(fAddress);
+ out.push_back(nodeSize);
+ append_uleb128(fFlags, out);
+ append_uleb128(fAddress, out);
+ }
+ }
+ else {
+ // no export info uleb128 of zero is one byte of zero
+ out.push_back(0);
+ }
+ // write number of children
+ out.push_back(fChildren.size());
+ // write each child
+ for (std::vector<Edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
+ Edge& e = *it;
+ append_string(e.fSubString, out);
+ append_uleb128(e.fChild->fTrieOffset, out);
+ }
+ }
+
+private:
+ static void append_uleb128(uint64_t value, std::vector<uint8_t>& out) {
+ uint8_t byte;
+ do {
+ byte = value & 0x7F;
+ value &= ~0x7F;
+ if ( value != 0 )
+ byte |= 0x80;
+ out.push_back(byte);
+ value = value >> 7;
+ } while( byte >= 0x80 );
+ }
+
+ static void append_string(const char* str, std::vector<uint8_t>& out) {
+ for (const char* s = str; *s != '\0'; ++s)
+ out.push_back(*s);
+ out.push_back('\0');
+ }
+
+ static unsigned int uleb128_size(uint64_t value) {
+ uint32_t result = 0;
+ do {
+ value = value >> 7;
+ ++result;
+ } while ( value != 0 );
+ return result;
+ }
+
+
+};
+
+inline uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end) {
+ uint64_t result = 0;
+ int bit = 0;
+ do {
+ if (p == end)
+ throw "malformed uleb128 extends beyond trie";
+
+ uint64_t slice = *p & 0x7f;
+
+ if (bit >= 64 || slice << bit >> bit != slice)
+ throw "uleb128 too big for 64-bits";
+ else {
+ result |= (slice << bit);
+ bit += 7;
+ }
+ }
+ while (*p++ & 0x80);
+ return result;
+}
+
+
+
+struct Entry
+{
+ const char* name;
+ uint64_t address;
+ uint64_t flags;
+ uint64_t other;
+ const char* importName;
+};
+
+
+
+inline void makeTrie(const std::vector<Entry>& entries, std::vector<uint8_t>& output)
+{
+ Node start(strdup(""));
+
+ // make nodes for all exported symbols
+ for (std::vector<Entry>::const_iterator it = entries.begin(); it != entries.end(); ++it) {
+ start.addSymbol(it->name, it->address, it->flags, it->other, it->importName);
+ }
+
+ // create vector of nodes
+ std::vector<Node*> orderedNodes;
+ orderedNodes.reserve(entries.size()*2);
+ for (std::vector<Entry>::const_iterator it = entries.begin(); it != entries.end(); ++it) {
+ start.addOrderedNodes(it->name, orderedNodes);
+ }
+
+ // assign each node in the vector an offset in the trie stream, iterating until all uleb128 sizes have stabilized
+ bool more;
+ do {
+ uint32_t offset = 0;
+ more = false;
+ for (std::vector<Node*>::iterator it = orderedNodes.begin(); it != orderedNodes.end(); ++it) {
+ if ( (*it)->updateOffset(offset) )
+ more = true;
+ }
+ } while ( more );
+
+ // create trie stream
+ for (std::vector<Node*>::iterator it = orderedNodes.begin(); it != orderedNodes.end(); ++it) {
+ (*it)->appendToStream(output);
+ }
+}
+
+struct EntryWithOffset
+{
+ uintptr_t nodeOffset;
+ Entry entry;
+
+ bool operator<(const EntryWithOffset& other) const { return ( nodeOffset < other.nodeOffset ); }
+};
+
+
+
+static inline void processExportNode(const uint8_t* const start, const uint8_t* p, const uint8_t* const end,
+ char* cummulativeString, int curStrOffset,
+ std::vector<EntryWithOffset>& output)
+{
+ if ( p >= end )
+ throw "malformed trie, node past end";
+ const uint8_t terminalSize = read_uleb128(p, end);
+ const uint8_t* children = p + terminalSize;
+ if ( terminalSize != 0 ) {
+ EntryWithOffset e;
+ e.nodeOffset = p-start;
+ e.entry.name = strdup(cummulativeString);
+ e.entry.flags = read_uleb128(p, end);
+ if ( e.entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+ e.entry.address = 0;
+ e.entry.other = read_uleb128(p, end); // dylib ordinal
+ e.entry.importName = (char*)p;
+ }
+ else {
+ e.entry.address = read_uleb128(p, end);
+ if ( e.entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
+ e.entry.other = read_uleb128(p, end);
+ else
+ e.entry.other = 0;
+ e.entry.importName = NULL;
+ }
+ output.push_back(e);
+ }
+ const uint8_t childrenCount = *children++;
+ const uint8_t* s = children;
+ for (uint8_t i=0; i < childrenCount; ++i) {
+ int edgeStrLen = 0;
+ while (*s != '\0') {
+ cummulativeString[curStrOffset+edgeStrLen] = *s++;
+ ++edgeStrLen;
+ }
+ cummulativeString[curStrOffset+edgeStrLen] = *s++;
+ uint32_t childNodeOffset = read_uleb128(s, end);
+ if (childNodeOffset == 0)
+ throw "malformed trie, childNodeOffset==0";
+ processExportNode(start, start+childNodeOffset, end, cummulativeString, curStrOffset+edgeStrLen, output);
+ }
+}
+
+
+inline void parseTrie(const uint8_t* start, const uint8_t* end, std::vector<Entry>& output)
+{
+ // empty trie has no entries
+ if ( start == end )
+ return;
+ // worst case largest exported symbol names is length of whole trie
+ char* cummulativeString = new char[end-start];
+ std::vector<EntryWithOffset> entries;
+ processExportNode(start, start, end, cummulativeString, 0, entries);
+ // to preserve tie layout order, sort by node offset
+ std::sort(entries.begin(), entries.end());
+ // copy to output
+ output.reserve(entries.size());
+ for (std::vector<EntryWithOffset>::iterator it=entries.begin(); it != entries.end(); ++it)
+ output.push_back(it->entry);
+ delete cummulativeString;
+}
+
+
+
+
+}; // namespace trie
+}; // namespace mach_o
+
+
+#endif // __MACH_O_TRIE__
+
+
--- /dev/null
+#!/bin/bash
+
+echo "" > ${DERIVED_FILE_DIR}/configure.h
+
+if [ -n "${IPHONEOS_DEPLOYMENT_TARGET}" ]; then
+ echo "#define DEFAULT_IPHONEOS_MIN_VERSION \"${IPHONEOS_DEPLOYMENT_TARGET}\"" >> ${DERIVED_FILE_DIR}/configure.h
+else
+ if [ -n "${MACOSX_DEPLOYMENT_TARGET}" ]; then
+ echo "#define DEFAULT_MACOSX_MIN_VERSION \"${MACOSX_DEPLOYMENT_TARGET}\"" >> ${DERIVED_FILE_DIR}/configure.h
+ fi
+fi
+
+if [ -z "${RC_SUPPORTED_ARCHS}" ]; then
+ RC_SUPPORTED_ARCHS="i386 x86_64"
+fi
+
+for ANARCH in ${RC_SUPPORTED_ARCHS}
+do
+ KNOWN_ARCHS=",armv4t,armv5,armv6,armv7,armv7f,armv7k,armv7s,i386,x86_64,"
+ FOUND=`echo "$KNOWN_ARCHS" | grep ",$ANARCH,"`
+ if [ $FOUND ]; then
+ echo "#define SUPPORT_ARCH_$ANARCH 1" >> ${DERIVED_FILE_DIR}/configure.h
+ else
+ echo "#error uknown architecture: $ANARCH" >> ${DERIVED_FILE_DIR}/configure.h
+ fi
+done
+
+echo "#define ALL_SUPPORTED_ARCHS \"${RC_SUPPORTED_ARCHS}\"" >> ${DERIVED_FILE_DIR}/configure.h
+
+
+# <rdar://problem/10897631> ld64 hardcodes a reference to /Developer/usr/lib/libLTO.dylib
+if [ -n "${DT_TOOLCHAIN_DIR}" ]
+then
+ echo "-Wl,-lazy_library,${DT_TOOLCHAIN_DIR}/usr/lib/libLTO.dylib" > ${DERIVED_SOURCES_DIR}/LTO_option.txt
+else
+ if [ -e "/Developer/usr/lib/libLTO.dylib" ]
+ then
+ echo "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib" > ${DERIVED_SOURCES_DIR}/LTO_option.txt
+ else
+ echo "-Wl,-lazy_library,${BUILT_PRODUCTS_DIR}/../lib/libLTO.dylib" > ${DERIVED_SOURCES_DIR}/LTO_option.txt
+ fi
+fi
+
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __ARCHITECTURES__
+#define __ARCHITECTURES__
+
+#include "FileAbstraction.hpp"
+
+
+//
+// Architectures
+//
+struct ppc
+{
+ typedef Pointer32<BigEndian> P;
+};
+
+struct ppc64
+{
+ typedef Pointer64<BigEndian> P;
+};
+
+struct x86
+{
+ typedef Pointer32<LittleEndian> P;
+};
+
+struct x86_64
+{
+ typedef Pointer64<LittleEndian> P;
+};
+
+struct arm
+{
+ typedef Pointer32<LittleEndian> P;
+};
+
+#endif // __ARCHITECTURES__
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __HEADER_LOAD_COMMANDS_HPP__
+#define __HEADER_LOAD_COMMANDS_HPP__
+
+#include <stdlib.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach-o/loader.h>
+
+#include <vector>
+
+#include "MachOFileAbstraction.hpp"
+#include "Options.h"
+#include "ld.hpp"
+
+namespace ld {
+namespace tool {
+
+class HeaderAndLoadCommandsAbtract : public ld::Atom
+{
+public:
+ HeaderAndLoadCommandsAbtract(const ld::Section& sect, ld::Atom::Definition d,
+ ld::Atom::Combine c, ld::Atom::Scope s, ld::Atom::ContentType ct,
+ ld::Atom::SymbolTableInclusion i, bool dds, bool thumb, bool al,
+ ld::Atom::Alignment a) : ld::Atom(sect, d, c, s, ct, i, dds, thumb, al, a) { }
+
+ virtual void setUUID(const uint8_t digest[16]) = 0;
+ virtual void recopyUUIDCommand() = 0;
+};
+
+template <typename A>
+class HeaderAndLoadCommandsAtom : public HeaderAndLoadCommandsAbtract
+{
+public:
+ HeaderAndLoadCommandsAtom(const Options& opts, ld::Internal& state,
+ OutputFile& writer);
+
+ // overrides of ld::Atom
+ virtual ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "mach-o header and load commands"; }
+ virtual uint64_t size() const;
+ virtual uint64_t objectAddress() const { return _address; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+
+ // overrides of HeaderAndLoadCommandsAbtract
+ virtual void setUUID(const uint8_t digest[16]) { memcpy(_uuid, digest, 16); }
+ virtual void recopyUUIDCommand();
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ unsigned int nonHiddenSectionCount() const;
+ unsigned int segmentCount() const;
+ static uint32_t alignedSize(uint32_t x);
+ uint32_t magic() const;
+ uint32_t cpuType() const;
+ uint32_t cpuSubType() const;
+ uint32_t flags() const;
+ uint32_t fileType() const;
+ uint32_t commandsCount() const;
+ uint32_t threadLoadCommandSize() const;
+ uint8_t* copySingleSegmentLoadCommand(uint8_t* p) const;
+ uint8_t* copySegmentLoadCommands(uint8_t* p) const;
+ uint8_t* copyDyldInfoLoadCommand(uint8_t* p) const;
+ uint8_t* copySymbolTableLoadCommand(uint8_t* p) const;
+ uint8_t* copyDynamicSymbolTableLoadCommand(uint8_t* p) const;
+ uint8_t* copyDyldLoadCommand(uint8_t* p) const;
+ uint8_t* copyDylibIDLoadCommand(uint8_t* p) const;
+ uint8_t* copyRoutinesLoadCommand(uint8_t* p) const;
+ uint8_t* copyUUIDLoadCommand(uint8_t* p) const;
+ uint8_t* copyVersionLoadCommand(uint8_t* p) const;
+ uint8_t* copySourceVersionLoadCommand(uint8_t* p) const;
+ uint8_t* copyThreadsLoadCommand(uint8_t* p) const;
+ uint8_t* copyEntryPointLoadCommand(uint8_t* p) const;
+ uint8_t* copyEncryptionLoadCommand(uint8_t* p) const;
+ uint8_t* copySplitSegInfoLoadCommand(uint8_t* p) const;
+ uint8_t* copyDylibLoadCommand(uint8_t* p, const ld::dylib::File*) const;
+ uint8_t* copyRPathLoadCommand(uint8_t* p, const char*) const;
+ uint8_t* copySubFrameworkLoadCommand(uint8_t* p) const;
+ uint8_t* copyAllowableClientLoadCommand(uint8_t* p, const char* client) const;
+ uint8_t* copySubLibraryLoadCommand(uint8_t* p, const char* name) const;
+ uint8_t* copySubUmbrellaLoadCommand(uint8_t* p, const char* name) const;
+ uint8_t* copyFunctionStartsLoadCommand(uint8_t* p) const;
+ uint8_t* copyDataInCodeLoadCommand(uint8_t* p) const;
+ uint8_t* copyDependentDRLoadCommand(uint8_t* p) const;
+ uint8_t* copyDyldEnvLoadCommand(uint8_t* p, const char* env) const;
+
+ uint32_t sectionFlags(ld::Internal::FinalSection* sect) const;
+ bool sectionTakesNoDiskSpace(ld::Internal::FinalSection* sect) const;
+
+
+ const Options& _options;
+ ld::Internal& _state;
+ OutputFile& _writer;
+ pint_t _address;
+ bool _hasDyldInfoLoadCommand;
+ bool _hasDyldLoadCommand;
+ bool _hasDylibIDLoadCommand;
+ bool _hasThreadLoadCommand;
+ bool _hasEntryPointLoadCommand;
+ bool _hasEncryptionLoadCommand;
+ bool _hasSplitSegInfoLoadCommand;
+ bool _hasRoutinesLoadCommand;
+ bool _hasUUIDLoadCommand;
+ bool _hasSymbolTableLoadCommand;
+ bool _hasDynamicSymbolTableLoadCommand;
+ bool _hasRPathLoadCommands;
+ bool _hasSubFrameworkLoadCommand;
+ bool _hasVersionLoadCommand;
+ bool _hasFunctionStartsLoadCommand;
+ bool _hasDataInCodeLoadCommand;
+ bool _hasSourceVersionLoadCommand;
+ bool _hasDependentDRInfo;
+ uint32_t _dylibLoadCommmandsCount;
+ uint32_t _allowableClientLoadCommmandsCount;
+ uint32_t _dyldEnvironExrasCount;
+ std::vector<const char*> _subLibraryNames;
+ std::vector<const char*> _subUmbrellaNames;
+ uint8_t _uuid[16];
+ mutable macho_uuid_command<P>* _uuidCmdInOutputBuffer;
+
+ static ld::Section _s_section;
+ static ld::Section _s_preload_section;
+};
+
+template <typename A>
+ld::Section HeaderAndLoadCommandsAtom<A>::_s_section("__TEXT", "__mach_header", ld::Section::typeMachHeader, true);
+template <typename A>
+ld::Section HeaderAndLoadCommandsAtom<A>::_s_preload_section("__HEADER", "__mach_header", ld::Section::typeMachHeader, true);
+
+
+template <typename A>
+HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : HeaderAndLoadCommandsAbtract((opts.outputKind() == Options::kPreload) ? _s_preload_section : _s_section,
+ ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
+ ld::Atom::symbolTableNotIn, false, false, false,
+ (opts.outputKind() == Options::kPreload) ? ld::Atom::Alignment(0) : ld::Atom::Alignment(12) ),
+ _options(opts), _state(state), _writer(writer), _address(0), _uuidCmdInOutputBuffer(NULL)
+{
+ bzero(_uuid, 16);
+ _hasDyldInfoLoadCommand = opts.makeCompressedDyldInfo();
+ _hasDyldLoadCommand = ((opts.outputKind() == Options::kDynamicExecutable) || (_options.outputKind() == Options::kDyld));
+ _hasDylibIDLoadCommand = (opts.outputKind() == Options::kDynamicLibrary);
+ _hasThreadLoadCommand = _options.needsThreadLoadCommand();
+ _hasEntryPointLoadCommand = _options.needsEntryPointLoadCommand();
+ _hasEncryptionLoadCommand = opts.makeEncryptable();
+ _hasSplitSegInfoLoadCommand = opts.sharedRegionEligible();
+ _hasRoutinesLoadCommand = (opts.initFunctionName() != NULL);
+ _hasSymbolTableLoadCommand = true;
+ _hasUUIDLoadCommand = (opts.UUIDMode() != Options::kUUIDNone);
+ switch ( opts.outputKind() ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kDyld:
+ case Options::kKextBundle:
+ _hasDynamicSymbolTableLoadCommand = true;
+ break;
+ case Options::kObjectFile:
+ if ( ! state.someObjectFileHasDwarf )
+ _hasUUIDLoadCommand = false;
+ _hasDynamicSymbolTableLoadCommand = false;
+ for (std::vector<ld::Internal::FinalSection*>::iterator it = _state.sections.begin(); it != _state.sections.end(); ++it) {
+ if ( (*it)->type() == ld::Section::typeNonLazyPointer ) {
+ _hasDynamicSymbolTableLoadCommand = true;
+ break;
+ }
+ }
+ break;
+ case Options::kStaticExecutable:
+ _hasDynamicSymbolTableLoadCommand = opts.positionIndependentExecutable();
+ break;
+ case Options::kPreload:
+ _hasDynamicSymbolTableLoadCommand = opts.positionIndependentExecutable();
+ break;
+ }
+ _hasRPathLoadCommands = (_options.rpaths().size() != 0);
+ _hasSubFrameworkLoadCommand = (_options.umbrellaName() != NULL);
+ _hasVersionLoadCommand = _options.addVersionLoadCommand();
+ _hasFunctionStartsLoadCommand = _options.addFunctionStarts();
+ _hasDataInCodeLoadCommand = _options.addDataInCodeInfo();
+ _hasSourceVersionLoadCommand = _options.needsSourceVersionLoadCommand();
+ _hasDependentDRInfo = _options.needsDependentDRInfo();
+ _dylibLoadCommmandsCount = _writer.dylibCount();
+ _allowableClientLoadCommmandsCount = _options.allowableClients().size();
+ _dyldEnvironExrasCount = _options.dyldEnvironExtras().size();
+ if ( ! _options.useSimplifiedDylibReExports() ) {
+ // target OS does not support LC_REEXPORT_DYLIB, so use old complicated load commands
+ for(uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) {
+ const ld::dylib::File* dylib = _writer.dylibByOrdinal(ord);
+ if ( dylib->willBeReExported() ) {
+ // if child says it is an sub-framework of the image being created, then nothing to do here
+ bool isSubFramework = false;
+ const char* childInUmbrella = dylib->parentUmbrella();
+ if ( childInUmbrella != NULL ) {
+ const char* myLeaf = strrchr(_options.installPath(), '/');
+ if ( myLeaf != NULL ) {
+ if ( strcmp(childInUmbrella, &myLeaf[1]) == 0 )
+ isSubFramework = true;
+ }
+ }
+ // LC_SUB_FRAMEWORK is in child, so do nothing in parent
+ if ( ! isSubFramework ) {
+ // this dylib also needs a sub_x load command
+ bool isFrameworkReExport = false;
+ const char* lastSlash = strrchr(dylib->installPath(), '/');
+ if ( lastSlash != NULL ) {
+ char frameworkName[strlen(lastSlash)+20];
+ sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
+ isFrameworkReExport = (strstr(dylib->installPath(), frameworkName) != NULL);
+ }
+ if ( isFrameworkReExport ) {
+ // needs a LC_SUB_UMBRELLA command
+ _subUmbrellaNames.push_back(&lastSlash[1]);
+ }
+ else {
+ // needs a LC_SUB_LIBRARY command
+ const char* nameStart = &lastSlash[1];
+ if ( lastSlash == NULL )
+ nameStart = dylib->installPath();
+ int len = strlen(nameStart);
+ const char* dot = strchr(nameStart, '.');
+ if ( dot != NULL )
+ len = dot - nameStart;
+ char* subLibName = new char[len+1];
+ strlcpy(subLibName, nameStart, len+1);
+ _subLibraryNames.push_back(subLibName);
+ }
+ }
+ }
+ }
+ }
+}
+
+template <typename A>
+uint32_t HeaderAndLoadCommandsAtom<A>::alignedSize(uint32_t size)
+{
+ if ( sizeof(pint_t) == 4 )
+ return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
+ else
+ return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
+}
+
+
+template <typename A>
+unsigned int HeaderAndLoadCommandsAtom<A>::nonHiddenSectionCount() const
+{
+ unsigned int count = 0;
+ for (std::vector<ld::Internal::FinalSection*>::iterator it = _state.sections.begin(); it != _state.sections.end(); ++it) {
+ if ( ! (*it)->isSectionHidden() && ((*it)->type() != ld::Section::typeTentativeDefs) )
+ ++count;
+ }
+ return count;
+}
+
+template <typename A>
+unsigned int HeaderAndLoadCommandsAtom<A>::segmentCount() const
+{
+ if ( _options.outputKind() == Options::kObjectFile ) {
+ // .o files have one anonymous segment that contains all sections
+ return 1;
+ }
+
+ unsigned int count = 0;
+ const char* lastSegName = "";
+ for (std::vector<ld::Internal::FinalSection*>::iterator it = _state.sections.begin(); it != _state.sections.end(); ++it) {
+ if ( _options.outputKind() == Options::kPreload ) {
+ if ( (*it)->type() == ld::Section::typeMachHeader )
+ continue; // for -preload, don't put hidden __HEADER segment into output
+ if ( (*it)->type() == ld::Section::typeLinkEdit )
+ continue; // for -preload, don't put hidden __LINKEDIT segment into output
+ }
+ if ( strcmp(lastSegName, (*it)->segmentName()) != 0 ) {
+ lastSegName = (*it)->segmentName();
+ ++count;
+ }
+ }
+ return count;
+}
+
+
+template <typename A>
+uint64_t HeaderAndLoadCommandsAtom<A>::size() const
+{
+ uint32_t sz = sizeof(macho_header<P>);
+
+ sz += sizeof(macho_segment_command<P>) * this->segmentCount();
+ sz += sizeof(macho_section<P>) * this->nonHiddenSectionCount();
+
+ if ( _hasDylibIDLoadCommand )
+ sz += alignedSize(sizeof(macho_dylib_command<P>) + strlen(_options.installPath()) + 1);
+
+ if ( _hasDyldInfoLoadCommand )
+ sz += sizeof(macho_dyld_info_command<P>);
+
+ if ( _hasSymbolTableLoadCommand )
+ sz += sizeof(macho_symtab_command<P>);
+
+ if ( _hasDynamicSymbolTableLoadCommand )
+ sz += sizeof(macho_dysymtab_command<P>);
+
+ if ( _hasDyldLoadCommand )
+ sz += alignedSize(sizeof(macho_dylinker_command<P>) + strlen(_options.dyldInstallPath()) + 1);
+
+ if ( _hasRoutinesLoadCommand )
+ sz += sizeof(macho_routines_command<P>);
+
+ if ( _hasUUIDLoadCommand )
+ sz += sizeof(macho_uuid_command<P>);
+
+ if ( _hasVersionLoadCommand )
+ sz += sizeof(macho_version_min_command<P>);
+
+ if ( _hasSourceVersionLoadCommand )
+ sz += sizeof(macho_source_version_command<P>);
+
+ if ( _hasThreadLoadCommand )
+ sz += this->threadLoadCommandSize();
+
+ if ( _hasEntryPointLoadCommand )
+ sz += sizeof(macho_entry_point_command<P>);
+
+ if ( _hasEncryptionLoadCommand )
+ sz += sizeof(macho_encryption_info_command<P>);
+
+ if ( _hasSplitSegInfoLoadCommand )
+ sz += sizeof(macho_linkedit_data_command<P>);
+
+ for(uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) {
+ sz += alignedSize(sizeof(macho_dylib_command<P>) + strlen(_writer.dylibByOrdinal(ord)->installPath()) + 1);
+ }
+
+ if ( _hasRPathLoadCommands ) {
+ const std::vector<const char*>& rpaths = _options.rpaths();
+ for (std::vector<const char*>::const_iterator it = rpaths.begin(); it != rpaths.end(); ++it) {
+ sz += alignedSize(sizeof(macho_rpath_command<P>) + strlen(*it) + 1);
+ }
+ }
+
+ if ( _hasSubFrameworkLoadCommand )
+ sz += alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(_options.umbrellaName()) + 1);
+
+ for (std::vector<const char*>::const_iterator it = _subLibraryNames.begin(); it != _subLibraryNames.end(); ++it) {
+ sz += alignedSize(sizeof(macho_sub_library_command<P>) + strlen(*it) + 1);
+ }
+
+ for (std::vector<const char*>::const_iterator it = _subUmbrellaNames.begin(); it != _subUmbrellaNames.end(); ++it) {
+ sz += alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(*it) + 1);
+ }
+
+ if ( _allowableClientLoadCommmandsCount != 0 ) {
+ const std::vector<const char*>& clients = _options.allowableClients();
+ for (std::vector<const char*>::const_iterator it = clients.begin(); it != clients.end(); ++it) {
+ sz += alignedSize(sizeof(macho_sub_client_command<P>) + strlen(*it) + 1);
+ }
+ }
+
+ if ( _dyldEnvironExrasCount != 0 ) {
+ const std::vector<const char*>& extras = _options.dyldEnvironExtras();
+ for (std::vector<const char*>::const_iterator it = extras.begin(); it != extras.end(); ++it) {
+ sz += alignedSize(sizeof(macho_dylinker_command<P>) + strlen(*it) + 1);
+ }
+ }
+
+ if ( _hasFunctionStartsLoadCommand )
+ sz += sizeof(macho_linkedit_data_command<P>);
+
+ if ( _hasDataInCodeLoadCommand )
+ sz += sizeof(macho_linkedit_data_command<P>);
+
+ if ( _hasDependentDRInfo )
+ sz += sizeof(macho_linkedit_data_command<P>);
+
+ return sz;
+}
+
+template <typename A>
+uint32_t HeaderAndLoadCommandsAtom<A>::commandsCount() const
+{
+ uint32_t count = this->segmentCount();
+
+ if ( _hasDylibIDLoadCommand )
+ ++count;
+
+ if ( _hasDyldInfoLoadCommand )
+ ++count;
+
+ if ( _hasSymbolTableLoadCommand )
+ ++count;
+
+ if ( _hasDynamicSymbolTableLoadCommand )
+ ++count;
+
+ if ( _hasDyldLoadCommand )
+ ++count;
+
+ if ( _hasRoutinesLoadCommand )
+ ++count;
+
+ if ( _hasUUIDLoadCommand )
+ ++count;
+
+ if ( _hasVersionLoadCommand )
+ ++count;
+
+ if ( _hasSourceVersionLoadCommand )
+ ++count;
+
+ if ( _hasThreadLoadCommand )
+ ++count;
+
+ if ( _hasEntryPointLoadCommand )
+ ++count;
+
+ if ( _hasEncryptionLoadCommand )
+ ++count;
+
+ if ( _hasSplitSegInfoLoadCommand )
+ ++count;
+
+ count += _dylibLoadCommmandsCount;
+
+ count += _options.rpaths().size();
+
+ if ( _hasSubFrameworkLoadCommand )
+ ++count;
+
+ count += _subLibraryNames.size();
+
+ count += _subUmbrellaNames.size();
+
+ count += _allowableClientLoadCommmandsCount;
+
+ count += _dyldEnvironExrasCount;
+
+ if ( _hasFunctionStartsLoadCommand )
+ ++count;
+
+ if ( _hasDataInCodeLoadCommand )
+ ++count;
+
+ if ( _hasDependentDRInfo )
+ ++count;
+
+ return count;
+}
+
+template <typename A>
+uint32_t HeaderAndLoadCommandsAtom<A>::fileType() const
+{
+ switch ( _options.outputKind() ) {
+ case Options::kDynamicExecutable:
+ case Options::kStaticExecutable:
+ return MH_EXECUTE;
+ case Options::kDynamicLibrary:
+ return MH_DYLIB;
+ case Options::kDynamicBundle:
+ return MH_BUNDLE;
+ case Options::kObjectFile:
+ return MH_OBJECT;
+ case Options::kDyld:
+ return MH_DYLINKER;
+ case Options::kPreload:
+ return MH_PRELOAD;
+ case Options::kKextBundle:
+ return MH_KEXT_BUNDLE;
+ }
+ throw "unknonwn mach-o file type";
+}
+
+template <typename A>
+uint32_t HeaderAndLoadCommandsAtom<A>::flags() const
+{
+ uint32_t bits = 0;
+ if ( _options.outputKind() == Options::kObjectFile ) {
+ if ( _state.allObjectFilesScatterable )
+ bits = MH_SUBSECTIONS_VIA_SYMBOLS;
+ }
+ else {
+ if ( _options.outputKind() == Options::kStaticExecutable ) {
+ bits |= MH_NOUNDEFS;
+ if ( _options.positionIndependentExecutable() )
+ bits |= MH_PIE;
+ }
+ else if ( _options.outputKind() == Options::kPreload ) {
+ bits |= MH_NOUNDEFS;
+ if ( _options.positionIndependentExecutable() )
+ bits |= MH_PIE;
+ }
+ else {
+ bits = MH_DYLDLINK;
+ switch ( _options.nameSpace() ) {
+ case Options::kTwoLevelNameSpace:
+ bits |= MH_TWOLEVEL | MH_NOUNDEFS;
+ break;
+ case Options::kFlatNameSpace:
+ break;
+ case Options::kForceFlatNameSpace:
+ bits |= MH_FORCE_FLAT;
+ break;
+ }
+ if ( _writer.hasWeakExternalSymbols || _writer.overridesWeakExternalSymbols )
+ bits |= MH_WEAK_DEFINES;
+ if ( _writer.usesWeakExternalSymbols || _writer.hasWeakExternalSymbols )
+ bits |= MH_BINDS_TO_WEAK;
+ if ( _options.prebind() )
+ bits |= MH_PREBOUND;
+ if ( _options.splitSeg() )
+ bits |= MH_SPLIT_SEGS;
+ if ( (_options.outputKind() == Options::kDynamicLibrary)
+ && _writer._noReExportedDylibs
+ && _options.useSimplifiedDylibReExports() ) {
+ bits |= MH_NO_REEXPORTED_DYLIBS;
+ }
+ if ( _options.positionIndependentExecutable() && ! _writer.pieDisabled )
+ bits |= MH_PIE;
+ if ( _options.markAutoDeadStripDylib() )
+ bits |= MH_DEAD_STRIPPABLE_DYLIB;
+ if ( _writer.hasThreadLocalVariableDefinitions )
+ bits |= MH_HAS_TLV_DESCRIPTORS;
+ if ( _options.hasNonExecutableHeap() )
+ bits |= MH_NO_HEAP_EXECUTION;
+ }
+ if ( _options.hasExecutableStack() )
+ bits |= MH_ALLOW_STACK_EXECUTION;
+ }
+ return bits;
+}
+
+template <> uint32_t HeaderAndLoadCommandsAtom<x86>::magic() const { return MH_MAGIC; }
+template <> uint32_t HeaderAndLoadCommandsAtom<x86_64>::magic() const { return MH_MAGIC_64; }
+template <> uint32_t HeaderAndLoadCommandsAtom<arm>::magic() const { return MH_MAGIC; }
+
+template <> uint32_t HeaderAndLoadCommandsAtom<x86>::cpuType() const { return CPU_TYPE_I386; }
+template <> uint32_t HeaderAndLoadCommandsAtom<x86_64>::cpuType() const { return CPU_TYPE_X86_64; }
+template <> uint32_t HeaderAndLoadCommandsAtom<arm>::cpuType() const { return CPU_TYPE_ARM; }
+
+
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<x86>::cpuSubType() const
+{
+ return CPU_SUBTYPE_I386_ALL;
+}
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<x86_64>::cpuSubType() const
+{
+ if ( (_options.outputKind() == Options::kDynamicExecutable) && (_options.macosxVersionMin() >= ld::mac10_5) )
+ return (CPU_SUBTYPE_X86_64_ALL | 0x80000000);
+ else
+ return CPU_SUBTYPE_X86_64_ALL;
+}
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<arm>::cpuSubType() const
+{
+ return _state.cpuSubType;
+}
+
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySingleSegmentLoadCommand(uint8_t* p) const
+{
+ // in .o files there is just one segment load command with a blank name
+ // and all sections under it
+ macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
+ cmd->set_cmd(macho_segment_command<P>::CMD);
+ cmd->set_segname("");
+ cmd->set_vmaddr(_options.baseAddress());
+ cmd->set_vmsize(0); // updated after sections set
+ cmd->set_fileoff(0); // updated after sections set
+ cmd->set_filesize(0); // updated after sections set
+ cmd->set_maxprot(VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
+ cmd->set_initprot(VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
+ cmd->set_nsects(this->nonHiddenSectionCount());
+ cmd->set_flags(0);
+ // add sections array
+ macho_section<P>* msect = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = _state.sections.begin(); sit != _state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* fsect = *sit;
+ if ( fsect->isSectionHidden() )
+ continue;
+ if ( fsect->type() == ld::Section::typeTentativeDefs )
+ continue;
+ msect->set_sectname(fsect->sectionName());
+ msect->set_segname(fsect->segmentName());
+ msect->set_addr(fsect->address);
+ msect->set_size(fsect->size);
+ msect->set_offset(fsect->fileOffset);
+ msect->set_align(fsect->alignment);
+ msect->set_reloff((fsect->relocCount == 0) ? 0 : _writer.sectionRelocationsSection->fileOffset + fsect->relocStart * sizeof(macho_relocation_info<P>));
+ msect->set_nreloc(fsect->relocCount);
+ msect->set_flags(sectionFlags(fsect));
+ msect->set_reserved1(fsect->indirectSymTabStartIndex);
+ msect->set_reserved2(fsect->indirectSymTabElementSize);
+ // update segment info
+ if ( cmd->fileoff() == 0 )
+ cmd->set_fileoff(fsect->fileOffset);
+ cmd->set_vmsize(fsect->address + fsect->size - cmd->vmaddr());
+ if ( (fsect->type() != ld::Section::typeZeroFill) && (fsect->type() != ld::Section::typeTentativeDefs) )
+ cmd->set_filesize(fsect->fileOffset + fsect->size - cmd->fileoff());
+ ++msect;
+ }
+ cmd->set_cmdsize(sizeof(macho_segment_command<P>) + cmd->nsects()*sizeof(macho_section<P>));
+ return p + cmd->cmdsize();
+}
+
+struct SegInfo {
+ SegInfo(const char* n, const Options&);
+ const char* segName;
+ uint32_t nonHiddenSectionCount;
+ uint32_t maxProt;
+ uint32_t initProt;
+ std::vector<ld::Internal::FinalSection*> sections;
+};
+
+
+SegInfo::SegInfo(const char* n, const Options& opts)
+ : segName(n), nonHiddenSectionCount(0), maxProt(opts.maxSegProtection(n)), initProt(opts.initialSegProtection(n))
+{
+}
+
+
+template <typename A>
+uint32_t HeaderAndLoadCommandsAtom<A>::sectionFlags(ld::Internal::FinalSection* sect) const
+{
+ uint32_t bits;
+ switch ( sect->type() ) {
+ case ld::Section::typeUnclassified:
+ if ( strcmp(sect->segmentName(), "__OBJC") == 0 )
+ return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+ else if ( (strcmp(sect->sectionName(), "__objc_classlist") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+ return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+ else if ( (strcmp(sect->sectionName(), "__objc_catlist") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+ return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+ else if ( (strncmp(sect->sectionName(), "__objc_superrefs", 16) == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+ return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+ else if ( (strncmp(sect->sectionName(), "__objc_nlclslist", 16) == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+ return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+ else if ( (strncmp(sect->sectionName(), "__objc_nlcatlist", 16) == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+ return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+ else
+ return S_REGULAR;
+ case ld::Section::typeCode:
+ bits = S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS;
+ if ( sect->hasLocalRelocs && ! _writer.pieDisabled )
+ bits |= S_ATTR_LOC_RELOC;
+ if ( sect->hasExternalRelocs )
+ bits |= S_ATTR_EXT_RELOC;
+ return bits;
+ case ld::Section::typePageZero:
+ return S_REGULAR;
+ case ld::Section::typeImportProxies:
+ return S_REGULAR;
+ case ld::Section::typeLinkEdit:
+ return S_REGULAR;
+ case ld::Section::typeMachHeader:
+ return S_REGULAR;
+ case ld::Section::typeStack:
+ return S_REGULAR;
+ case ld::Section::typeLiteral4:
+ return S_4BYTE_LITERALS;
+ case ld::Section::typeLiteral8:
+ return S_8BYTE_LITERALS;
+ case ld::Section::typeLiteral16:
+ return S_16BYTE_LITERALS;
+ case ld::Section::typeConstants:
+ return S_REGULAR;
+ case ld::Section::typeTempLTO:
+ assert(0 && "typeTempLTO should not make it to final linked image");
+ return S_REGULAR;
+ case ld::Section::typeAbsoluteSymbols:
+ assert(0 && "typeAbsoluteSymbols should not make it to final linked image");
+ return S_REGULAR;
+ case ld::Section::typeCString:
+ case ld::Section::typeNonStdCString:
+ return S_CSTRING_LITERALS;
+ case ld::Section::typeCStringPointer:
+ return S_LITERAL_POINTERS | S_ATTR_NO_DEAD_STRIP;
+ case ld::Section::typeUTF16Strings:
+ return S_REGULAR;
+ case ld::Section::typeCFString:
+ return S_REGULAR;
+ case ld::Section::typeObjC1Classes:
+ return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+ case ld::Section::typeCFI:
+ return S_REGULAR;
+ case ld::Section::typeLSDA:
+ return S_REGULAR;
+ case ld::Section::typeDtraceDOF:
+ return S_DTRACE_DOF;
+ case ld::Section::typeUnwindInfo:
+ return S_REGULAR;
+ case ld::Section::typeObjCClassRefs:
+ case ld::Section::typeObjC2CategoryList:
+ return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+ case ld::Section::typeZeroFill:
+ if ( _options.optimizeZeroFill() )
+ return S_ZEROFILL;
+ else
+ return S_REGULAR;
+ case ld::Section::typeTentativeDefs:
+ assert(0 && "typeTentativeDefs should not make it to final linked image");
+ return S_REGULAR;
+ case ld::Section::typeLazyPointer:
+ case ld::Section::typeLazyPointerClose:
+ return S_LAZY_SYMBOL_POINTERS;
+ case ld::Section::typeStubClose:
+ case ld::Section::typeStub:
+ if ( sect->hasLocalRelocs )
+ return S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_LOC_RELOC;
+ else
+ return S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS;
+ case ld::Section::typeNonLazyPointer:
+ if ( _options.outputKind() == Options::kKextBundle )
+ return S_REGULAR;
+ else if ( (_options.outputKind() == Options::kStaticExecutable) && _options.positionIndependentExecutable() )
+ return S_REGULAR;
+ else
+ return S_NON_LAZY_SYMBOL_POINTERS;
+ case ld::Section::typeDyldInfo:
+ return S_REGULAR;
+ case ld::Section::typeLazyDylibPointer:
+ return S_LAZY_DYLIB_SYMBOL_POINTERS;
+ case ld::Section::typeStubHelper:
+ if ( sect->hasLocalRelocs )
+ return S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_LOC_RELOC;
+ else
+ return S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS;
+ case ld::Section::typeInitializerPointers:
+ // <rdar://problem/11456679> i386 kexts need different section type
+ if ( (_options.outputKind() == Options::kObjectFile)
+ && (strcmp(sect->sectionName(), "__constructor") == 0)
+ && (strcmp(sect->segmentName(), "__TEXT") == 0) )
+ return S_REGULAR;
+ else
+ return S_MOD_INIT_FUNC_POINTERS;
+ case ld::Section::typeTerminatorPointers:
+ return S_MOD_TERM_FUNC_POINTERS;
+ case ld::Section::typeTLVInitialValues:
+ return S_THREAD_LOCAL_REGULAR;
+ case ld::Section::typeTLVZeroFill:
+ return S_THREAD_LOCAL_ZEROFILL;
+ case ld::Section::typeTLVDefs:
+ return S_THREAD_LOCAL_VARIABLES;
+ case ld::Section::typeTLVInitializerPointers:
+ return S_THREAD_LOCAL_INIT_FUNCTION_POINTERS;
+ case ld::Section::typeTLVPointers:
+ return S_THREAD_LOCAL_VARIABLE_POINTERS;
+ case ld::Section::typeFirstSection:
+ assert(0 && "typeFirstSection should not make it to final linked image");
+ return S_REGULAR;
+ case ld::Section::typeLastSection:
+ assert(0 && "typeLastSection should not make it to final linked image");
+ return S_REGULAR;
+ case ld::Section::typeDebug:
+ return S_REGULAR | S_ATTR_DEBUG;
+ }
+ return S_REGULAR;
+}
+
+
+template <typename A>
+bool HeaderAndLoadCommandsAtom<A>::sectionTakesNoDiskSpace(ld::Internal::FinalSection* sect) const
+{
+ switch ( sect->type() ) {
+ case ld::Section::typeZeroFill:
+ case ld::Section::typeTLVZeroFill:
+ return _options.optimizeZeroFill();
+ case ld::Section::typeAbsoluteSymbols:
+ case ld::Section::typeTentativeDefs:
+ case ld::Section::typeLastSection:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySegmentLoadCommands(uint8_t* p) const
+{
+ // group sections into segments
+ std::vector<SegInfo> segs;
+ const char* lastSegName = "";
+ for (std::vector<ld::Internal::FinalSection*>::iterator it = _state.sections.begin(); it != _state.sections.end(); ++it) {
+ ld::Internal::FinalSection* sect = *it;
+ if ( _options.outputKind() == Options::kPreload ) {
+ if ( (*it)->type() == ld::Section::typeMachHeader )
+ continue; // for -preload, don't put hidden __HEADER segment into output
+ if ( (*it)->type() == ld::Section::typeLinkEdit )
+ continue; // for -preload, don't put hidden __LINKEDIT segment into output
+ }
+ if ( strcmp(lastSegName, sect->segmentName()) != 0 ) {
+ SegInfo si(sect->segmentName(), _options);
+ segs.push_back(si);
+ lastSegName = sect->segmentName();
+ }
+ if ( ! sect->isSectionHidden() )
+ segs.back().nonHiddenSectionCount++;
+ segs.back().sections.push_back(sect);
+ }
+ // write out segment load commands for each section with trailing sections
+ for (std::vector<SegInfo>::iterator it = segs.begin(); it != segs.end(); ++it) {
+ SegInfo& si = *it;
+ ld::Internal::FinalSection* lastNonZeroFillSection = NULL;
+ for (int i=si.sections.size()-1; i >= 0; --i) {
+ if ( !sectionTakesNoDiskSpace(si.sections[i]) ) {
+ lastNonZeroFillSection = si.sections[i];
+ break;
+ }
+ }
+ uint64_t vmsize = si.sections.back()->address + si.sections.back()->size - si.sections.front()->address;
+ vmsize = ((vmsize+_options.segmentAlignment()-1) & (-_options.segmentAlignment()));
+ uint64_t filesize = 0;
+ if ( lastNonZeroFillSection != NULL ) {
+ filesize = lastNonZeroFillSection->address + lastNonZeroFillSection->size - si.sections.front()->address;
+ // round up all segments to page aligned, except __LINKEDIT
+ if ( (si.sections[0]->type() != ld::Section::typeLinkEdit) && (si.sections[0]->type() != ld::Section::typeImportProxies) )
+ filesize = (filesize + _options.segmentAlignment()-1) & (-_options.segmentAlignment());
+ }
+ if ( si.sections.front()->type() == ld::Section::typePageZero )
+ filesize = 0;
+ else if ( si.sections.front()->type() == ld::Section::typeStack )
+ filesize = 0;
+ macho_segment_command<P>* segCmd = (macho_segment_command<P>*)p;
+ segCmd->set_cmd(macho_segment_command<P>::CMD);
+ segCmd->set_cmdsize(sizeof(macho_segment_command<P>) + si.nonHiddenSectionCount*sizeof(macho_section<P>));
+ segCmd->set_segname(si.sections.front()->segmentName());
+ segCmd->set_vmaddr(si.sections.front()->address);
+ segCmd->set_vmsize(vmsize);
+ segCmd->set_fileoff(si.sections.front()->fileOffset);
+ segCmd->set_filesize(filesize);
+ segCmd->set_maxprot(si.maxProt);
+ segCmd->set_initprot(si.initProt);
+ segCmd->set_nsects(si.nonHiddenSectionCount);
+ segCmd->set_flags(0);
+ p += sizeof(macho_segment_command<P>);
+ macho_section<P>* msect = (macho_section<P>*)p;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = si.sections.begin(); sit != si.sections.end(); ++sit) {
+ ld::Internal::FinalSection* fsect = *sit;
+ if ( ! fsect->isSectionHidden() ) {
+ msect->set_sectname(fsect->sectionName());
+ msect->set_segname(fsect->segmentName());
+ msect->set_addr(fsect->address);
+ msect->set_size(fsect->size);
+ msect->set_offset(sectionTakesNoDiskSpace(fsect) ? 0 : fsect->fileOffset);
+ msect->set_align(fsect->alignment);
+ msect->set_reloff(0);
+ msect->set_nreloc(0);
+ msect->set_flags(sectionFlags(fsect));
+ msect->set_reserved1(fsect->indirectSymTabStartIndex);
+ msect->set_reserved2(fsect->indirectSymTabElementSize);
+ p += sizeof(macho_section<P>);
+ ++msect;
+ }
+ }
+ }
+
+ return p;
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySymbolTableLoadCommand(uint8_t* p) const
+{
+ // build LC_SYMTAB command
+ macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)p;
+ symbolTableCmd->set_cmd(LC_SYMTAB);
+ symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
+ symbolTableCmd->set_nsyms(_writer.symbolTableSection->size/sizeof(macho_nlist<P>));
+ symbolTableCmd->set_symoff(_writer.symbolTableSection->size == 0 ? 0 : _writer.symbolTableSection->fileOffset);
+ symbolTableCmd->set_stroff(_writer.stringPoolSection->size == 0 ? 0 : _writer.stringPoolSection->fileOffset );
+ symbolTableCmd->set_strsize(_writer.stringPoolSection->size);
+ return p + sizeof(macho_symtab_command<P>);
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDynamicSymbolTableLoadCommand(uint8_t* p) const
+{
+ // build LC_SYMTAB command
+ macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)p;
+ dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
+ dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
+ dynamicSymbolTableCmd->set_ilocalsym(0);
+ dynamicSymbolTableCmd->set_nlocalsym(_writer._localSymbolsCount);
+ dynamicSymbolTableCmd->set_iextdefsym(dynamicSymbolTableCmd->ilocalsym()+dynamicSymbolTableCmd->nlocalsym());
+ dynamicSymbolTableCmd->set_nextdefsym(_writer._globalSymbolsCount);
+ dynamicSymbolTableCmd->set_iundefsym(dynamicSymbolTableCmd->iextdefsym()+dynamicSymbolTableCmd->nextdefsym());
+ dynamicSymbolTableCmd->set_nundefsym(_writer._importSymbolsCount);
+
+ // FIX ME: support for 10.3 dylibs which need modules
+ //if ( fWriter.fModuleInfoAtom != NULL ) {
+ // dynamicSymbolTableCmd->set_tocoff(fWriter.fModuleInfoAtom->getTableOfContentsFileOffset());
+ // dynamicSymbolTableCmd->set_ntoc(fWriter.fSymbolTableExportCount);
+ // dynamicSymbolTableCmd->set_modtaboff(fWriter.fModuleInfoAtom->getModuleTableFileOffset());
+ // dynamicSymbolTableCmd->set_nmodtab(1);
+ // dynamicSymbolTableCmd->set_extrefsymoff(fWriter.fModuleInfoAtom->getReferencesFileOffset());
+ // dynamicSymbolTableCmd->set_nextrefsyms(fWriter.fModuleInfoAtom->getReferencesCount());
+ //}
+
+ bool hasIndirectSymbols = ( (_writer.indirectSymbolTableSection != NULL) && (_writer.indirectSymbolTableSection->size != 0) );
+ dynamicSymbolTableCmd->set_indirectsymoff(hasIndirectSymbols ? _writer.indirectSymbolTableSection->fileOffset : 0);
+ dynamicSymbolTableCmd->set_nindirectsyms( hasIndirectSymbols ? _writer.indirectSymbolTableSection->size/sizeof(uint32_t) : 0);
+
+ // FIX ME: support for classic relocations
+ if ( _options.outputKind() != Options::kObjectFile ) {
+ bool hasExternalRelocs = ( (_writer.externalRelocationsSection != NULL) && (_writer.externalRelocationsSection->size != 0) );
+ dynamicSymbolTableCmd->set_extreloff(hasExternalRelocs ? _writer.externalRelocationsSection->fileOffset : 0);
+ dynamicSymbolTableCmd->set_nextrel( hasExternalRelocs ? _writer.externalRelocationsSection->size/8 : 0);
+ bool hasLocalRelocs = ( (_writer.localRelocationsSection != NULL) && (_writer.localRelocationsSection->size != 0) );
+ dynamicSymbolTableCmd->set_locreloff(hasLocalRelocs ? _writer.localRelocationsSection->fileOffset : 0);
+ dynamicSymbolTableCmd->set_nlocrel (hasLocalRelocs ? _writer.localRelocationsSection->size/8 : 0);
+ }
+ return p + sizeof(macho_dysymtab_command<P>);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDyldInfoLoadCommand(uint8_t* p) const
+{
+ // build LC_DYLD_INFO command
+ macho_dyld_info_command<P>* cmd = (macho_dyld_info_command<P>*)p;
+
+ cmd->set_cmd(LC_DYLD_INFO_ONLY);
+ cmd->set_cmdsize(sizeof(macho_dyld_info_command<P>));
+ if ( _writer.rebaseSection->size != 0 ) {
+ cmd->set_rebase_off(_writer.rebaseSection->fileOffset);
+ cmd->set_rebase_size(_writer.rebaseSection->size);
+ }
+ if ( _writer.bindingSection->size != 0 ) {
+ cmd->set_bind_off(_writer.bindingSection->fileOffset);
+ cmd->set_bind_size(_writer.bindingSection->size);
+ }
+ if ( _writer.weakBindingSection->size != 0 ) {
+ cmd->set_weak_bind_off(_writer.weakBindingSection->fileOffset);
+ cmd->set_weak_bind_size(_writer.weakBindingSection->size);
+ }
+ if ( _writer.lazyBindingSection->size != 0 ) {
+ cmd->set_lazy_bind_off(_writer.lazyBindingSection->fileOffset);
+ cmd->set_lazy_bind_size(_writer.lazyBindingSection->size);
+ }
+ if ( _writer.exportSection->size != 0 ) {
+ cmd->set_export_off(_writer.exportSection->fileOffset);
+ cmd->set_export_size(_writer.exportSection->size);
+ }
+ return p + sizeof(macho_dyld_info_command<P>);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDyldLoadCommand(uint8_t* p) const
+{
+ uint32_t sz = alignedSize(sizeof(macho_dylinker_command<P>) + strlen(_options.dyldInstallPath()) + 1);
+ macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)p;
+ if ( _options.outputKind() == Options::kDyld )
+ cmd->set_cmd(LC_ID_DYLINKER);
+ else
+ cmd->set_cmd(LC_LOAD_DYLINKER);
+ cmd->set_cmdsize(sz);
+ cmd->set_name_offset();
+ strcpy((char*)&p[sizeof(macho_dylinker_command<P>)], _options.dyldInstallPath());
+ return p + sz;
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDylibIDLoadCommand(uint8_t* p) const
+{
+ uint32_t sz = alignedSize(sizeof(macho_dylib_command<P>) + strlen(_options.installPath()) + 1);
+ macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)p;
+ cmd->set_cmd(LC_ID_DYLIB);
+ cmd->set_cmdsize(sz);
+ cmd->set_name_offset();
+ cmd->set_timestamp(1); // needs to be some constant value that is different than DylibLoadCommandsAtom uses
+ cmd->set_current_version(_options.currentVersion32());
+ cmd->set_compatibility_version(_options.compatibilityVersion());
+ strcpy((char*)&p[sizeof(macho_dylib_command<P>)], _options.installPath());
+ return p + sz;
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyRoutinesLoadCommand(uint8_t* p) const
+{
+ pint_t initAddr = _state.entryPoint->finalAddress();
+ if ( _state.entryPoint->isThumb() )
+ initAddr |= 1ULL;
+ macho_routines_command<P>* cmd = (macho_routines_command<P>*)p;
+ cmd->set_cmd(macho_routines_command<P>::CMD);
+ cmd->set_cmdsize(sizeof(macho_routines_command<P>));
+ cmd->set_init_address(initAddr);
+ return p + sizeof(macho_routines_command<P>);
+}
+
+
+template <typename A>
+void HeaderAndLoadCommandsAtom<A>::recopyUUIDCommand()
+{
+ assert(_uuidCmdInOutputBuffer != NULL);
+ _uuidCmdInOutputBuffer->set_uuid(_uuid);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyUUIDLoadCommand(uint8_t* p) const
+{
+ macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)p;
+ cmd->set_cmd(LC_UUID);
+ cmd->set_cmdsize(sizeof(macho_uuid_command<P>));
+ cmd->set_uuid(_uuid);
+ _uuidCmdInOutputBuffer = cmd; // save for later re-write by recopyUUIDCommand()
+ return p + sizeof(macho_uuid_command<P>);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyVersionLoadCommand(uint8_t* p) const
+{
+ macho_version_min_command<P>* cmd = (macho_version_min_command<P>*)p;
+ ld::MacVersionMin macVersion = _options.macosxVersionMin();
+ ld::IOSVersionMin iOSVersion = _options.iOSVersionMin();
+ assert( (macVersion != ld::macVersionUnset) || (iOSVersion != ld::iOSVersionUnset) );
+ if ( macVersion != ld::macVersionUnset ) {
+ cmd->set_cmd(LC_VERSION_MIN_MACOSX);
+ cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
+ cmd->set_version((uint32_t)macVersion);
+ cmd->set_sdk(_options.sdkVersion());
+ }
+ else {
+ cmd->set_cmd(LC_VERSION_MIN_IPHONEOS);
+ cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
+ cmd->set_version((uint32_t)iOSVersion);
+ cmd->set_sdk(_options.sdkVersion());
+ }
+ return p + sizeof(macho_version_min_command<P>);
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySourceVersionLoadCommand(uint8_t* p) const
+{
+ macho_source_version_command<P>* cmd = (macho_source_version_command<P>*)p;
+ cmd->set_cmd(LC_SOURCE_VERSION);
+ cmd->set_cmdsize(sizeof(macho_source_version_command<P>));
+ cmd->set_version(_options.sourceVersion());
+ return p + sizeof(macho_source_version_command<P>);
+}
+
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<x86>::threadLoadCommandSize() const
+{
+ return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
+}
+
+template <>
+uint8_t* HeaderAndLoadCommandsAtom<x86>::copyThreadsLoadCommand(uint8_t* p) const
+{
+ assert(_state.entryPoint != NULL);
+ pint_t start = _state.entryPoint->finalAddress();
+ macho_thread_command<P>* cmd = (macho_thread_command<P>*)p;
+ cmd->set_cmd(LC_UNIXTHREAD);
+ cmd->set_cmdsize(threadLoadCommandSize());
+ cmd->set_flavor(1); // i386_THREAD_STATE
+ cmd->set_count(16); // i386_THREAD_STATE_COUNT;
+ cmd->set_thread_register(10, start);
+ if ( _options.hasCustomStack() )
+ cmd->set_thread_register(7, _options.customStackAddr()); // r1
+ return p + threadLoadCommandSize();
+}
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<x86_64>::threadLoadCommandSize() const
+{
+ return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4);
+}
+
+template <>
+uint8_t* HeaderAndLoadCommandsAtom<x86_64>::copyThreadsLoadCommand(uint8_t* p) const
+{
+ assert(_state.entryPoint != NULL);
+ pint_t start = _state.entryPoint->finalAddress();
+ macho_thread_command<P>* cmd = (macho_thread_command<P>*)p;
+ cmd->set_cmd(LC_UNIXTHREAD);
+ cmd->set_cmdsize(threadLoadCommandSize());
+ cmd->set_flavor(x86_THREAD_STATE64);
+ cmd->set_count(x86_THREAD_STATE64_COUNT);
+ cmd->set_thread_register(16, start); // rip
+ if ( _options.hasCustomStack() )
+ cmd->set_thread_register(7, _options.customStackAddr()); // r1
+ return p + threadLoadCommandSize();
+}
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<arm>::threadLoadCommandSize() const
+{
+ return this->alignedSize(16 + 17 * 4); // base size + ARM_THREAD_STATE_COUNT * 4
+}
+
+template <>
+uint8_t* HeaderAndLoadCommandsAtom<arm>::copyThreadsLoadCommand(uint8_t* p) const
+{
+ assert(_state.entryPoint != NULL);
+ pint_t start = _state.entryPoint->finalAddress();
+ if ( _state.entryPoint->isThumb() )
+ start |= 1ULL;
+ macho_thread_command<P>* cmd = (macho_thread_command<P>*)p;
+ cmd->set_cmd(LC_UNIXTHREAD);
+ cmd->set_cmdsize(threadLoadCommandSize());
+ cmd->set_flavor(1);
+ cmd->set_count(17);
+ cmd->set_thread_register(15, start); // pc
+ if ( _options.hasCustomStack() )
+ cmd->set_thread_register(13, _options.customStackAddr()); // sp
+ return p + threadLoadCommandSize();
+}
+
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyEntryPointLoadCommand(uint8_t* p) const
+{
+ macho_entry_point_command<P>* cmd = (macho_entry_point_command<P>*)p;
+ cmd->set_cmd(LC_MAIN);
+ cmd->set_cmdsize(sizeof(macho_entry_point_command<P>));
+ assert(_state.entryPoint != NULL);
+ pint_t start = _state.entryPoint->finalAddress();
+ if ( _state.entryPoint->isThumb() )
+ start |= 1ULL;
+ cmd->set_entryoff(start - this->finalAddress());
+ cmd->set_stacksize(_options.hasCustomStack() ? _options.customStackSize() : 0 );
+ return p + sizeof(macho_entry_point_command<P>);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyEncryptionLoadCommand(uint8_t* p) const
+{
+ macho_encryption_info_command<P>* cmd = (macho_encryption_info_command<P>*)p;
+ cmd->set_cmd(LC_ENCRYPTION_INFO);
+ cmd->set_cmdsize(sizeof(macho_encryption_info_command<P>));
+ assert(_writer.encryptedTextStartOffset() != 0);
+ assert(_writer.encryptedTextEndOffset() != 0);
+ cmd->set_cryptoff(_writer.encryptedTextStartOffset());
+ cmd->set_cryptsize(_writer.encryptedTextEndOffset()-_writer.encryptedTextStartOffset());
+ cmd->set_cryptid(0);
+ return p + sizeof(macho_encryption_info_command<P>);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySplitSegInfoLoadCommand(uint8_t* p) const
+{
+ macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)p;
+ cmd->set_cmd(LC_SEGMENT_SPLIT_INFO);
+ cmd->set_cmdsize(sizeof(macho_linkedit_data_command<P>));
+ cmd->set_dataoff(_writer.splitSegInfoSection->fileOffset);
+ cmd->set_datasize(_writer.splitSegInfoSection->size);
+ return p + sizeof(macho_linkedit_data_command<P>);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDylibLoadCommand(uint8_t* p, const ld::dylib::File* dylib) const
+{
+ uint32_t sz = alignedSize(sizeof(macho_dylib_command<P>) + strlen(dylib->installPath()) + 1);
+ macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)p;
+ if ( dylib->willBeLazyLoadedDylib() )
+ cmd->set_cmd(LC_LAZY_LOAD_DYLIB);
+ else if ( dylib->forcedWeakLinked() || dylib->allSymbolsAreWeakImported() )
+ cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
+ else if ( dylib->willBeReExported() && _options.useSimplifiedDylibReExports() )
+ cmd->set_cmd(LC_REEXPORT_DYLIB);
+ else if ( dylib->willBeUpwardDylib() && _options.useUpwardDylibs() )
+ cmd->set_cmd(LC_LOAD_UPWARD_DYLIB);
+ else
+ cmd->set_cmd(LC_LOAD_DYLIB);
+ cmd->set_cmdsize(sz);
+ cmd->set_timestamp(2); // needs to be some constant value that is different than DylibIDLoadCommandsAtom uses
+ cmd->set_current_version(dylib->currentVersion());
+ cmd->set_compatibility_version(dylib->compatibilityVersion());
+ cmd->set_name_offset();
+ strcpy((char*)&p[sizeof(macho_dylib_command<P>)], dylib->installPath());
+ return p + sz;
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyRPathLoadCommand(uint8_t* p, const char* path) const
+{
+ uint32_t sz = alignedSize(sizeof(macho_rpath_command<P>) + strlen(path) + 1);
+ macho_rpath_command<P>* cmd = (macho_rpath_command<P>*)p;
+ cmd->set_cmd(LC_RPATH);
+ cmd->set_cmdsize(sz);
+ cmd->set_path_offset();
+ strcpy((char*)&p[sizeof(macho_rpath_command<P>)], path);
+ return p + sz;
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySubFrameworkLoadCommand(uint8_t* p) const
+{
+ const char* umbrellaName = _options.umbrellaName();
+ uint32_t sz = alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(umbrellaName) + 1);
+ macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)p;
+ cmd->set_cmd(LC_SUB_FRAMEWORK);
+ cmd->set_cmdsize(sz);
+ cmd->set_umbrella_offset();
+ strcpy((char*)&p[sizeof(macho_sub_framework_command<P>)], umbrellaName);
+ return p + sz;
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyAllowableClientLoadCommand(uint8_t* p, const char* client) const
+{
+ uint32_t sz = alignedSize(sizeof(macho_sub_client_command<P>) + strlen(client) + 1);
+ macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)p;
+ cmd->set_cmd(LC_SUB_CLIENT);
+ cmd->set_cmdsize(sz);
+ cmd->set_client_offset();
+ strcpy((char*)&p[sizeof(macho_sub_client_command<P>)], client);
+ return p + sz;
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDyldEnvLoadCommand(uint8_t* p, const char* env) const
+{
+ uint32_t sz = alignedSize(sizeof(macho_dylinker_command<P>) + strlen(env) + 1);
+ macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)p;
+ cmd->set_cmd(LC_DYLD_ENVIRONMENT);
+ cmd->set_cmdsize(sz);
+ cmd->set_name_offset();
+ strcpy((char*)&p[sizeof(macho_dylinker_command<P>)], env);
+ return p + sz;
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySubUmbrellaLoadCommand(uint8_t* p, const char* nm) const
+{
+ uint32_t sz = alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(nm) + 1);
+ macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)p;
+ cmd->set_cmd(LC_SUB_UMBRELLA);
+ cmd->set_cmdsize(sz);
+ cmd->set_sub_umbrella_offset();
+ strcpy((char*)&p[sizeof(macho_sub_umbrella_command<P>)], nm);
+ return p + sz;
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySubLibraryLoadCommand(uint8_t* p, const char* nm) const
+{
+ uint32_t sz = alignedSize(sizeof(macho_sub_library_command<P>) + strlen(nm) + 1);
+ macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)p;
+ cmd->set_cmd(LC_SUB_LIBRARY);
+ cmd->set_cmdsize(sz);
+ cmd->set_sub_library_offset();
+ strcpy((char*)&p[sizeof(macho_sub_library_command<P>)], nm);
+ return p + sz;
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyFunctionStartsLoadCommand(uint8_t* p) const
+{
+ macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)p;
+ cmd->set_cmd(LC_FUNCTION_STARTS);
+ cmd->set_cmdsize(sizeof(macho_linkedit_data_command<P>));
+ cmd->set_dataoff(_writer.functionStartsSection->fileOffset);
+ cmd->set_datasize(_writer.functionStartsSection->size);
+ return p + sizeof(macho_linkedit_data_command<P>);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDataInCodeLoadCommand(uint8_t* p) const
+{
+ macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)p;
+ cmd->set_cmd(LC_DATA_IN_CODE);
+ cmd->set_cmdsize(sizeof(macho_linkedit_data_command<P>));
+ cmd->set_dataoff(_writer.dataInCodeSection->fileOffset);
+ cmd->set_datasize(_writer.dataInCodeSection->size);
+ return p + sizeof(macho_linkedit_data_command<P>);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDependentDRLoadCommand(uint8_t* p) const
+{
+ macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)p;
+ cmd->set_cmd(LC_DYLIB_CODE_SIGN_DRS);
+ cmd->set_cmdsize(sizeof(macho_linkedit_data_command<P>));
+ cmd->set_dataoff(_writer.dependentDRsSection->fileOffset);
+ cmd->set_datasize(_writer.dependentDRsSection->size);
+ return p + sizeof(macho_linkedit_data_command<P>);
+}
+
+
+template <typename A>
+void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ macho_header<P>* mh = (macho_header<P>*)buffer;
+ bzero(buffer, this->size());
+
+ // copy mach_header
+ mh->set_magic(this->magic());
+ mh->set_cputype(this->cpuType());
+ mh->set_cpusubtype(this->cpuSubType());
+ mh->set_filetype(this->fileType());
+ mh->set_ncmds(this->commandsCount());
+ mh->set_sizeofcmds(this->size()-sizeof(macho_header<P>));
+ mh->set_flags(this->flags());
+
+ // copy load commands
+ uint8_t* p = &buffer[sizeof(macho_header<P>)];
+
+ if ( _options.outputKind() == Options::kObjectFile )
+ p = this->copySingleSegmentLoadCommand(p);
+ else
+ p = this->copySegmentLoadCommands(p);
+
+ if ( _hasDylibIDLoadCommand )
+ p = this->copyDylibIDLoadCommand(p);
+
+ if ( _hasDyldInfoLoadCommand )
+ p = this->copyDyldInfoLoadCommand(p);
+
+ if ( _hasSymbolTableLoadCommand )
+ p = this->copySymbolTableLoadCommand(p);
+
+ if ( _hasDynamicSymbolTableLoadCommand )
+ p = this->copyDynamicSymbolTableLoadCommand(p);
+
+ if ( _hasDyldLoadCommand )
+ p = this->copyDyldLoadCommand(p);
+
+ if ( _hasRoutinesLoadCommand )
+ p = this->copyRoutinesLoadCommand(p);
+
+ if ( _hasUUIDLoadCommand )
+ p = this->copyUUIDLoadCommand(p);
+
+ if ( _hasVersionLoadCommand )
+ p = this->copyVersionLoadCommand(p);
+
+ if ( _hasSourceVersionLoadCommand )
+ p = this->copySourceVersionLoadCommand(p);
+
+ if ( _hasThreadLoadCommand )
+ p = this->copyThreadsLoadCommand(p);
+
+ if ( _hasEntryPointLoadCommand )
+ p = this->copyEntryPointLoadCommand(p);
+
+ if ( _hasEncryptionLoadCommand )
+ p = this->copyEncryptionLoadCommand(p);
+
+ if ( _hasSplitSegInfoLoadCommand )
+ p = this->copySplitSegInfoLoadCommand(p);
+
+ for(uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) {
+ p = this->copyDylibLoadCommand(p, _writer.dylibByOrdinal(ord));
+ }
+
+ if ( _hasRPathLoadCommands ) {
+ const std::vector<const char*>& rpaths = _options.rpaths();
+ for (std::vector<const char*>::const_iterator it = rpaths.begin(); it != rpaths.end(); ++it) {
+ p = this->copyRPathLoadCommand(p, *it);
+ }
+ }
+
+ if ( _hasSubFrameworkLoadCommand )
+ p = this->copySubFrameworkLoadCommand(p);
+
+ for (std::vector<const char*>::const_iterator it = _subLibraryNames.begin(); it != _subLibraryNames.end(); ++it) {
+ p = this->copySubLibraryLoadCommand(p, *it);
+ }
+
+ for (std::vector<const char*>::const_iterator it = _subUmbrellaNames.begin(); it != _subUmbrellaNames.end(); ++it) {
+ p = this->copySubUmbrellaLoadCommand(p, *it);
+ }
+
+ if ( _allowableClientLoadCommmandsCount != 0 ) {
+ const std::vector<const char*>& clients = _options.allowableClients();
+ for (std::vector<const char*>::const_iterator it = clients.begin(); it != clients.end(); ++it) {
+ p = this->copyAllowableClientLoadCommand(p, *it);
+ }
+ }
+
+ if ( _dyldEnvironExrasCount != 0 ) {
+ const std::vector<const char*>& extras = _options.dyldEnvironExtras();
+ for (std::vector<const char*>::const_iterator it = extras.begin(); it != extras.end(); ++it) {
+ p = this->copyDyldEnvLoadCommand(p, *it);
+ }
+ }
+
+ if ( _hasFunctionStartsLoadCommand )
+ p = this->copyFunctionStartsLoadCommand(p);
+
+ if ( _hasDataInCodeLoadCommand )
+ p = this->copyDataInCodeLoadCommand(p);
+
+ if ( _hasDependentDRInfo )
+ p = this->copyDependentDRLoadCommand(p);
+
+}
+
+
+
+} // namespace tool
+} // namespace ld
+
+#endif // __HEADER_LOAD_COMMANDS_HPP__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+#include <mach-o/fat.h>
+#include <sys/sysctl.h>
+#include <libkern/OSAtomic.h>
+
+#include <string>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+#include <list>
+#include <algorithm>
+#include <ext/hash_map>
+#include <ext/hash_set>
+#include <dlfcn.h>
+#include <AvailabilityMacros.h>
+
+#include "Options.h"
+
+#include "InputFiles.h"
+#include "macho_relocatable_file.h"
+#include "macho_dylib_file.h"
+#include "archive_file.h"
+#include "lto_file.h"
+#include "opaque_section_file.h"
+#include "Snapshot.h"
+
+const bool _s_logPThreads = false;
+
+namespace ld {
+namespace tool {
+
+class IgnoredFile : public ld::File {
+public:
+ IgnoredFile(const char* pth, time_t modTime, Ordinal ord, Type type) : ld::File(pth, modTime, ord, type) {};
+ virtual bool forEachAtom(AtomHandler&) const { return false; };
+ virtual bool justInTimeforEachAtom(const char* name, AtomHandler&) const { return false; };
+};
+
+
+class DSOHandleAtom : public ld::Atom {
+public:
+ DSOHandleAtom(const char* nm, ld::Atom::Scope sc,
+ ld::Atom::SymbolTableInclusion inc, ld::Section& sect=_s_section)
+ : ld::Atom(sect, ld::Atom::definitionRegular,
+ (sect == _s_section_text) ? ld::Atom::combineByName : ld::Atom::combineNever,
+ // make "weak def" so that link succeeds even if app defines __dso_handle
+ sc, ld::Atom::typeUnclassified, inc, true, false, false,
+ ld::Atom::Alignment(1)), _name(nm) {}
+
+ virtual ld::File* file() const { return NULL; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 0; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const
+ { }
+ virtual void setScope(Scope) { }
+
+ virtual ~DSOHandleAtom() {}
+
+ static ld::Section _s_section;
+ static ld::Section _s_section_preload;
+ static ld::Section _s_section_text;
+ static DSOHandleAtom _s_atomAll;
+ static DSOHandleAtom _s_atomExecutable;
+ static DSOHandleAtom _s_atomDylib;
+ static DSOHandleAtom _s_atomBundle;
+ static DSOHandleAtom _s_atomDyld;
+ static DSOHandleAtom _s_atomObjectFile;
+ static DSOHandleAtom _s_atomPreload;
+ static DSOHandleAtom _s_atomPreloadDSO;
+private:
+ const char* _name;
+};
+ld::Section DSOHandleAtom::_s_section("__TEXT", "__mach_header", ld::Section::typeMachHeader, true);
+ld::Section DSOHandleAtom::_s_section_preload("__HEADER", "__mach_header", ld::Section::typeMachHeader, true);
+ld::Section DSOHandleAtom::_s_section_text("__TEXT", "__text", ld::Section::typeCode, false);
+DSOHandleAtom DSOHandleAtom::_s_atomAll("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
+DSOHandleAtom DSOHandleAtom::_s_atomExecutable("__mh_execute_header", ld::Atom::scopeGlobal, ld::Atom::symbolTableInAndNeverStrip);
+DSOHandleAtom DSOHandleAtom::_s_atomDylib("__mh_dylib_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
+DSOHandleAtom DSOHandleAtom::_s_atomBundle("__mh_bundle_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
+DSOHandleAtom DSOHandleAtom::_s_atomDyld("__mh_dylinker_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
+DSOHandleAtom DSOHandleAtom::_s_atomObjectFile("__mh_object_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
+DSOHandleAtom DSOHandleAtom::_s_atomPreload("__mh_preload_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, _s_section_preload);
+DSOHandleAtom DSOHandleAtom::_s_atomPreloadDSO("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, _s_section_text);
+
+
+
+class PageZeroAtom : public ld::Atom {
+public:
+ PageZeroAtom(uint64_t sz)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeTranslationUnit, ld::Atom::typeZeroFill,
+ symbolTableNotIn, true, false, false, ld::Atom::Alignment(12)),
+ _size(sz) {}
+
+ virtual ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "page zero"; }
+ virtual uint64_t size() const { return _size; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const
+ { }
+ virtual void setScope(Scope) { }
+
+ virtual ~PageZeroAtom() {}
+
+ static ld::Section _s_section;
+ static DSOHandleAtom _s_atomAll;
+private:
+ uint64_t _size;
+};
+ld::Section PageZeroAtom::_s_section("__PAGEZERO", "__pagezero", ld::Section::typePageZero, true);
+
+
+class CustomStackAtom : public ld::Atom {
+public:
+ CustomStackAtom(uint64_t sz)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeTranslationUnit, ld::Atom::typeZeroFill,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(12)),
+ _size(sz) {}
+
+ virtual ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "custom stack"; }
+ virtual uint64_t size() const { return _size; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const
+ { }
+ virtual void setScope(Scope) { }
+
+ virtual ~CustomStackAtom() {}
+
+private:
+ uint64_t _size;
+ static ld::Section _s_section;
+};
+ld::Section CustomStackAtom::_s_section("__UNIXSTACK", "__stack", ld::Section::typeStack, true);
+
+
+
+const char* InputFiles::fileArch(const uint8_t* p, unsigned len)
+{
+ const char* result = mach_o::relocatable::archName(p);
+ if ( result != NULL )
+ return result;
+
+ result = lto::archName(p, len);
+ if ( result != NULL )
+ return result;
+
+ if ( strncmp((const char*)p, "!<arch>\n", 8) == 0 )
+ return "archive";
+
+ char *unsupported = (char *)malloc(128);
+ strcpy(unsupported, "unsupported file format (");
+ for (unsigned i=0; i<len && i < 16; i++) {
+ char buf[8];
+ sprintf(buf, " 0x%2x", p[i]);
+ strcat(unsupported, buf);
+ }
+ strcat(unsupported, " )");
+ return unsupported;
+}
+
+
+ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib)
+{
+ // map in whole file
+ uint64_t len = info.fileLen;
+ int fd = ::open(info.path, O_RDONLY, 0);
+ if ( fd == -1 )
+ throwf("can't open file, errno=%d", errno);
+ if ( info.fileLen < 20 )
+ throw "file too small";
+
+ uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+ if ( p == (uint8_t*)(-1) )
+ throwf("can't map file, errno=%d", errno);
+
+ // if fat file, skip to architecture we want
+ // Note: fat header is always big-endian
+ bool isFatFile = false;
+ uint32_t sliceToUse, sliceCount;
+ const fat_header* fh = (fat_header*)p;
+ if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+ isFatFile = true;
+ const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
+ bool sliceFound = false;
+ sliceCount = OSSwapBigToHostInt32(fh->nfat_arch);
+ if ( _options.preferSubArchitecture() ) {
+ // first try to find a slice that match cpu-type and cpu-sub-type
+ for (uint32_t i=0; i < sliceCount; ++i) {
+ if ( (OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture())
+ && (OSSwapBigToHostInt32(archs[i].cpusubtype) == (uint32_t)_options.subArchitecture()) ) {
+ sliceToUse = i;
+ sliceFound = true;
+ break;
+ }
+ }
+ }
+ if ( !sliceFound ) {
+ // look for any slice that matches just cpu-type
+ for (uint32_t i=0; i < sliceCount; ++i) {
+ if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture() ) {
+ sliceToUse = i;
+ sliceFound = true;
+ break;
+ }
+ }
+ }
+ if ( sliceFound ) {
+ uint32_t fileOffset = OSSwapBigToHostInt32(archs[sliceToUse].offset);
+ len = OSSwapBigToHostInt32(archs[sliceToUse].size);
+ if ( fileOffset+len > info.fileLen ) {
+ throwf("truncated fat file. Slice from %u to %llu is past end of file with length %llu",
+ fileOffset, fileOffset+len, info.fileLen);
+ }
+ // if requested architecture is page aligned within fat file, then remap just that portion of file
+ if ( (fileOffset & 0x00000FFF) == 0 ) {
+ // unmap whole file
+ munmap((caddr_t)p, info.fileLen);
+ // re-map just part we need
+ p = (uint8_t*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, fileOffset);
+ if ( p == (uint8_t*)(-1) )
+ throwf("can't re-map file, errno=%d", errno);
+ }
+ else {
+ p = &p[fileOffset];
+ }
+ }
+ }
+ ::close(fd);
+
+ // see if it is an object file
+ mach_o::relocatable::ParserOptions objOpts;
+ objOpts.architecture = _options.architecture();
+ objOpts.objSubtypeMustMatch = !_options.allowSubArchitectureMismatches();
+ objOpts.logAllFiles = _options.logAllFiles();
+ objOpts.convertUnwindInfo = _options.needsUnwindInfoSection();
+ objOpts.subType = _options.subArchitecture();
+ ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts);
+ if ( objResult != NULL ) {
+ OSAtomicAdd64(len, &_totalObjectSize);
+ OSAtomicIncrement32(&_totalObjectLoaded);
+ return objResult;
+ }
+
+ // see if it is an llvm object file
+ objResult = lto::parse(p, len, info.path, info.modTime, info.ordinal, _options.architecture(), _options.subArchitecture(), _options.logAllFiles());
+ if ( objResult != NULL ) {
+ OSAtomicAdd64(len, &_totalObjectSize);
+ OSAtomicIncrement32(&_totalObjectLoaded);
+ return objResult;
+ }
+
+ // see if it is a dynamic library
+ ld::dylib::File* dylibResult = mach_o::dylib::parse(p, len, info.path, info.modTime, _options, info.ordinal, info.options.fBundleLoader, indirectDylib);
+ if ( dylibResult != NULL ) {
+ return dylibResult;
+ }
+
+ // see if it is a static library
+ ::archive::ParserOptions archOpts;
+ archOpts.objOpts = objOpts;
+ archOpts.forceLoadThisArchive = info.options.fForceLoad;
+ archOpts.forceLoadAll = _options.fullyLoadArchives();
+ archOpts.forceLoadObjC = _options.loadAllObjcObjectsFromArchives();
+ archOpts.objcABI2 = _options.objCABIVersion2POverride();
+ archOpts.verboseLoad = _options.whyLoad();
+ archOpts.logAllFiles = _options.logAllFiles();
+ ld::archive::File* archiveResult = ::archive::parse(p, len, info.path, info.modTime, info.ordinal, archOpts);
+ if ( archiveResult != NULL ) {
+ OSAtomicAdd64(len, &_totalArchiveSize);
+ OSAtomicIncrement32(&_totalArchivesLoaded);
+ return archiveResult;
+ }
+
+ // does not seem to be any valid linker input file, check LTO misconfiguration problems
+ if ( lto::archName((uint8_t*)p, len) != NULL ) {
+ if ( lto::libLTOisLoaded() ) {
+ throwf("lto file was built for %s which is not the architecture being linked (%s): %s", fileArch(p, len), _options.architectureName(), info.path);
+ }
+ else {
+ const char* libLTO = "libLTO.dylib";
+ char ldPath[PATH_MAX];
+ char tmpPath[PATH_MAX];
+ char libLTOPath[PATH_MAX];
+ uint32_t bufSize = PATH_MAX;
+ if ( _options.overridePathlibLTO() != NULL ) {
+ libLTO = _options.overridePathlibLTO();
+ }
+ else if ( _NSGetExecutablePath(ldPath, &bufSize) != -1 ) {
+ if ( realpath(ldPath, tmpPath) != NULL ) {
+ char* lastSlash = strrchr(tmpPath, '/');
+ if ( lastSlash != NULL )
+ strcpy(lastSlash, "/../lib/libLTO.dylib");
+ libLTO = tmpPath;
+ if ( realpath(tmpPath, libLTOPath) != NULL )
+ libLTO = libLTOPath;
+ }
+ }
+ throwf("could not process llvm bitcode object file, because %s could not be loaded", libLTO);
+ }
+ }
+
+ // error handling
+ if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+ throwf("missing required architecture %s in file %s (%u slices)", _options.architectureName(), info.path, sliceCount);
+ }
+ else {
+ if ( isFatFile )
+ throwf("file is universal (%u slices) but does not contain a(n) %s slice: %s", sliceCount, _options.architectureName(), info.path);
+ else
+ throwf("file was built for %s which is not the architecture being linked (%s): %s", fileArch(p, len), _options.architectureName(), info.path);
+ }
+}
+
+void InputFiles::logDylib(ld::File* file, bool indirect)
+{
+ if ( _options.traceDylibs() ) {
+ const char* fullPath = file->path();
+ char realName[MAXPATHLEN];
+ if ( realpath(fullPath, realName) != NULL )
+ fullPath = realName;
+ const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(file);
+ if ( (dylib != NULL ) && dylib->willBeUpwardDylib() ) {
+ // don't log upward dylibs when XBS is computing dependencies
+ logTraceInfo("[Logging for XBS] Used upward dynamic library: %s\n", fullPath);
+ }
+ else {
+ if ( indirect )
+ logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath);
+ else
+ logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath);
+ }
+ }
+}
+
+void InputFiles::logArchive(ld::File* file) const
+{
+ if ( _options.traceArchives() && (_archiveFilesLogged.count(file) == 0) ) {
+ // <rdar://problem/4947347> LD_TRACE_ARCHIVES should only print out when a .o is actually used from an archive
+ _archiveFilesLogged.insert(file);
+ const char* fullPath = file->path();
+ char realName[MAXPATHLEN];
+ if ( realpath(fullPath, realName) != NULL )
+ fullPath = realName;
+ logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath);
+ }
+}
+
+
+void InputFiles::logTraceInfo(const char* format, ...) const
+{
+ // one time open() of custom LD_TRACE_FILE
+ static int trace_file = -1;
+ if ( trace_file == -1 ) {
+ const char *trace_file_path = _options.traceOutputFile();
+ if ( trace_file_path != NULL ) {
+ trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666);
+ if ( trace_file == -1 )
+ throwf("Could not open or create trace file: %s", trace_file_path);
+ }
+ else {
+ trace_file = fileno(stderr);
+ }
+ }
+
+ char trace_buffer[MAXPATHLEN * 2];
+ va_list ap;
+ va_start(ap, format);
+ int length = vsnprintf(trace_buffer, sizeof(trace_buffer), format, ap);
+ va_end(ap);
+ char* buffer_ptr = trace_buffer;
+
+ while (length > 0) {
+ ssize_t amount_written = write(trace_file, buffer_ptr, length);
+ if(amount_written == -1)
+ /* Failure to write shouldn't fail the build. */
+ return;
+ buffer_ptr += amount_written;
+ length -= amount_written;
+ }
+}
+
+ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* fromPath)
+{
+ //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath);
+ InstallNameToDylib::iterator pos = _installPathToDylibs.find(installPath);
+ if ( pos != _installPathToDylibs.end() ) {
+ return pos->second;
+ }
+ else {
+ // allow -dylib_path option to override indirect library to use
+ for (std::vector<Options::DylibOverride>::const_iterator dit = _options.dylibOverrides().begin(); dit != _options.dylibOverrides().end(); ++dit) {
+ if ( strcmp(dit->installName,installPath) == 0 ) {
+ try {
+ Options::FileInfo info = _options.findFile(dit->useInstead);
+ _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal();
+ info.ordinal = _indirectDylibOrdinal;
+ ld::File* reader = this->makeFile(info, true);
+ ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
+ if ( dylibReader != NULL ) {
+ addDylib(dylibReader, info);
+ //_installPathToDylibs[strdup(installPath)] = dylibReader;
+ this->logDylib(dylibReader, true);
+ return dylibReader;
+ }
+ else
+ throwf("indirect dylib at %s is not a dylib", dit->useInstead);
+ }
+ catch (const char* msg) {
+ warning("ignoring -dylib_file option, %s", msg);
+ }
+ }
+ }
+ char newPath[MAXPATHLEN];
+ // handle @loader_path
+ if ( strncmp(installPath, "@loader_path/", 13) == 0 ) {
+ strcpy(newPath, fromPath);
+ char* addPoint = strrchr(newPath,'/');
+ if ( addPoint != NULL )
+ strcpy(&addPoint[1], &installPath[13]);
+ else
+ strcpy(newPath, &installPath[13]);
+ installPath = newPath;
+ }
+ // note: @executable_path case is handled inside findFileUsingPaths()
+ // search for dylib using -F and -L paths
+ Options::FileInfo info = _options.findFileUsingPaths(installPath);
+ _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal();
+ info.ordinal = _indirectDylibOrdinal;
+ try {
+ ld::File* reader = this->makeFile(info, true);
+ ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
+ if ( dylibReader != NULL ) {
+ //assert(_installPathToDylibs.find(installPath) != _installPathToDylibs.end());
+ //_installPathToDylibs[strdup(installPath)] = dylibReader;
+ addDylib(dylibReader, info);
+ this->logDylib(dylibReader, true);
+ return dylibReader;
+ }
+ else
+ throwf("indirect dylib at %s is not a dylib", info.path);
+ }
+ catch (const char* msg) {
+ throwf("in %s, %s", info.path, msg);
+ }
+ }
+}
+
+
+
+void InputFiles::createIndirectDylibs()
+{
+ _allDirectDylibsLoaded = true;
+ _indirectDylibOrdinal = ld::File::Ordinal::indirectDylibBase();
+
+ // mark all dylibs initially specified as required and check if they can be used
+ for (InstallNameToDylib::iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); it++) {
+ it->second->setExplicitlyLinked();
+ this->checkDylibClientRestrictions(it->second);
+ }
+
+ // keep processing dylibs until no more dylibs are added
+ unsigned long lastMapSize = 0;
+ std::set<ld::dylib::File*> dylibsProcessed;
+ while ( lastMapSize != _allDylibs.size() ) {
+ lastMapSize = _allDylibs.size();
+ // can't iterator _installPathToDylibs while modifying it, so use temp buffer
+ std::vector<ld::dylib::File*> unprocessedDylibs;
+ for (std::set<ld::dylib::File*>::iterator it=_allDylibs.begin(); it != _allDylibs.end(); it++) {
+ if ( dylibsProcessed.count(*it) == 0 )
+ unprocessedDylibs.push_back(*it);
+ }
+ for (std::vector<ld::dylib::File*>::iterator it=unprocessedDylibs.begin(); it != unprocessedDylibs.end(); it++) {
+ dylibsProcessed.insert(*it);
+ (*it)->processIndirectLibraries(this, _options.implicitlyLinkIndirectPublicDylibs());
+ }
+ }
+
+ // go back over original dylibs and mark sub frameworks as re-exported
+ if ( _options.outputKind() == Options::kDynamicLibrary ) {
+ const char* myLeaf = strrchr(_options.installPath(), '/');
+ if ( myLeaf != NULL ) {
+ for (std::vector<class ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); it++) {
+ ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(*it);
+ if ( dylibReader != NULL ) {
+ const char* childParent = dylibReader->parentUmbrella();
+ if ( childParent != NULL ) {
+ if ( strcmp(childParent, &myLeaf[1]) == 0 ) {
+ // mark that this dylib will be re-exported
+ dylibReader->setWillBeReExported();
+ }
+ }
+ }
+ }
+ }
+ }
+
+}
+
+void InputFiles::createOpaqueFileSections()
+{
+ // extra command line section always at end
+ for (Options::ExtraSection::const_iterator it=_options.extraSectionsBegin(); it != _options.extraSectionsEnd(); ++it) {
+ _inputFiles.push_back(opaque_section::parse(it->segmentName, it->sectionName, it->path, it->data, it->dataLen));
+ }
+
+}
+
+
+void InputFiles::checkDylibClientRestrictions(ld::dylib::File* dylib)
+{
+ // Check for any restrictions on who can link with this dylib
+ const char* dylibParentName = dylib->parentUmbrella() ;
+ const std::vector<const char*>* clients = dylib->allowableClients();
+ if ( (dylibParentName != NULL) || (clients != NULL) ) {
+ // only dylibs that are in an umbrella or have a client list need verification
+ const char* installName = _options.installPath();
+ const char* installNameLastSlash = strrchr(installName, '/');
+ bool isParent = false;
+ bool isSibling = false;
+ bool isAllowableClient = false;
+ // There are three cases:
+ if ( (dylibParentName != NULL) && (installNameLastSlash != NULL) ) {
+ // starts after last slash
+ const char* myName = &installNameLastSlash[1];
+ unsigned int myNameLen = strlen(myName);
+ if ( strncmp(myName, "lib", 3) == 0 )
+ myName = &myName[3];
+ // up to first dot
+ const char* firstDot = strchr(myName, '.');
+ if ( firstDot != NULL )
+ myNameLen = firstDot - myName;
+ // up to first underscore
+ const char* firstUnderscore = strchr(myName, '_');
+ if ( (firstUnderscore != NULL) && ((firstUnderscore - myName) < (int)myNameLen) )
+ myNameLen = firstUnderscore - myName;
+
+ // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella
+ isParent = ( (strlen(dylibParentName) == myNameLen) && (strncmp(myName, dylibParentName, myNameLen) == 0) );
+
+ // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent
+ isSibling = ( (_options.umbrellaName() != NULL) && (strcmp(_options.umbrellaName(), dylibParentName) == 0) );
+ }
+
+ if ( !isParent && !isSibling && (clients != NULL) ) {
+ // case 3) the dylib has a list of allowable clients, and we are creating one of them
+ const char* clientName = _options.clientName();
+ int clientNameLen = 0;
+ if ( clientName != NULL ) {
+ // use client name as specified on command line
+ clientNameLen = strlen(clientName);
+ }
+ else {
+ // infer client name from output path (e.g. xxx/libfoo_variant.A.dylib --> foo, Bar.framework/Bar_variant --> Bar)
+ clientName = installName;
+ clientNameLen = strlen(clientName);
+ // starts after last slash
+ if ( installNameLastSlash != NULL )
+ clientName = &installNameLastSlash[1];
+ if ( strncmp(clientName, "lib", 3) == 0 )
+ clientName = &clientName[3];
+ // up to first dot
+ const char* firstDot = strchr(clientName, '.');
+ if ( firstDot != NULL )
+ clientNameLen = firstDot - clientName;
+ // up to first underscore
+ const char* firstUnderscore = strchr(clientName, '_');
+ if ( (firstUnderscore != NULL) && ((firstUnderscore - clientName) < clientNameLen) )
+ clientNameLen = firstUnderscore - clientName;
+ }
+
+ // Use clientName to check if this dylib is able to link against the allowable clients.
+ for (std::vector<const char*>::const_iterator it = clients->begin(); it != clients->end(); it++) {
+ if ( strncmp(*it, clientName, clientNameLen) == 0 )
+ isAllowableClient = true;
+ }
+ }
+
+ if ( !isParent && !isSibling && !isAllowableClient ) {
+ if ( dylibParentName != NULL ) {
+ throwf("cannot link directly with %s. Link against the umbrella framework '%s.framework' instead.",
+ dylib->path(), dylibParentName);
+ }
+ else {
+ throwf("cannot link directly with %s", dylib->path());
+ }
+ }
+ }
+}
+
+
+void InputFiles::inferArchitecture(Options& opts, const char** archName)
+{
+ _inferredArch = true;
+ // scan all input files, looking for a thin .o file.
+ // the first one found is presumably the architecture to link
+ uint8_t buffer[sizeof(mach_header_64)];
+ const std::vector<Options::FileInfo>& files = opts.getInputFiles();
+ for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) {
+ int fd = ::open(it->path, O_RDONLY, 0);
+ if ( fd != -1 ) {
+ ssize_t amount = read(fd, buffer, sizeof(buffer));
+ ::close(fd);
+ if ( amount >= (ssize_t)sizeof(buffer) ) {
+ cpu_type_t type;
+ cpu_subtype_t subtype;
+ if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype) ) {
+ opts.setArchitecture(type, subtype);
+ *archName = opts.architectureName();
+ return;
+ }
+ }
+ }
+ }
+
+ // no thin .o files found, so default to same architecture this tool was built as
+ warning("-arch not specified");
+#if __i386__
+ opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL);
+#elif __x86_64__
+ opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL);
+#elif __arm__
+ opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6);
+#else
+ #error unknown default architecture
+#endif
+ *archName = opts.architectureName();
+}
+
+
+InputFiles::InputFiles(Options& opts, const char** archName)
+ : _totalObjectSize(0), _totalArchiveSize(0),
+ _totalObjectLoaded(0), _totalArchivesLoaded(0), _totalDylibsLoaded(0),
+ _options(opts), _bundleLoader(NULL),
+ _allDirectDylibsLoaded(false), _inferredArch(false), _fileMonitor(-1),
+ _exception(NULL)
+{
+// fStartCreateReadersTime = mach_absolute_time();
+ if ( opts.architecture() == 0 ) {
+ // command line missing -arch, so guess arch
+ inferArchitecture(opts, archName);
+ }
+#if HAVE_PTHREADS
+ pthread_mutex_init(&_parseLock, NULL);
+ pthread_cond_init(&_parseWorkReady, NULL);
+ pthread_cond_init(&_newFileAvailable, NULL);
+#endif
+ const std::vector<Options::FileInfo>& files = _options.getInputFiles();
+ if ( files.size() == 0 )
+ throw "no object files specified";
+
+ _inputFiles.reserve(files.size());
+#if HAVE_PTHREADS
+ unsigned int inputFileSlot = 0;
+ _availableInputFiles = 0;
+ _parseCursor = 0;
+#endif
+ Options::FileInfo* entry;
+ for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) {
+ entry = (Options::FileInfo*)&(*it);
+#if HAVE_PTHREADS
+ // Assign input file slots to all the FileInfos.
+ // Also chain all FileInfos into one big list to set up for worker threads to do parsing.
+ entry->inputFileSlot = inputFileSlot;
+ entry->readyToParse = !entry->fromFileList || !_options.pipelineEnabled();
+ if (entry->readyToParse)
+ _availableInputFiles++;
+ _inputFiles.push_back(NULL);
+ inputFileSlot++;
+#else
+ // In the non-threaded case just parse the file now.
+ _inputFiles.push_back(makeFile(*entry, false));
+#endif
+ }
+
+#if HAVE_PTHREADS
+ _remainingInputFiles = files.size();
+
+ // initialize info for parsing input files on worker threads
+ unsigned int ncpus;
+ int mib[2];
+ size_t len = sizeof(ncpus);
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ if (sysctl(mib, 2, &ncpus, &len, NULL, 0) != 0) {
+ ncpus = 1;
+ }
+ _availableWorkers = MIN(ncpus, files.size()); // max # workers we permit
+ _idleWorkers = 0;
+
+ if (_options.pipelineEnabled()) {
+ // start up a thread to listen for available input files
+ startThread(InputFiles::waitForInputFiles);
+ }
+
+ // Start up one parser thread. More start on demand as parsed input files get consumed.
+ startThread(InputFiles::parseWorkerThread);
+ _availableWorkers--;
+#else
+ if (_options.pipelineEnabled()) {
+ throwf("pipelined linking not supported on this platform");
+ }
+#endif
+}
+
+
+#if HAVE_PTHREADS
+void InputFiles::startThread(void (*threadFunc)(InputFiles *)) const {
+ pthread_t thread;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ // set a nice big stack (same as main thread) because some code uses potentially large stack buffers
+ pthread_attr_setstacksize(&attr, 8 * 1024 * 1024);
+ pthread_create(&thread, &attr, (void *(*)(void*))threadFunc, (void *)this);
+ pthread_detach(thread);
+ pthread_attr_destroy(&attr);
+}
+
+// Work loop for input file parsing threads
+void InputFiles::parseWorkerThread() {
+ ld::File *file;
+ const char *exception = NULL;
+ pthread_mutex_lock(&_parseLock);
+ const std::vector<Options::FileInfo>& files = _options.getInputFiles();
+ if (_s_logPThreads) printf("worker starting\n");
+ do {
+ if (_availableInputFiles == 0) {
+ _idleWorkers++;
+ pthread_cond_wait(&_parseWorkReady, &_parseLock);
+ _idleWorkers--;
+ } else {
+ int slot = _parseCursor;
+ while (slot < (int)files.size() && (_inputFiles[slot] != NULL || !files[slot].readyToParse))
+ slot++;
+ assert(slot < (int)files.size());
+ Options::FileInfo& entry = (Options::FileInfo&)files[slot];
+ _parseCursor = slot+1;
+ _availableInputFiles--;
+ entry.readyToParse = false; // to avoid multiple threads finding this file
+ pthread_mutex_unlock(&_parseLock);
+ if (_s_logPThreads) printf("parsing index %u\n", slot);
+ try {
+ file = makeFile(entry, false);
+ } catch (const char *msg) {
+ if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) {
+ if ( _options.ignoreOtherArchInputFiles() ) {
+ // ignore, because this is about an architecture not in use
+ }
+ else {
+ warning("ignoring file %s, %s", entry.path, msg);
+ }
+ } else {
+ exception = msg;
+ }
+ file = new IgnoredFile(entry.path, entry.modTime, entry.ordinal, ld::File::Other);
+ }
+ pthread_mutex_lock(&_parseLock);
+ if (_remainingInputFiles > 0)
+ _remainingInputFiles--;
+ if (_s_logPThreads) printf("done with index %u, %d remaining\n", slot, _remainingInputFiles);
+ if (exception) {
+ // We are about to die, so set to zero to stop other threads from doing unneeded work.
+ _remainingInputFiles = 0;
+ _exception = exception;
+ } else {
+ _inputFiles[slot] = file;
+ if (_neededFileSlot == slot)
+ pthread_cond_signal(&_newFileAvailable);
+ }
+ }
+ } while (_remainingInputFiles);
+ if (_s_logPThreads) printf("worker exiting\n");
+ pthread_cond_broadcast(&_parseWorkReady);
+ pthread_cond_signal(&_newFileAvailable);
+ pthread_mutex_unlock(&_parseLock);
+}
+
+
+void InputFiles::parseWorkerThread(InputFiles *inputFiles) {
+ inputFiles->parseWorkerThread();
+}
+#endif
+
+
+ld::File* InputFiles::addDylib(ld::dylib::File* reader, const Options::FileInfo& info)
+{
+ _allDylibs.insert(reader);
+
+ if ( (reader->installPath() == NULL) && !info.options.fBundleLoader ) {
+ // this is a "blank" stub
+ // silently ignore it
+ return reader;
+ }
+ // store options about how dylib will be used in dylib itself
+ if ( info.options.fWeakImport )
+ reader->setForcedWeakLinked();
+ if ( info.options.fReExport )
+ reader->setWillBeReExported();
+ if ( info.options.fUpward ) {
+ if ( _options.outputKind() == Options::kDynamicLibrary )
+ reader->setWillBeUpwardDylib();
+ else
+ warning("ignoring upward dylib option for %s\n", info.path);
+ }
+ if ( info.options.fLazyLoad )
+ reader->setWillBeLazyLoadedDylb();
+
+ // add to map of loaded dylibs
+ const char* installPath = reader->installPath();
+ if ( installPath != NULL ) {
+ InstallNameToDylib::iterator pos = _installPathToDylibs.find(installPath);
+ if ( pos == _installPathToDylibs.end() ) {
+ _installPathToDylibs[strdup(installPath)] = reader;
+ }
+ else {
+ bool dylibOnCommandLineTwice = ( strcmp(pos->second->path(), reader->path()) == 0 );
+ bool isSymlink = false;
+ // ignore if this is a symlink to a dylib we've already loaded
+ if ( !dylibOnCommandLineTwice ) {
+ char existingDylibPath[PATH_MAX];
+ if ( realpath(pos->second->path(), existingDylibPath) != NULL ) {
+ char newDylibPath[PATH_MAX];
+ if ( realpath(reader->path(), newDylibPath) != NULL ) {
+ isSymlink = ( strcmp(existingDylibPath, newDylibPath) == 0 );
+ }
+ }
+ }
+ // remove warning for <rdar://problem/10860629> Same install name for CoreServices and CFNetwork?
+ //if ( !dylibOnCommandLineTwice && !isSymlink )
+ // warning("dylibs with same install name: %s and %s", pos->second->path(), reader->path());
+ }
+ }
+ else if ( info.options.fBundleLoader )
+ _bundleLoader = reader;
+
+ // log direct readers
+ if ( !_allDirectDylibsLoaded )
+ this->logDylib(reader, false);
+
+ // update stats
+ _totalDylibsLoaded++;
+
+ _searchLibraries.push_back(LibraryInfo(reader));
+ return reader;
+}
+
+
+#if HAVE_PTHREADS
+// Called during pipelined linking to listen for available input files.
+// Available files are enqueued for parsing.
+void InputFiles::waitForInputFiles()
+{
+ if (_s_logPThreads) printf("starting pipeline listener\n");
+ try {
+ const char *fifo = _options.pipelineFifo();
+ assert(fifo);
+ std::map<const char *, const Options::FileInfo*, strcompclass> fileMap;
+ const std::vector<Options::FileInfo>& files = _options.getInputFiles();
+ for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) {
+ const Options::FileInfo& entry = *it;
+ if (entry.fromFileList) {
+ fileMap[entry.path] = &entry;
+ }
+ }
+ FILE *fileStream = fopen(fifo, "r");
+ if (!fileStream)
+ throwf("pipelined linking error - failed to open stream. fopen() returns %s for \"%s\"\n", strerror(errno), fifo);
+ while (fileMap.size() > 0) {
+ char path_buf[PATH_MAX+1];
+ if (fgets(path_buf, PATH_MAX, fileStream) == NULL)
+ throwf("pipelined linking error - %lu missing input files", fileMap.size());
+ int len = strlen(path_buf);
+ if (path_buf[len-1] == '\n')
+ path_buf[len-1] = 0;
+ std::map<const char *, const Options::FileInfo*, strcompclass>::iterator it = fileMap.find(path_buf);
+ if (it == fileMap.end())
+ throwf("pipelined linking error - not in file list: %s\n", path_buf);
+ Options::FileInfo* inputInfo = (Options::FileInfo*)it->second;
+ if (!inputInfo->checkFileExists())
+ throwf("pipelined linking error - file does not exist: %s\n", inputInfo->path);
+ pthread_mutex_lock(&_parseLock);
+ if (_idleWorkers)
+ pthread_cond_signal(&_parseWorkReady);
+ inputInfo->readyToParse = true;
+ if (_parseCursor > inputInfo->inputFileSlot)
+ _parseCursor = inputInfo->inputFileSlot;
+ _availableInputFiles++;
+ if (_s_logPThreads) printf("pipeline listener: %s slot=%d, _parseCursor=%d, _availableInputFiles = %d remaining = %ld\n", path_buf, inputInfo->inputFileSlot, _parseCursor, _availableInputFiles, fileMap.size()-1);
+ pthread_mutex_unlock(&_parseLock);
+ fileMap.erase(it);
+ }
+ } catch (const char *msg) {
+ pthread_mutex_lock(&_parseLock);
+ _exception = msg;
+ pthread_cond_signal(&_newFileAvailable);
+ pthread_mutex_unlock(&_parseLock);
+ }
+}
+
+
+void InputFiles::waitForInputFiles(InputFiles *inputFiles) {
+ inputFiles->waitForInputFiles();
+}
+#endif
+
+
+void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
+{
+ // add all direct object, archives, and dylibs
+ const std::vector<Options::FileInfo>& files = _options.getInputFiles();
+ size_t fileIndex;
+ for (fileIndex=0; fileIndex<_inputFiles.size(); fileIndex++) {
+ ld::File *file;
+#if HAVE_PTHREADS
+ pthread_mutex_lock(&_parseLock);
+
+ // this loop waits for the needed file to be ready (parsed by worker thread)
+ while (_inputFiles[fileIndex] == NULL && _exception == NULL) {
+ // We are starved for input. If there are still files to parse and we have
+ // not maxed out the worker thread count start a new worker thread.
+ if (_availableInputFiles > 0 && _availableWorkers > 0) {
+ if (_s_logPThreads) printf("starting worker\n");
+ startThread(InputFiles::parseWorkerThread);
+ _availableWorkers--;
+ }
+ _neededFileSlot = fileIndex;
+ if (_s_logPThreads) printf("consumer blocking for %lu: %s\n", fileIndex, files[fileIndex].path);
+ pthread_cond_wait(&_newFileAvailable, &_parseLock);
+ }
+
+ if (_exception)
+ throw _exception;
+
+ // The input file is parsed. Assimilate it and call its atom iterator.
+ if (_s_logPThreads) printf("consuming slot %lu\n", fileIndex);
+ file = _inputFiles[fileIndex];
+ pthread_mutex_unlock(&_parseLock);
+#else
+ file = _inputFiles[fileIndex];
+#endif
+ const Options::FileInfo& info = files[fileIndex];
+ switch (file->type()) {
+ case ld::File::Reloc:
+ {
+ ld::relocatable::File* reloc = (ld::relocatable::File*)file;
+ _options.snapshot().recordObjectFile(reloc->path());
+ }
+ break;
+ case ld::File::Dylib:
+ {
+ ld::dylib::File* dylib = (ld::dylib::File*)file;
+ addDylib(dylib, info);
+ }
+ break;
+ case ld::File::Archive:
+ {
+ ld::archive::File* archive = (ld::archive::File*)file;
+ // <rdar://problem/9740166> force loaded archives should be in LD_TRACE
+ if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && _options.traceArchives() )
+ logArchive(archive);
+ _searchLibraries.push_back(LibraryInfo(archive));
+ }
+ break;
+ case ld::File::Other:
+ break;
+ default:
+ {
+ throwf("Unknown file type for %s", file->path());
+ }
+ break;
+ }
+ file->forEachAtom(handler);
+ }
+
+ createIndirectDylibs();
+ createOpaqueFileSections();
+
+ while (fileIndex < _inputFiles.size()) {
+ ld::File *file = _inputFiles[fileIndex];
+ file->forEachAtom(handler);
+ fileIndex++;
+ }
+
+ switch ( _options.outputKind() ) {
+ case Options::kStaticExecutable:
+ case Options::kDynamicExecutable:
+ // add implicit __dso_handle label
+ handler.doAtom(DSOHandleAtom::_s_atomExecutable);
+ handler.doAtom(DSOHandleAtom::_s_atomAll);
+ if ( _options.pageZeroSize() != 0 )
+ handler.doAtom(*new PageZeroAtom(_options.pageZeroSize()));
+ if ( _options.hasCustomStack() && !_options.needsEntryPointLoadCommand() )
+ handler.doAtom(*new CustomStackAtom(_options.customStackSize()));
+ break;
+ case Options::kDynamicLibrary:
+ // add implicit __dso_handle label
+ handler.doAtom(DSOHandleAtom::_s_atomDylib);
+ handler.doAtom(DSOHandleAtom::_s_atomAll);
+ break;
+ case Options::kDynamicBundle:
+ // add implicit __dso_handle label
+ handler.doAtom(DSOHandleAtom::_s_atomBundle);
+ handler.doAtom(DSOHandleAtom::_s_atomAll);
+ break;
+ case Options::kDyld:
+ // add implicit __dso_handle label
+ handler.doAtom(DSOHandleAtom::_s_atomDyld);
+ handler.doAtom(DSOHandleAtom::_s_atomAll);
+ break;
+ case Options::kPreload:
+ // add implicit __mh_preload_header label
+ handler.doAtom(DSOHandleAtom::_s_atomPreload);
+ // add implicit __dso_handle label, but put it in __text section because
+ // with -preload the mach_header is no in the address space.
+ handler.doAtom(DSOHandleAtom::_s_atomPreloadDSO);
+ break;
+ case Options::kObjectFile:
+ handler.doAtom(DSOHandleAtom::_s_atomObjectFile);
+ break;
+ case Options::kKextBundle:
+ // add implicit __dso_handle label
+ handler.doAtom(DSOHandleAtom::_s_atomAll);
+ break;
+ }
+}
+
+
+bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searchArchives, bool dataSymbolOnly, ld::File::AtomHandler& handler) const
+{
+ // Check each input library.
+ std::vector<LibraryInfo>::const_iterator libIterator = _searchLibraries.begin();
+
+
+ while (libIterator != _searchLibraries.end()) {
+ LibraryInfo lib = *libIterator;
+ if (lib.isDylib()) {
+ if (searchDylibs) {
+ ld::dylib::File *dylibFile = lib.dylib();
+ //fprintf(stderr, "searchLibraries(%s), looking in linked %s\n", name, dylibFile->path() );
+ if ( dylibFile->justInTimeforEachAtom(name, handler) ) {
+ // we found a definition in this dylib
+ // done, unless it is a weak definition in which case we keep searching
+ _options.snapshot().recordDylibSymbol(dylibFile, name);
+ if ( !dylibFile->hasWeakExternals() || !dylibFile->hasWeakDefinition(name)) {
+ return true;
+ }
+ // else continue search for a non-weak definition
+ }
+ }
+ } else {
+ if (searchArchives) {
+ ld::archive::File *archiveFile = lib.archive();
+ if ( dataSymbolOnly ) {
+ if ( archiveFile->justInTimeDataOnlyforEachAtom(name, handler) ) {
+ if ( _options.traceArchives() )
+ logArchive(archiveFile);
+ _options.snapshot().recordArchive(archiveFile->path());
+ // found data definition in static library, done
+ return true;
+ }
+ }
+ else {
+ if ( archiveFile->justInTimeforEachAtom(name, handler) ) {
+ if ( _options.traceArchives() )
+ logArchive(archiveFile);
+ _options.snapshot().recordArchive(archiveFile->path());
+ // found definition in static library, done
+ return true;
+ }
+ }
+ }
+ }
+ libIterator++;
+ }
+
+ // search indirect dylibs
+ if ( searchDylibs ) {
+ for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) {
+ ld::dylib::File* dylibFile = it->second;
+ bool searchThisDylib = false;
+ if ( _options.nameSpace() == Options::kTwoLevelNameSpace ) {
+ // for two level namesapce, just check all implicitly linked dylibs
+ searchThisDylib = dylibFile->implicitlyLinked() && !dylibFile->explicitlyLinked();
+ }
+ else {
+ // for flat namespace, check all indirect dylibs
+ searchThisDylib = ! dylibFile->explicitlyLinked();
+ }
+ if ( searchThisDylib ) {
+ //fprintf(stderr, "searchLibraries(%s), looking in implicitly linked %s\n", name, dylibFile->path() );
+ if ( dylibFile->justInTimeforEachAtom(name, handler) ) {
+ // we found a definition in this dylib
+ // done, unless it is a weak definition in which case we keep searching
+ _options.snapshot().recordDylibSymbol(dylibFile, name);
+ if ( !dylibFile->hasWeakExternals() || !dylibFile->hasWeakDefinition(name)) {
+ return true;
+ }
+ // else continue search for a non-weak definition
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+
+bool InputFiles::searchWeakDefInDylib(const char* name) const
+{
+ // search all relevant dylibs to see if any of a weak-def with this name
+ for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) {
+ ld::dylib::File* dylibFile = it->second;
+ if ( dylibFile->implicitlyLinked() || dylibFile->explicitlyLinked() ) {
+ if ( dylibFile->hasWeakExternals() && dylibFile->hasWeakDefinition(name) ) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool vectorContains(const std::vector<ld::dylib::File*>& vec, ld::dylib::File* key)
+{
+ return std::find(vec.begin(), vec.end(), key) != vec.end();
+}
+
+void InputFiles::dylibs(ld::Internal& state)
+{
+ bool dylibsOK = false;
+ switch ( _options.outputKind() ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ dylibsOK = true;
+ break;
+ case Options::kStaticExecutable:
+ case Options::kDyld:
+ case Options::kPreload:
+ case Options::kObjectFile:
+ case Options::kKextBundle:
+ dylibsOK = false;
+ break;
+ }
+
+ // add command line dylibs in order
+ for (std::vector<ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); ++it) {
+ ld::dylib::File* dylibFile = dynamic_cast<ld::dylib::File*>(*it);
+ // only add dylibs that are not "blank" dylib stubs
+ if ( (dylibFile != NULL) && ((dylibFile->installPath() != NULL) || (dylibFile == _bundleLoader)) ) {
+ if ( dylibsOK ) {
+ if ( ! vectorContains(state.dylibs, dylibFile) ) {
+ state.dylibs.push_back(dylibFile);
+ }
+ }
+ else
+ warning("unexpected dylib (%s) on link line", dylibFile->path());
+ }
+ }
+ // add implicitly linked dylibs
+ if ( _options.nameSpace() == Options::kTwoLevelNameSpace ) {
+ for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) {
+ ld::dylib::File* dylibFile = it->second;
+ if ( dylibFile->implicitlyLinked() && dylibsOK ) {
+ if ( ! vectorContains(state.dylibs, dylibFile) ) {
+ state.dylibs.push_back(dylibFile);
+ }
+ }
+ }
+ }
+
+ //fprintf(stderr, "all dylibs:\n");
+ //for(std::vector<ld::dylib::File*>::iterator it=state.dylibs.begin(); it != state.dylibs.end(); ++it) {
+ // const ld::dylib::File* dylib = *it;
+ // fprintf(stderr, " %p %s\n", dylib, dylib->path());
+ //}
+
+ // and -bundle_loader
+ state.bundleLoader = _bundleLoader;
+
+ // <rdar://problem/10807040> give an error when -nostdlib is used and libSystem is missing
+ if ( (state.dylibs.size() == 0) && _options.needsEntryPointLoadCommand() )
+ throw "dynamic main executables must link with libSystem.dylib";
+}
+
+
+} // namespace tool
+} // namespace ld
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __INPUT_FILES_H__
+#define __INPUT_FILES_H__
+
+#define HAVE_PTHREADS 1
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+#if HAVE_PTHREADS
+#include <pthread.h>
+#endif
+
+#include <vector>
+
+#include "Options.h"
+#include "ld.hpp"
+
+namespace ld {
+namespace tool {
+
+class InputFiles : public ld::dylib::File::DylibHandler
+{
+public:
+ InputFiles(Options& opts, const char** archName);
+
+ // implementation from ld::dylib::File::DylibHandler
+ virtual ld::dylib::File* findDylib(const char* installPath, const char* fromPath);
+
+ // iterates all atoms in initial files
+ void forEachInitialAtom(ld::File::AtomHandler&);
+ // searches libraries for name
+ bool searchLibraries(const char* name, bool searchDylibs, bool searchArchives,
+ bool dataSymbolOnly, ld::File::AtomHandler&) const;
+ // see if any linked dylibs export a weak def of symbol
+ bool searchWeakDefInDylib(const char* name) const;
+ // copy dylibs to link with in command line order
+ void dylibs(ld::Internal& state);
+
+ bool inferredArch() const { return _inferredArch; }
+
+ // for -print_statistics
+ volatile int64_t _totalObjectSize;
+ volatile int64_t _totalArchiveSize;
+ volatile int32_t _totalObjectLoaded;
+ volatile int32_t _totalArchivesLoaded;
+ volatile int32_t _totalDylibsLoaded;
+
+
+private:
+ void inferArchitecture(Options& opts, const char** archName);
+ const char* fileArch(const uint8_t* p, unsigned len);
+ ld::File* makeFile(const Options::FileInfo& info, bool indirectDylib);
+ ld::File* addDylib(ld::dylib::File* f, const Options::FileInfo& info);
+ void logTraceInfo (const char* format, ...) const;
+ void logDylib(ld::File*, bool indirect);
+ void logArchive(ld::File*) const;
+ void createIndirectDylibs();
+ void checkDylibClientRestrictions(ld::dylib::File*);
+ void createOpaqueFileSections();
+
+ // for pipelined linking
+ void waitForInputFiles();
+ static void waitForInputFiles(InputFiles *inputFiles);
+
+ // for threaded input file processing
+ void parseWorkerThread();
+ static void parseWorkerThread(InputFiles *inputFiles);
+ void startThread(void (*threadFunc)(InputFiles *)) const;
+
+ class CStringEquals {
+ public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+ };
+ typedef __gnu_cxx::hash_map<const char*, ld::dylib::File*, __gnu_cxx::hash<const char*>, CStringEquals> InstallNameToDylib;
+
+ const Options& _options;
+ std::vector<ld::File*> _inputFiles;
+ mutable std::set<class ld::File*> _archiveFilesLogged;
+ InstallNameToDylib _installPathToDylibs;
+ std::set<ld::dylib::File*> _allDylibs;
+ ld::dylib::File* _bundleLoader;
+ bool _allDirectDylibsLoaded;
+ bool _inferredArch;
+ int _fileMonitor;
+ struct strcompclass {
+ bool operator() (const char *a, const char *b) const { return ::strcmp(a, b) < 0; }
+ };
+
+ // for threaded input file processing
+#if HAVE_PTHREADS
+ pthread_mutex_t _parseLock;
+ pthread_cond_t _parseWorkReady; // used by parse threads to block for work
+ pthread_cond_t _newFileAvailable; // used by main thread to block for parsed input files
+ int _availableWorkers; // number of remaining unstarted parse threads
+ int _idleWorkers; // number of running parse threads that are idle
+ int _neededFileSlot; // input file the resolver is currently blocked waiting for
+ int _parseCursor; // slot to begin searching for a file to parse
+ int _availableInputFiles; // number of input fileinfos with readyToParse==true
+#endif
+ const char * _exception; // passes an exception message from parse thread to main thread
+ int _remainingInputFiles; // number of input files still to parse
+
+ ld::File::Ordinal _indirectDylibOrdinal;
+
+ class LibraryInfo {
+ ld::File* _lib;
+ bool _isDylib;
+ public:
+ LibraryInfo(ld::dylib::File* dylib) : _lib(dylib), _isDylib(true) {};
+ LibraryInfo(ld::archive::File* dylib) : _lib(dylib), _isDylib(false) {};
+
+ bool isDylib() { return _isDylib; }
+ ld::dylib::File *dylib() { return (ld::dylib::File*)_lib; }
+ ld::archive::File *archive() { return (ld::archive::File*)_lib; }
+ };
+ std::vector<LibraryInfo> _searchLibraries;
+};
+
+} // namespace tool
+} // namespace ld
+
+#endif // __INPUT_FILES_H__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __LINKEDIT_HPP__
+#define __LINKEDIT_HPP__
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "Options.h"
+#include "ld.hpp"
+#include "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+#include "code-sign-blobs/superblob.h"
+
+namespace ld {
+namespace tool {
+
+class ByteStream {
+private:
+ std::vector<uint8_t> _data;
+public:
+ std::vector<uint8_t>& bytes() { return _data; }
+ unsigned long size() const { return _data.size(); }
+ void reserve(unsigned long l) { _data.reserve(l); }
+ const uint8_t* start() const { return &_data[0]; }
+
+ void append_uleb128(uint64_t value) {
+ uint8_t byte;
+ do {
+ byte = value & 0x7F;
+ value &= ~0x7F;
+ if ( value != 0 )
+ byte |= 0x80;
+ _data.push_back(byte);
+ value = value >> 7;
+ } while( byte >= 0x80 );
+ }
+
+ void append_sleb128(int64_t value) {
+ bool isNeg = ( value < 0 );
+ uint8_t byte;
+ bool more;
+ do {
+ byte = value & 0x7F;
+ value = value >> 7;
+ if ( isNeg )
+ more = ( (value != -1) || ((byte & 0x40) == 0) );
+ else
+ more = ( (value != 0) || ((byte & 0x40) != 0) );
+ if ( more )
+ byte |= 0x80;
+ _data.push_back(byte);
+ }
+ while( more );
+ }
+
+ void append_string(const char* str) {
+ for (const char* s = str; *s != '\0'; ++s)
+ _data.push_back(*s);
+ _data.push_back('\0');
+ }
+
+ void append_byte(uint8_t byte) {
+ _data.push_back(byte);
+ }
+
+ static unsigned int uleb128_size(uint64_t value) {
+ uint32_t result = 0;
+ do {
+ value = value >> 7;
+ ++result;
+ } while ( value != 0 );
+ return result;
+ }
+
+ void pad_to_size(unsigned int alignment) {
+ while ( (_data.size() % alignment) != 0 )
+ _data.push_back(0);
+ }
+};
+
+
+class LinkEditAtom : public ld::Atom
+{
+public:
+
+ // overrides of ld::Atom
+ virtual ld::File* file() const { return NULL; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual uint64_t size() const;
+ virtual void copyRawContent(uint8_t buffer[]) const;
+
+ virtual void encode() const = 0;
+
+ LinkEditAtom(const Options& opts, ld::Internal& state,
+ OutputFile& writer, const ld::Section& sect,
+ unsigned int pointerSize)
+ : ld::Atom(sect, ld::Atom::definitionRegular,
+ ld::Atom::combineNever, ld::Atom::scopeTranslationUnit,
+ ld::Atom::typeUnclassified, ld::Atom::symbolTableNotIn,
+ false, false, false, ld::Atom::Alignment(log2(pointerSize))),
+ _options(opts), _state(state), _writer(writer),
+ _encoded(false) { }
+protected:
+ const Options& _options;
+ ld::Internal& _state;
+ OutputFile& _writer;
+ mutable ByteStream _encodedData;
+ mutable bool _encoded;
+};
+
+uint64_t LinkEditAtom::size() const
+{
+ assert(_encoded);
+ return _encodedData.size();
+}
+
+void LinkEditAtom::copyRawContent(uint8_t buffer[]) const
+{
+ assert(_encoded);
+ memcpy(buffer, _encodedData.start(), _encodedData.size());
+}
+
+
+
+
+template <typename A>
+class RebaseInfoAtom : public LinkEditAtom
+{
+public:
+ RebaseInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { _encoded = true; }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "rebase info"; }
+ // overrides of LinkEditAtom
+ virtual void encode() const;
+
+private:
+ struct rebase_tmp
+ {
+ rebase_tmp(uint8_t op, uint64_t p1, uint64_t p2=0) : opcode(op), operand1(p1), operand2(p2) {}
+ uint8_t opcode;
+ uint64_t operand1;
+ uint64_t operand2;
+ };
+
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section RebaseInfoAtom<A>::_s_section("__LINKEDIT", "__rebase", ld::Section::typeLinkEdit, true);
+
+
+template <typename A>
+void RebaseInfoAtom<A>::encode() const
+{
+ // omit relocs if this was supposed to be PIE but PIE not possible
+ if ( _options.positionIndependentExecutable() && this->_writer.pieDisabled )
+ return;
+
+ // sort rebase info by type, then address
+ std::vector<OutputFile::RebaseInfo>& info = this->_writer._rebaseInfo;
+ std::sort(info.begin(), info.end());
+
+ // convert to temp encoding that can be more easily optimized
+ std::vector<rebase_tmp> mid;
+ uint64_t curSegStart = 0;
+ uint64_t curSegEnd = 0;
+ uint32_t curSegIndex = 0;
+ uint8_t type = 0;
+ uint64_t address = (uint64_t)(-1);
+ for (std::vector<OutputFile::RebaseInfo>::iterator it = info.begin(); it != info.end(); ++it) {
+ if ( type != it->_type ) {
+ mid.push_back(rebase_tmp(REBASE_OPCODE_SET_TYPE_IMM, it->_type));
+ type = it->_type;
+ }
+ if ( address != it->_address ) {
+ if ( (it->_address < curSegStart) || ( it->_address >= curSegEnd) ) {
+ if ( ! this->_writer.findSegment(this->_state, it->_address, &curSegStart, &curSegEnd, &curSegIndex) )
+ throw "binding address outside range of any segment";
+ mid.push_back(rebase_tmp(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, curSegIndex, it->_address - curSegStart));
+ }
+ else {
+ mid.push_back(rebase_tmp(REBASE_OPCODE_ADD_ADDR_ULEB, it->_address-address));
+ }
+ address = it->_address;
+ }
+ mid.push_back(rebase_tmp(REBASE_OPCODE_DO_REBASE_ULEB_TIMES, 1));
+ address += sizeof(pint_t);
+ }
+ mid.push_back(rebase_tmp(REBASE_OPCODE_DONE, 0));
+
+ // optimize phase 1, compress packed runs of pointers
+ rebase_tmp* dst = &mid[0];
+ for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
+ if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (src->operand1 == 1) ) {
+ *dst = *src++;
+ while (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES ) {
+ dst->operand1 += src->operand1;
+ ++src;
+ }
+ --src;
+ ++dst;
+ }
+ else {
+ *dst++ = *src;
+ }
+ }
+ dst->opcode = REBASE_OPCODE_DONE;
+
+ // optimize phase 2, combine rebase/add pairs
+ dst = &mid[0];
+ for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
+ if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES)
+ && (src->operand1 == 1)
+ && (src[1].opcode == REBASE_OPCODE_ADD_ADDR_ULEB)) {
+ dst->opcode = REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB;
+ dst->operand1 = src[1].operand1;
+ ++src;
+ ++dst;
+ }
+ else {
+ *dst++ = *src;
+ }
+ }
+ dst->opcode = REBASE_OPCODE_DONE;
+
+ // optimize phase 3, compress packed runs of REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB with
+ // same addr delta into one REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
+ dst = &mid[0];
+ for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
+ uint64_t delta = src->operand1;
+ if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
+ && (src[1].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
+ && (src[2].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
+ && (src[1].operand1 == delta)
+ && (src[2].operand1 == delta) ) {
+ // found at least three in a row, this is worth compressing
+ dst->opcode = REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB;
+ dst->operand1 = 1;
+ dst->operand2 = delta;
+ ++src;
+ while ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
+ && (src->operand1 == delta) ) {
+ dst->operand1++;
+ ++src;
+ }
+ --src;
+ ++dst;
+ }
+ else {
+ *dst++ = *src;
+ }
+ }
+ dst->opcode = REBASE_OPCODE_DONE;
+
+ // optimize phase 4, use immediate encodings
+ for (rebase_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
+ if ( (p->opcode == REBASE_OPCODE_ADD_ADDR_ULEB)
+ && (p->operand1 < (15*sizeof(pint_t)))
+ && ((p->operand1 % sizeof(pint_t)) == 0) ) {
+ p->opcode = REBASE_OPCODE_ADD_ADDR_IMM_SCALED;
+ p->operand1 = p->operand1/sizeof(pint_t);
+ }
+ else if ( (p->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (p->operand1 < 15) ) {
+ p->opcode = REBASE_OPCODE_DO_REBASE_IMM_TIMES;
+ }
+ }
+
+ // convert to compressed encoding
+ const static bool log = false;
+ this->_encodedData.reserve(info.size()*2);
+ bool done = false;
+ for (typename std::vector<rebase_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
+ switch ( it->opcode ) {
+ case REBASE_OPCODE_DONE:
+ if ( log ) fprintf(stderr, "REBASE_OPCODE_DONE()\n");
+ done = true;
+ break;
+ case REBASE_OPCODE_SET_TYPE_IMM:
+ if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
+ this->_encodedData.append_byte(REBASE_OPCODE_SET_TYPE_IMM | it->operand1);
+ break;
+ case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
+ this->_encodedData.append_byte(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
+ this->_encodedData.append_uleb128(it->operand2);
+ break;
+ case REBASE_OPCODE_ADD_ADDR_ULEB:
+ if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
+ this->_encodedData.append_byte(REBASE_OPCODE_ADD_ADDR_ULEB);
+ this->_encodedData.append_uleb128(it->operand1);
+ break;
+ case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+ if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
+ this->_encodedData.append_byte(REBASE_OPCODE_ADD_ADDR_IMM_SCALED | it->operand1 );
+ break;
+ case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+ if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_IMM_TIMES(%lld)\n", it->operand1);
+ this->_encodedData.append_byte(REBASE_OPCODE_DO_REBASE_IMM_TIMES | it->operand1);
+ break;
+ case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+ if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%lld)\n", it->operand1);
+ this->_encodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
+ this->_encodedData.append_uleb128(it->operand1);
+ break;
+ case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+ if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
+ this->_encodedData.append_byte(REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
+ this->_encodedData.append_uleb128(it->operand1);
+ break;
+ case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
+ if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
+ this->_encodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
+ this->_encodedData.append_uleb128(it->operand1);
+ this->_encodedData.append_uleb128(it->operand2);
+ break;
+ }
+ }
+
+
+ // align to pointer size
+ this->_encodedData.pad_to_size(sizeof(pint_t));
+
+ this->_encoded = true;
+
+ if (log) fprintf(stderr, "total rebase info size = %ld\n", this->_encodedData.size());
+}
+
+
+template <typename A>
+class BindingInfoAtom : public LinkEditAtom
+{
+public:
+ BindingInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "binding info"; }
+ // overrides of LinkEditAtom
+ virtual void encode() const;
+
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ struct binding_tmp
+ {
+ binding_tmp(uint8_t op, uint64_t p1, uint64_t p2=0, const char* s=NULL)
+ : opcode(op), operand1(p1), operand2(p2), name(s) {}
+ uint8_t opcode;
+ uint64_t operand1;
+ uint64_t operand2;
+ const char* name;
+ };
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section BindingInfoAtom<A>::_s_section("__LINKEDIT", "__binding", ld::Section::typeLinkEdit, true);
+
+
+template <typename A>
+void BindingInfoAtom<A>::encode() const
+{
+ // sort by library, symbol, type, then address
+ std::vector<OutputFile::BindingInfo>& info = this->_writer._bindingInfo;
+ std::sort(info.begin(), info.end());
+
+ // convert to temp encoding that can be more easily optimized
+ std::vector<binding_tmp> mid;
+ uint64_t curSegStart = 0;
+ uint64_t curSegEnd = 0;
+ uint32_t curSegIndex = 0;
+ int ordinal = 0x80000000;
+ const char* symbolName = NULL;
+ uint8_t type = 0;
+ uint64_t address = (uint64_t)(-1);
+ int64_t addend = 0;
+ for (std::vector<OutputFile::BindingInfo>::const_iterator it = info.begin(); it != info.end(); ++it) {
+ if ( ordinal != it->_libraryOrdinal ) {
+ if ( it->_libraryOrdinal <= 0 ) {
+ // special lookups are encoded as negative numbers in BindingInfo
+ mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM, it->_libraryOrdinal));
+ }
+ else {
+ mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB, it->_libraryOrdinal));
+ }
+ ordinal = it->_libraryOrdinal;
+ }
+ if ( symbolName != it->_symbolName ) {
+ mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->_flags, 0, it->_symbolName));
+ symbolName = it->_symbolName;
+ }
+ if ( type != it->_type ) {
+ mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->_type));
+ type = it->_type;
+ }
+ if ( address != it->_address ) {
+ if ( (it->_address < curSegStart) || ( it->_address >= curSegEnd) ) {
+ if ( ! this->_writer.findSegment(this->_state, it->_address, &curSegStart, &curSegEnd, &curSegIndex) )
+ throw "binding address outside range of any segment";
+ mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, curSegIndex, it->_address - curSegStart));
+ }
+ else {
+ mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->_address-address));
+ }
+ address = it->_address;
+ }
+ if ( addend != it->_addend ) {
+ mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->_addend));
+ addend = it->_addend;
+ }
+ mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
+ address += sizeof(pint_t);
+ }
+ mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
+
+
+ // optimize phase 1, combine bind/add pairs
+ binding_tmp* dst = &mid[0];
+ for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
+ if ( (src->opcode == BIND_OPCODE_DO_BIND)
+ && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
+ dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
+ dst->operand1 = src[1].operand1;
+ ++src;
+ ++dst;
+ }
+ else {
+ *dst++ = *src;
+ }
+ }
+ dst->opcode = BIND_OPCODE_DONE;
+
+ // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
+ // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
+ dst = &mid[0];
+ for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
+ uint64_t delta = src->operand1;
+ if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
+ && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
+ && (src[1].operand1 == delta) ) {
+ // found at least two in a row, this is worth compressing
+ dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
+ dst->operand1 = 1;
+ dst->operand2 = delta;
+ ++src;
+ while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
+ && (src->operand1 == delta) ) {
+ dst->operand1++;
+ ++src;
+ }
+ --src;
+ ++dst;
+ }
+ else {
+ *dst++ = *src;
+ }
+ }
+ dst->opcode = BIND_OPCODE_DONE;
+
+ // optimize phase 3, use immediate encodings
+ for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
+ if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
+ && (p->operand1 < (15*sizeof(pint_t)))
+ && ((p->operand1 % sizeof(pint_t)) == 0) ) {
+ p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
+ p->operand1 = p->operand1/sizeof(pint_t);
+ }
+ else if ( (p->opcode == BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB) && (p->operand1 <= 15) ) {
+ p->opcode = BIND_OPCODE_SET_DYLIB_ORDINAL_IMM;
+ }
+ }
+ dst->opcode = BIND_OPCODE_DONE;
+
+ // convert to compressed encoding
+ const static bool log = false;
+ this->_encodedData.reserve(info.size()*2);
+ bool done = false;
+ for (typename std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
+ switch ( it->opcode ) {
+ case BIND_OPCODE_DONE:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
+ done = true;
+ break;
+ case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
+ this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
+ break;
+ case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
+ this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
+ this->_encodedData.append_uleb128(it->operand1);
+ break;
+ case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
+ this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
+ break;
+ case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
+ this->_encodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
+ this->_encodedData.append_string(it->name);
+ break;
+ case BIND_OPCODE_SET_TYPE_IMM:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
+ this->_encodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
+ break;
+ case BIND_OPCODE_SET_ADDEND_SLEB:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
+ this->_encodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
+ this->_encodedData.append_sleb128(it->operand1);
+ break;
+ case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
+ this->_encodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
+ this->_encodedData.append_uleb128(it->operand2);
+ break;
+ case BIND_OPCODE_ADD_ADDR_ULEB:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
+ this->_encodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
+ this->_encodedData.append_uleb128(it->operand1);
+ break;
+ case BIND_OPCODE_DO_BIND:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
+ this->_encodedData.append_byte(BIND_OPCODE_DO_BIND);
+ break;
+ case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
+ this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
+ this->_encodedData.append_uleb128(it->operand1);
+ break;
+ case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
+ this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
+ break;
+ case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
+ this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
+ this->_encodedData.append_uleb128(it->operand1);
+ this->_encodedData.append_uleb128(it->operand2);
+ break;
+ }
+ }
+
+ // align to pointer size
+ this->_encodedData.pad_to_size(sizeof(pint_t));
+
+ this->_encoded = true;
+
+ if (log) fprintf(stderr, "total binding info size = %ld\n", this->_encodedData.size());
+}
+
+
+
+template <typename A>
+class WeakBindingInfoAtom : public LinkEditAtom
+{
+public:
+ WeakBindingInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { _encoded = true; }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "weak binding info"; }
+ // overrides of LinkEditAtom
+ virtual void encode() const;
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ struct WeakBindingSorter
+ {
+ bool operator()(const OutputFile::BindingInfo& left, const OutputFile::BindingInfo& right)
+ {
+ // sort by symbol, type, address
+ if ( left._symbolName != right._symbolName )
+ return ( strcmp(left._symbolName, right._symbolName) < 0 );
+ if ( left._type != right._type )
+ return (left._type < right._type);
+ return (left._address < right._address);
+ }
+ };
+
+ struct binding_tmp
+ {
+ binding_tmp(uint8_t op, uint64_t p1, uint64_t p2=0, const char* s=NULL)
+ : opcode(op), operand1(p1), operand2(p2), name(s) {}
+ uint8_t opcode;
+ uint64_t operand1;
+ uint64_t operand2;
+ const char* name;
+ };
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section WeakBindingInfoAtom<A>::_s_section("__LINKEDIT", "__weak_binding", ld::Section::typeLinkEdit, true);
+
+
+template <typename A>
+void WeakBindingInfoAtom<A>::encode() const
+{
+ // sort by symbol, type, address
+ std::vector<OutputFile::BindingInfo>& info = this->_writer._weakBindingInfo;
+ if ( info.size() == 0 ) {
+ // short circuit if no weak binding needed
+ this->_encoded = true;
+ return;
+ }
+ std::sort(info.begin(), info.end(), WeakBindingSorter());
+
+ // convert to temp encoding that can be more easily optimized
+ std::vector<binding_tmp> mid;
+ mid.reserve(info.size());
+ uint64_t curSegStart = 0;
+ uint64_t curSegEnd = 0;
+ uint32_t curSegIndex = 0;
+ const char* symbolName = NULL;
+ uint8_t type = 0;
+ uint64_t address = (uint64_t)(-1);
+ int64_t addend = 0;
+ for (typename std::vector<OutputFile::BindingInfo>::const_iterator it = info.begin(); it != info.end(); ++it) {
+ if ( symbolName != it->_symbolName ) {
+ mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->_flags, 0, it->_symbolName));
+ symbolName = it->_symbolName;
+ }
+ // non-weak symbols just have BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+ // weak symbols have SET_SEG, ADD_ADDR, SET_ADDED, DO_BIND
+ if ( it->_type != BIND_TYPE_OVERRIDE_OF_WEAKDEF_IN_DYLIB ) {
+ if ( type != it->_type ) {
+ mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->_type));
+ type = it->_type;
+ }
+ if ( address != it->_address ) {
+ if ( (it->_address < curSegStart) || ( it->_address >= curSegEnd) ) {
+ if ( ! this->_writer.findSegment(this->_state, it->_address, &curSegStart, &curSegEnd, &curSegIndex) )
+ throw "binding address outside range of any segment";
+ mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, curSegIndex, it->_address - curSegStart));
+ }
+ else {
+ mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->_address-address));
+ }
+ address = it->_address;
+ }
+ if ( addend != it->_addend ) {
+ mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->_addend));
+ addend = it->_addend;
+ }
+ mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
+ address += sizeof(pint_t);
+ }
+ }
+ mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
+
+
+ // optimize phase 1, combine bind/add pairs
+ binding_tmp* dst = &mid[0];
+ for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
+ if ( (src->opcode == BIND_OPCODE_DO_BIND)
+ && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
+ dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
+ dst->operand1 = src[1].operand1;
+ ++src;
+ ++dst;
+ }
+ else {
+ *dst++ = *src;
+ }
+ }
+ dst->opcode = BIND_OPCODE_DONE;
+
+ // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
+ // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
+ dst = &mid[0];
+ for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
+ uint64_t delta = src->operand1;
+ if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
+ && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
+ && (src[1].operand1 == delta) ) {
+ // found at least two in a row, this is worth compressing
+ dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
+ dst->operand1 = 1;
+ dst->operand2 = delta;
+ ++src;
+ while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
+ && (src->operand1 == delta) ) {
+ dst->operand1++;
+ ++src;
+ }
+ --src;
+ ++dst;
+ }
+ else {
+ *dst++ = *src;
+ }
+ }
+ dst->opcode = BIND_OPCODE_DONE;
+
+ // optimize phase 3, use immediate encodings
+ for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
+ if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
+ && (p->operand1 < (15*sizeof(pint_t)))
+ && ((p->operand1 % sizeof(pint_t)) == 0) ) {
+ p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
+ p->operand1 = p->operand1/sizeof(pint_t);
+ }
+ }
+ dst->opcode = BIND_OPCODE_DONE;
+
+
+ // convert to compressed encoding
+ const static bool log = false;
+ this->_encodedData.reserve(info.size()*2);
+ bool done = false;
+ for (typename std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
+ switch ( it->opcode ) {
+ case BIND_OPCODE_DONE:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
+ this->_encodedData.append_byte(BIND_OPCODE_DONE);
+ done = true;
+ break;
+ case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
+ this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
+ break;
+ case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
+ this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
+ this->_encodedData.append_uleb128(it->operand1);
+ break;
+ case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
+ this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
+ break;
+ case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
+ this->_encodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
+ this->_encodedData.append_string(it->name);
+ break;
+ case BIND_OPCODE_SET_TYPE_IMM:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
+ this->_encodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
+ break;
+ case BIND_OPCODE_SET_ADDEND_SLEB:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
+ this->_encodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
+ this->_encodedData.append_sleb128(it->operand1);
+ break;
+ case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
+ this->_encodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
+ this->_encodedData.append_uleb128(it->operand2);
+ break;
+ case BIND_OPCODE_ADD_ADDR_ULEB:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
+ this->_encodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
+ this->_encodedData.append_uleb128(it->operand1);
+ break;
+ case BIND_OPCODE_DO_BIND:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
+ this->_encodedData.append_byte(BIND_OPCODE_DO_BIND);
+ break;
+ case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
+ this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
+ this->_encodedData.append_uleb128(it->operand1);
+ break;
+ case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
+ this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
+ break;
+ case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+ if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
+ this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
+ this->_encodedData.append_uleb128(it->operand1);
+ this->_encodedData.append_uleb128(it->operand2);
+ break;
+ }
+ }
+
+ // align to pointer size
+ this->_encodedData.pad_to_size(sizeof(pint_t));
+
+ this->_encoded = true;
+
+ if (log) fprintf(stderr, "total weak binding info size = %ld\n", this->_encodedData.size());
+
+}
+
+
+
+template <typename A>
+class LazyBindingInfoAtom : public LinkEditAtom
+{
+public:
+ LazyBindingInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) {_encoded = true; }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "lazy binding info"; }
+ // overrides of LinkEditAtom
+ virtual void encode() const;
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section LazyBindingInfoAtom<A>::_s_section("__LINKEDIT", "__lazy_binding", ld::Section::typeLinkEdit, true);
+
+
+
+template <typename A>
+void LazyBindingInfoAtom<A>::encode() const
+{
+ // stream all lazy bindings and record start offsets
+ std::vector<OutputFile::BindingInfo>& info = this->_writer._lazyBindingInfo;
+ for (std::vector<OutputFile::BindingInfo>::const_iterator it = info.begin(); it != info.end(); ++it) {
+ // record start offset for use by stub helper
+ this->_writer.setLazyBindingInfoOffset(it->_address, this->_encodedData.size());
+
+ // write address to bind
+ uint64_t segStart = 0;
+ uint64_t segEnd = 0;
+ uint32_t segIndex = 0;
+ if ( ! this->_writer.findSegment(this->_state, it->_address, &segStart, &segEnd, &segIndex) )
+ throw "lazy binding address outside range of any segment";
+ this->_encodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segIndex);
+ this->_encodedData.append_uleb128(it->_address - segStart);
+
+ // write ordinal
+ if ( it->_libraryOrdinal <= 0 ) {
+ // special lookups are encoded as negative numbers in BindingInfo
+ this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->_libraryOrdinal & BIND_IMMEDIATE_MASK) );
+ }
+ else if ( it->_libraryOrdinal <= 15 ) {
+ // small ordinals are encoded in opcode
+ this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->_libraryOrdinal);
+ }
+ else {
+ this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
+ this->_encodedData.append_uleb128(it->_libraryOrdinal);
+ }
+ // write symbol name
+ this->_encodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->_flags);
+ this->_encodedData.append_string(it->_symbolName);
+ // write do bind
+ this->_encodedData.append_byte(BIND_OPCODE_DO_BIND);
+ this->_encodedData.append_byte(BIND_OPCODE_DONE);
+ }
+
+ // align to pointer size
+ this->_encodedData.pad_to_size(sizeof(pint_t));
+
+ this->_encoded = true;
+ //fprintf(stderr, "lazy binding info size = %ld, for %ld entries\n", _encodedData.size(), allLazys.size());
+}
+
+
+
+template <typename A>
+class ExportInfoAtom : public LinkEditAtom
+{
+public:
+ ExportInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { _encoded = true; }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "export info"; }
+ // overrides of LinkEditAtom
+ virtual void encode() const;
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ const ld::Atom* stubForResolverFunction(const ld::Atom* resolver) const;
+
+ struct TrieEntriesSorter
+ {
+ TrieEntriesSorter(const Options& o) : _options(o) {}
+
+ bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
+ {
+ unsigned int leftOrder;
+ unsigned int rightOrder;
+ _options.exportedSymbolOrder(left.name, &leftOrder);
+ _options.exportedSymbolOrder(right.name, &rightOrder);
+ if ( leftOrder != rightOrder )
+ return (leftOrder < rightOrder);
+ else
+ return (left.address < right.address);
+ }
+ private:
+ const Options& _options;
+ };
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section ExportInfoAtom<A>::_s_section("__LINKEDIT", "__export", ld::Section::typeLinkEdit, true);
+
+template <typename A>
+const ld::Atom* ExportInfoAtom<A>::stubForResolverFunction(const ld::Atom* resolver) const
+{
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = _state.sections.begin(); sit != _state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( (sect->type() == ld::Section::typeStub) || (sect->type() == ld::Section::typeStubClose) ) {
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ if ( strcmp(atom->name(), resolver->name()) == 0 )
+ return atom;
+ }
+ }
+ }
+ assert(0 && "no stub for resolver function");
+ return NULL;
+}
+
+
+template <typename A>
+void ExportInfoAtom<A>::encode() const
+{
+ // make vector of mach_o::trie::Entry for all exported symbols
+ std::vector<const ld::Atom*>& exports = this->_writer._exportedAtoms;
+ uint64_t imageBaseAddress = this->_writer.headerAndLoadCommandsSection->address;
+ std::vector<mach_o::trie::Entry> entries;
+ entries.reserve(exports.size());
+ for (std::vector<const ld::Atom*>::const_iterator it = exports.begin(); it != exports.end(); ++it) {
+ const ld::Atom* atom = *it;
+ mach_o::trie::Entry entry;
+ uint64_t flags = (atom->contentType() == ld::Atom::typeTLV) ? EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL : EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
+ uint64_t other = 0;
+ uint64_t address = atom->finalAddress() - imageBaseAddress;
+ if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) )
+ flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
+ if ( atom->definition() == ld::Atom::definitionProxy ) {
+ entry.name = atom->name();
+ entry.flags = flags | EXPORT_SYMBOL_FLAGS_REEXPORT;
+ entry.other = this->_writer.compressedOrdinalForAtom(atom);
+ if ( entry.other == BIND_SPECIAL_DYLIB_SELF ) {
+ warning("not adding explict export for symbol %s because it is already re-exported from dylib %s", entry.name, atom->file()->path());
+ continue;
+ }
+ if ( atom->isAlias() ) {
+ // alias proxy means symbol was re-exported with a name change
+ const ld::Atom* aliasOf = NULL;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+ assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+ aliasOf = fit->u.target;
+ }
+ }
+ assert(aliasOf != NULL);
+ entry.importName = aliasOf->name();
+ }
+ else {
+ // symbol name stays same as re-export
+ entry.importName = atom->name();
+ }
+ entries.push_back(entry);
+ //fprintf(stderr, "re-export %s from lib %llu as %s\n", entry.importName, entry.other, entry.name);
+ }
+ else {
+ if ( atom->isThumb() )
+ address |= 1;
+ if ( atom->contentType() == ld::Atom::typeResolver ) {
+ flags |= EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER;
+ // set normal lookup to return stub address
+ // and add resolver function in new location that newer dyld's can access
+ other = address;
+ const ld::Atom* stub = stubForResolverFunction(atom);
+ address = stub->finalAddress() - imageBaseAddress;
+ if ( stub->isThumb() )
+ address |= 1;
+ }
+ entry.name = atom->name();
+ entry.flags = flags;
+ entry.address = address;
+ entry.other = other;
+ entry.importName = NULL;
+ entries.push_back(entry);
+ }
+ }
+
+ // sort vector by -exported_symbols_order, and any others by address
+ std::sort(entries.begin(), entries.end(), TrieEntriesSorter(_options));
+
+ // create trie
+ mach_o::trie::makeTrie(entries, this->_encodedData.bytes());
+
+ // align to pointer size
+ this->_encodedData.pad_to_size(sizeof(pint_t));
+
+ this->_encoded = true;
+}
+
+
+template <typename A>
+class SplitSegInfoAtom : public LinkEditAtom
+{
+public:
+ SplitSegInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "split seg info"; }
+ // overrides of LinkEditAtom
+ virtual void encode() const;
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ void addSplitSegInfo(uint64_t address, ld::Fixup::Kind k, uint32_t) const;
+ void uleb128EncodeAddresses(const std::vector<uint64_t>& locations) const;
+
+ mutable std::vector<uint64_t> _32bitPointerLocations;
+ mutable std::vector<uint64_t> _64bitPointerLocations;
+ mutable std::vector<uint64_t> _thumbLo16Locations;
+ mutable std::vector<uint64_t> _thumbHi16Locations[16];
+ mutable std::vector<uint64_t> _armLo16Locations;
+ mutable std::vector<uint64_t> _armHi16Locations[16];
+
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section SplitSegInfoAtom<A>::_s_section("__LINKEDIT", "__splitSegInfo", ld::Section::typeLinkEdit, true);
+
+template <>
+void SplitSegInfoAtom<x86_64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
+{
+ switch (kind) {
+ case ld::Fixup::kindStoreX86PCRel32:
+ case ld::Fixup::kindStoreX86PCRel32_1:
+ case ld::Fixup::kindStoreX86PCRel32_2:
+ case ld::Fixup::kindStoreX86PCRel32_4:
+ case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+ case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
+ case ld::Fixup::kindStoreX86PCRel32GOT:
+ case ld::Fixup::kindStoreLittleEndian32:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+ _32bitPointerLocations.push_back(address);
+ break;
+ case ld::Fixup::kindStoreLittleEndian64:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+ _64bitPointerLocations.push_back(address);
+ break;
+ default:
+ warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
+ break;
+ }
+}
+
+template <>
+void SplitSegInfoAtom<x86>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
+{
+ switch (kind) {
+ case ld::Fixup::kindStoreLittleEndian32:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ _32bitPointerLocations.push_back(address);
+ break;
+ default:
+ warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
+ break;
+ }
+}
+
+template <>
+void SplitSegInfoAtom<arm>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
+{
+ switch (kind) {
+ case ld::Fixup::kindStoreLittleEndian32:
+ _32bitPointerLocations.push_back(address);
+ break;
+ case ld::Fixup::kindStoreARMLow16:
+ _armLo16Locations.push_back(address);
+ break;
+ case ld::Fixup::kindStoreThumbLow16:
+ _thumbLo16Locations.push_back(address);
+ break;
+ case ld::Fixup::kindStoreARMHigh16:
+ assert(extra < 16);
+ _armHi16Locations[extra].push_back(address);
+ break;
+ case ld::Fixup::kindStoreThumbHigh16:
+ assert(extra < 16);
+ _thumbHi16Locations[extra].push_back(address);
+ break;
+ default:
+ warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
+ break;
+ }
+}
+
+
+
+template <typename A>
+void SplitSegInfoAtom<A>::uleb128EncodeAddresses(const std::vector<uint64_t>& locations) const
+{
+ pint_t addr = this->_options.baseAddress();
+ for(typename std::vector<uint64_t>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
+ pint_t nextAddr = *it;
+ //fprintf(stderr, "nextAddr=0x%0llX\n", (uint64_t)nextAddr);
+ uint64_t delta = nextAddr - addr;
+ //fprintf(stderr, "delta=0x%0llX\n", delta);
+ if ( delta == 0 )
+ throw "double split seg info for same address";
+ // uleb128 encode
+ uint8_t byte;
+ do {
+ byte = delta & 0x7F;
+ delta &= ~0x7F;
+ if ( delta != 0 )
+ byte |= 0x80;
+ this->_encodedData.append_byte(byte);
+ delta = delta >> 7;
+ }
+ while( byte >= 0x80 );
+ addr = nextAddr;
+ }
+}
+
+
+template <typename A>
+void SplitSegInfoAtom<A>::encode() const
+{
+ // sort into group by pointer adjustment kind
+ std::vector<OutputFile::SplitSegInfoEntry>& info = this->_writer._splitSegInfos;
+ for (std::vector<OutputFile::SplitSegInfoEntry>::const_iterator it = info.begin(); it != info.end(); ++it) {
+ this->addSplitSegInfo(it->address, it->kind, it->extra);
+ }
+
+ // delta compress runs of addresses
+ this->_encodedData.reserve(8192);
+ if ( _32bitPointerLocations.size() != 0 ) {
+ this->_encodedData.append_byte(1);
+ //fprintf(stderr, "type 1:\n");
+ std::sort(_32bitPointerLocations.begin(), _32bitPointerLocations.end());
+ this->uleb128EncodeAddresses(_32bitPointerLocations);
+ this->_encodedData.append_byte(0); // terminator
+ }
+
+ if ( _64bitPointerLocations.size() != 0 ) {
+ this->_encodedData.append_byte(2);
+ //fprintf(stderr, "type 2:\n");
+ std::sort(_64bitPointerLocations.begin(), _64bitPointerLocations.end());
+ this->uleb128EncodeAddresses(_64bitPointerLocations);
+ this->_encodedData.append_byte(0); // terminator
+ }
+
+ if ( _thumbLo16Locations.size() != 0 ) {
+ this->_encodedData.append_byte(5);
+ //fprintf(stderr, "type 5:\n");
+ std::sort(_thumbLo16Locations.begin(), _thumbLo16Locations.end());
+ this->uleb128EncodeAddresses(_thumbLo16Locations);
+ this->_encodedData.append_byte(0); // terminator
+ }
+
+ if ( _armLo16Locations.size() != 0 ) {
+ this->_encodedData.append_byte(6);
+ //fprintf(stderr, "type 6:\n");
+ std::sort(_armLo16Locations.begin(), _armLo16Locations.end());
+ this->uleb128EncodeAddresses(_armLo16Locations);
+ this->_encodedData.append_byte(0); // terminator
+ }
+
+ for (uint32_t i=0; i < 16; ++i) {
+ if ( _thumbHi16Locations[i].size() != 0 ) {
+ this->_encodedData.append_byte(16+i);
+ //fprintf(stderr, "type 16+%d:\n", i);
+ std::sort(_thumbHi16Locations[i].begin(), _thumbHi16Locations[i].end());
+ this->uleb128EncodeAddresses(_thumbHi16Locations[i]);
+ this->_encodedData.append_byte(0); // terminator
+ }
+ }
+
+ for (uint32_t i=0; i < 16; ++i) {
+ if ( _armHi16Locations[i].size() != 0 ) {
+ this->_encodedData.append_byte(32+i);
+ //fprintf(stderr, "type 32+%d:\n", i);
+ std::sort(_armHi16Locations[i].begin(), _armHi16Locations[i].end());
+ this->uleb128EncodeAddresses(_armHi16Locations[i]);
+ this->_encodedData.append_byte(0); // terminator
+ }
+ }
+
+ // always add zero byte to mark end
+ this->_encodedData.append_byte(0);
+
+ // align to pointer size
+ this->_encodedData.pad_to_size(sizeof(pint_t));
+
+ this->_encoded = true;
+
+ // clean up temporaries
+ _32bitPointerLocations.clear();
+ _64bitPointerLocations.clear();
+}
+
+template <typename A>
+class FunctionStartsAtom : public LinkEditAtom
+{
+public:
+ FunctionStartsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "function starts"; }
+ // overrides of LinkEditAtom
+ virtual void encode() const;
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section FunctionStartsAtom<A>::_s_section("__LINKEDIT", "__funcStarts", ld::Section::typeLinkEdit, true);
+
+
+template <typename A>
+void FunctionStartsAtom<A>::encode() const
+{
+ this->_encodedData.reserve(8192);
+ const uint64_t badAddress = 0xFFFFFFFFFFFFFFFF;
+ uint64_t addr = badAddress;
+ // delta compress all function addresses
+ for (std::vector<ld::Internal::FinalSection*>::iterator it = this->_state.sections.begin(); it != this->_state.sections.end(); ++it) {
+ ld::Internal::FinalSection* sect = *it;
+ if ( sect->type() == ld::Section::typeMachHeader ) {
+ // start with delta from start of __TEXT
+ addr = sect->address;
+ }
+ else if ( sect->type() == ld::Section::typeCode ) {
+ assert(addr != badAddress);
+ std::vector<const ld::Atom*>& atoms = sect->atoms;
+ for (std::vector<const ld::Atom*>::iterator ait = atoms.begin(); ait != atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ // <rdar://problem/10422823> filter out zero-length atoms, so LC_FUNCTION_STARTS address can't spill into next section
+ if ( atom->size() == 0 )
+ continue;
+ uint64_t nextAddr = atom->finalAddress();
+ if ( atom->isThumb() )
+ nextAddr |= 1;
+ uint64_t delta = nextAddr - addr;
+ if ( delta != 0 )
+ this->_encodedData.append_uleb128(delta);
+ addr = nextAddr;
+ }
+ }
+ }
+
+ // terminator
+ this->_encodedData.append_byte(0);
+
+ // align to pointer size
+ this->_encodedData.pad_to_size(sizeof(pint_t));
+
+ this->_encoded = true;
+}
+
+
+// <rdar://problem/9218847> Need way to formalize data in code
+template <typename A>
+class DataInCodeAtom : public LinkEditAtom
+{
+public:
+ DataInCodeAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "data-in-code info"; }
+ // overrides of LinkEditAtom
+ virtual void encode() const;
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ struct FixupByAddressSorter
+ {
+ bool operator()(const ld::Fixup* left, const ld::Fixup* right)
+ {
+ return (left->offsetInAtom < right->offsetInAtom);
+ }
+ };
+
+ void encodeEntry(uint32_t startImageOffset, int len, ld::Fixup::Kind kind) const {
+ //fprintf(stderr, "encodeEntry(start=0x%08X, len=0x%04X, kind=%04X\n", startImageOffset, len, kind);
+ do {
+ macho_data_in_code_entry<P> entry;
+ entry.set_offset(startImageOffset);
+ entry.set_length(len);
+ switch ( kind ) {
+ case ld::Fixup::kindDataInCodeStartData:
+ entry.set_kind(DICE_KIND_DATA);
+ break;
+ case ld::Fixup::kindDataInCodeStartJT8:
+ entry.set_kind(DICE_KIND_JUMP_TABLE8);
+ break;
+ case ld::Fixup::kindDataInCodeStartJT16:
+ entry.set_kind(DICE_KIND_JUMP_TABLE16);
+ break;
+ case ld::Fixup::kindDataInCodeStartJT32:
+ entry.set_kind(DICE_KIND_JUMP_TABLE32);
+ break;
+ case ld::Fixup::kindDataInCodeStartJTA32:
+ entry.set_kind(DICE_KIND_ABS_JUMP_TABLE32);
+ break;
+ default:
+ assert(0 && "bad L$start$ label to encode");
+ }
+ uint8_t* bp = (uint8_t*)&entry;
+ this->_encodedData.append_byte(bp[0]);
+ this->_encodedData.append_byte(bp[1]);
+ this->_encodedData.append_byte(bp[2]);
+ this->_encodedData.append_byte(bp[3]);
+ this->_encodedData.append_byte(bp[4]);
+ this->_encodedData.append_byte(bp[5]);
+ this->_encodedData.append_byte(bp[6]);
+ this->_encodedData.append_byte(bp[7]);
+ // in rare case data range is huge, create multiple entries
+ len -= 0xFFF8;
+ startImageOffset += 0xFFF8;
+ } while ( len > 0 );
+ }
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section DataInCodeAtom<A>::_s_section("__LINKEDIT", "__dataInCode", ld::Section::typeLinkEdit, true);
+
+
+template <typename A>
+void DataInCodeAtom<A>::encode() const
+{
+ if ( this->_writer.hasDataInCode ) {
+ uint64_t mhAddress = 0;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = _state.sections.begin(); sit != _state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() == ld::Section::typeMachHeader )
+ mhAddress = sect->address;
+ if ( sect->type() != ld::Section::typeCode )
+ continue;
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ // gather all code-in-data labels
+ std::vector<const ld::Fixup*> dataInCodeLabels;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ switch ( fit->kind ) {
+ case ld::Fixup::kindDataInCodeStartData:
+ case ld::Fixup::kindDataInCodeStartJT8:
+ case ld::Fixup::kindDataInCodeStartJT16:
+ case ld::Fixup::kindDataInCodeStartJT32:
+ case ld::Fixup::kindDataInCodeStartJTA32:
+ case ld::Fixup::kindDataInCodeEnd:
+ dataInCodeLabels.push_back(fit);
+ break;
+ default:
+ break;
+ }
+ }
+ // to do: sort labels by address
+ std::sort(dataInCodeLabels.begin(), dataInCodeLabels.end(), FixupByAddressSorter());
+
+ // convert to array of struct data_in_code_entry
+ ld::Fixup::Kind prevKind = ld::Fixup::kindDataInCodeEnd;
+ uint32_t prevOffset = 0;
+ for ( std::vector<const ld::Fixup*>::iterator sfit = dataInCodeLabels.begin(); sfit != dataInCodeLabels.end(); ++sfit) {
+ if ( ((*sfit)->kind != prevKind) && (prevKind != ld::Fixup::kindDataInCodeEnd) ) {
+ int len = (*sfit)->offsetInAtom - prevOffset;
+ if ( len == 0 )
+ warning("multiple L$start$ labels found at same address in %s at offset 0x%04X", atom->name(), prevOffset);
+ this->encodeEntry(atom->finalAddress()+prevOffset-mhAddress, (*sfit)->offsetInAtom - prevOffset, prevKind);
+ }
+ prevKind = (*sfit)->kind;
+ prevOffset = (*sfit)->offsetInAtom;
+ }
+ if ( prevKind != ld::Fixup::kindDataInCodeEnd ) {
+ // add entry if function ends with data
+ this->encodeEntry(atom->finalAddress()+prevOffset-mhAddress, atom->size() - prevOffset, prevKind);
+ }
+ }
+ }
+ }
+
+ this->_encoded = true;
+}
+
+
+
+
+
+// <rdar://problem/7209249> linker needs to cache "Designated Requirements" in linked binary
+template <typename A>
+class DependentDRAtom : public LinkEditAtom
+{
+public:
+ DependentDRAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "dependent dylib DR info"; }
+ // overrides of LinkEditAtom
+ virtual void encode() const;
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ static ld::Section _s_section;
+
+};
+
+template <typename A>
+ld::Section DependentDRAtom<A>::_s_section("__LINKEDIT", "__dependentDR", ld::Section::typeLinkEdit, true);
+
+
+template <typename A>
+void DependentDRAtom<A>::encode() const
+{
+ Security::SuperBlobCore<Security::SuperBlob<Security::kSecCodeMagicDRList>, Security::kSecCodeMagicDRList, uint32_t>::Maker maker;
+
+ uint32_t index = 0;
+ for(std::vector<ld::dylib::File*>::iterator it=_state.dylibs.begin(); it != _state.dylibs.end(); ++it) {
+ const ld::dylib::File* dylib = *it;
+ Security::BlobCore* dylibDR = (Security::BlobCore*)dylib->codeSignatureDR();
+ void* dup = NULL;
+ if ( dylibDR != NULL ) {
+ // <rdar://problem/11315321> Maker takes ownership of every blob added
+ // We need to make a copy here because dylib still owns the pointer returned by codeSignatureDR()
+ dup = ::malloc(dylibDR->length());
+ ::memcpy(dup, dylibDR, dylibDR->length());
+ }
+ maker.add(index, (Security::BlobCore*)dup);
+ ++index;
+ }
+
+ Security::SuperBlob<Security::kSecCodeMagicDRList>* topBlob = maker.make();
+ const uint8_t* data = (uint8_t*)topBlob->data();
+ for(size_t i=0; i < topBlob->length(); ++i)
+ _encodedData.append_byte(data[i]);
+
+ this->_encodedData.pad_to_size(sizeof(pint_t));
+
+ this->_encoded = true;
+}
+
+
+
+} // namespace tool
+} // namespace ld
+
+#endif // __LINKEDIT_HPP__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __LINKEDIT_CLASSIC_HPP__
+#define __LINKEDIT_CLASSIC_HPP__
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "Options.h"
+#include "ld.hpp"
+#include "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+
+namespace ld {
+namespace tool {
+
+
+
+class ClassicLinkEditAtom : public ld::Atom
+{
+public:
+
+ // overrides of ld::Atom
+ virtual ld::File* file() const { return NULL; }
+ virtual uint64_t objectAddress() const { return 0; }
+
+ virtual void encode() = 0;
+ virtual bool hasStabs(uint32_t& ssos, uint32_t& ssoe, uint32_t& sos, uint32_t& soe) { return false; }
+
+ ClassicLinkEditAtom(const Options& opts, ld::Internal& state,
+ OutputFile& writer, const ld::Section& sect,
+ unsigned int pointerSize)
+ : ld::Atom(sect, ld::Atom::definitionRegular,
+ ld::Atom::combineNever, ld::Atom::scopeTranslationUnit,
+ ld::Atom::typeUnclassified, ld::Atom::symbolTableNotIn,
+ false, false, false, ld::Atom::Alignment(log2(pointerSize))),
+ _options(opts), _state(state), _writer(writer) { }
+protected:
+ const Options& _options;
+ ld::Internal& _state;
+ OutputFile& _writer;
+};
+
+
+
+class StringPoolAtom : public ClassicLinkEditAtom
+{
+public:
+ StringPoolAtom(const Options& opts, ld::Internal& state,
+ OutputFile& writer, int pointerSize);
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "string pool"; }
+ virtual uint64_t size() const;
+ virtual void copyRawContent(uint8_t buffer[]) const;
+ // overrides of ClassicLinkEditAtom
+ virtual void encode() { }
+
+ int32_t add(const char* name);
+ int32_t addUnique(const char* name);
+ int32_t emptyString() { return 1; }
+ const char* stringForIndex(int32_t) const;
+ uint32_t currentOffset();
+
+private:
+ class CStringEquals
+ {
+ public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+ };
+ enum { kBufferSize = 0x01000000 };
+ typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
+
+ const uint32_t _pointerSize;
+ std::vector<char*> _fullBuffers;
+ char* _currentBuffer;
+ uint32_t _currentBufferUsed;
+ StringToOffset _uniqueStrings;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StringPoolAtom::_s_section("__LINKEDIT", "__string_pool", ld::Section::typeLinkEdit, true);
+
+
+StringPoolAtom::StringPoolAtom(const Options& opts, ld::Internal& state, OutputFile& writer, int pointerSize)
+ : ClassicLinkEditAtom(opts, state, writer, _s_section, pointerSize),
+ _pointerSize(pointerSize), _currentBuffer(NULL), _currentBufferUsed(0)
+{
+ _currentBuffer = new char[kBufferSize];
+ // burn first byte of string pool (so zero is never a valid string offset)
+ _currentBuffer[_currentBufferUsed++] = ' ';
+ // make offset 1 always point to an empty string
+ _currentBuffer[_currentBufferUsed++] = '\0';
+}
+
+uint64_t StringPoolAtom::size() const
+{
+ // pointer size align size
+ return (kBufferSize * _fullBuffers.size() + _currentBufferUsed + _pointerSize-1) & (-_pointerSize);
+}
+
+void StringPoolAtom::copyRawContent(uint8_t buffer[]) const
+{
+ uint64_t offset = 0;
+ for (unsigned int i=0; i < _fullBuffers.size(); ++i) {
+ memcpy(&buffer[offset], _fullBuffers[i], kBufferSize);
+ offset += kBufferSize;
+ }
+ memcpy(&buffer[offset], _currentBuffer, _currentBufferUsed);
+ // zero fill end to align
+ offset += _currentBufferUsed;
+ while ( (offset % _pointerSize) != 0 )
+ buffer[offset++] = 0;
+}
+
+int32_t StringPoolAtom::add(const char* str)
+{
+ int32_t offset = kBufferSize * _fullBuffers.size() + _currentBufferUsed;
+ int lenNeeded = strlcpy(&_currentBuffer[_currentBufferUsed], str, kBufferSize-_currentBufferUsed)+1;
+ if ( (_currentBufferUsed+lenNeeded) < kBufferSize ) {
+ _currentBufferUsed += lenNeeded;
+ }
+ else {
+ int copied = kBufferSize-_currentBufferUsed-1;
+ // change trailing '\0' that strlcpy added to real char
+ _currentBuffer[kBufferSize-1] = str[copied];
+ // alloc next buffer
+ _fullBuffers.push_back(_currentBuffer);
+ _currentBuffer = new char[kBufferSize];
+ _currentBufferUsed = 0;
+ // append rest of string
+ this->add(&str[copied+1]);
+ }
+ return offset;
+}
+
+uint32_t StringPoolAtom::currentOffset()
+{
+ return kBufferSize * _fullBuffers.size() + _currentBufferUsed;
+}
+
+
+int32_t StringPoolAtom::addUnique(const char* str)
+{
+ StringToOffset::iterator pos = _uniqueStrings.find(str);
+ if ( pos != _uniqueStrings.end() ) {
+ return pos->second;
+ }
+ else {
+ int32_t offset = this->add(str);
+ _uniqueStrings[str] = offset;
+ return offset;
+ }
+}
+
+
+const char* StringPoolAtom::stringForIndex(int32_t index) const
+{
+ int32_t currentBufferStartIndex = kBufferSize * _fullBuffers.size();
+ int32_t maxIndex = currentBufferStartIndex + _currentBufferUsed;
+ // check for out of bounds
+ if ( index > maxIndex )
+ return "";
+ // check for index in _currentBuffer
+ if ( index > currentBufferStartIndex )
+ return &_currentBuffer[index-currentBufferStartIndex];
+ // otherwise index is in a full buffer
+ uint32_t fullBufferIndex = index/kBufferSize;
+ return &_fullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)];
+}
+
+
+
+template <typename A>
+class SymbolTableAtom : public ClassicLinkEditAtom
+{
+public:
+ SymbolTableAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : ClassicLinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)),
+ _stabsStringsOffsetStart(0), _stabsStringsOffsetEnd(0),
+ _stabsIndexStart(0), _stabsIndexEnd(0) { }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "symbol table"; }
+ virtual uint64_t size() const;
+ virtual void copyRawContent(uint8_t buffer[]) const;
+ // overrides of ClassicLinkEditAtom
+ virtual void encode();
+ virtual bool hasStabs(uint32_t& ssos, uint32_t& ssoe, uint32_t& sos, uint32_t& soe);
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ bool addLocal(const ld::Atom* atom, StringPoolAtom* pool);
+ void addGlobal(const ld::Atom* atom, StringPoolAtom* pool);
+ void addImport(const ld::Atom* atom, StringPoolAtom* pool);
+ uint8_t classicOrdinalForProxy(const ld::Atom* atom);
+ uint32_t stringOffsetForStab(const ld::relocatable::File::Stab& stab, StringPoolAtom* pool);
+ uint64_t valueForStab(const ld::relocatable::File::Stab& stab);
+ uint8_t sectionIndexForStab(const ld::relocatable::File::Stab& stab);
+
+
+ mutable std::vector<macho_nlist<P> > _globals;
+ mutable std::vector<macho_nlist<P> > _locals;
+ mutable std::vector<macho_nlist<P> > _imports;
+
+ uint32_t _stabsStringsOffsetStart;
+ uint32_t _stabsStringsOffsetEnd;
+ uint32_t _stabsIndexStart;
+ uint32_t _stabsIndexEnd;
+
+ static ld::Section _s_section;
+ static int _s_anonNameIndex;
+
+};
+
+template <typename A>
+ld::Section SymbolTableAtom<A>::_s_section("__LINKEDIT", "__symbol_table", ld::Section::typeLinkEdit, true);
+
+template <typename A>
+int SymbolTableAtom<A>::_s_anonNameIndex = 1;
+
+
+template <typename A>
+bool SymbolTableAtom<A>::addLocal(const ld::Atom* atom, StringPoolAtom* pool)
+{
+ macho_nlist<P> entry;
+ assert(atom->symbolTableInclusion() != ld::Atom::symbolTableNotIn);
+
+ // set n_strx
+ const char* symbolName = atom->name();
+ char anonName[32];
+ if ( this->_options.outputKind() == Options::kObjectFile ) {
+ if ( atom->contentType() == ld::Atom::typeCString ) {
+ if ( atom->combine() == ld::Atom::combineByNameAndContent ) {
+ // don't use 'l' labels for x86_64 strings
+ // <rdar://problem/6605499> x86_64 obj-c runtime confused when static lib is stripped
+ sprintf(anonName, "LC%u", _s_anonNameIndex++);
+ symbolName = anonName;
+ }
+ }
+ else if ( atom->contentType() == ld::Atom::typeCFI ) {
+ if ( _options.removeEHLabels() )
+ return false;
+ // synthesize .eh name
+ if ( strcmp(atom->name(), "CIE") == 0 )
+ symbolName = "EH_Frame1";
+ else
+ symbolName = "func.eh";
+ }
+ else if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel ) {
+ // make auto-strip anonymous name for symbol
+ sprintf(anonName, "l%03u", _s_anonNameIndex++);
+ symbolName = anonName;
+ }
+ }
+ entry.set_n_strx(pool->add(symbolName));
+
+ // set n_type
+ uint8_t type = N_SECT;
+ if ( atom->definition() == ld::Atom::definitionAbsolute ) {
+ type = N_ABS;
+ }
+ else if ( (atom->section().type() == ld::Section::typeObjC1Classes)
+ && (this->_options.outputKind() == Options::kObjectFile) ) {
+ // __OBJC __class has floating abs symbols for each class data structure
+ type = N_ABS;
+ }
+ if ( atom->scope() == ld::Atom::scopeLinkageUnit )
+ type |= N_PEXT;
+ entry.set_n_type(type);
+
+ // set n_sect (section number of implementation )
+ if ( atom->definition() == ld::Atom::definitionAbsolute )
+ entry.set_n_sect(0);
+ else
+ entry.set_n_sect(atom->machoSection());
+
+ // set n_desc
+ uint16_t desc = 0;
+ if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip )
+ desc |= REFERENCED_DYNAMICALLY;
+ if ( atom->dontDeadStrip() && (this->_options.outputKind() == Options::kObjectFile) )
+ desc |= N_NO_DEAD_STRIP;
+ if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) )
+ desc |= N_WEAK_DEF;
+ if ( atom->isThumb() )
+ desc |= N_ARM_THUMB_DEF;
+ entry.set_n_desc(desc);
+
+ // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
+ if ( atom->definition() == ld::Atom::definitionAbsolute )
+ entry.set_n_value(atom->objectAddress());
+ else
+ entry.set_n_value(atom->finalAddress());
+
+ // add to array
+ _locals.push_back(entry);
+ return true;
+}
+
+
+template <typename A>
+void SymbolTableAtom<A>::addGlobal(const ld::Atom* atom, StringPoolAtom* pool)
+{
+ macho_nlist<P> entry;
+
+ // set n_strx
+ const char* symbolName = atom->name();
+ char anonName[32];
+ if ( this->_options.outputKind() == Options::kObjectFile ) {
+ if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel ) {
+ // make auto-strip anonymous name for symbol
+ sprintf(anonName, "l%03u", _s_anonNameIndex++);
+ symbolName = anonName;
+ }
+ }
+ entry.set_n_strx(pool->add(symbolName));
+
+ // set n_type
+ if ( atom->definition() == ld::Atom::definitionAbsolute ) {
+ entry.set_n_type(N_EXT | N_ABS);
+ }
+ else if ( (atom->section().type() == ld::Section::typeObjC1Classes)
+ && (this->_options.outputKind() == Options::kObjectFile) ) {
+ // __OBJC __class has floating abs symbols for each class data structure
+ entry.set_n_type(N_EXT | N_ABS);
+ }
+ else if ( (atom->definition() == ld::Atom::definitionProxy) && (atom->scope() == ld::Atom::scopeGlobal) ) {
+ entry.set_n_type(N_EXT | N_INDR);
+ }
+ else {
+ entry.set_n_type(N_EXT | N_SECT);
+ if ( (atom->scope() == ld::Atom::scopeLinkageUnit) && (this->_options.outputKind() == Options::kObjectFile) ) {
+ if ( this->_options.keepPrivateExterns() )
+ entry.set_n_type(N_EXT | N_SECT | N_PEXT);
+ }
+ else if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)
+ && (atom->section().type() == ld::Section::typeMachHeader)
+ && !_options.positionIndependentExecutable() ) {
+ // the __mh_execute_header is historical magic in non-pie executabls and must be an absolute symbol
+ entry.set_n_type(N_EXT | N_ABS);
+ }
+ }
+
+ // set n_sect (section number of implementation)
+ if ( atom->definition() == ld::Atom::definitionAbsolute )
+ entry.set_n_sect(0);
+ else if ( (atom->definition() == ld::Atom::definitionProxy) && (atom->scope() == ld::Atom::scopeGlobal) )
+ entry.set_n_sect(0);
+ else
+ entry.set_n_sect(atom->machoSection());
+
+ // set n_desc
+ uint16_t desc = 0;
+ if ( atom->isThumb() )
+ desc |= N_ARM_THUMB_DEF;
+ if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip )
+ desc |= REFERENCED_DYNAMICALLY;
+ if ( (atom->contentType() == ld::Atom::typeResolver) && (this->_options.outputKind() == Options::kObjectFile) )
+ desc |= N_SYMBOL_RESOLVER;
+ if ( atom->dontDeadStrip() && (this->_options.outputKind() == Options::kObjectFile) )
+ desc |= N_NO_DEAD_STRIP;
+ if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) ) {
+ desc |= N_WEAK_DEF;
+ // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
+ if ( (atom->scope() == ld::Atom::scopeGlobal) && atom->autoHide() && (this->_options.outputKind() == Options::kObjectFile) )
+ desc |= N_WEAK_REF;
+ }
+ entry.set_n_desc(desc);
+
+ // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
+ if ( atom->definition() == ld::Atom::definitionAbsolute )
+ entry.set_n_value(atom->objectAddress());
+ else if ( (atom->definition() == ld::Atom::definitionProxy) && (atom->scope() == ld::Atom::scopeGlobal) ) {
+ if ( atom->isAlias() ) {
+ // this re-export also renames
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+ assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+ entry.set_n_value(pool->add(fit->u.target->name()));
+ }
+ }
+ }
+ else
+ entry.set_n_value(entry.n_strx());
+ }
+ else
+ entry.set_n_value(atom->finalAddress());
+
+ // add to array
+ _globals.push_back(entry);
+}
+
+template <typename A>
+uint8_t SymbolTableAtom<A>::classicOrdinalForProxy(const ld::Atom* atom)
+{
+ assert(atom->definition() == ld::Atom::definitionProxy);
+ // when linking for flat-namespace ordinals are always zero
+ if ( _options.nameSpace() != Options::kTwoLevelNameSpace )
+ return 0;
+ const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(atom->file());
+ // when linking -undefined dynamic_lookup, unbound symbols use DYNAMIC_LOOKUP_ORDINAL
+ if ( dylib == NULL ) {
+ if (_options.undefinedTreatment() == Options::kUndefinedDynamicLookup )
+ return DYNAMIC_LOOKUP_ORDINAL;
+ if (_options.allowedUndefined(atom->name()) )
+ return DYNAMIC_LOOKUP_ORDINAL;
+ }
+ assert(dylib != NULL);
+ int ord = this->_writer.dylibToOrdinal(dylib);
+ if ( ord == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE )
+ return EXECUTABLE_ORDINAL;
+ return ord;
+}
+
+
+template <typename A>
+void SymbolTableAtom<A>::addImport(const ld::Atom* atom, StringPoolAtom* pool)
+{
+ macho_nlist<P> entry;
+
+ // set n_strx
+ entry.set_n_strx(pool->add(atom->name()));
+
+ // set n_type
+ if ( this->_options.outputKind() == Options::kObjectFile ) {
+ if ( (atom->scope() == ld::Atom::scopeLinkageUnit)
+ && (atom->definition() == ld::Atom::definitionTentative) )
+ entry.set_n_type(N_UNDF | N_EXT | N_PEXT);
+ else
+ entry.set_n_type(N_UNDF | N_EXT);
+ }
+ else {
+ if ( this->_options.prebind() )
+ entry.set_n_type(N_PBUD | N_EXT);
+ else
+ entry.set_n_type(N_UNDF | N_EXT);
+ }
+
+ // set n_sect
+ entry.set_n_sect(0);
+
+ uint16_t desc = 0;
+ if ( this->_options.outputKind() != Options::kObjectFile ) {
+ uint8_t ordinal = this->classicOrdinalForProxy(atom);
+ //fprintf(stderr, "ordinal=%u from reader=%p for symbol=%s\n", ordinal, atom->getFile(), atom->getName());
+ SET_LIBRARY_ORDINAL(desc, ordinal);
+
+#if 0
+ // set n_desc ( high byte is library ordinal, low byte is reference type )
+ std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(atom);
+ if ( pos != fStubsMap.end() || ( strncmp(atom->getName(), ".objc_class_name_", 17) == 0) )
+ desc |= REFERENCE_FLAG_UNDEFINED_LAZY;
+ else
+ desc |= REFERENCE_FLAG_UNDEFINED_NON_LAZY;
+#endif
+ }
+ else if ( atom->definition() == ld::Atom::definitionTentative ) {
+ uint8_t align = atom->alignment().powerOf2;
+ // always record custom alignment of common symbols to match what compiler does
+ SET_COMM_ALIGN(desc, align);
+ }
+ if ( (this->_options.outputKind() != Options::kObjectFile)
+ && (atom->definition() == ld::Atom::definitionProxy)
+ && (atom->combine() == ld::Atom::combineByName) ) {
+ desc |= N_REF_TO_WEAK;
+ }
+ const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(atom->file());
+ if ( atom->weakImported() || ((dylib != NULL) && dylib->forcedWeakLinked()) )
+ desc |= N_WEAK_REF;
+ entry.set_n_desc(desc);
+
+ // set n_value, zero for import proxy and size for tentative definition
+ if ( atom->definition() == ld::Atom::definitionTentative )
+ entry.set_n_value(atom->size());
+ else
+ entry.set_n_value(0);
+
+ // add to array
+ _imports.push_back(entry);
+}
+
+template <typename A>
+uint8_t SymbolTableAtom<A>::sectionIndexForStab(const ld::relocatable::File::Stab& stab)
+{
+ // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN
+ if ( stab.type == N_FUN )
+ return stab.other;
+ else if ( stab.type == N_GSYM )
+ return 0;
+ else if ( stab.atom != NULL )
+ return stab.atom->machoSection();
+ else
+ return stab.other;
+}
+
+
+template <typename A>
+uint64_t SymbolTableAtom<A>::valueForStab(const ld::relocatable::File::Stab& stab)
+{
+ switch ( stab.type ) {
+ case N_FUN:
+ if ( stab.atom == NULL ) {
+ // <rdar://problem/5591394> Add support to ld64 for N_FUN stabs when used for symbolic constants
+ return stab.value;
+ }
+ if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
+ // end of function N_FUN has size
+ return stab.atom->size();
+ }
+ else {
+ // start of function N_FUN has address
+ return stab.atom->finalAddress();
+ }
+ case N_LBRAC:
+ case N_RBRAC:
+ case N_SLINE:
+ if ( stab.atom == NULL )
+ // some weird assembly files have slines not associated with a function
+ return stab.value;
+ else
+ // all these stab types need their value changed from an offset in the atom to an address
+ return stab.atom->finalAddress() + stab.value;
+ case N_STSYM:
+ case N_LCSYM:
+ case N_BNSYM:
+ // all these need address of atom
+ if ( stab.atom != NULL )
+ return stab.atom->finalAddress();
+ else
+ return 0; // <rdar://problem/7811357> work around for mismatch N_BNSYM
+ case N_ENSYM:
+ return stab.atom->size();
+ case N_SO:
+ if ( stab.atom == NULL ) {
+ return 0;
+ }
+ else {
+ if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
+ // end of translation unit N_SO has address of end of last atom
+ return stab.atom->finalAddress() + stab.atom->size();
+ }
+ else {
+ // start of translation unit N_SO has address of end of first atom
+ return stab.atom->finalAddress();
+ }
+ }
+ break;
+ default:
+ return stab.value;
+ }
+}
+
+template <typename A>
+uint32_t SymbolTableAtom<A>::stringOffsetForStab(const ld::relocatable::File::Stab& stab, StringPoolAtom* pool)
+{
+ switch (stab.type) {
+ case N_SO:
+ if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
+ return pool->emptyString();
+ break;
+ }
+ // fall into uniquing case
+ case N_SOL:
+ case N_BINCL:
+ case N_EXCL:
+ return pool->addUnique(stab.string);
+ break;
+ default:
+ if ( stab.string == NULL )
+ return 0;
+ else if ( stab.string[0] == '\0' )
+ return pool->emptyString();
+ else
+ return pool->add(stab.string);
+ }
+ return 0;
+}
+
+
+
+template <typename A>
+bool SymbolTableAtom<A>::hasStabs(uint32_t& ssos, uint32_t& ssoe, uint32_t& sos, uint32_t& soe)
+{
+ ssos = _stabsStringsOffsetStart;
+ ssoe = _stabsStringsOffsetEnd;
+ sos = _stabsIndexStart * sizeof(macho_nlist<P>);
+ soe = _stabsIndexEnd * sizeof(macho_nlist<P>);
+ return ( (_stabsIndexStart != _stabsIndexEnd) || (_stabsStringsOffsetStart != _stabsStringsOffsetEnd) );
+}
+
+
+template <typename A>
+void SymbolTableAtom<A>::encode()
+{
+ uint32_t symbolIndex = 0;
+
+ // make nlist entries for all local symbols
+ std::vector<const ld::Atom*>& localAtoms = this->_writer._localAtoms;
+ std::vector<const ld::Atom*>& globalAtoms = this->_writer._exportedAtoms;
+ _locals.reserve(localAtoms.size()+this->_state.stabs.size());
+ this->_writer._localSymbolsStartIndex = 0;
+ // make nlist entries for all debug notes
+ _stabsIndexStart = symbolIndex;
+ _stabsStringsOffsetStart = this->_writer._stringPoolAtom->currentOffset();
+ for (std::vector<ld::relocatable::File::Stab>::const_iterator sit=this->_state.stabs.begin(); sit != this->_state.stabs.end(); ++sit) {
+ macho_nlist<P> entry;
+ entry.set_n_type(sit->type);
+ entry.set_n_sect(sectionIndexForStab(*sit));
+ entry.set_n_desc(sit->desc);
+ entry.set_n_value(valueForStab(*sit));
+ entry.set_n_strx(stringOffsetForStab(*sit, this->_writer._stringPoolAtom));
+ _locals.push_back(entry);
+ ++symbolIndex;
+ }
+ _stabsIndexEnd = symbolIndex;
+ _stabsStringsOffsetEnd = this->_writer._stringPoolAtom->currentOffset();
+ for (std::vector<const ld::Atom*>::const_iterator it=localAtoms.begin(); it != localAtoms.end(); ++it) {
+ const ld::Atom* atom = *it;
+ if ( this->addLocal(atom, this->_writer._stringPoolAtom) )
+ this->_writer._atomToSymbolIndex[atom] = symbolIndex++;
+ }
+ this->_writer._localSymbolsCount = symbolIndex;
+
+
+ // make nlist entries for all global symbols
+ _globals.reserve(globalAtoms.size());
+ this->_writer._globalSymbolsStartIndex = symbolIndex;
+ for (std::vector<const ld::Atom*>::const_iterator it=globalAtoms.begin(); it != globalAtoms.end(); ++it) {
+ const ld::Atom* atom = *it;
+ this->addGlobal(atom, this->_writer._stringPoolAtom);
+ this->_writer._atomToSymbolIndex[atom] = symbolIndex++;
+ }
+ this->_writer._globalSymbolsCount = symbolIndex - this->_writer._globalSymbolsStartIndex;
+
+ // make nlist entries for all undefined (imported) symbols
+ std::vector<const ld::Atom*>& importAtoms = this->_writer._importedAtoms;
+ _imports.reserve(importAtoms.size());
+ this->_writer._importSymbolsStartIndex = symbolIndex;
+ for (std::vector<const ld::Atom*>::const_iterator it=importAtoms.begin(); it != importAtoms.end(); ++it) {
+ this->addImport(*it, this->_writer._stringPoolAtom);
+ this->_writer._atomToSymbolIndex[*it] = symbolIndex++;
+ }
+ this->_writer._importSymbolsCount = symbolIndex - this->_writer._importSymbolsStartIndex;
+}
+
+template <typename A>
+uint64_t SymbolTableAtom<A>::size() const
+{
+ return sizeof(macho_nlist<P>) * (_locals.size() + _globals.size() + _imports.size());
+}
+
+template <typename A>
+void SymbolTableAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ memcpy(&buffer[this->_writer._localSymbolsStartIndex*sizeof(macho_nlist<P>)], &_locals[0],
+ this->_writer._localSymbolsCount*sizeof(macho_nlist<P>));
+ memcpy(&buffer[this->_writer._globalSymbolsStartIndex*sizeof(macho_nlist<P>)], &_globals[0],
+ this->_writer._globalSymbolsCount*sizeof(macho_nlist<P>));
+ memcpy(&buffer[this->_writer._importSymbolsStartIndex *sizeof(macho_nlist<P>)], &_imports[0],
+ this->_writer._importSymbolsCount*sizeof(macho_nlist<P>));
+}
+
+
+
+
+class RelocationsAtomAbstract : public ClassicLinkEditAtom
+{
+public:
+ RelocationsAtomAbstract(const Options& opts, ld::Internal& state,
+ OutputFile& writer, const ld::Section& sect,
+ unsigned int pointerSize)
+ : ClassicLinkEditAtom(opts, state, writer, sect, pointerSize) { }
+
+ virtual void addPointerReloc(uint64_t addr, uint32_t symNum) = 0;
+ virtual void addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum) = 0;
+ virtual void addExternalPointerReloc(uint64_t addr, const ld::Atom*) = 0;
+ virtual void addExternalCallSiteReloc(uint64_t addr, const ld::Atom*) = 0;
+ virtual uint64_t relocBaseAddress(ld::Internal& state) = 0;
+ virtual void addSectionReloc(ld::Internal::FinalSection* sect, ld::Fixup::Kind,
+ const ld::Atom* inAtom, uint32_t offsetInAtom,
+ bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+ const ld::Atom* toTarget, uint64_t toAddend,
+ const ld::Atom* fromTarget, uint64_t fromAddend) = 0;
+protected:
+ uint32_t symbolIndex(const ld::Atom* atom) const;
+
+};
+
+
+
+uint32_t RelocationsAtomAbstract::symbolIndex(const ld::Atom* atom) const
+{
+ std::map<const ld::Atom*, uint32_t>::iterator pos = this->_writer._atomToSymbolIndex.find(atom);
+ if ( pos != this->_writer._atomToSymbolIndex.end() )
+ return pos->second;
+ fprintf(stderr, "_atomToSymbolIndex content:\n");
+ for(std::map<const ld::Atom*, uint32_t>::iterator it = this->_writer._atomToSymbolIndex.begin(); it != this->_writer._atomToSymbolIndex.end(); ++it) {
+ fprintf(stderr, "%p(%s) => %d\n", it->first, it->first->name(), it->second);
+ }
+ throwf("internal error: atom not found in symbolIndex(%s)", atom->name());
+}
+
+
+template <typename A>
+class LocalRelocationsAtom : public RelocationsAtomAbstract
+{
+public:
+ LocalRelocationsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : RelocationsAtomAbstract(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "local relocations"; }
+ virtual uint64_t size() const;
+ virtual void copyRawContent(uint8_t buffer[]) const;
+ // overrides of ClassicLinkEditAtom
+ virtual void encode() {}
+ // overrides of RelocationsAtomAbstract
+ virtual void addPointerReloc(uint64_t addr, uint32_t symNum);
+ virtual void addExternalPointerReloc(uint64_t addr, const ld::Atom*) {}
+ virtual void addExternalCallSiteReloc(uint64_t addr, const ld::Atom*) {}
+ virtual uint64_t relocBaseAddress(ld::Internal& state);
+ virtual void addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum);
+ virtual void addSectionReloc(ld::Internal::FinalSection* sect, ld::Fixup::Kind,
+ const ld::Atom* inAtom, uint32_t offsetInAtom,
+ bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+ const ld::Atom* toTarget, uint64_t toAddend,
+ const ld::Atom* fromTarget, uint64_t fromAddend) { }
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ std::vector<macho_relocation_info<P> > _relocs;
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section LocalRelocationsAtom<A>::_s_section("__LINKEDIT", "__local_relocs", ld::Section::typeLinkEdit, true);
+
+
+template <>
+uint64_t LocalRelocationsAtom<x86_64>::relocBaseAddress(ld::Internal& state)
+{
+ if ( _options.outputKind() == Options::kKextBundle ) {
+ // for kext bundles the reloc base address starts at __TEXT segment
+ return _options.baseAddress();
+ }
+ // for all other kinds, the x86_64 reloc base address starts at __DATA segment
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( strcmp(sect->segmentName(), "__DATA") == 0 )
+ return sect->address;
+ }
+ throw "__DATA segment not found";
+}
+
+template <typename A>
+uint64_t LocalRelocationsAtom<A>::relocBaseAddress(ld::Internal& state)
+{
+ return _options.baseAddress();
+}
+
+template <typename A>
+void LocalRelocationsAtom<A>::addPointerReloc(uint64_t addr, uint32_t symNum)
+{
+ macho_relocation_info<P> reloc;
+ reloc.set_r_address(addr);
+ reloc.set_r_symbolnum(symNum);
+ reloc.set_r_pcrel(false);
+ reloc.set_r_length();
+ reloc.set_r_extern(false);
+ reloc.set_r_type(GENERIC_RELOC_VANILLA);
+ _relocs.push_back(reloc);
+}
+
+template <typename A>
+void LocalRelocationsAtom<A>::addTextReloc(uint64_t addr, ld::Fixup::Kind kind, uint64_t targetAddr, uint32_t symNum)
+{
+}
+
+
+template <typename A>
+uint64_t LocalRelocationsAtom<A>::size() const
+{
+ return _relocs.size() * sizeof(macho_relocation_info<P>);
+}
+
+template <typename A>
+void LocalRelocationsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ memcpy(buffer, &_relocs[0], _relocs.size()*sizeof(macho_relocation_info<P>));
+}
+
+
+
+
+
+
+template <typename A>
+class ExternalRelocationsAtom : public RelocationsAtomAbstract
+{
+public:
+ ExternalRelocationsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : RelocationsAtomAbstract(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "external relocations"; }
+ virtual uint64_t size() const;
+ virtual void copyRawContent(uint8_t buffer[]) const;
+ // overrides of ClassicLinkEditAtom
+ virtual void encode() {}
+ // overrides of RelocationsAtomAbstract
+ virtual void addPointerReloc(uint64_t addr, uint32_t symNum) {}
+ virtual void addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum) {}
+ virtual void addExternalPointerReloc(uint64_t addr, const ld::Atom*);
+ virtual void addExternalCallSiteReloc(uint64_t addr, const ld::Atom*);
+ virtual uint64_t relocBaseAddress(ld::Internal& state);
+ virtual void addSectionReloc(ld::Internal::FinalSection* sect, ld::Fixup::Kind,
+ const ld::Atom* inAtom, uint32_t offsetInAtom,
+ bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+ const ld::Atom* toTarget, uint64_t toAddend,
+ const ld::Atom* fromTarget, uint64_t fromAddend) { }
+
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ struct LocAndAtom {
+ LocAndAtom(uint64_t l, const ld::Atom* a) : loc(l), atom(a), symbolIndex(0) {}
+
+ uint64_t loc;
+ const ld::Atom* atom;
+ uint32_t symbolIndex;
+
+ bool operator<(const LocAndAtom& rhs) const {
+ // sort first by symbol number
+ if ( this->symbolIndex != rhs.symbolIndex )
+ return (this->symbolIndex < rhs.symbolIndex);
+ // then sort all uses of the same symbol by address
+ return (this->loc < rhs.loc);
+ }
+
+ };
+
+ static uint32_t pointerReloc();
+ static uint32_t callReloc();
+
+ mutable std::vector<LocAndAtom> _pointerLocations;
+ mutable std::vector<LocAndAtom> _callSiteLocations;
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section ExternalRelocationsAtom<A>::_s_section("__LINKEDIT", "__extrn_relocs", ld::Section::typeLinkEdit, true);
+
+template <>
+uint64_t ExternalRelocationsAtom<x86_64>::relocBaseAddress(ld::Internal& state)
+{
+ // for x86_64 the reloc base address starts at __DATA segment
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( strcmp(sect->segmentName(), "__DATA") == 0 )
+ return sect->address;
+ }
+ throw "__DATA segment not found";
+}
+
+template <typename A>
+uint64_t ExternalRelocationsAtom<A>::relocBaseAddress(ld::Internal& state)
+{
+ return 0;
+}
+
+template <typename A>
+void ExternalRelocationsAtom<A>::addExternalPointerReloc(uint64_t addr, const ld::Atom* target)
+{
+ _pointerLocations.push_back(LocAndAtom(addr, target));
+}
+
+template <typename A>
+void ExternalRelocationsAtom<A>::addExternalCallSiteReloc(uint64_t addr, const ld::Atom* target)
+{
+ _callSiteLocations.push_back(LocAndAtom(addr, target));
+}
+
+
+template <typename A>
+uint64_t ExternalRelocationsAtom<A>::size() const
+{
+ if ( _options.outputKind() == Options::kStaticExecutable ) {
+ assert(_pointerLocations.size() == 0);
+ assert(_callSiteLocations.size() == 0);
+ }
+ return (_pointerLocations.size() + _callSiteLocations.size()) * sizeof(macho_relocation_info<P>);
+}
+
+#if SUPPORT_ARCH_arm_any
+template <> uint32_t ExternalRelocationsAtom<arm>::pointerReloc() { return ARM_RELOC_VANILLA; }
+#endif
+template <> uint32_t ExternalRelocationsAtom<x86>::pointerReloc() { return GENERIC_RELOC_VANILLA; }
+template <> uint32_t ExternalRelocationsAtom<x86_64>::pointerReloc() { return X86_64_RELOC_UNSIGNED; }
+
+
+template <> uint32_t ExternalRelocationsAtom<x86_64>::callReloc() { return X86_64_RELOC_BRANCH; }
+template <> uint32_t ExternalRelocationsAtom<x86>::callReloc() { return GENERIC_RELOC_VANILLA; }
+template <typename A>
+uint32_t ExternalRelocationsAtom<A>::callReloc()
+{
+ assert(0 && "external call relocs not implemented");
+ return 0;
+}
+
+
+template <typename A>
+void ExternalRelocationsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ macho_relocation_info<P>* r = (macho_relocation_info<P>*)buffer;
+
+ // assign symbol index, now that symbol table is built
+ for (typename std::vector<LocAndAtom>::iterator it = _pointerLocations.begin(); it != _pointerLocations.end(); ++it) {
+ it->symbolIndex = symbolIndex(it->atom);
+ }
+ std::sort(_pointerLocations.begin(), _pointerLocations.end());
+ for (typename std::vector<LocAndAtom>::const_iterator it = _pointerLocations.begin(); it != _pointerLocations.end(); ++it, ++r) {
+ r->set_r_address(it->loc);
+ r->set_r_symbolnum(it->symbolIndex);
+ r->set_r_pcrel(false);
+ r->set_r_length();
+ r->set_r_extern(true);
+ r->set_r_type(this->pointerReloc());
+ }
+
+ for (typename std::vector<LocAndAtom>::iterator it = _callSiteLocations.begin(); it != _callSiteLocations.end(); ++it) {
+ it->symbolIndex = symbolIndex(it->atom);
+ }
+ std::sort(_callSiteLocations.begin(), _callSiteLocations.end());
+ for (typename std::vector<LocAndAtom>::const_iterator it = _callSiteLocations.begin(); it != _callSiteLocations.end(); ++it, ++r) {
+ r->set_r_address(it->loc);
+ r->set_r_symbolnum(it->symbolIndex);
+ r->set_r_pcrel(true);
+ r->set_r_length(2);
+ r->set_r_extern(true);
+ r->set_r_type(this->callReloc());
+ }
+}
+
+
+template <typename A>
+class SectionRelocationsAtom : public RelocationsAtomAbstract
+{
+public:
+ SectionRelocationsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : RelocationsAtomAbstract(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "section relocations"; }
+ virtual uint64_t size() const;
+ virtual void copyRawContent(uint8_t buffer[]) const;
+ // overrides of ClassicLinkEditAtom
+ virtual void encode();
+ // overrides of RelocationsAtomAbstract
+ virtual void addPointerReloc(uint64_t addr, uint32_t symNum) {}
+ virtual void addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum) {}
+ virtual void addExternalPointerReloc(uint64_t addr, const ld::Atom*) {}
+ virtual void addExternalCallSiteReloc(uint64_t addr, const ld::Atom*) {}
+ virtual uint64_t relocBaseAddress(ld::Internal& state) { return 0; }
+ virtual void addSectionReloc(ld::Internal::FinalSection* sect, ld::Fixup::Kind,
+ const ld::Atom* inAtom, uint32_t offsetInAtom,
+ bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+ const ld::Atom* toTarget, uint64_t toAddend,
+ const ld::Atom* fromTarget, uint64_t fromAddend);
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+
+ struct Entry {
+ ld::Fixup::Kind kind;
+ bool toTargetUsesExternalReloc;
+ bool fromTargetUsesExternalReloc;
+ const ld::Atom* inAtom;
+ uint32_t offsetInAtom;
+ const ld::Atom* toTarget;
+ uint64_t toAddend;
+ const ld::Atom* fromTarget;
+ uint64_t fromAddend;
+ };
+ uint32_t sectSymNum(bool external, const ld::Atom* target);
+ void encodeSectionReloc(ld::Internal::FinalSection* sect,
+ const Entry& entry, std::vector<macho_relocation_info<P> >& relocs);
+
+ struct SectionAndEntries {
+ ld::Internal::FinalSection* sect;
+ std::vector<Entry> entries;
+ std::vector<macho_relocation_info<P> > relocs;
+ };
+
+ std::vector<SectionAndEntries> _entriesBySection;
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section SectionRelocationsAtom<A>::_s_section("__LINKEDIT", "__sect_relocs", ld::Section::typeLinkEdit, true);
+
+
+
+
+template <typename A>
+uint64_t SectionRelocationsAtom<A>::size() const
+{
+ uint32_t count = 0;
+ for(typename std::vector<SectionAndEntries>::const_iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
+ const SectionAndEntries& se = *it;
+ count += se.relocs.size();
+ }
+ return count * sizeof(macho_relocation_info<P>);
+}
+
+template <typename A>
+void SectionRelocationsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ uint32_t offset = 0;
+ for(typename std::vector<SectionAndEntries>::const_iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
+ const SectionAndEntries& se = *it;
+ memcpy(&buffer[offset], &se.relocs[0], se.relocs.size()*sizeof(macho_relocation_info<P>));
+ offset += (se.relocs.size() * sizeof(macho_relocation_info<P>));
+ }
+}
+
+
+template <>
+void SectionRelocationsAtom<x86_64>::encodeSectionReloc(ld::Internal::FinalSection* sect,
+ const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+ macho_relocation_info<P> reloc1;
+ macho_relocation_info<P> reloc2;
+ uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+ bool external = entry.toTargetUsesExternalReloc;
+ uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+ bool fromExternal = false;
+ uint32_t fromSymbolNum = 0;
+ if ( entry.fromTarget != NULL ) {
+ fromExternal = entry.fromTargetUsesExternalReloc;
+ fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
+ }
+
+
+ switch ( entry.kind ) {
+ case ld::Fixup::kindStoreX86BranchPCRel32:
+ case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+ case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+ case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(X86_64_RELOC_BRANCH);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreX86BranchPCRel8:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(0);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(X86_64_RELOC_BRANCH);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreX86PCRel32:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(X86_64_RELOC_SIGNED);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreX86PCRel32_1:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(X86_64_RELOC_SIGNED_1);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreX86PCRel32_2:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(X86_64_RELOC_SIGNED_2);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreX86PCRel32_4:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(X86_64_RELOC_SIGNED_4);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreX86PCRel32GOT:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(X86_64_RELOC_GOT);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreLittleEndian64:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+ if ( entry.fromTarget != NULL ) {
+ // this is a pointer-diff
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(3);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
+ reloc2.set_r_address(address);
+ reloc2.set_r_symbolnum(fromSymbolNum);
+ reloc2.set_r_pcrel(false);
+ reloc2.set_r_length(3);
+ reloc2.set_r_extern(fromExternal);
+ reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
+ relocs.push_back(reloc2);
+ relocs.push_back(reloc1);
+ }
+ else {
+ // regular pointer
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(3);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
+ relocs.push_back(reloc1);
+ }
+ break;
+
+ case ld::Fixup::kindStoreLittleEndian32:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ if ( entry.fromTarget != NULL ) {
+ // this is a pointer-diff
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
+ reloc2.set_r_address(address);
+ reloc2.set_r_symbolnum(fromSymbolNum);
+ reloc2.set_r_pcrel(false);
+ reloc2.set_r_length(2);
+ reloc2.set_r_extern(fromExternal);
+ reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
+ relocs.push_back(reloc2);
+ relocs.push_back(reloc1);
+ }
+ else {
+ // regular pointer
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
+ relocs.push_back(reloc1);
+ }
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(X86_64_RELOC_TLV);
+ relocs.push_back(reloc1);
+ break;
+ default:
+ assert(0 && "need to handle -r reloc");
+
+ }
+
+}
+
+
+
+template <typename A>
+uint32_t SectionRelocationsAtom<A>::sectSymNum(bool external, const ld::Atom* target)
+{
+ if ( target->definition() == ld::Atom::definitionAbsolute )
+ return R_ABS;
+ if ( external )
+ return this->symbolIndex(target); // in external relocations, r_symbolnum field is symbol index
+ else
+ return target->machoSection(); // in non-extern relocations, r_symbolnum is mach-o section index of target
+}
+
+template <>
+void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection* sect,
+ const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+ macho_relocation_info<P> reloc1;
+ macho_relocation_info<P> reloc2;
+ macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
+ macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
+ uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+ bool external = entry.toTargetUsesExternalReloc;
+ uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+ bool fromExternal = false;
+ uint32_t fromSymbolNum = 0;
+ if ( entry.fromTarget != NULL ) {
+ fromExternal = entry.fromTargetUsesExternalReloc;
+ fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
+ }
+
+ switch ( entry.kind ) {
+ case ld::Fixup::kindStoreX86PCRel32:
+ case ld::Fixup::kindStoreX86BranchPCRel32:
+ case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+ case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+ case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+ if ( !external && (entry.toAddend != 0) ) {
+ // use scattered reloc is target offset is non-zero
+ sreloc1->set_r_scattered(true);
+ sreloc1->set_r_pcrel(true);
+ sreloc1->set_r_length(2);
+ sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+ sreloc1->set_r_address(address);
+ sreloc1->set_r_value(entry.toTarget->finalAddress());
+ }
+ else {
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+ }
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreX86BranchPCRel8:
+ if ( !external && (entry.toAddend != 0) ) {
+ // use scattered reloc is target offset is non-zero
+ sreloc1->set_r_scattered(true);
+ sreloc1->set_r_pcrel(true);
+ sreloc1->set_r_length(0);
+ sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+ sreloc1->set_r_address(address);
+ sreloc1->set_r_value(entry.toTarget->finalAddress());
+ }
+ else {
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(0);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+ }
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreX86PCRel16:
+ if ( !external && (entry.toAddend != 0) ) {
+ // use scattered reloc is target offset is non-zero
+ sreloc1->set_r_scattered(true);
+ sreloc1->set_r_pcrel(true);
+ sreloc1->set_r_length(1);
+ sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+ sreloc1->set_r_address(address);
+ sreloc1->set_r_value(entry.toTarget->finalAddress());
+ }
+ else {
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(1);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+ }
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreLittleEndian32:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ if ( entry.fromTarget != NULL ) {
+ // this is a pointer-diff
+ sreloc1->set_r_scattered(true);
+ sreloc1->set_r_pcrel(false);
+ sreloc1->set_r_length(2);
+ if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
+ sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
+ else
+ sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
+ sreloc1->set_r_address(address);
+ if ( entry.toTarget == entry.inAtom ) {
+ if ( entry.toAddend > entry.toTarget->size() )
+ sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.offsetInAtom);
+ else
+ sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+ }
+ else
+ sreloc1->set_r_value(entry.toTarget->finalAddress());
+ sreloc2->set_r_scattered(true);
+ sreloc2->set_r_pcrel(false);
+ sreloc2->set_r_length(2);
+ sreloc2->set_r_type(GENERIC_RELOC_PAIR);
+ sreloc2->set_r_address(0);
+ if ( entry.fromTarget == entry.inAtom ) {
+ if ( entry.fromAddend > entry.fromTarget->size() )
+ sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom);
+ else
+ sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
+ }
+ else
+ sreloc2->set_r_value(entry.fromTarget->finalAddress());
+ relocs.push_back(reloc1);
+ relocs.push_back(reloc2);
+ }
+ else {
+ // regular pointer
+ if ( !external && (entry.toAddend != 0) && (entry.toTarget->symbolTableInclusion() != ld::Atom::symbolTableNotIn) ) {
+ // use scattered reloc if target offset is non-zero into named atom (5658046)
+ sreloc1->set_r_scattered(true);
+ sreloc1->set_r_pcrel(false);
+ sreloc1->set_r_length(2);
+ sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+ sreloc1->set_r_address(address);
+ sreloc1->set_r_value(entry.toTarget->finalAddress());
+ }
+ else {
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+ }
+ relocs.push_back(reloc1);
+ }
+ break;
+ case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreX86Abs32TLVLoad:
+ case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(entry.kind == ld::Fixup::kindStoreX86PCRel32TLVLoad);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(GENERIC_RLEOC_TLV);
+ relocs.push_back(reloc1);
+ break;
+ default:
+ assert(0 && "need to handle -r reloc");
+
+ }
+}
+
+
+
+#if SUPPORT_ARCH_arm_any
+template <>
+void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection* sect,
+ const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+ macho_relocation_info<P> reloc1;
+ macho_relocation_info<P> reloc2;
+ macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
+ macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
+ uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+ bool external = entry.toTargetUsesExternalReloc;
+ uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+ bool fromExternal = false;
+ uint32_t fromSymbolNum = 0;
+ if ( entry.fromTarget != NULL ) {
+ fromExternal = entry.fromTargetUsesExternalReloc;
+ fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
+ }
+
+
+ switch ( entry.kind ) {
+ case ld::Fixup::kindStoreTargetAddressARMBranch24:
+ case ld::Fixup::kindStoreARMBranch24:
+ case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+ case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+ if ( !external && (entry.toAddend != 0) ) {
+ // use scattered reloc is target offset is non-zero
+ sreloc1->set_r_scattered(true);
+ sreloc1->set_r_pcrel(true);
+ sreloc1->set_r_length(2);
+ sreloc1->set_r_type(ARM_RELOC_BR24);
+ sreloc1->set_r_address(address);
+ sreloc1->set_r_value(entry.toTarget->finalAddress());
+ }
+ else {
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM_RELOC_BR24);
+ }
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+ case ld::Fixup::kindStoreThumbBranch22:
+ case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+ case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+ if ( !external && (entry.toAddend != 0) ) {
+ // use scattered reloc is target offset is non-zero
+ sreloc1->set_r_scattered(true);
+ sreloc1->set_r_pcrel(true);
+ sreloc1->set_r_length(2);
+ sreloc1->set_r_type(ARM_THUMB_RELOC_BR22);
+ sreloc1->set_r_address(address);
+ sreloc1->set_r_value(entry.toTarget->finalAddress());
+ }
+ else {
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM_THUMB_RELOC_BR22);
+ }
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreLittleEndian32:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ if ( entry.fromTarget != NULL ) {
+ // this is a pointer-diff
+ sreloc1->set_r_scattered(true);
+ sreloc1->set_r_pcrel(false);
+ sreloc1->set_r_length(2);
+ if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
+ sreloc1->set_r_type(ARM_RELOC_LOCAL_SECTDIFF);
+ else
+ sreloc1->set_r_type(ARM_RELOC_SECTDIFF);
+ sreloc1->set_r_address(address);
+ if ( entry.toTarget == entry.inAtom ) {
+ if ( entry.toAddend > entry.toTarget->size() )
+ sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.offsetInAtom);
+ else
+ sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+ }
+ else {
+ sreloc1->set_r_value(entry.toTarget->finalAddress());
+ }
+ sreloc2->set_r_scattered(true);
+ sreloc2->set_r_pcrel(false);
+ sreloc2->set_r_length(2);
+ sreloc2->set_r_type(ARM_RELOC_PAIR);
+ sreloc2->set_r_address(0);
+ if ( entry.fromTarget == entry.inAtom ) {
+ //unsigned int pcBaseOffset = entry.inAtom->isThumb() ? 4 : 8;
+ //if ( entry.fromAddend > pcBaseOffset )
+ // sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend-pcBaseOffset);
+ //else
+ sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
+ }
+ else {
+ sreloc2->set_r_value(entry.fromTarget->finalAddress());
+ }
+ relocs.push_back(reloc1);
+ relocs.push_back(reloc2);
+ }
+ else {
+ // regular pointer
+ if ( !external && (entry.toAddend != 0) ) {
+ // use scattered reloc is target offset is non-zero
+ sreloc1->set_r_scattered(true);
+ sreloc1->set_r_pcrel(false);
+ sreloc1->set_r_length(2);
+ sreloc1->set_r_type(ARM_RELOC_VANILLA);
+ sreloc1->set_r_address(address);
+ sreloc1->set_r_value(entry.toTarget->finalAddress());
+ }
+ else {
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM_RELOC_VANILLA);
+ }
+ relocs.push_back(reloc1);
+ }
+ break;
+
+ case ld::Fixup::kindStoreARMLow16:
+ case ld::Fixup::kindStoreARMHigh16:
+ case ld::Fixup::kindStoreThumbLow16:
+ case ld::Fixup::kindStoreThumbHigh16:
+ {
+ int len = 0;
+ uint32_t otherHalf = 0;
+ uint32_t value = entry.toTarget->finalAddress()+entry.toAddend;
+ if ( entry.fromTarget != NULL )
+ value -= (entry.fromTarget->finalAddress()+entry.fromAddend);
+ switch ( entry.kind ) {
+ case ld::Fixup::kindStoreARMLow16:
+ len = 0;
+ otherHalf = value >> 16;
+ break;
+ case ld::Fixup::kindStoreARMHigh16:
+ len = 1;
+ otherHalf = value & 0xFFFF;
+ break;
+ case ld::Fixup::kindStoreThumbLow16:
+ len = 2;
+ otherHalf = value >> 16;
+ break;
+ case ld::Fixup::kindStoreThumbHigh16:
+ len = 3;
+ otherHalf = value & 0xFFFF;
+ break;
+ default:
+ break;
+ }
+ if ( entry.fromTarget != NULL ) {
+ // this is a sect-diff
+ sreloc1->set_r_scattered(true);
+ sreloc1->set_r_pcrel(false);
+ sreloc1->set_r_length(len);
+ sreloc1->set_r_type(ARM_RELOC_HALF_SECTDIFF);
+ sreloc1->set_r_address(address);
+ sreloc1->set_r_value(entry.toTarget->finalAddress());
+ sreloc2->set_r_scattered(true);
+ sreloc2->set_r_pcrel(false);
+ sreloc2->set_r_length(len);
+ sreloc2->set_r_type(ARM_RELOC_PAIR);
+ sreloc2->set_r_address(otherHalf);
+ if ( entry.fromTarget == entry.inAtom )
+ sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
+ else
+ sreloc2->set_r_value(entry.fromTarget->finalAddress());
+ relocs.push_back(reloc1);
+ relocs.push_back(reloc2);
+ }
+ else {
+ // this is absolute address
+ if ( !external && (entry.toAddend != 0) ) {
+ // use scattered reloc is target offset is non-zero
+ sreloc1->set_r_scattered(true);
+ sreloc1->set_r_pcrel(false);
+ sreloc1->set_r_length(len);
+ sreloc1->set_r_type(ARM_RELOC_HALF);
+ sreloc1->set_r_address(address);
+ sreloc1->set_r_value(entry.toTarget->finalAddress());
+ reloc2.set_r_address(otherHalf);
+ reloc2.set_r_symbolnum(0);
+ reloc2.set_r_pcrel(false);
+ reloc2.set_r_length(len);
+ reloc2.set_r_extern(false);
+ reloc2.set_r_type(ARM_RELOC_PAIR);
+ relocs.push_back(reloc1);
+ relocs.push_back(reloc2);
+ }
+ else {
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(len);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM_RELOC_HALF);
+ reloc2.set_r_address(otherHalf); // other half
+ reloc2.set_r_symbolnum(0);
+ reloc2.set_r_pcrel(false);
+ reloc2.set_r_length(len);
+ reloc2.set_r_extern(false);
+ reloc2.set_r_type(ARM_RELOC_PAIR);
+ relocs.push_back(reloc1);
+ relocs.push_back(reloc2);
+ }
+ }
+ }
+ break;
+
+ default:
+ assert(0 && "need to handle -r reloc");
+
+ }
+}
+#endif
+
+
+
+template <typename A>
+void SectionRelocationsAtom<A>::addSectionReloc(ld::Internal::FinalSection* sect, ld::Fixup::Kind kind,
+ const ld::Atom* inAtom, uint32_t offsetInAtom,
+ bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+ const ld::Atom* toTarget, uint64_t toAddend,
+ const ld::Atom* fromTarget, uint64_t fromAddend)
+{
+ Entry entry;
+ entry.kind = kind;
+ entry.toTargetUsesExternalReloc = toTargetUsesExternalReloc;
+ entry.fromTargetUsesExternalReloc = fromTargetExternalReloc;
+ entry.inAtom = inAtom;
+ entry.offsetInAtom = offsetInAtom;
+ entry.toTarget = toTarget;
+ entry.toAddend = toAddend;
+ entry.fromTarget = fromTarget;
+ entry.fromAddend = fromAddend;
+
+ static ld::Internal::FinalSection* lastSection = NULL;
+ static SectionAndEntries* lastSectionAndEntries = NULL;
+
+ if ( sect != lastSection ) {
+ for(typename std::vector<SectionAndEntries>::iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
+ if ( sect == it->sect ) {
+ lastSection = sect;
+ lastSectionAndEntries = &*it;
+ break;
+ }
+ }
+ if ( sect != lastSection ) {
+ SectionAndEntries tmp;
+ tmp.sect = sect;
+ _entriesBySection.push_back(tmp);
+ lastSection = sect;
+ lastSectionAndEntries = &_entriesBySection.back();
+ }
+ }
+ lastSectionAndEntries->entries.push_back(entry);
+}
+
+template <typename A>
+void SectionRelocationsAtom<A>::encode()
+{
+ // convert each Entry record to one or two reloc records
+ for(typename std::vector<SectionAndEntries>::iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
+ SectionAndEntries& se = *it;
+ for(typename std::vector<Entry>::iterator eit=se.entries.begin(); eit != se.entries.end(); ++eit) {
+ encodeSectionReloc(se.sect, *eit, se.relocs);
+ }
+ }
+
+ // update sections with start and count or relocs
+ uint32_t index = 0;
+ for(typename std::vector<SectionAndEntries>::iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
+ SectionAndEntries& se = *it;
+ se.sect->relocStart = index;
+ se.sect->relocCount = se.relocs.size();
+ index += se.sect->relocCount;
+ }
+
+}
+
+
+
+template <typename A>
+class IndirectSymbolTableAtom : public ClassicLinkEditAtom
+{
+public:
+ IndirectSymbolTableAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+ : ClassicLinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+ // overrides of ld::Atom
+ virtual const char* name() const { return "indirect symbol table"; }
+ virtual uint64_t size() const;
+ virtual void copyRawContent(uint8_t buffer[]) const;
+ // overrides of ClassicLinkEditAtom
+ virtual void encode();
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ void encodeStubSection(ld::Internal::FinalSection* sect);
+ void encodeLazyPointerSection(ld::Internal::FinalSection* sect);
+ void encodeNonLazyPointerSection(ld::Internal::FinalSection* sect);
+ uint32_t symIndexOfStubAtom(const ld::Atom*);
+ uint32_t symIndexOfLazyPointerAtom(const ld::Atom*);
+ uint32_t symIndexOfNonLazyPointerAtom(const ld::Atom*);
+ uint32_t symbolIndex(const ld::Atom*);
+ bool kextBundlesDontHaveIndirectSymbolTable();
+
+
+ std::vector<uint32_t> _entries;
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section IndirectSymbolTableAtom<A>::_s_section("__LINKEDIT", "__ind_sym_tab", ld::Section::typeLinkEdit, true);
+
+
+
+
+template <typename A>
+uint32_t IndirectSymbolTableAtom<A>::symbolIndex(const ld::Atom* atom)
+{
+ std::map<const ld::Atom*, uint32_t>::iterator pos = this->_writer._atomToSymbolIndex.find(atom);
+ if ( pos != this->_writer._atomToSymbolIndex.end() )
+ return pos->second;
+ //fprintf(stderr, "_atomToSymbolIndex content:\n");
+ //for(std::map<const ld::Atom*, uint32_t>::iterator it = this->_writer._atomToSymbolIndex.begin(); it != this->_writer._atomToSymbolIndex.end(); ++it) {
+ // fprintf(stderr, "%p(%s) => %d\n", it->first, it->first->name(), it->second);
+ //}
+ throwf("internal error: atom not found in symbolIndex(%s)", atom->name());
+}
+
+template <typename A>
+uint32_t IndirectSymbolTableAtom<A>::symIndexOfStubAtom(const ld::Atom* stubAtom)
+{
+ for (ld::Fixup::iterator fit = stubAtom->fixupsBegin(); fit != stubAtom->fixupsEnd(); ++fit) {
+ if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+ assert((fit->u.target->contentType() == ld::Atom::typeLazyPointer)
+ || (fit->u.target->contentType() == ld::Atom::typeLazyDylibPointer));
+ return symIndexOfLazyPointerAtom(fit->u.target);
+ }
+ }
+ throw "internal error: stub missing fixup to lazy pointer";
+}
+
+
+template <typename A>
+uint32_t IndirectSymbolTableAtom<A>::symIndexOfLazyPointerAtom(const ld::Atom* lpAtom)
+{
+ for (ld::Fixup::iterator fit = lpAtom->fixupsBegin(); fit != lpAtom->fixupsEnd(); ++fit) {
+ if ( fit->kind == ld::Fixup::kindLazyTarget ) {
+ assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+ return symbolIndex(fit->u.target);
+ }
+ }
+ throw "internal error: lazy pointer missing fixupLazyTarget fixup";
+}
+
+template <typename A>
+uint32_t IndirectSymbolTableAtom<A>::symIndexOfNonLazyPointerAtom(const ld::Atom* nlpAtom)
+{
+ //fprintf(stderr, "symIndexOfNonLazyPointerAtom(%p) %s\n", nlpAtom, nlpAtom->name());
+ for (ld::Fixup::iterator fit = nlpAtom->fixupsBegin(); fit != nlpAtom->fixupsEnd(); ++fit) {
+ // non-lazy-pointer to a stripped symbol => no symbol index
+ if ( fit->clusterSize != ld::Fixup::k1of1 )
+ return INDIRECT_SYMBOL_LOCAL;
+ const ld::Atom* target;
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingDirectlyBound:
+ target = fit->u.target;
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ target = _state.indirectBindingTable[fit->u.bindingIndex];
+ break;
+ default:
+ throw "internal error: unexpected non-lazy pointer binding";
+ }
+ bool targetIsGlobal = (target->scope() == ld::Atom::scopeGlobal);
+ switch ( target->definition() ) {
+ case ld::Atom::definitionRegular:
+ if ( targetIsGlobal ) {
+ if ( _options.outputKind() == Options::kObjectFile ) {
+ // nlpointer to global symbol uses indirect symbol table in .o files
+ return symbolIndex(target);
+ }
+ else if ( target->combine() == ld::Atom::combineByName ) {
+ // dyld needs to bind nlpointer to global weak def
+ return symbolIndex(target);
+ }
+ else if ( _options.nameSpace() != Options::kTwoLevelNameSpace ) {
+ // dyld needs to bind nlpointer to global def linked for flat namespace
+ return symbolIndex(target);
+ }
+ }
+ break;
+ case ld::Atom::definitionTentative:
+ case ld::Atom::definitionAbsolute:
+ if ( _options.outputKind() == Options::kObjectFile ) {
+ // tentative def in .o file always uses symbol index
+ return symbolIndex(target);
+ }
+ // dyld needs to bind nlpointer to global def linked for flat namespace
+ if ( targetIsGlobal && _options.nameSpace() != Options::kTwoLevelNameSpace )
+ return symbolIndex(target);
+ break;
+ case ld::Atom::definitionProxy:
+ // dyld needs to bind nlpointer to something in another dylib
+ {
+ const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
+ if ( (dylib != NULL) && dylib->willBeLazyLoadedDylib() )
+ throwf("illegal data reference to %s in lazy loaded dylib %s", target->name(), dylib->path());
+ }
+ return symbolIndex(target);
+ }
+ }
+ if ( nlpAtom->fixupsBegin() == nlpAtom->fixupsEnd() ) {
+ // no fixups means this is the ImageLoader cache slot
+ return INDIRECT_SYMBOL_ABS;
+ }
+
+ // The magic index INDIRECT_SYMBOL_LOCAL tells dyld it should does not need to bind
+ // this non-lazy pointer.
+ return INDIRECT_SYMBOL_LOCAL;
+}
+
+
+
+template <typename A>
+void IndirectSymbolTableAtom<A>::encodeStubSection(ld::Internal::FinalSection* sect)
+{
+ sect->indirectSymTabStartIndex = _entries.size();
+ sect->indirectSymTabElementSize = sect->atoms[0]->size();
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ _entries.push_back(symIndexOfStubAtom(*ait));
+ }
+}
+
+template <typename A>
+void IndirectSymbolTableAtom<A>::encodeLazyPointerSection(ld::Internal::FinalSection* sect)
+{
+ sect->indirectSymTabStartIndex = _entries.size();
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ _entries.push_back(symIndexOfLazyPointerAtom(*ait));
+ }
+}
+
+template <typename A>
+void IndirectSymbolTableAtom<A>::encodeNonLazyPointerSection(ld::Internal::FinalSection* sect)
+{
+ sect->indirectSymTabStartIndex = _entries.size();
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ _entries.push_back(symIndexOfNonLazyPointerAtom(*ait));
+ }
+}
+
+template <typename A>
+bool IndirectSymbolTableAtom<A>::kextBundlesDontHaveIndirectSymbolTable()
+{
+ return true;
+}
+
+template <typename A>
+void IndirectSymbolTableAtom<A>::encode()
+{
+ // static executables should not have an indirect symbol table, unless PIE
+ if ( (this->_options.outputKind() == Options::kStaticExecutable) && !_options.positionIndependentExecutable() )
+ return;
+
+ // x86_64 kext bundles should not have an indirect symbol table
+ if ( (this->_options.outputKind() == Options::kKextBundle) && kextBundlesDontHaveIndirectSymbolTable() )
+ return;
+
+ // slidable static executables (-static -pie) should not have an indirect symbol table
+ if ( (this->_options.outputKind() == Options::kStaticExecutable) && this->_options.positionIndependentExecutable() )
+ return;
+
+ // find all special sections that need a range of the indirect symbol table section
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = this->_state.sections.begin(); sit != this->_state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ switch ( sect->type() ) {
+ case ld::Section::typeStub:
+ case ld::Section::typeStubClose:
+ this->encodeStubSection(sect);
+ break;
+ case ld::Section::typeLazyPointerClose:
+ case ld::Section::typeLazyPointer:
+ case ld::Section::typeLazyDylibPointer:
+ this->encodeLazyPointerSection(sect);
+ break;
+ case ld::Section::typeNonLazyPointer:
+ this->encodeNonLazyPointerSection(sect);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+template <typename A>
+uint64_t IndirectSymbolTableAtom<A>::size() const
+{
+ return _entries.size() * sizeof(uint32_t);
+}
+
+template <typename A>
+void IndirectSymbolTableAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ uint32_t* array = (uint32_t*)buffer;
+ for(unsigned long i=0; i < _entries.size(); ++i) {
+ E::set32(array[i], _entries[i]);
+ }
+}
+
+
+
+
+
+
+
+
+} // namespace tool
+} // namespace ld
+
+#endif // __LINKEDIT_CLASSIC_HPP__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <mach/vm_prot.h>
+#include <sys/sysctl.h>
+#include <mach-o/dyld.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <spawn.h>
+#include <cxxabi.h>
+#include <Availability.h>
+
+#include <vector>
+
+#include "Options.h"
+#include "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+#include "Snapshot.h"
+
+// upward dependency on lto::version()
+namespace lto {
+ extern const char* version();
+}
+
+// magic to place command line in crash reports
+const int crashreporterBufferSize = 2000;
+static char crashreporterBuffer[crashreporterBufferSize];
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+ #include <CrashReporterClient.h>
+ // hack until ld does not need to build on 10.6 anymore
+ struct crashreporter_annotations_t gCRAnnotations
+ __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION)))
+ = { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0 };
+#else
+ extern "C" char* __crashreporter_info__;
+ __attribute__((used))
+ char* __crashreporter_info__ = crashreporterBuffer;
+#endif
+
+
+static bool sEmitWarnings = true;
+static bool sFatalWarnings = false;
+static const char* sWarningsSideFilePath = NULL;
+static FILE* sWarningsSideFile = NULL;
+static int sWarningsCount = 0;
+
+void warning(const char* format, ...)
+{
+ ++sWarningsCount;
+ if ( sEmitWarnings ) {
+ va_list list;
+ if ( sWarningsSideFilePath != NULL ) {
+ if ( sWarningsSideFile == NULL )
+ sWarningsSideFile = fopen(sWarningsSideFilePath, "a");
+ }
+ va_start(list, format);
+ fprintf(stderr, "ld: warning: ");
+ vfprintf(stderr, format, list);
+ fprintf(stderr, "\n");
+ if ( sWarningsSideFile != NULL ) {
+ fprintf(sWarningsSideFile, "ld: warning: ");
+ vfprintf(sWarningsSideFile, format, list);
+ fprintf(sWarningsSideFile, "\n");
+ fflush(sWarningsSideFile);
+ }
+ va_end(list);
+ }
+}
+
+void throwf(const char* format, ...)
+{
+ va_list list;
+ char* p;
+ va_start(list, format);
+ vasprintf(&p, format, list);
+ va_end(list);
+
+ const char* t = p;
+ throw t;
+}
+
+bool Options::FileInfo::checkFileExists(const char *p)
+{
+ struct stat statBuffer;
+ if (p == NULL) p = path;
+ if ( stat(p, &statBuffer) == 0 ) {
+ if (p != path) path = strdup(p);
+ fileLen = statBuffer.st_size;
+ modTime = statBuffer.st_mtime;
+ return true;
+ }
+ return false;
+}
+
+Options::Options(int argc, const char* argv[])
+ : fOutputFile("a.out"), fArchitecture(0), fSubArchitecture(0), fArchitectureName("unknown"), fOutputKind(kDynamicExecutable),
+ fHasPreferredSubType(false), fArchSupportsThumb2(false), fPrebind(false), fBindAtLoad(false), fKeepPrivateExterns(false),
+ fNeedsModuleTable(false), fIgnoreOtherArchFiles(false), fErrorOnOtherArchFiles(false), fForceSubtypeAll(false),
+ fInterposeMode(kInterposeNone), fDeadStrip(false), fNameSpace(kTwoLevelNameSpace),
+ fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fFinalName(NULL), fEntryName("start"),
+ fBaseAddress(0), fMaxAddress(0x7FFFFFFFFFFFFFFFLL),
+ fBaseWritableAddress(0), fSplitSegs(false),
+ fExportMode(kExportDefault), fLibrarySearchMode(kSearchDylibAndArchiveInEachDir),
+ fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(true),
+ fWeakReferenceMismatchTreatment(kWeakReferenceMismatchNonWeak),
+ fClientName(NULL),
+ fUmbrellaName(NULL), fInitFunctionName(NULL), fDotOutputFile(NULL), fExecutablePath(NULL),
+ fBundleLoader(NULL), fDtraceScriptName(NULL), fSegAddrTablePath(NULL), fMapPath(NULL),
+ fDyldInstallPath("/usr/lib/dyld"), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL),
+ fZeroPageSize(ULLONG_MAX), fStackSize(0), fStackAddr(0), fSourceVersion(0), fSDKVersion(0), fExecutableStack(false),
+ fNonExecutableHeap(false), fDisableNonExecutableHeap(false),
+ fMinimumHeaderPad(32), fSegmentAlignment(4096),
+ fCommonsMode(kCommonsIgnoreDylibs), fUUIDMode(kUUIDContent), fLocalSymbolHandling(kLocalSymbolsAll), fWarnCommons(false),
+ fVerbose(false), fKeepRelocations(false), fWarnStabs(false),
+ fTraceDylibSearching(false), fPause(false), fStatistics(false), fPrintOptions(false),
+ fSharedRegionEligible(false), fPrintOrderFileStatistics(false),
+ fReadOnlyx86Stubs(false), fPositionIndependentExecutable(false), fPIEOnCommandLine(false),
+ fDisablePositionIndependentExecutable(false), fMaxMinimumHeaderPad(false),
+ fDeadStripDylibs(false), fAllowTextRelocs(false), fWarnTextRelocs(false), fKextsUseStubs(false),
+ fUsingLazyDylibLinking(false), fEncryptable(true),
+ fOrderData(true), fMarkDeadStrippableDylib(false),
+ fMakeCompressedDyldInfo(true), fMakeCompressedDyldInfoForceOff(false), fNoEHLabels(false),
+ fAllowCpuSubtypeMismatches(false), fUseSimplifiedDylibReExports(false),
+ fObjCABIVersion2Override(false), fObjCABIVersion1Override(false), fCanUseUpwardDylib(false),
+ fFullyLoadArchives(false), fLoadAllObjcObjectsFromArchives(false), fFlatNamespace(false),
+ fLinkingMainExecutable(false), fForFinalLinkedImage(false), fForStatic(false),
+ fForDyld(false), fMakeTentativeDefinitionsReal(false), fWhyLoad(false), fRootSafe(false),
+ fSetuidSafe(false), fImplicitlyLinkPublicDylibs(true), fAddCompactUnwindEncoding(true),
+ fWarnCompactUnwind(false), fRemoveDwarfUnwindIfCompactExists(false),
+ fAutoOrderInitializers(true), fOptimizeZeroFill(true), fMergeZeroFill(false), fLogObjectFiles(false),
+ fLogAllFiles(false), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false),
+ fOutputSlidable(false), fWarnWeakExports(false),
+ fObjcGcCompaction(false), fObjCGc(false), fObjCGcOnly(false),
+ fDemangle(false), fTLVSupport(false),
+ fVersionLoadCommand(false), fVersionLoadCommandForcedOn(false),
+ fVersionLoadCommandForcedOff(false), fFunctionStartsLoadCommand(false),
+ fFunctionStartsForcedOn(false), fFunctionStartsForcedOff(false),
+ fDataInCodeInfoLoadCommand(false), fDataInCodeInfoLoadCommandForcedOn(false), fDataInCodeInfoLoadCommandForcedOff(false),
+ fCanReExportSymbols(false), fObjcCategoryMerging(true), fPageAlignDataAtoms(false),
+ fNeedsThreadLoadCommand(false), fEntryPointLoadCommand(false),
+ fEntryPointLoadCommandForceOn(false), fEntryPointLoadCommandForceOff(false),
+ fSourceVersionLoadCommand(false),
+ fSourceVersionLoadCommandForceOn(false), fSourceVersionLoadCommandForceOff(false),
+ fDependentDRInfo(false), fDependentDRInfoForcedOn(false), fDependentDRInfoForcedOff(false),
+ fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
+ fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset),
+ fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL)
+{
+ this->checkForClassic(argc, argv);
+ this->parsePreCommandLineEnvironmentSettings();
+ this->parse(argc, argv);
+ this->parsePostCommandLineEnvironmentSettings();
+ this->reconfigureDefaults();
+ this->checkIllegalOptionCombinations();
+}
+
+Options::~Options()
+{
+}
+
+bool Options::errorBecauseOfWarnings() const
+{
+ return (sFatalWarnings && (sWarningsCount > 0));
+}
+
+
+const char* Options::installPath() const
+{
+ if ( fDylibInstallName != NULL )
+ return fDylibInstallName;
+ else if ( fFinalName != NULL )
+ return fFinalName;
+ else
+ return fOutputFile;
+}
+
+
+bool Options::interposable(const char* name) const
+{
+ switch ( fInterposeMode ) {
+ case kInterposeNone:
+ return false;
+ case kInterposeAllExternal:
+ return true;
+ case kInterposeSome:
+ return fInterposeList.contains(name);
+ }
+ throw "internal error";
+}
+
+
+bool Options::printWhyLive(const char* symbolName) const
+{
+ return ( fWhyLive.find(symbolName) != fWhyLive.end() );
+}
+
+
+const char* Options::dotOutputFile()
+{
+ return fDotOutputFile;
+}
+
+
+bool Options::hasWildCardExportRestrictList() const
+{
+ // has -exported_symbols_list which contains some wildcards
+ return ((fExportMode == kExportSome) && fExportSymbols.hasWildCards());
+}
+
+bool Options::hasWeakBitTweaks() const
+{
+ // has -exported_symbols_list which contains some wildcards
+ return (!fForceWeakSymbols.empty() || !fForceNotWeakSymbols.empty());
+}
+
+bool Options::allGlobalsAreDeadStripRoots() const
+{
+ // -exported_symbols_list means globals are not exported by default
+ if ( fExportMode == kExportSome )
+ return false;
+ //
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kStaticExecutable:
+ case Options::kPreload:
+ // by default unused globals in a main executable are stripped
+ return false;
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kKextBundle:
+ return true;
+ }
+ return false;
+}
+
+
+bool Options::keepRelocations()
+{
+ return fKeepRelocations;
+}
+
+bool Options::warnStabs()
+{
+ return fWarnStabs;
+}
+
+const char* Options::executablePath()
+{
+ return fExecutablePath;
+}
+
+
+uint32_t Options::initialSegProtection(const char* segName) const
+{
+ for(std::vector<Options::SegmentProtect>::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) {
+ if ( strcmp(it->name, segName) == 0 ) {
+ return it->init;
+ }
+ }
+ if ( strcmp(segName, "__PAGEZERO") == 0 ) {
+ return 0;
+ }
+ else if ( strcmp(segName, "__TEXT") == 0 ) {
+ return VM_PROT_READ | VM_PROT_EXECUTE;
+ }
+ else if ( strcmp(segName, "__LINKEDIT") == 0 ) {
+ return VM_PROT_READ;
+ }
+
+ // all others default to read-write
+ return VM_PROT_READ | VM_PROT_WRITE;
+}
+
+uint32_t Options::maxSegProtection(const char* segName) const
+{
+ // iPhoneOS always uses same protection for max and initial
+ // <rdar://problem/11663436> simulator apps need to use MacOSX max-prot
+ if ( (fIOSVersionMin != ld::iOSVersionUnset) && (fArchitecture != CPU_TYPE_I386) )
+ return initialSegProtection(segName);
+
+ for(std::vector<Options::SegmentProtect>::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) {
+ if ( strcmp(it->name, segName) == 0 ) {
+ return it->max;
+ }
+ }
+ if ( strcmp(segName, "__PAGEZERO") == 0 ) {
+ return 0;
+ }
+ // all others default to all
+ return VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+}
+
+uint64_t Options::segPageSize(const char* segName) const
+{
+ for(std::vector<SegmentSize>::const_iterator it=fCustomSegmentSizes.begin(); it != fCustomSegmentSizes.end(); ++it) {
+ if ( strcmp(it->name, segName) == 0 )
+ return it->size;
+ }
+ return fSegmentAlignment;
+}
+
+uint64_t Options::customSegmentAddress(const char* segName) const
+{
+ for(std::vector<SegmentStart>::const_iterator it=fCustomSegmentAddresses.begin(); it != fCustomSegmentAddresses.end(); ++it) {
+ if ( strcmp(it->name, segName) == 0 )
+ return it->address;
+ }
+ // if custom stack in use, model as segment with custom address
+ if ( (fStackSize != 0) && (strcmp("__UNIXSTACK", segName) == 0) )
+ return fStackAddr - fStackSize;
+ return 0;
+}
+
+bool Options::hasCustomSegmentAddress(const char* segName) const
+{
+ for(std::vector<SegmentStart>::const_iterator it=fCustomSegmentAddresses.begin(); it != fCustomSegmentAddresses.end(); ++it) {
+ if ( strcmp(it->name, segName) == 0 )
+ return true;
+ }
+ // if custom stack in use, model as segment with custom address
+ if ( (fStackSize != 0) && (strcmp("__UNIXSTACK", segName) == 0) )
+ return true;
+ return false;
+}
+
+bool Options::hasCustomSectionAlignment(const char* segName, const char* sectName) const
+{
+ for (std::vector<SectionAlignment>::const_iterator it = fSectionAlignments.begin(); it != fSectionAlignments.end(); ++it) {
+ if ( (strcmp(it->segmentName, segName) == 0) && (strcmp(it->sectionName, sectName) == 0) )
+ return true;
+ }
+ return false;
+}
+
+uint8_t Options::customSectionAlignment(const char* segName, const char* sectName) const
+{
+ for (std::vector<SectionAlignment>::const_iterator it = fSectionAlignments.begin(); it != fSectionAlignments.end(); ++it) {
+ if ( (strcmp(it->segmentName, segName) == 0) && (strcmp(it->sectionName, sectName) == 0) )
+ return it->alignment;
+ }
+ return 0;
+}
+
+
+bool Options::hasExportedSymbolOrder()
+{
+ return (fExportSymbolsOrder.size() > 0);
+}
+
+bool Options::exportedSymbolOrder(const char* sym, unsigned int* order) const
+{
+ NameToOrder::const_iterator pos = fExportSymbolsOrder.find(sym);
+ if ( pos != fExportSymbolsOrder.end() ) {
+ *order = pos->second;
+ return true;
+ }
+ else {
+ *order = 0xFFFFFFFF;
+ return false;
+ }
+}
+
+void Options::loadSymbolOrderFile(const char* fileOfExports, NameToOrder& orderMapping)
+{
+ // read in whole file
+ int fd = ::open(fileOfExports, O_RDONLY, 0);
+ if ( fd == -1 )
+ throwf("can't open -exported_symbols_order file: %s", fileOfExports);
+ struct stat stat_buf;
+ ::fstat(fd, &stat_buf);
+ char* p = (char*)malloc(stat_buf.st_size);
+ if ( p == NULL )
+ throwf("can't process -exported_symbols_order file: %s", fileOfExports);
+
+ if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size )
+ throwf("can't read -exported_symbols_order file: %s", fileOfExports);
+
+ ::close(fd);
+
+ // parse into symbols and add to hash_set
+ unsigned int count = 0;
+ char * const end = &p[stat_buf.st_size];
+ enum { lineStart, inSymbol, inComment } state = lineStart;
+ char* symbolStart = NULL;
+ for (char* s = p; s < end; ++s ) {
+ switch ( state ) {
+ case lineStart:
+ if ( *s =='#' ) {
+ state = inComment;
+ }
+ else if ( !isspace(*s) ) {
+ state = inSymbol;
+ symbolStart = s;
+ }
+ break;
+ case inSymbol:
+ if ( (*s == '\n') || (*s == '\r') ) {
+ *s = '\0';
+ // removing any trailing spaces
+ char* last = s-1;
+ while ( isspace(*last) ) {
+ *last = '\0';
+ --last;
+ }
+ orderMapping[symbolStart] = ++count;
+ symbolStart = NULL;
+ state = lineStart;
+ }
+ break;
+ case inComment:
+ if ( (*s == '\n') || (*s == '\r') )
+ state = lineStart;
+ break;
+ }
+ }
+ if ( state == inSymbol ) {
+ warning("missing line-end at end of file \"%s\"", fileOfExports);
+ int len = end-symbolStart+1;
+ char* temp = new char[len];
+ strlcpy(temp, symbolStart, len);
+
+ // remove any trailing spaces
+ char* last = &temp[len-2];
+ while ( isspace(*last) ) {
+ *last = '\0';
+ --last;
+ }
+ orderMapping[temp] = ++count;
+ }
+
+ // Note: we do not free() the malloc buffer, because the strings are used by the export-set hash table
+}
+
+bool Options::forceWeak(const char* symbolName) const
+{
+ return fForceWeakSymbols.contains(symbolName);
+}
+
+bool Options::forceNotWeak(const char* symbolName) const
+{
+ return fForceNotWeakSymbols.contains(symbolName);
+}
+
+bool Options::forceWeakNonWildCard(const char* symbolName) const
+{
+ return fForceWeakSymbols.containsNonWildcard(symbolName);
+}
+
+bool Options::forceNotWeakNonWildcard(const char* symbolName) const
+{
+ return fForceNotWeakSymbols.containsNonWildcard(symbolName);
+}
+
+
+bool Options::shouldExport(const char* symbolName) const
+{
+ switch (fExportMode) {
+ case kExportSome:
+ return fExportSymbols.contains(symbolName);
+ case kDontExportSome:
+ return ! fDontExportSymbols.contains(symbolName);
+ case kExportDefault:
+ return true;
+ }
+ throw "internal error";
+}
+
+bool Options::shouldReExport(const char* symbolName) const
+{
+ return fReExportSymbols.contains(symbolName);
+}
+
+bool Options::keepLocalSymbol(const char* symbolName) const
+{
+ switch (fLocalSymbolHandling) {
+ case kLocalSymbolsAll:
+ return true;
+ case kLocalSymbolsNone:
+ return false;
+ case kLocalSymbolsSelectiveInclude:
+ return fLocalSymbolsIncluded.contains(symbolName);
+ case kLocalSymbolsSelectiveExclude:
+ return ! fLocalSymbolsExcluded.contains(symbolName);
+ }
+ throw "internal error";
+}
+
+void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype)
+{
+ for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+ if ( (type == t->cpuType) && (subtype == t->cpuSubType) ) {
+ fArchitecture = type;
+ fSubArchitecture = subtype;
+ fArchitectureName = t->archName;
+ fHasPreferredSubType = t->isSubType;
+ fArchSupportsThumb2 = t->supportsThumb2;
+ switch ( type ) {
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64:
+ if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
+ #ifdef DEFAULT_MACOSX_MIN_VERSION
+ warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
+ setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
+ #else
+ warning("-macosx_version_min not specified, assuming 10.6");
+ fMacVersionMin = ld::mac10_6;
+ #endif
+ }
+ if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff )
+ fMakeCompressedDyldInfo = true;
+ break;
+ case CPU_TYPE_ARM:
+ if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
+ #if defined(DEFAULT_IPHONEOS_MIN_VERSION)
+ warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
+ setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
+ #elif defined(DEFAULT_MACOSX_MIN_VERSION)
+ warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
+ setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
+ #else
+ warning("-macosx_version_min not specified, assuming 10.6");
+ fMacVersionMin = ld::mac10_6;
+ #endif
+ }
+ if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff )
+ fMakeCompressedDyldInfo = true;
+ break;
+ }
+ fLinkSnapshot.recordArch(fArchitectureName);
+ return;
+ }
+ }
+ fArchitectureName = "unknown architecture";
+}
+
+void Options::parseArch(const char* arch)
+{
+ if ( arch == NULL )
+ throw "-arch must be followed by an architecture string";
+ for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+ if ( strcmp(t->archName,arch) == 0 ) {
+ fArchitectureName = arch;
+ fArchitecture = t->cpuType;
+ fSubArchitecture = t->cpuSubType;
+ fHasPreferredSubType = t->isSubType;
+ fArchSupportsThumb2 = t->supportsThumb2;
+ return;
+ }
+ }
+ throwf("unknown/unsupported architecture name for: -arch %s", arch);
+}
+
+bool Options::checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result) const
+{
+ char possiblePath[strlen(dir)+strlen(rootName)+strlen(format)+8];
+ sprintf(possiblePath, format, dir, rootName);
+ bool found = result.checkFileExists(possiblePath);
+ if ( fTraceDylibSearching )
+ printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), possiblePath);
+ return found;
+}
+
+
+Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly)
+{
+ FileInfo result;
+ const int rootNameLen = strlen(rootName);
+ // if rootName ends in .o there is no .a vs .dylib choice
+ if ( (rootNameLen > 3) && (strcmp(&rootName[rootNameLen-2], ".o") == 0) ) {
+ for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+ it != fLibrarySearchPaths.end();
+ it++) {
+ const char* dir = *it;
+ if ( checkForFile("%s/%s", dir, rootName, result) )
+ return result;
+ }
+ }
+ else {
+ bool lookForDylibs = ( fOutputKind != Options::kDyld);
+ switch ( fLibrarySearchMode ) {
+ case kSearchAllDirsForDylibsThenAllDirsForArchives:
+ // first look in all directories for just for dylibs
+ if ( lookForDylibs ) {
+ for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+ it != fLibrarySearchPaths.end();
+ it++) {
+ const char* dir = *it;
+ if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) )
+ return result;
+ }
+ for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+ it != fLibrarySearchPaths.end();
+ it++) {
+ const char* dir = *it;
+ if ( checkForFile("%s/lib%s.so", dir, rootName, result) )
+ return result;
+ }
+ }
+ // next look in all directories for just for archives
+ if ( !dylibsOnly ) {
+ for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+ it != fLibrarySearchPaths.end();
+ it++) {
+ const char* dir = *it;
+ if ( checkForFile("%s/lib%s.a", dir, rootName, result) )
+ return result;
+ }
+ }
+ break;
+
+ case kSearchDylibAndArchiveInEachDir:
+ // look in each directory for just for a dylib then for an archive
+ for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+ it != fLibrarySearchPaths.end();
+ it++) {
+ const char* dir = *it;
+ if ( lookForDylibs && checkForFile("%s/lib%s.dylib", dir, rootName, result) )
+ return result;
+ if ( lookForDylibs && checkForFile("%s/lib%s.so", dir, rootName, result) )
+ return result;
+ if ( !dylibsOnly && checkForFile("%s/lib%s.a", dir, rootName, result) )
+ return result;
+ }
+ break;
+ }
+ }
+ throwf("library not found for -l%s", rootName);
+}
+
+Options::FileInfo Options::findFramework(const char* frameworkName)
+{
+ if ( frameworkName == NULL )
+ throw "-framework missing next argument";
+ char temp[strlen(frameworkName)+1];
+ strcpy(temp, frameworkName);
+ const char* name = temp;
+ const char* suffix = NULL;
+ char* comma = strchr(temp, ',');
+ if ( comma != NULL ) {
+ *comma = '\0';
+ suffix = &comma[1];
+ }
+ return findFramework(name, suffix);
+}
+
+Options::FileInfo Options::findFramework(const char* rootName, const char* suffix)
+{
+ 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[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);
+ }
+ }
+ FileInfo result;
+ bool found = result.checkFileExists(possiblePath);
+ if ( fTraceDylibSearching )
+ printf("[Logging for XBS]%sfound framework: '%s'\n",
+ (found ? " " : " not "), possiblePath);
+ if ( found ) {
+ return result;
+ }
+ }
+ // try without suffix
+ if ( suffix != NULL )
+ return findFramework(rootName, NULL);
+ else
+ throwf("framework not found %s", rootName);
+}
+
+Options::FileInfo Options::findFile(const char* path) const
+{
+ FileInfo result;
+
+ // if absolute path and not a .o file, the use SDK prefix
+ if ( (path[0] == '/') && (strcmp(&path[strlen(path)-2], ".o") != 0) ) {
+ const int pathLen = strlen(path);
+ for (std::vector<const char*>::const_iterator it = fSDKPaths.begin(); it != fSDKPaths.end(); it++) {
+ // ??? Shouldn't we be using String here?
+ const char* sdkPathDir = *it;
+ const int sdkPathDirLen = strlen(sdkPathDir);
+ char possiblePath[sdkPathDirLen+pathLen+4];
+ strcpy(possiblePath, sdkPathDir);
+ if ( possiblePath[sdkPathDirLen-1] == '/' )
+ possiblePath[sdkPathDirLen-1] = '\0';
+ strcat(possiblePath, path);
+ if ( result.checkFileExists(possiblePath) ) {
+ return result;
+ }
+ }
+ }
+ // try raw path
+ if ( result.checkFileExists(path) ) {
+ return result;
+ }
+
+ // try @executable_path substitution
+ if ( (strncmp(path, "@executable_path/", 17) == 0) && (fExecutablePath != NULL) ) {
+ char newPath[strlen(fExecutablePath) + strlen(path)];
+ strcpy(newPath, fExecutablePath);
+ char* addPoint = strrchr(newPath,'/');
+ if ( addPoint != NULL )
+ strcpy(&addPoint[1], &path[17]);
+ else
+ strcpy(newPath, &path[17]);
+ if ( result.checkFileExists(newPath) ) {
+ return result;
+ }
+ }
+
+ // not found
+ throwf("file not found: %s", path);
+}
+
+Options::FileInfo Options::findFileUsingPaths(const char* path) const
+{
+ FileInfo result;
+
+ const char* lastSlash = strrchr(path, '/');
+ const char* leafName = (lastSlash == NULL) ? path : &lastSlash[1];
+
+ // Is this in a framework?
+ // /path/Foo.framework/Foo ==> true (Foo)
+ // /path/Foo.framework/Frameworks/Bar.framework/Bar ==> true (Bar)
+ // /path/Foo.framework/Resources/Bar ==> false
+ bool isFramework = false;
+ if ( lastSlash != NULL ) {
+ char frameworkDir[strlen(leafName) + 20];
+ strcpy(frameworkDir, "/");
+ strcat(frameworkDir, leafName);
+ strcat(frameworkDir, ".framework/");
+ if ( strstr(path, frameworkDir) != NULL )
+ isFramework = true;
+ }
+
+ // These are abbreviated versions of the routines findFramework and findLibrary above
+ // because we already know the final name of the file that we're looking for and so
+ // don't need to try variations, just paths. We do need to add the additional bits
+ // onto the framework path though.
+ if ( isFramework ) {
+ for (std::vector<const char*>::const_iterator it = fFrameworkSearchPaths.begin();
+ it != fFrameworkSearchPaths.end();
+ it++) {
+ const char* dir = *it;
+ char possiblePath[PATH_MAX];
+ strcpy(possiblePath, dir);
+ strcat(possiblePath, "/");
+ strcat(possiblePath, leafName);
+ strcat(possiblePath, ".framework");
+
+ //fprintf(stderr,"Finding Framework: %s/%s, leafName=%s\n", possiblePath, leafName, leafName);
+ if ( checkForFile("%s/%s", possiblePath, leafName, result) )
+ return result;
+ }
+ }
+ else {
+ // if this is a .dylib inside a framework, do not search -L paths
+ // <rdar://problem/5427952> ld64's re-export cycle detection logic prevents use of X11 libGL on Leopard
+ int leafLen = strlen(leafName);
+ bool embeddedDylib = ( (leafLen > 6)
+ && (strcmp(&leafName[leafLen-6], ".dylib") == 0)
+ && (strstr(path, ".framework/") != NULL) );
+ if ( !embeddedDylib ) {
+ for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
+ it != fLibrarySearchPaths.end();
+ it++) {
+ const char* dir = *it;
+ //fprintf(stderr,"Finding Library: %s/%s\n", dir, leafName);
+ if ( checkForFile("%s/%s", dir, leafName, result) )
+ return result;
+ }
+ }
+ }
+
+ // If we didn't find it fall back to findFile.
+ return findFile(path);
+}
+
+
+void Options::parseSegAddrTable(const char* segAddrPath, const char* installPth)
+{
+ FILE* file = fopen(segAddrPath, "r");
+ if ( file == NULL ) {
+ warning("-seg_addr_table file cannot be read: %s", segAddrPath);
+ return;
+ }
+
+ char path[PATH_MAX];
+ uint64_t firstColumAddress = 0;
+ uint64_t secondColumAddress = 0;
+ bool hasSecondColumn = false;
+ while ( fgets(path, PATH_MAX, file) != NULL ) {
+ path[PATH_MAX-1] = '\0';
+ char* eol = strchr(path, '\n');
+ if ( eol != NULL )
+ *eol = '\0';
+ // ignore lines not starting with 0x number
+ if ( (path[0] == '0') && (path[1] == 'x') ) {
+ char* p;
+ firstColumAddress = strtoull(path, &p, 16);
+ while ( isspace(*p) )
+ ++p;
+ // see if second column is a number
+ if ( (p[0] == '0') && (p[1] == 'x') ) {
+ secondColumAddress = strtoull(p, &p, 16);
+ hasSecondColumn = true;
+ while ( isspace(*p) )
+ ++p;
+ }
+ while ( isspace(*p) )
+ ++p;
+ if ( p[0] == '/' ) {
+ // remove any trailing whitespace
+ for(char* end = eol-1; (end > p) && isspace(*end); --end)
+ *end = '\0';
+ // see if this line is for the dylib being linked
+ if ( strcmp(p, installPth) == 0 ) {
+ fBaseAddress = firstColumAddress;
+ if ( hasSecondColumn ) {
+ fBaseWritableAddress = secondColumAddress;
+ fSplitSegs = true;
+ }
+ break; // out of while loop
+ }
+ }
+ }
+ }
+
+ fclose(file);
+}
+
+void Options::loadFileList(const char* fileOfPaths, ld::File::Ordinal baseOrdinal)
+{
+ FILE* file;
+ const char* comma = strrchr(fileOfPaths, ',');
+ const char* prefix = NULL;
+ if ( comma != NULL ) {
+ // <rdar://problem/5907981> -filelist fails with comma in path
+ file = fopen(fileOfPaths, "r");
+ if ( file == NULL ) {
+ prefix = comma+1;
+ int realFileOfPathsLen = comma-fileOfPaths;
+ char realFileOfPaths[realFileOfPathsLen+1];
+ strncpy(realFileOfPaths,fileOfPaths, realFileOfPathsLen);
+ realFileOfPaths[realFileOfPathsLen] = '\0';
+ file = fopen(realFileOfPaths, "r");
+ if ( file == NULL )
+ throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", realFileOfPaths, errno, strerror(errno));
+ }
+ }
+ else {
+ file = fopen(fileOfPaths, "r");
+ if ( file == NULL )
+ throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", fileOfPaths, errno, strerror(errno));
+ }
+
+ char path[PATH_MAX];
+ ld::File::Ordinal previousOrdinal = baseOrdinal;
+ while ( fgets(path, PATH_MAX, file) != NULL ) {
+ path[PATH_MAX-1] = '\0';
+ char* eol = strchr(path, '\n');
+ if ( eol != NULL )
+ *eol = '\0';
+ if ( prefix != NULL ) {
+ char builtPath[strlen(prefix)+strlen(path)+2];
+ strcpy(builtPath, prefix);
+ strcat(builtPath, "/");
+ strcat(builtPath, path);
+ if (fPipelineFifo != NULL) {
+ FileInfo info = FileInfo(builtPath);
+ info.ordinal = previousOrdinal.nextFileListOrdinal();
+ previousOrdinal = info.ordinal;
+ info.fromFileList = true;
+ fInputFiles.push_back(info);
+ } else {
+ FileInfo info = findFile(builtPath);
+ info.ordinal = previousOrdinal.nextFileListOrdinal();
+ previousOrdinal = info.ordinal;
+ info.fromFileList = true;
+ fInputFiles.push_back(info);
+ }
+ }
+ else {
+ if (fPipelineFifo != NULL) {
+ FileInfo info = FileInfo(path);
+ info.ordinal = previousOrdinal.nextFileListOrdinal();
+ previousOrdinal = info.ordinal;
+ info.fromFileList = true;
+ fInputFiles.push_back(info);
+ } else {
+ FileInfo info = findFile(path);
+ info.ordinal = previousOrdinal.nextFileListOrdinal();
+ previousOrdinal = info.ordinal;
+ info.fromFileList = true;
+ fInputFiles.push_back(info);
+ }
+ }
+ }
+ fclose(file);
+}
+
+
+void Options::SetWithWildcards::remove(const NameSet& toBeRemoved)
+{
+ for(NameSet::const_iterator it=toBeRemoved.begin(); it != toBeRemoved.end(); ++it) {
+ const char* symbolName = *it;
+ NameSet::iterator pos = fRegular.find(symbolName);
+ if ( pos != fRegular.end() )
+ fRegular.erase(pos);
+ }
+}
+
+bool Options::SetWithWildcards::hasWildCards(const char* symbol)
+{
+ // an exported symbol name containing *, ?, or [ requires wildcard matching
+ return ( strpbrk(symbol, "*?[") != NULL );
+}
+
+void Options::SetWithWildcards::insert(const char* symbol)
+{
+ if ( hasWildCards(symbol) )
+ fWildCard.push_back(symbol);
+ else
+ fRegular.insert(symbol);
+}
+
+bool Options::SetWithWildcards::contains(const char* symbol) const
+{
+ // first look at hash table on non-wildcard symbols
+ if ( fRegular.find(symbol) != fRegular.end() )
+ return true;
+ // next walk list of wild card symbols looking for a match
+ for(std::vector<const char*>::const_iterator it = fWildCard.begin(); it != fWildCard.end(); ++it) {
+ if ( wildCardMatch(*it, symbol) )
+ return true;
+ }
+ return false;
+}
+
+bool Options::SetWithWildcards::containsNonWildcard(const char* symbol) const
+{
+ // look at hash table on non-wildcard symbols
+ return ( fRegular.find(symbol) != fRegular.end() );
+}
+
+
+
+bool Options::SetWithWildcards::inCharRange(const char*& p, unsigned char c) const
+{
+ ++p; // find end
+ const char* b = p;
+ while ( *p != '\0' ) {
+ if ( *p == ']') {
+ const char* e = p;
+ // found beginining [ and ending ]
+ unsigned char last = '\0';
+ for ( const char* s = b; s < e; ++s ) {
+ if ( *s == '-' ) {
+ unsigned char next = *(++s);
+ if ( (last <= c) && (c <= next) )
+ return true;
+ ++s;
+ }
+ else {
+ if ( *s == c )
+ return true;
+ last = *s;
+ }
+ }
+ return false;
+ }
+ ++p;
+ }
+ return false;
+}
+
+bool Options::SetWithWildcards::wildCardMatch(const char* pattern, const char* symbol) const
+{
+ const char* s = symbol;
+ for (const char* p = pattern; *p != '\0'; ++p) {
+ switch ( *p ) {
+ case '*':
+ if ( p[1] == '\0' )
+ return true;
+ for (const char* t = s; *t != '\0'; ++t) {
+ if ( wildCardMatch(&p[1], t) )
+ return true;
+ }
+ return false;
+ case '?':
+ if ( *s == '\0' )
+ return false;
+ ++s;
+ break;
+ case '[':
+ if ( ! inCharRange(p, *s) )
+ return false;
+ ++s;
+ break;
+ default:
+ if ( *s != *p )
+ return false;
+ ++s;
+ }
+ }
+ return (*s == '\0');
+}
+
+
+void Options::loadExportFile(const char* fileOfExports, const char* option, SetWithWildcards& set)
+{
+ if ( fileOfExports == NULL )
+ throwf("missing file after %s", option);
+ // read in whole file
+ int fd = ::open(fileOfExports, O_RDONLY, 0);
+ if ( fd == -1 )
+ throwf("can't open %s file: %s", option, fileOfExports);
+ struct stat stat_buf;
+ ::fstat(fd, &stat_buf);
+ char* p = (char*)malloc(stat_buf.st_size);
+ if ( p == NULL )
+ throwf("can't process %s file: %s", option, fileOfExports);
+
+ if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size )
+ throwf("can't read %s file: %s", option, fileOfExports);
+
+ ::close(fd);
+
+ // parse into symbols and add to hash_set
+ char * const end = &p[stat_buf.st_size];
+ enum { lineStart, inSymbol, inComment } state = lineStart;
+ char* symbolStart = NULL;
+ for (char* s = p; s < end; ++s ) {
+ switch ( state ) {
+ case lineStart:
+ if ( *s =='#' ) {
+ state = inComment;
+ }
+ else if ( !isspace(*s) ) {
+ state = inSymbol;
+ symbolStart = s;
+ }
+ break;
+ case inSymbol:
+ if ( (*s == '\n') || (*s == '\r') ) {
+ *s = '\0';
+ // removing any trailing spaces
+ char* last = s-1;
+ while ( isspace(*last) ) {
+ *last = '\0';
+ --last;
+ }
+ set.insert(symbolStart);
+ symbolStart = NULL;
+ state = lineStart;
+ }
+ break;
+ case inComment:
+ if ( (*s == '\n') || (*s == '\r') )
+ state = lineStart;
+ break;
+ }
+ }
+ if ( state == inSymbol ) {
+ warning("missing line-end at end of file \"%s\"", fileOfExports);
+ int len = end-symbolStart+1;
+ char* temp = new char[len];
+ strlcpy(temp, symbolStart, len);
+
+ // remove any trailing spaces
+ char* last = &temp[len-2];
+ while ( isspace(*last) ) {
+ *last = '\0';
+ --last;
+ }
+ set.insert(temp);
+ }
+
+ // Note: we do not free() the malloc buffer, because the strings are used by the export-set hash table
+}
+
+void Options::parseAliasFile(const char* fileOfAliases)
+{
+ // read in whole file
+ int fd = ::open(fileOfAliases, O_RDONLY, 0);
+ if ( fd == -1 )
+ throwf("can't open alias file: %s", fileOfAliases);
+ struct stat stat_buf;
+ ::fstat(fd, &stat_buf);
+ char* p = (char*)malloc(stat_buf.st_size+1);
+ if ( p == NULL )
+ throwf("can't process alias file: %s", fileOfAliases);
+
+ if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size )
+ throwf("can't read alias file: %s", fileOfAliases);
+ p[stat_buf.st_size] = '\n';
+ ::close(fd);
+
+ // parse into symbols and add to fAliases
+ AliasPair pair;
+ char * const end = &p[stat_buf.st_size+1];
+ enum { lineStart, inRealName, inBetween, inAliasName, inComment } state = lineStart;
+ int lineNumber = 1;
+ for (char* s = p; s < end; ++s ) {
+ switch ( state ) {
+ case lineStart:
+ if ( *s =='#' ) {
+ state = inComment;
+ }
+ else if ( !isspace(*s) ) {
+ state = inRealName;
+ pair.realName = s;
+ }
+ break;
+ case inRealName:
+ if ( *s == '\n' ) {
+ warning("line needs two symbols but has only one at line #%d in \"%s\"", lineNumber, fileOfAliases);
+ ++lineNumber;
+ state = lineStart;
+ }
+ else if ( isspace(*s) ) {
+ *s = '\0';
+ state = inBetween;
+ }
+ break;
+ case inBetween:
+ if ( *s == '\n' ) {
+ warning("line needs two symbols but has only one at line #%d in \"%s\"", lineNumber, fileOfAliases);
+ ++lineNumber;
+ state = lineStart;
+ }
+ else if ( ! isspace(*s) ) {
+ state = inAliasName;
+ pair.alias = s;
+ }
+ break;
+ case inAliasName:
+ if ( *s =='#' ) {
+ *s = '\0';
+ // removing any trailing spaces
+ char* last = s-1;
+ while ( isspace(*last) ) {
+ *last = '\0';
+ --last;
+ }
+ fAliases.push_back(pair);
+ state = inComment;
+ }
+ else if ( *s == '\n' ) {
+ *s = '\0';
+ // removing any trailing spaces
+ char* last = s-1;
+ while ( isspace(*last) ) {
+ *last = '\0';
+ --last;
+ }
+ fAliases.push_back(pair);
+ state = lineStart;
+ }
+ break;
+ case inComment:
+ if ( *s == '\n' )
+ state = lineStart;
+ break;
+ }
+ }
+
+ // Note: we do not free() the malloc buffer, because the strings therein are used by fAliases
+}
+
+
+
+void Options::setUndefinedTreatment(const char* treatment)
+{
+ if ( treatment == NULL )
+ throw "-undefined missing [ warning | error | suppress | dynamic_lookup ]";
+
+ if ( strcmp(treatment, "warning") == 0 )
+ fUndefinedTreatment = kUndefinedWarning;
+ else if ( strcmp(treatment, "error") == 0 )
+ fUndefinedTreatment = kUndefinedError;
+ else if ( strcmp(treatment, "suppress") == 0 )
+ fUndefinedTreatment = kUndefinedSuppress;
+ else if ( strcmp(treatment, "dynamic_lookup") == 0 )
+ fUndefinedTreatment = kUndefinedDynamicLookup;
+ else
+ throw "invalid option to -undefined [ warning | error | suppress | dynamic_lookup ]";
+}
+
+Options::Treatment Options::parseTreatment(const char* treatment)
+{
+ if ( treatment == NULL )
+ return kNULL;
+
+ if ( strcmp(treatment, "warning") == 0 )
+ return kWarning;
+ else if ( strcmp(treatment, "error") == 0 )
+ return kError;
+ else if ( strcmp(treatment, "suppress") == 0 )
+ return kSuppress;
+ else
+ return kInvalid;
+}
+
+void Options::setMacOSXVersionMin(const char* version)
+{
+ if ( version == NULL )
+ throw "-macosx_version_min argument missing";
+
+ if ( (strncmp(version, "10.", 3) == 0) && isdigit(version[3]) ) {
+ unsigned int minorVersion = version[3] - '0';
+ fMacVersionMin = (ld::MacVersionMin)(0x000A0000 | (minorVersion << 8));
+ }
+ else {
+ warning("unknown option to -macosx_version_min, not 10.x");
+ }
+}
+
+void Options::setIOSVersionMin(const char* version)
+{
+ if ( version == NULL )
+ throw "-ios_version_min argument missing";
+ if ( ! isdigit(version[0]) )
+ throw "-ios_version_min argument is not a number";
+ if ( version[1] != '.' )
+ throw "-ios_version_min argument is missing period as second character";
+ if ( ! isdigit(version[2]) )
+ throw "-ios_version_min argument is not a number";
+
+ unsigned int majorVersion = version[0] - '0';
+ unsigned int minorVersion = version[2] - '0';
+ fIOSVersionMin = (ld::IOSVersionMin)((majorVersion << 16) | (minorVersion << 8));
+}
+
+bool Options::minOS(ld::MacVersionMin requiredMacMin, ld::IOSVersionMin requirediPhoneOSMin)
+{
+ if ( fMacVersionMin != ld::macVersionUnset ) {
+ return ( fMacVersionMin >= requiredMacMin );
+ }
+ else {
+ return ( fIOSVersionMin >= requirediPhoneOSMin);
+ }
+}
+
+
+void Options::setWeakReferenceMismatchTreatment(const char* treatment)
+{
+ if ( treatment == NULL )
+ throw "-weak_reference_mismatches missing [ error | weak | non-weak ]";
+
+ if ( strcmp(treatment, "error") == 0 )
+ fWeakReferenceMismatchTreatment = kWeakReferenceMismatchError;
+ else if ( strcmp(treatment, "weak") == 0 )
+ fWeakReferenceMismatchTreatment = kWeakReferenceMismatchWeak;
+ else if ( strcmp(treatment, "non-weak") == 0 )
+ fWeakReferenceMismatchTreatment = kWeakReferenceMismatchNonWeak;
+ else
+ throw "invalid option to -weak_reference_mismatches [ error | weak | non-weak ]";
+}
+
+Options::CommonsMode Options::parseCommonsTreatment(const char* mode)
+{
+ if ( mode == NULL )
+ throw "-commons missing [ ignore_dylibs | use_dylibs | error ]";
+
+ if ( strcmp(mode, "ignore_dylibs") == 0 )
+ return kCommonsIgnoreDylibs;
+ else if ( strcmp(mode, "use_dylibs") == 0 )
+ return kCommonsOverriddenByDylibs;
+ else if ( strcmp(mode, "error") == 0 )
+ return kCommonsConflictsDylibsError;
+ else
+ throw "invalid option to -commons [ ignore_dylibs | use_dylibs | error ]";
+}
+
+void Options::addDylibOverride(const char* paths)
+{
+ if ( paths == NULL )
+ throw "-dylib_file must followed by two colon separated paths";
+ const char* colon = strchr(paths, ':');
+ if ( colon == NULL )
+ throw "-dylib_file must followed by two colon separated paths";
+ int len = colon-paths;
+ char* target = new char[len+2];
+ strncpy(target, paths, len);
+ target[len] = '\0';
+ DylibOverride entry;
+ entry.installName = target;
+ entry.useInstead = &colon[1];
+ fDylibOverrides.push_back(entry);
+}
+
+uint64_t Options::parseAddress(const char* addr)
+{
+ char* endptr;
+ uint64_t result = strtoull(addr, &endptr, 16);
+ return result;
+}
+
+uint32_t Options::parseProtection(const char* prot)
+{
+ uint32_t result = 0;
+ for(const char* p = prot; *p != '\0'; ++p) {
+ switch(tolower(*p)) {
+ case 'r':
+ result |= VM_PROT_READ;
+ break;
+ case 'w':
+ result |= VM_PROT_WRITE;
+ break;
+ case 'x':
+ result |= VM_PROT_EXECUTE;
+ break;
+ case '-':
+ break;
+ default:
+ throwf("unknown -segprot lettter in %s", prot);
+ }
+ }
+ return result;
+}
+
+
+//
+// Parses number of form A[.B[.B[.D[.E]]]] into a uint64_t where the bits are a24.b10.c10.d10.e10
+//
+uint64_t Options::parseVersionNumber64(const char* versionString)
+{
+ uint64_t a = 0;
+ uint64_t b = 0;
+ uint64_t c = 0;
+ uint64_t d = 0;
+ uint64_t e = 0;
+ char* end;
+ a = strtoul(versionString, &end, 10);
+ if ( *end == '.' ) {
+ b = strtoul(&end[1], &end, 10);
+ if ( *end == '.' ) {
+ c = strtoul(&end[1], &end, 10);
+ if ( *end == '.' ) {
+ d = strtoul(&end[1], &end, 10);
+ if ( *end == '.' ) {
+ e = strtoul(&end[1], &end, 10);
+ }
+ }
+ }
+ }
+ if ( (*end != '\0') || (a > 0xFFFFFF) || (b > 0x3FF) || (c > 0x3FF) || (d > 0x3FF) || (e > 0x3FF) )
+ throwf("malformed 64-bit a.b.c.d.e version number: %s", versionString);
+
+ return (a << 40) | ( b << 30 ) | ( c << 20 ) | ( d << 10 ) | e;
+}
+
+
+uint32_t Options::currentVersion32() const
+{
+ // warn if it does not fit into 32 bit vers number
+ uint32_t a = (fDylibCurrentVersion >> 40) & 0xFFFF;
+ uint32_t b = (fDylibCurrentVersion >> 30) & 0xFF;
+ uint32_t c = (fDylibCurrentVersion >> 20) & 0xFF;
+ uint64_t rep32 = ((uint64_t)a << 40) | ((uint64_t)b << 30) | ((uint64_t)c << 20);
+ if ( rep32 != fDylibCurrentVersion ) {
+ warning("truncating -current_version to fit in 32-bit space used by old mach-o format");
+ a = (fDylibCurrentVersion >> 40) & 0xFFFFFF;
+ if ( a > 0xFFFF )
+ a = 0xFFFF;
+ b = (fDylibCurrentVersion >> 30) & 0x3FF;
+ if ( b > 0xFF )
+ b = 0xFF;
+ c = (fDylibCurrentVersion >> 20) & 0x3FF;
+ if ( c > 0xFF )
+ c = 0xFF;
+ }
+ return (a << 16) | ( b << 8 ) | c;
+}
+
+//
+// Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz
+//
+uint32_t Options::parseVersionNumber32(const char* versionString)
+{
+ uint32_t x = 0;
+ uint32_t y = 0;
+ uint32_t z = 0;
+ char* end;
+ x = strtoul(versionString, &end, 10);
+ if ( *end == '.' ) {
+ y = strtoul(&end[1], &end, 10);
+ if ( *end == '.' ) {
+ z = strtoul(&end[1], &end, 10);
+ }
+ }
+ if ( (*end != '\0') || (x > 0xffff) || (y > 0xff) || (z > 0xff) )
+ throwf("malformed 32-bit x.y.z version number: %s", versionString);
+
+ return (x << 16) | ( y << 8 ) | z;
+}
+
+static const char* cstringSymbolName(const char* orderFileString)
+{
+ char* result;
+ asprintf(&result, "cstring=%s", orderFileString);
+ // convert escaped characters
+ char* d = result;
+ for(const char* s=result; *s != '\0'; ++s, ++d) {
+ if ( *s == '\\' ) {
+ ++s;
+ switch ( *s ) {
+ case 'n':
+ *d = '\n';
+ break;
+ case 't':
+ *d = '\t';
+ break;
+ case 'v':
+ *d = '\v';
+ break;
+ case 'b':
+ *d = '\b';
+ break;
+ case 'r':
+ *d = '\r';
+ break;
+ case 'f':
+ *d = '\f';
+ break;
+ case 'a':
+ *d = '\a';
+ break;
+ case '\\':
+ *d = '\\';
+ break;
+ case '?':
+ *d = '\?';
+ break;
+ case '\'':
+ *d = '\r';
+ break;
+ case '\"':
+ *d = '\"';
+ break;
+ case 'x':
+ // hexadecimal value of char
+ {
+ ++s;
+ char value = 0;
+ while ( isxdigit(*s) ) {
+ value *= 16;
+ if ( isdigit(*s) )
+ value += (*s-'0');
+ else
+ value += ((toupper(*s)-'A') + 10);
+ ++s;
+ }
+ *d = value;
+ }
+ break;
+ default:
+ if ( isdigit(*s) ) {
+ // octal value of char
+ char value = 0;
+ while ( isdigit(*s) ) {
+ value = (value << 3) + (*s-'0');
+ ++s;
+ }
+ *d = value;
+ }
+ }
+ }
+ else {
+ *d = *s;
+ }
+ }
+ *d = '\0';
+ return result;
+}
+
+void Options::parseOrderFile(const char* path, bool cstring)
+{
+ // order files override auto-ordering
+ fAutoOrderInitializers = false;
+
+ // read in whole file
+ int fd = ::open(path, O_RDONLY, 0);
+ if ( fd == -1 )
+ throwf("can't open order file: %s", path);
+ struct stat stat_buf;
+ ::fstat(fd, &stat_buf);
+ char* p = (char*)malloc(stat_buf.st_size+1);
+ if ( p == NULL )
+ throwf("can't process order file: %s", path);
+ if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size )
+ throwf("can't read order file: %s", path);
+ ::close(fd);
+ p[stat_buf.st_size] = '\n';
+
+ // parse into vector of pairs
+ char * const end = &p[stat_buf.st_size+1];
+ enum { lineStart, inSymbol, inComment } state = lineStart;
+ char* symbolStart = NULL;
+ for (char* s = p; s < end; ++s ) {
+ switch ( state ) {
+ case lineStart:
+ if ( *s =='#' ) {
+ state = inComment;
+ }
+ else if ( !isspace(*s) || cstring ) {
+ state = inSymbol;
+ symbolStart = s;
+ }
+ break;
+ case inSymbol:
+ if ( (*s == '\n') || (!cstring && (*s == '#')) ) {
+ bool wasComment = (*s == '#');
+ *s = '\0';
+ // removing any trailing spaces
+ char* last = s-1;
+ while ( isspace(*last) ) {
+ *last = '\0';
+ --last;
+ }
+ // if there is an architecture prefix, only use this symbol it if matches current arch
+ if ( strncmp(symbolStart, "ppc:", 4) == 0 ) {
+ symbolStart = NULL;
+ }
+ else if ( strncmp(symbolStart, "ppc64:", 6) == 0 ) {
+ symbolStart = NULL;
+ }
+ else if ( strncmp(symbolStart, "i386:", 5) == 0 ) {
+ if ( fArchitecture == CPU_TYPE_I386 )
+ symbolStart = &symbolStart[5];
+ else
+ symbolStart = NULL;
+ }
+ else if ( strncmp(symbolStart, "x86_64:", 7) == 0 ) {
+ if ( fArchitecture == CPU_TYPE_X86_64 )
+ symbolStart = &symbolStart[7];
+ else
+ symbolStart = NULL;
+ }
+ else if ( strncmp(symbolStart, "arm:", 4) == 0 ) {
+ if ( fArchitecture == CPU_TYPE_ARM )
+ symbolStart = &symbolStart[4];
+ else
+ symbolStart = NULL;
+ }
+ if ( symbolStart != NULL ) {
+ char* objFileName = NULL;
+ char* colon = strstr(symbolStart, ".o:");
+ if ( colon != NULL ) {
+ colon[2] = '\0';
+ objFileName = symbolStart;
+ symbolStart = &colon[3];
+ }
+ // trim leading spaces
+ while ( isspace(*symbolStart) )
+ ++symbolStart;
+ Options::OrderedSymbol pair;
+ if ( cstring )
+ pair.symbolName = cstringSymbolName(symbolStart);
+ else
+ pair.symbolName = symbolStart;
+ pair.objectFileName = objFileName;
+ fOrderedSymbols.push_back(pair);
+ }
+ symbolStart = NULL;
+ if ( wasComment )
+ state = inComment;
+ else
+ state = lineStart;
+ }
+ break;
+ case inComment:
+ if ( *s == '\n' )
+ state = lineStart;
+ break;
+ }
+ }
+ // Note: we do not free() the malloc buffer, because the strings are used by the fOrderedSymbols
+}
+
+void Options::parseSectionOrderFile(const char* segment, const char* section, const char* path)
+{
+ if ( (strcmp(section, "__cstring") == 0) && (strcmp(segment, "__TEXT") == 0) ) {
+ parseOrderFile(path, true);
+ }
+ else if ( (strncmp(section, "__literal",9) == 0) && (strcmp(segment, "__TEXT") == 0) ) {
+ warning("sorting of __literal[4,8,16] sections not supported");
+ }
+ else {
+ // ignore section information and append all symbol names to global order file
+ parseOrderFile(path, false);
+ }
+}
+
+void Options::addSection(const char* segment, const char* section, const char* path)
+{
+ if ( strlen(segment) > 16 )
+ throw "-seccreate segment name max 16 chars";
+ if ( strlen(section) > 16 ) {
+ char* tmp = strdup(section);
+ tmp[16] = '\0';
+ warning("-seccreate section name (%s) truncated to 16 chars (%s)\n", section, tmp);
+ section = tmp;
+ }
+
+ // read in whole file
+ int fd = ::open(path, O_RDONLY, 0);
+ if ( fd == -1 )
+ throwf("can't open -sectcreate file: %s", path);
+ struct stat stat_buf;
+ ::fstat(fd, &stat_buf);
+ char* p = (char*)malloc(stat_buf.st_size);
+ if ( p == NULL )
+ throwf("can't process -sectcreate file: %s", path);
+ if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size )
+ throwf("can't read -sectcreate file: %s", path);
+ ::close(fd);
+
+ // record section to create
+ ExtraSection info = { segment, section, path, (uint8_t*)p, stat_buf.st_size };
+ fExtraSections.push_back(info);
+}
+
+void Options::addSectionAlignment(const char* segment, const char* section, const char* alignmentStr)
+{
+ if ( strlen(segment) > 16 )
+ throw "-sectalign segment name max 16 chars";
+ if ( strlen(section) > 16 )
+ throw "-sectalign section name max 16 chars";
+
+ // argument to -sectalign is a hexadecimal number
+ char* endptr;
+ unsigned long value = strtoul(alignmentStr, &endptr, 16);
+ if ( *endptr != '\0')
+ throw "argument for -sectalign is not a hexadecimal number";
+ if ( value > 0x8000 )
+ throw "argument for -sectalign must be less than or equal to 0x8000";
+ if ( value == 0 ) {
+ warning("zero is not a valid -sectalign");
+ value = 1;
+ }
+
+ // alignment is power of 2 (e.g. page alignment = 12)
+ uint8_t alignment = (uint8_t)__builtin_ctz(value);
+ if ( (unsigned long)(1 << alignment) != value ) {
+ warning("alignment for -sectalign %s %s is not a power of two, using 0x%X",
+ segment, section, 1 << alignment);
+ }
+
+ SectionAlignment info = { segment, section, alignment };
+ fSectionAlignments.push_back(info);
+}
+
+void Options::addLibrary(const FileInfo& info)
+{
+ // if this library has already been added, don't add again (archives are automatically repeatedly searched)
+ for (std::vector<Options::FileInfo>::iterator fit = fInputFiles.begin(); fit != fInputFiles.end(); fit++) {
+ if ( strcmp(info.path, fit->path) == 0 ) {
+ // if dylib is specified again but weak, record that it should be weak
+ if ( info.options.fWeakImport )
+ fit->options.fWeakImport = true;
+ return;
+ }
+ }
+ // add to list
+ fInputFiles.push_back(info);
+}
+
+void Options::warnObsolete(const char* arg)
+{
+ warning("option %s is obsolete and being ignored", arg);
+}
+
+
+
+
+//
+// Process all command line arguments.
+//
+// The only error checking done here is that each option is valid and if it has arguments
+// that they too are valid.
+//
+// The general rule is "last option wins", i.e. if both -bundle and -dylib are specified,
+// whichever was last on the command line is used.
+//
+// Error check for invalid combinations of options is done in checkIllegalOptionCombinations()
+//
+void Options::parse(int argc, const char* argv[])
+{
+ // Store the original args in the link snapshot.
+ fLinkSnapshot.recordRawArgs(argc, argv);
+
+ // pass one builds search list from -L and -F options
+ this->buildSearchPaths(argc, argv);
+
+ // reduce re-allocations
+ fInputFiles.reserve(32);
+
+ // pass two parse all other options
+ for(int i=1; i < argc; ++i) {
+ const char* arg = argv[i];
+
+ if ( arg[0] == '-' ) {
+ // by default, copy one arg to the snapshot link command, and do no file copying
+ int snapshotArgIndex = i;
+ int snapshotArgCount = -1; // -1 means compute count based on change in index
+ int snapshotFileArgIndex = -1; // -1 means no data file parameter to arg
+
+ // Since we don't care about the files passed, just the option names, we do this here.
+ if (fPrintOptions)
+ fprintf (stderr, "[Logging ld64 options]\t%s\n", arg);
+
+ if ( (arg[1] == 'L') || (arg[1] == 'F') ) {
+ snapshotArgCount = 0; // stripped out of link snapshot
+ if (arg[2] == '\0')
+ ++i;
+ // previously handled by buildSearchPaths()
+ }
+ // The one gnu style option we have to keep compatibility
+ // with gcc. Might as well have the single hyphen one as well.
+ else if ( (strcmp(arg, "--help") == 0)
+ || (strcmp(arg, "-help") == 0)) {
+ fprintf (stdout, "ld64: For information on command line options please use 'man ld'.\n");
+ exit (0);
+ }
+ else if ( strcmp(arg, "-arch") == 0 ) {
+ parseArch(argv[++i]);
+ }
+ else if ( strcmp(arg, "-dynamic") == 0 ) {
+ // default
+ }
+ else if ( strcmp(arg, "-static") == 0 ) {
+ fForStatic = true;
+ if ( (fOutputKind != kObjectFile) && (fOutputKind != kKextBundle) ) {
+ fOutputKind = kStaticExecutable;
+ }
+ }
+ else if ( strcmp(arg, "-dylib") == 0 ) {
+ fOutputKind = kDynamicLibrary;
+ }
+ else if ( strcmp(arg, "-bundle") == 0 ) {
+ fOutputKind = kDynamicBundle;
+ }
+ else if ( strcmp(arg, "-dylinker") == 0 ) {
+ fOutputKind = kDyld;
+ }
+ else if ( strcmp(arg, "-execute") == 0 ) {
+ if ( fOutputKind != kStaticExecutable )
+ fOutputKind = kDynamicExecutable;
+ }
+ else if ( strcmp(arg, "-preload") == 0 ) {
+ fOutputKind = kPreload;
+ }
+ else if ( strcmp(arg, "-r") == 0 ) {
+ fOutputKind = kObjectFile;
+ }
+ else if ( strcmp(arg, "-kext") == 0 ) {
+ fOutputKind = kKextBundle;
+ }
+ else if ( strcmp(arg, "-o") == 0 ) {
+ snapshotArgCount = 0;
+ fOutputFile = argv[++i];
+ fLinkSnapshot.setSnapshotName(fOutputFile);
+ }
+ else if ( strncmp(arg, "-lazy-l", 7) == 0 ) {
+ snapshotArgCount = 0;
+ FileInfo info = findLibrary(&arg[7], true);
+ info.options.fLazyLoad = true;
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ addLibrary(info);
+ fUsingLazyDylibLinking = true;
+ }
+ else if ( strcmp(arg, "-lto_library") == 0 ) {
+ snapshotFileArgIndex = 1;
+ fOverridePathlibLTO = argv[++i];
+ if ( fOverridePathlibLTO == NULL )
+ throw "missing argument to -lto_library";
+ }
+ else if ( (arg[1] == 'l') && (strncmp(arg,"-lazy_",6) !=0) ) {
+ snapshotArgCount = 0;
+ FileInfo info = findLibrary(&arg[2]);
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ addLibrary(info);
+ }
+ // This causes a dylib to be weakly bound at
+ // link time. This corresponds to weak_import.
+ else if ( strncmp(arg, "-weak-l", 7) == 0 ) {
+ // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+ snapshotArgCount = 0;
+ FileInfo info = findLibrary(&arg[7]);
+ info.options.fWeakImport = true;
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ addLibrary(info);
+ }
+ // Avoid lazy binding.
+ else if ( strcmp(arg, "-bind_at_load") == 0 ) {
+ fBindAtLoad = true;
+ }
+ else if ( strcmp(arg, "-twolevel_namespace") == 0 ) {
+ fNameSpace = kTwoLevelNameSpace;
+ }
+ else if ( strcmp(arg, "-flat_namespace") == 0 ) {
+ fNameSpace = kFlatNameSpace;
+ }
+ // Also sets a bit to ensure dyld causes everything
+ // in the namespace to be flat.
+ // ??? Deprecate
+ else if ( strcmp(arg, "-force_flat_namespace") == 0 ) {
+ fNameSpace = kForceFlatNameSpace;
+ }
+ // Similar to --whole-archive.
+ else if ( strcmp(arg, "-all_load") == 0 ) {
+ fFullyLoadArchives = true;
+ }
+ else if ( strcmp(arg, "-noall_load") == 0) {
+ warnObsolete(arg);
+ }
+ // Similar to -all_load
+ else if ( strcmp(arg, "-ObjC") == 0 ) {
+ fLoadAllObjcObjectsFromArchives = true;
+ }
+ // Similar to -all_load, but for the following archive only.
+ else if ( strcmp(arg, "-force_load") == 0 ) {
+ FileInfo info = findFile(argv[++i]);
+ info.options.fForceLoad = true;
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ addLibrary(info);
+ }
+ // Library versioning.
+ else if ( (strcmp(arg, "-dylib_compatibility_version") == 0)
+ || (strcmp(arg, "-compatibility_version") == 0)) {
+ const char* vers = argv[++i];
+ if ( vers == NULL )
+ throw "-dylib_compatibility_version missing <version>";
+ fDylibCompatVersion = parseVersionNumber32(vers);
+ }
+ else if ( (strcmp(arg, "-dylib_current_version") == 0)
+ || (strcmp(arg, "-current_version") == 0)) {
+ const char* vers = argv[++i];
+ if ( vers == NULL )
+ throw "-dylib_current_version missing <version>";
+ fDylibCurrentVersion = parseVersionNumber64(vers);
+ }
+ else if ( strcmp(arg, "-sectorder") == 0 ) {
+ if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) )
+ throw "-sectorder missing <segment> <section> <file-path>";
+ snapshotFileArgIndex = 3;
+ parseSectionOrderFile(argv[i+1], argv[i+2], argv[i+3]);
+ i += 3;
+ }
+ else if ( strcmp(arg, "-order_file") == 0 ) {
+ snapshotFileArgIndex = 1;
+ parseOrderFile(argv[++i], false);
+ }
+ else if ( strcmp(arg, "-order_file_statistics") == 0 ) {
+ fPrintOrderFileStatistics = true;
+ }
+ // ??? Deprecate segcreate.
+ // -sectcreate puts whole files into a section in the output.
+ else if ( (strcmp(arg, "-sectcreate") == 0) || (strcmp(arg, "-segcreate") == 0) ) {
+ if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) )
+ throw "-sectcreate missing <segment> <section> <file-path>";
+ snapshotFileArgIndex = 3;
+ addSection(argv[i+1], argv[i+2], argv[i+3]);
+ i += 3;
+ }
+ // Since we have a full path in binary/library names we need to be able to override it.
+ else if ( (strcmp(arg, "-dylib_install_name") == 0)
+ || (strcmp(arg, "-dylinker_install_name") == 0)
+ || (strcmp(arg, "-install_name") == 0)) {
+ fDylibInstallName = argv[++i];
+ if ( fDylibInstallName == NULL )
+ throw "-install_name missing <path>";
+ }
+ // Sets the base address of the output.
+ else if ( (strcmp(arg, "-seg1addr") == 0) || (strcmp(arg, "-image_base") == 0) ) {
+ const char* address = argv[++i];
+ if ( address == NULL )
+ throwf("%s missing <address>", arg);
+ fBaseAddress = parseAddress(address);
+ uint64_t temp = ((fBaseAddress+fSegmentAlignment-1) & (-fSegmentAlignment));
+ if ( fBaseAddress != temp ) {
+ warning("-seg1addr not %lld byte aligned, rounding up", fSegmentAlignment);
+ fBaseAddress = temp;
+ }
+ }
+ else if ( strcmp(arg, "-e") == 0 ) {
+ fEntryName = argv[++i];
+ }
+ // Same as -@ from the FSF linker.
+ else if ( strcmp(arg, "-filelist") == 0 ) {
+ snapshotArgCount = 0;
+ const char* path = argv[++i];
+ if ( (path == NULL) || (path[0] == '-') )
+ throw "-filelist missing <path>";
+ ld::File::Ordinal baseOrdinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ loadFileList(path, baseOrdinal);
+ }
+ else if ( strcmp(arg, "-keep_private_externs") == 0 ) {
+ fKeepPrivateExterns = true;
+ }
+ else if ( strcmp(arg, "-final_output") == 0 ) {
+ fFinalName = argv[++i];
+ }
+ // Ensure that all calls to exported symbols go through lazy pointers. Multi-module
+ // just ensures that this happens for cross object file boundaries.
+ else if ( (strcmp(arg, "-interposable") == 0) || (strcmp(arg, "-multi_module") == 0)) {
+ switch ( fInterposeMode ) {
+ case kInterposeNone:
+ case kInterposeAllExternal:
+ fInterposeMode = kInterposeAllExternal;
+ break;
+ case kInterposeSome:
+ // do nothing, -interposable_list overrides -interposable"
+ break;
+ }
+ }
+ else if ( strcmp(arg, "-interposable_list") == 0 ) {
+ snapshotFileArgIndex = 1;
+ fInterposeMode = kInterposeSome;
+ loadExportFile(argv[++i], "-interposable_list", fInterposeList);
+ }
+ // Default for -interposable/-multi_module/-single_module.
+ else if ( strcmp(arg, "-single_module") == 0 ) {
+ fInterposeMode = kInterposeNone;
+ }
+ else if ( strcmp(arg, "-exported_symbols_list") == 0 ) {
+ snapshotFileArgIndex = 1;
+ if ( fExportMode == kDontExportSome )
+ throw "can't use -exported_symbols_list and -unexported_symbols_list";
+ fExportMode = kExportSome;
+ loadExportFile(argv[++i], "-exported_symbols_list", fExportSymbols);
+ }
+ else if ( strcmp(arg, "-unexported_symbols_list") == 0 ) {
+ snapshotFileArgIndex = 1;
+ if ( fExportMode == kExportSome )
+ throw "can't use -unexported_symbols_list and -exported_symbols_list";
+ fExportMode = kDontExportSome;
+ loadExportFile(argv[++i], "-unexported_symbols_list", fDontExportSymbols);
+ }
+ else if ( strcmp(arg, "-exported_symbol") == 0 ) {
+ if ( fExportMode == kDontExportSome )
+ throw "can't use -exported_symbol and -unexported_symbols";
+ fExportMode = kExportSome;
+ fExportSymbols.insert(argv[++i]);
+ }
+ else if ( strcmp(arg, "-unexported_symbol") == 0 ) {
+ if ( fExportMode == kExportSome )
+ throw "can't use -unexported_symbol and -exported_symbol";
+ fExportMode = kDontExportSome;
+ fDontExportSymbols.insert(argv[++i]);
+ }
+ else if ( strcmp(arg, "-non_global_symbols_no_strip_list") == 0 ) {
+ snapshotFileArgIndex = 1;
+ if ( fLocalSymbolHandling == kLocalSymbolsSelectiveExclude )
+ throw "can't use -non_global_symbols_no_strip_list and -non_global_symbols_strip_list";
+ fLocalSymbolHandling = kLocalSymbolsSelectiveInclude;
+ loadExportFile(argv[++i], "-non_global_symbols_no_strip_list", fLocalSymbolsIncluded);
+ }
+ else if ( strcmp(arg, "-non_global_symbols_strip_list") == 0 ) {
+ snapshotFileArgIndex = 1;
+ if ( fLocalSymbolHandling == kLocalSymbolsSelectiveInclude )
+ throw "can't use -non_global_symbols_no_strip_list and -non_global_symbols_strip_list";
+ fLocalSymbolHandling = kLocalSymbolsSelectiveExclude;
+ loadExportFile(argv[++i], "-non_global_symbols_strip_list", fLocalSymbolsExcluded);
+ }
+ // ??? Deprecate
+ else if ( strcmp(arg, "-no_arch_warnings") == 0 ) {
+ fIgnoreOtherArchFiles = true;
+ }
+ else if ( strcmp(arg, "-force_cpusubtype_ALL") == 0 ) {
+ fForceSubtypeAll = true;
+ fAllowCpuSubtypeMismatches = true;
+ }
+ // Similar to -weak-l but uses the absolute path name to the library.
+ else if ( strcmp(arg, "-weak_library") == 0 ) {
+ // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+ snapshotArgCount = 0;
+ FileInfo info = findFile(argv[++i]);
+ info.options.fWeakImport = true;
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ addLibrary(info);
+ }
+ else if ( strcmp(arg, "-lazy_library") == 0 ) {
+ // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+ snapshotArgCount = 0;
+ FileInfo info = findFile(argv[++i]);
+ info.options.fLazyLoad = true;
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ addLibrary(info);
+ fUsingLazyDylibLinking = true;
+ }
+ else if ( strcmp(arg, "-framework") == 0 ) {
+ snapshotArgCount = 0;
+ FileInfo info = findFramework(argv[++i]);
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ addLibrary(info);
+ }
+ else if ( strcmp(arg, "-weak_framework") == 0 ) {
+ // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+ snapshotArgCount = 0;
+ FileInfo info = findFramework(argv[++i]);
+ info.options.fWeakImport = true;
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ addLibrary(info);
+ }
+ else if ( strcmp(arg, "-lazy_framework") == 0 ) {
+ // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+ snapshotArgCount = 0;
+ FileInfo info = findFramework(argv[++i]);
+ info.options.fLazyLoad = true;
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ addLibrary(info);
+ fUsingLazyDylibLinking = true;
+ }
+ else if ( strcmp(arg, "-search_paths_first") == 0 ) {
+ // previously handled by buildSearchPaths()
+ }
+ else if ( strcmp(arg, "-search_dylibs_first") == 0 ) {
+ // previously handled by buildSearchPaths()
+ }
+ else if ( strcmp(arg, "-undefined") == 0 ) {
+ setUndefinedTreatment(argv[++i]);
+ }
+ // Debugging output flag.
+ else if ( strcmp(arg, "-arch_multiple") == 0 ) {
+ fMessagesPrefixedWithArchitecture = true;
+ }
+ // Specify what to do with relocations in read only
+ // sections like .text. Could be errors, warnings,
+ // or suppressed. Currently we do nothing with the
+ // flag.
+ else if ( strcmp(arg, "-read_only_relocs") == 0 ) {
+ switch ( parseTreatment(argv[++i]) ) {
+ case kNULL:
+ case kInvalid:
+ throw "-read_only_relocs missing [ warning | error | suppress ]";
+ case kWarning:
+ fWarnTextRelocs = true;
+ fAllowTextRelocs = true;
+ break;
+ case kSuppress:
+ fWarnTextRelocs = false;
+ fAllowTextRelocs = true;
+ break;
+ case kError:
+ fWarnTextRelocs = false;
+ fAllowTextRelocs = false;
+ break;
+ }
+ }
+ else if ( strcmp(arg, "-sect_diff_relocs") == 0 ) {
+ warnObsolete(arg);
+ ++i;
+ }
+ // Warn, error or make strong a mismatch between weak
+ // and non-weak references.
+ else if ( strcmp(arg, "-weak_reference_mismatches") == 0 ) {
+ setWeakReferenceMismatchTreatment(argv[++i]);
+ }
+ // For a deployment target of 10.3 and earlier ld64 will
+ // prebind an executable with 0s in all addresses that
+ // are prebound. This can then be fixed up by update_prebinding
+ // later. Prebinding is less useful on 10.4 and greater.
+ else if ( strcmp(arg, "-prebind") == 0 ) {
+ fPrebind = true;
+ }
+ else if ( strcmp(arg, "-noprebind") == 0 ) {
+ warnObsolete(arg);
+ fPrebind = false;
+ }
+ else if ( strcmp(arg, "-prebind_allow_overlap") == 0 ) {
+ warnObsolete(arg);
+ }
+ else if ( strcmp(arg, "-prebind_all_twolevel_modules") == 0 ) {
+ warnObsolete(arg);
+ }
+ else if ( strcmp(arg, "-noprebind_all_twolevel_modules") == 0 ) {
+ warnObsolete(arg);
+ }
+ else if ( strcmp(arg, "-nofixprebinding") == 0 ) {
+ warnObsolete(arg);
+ }
+ // This should probably be deprecated when we respect -L and -F
+ // when searching for libraries.
+ else if ( strcmp(arg, "-dylib_file") == 0 ) {
+ // ignore for snapshot because a stub dylib will be created in the snapshot
+ snapshotArgCount = 0;
+ addDylibOverride(argv[++i]);
+ }
+ // What to expand @executable_path to if found in dependent dylibs
+ else if ( strcmp(arg, "-executable_path") == 0 ) {
+ fExecutablePath = argv[++i];
+ if ( (fExecutablePath == NULL) || (fExecutablePath[0] == '-') )
+ throw "-executable_path missing <path>";
+ // if a directory was passed, add / to end
+ // <rdar://problem/5171880> ld64 can't find @executable _path relative dylibs from our umbrella frameworks
+ struct stat statBuffer;
+ if ( stat(fExecutablePath, &statBuffer) == 0 ) {
+ if ( (statBuffer.st_mode & S_IFMT) == S_IFDIR ) {
+ char* pathWithSlash = new char[strlen(fExecutablePath)+2];
+ strcpy(pathWithSlash, fExecutablePath);
+ strcat(pathWithSlash, "/");
+ fExecutablePath = pathWithSlash;
+ }
+ }
+ }
+ // Aligns all segments to the power of 2 boundary specified.
+ else if ( strcmp(arg, "-segalign") == 0 ) {
+ const char* size = argv[++i];
+ if ( size == NULL )
+ throw "-segalign missing <size>";
+ fSegmentAlignment = parseAddress(size);
+ uint8_t alignment = (uint8_t)__builtin_ctz(fSegmentAlignment);
+ uint32_t p2aligned = (1 << alignment);
+ if ( p2aligned != fSegmentAlignment ) {
+ warning("alignment for -segalign %s is not a power of two, using 0x%X", size, p2aligned);
+ fSegmentAlignment = p2aligned;
+ }
+ }
+ // Puts a specified segment at a particular address that must
+ // be a multiple of the segment alignment.
+ else if ( strcmp(arg, "-segaddr") == 0 ) {
+ SegmentStart seg;
+ seg.name = argv[++i];
+ if ( (seg.name == NULL) || (argv[i+1] == NULL) )
+ throw "-segaddr missing segName Adddress";
+ seg.address = parseAddress(argv[++i]);
+ uint64_t temp = ((seg.address+fSegmentAlignment-1) & (-fSegmentAlignment));
+ if ( seg.address != temp )
+ warning("-segaddr %s not %lld byte aligned", seg.name, fSegmentAlignment);
+ fCustomSegmentAddresses.push_back(seg);
+ }
+ // ??? Deprecate when we deprecate split-seg.
+ else if ( strcmp(arg, "-segs_read_only_addr") == 0 ) {
+ fBaseAddress = parseAddress(argv[++i]);
+ }
+ // ??? Deprecate when we deprecate split-seg.
+ else if ( strcmp(arg, "-segs_read_write_addr") == 0 ) {
+ fBaseWritableAddress = parseAddress(argv[++i]);
+ fSplitSegs = true;
+ }
+ // ??? Deprecate when we get rid of basing at build time.
+ else if ( strcmp(arg, "-seg_addr_table") == 0 ) {
+ snapshotFileArgIndex = 1;
+ const char* name = argv[++i];
+ if ( name == NULL )
+ throw "-seg_addr_table missing argument";
+ fSegAddrTablePath = name;
+ }
+ else if ( strcmp(arg, "-seg_addr_table_filename") == 0 ) {
+ warnObsolete(arg);
+ ++i;
+ }
+ else if ( strcmp(arg, "-segprot") == 0 ) {
+ SegmentProtect seg;
+ seg.name = argv[++i];
+ if ( (seg.name == NULL) || (argv[i+1] == NULL) || (argv[i+2] == NULL) )
+ throw "-segprot missing segName max-prot init-prot";
+ seg.max = parseProtection(argv[++i]);
+ seg.init = parseProtection(argv[++i]);
+ fCustomSegmentProtections.push_back(seg);
+ }
+ else if ( strcmp(arg, "-pagezero_size") == 0 ) {
+ const char* size = argv[++i];
+ if ( size == NULL )
+ throw "-pagezero_size missing <size>";
+ fZeroPageSize = parseAddress(size);
+ uint64_t temp = fZeroPageSize & (-4096); // page align
+ if ( (fZeroPageSize != temp) )
+ warning("-pagezero_size not page aligned, rounding down");
+ fZeroPageSize = temp;
+ }
+ else if ( strcmp(arg, "-stack_addr") == 0 ) {
+ const char* address = argv[++i];
+ if ( address == NULL )
+ throw "-stack_addr missing <address>";
+ fStackAddr = parseAddress(address);
+ }
+ else if ( strcmp(arg, "-stack_size") == 0 ) {
+ const char* size = argv[++i];
+ if ( size == NULL )
+ throw "-stack_size missing <address>";
+ fStackSize = parseAddress(size);
+ uint64_t temp = fStackSize & (-4096); // page align
+ if ( (fStackSize != temp) )
+ warning("-stack_size not page aligned, rounding down");
+ }
+ else if ( strcmp(arg, "-allow_stack_execute") == 0 ) {
+ fExecutableStack = true;
+ }
+ else if ( strcmp(arg, "-allow_heap_execute") == 0 ) {
+ fDisableNonExecutableHeap = true;
+ }
+ else if ( strcmp(arg, "-sectalign") == 0 ) {
+ if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) )
+ throw "-sectalign missing <segment> <section> <file-path>";
+ addSectionAlignment(argv[i+1], argv[i+2], argv[i+3]);
+ i += 3;
+ }
+ else if ( strcmp(arg, "-sectorder_detail") == 0 ) {
+ warnObsolete(arg);
+ }
+ else if ( strcmp(arg, "-sectobjectsymbols") == 0 ) {
+ warnObsolete(arg);
+ i += 2;
+ }
+ else if ( strcmp(arg, "-bundle_loader") == 0 ) {
+ snapshotFileArgIndex = 1;
+ fBundleLoader = argv[++i];
+ if ( (fBundleLoader == NULL) || (fBundleLoader[0] == '-') )
+ throw "-bundle_loader missing <path>";
+ FileInfo info = findFile(fBundleLoader);
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ info.options.fBundleLoader = true;
+ fInputFiles.push_back(info);
+ }
+ else if ( strcmp(arg, "-private_bundle") == 0 ) {
+ warnObsolete(arg);
+ }
+ else if ( strcmp(arg, "-twolevel_namespace_hints") == 0 ) {
+ // FIX FIX
+ }
+ // Use this flag to set default behavior for deployement targets.
+ else if ( strcmp(arg, "-macosx_version_min") == 0 ) {
+ setMacOSXVersionMin(argv[++i]);
+ }
+ else if ( (strcmp(arg, "-ios_version_min") == 0) || (strcmp(arg, "-iphoneos_version_min") == 0) ) {
+ setIOSVersionMin(argv[++i]);
+ }
+ else if ( strcmp(arg, "-ios_simulator_version_min") == 0 ) {
+ setIOSVersionMin(argv[++i]);
+ }
+ else if ( strcmp(arg, "-multiply_defined") == 0 ) {
+ //warnObsolete(arg);
+ ++i;
+ }
+ else if ( strcmp(arg, "-multiply_defined_unused") == 0 ) {
+ warnObsolete(arg);
+ ++i;
+ }
+ else if ( strcmp(arg, "-nomultidefs") == 0 ) {
+ warnObsolete(arg);
+ }
+ // Display each file in which the argument symbol appears and whether
+ // the file defines or references it. This option takes an argument
+ // as -y<symbol> note that there is no space.
+ else if ( strncmp(arg, "-y", 2) == 0 ) {
+ warnObsolete("-y");
+ }
+ // Same output as -y, but output <arg> number of undefined symbols only.
+ else if ( strcmp(arg, "-Y") == 0 ) {
+ //warnObsolete(arg);
+ ++i;
+ }
+ // This option affects all objects linked into the final result.
+ else if ( strcmp(arg, "-m") == 0 ) {
+ warnObsolete(arg);
+ }
+ else if ( (strcmp(arg, "-why_load") == 0) || (strcmp(arg, "-whyload") == 0) ) {
+ fWhyLoad = true;
+ }
+ else if ( strcmp(arg, "-why_live") == 0 ) {
+ const char* name = argv[++i];
+ if ( name == NULL )
+ throw "-why_live missing symbol name argument";
+ fWhyLive.insert(name);
+ }
+ else if ( strcmp(arg, "-u") == 0 ) {
+ const char* name = argv[++i];
+ if ( name == NULL )
+ throw "-u missing argument";
+ fInitialUndefines.push_back(name);
+ }
+ else if ( strcmp(arg, "-U") == 0 ) {
+ const char* name = argv[++i];
+ if ( name == NULL )
+ throw "-U missing argument";
+ fAllowedUndefined.insert(name);
+ }
+ else if ( strcmp(arg, "-s") == 0 ) {
+ warnObsolete(arg);
+ fLocalSymbolHandling = kLocalSymbolsNone;
+ fDebugInfoStripping = Options::kDebugInfoNone;
+ }
+ else if ( strcmp(arg, "-x") == 0 ) {
+ fLocalSymbolHandling = kLocalSymbolsNone;
+ }
+ else if ( strcmp(arg, "-S") == 0 ) {
+ fDebugInfoStripping = Options::kDebugInfoNone;
+ }
+ else if ( strcmp(arg, "-X") == 0 ) {
+ warnObsolete(arg);
+ }
+ else if ( strcmp(arg, "-Si") == 0 ) {
+ warnObsolete(arg);
+ fDebugInfoStripping = Options::kDebugInfoFull;
+ }
+ else if ( strcmp(arg, "-b") == 0 ) {
+ warnObsolete(arg);
+ }
+ else if ( strcmp(arg, "-Sn") == 0 ) {
+ warnObsolete(arg);
+ fDebugInfoStripping = Options::kDebugInfoFull;
+ }
+ else if ( strcmp(arg, "-Sp") == 0 ) {
+ warnObsolete(arg);
+ }
+ else if ( strcmp(arg, "-dead_strip") == 0 ) {
+ fDeadStrip = true;
+ }
+ else if ( strcmp(arg, "-no_dead_strip_inits_and_terms") == 0 ) {
+ fDeadStrip = true;
+ }
+ else if ( strcmp(arg, "-w") == 0 ) {
+ // previously handled by buildSearchPaths()
+ }
+ else if ( strcmp(arg, "-fatal_warnings") == 0 ) {
+ // previously handled by buildSearchPaths()
+ }
+ else if ( strcmp(arg, "-arch_errors_fatal") == 0 ) {
+ fErrorOnOtherArchFiles = true;
+ }
+ else if ( strcmp(arg, "-M") == 0 ) {
+ // FIX FIX
+ }
+ else if ( strcmp(arg, "-headerpad") == 0 ) {
+ const char* size = argv[++i];
+ if ( size == NULL )
+ throw "-headerpad missing argument";
+ fMinimumHeaderPad = parseAddress(size);
+ }
+ else if ( strcmp(arg, "-headerpad_max_install_names") == 0 ) {
+ fMaxMinimumHeaderPad = true;
+ }
+ else if ( strcmp(arg, "-t") == 0 ) {
+ fLogAllFiles = true;
+ }
+ else if ( strcmp(arg, "-whatsloaded") == 0 ) {
+ fLogObjectFiles = true;
+ }
+ else if ( strcmp(arg, "-A") == 0 ) {
+ warnObsolete(arg);
+ ++i;
+ }
+ else if ( strcmp(arg, "-umbrella") == 0 ) {
+ const char* name = argv[++i];
+ if ( name == NULL )
+ throw "-umbrella missing argument";
+ fUmbrellaName = name;
+ }
+ else if ( strcmp(arg, "-allowable_client") == 0 ) {
+ const char* name = argv[++i];
+
+ if ( name == NULL )
+ throw "-allowable_client missing argument";
+
+ fAllowableClients.push_back(name);
+ }
+ else if ( strcmp(arg, "-client_name") == 0 ) {
+ const char* name = argv[++i];
+
+ if ( name == NULL )
+ throw "-client_name missing argument";
+
+ fClientName = name;
+ }
+ else if ( strcmp(arg, "-sub_umbrella") == 0 ) {
+ const char* name = argv[++i];
+ if ( name == NULL )
+ throw "-sub_umbrella missing argument";
+ fSubUmbellas.push_back(name);
+ }
+ else if ( strcmp(arg, "-sub_library") == 0 ) {
+ const char* name = argv[++i];
+ if ( name == NULL )
+ throw "-sub_library missing argument";
+ fSubLibraries.push_back(name);
+ }
+ else if ( strcmp(arg, "-init") == 0 ) {
+ const char* name = argv[++i];
+ if ( name == NULL )
+ throw "-init missing argument";
+ fInitFunctionName = name;
+ }
+ else if ( strcmp(arg, "-dot") == 0 ) {
+ const char* name = argv[++i];
+ if ( name == NULL )
+ throw "-dot missing argument";
+ fDotOutputFile = name;
+ }
+ else if ( strcmp(arg, "-warn_commons") == 0 ) {
+ fWarnCommons = true;
+ }
+ else if ( strcmp(arg, "-commons") == 0 ) {
+ fCommonsMode = parseCommonsTreatment(argv[++i]);
+ }
+ else if ( strcmp(arg, "-keep_relocs") == 0 ) {
+ fKeepRelocations = true;
+ }
+ else if ( strcmp(arg, "-warn_stabs") == 0 ) {
+ fWarnStabs = true;
+ }
+ else if ( strcmp(arg, "-pause") == 0 ) {
+ fPause = true;
+ }
+ else if ( strcmp(arg, "-print_statistics") == 0 ) {
+ fStatistics = true;
+ }
+ else if ( strcmp(arg, "-d") == 0 ) {
+ fMakeTentativeDefinitionsReal = true;
+ }
+ else if ( strcmp(arg, "-v") == 0 ) {
+ // previously handled by buildSearchPaths()
+ }
+ else if ( strcmp(arg, "-Z") == 0 ) {
+ // previously handled by buildSearchPaths()
+ }
+ else if ( strcmp(arg, "-syslibroot") == 0 ) {
+ snapshotArgCount = 0;
+ ++i;
+ // previously handled by buildSearchPaths()
+ }
+ else if ( strcmp(arg, "-no_uuid") == 0 ) {
+ fUUIDMode = kUUIDNone;
+ }
+ else if ( strcmp(arg, "-random_uuid") == 0 ) {
+ fUUIDMode = kUUIDRandom;
+ }
+ else if ( strcmp(arg, "-dtrace") == 0 ) {
+ snapshotFileArgIndex = 1;
+ const char* name = argv[++i];
+ if ( name == NULL )
+ throw "-dtrace missing argument";
+ fDtraceScriptName = name;
+ }
+ else if ( strcmp(arg, "-root_safe") == 0 ) {
+ fRootSafe = true;
+ }
+ else if ( strcmp(arg, "-setuid_safe") == 0 ) {
+ fSetuidSafe = true;
+ }
+ else if ( strcmp(arg, "-alias") == 0 ) {
+ Options::AliasPair pair;
+ pair.realName = argv[++i];
+ if ( pair.realName == NULL )
+ throw "missing argument to -alias";
+ pair.alias = argv[++i];
+ if ( pair.alias == NULL )
+ throw "missing argument to -alias";
+ fAliases.push_back(pair);
+ }
+ else if ( strcmp(arg, "-alias_list") == 0 ) {
+ snapshotFileArgIndex = 1;
+ parseAliasFile(argv[++i]);
+ }
+ // put this last so that it does not interfer with other options starting with 'i'
+ else if ( strncmp(arg, "-i", 2) == 0 ) {
+ const char* colon = strchr(arg, ':');
+ if ( colon == NULL )
+ throwf("unknown option: %s", arg);
+ Options::AliasPair pair;
+ char* temp = new char[colon-arg];
+ strlcpy(temp, &arg[2], colon-arg-1);
+ pair.realName = &colon[1];
+ pair.alias = temp;
+ fAliases.push_back(pair);
+ }
+ else if ( strcmp(arg, "-save-temps") == 0 ) {
+ fSaveTempFiles = true;
+ }
+ else if ( strcmp(arg, "-rpath") == 0 ) {
+ const char* path = argv[++i];
+ if ( path == NULL )
+ throw "missing argument to -rpath";
+ fRPaths.push_back(path);
+ }
+ else if ( strcmp(arg, "-read_only_stubs") == 0 ) {
+ fReadOnlyx86Stubs = true;
+ }
+ else if ( strcmp(arg, "-slow_stubs") == 0 ) {
+ warnObsolete(arg);
+ }
+ else if ( strcmp(arg, "-map") == 0 ) {
+ fMapPath = argv[++i];
+ if ( fMapPath == NULL )
+ throw "missing argument to -map";
+ }
+ else if ( strcmp(arg, "-pie") == 0 ) {
+ fPositionIndependentExecutable = true;
+ fPIEOnCommandLine = true;
+ }
+ else if ( strcmp(arg, "-no_pie") == 0 ) {
+ fDisablePositionIndependentExecutable = true;
+ }
+ else if ( strncmp(arg, "-reexport-l", 11) == 0 ) {
+ // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+ snapshotArgCount = 0;
+ FileInfo info = findLibrary(&arg[11], true);
+ info.options.fReExport = true;
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ addLibrary(info);
+ }
+ else if ( strcmp(arg, "-reexport_library") == 0 ) {
+ // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+ snapshotArgCount = 0;
+ FileInfo info = findFile(argv[++i]);
+ info.options.fReExport = true;
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ addLibrary(info);
+ }
+ else if ( strcmp(arg, "-reexport_framework") == 0 ) {
+ // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+ snapshotArgCount = 0;
+ FileInfo info = findFramework(argv[++i]);
+ info.options.fReExport = true;
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ addLibrary(info);
+ }
+ else if ( strncmp(arg, "-upward-l", 9) == 0 ) {
+ // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+ snapshotArgCount = 0;
+ FileInfo info = findLibrary(&arg[9], true);
+ info.options.fUpward = true;
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ addLibrary(info);
+ }
+ else if ( strcmp(arg, "-upward_library") == 0 ) {
+ // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+ snapshotArgCount = 0;
+ FileInfo info = findFile(argv[++i]);
+ info.options.fUpward = true;
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ addLibrary(info);
+ }
+ else if ( strcmp(arg, "-upward_framework") == 0 ) {
+ // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+ snapshotArgCount = 0;
+ FileInfo info = findFramework(argv[++i]);
+ info.options.fUpward = true;
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ addLibrary(info);
+ }
+ else if ( strcmp(arg, "-dead_strip_dylibs") == 0 ) {
+ fDeadStripDylibs = true;
+ }
+ else if ( strcmp(arg, "-no_implicit_dylibs") == 0 ) {
+ fImplicitlyLinkPublicDylibs = false;
+ }
+ else if ( strcmp(arg, "-new_linker") == 0 ) {
+ // ignore
+ }
+ else if ( strcmp(arg, "-no_encryption") == 0 ) {
+ fEncryptable = false;
+ }
+ else if ( strcmp(arg, "-no_compact_unwind") == 0 ) {
+ fAddCompactUnwindEncoding = false;
+ }
+ else if ( strcmp(arg, "-mllvm") == 0 ) {
+ const char* opts = argv[++i];
+ if ( opts == NULL )
+ throw "missing argument to -mllvm";
+ fLLVMOptions.push_back(opts);
+ }
+ else if ( strcmp(arg, "-no_order_inits") == 0 ) {
+ fAutoOrderInitializers = false;
+ }
+ else if ( strcmp(arg, "-no_order_data") == 0 ) {
+ fOrderData = false;
+ }
+ else if ( strcmp(arg, "-seg_page_size") == 0 ) {
+ SegmentSize seg;
+ seg.name = argv[++i];
+ if ( (seg.name == NULL) || (argv[i+1] == NULL) )
+ throw "-seg_page_size missing segName Adddress";
+ seg.size = parseAddress(argv[++i]);
+ uint64_t temp = seg.size & (-4096); // page align
+ if ( (seg.size != temp) )
+ warning("-seg_page_size %s not 4K aligned, rounding down", seg.name);
+ fCustomSegmentSizes.push_back(seg);
+ }
+ else if ( strcmp(arg, "-mark_dead_strippable_dylib") == 0 ) {
+ fMarkDeadStrippableDylib = true;
+ }
+ else if ( strcmp(arg, "-exported_symbols_order") == 0 ) {
+ snapshotFileArgIndex = 1;
+ loadSymbolOrderFile(argv[++i], fExportSymbolsOrder);
+ }
+ else if ( strcmp(arg, "-no_compact_linkedit") == 0 ) {
+ warnObsolete("-no_compact_linkedit");
+ }
+ else if ( strcmp(arg, "-no_eh_labels") == 0 ) {
+ fNoEHLabels = true;
+ }
+ else if ( strcmp(arg, "-warn_compact_unwind") == 0 ) {
+ fWarnCompactUnwind = true;
+ }
+ else if ( strcmp(arg, "-allow_sub_type_mismatches") == 0 ) {
+ fAllowCpuSubtypeMismatches = true;
+ }
+ else if ( strcmp(arg, "-no_zero_fill_sections") == 0 ) {
+ fOptimizeZeroFill = false;
+ }
+ else if ( strcmp(arg, "-merge_zero_fill_sections") == 0 ) {
+ fMergeZeroFill = true;
+ }
+ else if ( strcmp(arg, "-objc_abi_version") == 0 ) {
+ const char* version = argv[++i];
+ if ( version == NULL )
+ throw "-objc_abi_version missing version number";
+ if ( strcmp(version, "2") == 0 ) {
+ fObjCABIVersion1Override = false;
+ fObjCABIVersion2Override = true;
+ }
+ else if ( strcmp(version, "1") == 0 ) {
+ fObjCABIVersion1Override = true;
+ fObjCABIVersion2Override = false;
+ }
+ else
+ warning("ignoring unrecognized argument (%s) to -objc_abi_version", version);
+ }
+ else if ( strcmp(arg, "-warn_weak_exports") == 0 ) {
+ fWarnWeakExports = true;
+ }
+ else if ( strcmp(arg, "-objc_gc_compaction") == 0 ) {
+ fObjcGcCompaction = true;
+ }
+ else if ( strcmp(arg, "-objc_gc") == 0 ) {
+ fObjCGc = true;
+ if ( fObjCGcOnly ) {
+ warning("-objc_gc overriding -objc_gc_only");
+ fObjCGcOnly = false;
+ }
+ }
+ else if ( strcmp(arg, "-objc_gc_only") == 0 ) {
+ fObjCGcOnly = true;
+ if ( fObjCGc ) {
+ warning("-objc_gc_only overriding -objc_gc");
+ fObjCGc = false;
+ }
+ }
+ else if ( strcmp(arg, "-demangle") == 0 ) {
+ fDemangle = true;
+ }
+ else if ( strcmp(arg, "-version_load_command") == 0 ) {
+ fVersionLoadCommandForcedOn = true;
+ fVersionLoadCommandForcedOff = false;
+ }
+ else if ( strcmp(arg, "-no_version_load_command") == 0 ) {
+ fVersionLoadCommandForcedOff = true;
+ fVersionLoadCommandForcedOn = false;
+ }
+ else if ( strcmp(arg, "-function_starts") == 0 ) {
+ fFunctionStartsForcedOn = true;
+ fFunctionStartsForcedOff = false;
+ }
+ else if ( strcmp(arg, "-no_function_starts") == 0 ) {
+ fFunctionStartsForcedOff = true;
+ fFunctionStartsForcedOn = false;
+ }
+ else if ( strcmp(arg, "-no_data_in_code_info") == 0 ) {
+ fDataInCodeInfoLoadCommandForcedOff = true;
+ fDataInCodeInfoLoadCommandForcedOn = false;
+ }
+ else if ( strcmp(arg, "-data_in_code_info") == 0 ) {
+ fDataInCodeInfoLoadCommandForcedOn = true;
+ fDataInCodeInfoLoadCommandForcedOff = false;
+ }
+ else if ( strcmp(arg, "-object_path_lto") == 0 ) {
+ fTempLtoObjectPath = argv[++i];
+ if ( fTempLtoObjectPath == NULL )
+ throw "missing argument to -object_path_lto";
+ }
+ else if ( strcmp(arg, "-no_objc_category_merging") == 0 ) {
+ fObjcCategoryMerging = false;
+ }
+ else if ( strcmp(arg, "-force_symbols_weak_list") == 0 ) {
+ snapshotFileArgIndex = 1;
+ loadExportFile(argv[++i], "-force_symbols_weak_list", fForceWeakSymbols);
+ }
+ else if ( strcmp(arg, "-force_symbols_not_weak_list") == 0 ) {
+ snapshotFileArgIndex = 1;
+ loadExportFile(argv[++i], "-force_symbols_not_weak_list", fForceNotWeakSymbols);
+ }
+ else if ( strcmp(arg, "-force_symbol_weak") == 0 ) {
+ const char* symbol = argv[++i];
+ if ( symbol == NULL )
+ throw "-force_symbol_weak missing <symbol>";
+ fForceWeakSymbols.insert(symbol);
+ }
+ else if ( strcmp(arg, "-force_symbol_not_weak") == 0 ) {
+ const char* symbol = argv[++i];
+ if ( symbol == NULL )
+ throw "-force_symbol_not_weak missing <symbol>";
+ fForceNotWeakSymbols.insert(symbol);
+ }
+ else if ( strcmp(arg, "-reexported_symbols_list") == 0 ) {
+ snapshotFileArgIndex = 1;
+ if ( fExportMode == kExportSome )
+ throw "can't use -exported_symbols_list and -reexported_symbols_list";
+ loadExportFile(argv[++i], "-reexported_symbols_list", fReExportSymbols);
+ }
+ else if ( strcmp(arg, "-dyld_env") == 0 ) {
+ const char* envarg = argv[++i];
+ if ( envarg == NULL )
+ throw "-dyld_env missing ENV=VALUE";
+ if ( strchr(envarg, '=') == NULL )
+ throw "-dyld_env missing ENV=VALUE";
+ fDyldEnvironExtras.push_back(envarg);
+ }
+ else if ( strcmp(arg, "-page_align_data_atoms") == 0 ) {
+ fPageAlignDataAtoms = true;
+ }
+ else if (strcmp(arg, "-debug_snapshot") == 0) {
+ fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
+ fSnapshotRequested = true;
+ }
+ else if ( strcmp(arg, "-new_main") == 0 ) {
+ fEntryPointLoadCommandForceOn = true;
+ }
+ else if ( strcmp(arg, "-no_new_main") == 0 ) {
+ fEntryPointLoadCommandForceOff = true;
+ }
+ else if ( strcmp(arg, "-source_version") == 0 ) {
+ const char* vers = argv[++i];
+ if ( vers == NULL )
+ throw "-source_version missing <version>";
+ fSourceVersion = parseVersionNumber64(vers);
+ }
+ else if ( strcmp(arg, "-add_source_version") == 0 ) {
+ fSourceVersionLoadCommandForceOn = true;
+ }
+ else if ( strcmp(arg, "-no_source_version") == 0 ) {
+ fSourceVersionLoadCommandForceOff = true;
+ }
+ else if ( strcmp(arg, "-sdk_version") == 0 ) {
+ const char* vers = argv[++i];
+ if ( vers == NULL )
+ throw "-sdk_version missing <version>";
+ fSDKVersion = parseVersionNumber32(vers);
+ }
+ else if ( strcmp(arg, "-dependent_dr_info") == 0 ) {
+ fDependentDRInfoForcedOn = true;
+ }
+ else if ( strcmp(arg, "-no_dependent_dr_info") == 0 ) {
+ fDependentDRInfoForcedOff = true;
+ }
+ else if ( strcmp(arg, "-kexts_use_stubs") == 0 ) {
+ fKextsUseStubs = true;
+ }
+ else {
+ throwf("unknown option: %s", arg);
+ }
+
+ if (snapshotArgCount == -1)
+ snapshotArgCount = i-snapshotArgIndex+1;
+ if (snapshotArgCount > 0)
+ fLinkSnapshot.addSnapshotLinkArg(snapshotArgIndex, snapshotArgCount, snapshotFileArgIndex);
+ }
+ else {
+ FileInfo info = findFile(arg);
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+ if ( strcmp(&info.path[strlen(info.path)-2], ".a") == 0 )
+ addLibrary(info);
+ else
+ fInputFiles.push_back(info);
+ }
+ }
+
+ // if a -lazy option was used, implicitly link in lazydylib1.o
+ if ( fUsingLazyDylibLinking ) {
+ FileInfo info = findLibrary("lazydylib1.o");
+ info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)argc);
+ addLibrary(info);
+ }
+
+ if (fSnapshotRequested)
+ fLinkSnapshot.createSnapshot();
+}
+
+
+
+//
+// -syslibroot <path> is used for SDK support.
+// The rule is that all search paths (both explicit and default) are
+// checked to see if they exist in the SDK. If so, that path is
+// replaced with the sdk prefixed path. If not, that search path
+// is used as is. If multiple -syslibroot options are specified
+// their directory structures are logically overlayed and files
+// from sdks specified earlier on the command line used before later ones.
+
+void Options::buildSearchPaths(int argc, const char* argv[])
+{
+ bool addStandardLibraryDirectories = true;
+ std::vector<const char*> libraryPaths;
+ std::vector<const char*> frameworkPaths;
+ libraryPaths.reserve(10);
+ frameworkPaths.reserve(10);
+ // scan through argv looking for -L, -F, -Z, and -syslibroot options
+ for(int i=0; i < argc; ++i) {
+ if ( (argv[i][0] == '-') && (argv[i][1] == 'L') ) {
+ const char* libSearchDir = &argv[i][2];
+ // Allow either "-L{path}" or "-L {path}".
+ if (argv[i][2] == '\0') {
+ // -L {path}. Make sure there is an argument following this.
+ const char* path = argv[++i];
+ if ( path == NULL )
+ throw "-L missing argument";
+ libSearchDir = path;
+ }
+ if ( libSearchDir[0] == '\0' )
+ throw "-L must be immediately followed by a directory path (no space)";
+ struct stat statbuf;
+ if ( stat(libSearchDir, &statbuf) == 0 ) {
+ if ( statbuf.st_mode & S_IFDIR )
+ libraryPaths.push_back(libSearchDir);
+ else
+ warning("path '%s' following -L not a directory", libSearchDir);
+ }
+ else {
+ warning("directory not found for option '-L%s'", libSearchDir);
+ }
+ }
+ else if ( (argv[i][0] == '-') && (argv[i][1] == 'F') ) {
+ const char* frameworkSearchDir = &argv[i][2];
+ // Allow either "-F{path}" or "-F {path}".
+ if (argv[i][2] == '\0') {
+ // -F {path}. Make sure there is an argument following this.
+ const char* path = argv[++i];
+ if ( path == NULL )
+ throw "-F missing argument";
+ frameworkSearchDir = path;
+ }
+ if ( frameworkSearchDir[0] == '\0' )
+ throw "-F must be immediately followed by a directory path (no space)";
+ struct stat statbuf;
+ if ( stat(frameworkSearchDir, &statbuf) == 0 ) {
+ if ( statbuf.st_mode & S_IFDIR )
+ frameworkPaths.push_back(frameworkSearchDir);
+ else
+ warning("path '%s' following -F not a directory", frameworkSearchDir);
+ }
+ else {
+ warning("directory not found for option '-F%s'", frameworkSearchDir);
+ }
+ }
+ else if ( strcmp(argv[i], "-Z") == 0 )
+ addStandardLibraryDirectories = false;
+ else if ( strcmp(argv[i], "-v") == 0 ) {
+ fVerbose = true;
+ extern const char ldVersionString[];
+ fprintf(stderr, "%s", ldVersionString);
+ fprintf(stderr, "configured to support archs: %s\n", ALL_SUPPORTED_ARCHS);
+ // if only -v specified, exit cleanly
+ if ( argc == 2 ) {
+ const char* ltoVers = lto::version();
+ if ( ltoVers != NULL )
+ fprintf(stderr, "LTO support using: %s\n", ltoVers);
+ exit(0);
+ }
+ }
+ else if ( strcmp(argv[i], "-syslibroot") == 0 ) {
+ const char* path = argv[++i];
+ if ( path == NULL )
+ throw "-syslibroot missing argument";
+ fSDKPaths.push_back(path);
+ }
+ else if ( strcmp(argv[i], "-search_paths_first") == 0 ) {
+ fLibrarySearchMode = kSearchDylibAndArchiveInEachDir;
+ }
+ else if ( strcmp(argv[i], "-search_dylibs_first") == 0 ) {
+ fLibrarySearchMode = kSearchAllDirsForDylibsThenAllDirsForArchives;
+ }
+ else if ( strcmp(argv[i], "-w") == 0 ) {
+ sEmitWarnings = false;
+ }
+ else if ( strcmp(argv[i], "-fatal_warnings") == 0 ) {
+ sFatalWarnings = true;
+ }
+ }
+ int standardLibraryPathsStartIndex = libraryPaths.size();
+ int standardFrameworkPathsStartIndex = frameworkPaths.size();
+ if ( addStandardLibraryDirectories ) {
+ libraryPaths.push_back("/usr/lib");
+ libraryPaths.push_back("/usr/local/lib");
+
+ frameworkPaths.push_back("/Library/Frameworks/");
+ frameworkPaths.push_back("/System/Library/Frameworks/");
+ // <rdar://problem/5433882> remove /Network/Library/Frameworks from default search path
+ }
+
+ // <rdar://problem/5829579> Support for configure based hacks
+ // if last -syslibroot is /, then ignore all syslibroots
+ if ( fSDKPaths.size() > 0 ) {
+ if ( strcmp(fSDKPaths.back(), "/") == 0 ) {
+ fSDKPaths.clear();
+ }
+ }
+
+ // now merge sdk and library paths to make real search paths
+ fLibrarySearchPaths.reserve(libraryPaths.size()*(fSDKPaths.size()+1));
+ int libIndex = 0;
+ for (std::vector<const char*>::iterator it = libraryPaths.begin(); it != libraryPaths.end(); ++it, ++libIndex) {
+ const char* libDir = *it;
+ bool sdkOverride = false;
+ if ( libDir[0] == '/' ) {
+ char betterLibDir[PATH_MAX];
+ if ( strstr(libDir, "/..") != NULL ) {
+ if ( realpath(libDir, betterLibDir) != NULL )
+ libDir = strdup(betterLibDir);
+ }
+ const int libDirLen = strlen(libDir);
+ for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) {
+ const char* sdkDir = *sdkit;
+ const int sdkDirLen = strlen(sdkDir);
+ char newPath[libDirLen + sdkDirLen+4];
+ strcpy(newPath, sdkDir);
+ if ( newPath[sdkDirLen-1] == '/' )
+ newPath[sdkDirLen-1] = '\0';
+ strcat(newPath, libDir);
+ struct stat statBuffer;
+ if ( stat(newPath, &statBuffer) == 0 ) {
+ fLibrarySearchPaths.push_back(strdup(newPath));
+ sdkOverride = true;
+ }
+ }
+ }
+ if ( !sdkOverride ) {
+ if ( (libIndex >= standardLibraryPathsStartIndex) && (fSDKPaths.size() == 1) ) {
+ // <rdar://problem/6438270> -syslibroot should skip standard search paths not in the SDK
+ // if one SDK is specified and a standard library path is not in the SDK, don't use it
+ }
+ else {
+ fLibrarySearchPaths.push_back(libDir);
+ }
+ }
+ }
+
+ // now merge sdk and framework paths to make real search paths
+ fFrameworkSearchPaths.reserve(frameworkPaths.size()*(fSDKPaths.size()+1));
+ int frameIndex = 0;
+ for (std::vector<const char*>::iterator it = frameworkPaths.begin(); it != frameworkPaths.end(); ++it, ++frameIndex) {
+ const char* frameworkDir = *it;
+ bool sdkOverride = false;
+ if ( frameworkDir[0] == '/' ) {
+ char betterFrameworkDir[PATH_MAX];
+ if ( strstr(frameworkDir, "/..") != NULL ) {
+ if ( realpath(frameworkDir, betterFrameworkDir) != NULL )
+ frameworkDir = strdup(betterFrameworkDir);
+ }
+ const int frameworkDirLen = strlen(frameworkDir);
+ for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) {
+ const char* sdkDir = *sdkit;
+ const int sdkDirLen = strlen(sdkDir);
+ char newPath[frameworkDirLen + sdkDirLen+4];
+ strcpy(newPath, sdkDir);
+ if ( newPath[sdkDirLen-1] == '/' )
+ newPath[sdkDirLen-1] = '\0';
+ strcat(newPath, frameworkDir);
+ struct stat statBuffer;
+ if ( stat(newPath, &statBuffer) == 0 ) {
+ fFrameworkSearchPaths.push_back(strdup(newPath));
+ sdkOverride = true;
+ }
+ }
+ }
+ if ( !sdkOverride ) {
+ if ( (frameIndex >= standardFrameworkPathsStartIndex) && (fSDKPaths.size() == 1) ) {
+ // <rdar://problem/6438270> -syslibroot should skip standard search paths not in the SDK
+ // if one SDK is specified and a standard library path is not in the SDK, don't use it
+ }
+ else {
+ fFrameworkSearchPaths.push_back(frameworkDir);
+ }
+ }
+ }
+
+ if ( fVerbose ) {
+ fprintf(stderr,"Library search paths:\n");
+ for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+ it != fLibrarySearchPaths.end();
+ it++)
+ fprintf(stderr,"\t%s\n", *it);
+ fprintf(stderr,"Framework search paths:\n");
+ for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin();
+ it != fFrameworkSearchPaths.end();
+ it++)
+ fprintf(stderr,"\t%s\n", *it);
+ }
+}
+
+// this is run before the command line is parsed
+void Options::parsePreCommandLineEnvironmentSettings()
+{
+ if ((getenv("LD_TRACE_ARCHIVES") != NULL)
+ || (getenv("RC_TRACE_ARCHIVES") != NULL))
+ fTraceArchives = true;
+
+ if ((getenv("LD_TRACE_DYLIBS") != NULL)
+ || (getenv("RC_TRACE_DYLIBS") != NULL)) {
+ fTraceDylibs = true;
+ fTraceIndirectDylibs = true;
+ }
+
+ if (getenv("RC_TRACE_DYLIB_SEARCHING") != NULL) {
+ fTraceDylibSearching = true;
+ }
+
+ if (getenv("LD_PRINT_OPTIONS") != NULL)
+ fPrintOptions = true;
+
+ if (fTraceDylibs || fTraceArchives)
+ fTraceOutputFile = getenv("LD_TRACE_FILE");
+
+ if (getenv("LD_PRINT_ORDER_FILE_STATISTICS") != NULL)
+ fPrintOrderFileStatistics = true;
+
+ if (getenv("LD_SPLITSEGS_NEW_LIBRARIES") != NULL)
+ fSplitSegs = true;
+
+ if (getenv("LD_NO_ENCRYPT") != NULL)
+ fEncryptable = false;
+
+ if (getenv("LD_ALLOW_CPU_SUBTYPE_MISMATCHES") != NULL)
+ fAllowCpuSubtypeMismatches = true;
+
+ sWarningsSideFilePath = getenv("LD_WARN_FILE");
+
+ const char* customDyldPath = getenv("LD_DYLD_PATH");
+ if ( customDyldPath != NULL )
+ fDyldInstallPath = customDyldPath;
+
+ const char* debugArchivePath = getenv("LD_DEBUG_SNAPSHOT");
+ if (debugArchivePath != NULL) {
+ fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
+ if (strlen(debugArchivePath) > 0)
+ fLinkSnapshot.setSnapshotPath(debugArchivePath);
+ fSnapshotRequested = true;
+ }
+
+ const char* pipeFdString = getenv("LD_PIPELINE_FIFO");
+ if (pipeFdString != NULL) {
+ fPipelineFifo = pipeFdString;
+ }
+}
+
+
+// this is run after the command line is parsed
+void Options::parsePostCommandLineEnvironmentSettings()
+{
+ // when building a dynamic main executable, default any use of @executable_path to output path
+ if ( fExecutablePath == NULL && (fOutputKind == kDynamicExecutable) ) {
+ fExecutablePath = fOutputFile;
+ }
+
+ // allow build system to set default seg_addr_table
+ if ( fSegAddrTablePath == NULL )
+ fSegAddrTablePath = getenv("LD_SEG_ADDR_TABLE");
+
+ // allow build system to turn on prebinding
+ if ( !fPrebind ) {
+ fPrebind = ( getenv("LD_PREBIND") != NULL );
+ }
+
+ // allow build system to force on dead-code-stripping
+ if ( !fDeadStrip ) {
+ if ( getenv("LD_DEAD_STRIP") != NULL ) {
+ switch (fOutputKind) {
+ case Options::kDynamicLibrary:
+ case Options::kDynamicExecutable:
+ case Options::kDynamicBundle:
+ fDeadStrip = true;
+ break;
+ case Options::kPreload:
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kStaticExecutable:
+ case Options::kKextBundle:
+ break;
+ }
+ }
+ }
+
+ // allow build system to force on -warn_commons
+ if ( getenv("LD_WARN_COMMONS") != NULL )
+ fWarnCommons = true;
+
+ // allow B&I to set default -source_version
+ if ( fSourceVersion == 0 ) {
+ const char* vers = getenv("RC_ProjectSourceVersion");
+ if ( vers != NULL )
+ fSourceVersion = parseVersionNumber64(vers);
+ }
+
+}
+
+void Options::reconfigureDefaults()
+{
+ // sync reader options
+ switch ( fOutputKind ) {
+ case Options::kObjectFile:
+ fForFinalLinkedImage = false;
+ break;
+ case Options::kDyld:
+ fForDyld = true;
+ fForFinalLinkedImage = true;
+ fNoEHLabels = true;
+ break;
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kKextBundle:
+ fForFinalLinkedImage = true;
+ fNoEHLabels = true;
+ break;
+ case Options::kDynamicExecutable:
+ case Options::kStaticExecutable:
+ case Options::kPreload:
+ fLinkingMainExecutable = true;
+ fForFinalLinkedImage = true;
+ fNoEHLabels = true;
+ break;
+ }
+
+ // set default min OS version
+ if ( (fMacVersionMin == ld::macVersionUnset)
+ && (fIOSVersionMin == ld::iOSVersionUnset) ) {
+ // if neither -macosx_version_min nor -iphoneos_version_min used, try environment variables
+ const char* macVers = getenv("MACOSX_DEPLOYMENT_TARGET");
+ const char* iPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET");
+ const char* iOSVers = getenv("IOS_DEPLOYMENT_TARGET");
+ const char* iOSSimulatorVers = getenv("IOS_SIMULATOR_DEPLOYMENT_TARGET");
+ if ( macVers != NULL )
+ setMacOSXVersionMin(macVers);
+ else if ( iPhoneVers != NULL )
+ setIOSVersionMin(iPhoneVers);
+ else if ( iOSVers != NULL )
+ setIOSVersionMin(iOSVers);
+ else if ( iOSSimulatorVers != NULL )
+ setIOSVersionMin(iOSSimulatorVers);
+ else {
+ // if still nothing, set default based on architecture
+ switch ( fArchitecture ) {
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64:
+ if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) {
+ #ifdef DEFAULT_MACOSX_MIN_VERSION
+ warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
+ setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
+ #else
+ warning("-macosx_version_min not specified, assuming 10.6");
+ fMacVersionMin = ld::mac10_6;
+ #endif
+ }
+ break;
+ case CPU_TYPE_ARM:
+ if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) {
+ #if defined(DEFAULT_IPHONEOS_MIN_VERSION)
+ warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
+ setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
+ #elif defined(DEFAULT_MACOSX_MIN_VERSION)
+ warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
+ setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
+ #else
+ warning("-macosx_version_min not specified, assuming 10.6");
+ fMacVersionMin = ld::mac10_6;
+ #endif
+ }
+ break;
+ default:
+ // architecture will be infered ;ater by examining .o files
+ break;
+ }
+ }
+ }
+
+
+ // adjust min based on architecture
+ switch ( fArchitecture ) {
+ case CPU_TYPE_I386:
+ if ( (fMacVersionMin < ld::mac10_4) && (fIOSVersionMin == ld::iOSVersionUnset) ) {
+ //warning("-macosx_version_min should be 10.4 or later for i386");
+ fMacVersionMin = ld::mac10_4;
+ }
+ break;
+ case CPU_TYPE_X86_64:
+ if ( (fMacVersionMin < ld::mac10_4) && (fIOSVersionMin == ld::iOSVersionUnset) ) {
+ //warning("-macosx_version_min should be 10.4 or later for x86_64");
+ fMacVersionMin = ld::mac10_4;
+ }
+ break;
+ }
+
+ // adjust kext type based on architecture
+ if ( fOutputKind == kKextBundle ) {
+ switch ( fArchitecture ) {
+ case CPU_TYPE_X86_64:
+ // x86_64 uses new MH_KEXT_BUNDLE type
+ fMakeCompressedDyldInfo = false;
+ fMakeCompressedDyldInfoForceOff = true;
+ fAllowTextRelocs = true;
+ fUndefinedTreatment = kUndefinedDynamicLookup;
+ break;
+ case CPU_TYPE_ARM:
+ if ( fIOSVersionMin >= ld::iOS_5_0 ) {
+ // iOS 5.0 and later use new MH_KEXT_BUNDLE type
+ fMakeCompressedDyldInfo = false;
+ fMakeCompressedDyldInfoForceOff = true;
+ // kexts are PIC in iOS 6.0 and later
+ fAllowTextRelocs = (fIOSVersionMin < ld::iOS_6_0);
+ fKextsUseStubs = !fAllowTextRelocs;
+ fUndefinedTreatment = kUndefinedDynamicLookup;
+ break;
+ }
+ // else use object file
+ case CPU_TYPE_I386:
+ // use .o files
+ fOutputKind = kObjectFile;
+ break;
+ }
+ }
+
+ // disable implicit dylibs when targeting 10.3
+ // <rdar://problem/5451987> add option to disable implicit load commands for indirectly used public dylibs
+ if ( !minOS(ld::mac10_4, ld::iOS_2_0) )
+ fImplicitlyLinkPublicDylibs = false;
+
+
+ // allow build system to force linker to ignore -prebind
+ if ( getenv("LD_FORCE_NO_PREBIND") != NULL )
+ fPrebind = false;
+
+ // allow build system to force linker to ignore -seg_addr_table
+ if ( getenv("LD_FORCE_NO_SEG_ADDR_TABLE") != NULL )
+ fSegAddrTablePath = NULL;
+
+ // check for base address specified externally
+ if ( (fSegAddrTablePath != NULL) && (fOutputKind == Options::kDynamicLibrary) ) {
+ parseSegAddrTable(fSegAddrTablePath, this->installPath());
+ // HACK to support seg_addr_table entries that are physical paths instead of install paths
+ if ( fBaseAddress == 0 ) {
+ if ( strcmp(this->installPath(), "/usr/lib/libstdc++.6.dylib") == 0 ) {
+ parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libstdc++.6.0.4.dylib");
+ if ( fBaseAddress == 0 )
+ parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libstdc++.6.0.9.dylib");
+ }
+
+ else if ( strcmp(this->installPath(), "/usr/lib/libz.1.dylib") == 0 )
+ parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libz.1.2.3.dylib");
+
+ else if ( strcmp(this->installPath(), "/usr/lib/libutil.dylib") == 0 )
+ parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libutil1.0.dylib");
+ }
+ }
+
+ // split segs only allowed for dylibs
+ if ( fSplitSegs ) {
+ // split seg only supported for i386, and arm.
+ switch ( fArchitecture ) {
+ case CPU_TYPE_I386:
+ if ( fOutputKind != Options::kDynamicLibrary )
+ fSplitSegs = false;
+ // make sure read and write segments are proper distance apart
+ if ( fSplitSegs && (fBaseWritableAddress-fBaseAddress != 0x10000000) )
+ fBaseWritableAddress = fBaseAddress + 0x10000000;
+ break;
+ case CPU_TYPE_ARM:
+ if ( fOutputKind != Options::kDynamicLibrary ) {
+ fSplitSegs = false;
+ }
+ else {
+ // make sure read and write segments are proper distance apart
+ if ( fSplitSegs && (fBaseWritableAddress-fBaseAddress != 0x08000000) )
+ fBaseWritableAddress = fBaseAddress + 0x08000000;
+ }
+ break;
+ default:
+ fSplitSegs = false;
+ fBaseAddress = 0;
+ fBaseWritableAddress = 0;
+ }
+ }
+
+ // set too-large size
+ switch ( fArchitecture ) {
+ case CPU_TYPE_I386:
+ fMaxAddress = 0xFFFFFFFF;
+ break;
+ case CPU_TYPE_X86_64:
+ break;
+ case CPU_TYPE_ARM:
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ // user land code is limited to low 1GB
+ fMaxAddress = 0x2FFFFFFF;
+ break;
+ case Options::kStaticExecutable:
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kPreload:
+ case Options::kKextBundle:
+ fMaxAddress = 0xFFFFFFFF;
+ break;
+ }
+ // range check -seg1addr for ARM
+ if ( fBaseAddress > fMaxAddress ) {
+ warning("ignoring -seg1addr 0x%08llX. Address out of range.", fBaseAddress);
+ fBaseAddress = 0;
+ }
+ break;
+ }
+
+ // <rdar://problem/6138961> -r implies no prebinding for all architectures
+ if ( fOutputKind == Options::kObjectFile )
+ fPrebind = false;
+
+ // disable prebinding depending on arch and min OS version
+ if ( fPrebind ) {
+ switch ( fArchitecture ) {
+ case CPU_TYPE_I386:
+ if ( fMacVersionMin == ld::mac10_4 ) {
+ // in 10.4 only split seg dylibs are prebound
+ if ( (fOutputKind != Options::kDynamicLibrary) || ! fSplitSegs )
+ fPrebind = false;
+ }
+ else if ( fMacVersionMin >= ld::mac10_5 ) {
+ // in 10.5 nothing is prebound
+ fPrebind = false;
+ }
+ else if ( fIOSVersionMin != ld::iOSVersionUnset ) {
+ // nothing in simulator is prebound
+ fPrebind = false;
+ }
+ else {
+ // in 10.3 and earlier only dylibs and main executables could be prebound
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ // only main executables and dylibs can be prebound
+ break;
+ case Options::kStaticExecutable:
+ case Options::kDynamicBundle:
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kPreload:
+ case Options::kKextBundle:
+ // disable prebinding for everything else
+ fPrebind = false;
+ break;
+ }
+ }
+ break;
+ case CPU_TYPE_X86_64:
+ fPrebind = false;
+ break;
+ case CPU_TYPE_ARM:
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ // only main executables and dylibs can be prebound
+ break;
+ case Options::kStaticExecutable:
+ case Options::kDynamicBundle:
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kPreload:
+ case Options::kKextBundle:
+ // disable prebinding for everything else
+ fPrebind = false;
+ break;
+ }
+ break;
+ }
+ }
+
+ // only prebound images can be split-seg
+ if ( fSplitSegs && !fPrebind )
+ fSplitSegs = false;
+
+ // determine if info for shared region should be added
+ if ( fOutputKind == Options::kDynamicLibrary ) {
+ if ( minOS(ld::mac10_5, ld::iOS_3_1) )
+ if ( !fPrebind )
+ if ( (strncmp(this->installPath(), "/usr/lib/", 9) == 0)
+ || (strncmp(this->installPath(), "/System/Library/", 16) == 0) )
+ fSharedRegionEligible = true;
+ }
+ else if ( fOutputKind == Options::kDyld ) {
+ // <rdar://problem/10111122> Enable dyld to be put into the dyld shared cache
+ fSharedRegionEligible = true;
+ }
+
+ // figure out if module table is needed for compatibility with old ld/dyld
+ if ( fOutputKind == Options::kDynamicLibrary ) {
+ switch ( fArchitecture ) {
+ case CPU_TYPE_I386:
+ if ( fIOSVersionMin != ld::iOSVersionUnset ) // simulator never needs modules
+ break;
+ case CPU_TYPE_ARM:
+ if ( fPrebind )
+ fNeedsModuleTable = true; // redo_prebinding requires a module table
+ break;
+ }
+ }
+
+ // <rdar://problem/5366363> -r -x implies -S
+ if ( (fOutputKind == Options::kObjectFile) && (fLocalSymbolHandling == kLocalSymbolsNone) )
+ fDebugInfoStripping = Options::kDebugInfoNone;
+
+ // choose how to process unwind info
+ switch ( fArchitecture ) {
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64:
+ switch ( fOutputKind ) {
+ case Options::kObjectFile:
+ case Options::kStaticExecutable:
+ case Options::kPreload:
+ case Options::kKextBundle:
+ fAddCompactUnwindEncoding = false;
+ break;
+ case Options::kDyld:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kDynamicExecutable:
+ //if ( fAddCompactUnwindEncoding && (fVersionMin >= ld::mac10_6) )
+ // fRemoveDwarfUnwindIfCompactExists = true;
+ break;
+ }
+ break;
+ case CPU_TYPE_ARM:
+ fAddCompactUnwindEncoding = false;
+ fRemoveDwarfUnwindIfCompactExists = false;
+ break;
+ case 0:
+ // if -arch is missing, assume we don't want compact unwind info
+ fAddCompactUnwindEncoding = false;
+ break;
+ }
+
+ // only ARM main executables can be encrypted
+ if ( fOutputKind != Options::kDynamicExecutable )
+ fEncryptable = false;
+ if ( fArchitecture != CPU_TYPE_ARM )
+ fEncryptable = false;
+
+ // don't move inits in dyld because dyld wants certain
+ // entries point at stable locations at the start of __text
+ if ( fOutputKind == Options::kDyld )
+ fAutoOrderInitializers = false;
+
+
+ // disable __data ordering for some output kinds
+ switch ( fOutputKind ) {
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kStaticExecutable:
+ case Options::kPreload:
+ case Options::kKextBundle:
+ fOrderData = false;
+ break;
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ break;
+ }
+
+ // only use compressed LINKEDIT for final linked images
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ break;
+ case Options::kPreload:
+ case Options::kStaticExecutable:
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kKextBundle:
+ fMakeCompressedDyldInfoForceOff = true;
+ break;
+ }
+ if ( fMakeCompressedDyldInfoForceOff )
+ fMakeCompressedDyldInfo = false;
+
+
+ // only use compressed LINKEDIT for:
+ // Mac OS X 10.6 or later
+ // iOS 3.1 or later
+ if ( fMakeCompressedDyldInfo ) {
+ if ( !minOS(ld::mac10_6, ld::iOS_3_1) )
+ fMakeCompressedDyldInfo = false;
+ }
+
+
+ // only ARM enforces that cpu-sub-types must match
+ if ( fArchitecture != CPU_TYPE_ARM )
+ fAllowCpuSubtypeMismatches = true;
+
+ // only final linked images can not optimize zero fill sections
+ if ( fOutputKind == Options::kObjectFile )
+ fOptimizeZeroFill = true;
+
+ // all undefines in -r mode
+// if ( fOutputKind == Options::kObjectFile )
+// fUndefinedTreatment = kUndefinedSuppress;
+
+ // only dynamic final linked images should warn about use of commmons
+ if ( fWarnCommons ) {
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ break;
+ case Options::kPreload:
+ case Options::kStaticExecutable:
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kKextBundle:
+ fWarnCommons = false;
+ break;
+ }
+ }
+
+ // Mac OS X 10.5 and iPhoneOS 2.0 support LC_REEXPORT_DYLIB
+ if ( minOS(ld::mac10_5, ld::iOS_2_0) )
+ fUseSimplifiedDylibReExports = true;
+
+ // Mac OS X 10.7 and iOS 4.2 support LC_LOAD_UPWARD_DYLIB
+ if ( minOS(ld::mac10_7, ld::iOS_4_2) && (fOutputKind == kDynamicLibrary) )
+ fCanUseUpwardDylib = true;
+
+ // MacOSX 10.7 defaults to PIE
+ if ( ((fArchitecture == CPU_TYPE_X86_64) || (fArchitecture == CPU_TYPE_I386))
+ && (fOutputKind == kDynamicExecutable)
+ && (fMacVersionMin >= ld::mac10_7) ) {
+ fPositionIndependentExecutable = true;
+ }
+
+ // armv7 for iOS4.3 defaults to PIE
+ if ( (fArchitecture == CPU_TYPE_ARM)
+ && fArchSupportsThumb2
+ && (fOutputKind == kDynamicExecutable)
+ && (fIOSVersionMin >= ld::iOS_4_3) ) {
+ fPositionIndependentExecutable = true;
+ }
+
+ // -no_pie anywhere on command line disable PIE
+ if ( fDisablePositionIndependentExecutable )
+ fPositionIndependentExecutable = false;
+
+ // set fOutputSlidable
+ switch ( fOutputKind ) {
+ case Options::kObjectFile:
+ fOutputSlidable = false;
+ break;
+ case Options::kStaticExecutable:
+ case Options::kDynamicExecutable:
+ fOutputSlidable = fPositionIndependentExecutable;
+ break;
+ case Options::kPreload:
+ fOutputSlidable = fPIEOnCommandLine;
+ break;
+ case Options::kDyld:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kKextBundle:
+ fOutputSlidable = true;
+ break;
+ }
+
+ // let linker know if thread local variables are supported
+ if ( fMacVersionMin >= ld::mac10_7 ) {
+ fTLVSupport = true;
+ }
+
+ // default to adding version load command for dynamic code, static code must opt-in
+ switch ( fOutputKind ) {
+ case Options::kObjectFile:
+ fVersionLoadCommand = false;
+ break;
+ case Options::kStaticExecutable:
+ case Options::kPreload:
+ case Options::kKextBundle:
+ if ( fVersionLoadCommandForcedOn )
+ fVersionLoadCommand = true;
+ break;
+ case Options::kDynamicExecutable:
+ case Options::kDyld:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ if ( !fVersionLoadCommandForcedOff )
+ fVersionLoadCommand = true;
+ // <rdar://problem/9945513> for now, don't create version load commands for iOS simulator builds
+ if ( fVersionLoadCommand && (fArchitecture == CPU_TYPE_I386) ) {
+ for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) {
+ if ( strstr(*sdkit, "/iPhoneSimulator.platform/") != NULL )
+ fVersionLoadCommand = false;
+ }
+ }
+ break;
+ }
+
+ // default to adding functions start for dynamic code, static code must opt-in
+ switch ( fOutputKind ) {
+ case Options::kPreload:
+ case Options::kStaticExecutable:
+ case Options::kKextBundle:
+ if ( fDataInCodeInfoLoadCommandForcedOn )
+ fDataInCodeInfoLoadCommand = true;
+ if ( fFunctionStartsForcedOn )
+ fFunctionStartsLoadCommand = true;
+ break;
+ case Options::kObjectFile:
+ case Options::kDynamicExecutable:
+ case Options::kDyld:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ if ( !fDataInCodeInfoLoadCommandForcedOff )
+ fDataInCodeInfoLoadCommand = true;
+ if ( !fFunctionStartsForcedOff )
+ fFunctionStartsLoadCommand = true;
+ break;
+ }
+
+ // support re-export of individual symbols in MacOSX 10.7 and iOS 4.2
+ if ( (fOutputKind == kDynamicLibrary) && minOS(ld::mac10_7, ld::iOS_4_2) )
+ fCanReExportSymbols = true;
+
+ // ObjC optimization is only in dynamic final linked images
+ switch ( fOutputKind ) {
+ case Options::kObjectFile:
+ case Options::kStaticExecutable:
+ case Options::kPreload:
+ case Options::kKextBundle:
+ case Options::kDyld:
+ fObjcCategoryMerging = false;
+ break;
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ break;
+ }
+
+ // i386 main executables linked on Mac OS X 10.7 default to NX heap
+ // regardless of target unless overriden with -allow_heap_execute anywhere
+ // on the command line
+ if ( (fArchitecture == CPU_TYPE_I386) && (fOutputKind == kDynamicExecutable) && !fDisableNonExecutableHeap)
+ fNonExecutableHeap = true;
+
+ // Use LC_MAIN instead of LC_UNIXTHREAD for newer OSs
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ if ( fEntryPointLoadCommandForceOn ) {
+ fEntryPointLoadCommand = true;
+ fEntryName = "_main";
+ }
+ else if ( fEntryPointLoadCommandForceOff ) {
+ fNeedsThreadLoadCommand = true;
+ }
+ else {
+ if ( (fIOSVersionMin != ld::iOSVersionUnset) && (fArchitecture == CPU_TYPE_I386) ) {
+ // don't use LC_MAIN for simulator until min host OS is 10.8 for simulator
+ fNeedsThreadLoadCommand = true;
+ fEntryPointLoadCommand = false;
+ }
+ else if ( minOS(ld::mac10_8, ld::iOS_6_0) ) {
+ fEntryPointLoadCommand = true;
+ fEntryName = "_main";
+ }
+ else
+ fNeedsThreadLoadCommand = true;
+ }
+ break;
+ case Options::kObjectFile:
+ case Options::kKextBundle:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ break;
+
+ case Options::kStaticExecutable:
+ case Options::kPreload:
+ case Options::kDyld:
+ fNeedsThreadLoadCommand = true;
+ break;
+ }
+
+ // add LC_SOURCE_VERSION
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kKextBundle:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kDyld:
+ case Options::kStaticExecutable:
+ if ( fSourceVersionLoadCommandForceOn ) {
+ fSourceVersionLoadCommand = true;
+ }
+ else if ( fSourceVersionLoadCommandForceOff ) {
+ fSourceVersionLoadCommand = false;
+ }
+ else {
+ if ( minOS(ld::mac10_8, ld::iOS_6_0) ) {
+ fSourceVersionLoadCommand = true;
+ }
+ else
+ fSourceVersionLoadCommand = false;
+ }
+ break;
+ case Options::kObjectFile:
+ case Options::kPreload:
+ fSourceVersionLoadCommand = false;
+ break;
+ }
+
+
+ // add LC_DYLIB_CODE_SIGN_DRS
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ if ( fDependentDRInfoForcedOn ) {
+ fDependentDRInfo = true;
+ }
+ else if ( fDependentDRInfoForcedOff ) {
+ fDependentDRInfo = false;
+ }
+ else {
+ if ( minOS(ld::mac10_8, ld::iOS_6_0) )
+ fDependentDRInfo = true;
+ else
+ fDependentDRInfo = false;
+ }
+ break;
+ case Options::kKextBundle:
+ case Options::kDyld:
+ case Options::kStaticExecutable:
+ case Options::kObjectFile:
+ case Options::kPreload:
+ fDependentDRInfo = false;
+ break;
+ }
+
+ // if -sdk_version not on command line, infer from -syslibroot
+ if ( (fSDKVersion == 0) && (fSDKPaths.size() > 0) ) {
+ const char* sdkPath = fSDKPaths.front();
+ const char* end = &sdkPath[strlen(sdkPath)-1];
+ while ( !isdigit(*end) && (end > sdkPath) )
+ --end;
+ const char* start = end-1;
+ while ( (isdigit(*start) || (*start == '.')) && (start > sdkPath))
+ --start;
+ char sdkVersionStr[32];
+ int len = end-start+1;
+ if ( len > 2 ) {
+ strlcpy(sdkVersionStr, start+1, len);
+ fSDKVersion = parseVersionNumber32(sdkVersionStr);
+ }
+ }
+
+ // if -sdk_version and -syslibroot not used, but targeting MacOSX, use current OS version
+ if ( (fSDKVersion == 0) && (fMacVersionMin != ld::macVersionUnset) ) {
+ // special case if RC_ProjectName and MACOSX_DEPLOYMENT_TARGET are both set that sdkversion=minos
+ if ( getenv("RC_ProjectName") && getenv("MACOSX_DEPLOYMENT_TARGET") ) {
+ fSDKVersion = fMacVersionMin;
+ }
+ else {
+ int mib[2] = { CTL_KERN, KERN_OSRELEASE };
+ char kernVersStr[100];
+ size_t strlen = sizeof(kernVersStr);
+ if ( sysctl(mib, 2, kernVersStr, &strlen, NULL, 0) != -1 ) {
+ uint32_t kernVers = parseVersionNumber32(kernVersStr);
+ int minor = (kernVers >> 16) - 4; // kernel major version is 4 ahead of x in 10.x
+ fSDKVersion = 0x000A0000 + (minor << 8);
+ }
+ }
+ }
+
+}
+
+void Options::checkIllegalOptionCombinations()
+{
+ // check -undefined setting
+ switch ( fUndefinedTreatment ) {
+ case kUndefinedError:
+ case kUndefinedDynamicLookup:
+ // always legal
+ break;
+ case kUndefinedWarning:
+ case kUndefinedSuppress:
+ // requires flat namespace
+ if ( fNameSpace == kTwoLevelNameSpace )
+ throw "can't use -undefined warning or suppress with -twolevel_namespace";
+ break;
+ }
+
+ // unify -sub_umbrella with dylibs
+ for (std::vector<const char*>::iterator it = fSubUmbellas.begin(); it != fSubUmbellas.end(); it++) {
+ const char* subUmbrella = *it;
+ bool found = false;
+ for (std::vector<Options::FileInfo>::iterator fit = fInputFiles.begin(); fit != fInputFiles.end(); fit++) {
+ Options::FileInfo& info = *fit;
+ const char* lastSlash = strrchr(info.path, '/');
+ if ( lastSlash == NULL )
+ lastSlash = info.path - 1;
+ if ( strcmp(&lastSlash[1], subUmbrella) == 0 ) {
+ info.options.fReExport = true;
+ found = true;
+ fLinkSnapshot.recordSubUmbrella(info.path);
+ break;
+ }
+ }
+ if ( ! found )
+ warning("-sub_umbrella %s does not match a supplied dylib", subUmbrella);
+ }
+
+ // unify -sub_library with dylibs
+ for (std::vector<const char*>::iterator it = fSubLibraries.begin(); it != fSubLibraries.end(); it++) {
+ const char* subLibrary = *it;
+ bool found = false;
+ for (std::vector<Options::FileInfo>::iterator fit = fInputFiles.begin(); fit != fInputFiles.end(); fit++) {
+ Options::FileInfo& info = *fit;
+ const char* lastSlash = strrchr(info.path, '/');
+ if ( lastSlash == NULL )
+ lastSlash = info.path - 1;
+ const char* dot = strchr(&lastSlash[1], '.');
+ if ( dot == NULL )
+ dot = &lastSlash[strlen(lastSlash)];
+ if ( strncmp(&lastSlash[1], subLibrary, dot-lastSlash-1) == 0 ) {
+ info.options.fReExport = true;
+ found = true;
+ fLinkSnapshot.recordSubLibrary(info.path);
+ break;
+ }
+ }
+ if ( ! found )
+ warning("-sub_library %s does not match a supplied dylib", subLibrary);
+ }
+
+ // sync reader options
+ if ( fNameSpace != kTwoLevelNameSpace )
+ fFlatNamespace = true;
+
+ // check -stack_addr
+ if ( fStackAddr != 0 ) {
+ switch (fArchitecture) {
+ case CPU_TYPE_I386:
+ case CPU_TYPE_ARM:
+ if ( fStackAddr > 0xFFFFFFFF )
+ throw "-stack_addr must be < 4G for 32-bit processes";
+ break;
+ case CPU_TYPE_X86_64:
+ break;
+ }
+ if ( (fStackAddr & -4096) != fStackAddr )
+ throw "-stack_addr must be multiples of 4K";
+ if ( fStackSize == 0 )
+ throw "-stack_addr must be used with -stack_size";
+ }
+
+ // check -stack_size
+ if ( fStackSize != 0 ) {
+ switch (fArchitecture) {
+ case CPU_TYPE_I386:
+ if ( fStackSize > 0xFFFFFFFF )
+ throw "-stack_size must be < 4G for 32-bit processes";
+ if ( fStackAddr == 0 ) {
+ fStackAddr = 0xC0000000;
+ }
+ if ( (fStackAddr > 0xB0000000) && ((fStackAddr-fStackSize) < 0xB0000000) )
+ warning("custom stack placement overlaps and will disable shared region");
+ break;
+ case CPU_TYPE_ARM:
+ if ( fStackSize > 0x2F000000 )
+ throw "-stack_size must be < 752MB";
+ if ( fStackAddr == 0 )
+ fStackAddr = 0x2F000000;
+ if ( fStackAddr > 0x30000000)
+ throw "-stack_addr must be < 0x30000000 for arm";
+ case CPU_TYPE_X86_64:
+ if ( fStackAddr == 0 ) {
+ fStackAddr = 0x00007FFF5C000000LL;
+ }
+ break;
+ }
+ if ( (fStackSize & -4096) != fStackSize )
+ throw "-stack_size must be multiples of 4K";
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kStaticExecutable:
+ // custom stack size only legal when building main executable
+ break;
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kPreload:
+ case Options::kKextBundle:
+ throw "-stack_size option can only be used when linking a main executable";
+ }
+ if ( fStackSize > fStackAddr )
+ throwf("-stack_size (0x%08llX) must be smaller than -stack_addr (0x%08llX)", fStackSize, fStackAddr);
+ }
+
+ // check that -allow_stack_execute is only used with main executables
+ if ( fExecutableStack ) {
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kStaticExecutable:
+ // -allow_stack_execute size only legal when building main executable
+ break;
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kPreload:
+ case Options::kKextBundle:
+ throw "-allow_stack_execute option can only be used when linking a main executable";
+ }
+ }
+
+ // check that -allow_heap_execute is only used with i386 main executables
+ if ( fDisableNonExecutableHeap ) {
+ if ( fArchitecture != CPU_TYPE_I386 )
+ throw "-allow_heap_execute option can only be used when linking for i386";
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ // -allow_heap_execute only legal when building main executable
+ break;
+ case Options::kStaticExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kPreload:
+ case Options::kKextBundle:
+ throw "-allow_heap_execute option can only be used when linking a main executable";
+ }
+ }
+
+ // check -client_name is only used when making a bundle or main executable
+ if ( fClientName != NULL ) {
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicBundle:
+ break;
+ case Options::kStaticExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kPreload:
+ case Options::kKextBundle:
+ throw "-client_name can only be used with -bundle";
+ }
+ }
+
+ // check -init is only used when building a dylib
+ if ( (fInitFunctionName != NULL) && (fOutputKind != Options::kDynamicLibrary) )
+ throw "-init can only be used with -dynamiclib";
+
+ // check -bundle_loader only used with -bundle
+ if ( (fBundleLoader != NULL) && (fOutputKind != Options::kDynamicBundle) )
+ throw "-bundle_loader can only be used with -bundle";
+
+ // check -dtrace not used with -r
+ if ( (fDtraceScriptName != NULL) && (fOutputKind == Options::kObjectFile) )
+ throw "-dtrace can only be used when creating final linked images";
+
+ // check -d can only be used with -r
+ if ( fMakeTentativeDefinitionsReal && (fOutputKind != Options::kObjectFile) )
+ throw "-d can only be used with -r";
+
+ // check that -root_safe is not used with -r
+ if ( fRootSafe && (fOutputKind == Options::kObjectFile) )
+ throw "-root_safe cannot be used with -r";
+
+ // check that -setuid_safe is not used with -r
+ if ( fSetuidSafe && (fOutputKind == Options::kObjectFile) )
+ throw "-setuid_safe cannot be used with -r";
+
+ // rdar://problem/4718189 map ObjC class names to new runtime names
+ bool alterObjC1ClassNamesToObjC2 = false;
+ switch (fArchitecture) {
+ case CPU_TYPE_I386:
+ // i386 only uses new symbols when using objc2 ABI
+ if ( fObjCABIVersion2Override )
+ alterObjC1ClassNamesToObjC2 = true;
+ break;
+ case CPU_TYPE_X86_64:
+ case CPU_TYPE_ARM:
+ alterObjC1ClassNamesToObjC2 = true;
+ break;
+ }
+
+ // make sure all required exported symbols exist
+ std::vector<const char*> impliedExports;
+ for (NameSet::iterator it=fExportSymbols.regularBegin(); it != fExportSymbols.regularEnd(); ++it) {
+ const char* name = *it;
+ const int len = strlen(name);
+ if ( (strcmp(&name[len-3], ".eh") == 0) || (strncmp(name, ".objc_category_name_", 20) == 0) ) {
+ // never export .eh symbols
+ warning("ignoring %s in export list", name);
+ }
+ else if ( (fArchitecture == CPU_TYPE_I386) && !fObjCABIVersion2Override && (strncmp(name, "_OBJC_CLASS_$", 13) == 0) ) {
+ warning("ignoring Objc2 Class symbol %s in i386 export list", name);
+ fRemovedExports.insert(name);
+ }
+ else if ( alterObjC1ClassNamesToObjC2 && (strncmp(name, ".objc_class_name_", 17) == 0) ) {
+ // linking ObjC2 ABI, but have ObjC1 ABI name in export list. Change it to intended name
+ fRemovedExports.insert(name);
+ char* temp;
+ asprintf(&temp, "_OBJC_CLASS_$_%s", &name[17]);
+ impliedExports.push_back(temp);
+ asprintf(&temp, "_OBJC_METACLASS_$_%s", &name[17]);
+ impliedExports.push_back(temp);
+ }
+ else {
+ fInitialUndefines.push_back(name);
+ }
+ }
+ fExportSymbols.remove(fRemovedExports);
+ for (std::vector<const char*>::iterator it=impliedExports.begin(); it != impliedExports.end(); ++it) {
+ const char* name = *it;
+ fExportSymbols.insert(name);
+ fInitialUndefines.push_back(name);
+ }
+
+ // make sure all required re-exported symbols exist
+ for (NameSet::iterator it=fReExportSymbols.regularBegin(); it != fReExportSymbols.regularEnd(); ++it) {
+ fInitialUndefines.push_back(*it);
+ }
+
+ // make sure that -init symbol exists
+ if ( fInitFunctionName != NULL )
+ fInitialUndefines.push_back(fInitFunctionName);
+
+ // make sure that entry symbol exists
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kStaticExecutable:
+ case Options::kDyld:
+ case Options::kPreload:
+ fInitialUndefines.push_back(fEntryName);
+ break;
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kObjectFile:
+ case Options::kKextBundle:
+ break;
+ }
+
+ // make sure every alias base exists
+ for (std::vector<AliasPair>::iterator it=fAliases.begin(); it != fAliases.end(); ++it) {
+ fInitialUndefines.push_back(it->realName);
+ }
+
+ // check custom segments
+ if ( fCustomSegmentAddresses.size() != 0 ) {
+ // verify no segment is in zero page
+ if ( fZeroPageSize != ULLONG_MAX ) {
+ for (std::vector<SegmentStart>::iterator it = fCustomSegmentAddresses.begin(); it != fCustomSegmentAddresses.end(); ++it) {
+ if ( it->address < fZeroPageSize )
+ throwf("-segaddr %s 0x%llX conflicts with -pagezero_size", it->name, it->address);
+ }
+ }
+ // verify no duplicates
+ for (std::vector<SegmentStart>::iterator it = fCustomSegmentAddresses.begin(); it != fCustomSegmentAddresses.end(); ++it) {
+ for (std::vector<SegmentStart>::iterator it2 = fCustomSegmentAddresses.begin(); it2 != fCustomSegmentAddresses.end(); ++it2) {
+ if ( (it->address == it2->address) && (it != it2) )
+ throwf("duplicate -segaddr addresses for %s and %s", it->name, it2->name);
+ }
+ // a custom segment address of zero will disable the use of a zero page
+ if ( it->address == 0 )
+ fZeroPageSize = 0;
+ }
+ }
+
+ if ( fZeroPageSize == ULLONG_MAX ) {
+ // zero page size not specified on command line, set default
+ switch (fArchitecture) {
+ case CPU_TYPE_I386:
+ case CPU_TYPE_ARM:
+ // first 4KB for 32-bit architectures
+ fZeroPageSize = 0x1000;
+ break;
+ case CPU_TYPE_X86_64:
+ // first 4GB for x86_64 on all OS's
+ fZeroPageSize = 0x100000000ULL;
+ break;
+ default:
+ // if -arch not used, default to 4K zero-page
+ fZeroPageSize = 0x1000;
+ }
+ }
+ else {
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kStaticExecutable:
+ // -pagezero_size size only legal when building main executable
+ break;
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kPreload:
+ case Options::kKextBundle:
+ if ( fZeroPageSize != 0 )
+ throw "-pagezero_size option can only be used when linking a main executable";
+ }
+ }
+
+ // if main executable with custom base address, model zero page as custom segment
+ if ( (fOutputKind == Options::kDynamicExecutable) && (fBaseAddress != 0) && (fZeroPageSize != 0) ) {
+ SegmentStart seg;
+ seg.name = "__PAGEZERO";
+ seg.address = 0;;
+ fCustomSegmentAddresses.push_back(seg);
+ }
+
+ // -dead_strip and -r are incompatible
+ if ( fDeadStrip && (fOutputKind == Options::kObjectFile) )
+ throw "-r and -dead_strip cannot be used together";
+
+ // can't use -rpath unless targeting 10.5 or later
+ if ( fRPaths.size() > 0 ) {
+ if ( !minOS(ld::mac10_5, ld::iOS_2_0) )
+ throw "-rpath can only be used when targeting Mac OS X 10.5 or later";
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ break;
+ case Options::kStaticExecutable:
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kPreload:
+ case Options::kKextBundle:
+ throw "-rpath can only be used when creating a dynamic final linked image";
+ }
+ }
+
+ if ( fPositionIndependentExecutable ) {
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ // check -pie is only used when building a dynamic main executable for 10.5
+ if ( !minOS(ld::mac10_5, ld::iOS_4_2) ) {
+ if ( fIOSVersionMin == ld::iOSVersionUnset )
+ throw "-pie can only be used when targeting Mac OS X 10.5 or later";
+ else
+ throw "-pie can only be used when targeting iOS 4.2 or later";
+ }
+ break;
+ case Options::kStaticExecutable:
+ case Options::kPreload:
+ // -pie is ok with -static or -preload
+ break;
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ warning("-pie being ignored. It is only used when linking a main executable");
+ fPositionIndependentExecutable = false;
+ break;
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kKextBundle:
+ throw "-pie can only be used when linking a main executable";
+ }
+ }
+
+ // check -read_only_relocs is not used with x86_64
+ if ( fAllowTextRelocs ) {
+ if ( (fArchitecture == CPU_TYPE_X86_64) && (fOutputKind != kKextBundle) ) {
+ warning("-read_only_relocs cannot be used with x86_64");
+ fAllowTextRelocs = false;
+ }
+ }
+
+ // check -mark_auto_dead_strip is only used with dylibs
+ if ( fMarkDeadStrippableDylib ) {
+ if ( fOutputKind != Options::kDynamicLibrary ) {
+ warning("-mark_auto_dead_strip can only be used when creating a dylib");
+ fMarkDeadStrippableDylib = false;
+ }
+ }
+
+ // -force_cpusubtype_ALL is not supported for ARM
+ if ( fForceSubtypeAll ) {
+ if ( fArchitecture == CPU_TYPE_ARM ) {
+ warning("-force_cpusubtype_ALL will become unsupported for ARM architectures");
+ }
+ }
+
+ // -reexported_symbols_list can only be used with -dynamiclib
+ if ( !fReExportSymbols.empty() ) {
+ if ( fOutputKind != Options::kDynamicLibrary )
+ throw "-reexported_symbols_list can only used used when created dynamic libraries";
+ if ( !minOS(ld::mac10_7, ld::iOS_4_2) )
+ throw "targeted OS version does not support -reexported_symbols_list";
+ }
+
+ // -dyld_env can only be used with main executables
+ if ( (fOutputKind != Options::kDynamicExecutable) && (fDyldEnvironExtras.size() != 0) )
+ throw "-dyld_env can only used used when created main executables";
+}
+
+
+void Options::checkForClassic(int argc, const char* argv[])
+{
+ // scan options
+ bool archFound = false;
+ bool staticFound = false;
+ bool dtraceFound = false;
+ bool kextFound = false;
+ bool rFound = false;
+ bool creatingMachKernel = false;
+ bool newLinker = false;
+
+ // build command line buffer in case ld crashes
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+ CRSetCrashLogMessage(crashreporterBuffer);
+#endif
+ const char* srcRoot = getenv("SRCROOT");
+ if ( srcRoot != NULL ) {
+ strlcpy(crashreporterBuffer, "SRCROOT=", crashreporterBufferSize);
+ strlcat(crashreporterBuffer, srcRoot, crashreporterBufferSize);
+ strlcat(crashreporterBuffer, "\n", crashreporterBufferSize);
+ }
+#ifdef LD_VERS
+ strlcat(crashreporterBuffer, LD_VERS, crashreporterBufferSize);
+ strlcat(crashreporterBuffer, "\n", crashreporterBufferSize);
+#endif
+ strlcat(crashreporterBuffer, "ld ", crashreporterBufferSize);
+ for(int i=1; i < argc; ++i) {
+ strlcat(crashreporterBuffer, argv[i], crashreporterBufferSize);
+ strlcat(crashreporterBuffer, " ", crashreporterBufferSize);
+ }
+
+ for(int i=0; i < argc; ++i) {
+ const char* arg = argv[i];
+ if ( arg[0] == '-' ) {
+ if ( strcmp(arg, "-arch") == 0 ) {
+ parseArch(argv[++i]);
+ archFound = true;
+ }
+ else if ( strcmp(arg, "-static") == 0 ) {
+ staticFound = true;
+ }
+ else if ( strcmp(arg, "-kext") == 0 ) {
+ kextFound = true;
+ }
+ else if ( strcmp(arg, "-dtrace") == 0 ) {
+ dtraceFound = true;
+ }
+ else if ( strcmp(arg, "-r") == 0 ) {
+ rFound = true;
+ }
+ else if ( strcmp(arg, "-new_linker") == 0 ) {
+ newLinker = true;
+ }
+ else if ( strcmp(arg, "-classic_linker") == 0 ) {
+ // ld_classic does not understand this option, so remove it
+ for(int j=i; j < argc; ++j)
+ argv[j] = argv[j+1];
+ warning("using ld_classic");
+ this->gotoClassicLinker(argc-1, argv);
+ }
+ else if ( strcmp(arg, "-o") == 0 ) {
+ const char* outfile = argv[++i];
+ if ( (outfile != NULL) && (strstr(outfile, "/mach_kernel") != NULL) )
+ creatingMachKernel = true;
+ }
+ }
+ }
+}
+
+void Options::gotoClassicLinker(int argc, const char* argv[])
+{
+ argv[0] = "ld_classic";
+ // ld_classic does not support -iphoneos_version_min, so change
+ for(int j=0; j < argc; ++j) {
+ if ( (strcmp(argv[j], "-iphoneos_version_min") == 0) || (strcmp(argv[j], "-ios_version_min") == 0) ) {
+ argv[j] = "-macosx_version_min";
+ if ( j < argc-1 )
+ argv[j+1] = "10.5";
+ break;
+ }
+ }
+ // ld classic does not understand -kext (change to -static -r)
+ for(int j=0; j < argc; ++j) {
+ if ( strcmp(argv[j], "-kext") == 0)
+ argv[j] = "-r";
+ else if ( strcmp(argv[j], "-dynamic") == 0)
+ argv[j] = "-static";
+ }
+ // ld classic does not understand -demangle
+ for(int j=0; j < argc; ++j) {
+ if ( strcmp(argv[j], "-demangle") == 0)
+ argv[j] = "-noprebind";
+ }
+ // in -v mode, print command line passed to ld_classic
+ for(int i=0; i < argc; ++i) {
+ if ( strcmp(argv[i], "-v") == 0 ) {
+ for(int j=0; j < argc; ++j)
+ printf("%s ", argv[j]);
+ printf("\n");
+ break;
+ }
+ }
+ char rawPath[PATH_MAX];
+ char path[PATH_MAX];
+ uint32_t bufSize = PATH_MAX;
+ if ( _NSGetExecutablePath(rawPath, &bufSize) != -1 ) {
+ if ( realpath(rawPath, path) != NULL ) {
+ char* lastSlash = strrchr(path, '/');
+ if ( lastSlash != NULL ) {
+ strcpy(lastSlash+1, "ld_classic");
+ argv[0] = path;
+ execvp(path, (char**)argv);
+ }
+ }
+ }
+ // in case of error in above, try searching for ld_classic via PATH
+ execvp(argv[0], (char**)argv);
+ fprintf(stderr, "can't exec ld_classic\n");
+ exit(1);
+}
+
+
+// Note, returned string buffer is own by this function.
+// It should not be freed
+// It will be reused, so clients need to strdup() if they want
+// to use it long term.
+const char* Options::demangleSymbol(const char* sym) const
+{
+ // only try to demangle symbols if -demangle on command line
+ if ( !fDemangle )
+ return sym;
+
+ // only try to demangle symbols that look like C++ symbols
+ if ( strncmp(sym, "__Z", 3) != 0 )
+ return sym;
+
+ static size_t size = 1024;
+ static char* buff = (char*)malloc(size);
+ int status;
+
+ char* result = abi::__cxa_demangle(&sym[1], buff, &size, &status);
+ if ( result != NULL ) {
+ // if demangling successful, keep buffer for next demangle
+ buff = result;
+ return buff;
+ }
+ return sym;
+}
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __OPTIONS__
+#define __OPTIONS__
+
+
+#include <stdint.h>
+#include <mach/machine.h>
+
+#include <vector>
+#include <ext/hash_set>
+#include <ext/hash_map>
+
+#include "ld.hpp"
+#include "Snapshot.h"
+
+extern void throwf (const char* format, ...) __attribute__ ((noreturn,format(printf, 1, 2)));
+extern void warning(const char* format, ...) __attribute__((format(printf, 1, 2)));
+
+class Snapshot;
+
+class LibraryOptions
+{
+public:
+ LibraryOptions() : fWeakImport(false), fReExport(false), fBundleLoader(false),
+ fLazyLoad(false), fUpward(false), fForceLoad(false) {}
+ // for dynamic libraries
+ bool fWeakImport;
+ bool fReExport;
+ bool fBundleLoader;
+ bool fLazyLoad;
+ bool fUpward;
+ // for static libraries
+ bool fForceLoad;
+};
+
+
+
+//
+// The public interface to the Options class is the abstract representation of what work the linker
+// should do.
+//
+// This abstraction layer will make it easier to support a future where the linker is a shared library
+// invoked directly from Xcode. The target settings in Xcode would be used to directly construct an Options
+// object (without building a command line which is then parsed).
+//
+//
+class Options
+{
+public:
+ Options(int argc, const char* argv[]);
+ ~Options();
+
+ enum OutputKind { kDynamicExecutable, kStaticExecutable, kDynamicLibrary, kDynamicBundle, kObjectFile, kDyld, kPreload, kKextBundle };
+ enum NameSpace { kTwoLevelNameSpace, kFlatNameSpace, kForceFlatNameSpace };
+ // Standard treatment for many options.
+ enum Treatment { kError, kWarning, kSuppress, kNULL, kInvalid };
+ enum UndefinedTreatment { kUndefinedError, kUndefinedWarning, kUndefinedSuppress, kUndefinedDynamicLookup };
+ enum WeakReferenceMismatchTreatment { kWeakReferenceMismatchError, kWeakReferenceMismatchWeak,
+ kWeakReferenceMismatchNonWeak };
+ enum CommonsMode { kCommonsIgnoreDylibs, kCommonsOverriddenByDylibs, kCommonsConflictsDylibsError };
+ enum UUIDMode { kUUIDNone, kUUIDRandom, kUUIDContent };
+ enum LocalSymbolHandling { kLocalSymbolsAll, kLocalSymbolsNone, kLocalSymbolsSelectiveInclude, kLocalSymbolsSelectiveExclude };
+ enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull };
+
+ class FileInfo {
+ public:
+ const char* path;
+ uint64_t fileLen;
+ time_t modTime;
+ LibraryOptions options;
+ ld::File::Ordinal ordinal;
+ bool fromFileList;
+
+ // These are used by the threaded input file parsing engine.
+ mutable int inputFileSlot; // The input file "slot" assigned to this particular file
+ bool readyToParse;
+
+ // The use pattern for FileInfo is to create one on the stack in a leaf function and return
+ // it to the calling frame by copy. Therefore the copy constructor steals the path string from
+ // the source, which dies with the stack frame.
+ FileInfo(FileInfo const &other) : path(other.path), fileLen(other.fileLen), modTime(other.modTime), options(other.options), ordinal(other.ordinal), fromFileList(other.fromFileList), inputFileSlot(-1) { ((FileInfo&)other).path = NULL; };
+
+ // Create an empty FileInfo. The path can be set implicitly by checkFileExists().
+ FileInfo() : path(NULL), fileLen(0), modTime(0), options(), fromFileList(false) {};
+
+ // Create a FileInfo for a specific path, but does not stat the file.
+ FileInfo(const char *_path) : path(strdup(_path)), fileLen(0), modTime(0), options(), fromFileList(false) {};
+
+ ~FileInfo() { if (path) ::free((void*)path); }
+
+ // Stat the file and update fileLen and modTime.
+ // If the object already has a path the p must be NULL.
+ // If the object does not have a path then p can be any candidate path, and if the file exists the object permanently remembers the path.
+ // Returns true if the file exists, false if not.
+ bool checkFileExists(const char *p=NULL);
+
+ // Returns true if a previous call to checkFileExists() succeeded.
+ // Returns false if the file does not exist of checkFileExists() has never been called.
+ bool missing() const { return modTime==0; }
+};
+
+ struct ExtraSection {
+ const char* segmentName;
+ const char* sectionName;
+ const char* path;
+ const uint8_t* data;
+ uint64_t dataLen;
+ typedef ExtraSection* iterator;
+ typedef const ExtraSection* const_iterator;
+ };
+
+ struct SectionAlignment {
+ const char* segmentName;
+ const char* sectionName;
+ uint8_t alignment;
+ };
+
+ struct OrderedSymbol {
+ const char* symbolName;
+ const char* objectFileName;
+ };
+ typedef const OrderedSymbol* OrderedSymbolsIterator;
+
+ struct SegmentStart {
+ const char* name;
+ uint64_t address;
+ };
+
+ struct SegmentSize {
+ const char* name;
+ uint64_t size;
+ };
+
+ struct SegmentProtect {
+ const char* name;
+ uint32_t max;
+ uint32_t init;
+ };
+
+ struct DylibOverride {
+ const char* installName;
+ const char* useInstead;
+ };
+
+ struct AliasPair {
+ const char* realName;
+ const char* alias;
+ };
+
+ typedef const char* const* UndefinesIterator;
+
+// const ObjectFile::ReaderOptions& readerOptions();
+ const char* outputFilePath() const { return fOutputFile; }
+ const std::vector<FileInfo>& getInputFiles() const { return fInputFiles; }
+
+ cpu_type_t architecture() const { return fArchitecture; }
+ bool preferSubArchitecture() const { return fHasPreferredSubType; }
+ cpu_subtype_t subArchitecture() const { return fSubArchitecture; }
+ bool allowSubArchitectureMismatches() const { return fAllowCpuSubtypeMismatches; }
+ bool forceCpuSubtypeAll() const { return fForceSubtypeAll; }
+ const char* architectureName() const { return fArchitectureName; }
+ void setArchitecture(cpu_type_t, cpu_subtype_t subtype);
+ bool archSupportsThumb2() const { return fArchSupportsThumb2; }
+ OutputKind outputKind() const { return fOutputKind; }
+ bool prebind() const { return fPrebind; }
+ bool bindAtLoad() const { return fBindAtLoad; }
+ NameSpace nameSpace() const { return fNameSpace; }
+ const char* installPath() const; // only for kDynamicLibrary
+ uint64_t currentVersion() const { return fDylibCurrentVersion; } // only for kDynamicLibrary
+ uint32_t currentVersion32() const; // only for kDynamicLibrary
+ uint32_t compatibilityVersion() const { return fDylibCompatVersion; } // only for kDynamicLibrary
+ const char* entryName() const { return fEntryName; } // only for kDynamicExecutable or kStaticExecutable
+ const char* executablePath();
+ uint64_t baseAddress() const { return fBaseAddress; }
+ uint64_t maxAddress() const { return fMaxAddress; }
+ bool keepPrivateExterns() const { return fKeepPrivateExterns; } // only for kObjectFile
+ bool needsModuleTable() const { return fNeedsModuleTable; } // only for kDynamicLibrary
+ bool interposable(const char* name) const;
+ bool hasExportRestrictList() const { return (fExportMode != kExportDefault); } // -exported_symbol or -unexported_symbol
+ bool hasExportMaskList() const { return (fExportMode == kExportSome); } // just -exported_symbol
+ bool hasWildCardExportRestrictList() const;
+ bool hasReExportList() const { return ! fReExportSymbols.empty(); }
+ bool wasRemovedExport(const char* sym) const { return ( fRemovedExports.find(sym) != fRemovedExports.end() ); }
+ bool allGlobalsAreDeadStripRoots() const;
+ bool shouldExport(const char*) const;
+ bool shouldReExport(const char*) const;
+ bool ignoreOtherArchInputFiles() const { return fIgnoreOtherArchFiles; }
+ bool traceDylibs() const { return fTraceDylibs; }
+ bool traceArchives() const { return fTraceArchives; }
+ bool deadCodeStrip() const { return fDeadStrip; }
+ UndefinedTreatment undefinedTreatment() const { return fUndefinedTreatment; }
+ ld::MacVersionMin macosxVersionMin() const { return fMacVersionMin; }
+ ld::IOSVersionMin iOSVersionMin() const { return fIOSVersionMin; }
+ bool minOS(ld::MacVersionMin mac, ld::IOSVersionMin iPhoneOS);
+ bool messagesPrefixedWithArchitecture();
+ Treatment picTreatment();
+ WeakReferenceMismatchTreatment weakReferenceMismatchTreatment() const { return fWeakReferenceMismatchTreatment; }
+ const char* umbrellaName() const { return fUmbrellaName; }
+ const std::vector<const char*>& allowableClients() const { return fAllowableClients; }
+ const char* clientName() const { return fClientName; }
+ const char* initFunctionName() const { return fInitFunctionName; } // only for kDynamicLibrary
+ const char* dotOutputFile();
+ uint64_t pageZeroSize() const { return fZeroPageSize; }
+ bool hasCustomStack() const { return (fStackSize != 0); }
+ uint64_t customStackSize() const { return fStackSize; }
+ uint64_t customStackAddr() const { return fStackAddr; }
+ bool hasExecutableStack() const { return fExecutableStack; }
+ bool hasNonExecutableHeap() const { return fNonExecutableHeap; }
+ UndefinesIterator initialUndefinesBegin() const { return &fInitialUndefines[0]; }
+ UndefinesIterator initialUndefinesEnd() const { return &fInitialUndefines[fInitialUndefines.size()]; }
+ bool printWhyLive(const char* name) const;
+ uint32_t minimumHeaderPad() const { return fMinimumHeaderPad; }
+ bool maxMminimumHeaderPad() const { return fMaxMinimumHeaderPad; }
+ ExtraSection::const_iterator extraSectionsBegin() const { return &fExtraSections[0]; }
+ ExtraSection::const_iterator extraSectionsEnd() const { return &fExtraSections[fExtraSections.size()]; }
+ CommonsMode commonsMode() const { return fCommonsMode; }
+ bool warnCommons() const { return fWarnCommons; }
+ bool keepRelocations();
+ FileInfo findFile(const char* path) const;
+ UUIDMode UUIDMode() const { return fUUIDMode; }
+ bool warnStabs();
+ bool pauseAtEnd() { return fPause; }
+ bool printStatistics() const { return fStatistics; }
+ bool printArchPrefix() const { return fMessagesPrefixedWithArchitecture; }
+ void gotoClassicLinker(int argc, const char* argv[]);
+ bool sharedRegionEligible() const { return fSharedRegionEligible; }
+ bool printOrderFileStatistics() const { return fPrintOrderFileStatistics; }
+ const char* dTraceScriptName() { return fDtraceScriptName; }
+ bool dTrace() { return (fDtraceScriptName != NULL); }
+ unsigned long orderedSymbolsCount() const { return fOrderedSymbols.size(); }
+ OrderedSymbolsIterator orderedSymbolsBegin() const { return &fOrderedSymbols[0]; }
+ OrderedSymbolsIterator orderedSymbolsEnd() const { return &fOrderedSymbols[fOrderedSymbols.size()]; }
+ bool splitSeg() const { return fSplitSegs; }
+ uint64_t baseWritableAddress() { return fBaseWritableAddress; }
+ uint64_t segmentAlignment() const { return fSegmentAlignment; }
+ uint64_t segPageSize(const char* segName) const;
+ uint64_t customSegmentAddress(const char* segName) const;
+ bool hasCustomSegmentAddress(const char* segName) const;
+ bool hasCustomSectionAlignment(const char* segName, const char* sectName) const;
+ uint8_t customSectionAlignment(const char* segName, const char* sectName) const;
+ uint32_t initialSegProtection(const char*) const;
+ uint32_t maxSegProtection(const char*) const;
+ bool saveTempFiles() const { return fSaveTempFiles; }
+ const std::vector<const char*>& rpaths() const { return fRPaths; }
+ bool readOnlyx86Stubs() { return fReadOnlyx86Stubs; }
+ const std::vector<DylibOverride>& dylibOverrides() const { return fDylibOverrides; }
+ const char* generatedMapPath() const { return fMapPath; }
+ bool positionIndependentExecutable() const { return fPositionIndependentExecutable; }
+ Options::FileInfo findFileUsingPaths(const char* path) const;
+ bool deadStripDylibs() const { return fDeadStripDylibs; }
+ bool allowedUndefined(const char* name) const { return ( fAllowedUndefined.find(name) != fAllowedUndefined.end() ); }
+ bool someAllowedUndefines() const { return (fAllowedUndefined.size() != 0); }
+ LocalSymbolHandling localSymbolHandling() { return fLocalSymbolHandling; }
+ bool keepLocalSymbol(const char* symbolName) const;
+ bool allowTextRelocs() const { return fAllowTextRelocs; }
+ bool warnAboutTextRelocs() const { return fWarnTextRelocs; }
+ bool kextsUseStubs() const { return fKextsUseStubs; }
+ bool usingLazyDylibLinking() const { return fUsingLazyDylibLinking; }
+ bool verbose() const { return fVerbose; }
+ bool makeEncryptable() const { return fEncryptable; }
+ bool needsUnwindInfoSection() const { return fAddCompactUnwindEncoding; }
+ const std::vector<const char*>& llvmOptions() const{ return fLLVMOptions; }
+ const std::vector<const char*>& dyldEnvironExtras() const{ return fDyldEnvironExtras; }
+ bool makeCompressedDyldInfo() const { return fMakeCompressedDyldInfo; }
+ bool hasExportedSymbolOrder();
+ bool exportedSymbolOrder(const char* sym, unsigned int* order) const;
+ bool orderData() { return fOrderData; }
+ bool errorOnOtherArchFiles() const { return fErrorOnOtherArchFiles; }
+ bool markAutoDeadStripDylib() const { return fMarkDeadStrippableDylib; }
+ bool removeEHLabels() const { return fNoEHLabels; }
+ bool useSimplifiedDylibReExports() const { return fUseSimplifiedDylibReExports; }
+ bool objCABIVersion2POverride() const { return fObjCABIVersion2Override; }
+ bool useUpwardDylibs() const { return fCanUseUpwardDylib; }
+ bool fullyLoadArchives() const { return fFullyLoadArchives; }
+ bool loadAllObjcObjectsFromArchives() const { return fLoadAllObjcObjectsFromArchives; }
+ bool autoOrderInitializers() const { return fAutoOrderInitializers; }
+ bool optimizeZeroFill() const { return fOptimizeZeroFill; }
+ bool mergeZeroFill() const { return fMergeZeroFill; }
+ bool logAllFiles() const { return fLogAllFiles; }
+ DebugInfoStripping debugInfoStripping() const { return fDebugInfoStripping; }
+ bool flatNamespace() const { return fFlatNamespace; }
+ bool linkingMainExecutable() const { return fLinkingMainExecutable; }
+ bool implicitlyLinkIndirectPublicDylibs() const { return fImplicitlyLinkPublicDylibs; }
+ bool whyLoad() const { return fWhyLoad; }
+ const char* traceOutputFile() const { return fTraceOutputFile; }
+ bool outputSlidable() const { return fOutputSlidable; }
+ bool haveCmdLineAliases() const { return (fAliases.size() != 0); }
+ const std::vector<AliasPair>& cmdLineAliases() const { return fAliases; }
+ bool makeTentativeDefinitionsReal() const { return fMakeTentativeDefinitionsReal; }
+ const char* dyldInstallPath() const { return fDyldInstallPath; }
+ bool warnWeakExports() const { return fWarnWeakExports; }
+ bool objcGcCompaction() const { return fObjcGcCompaction; }
+ bool objcGc() const { return fObjCGc; }
+ bool objcGcOnly() const { return fObjCGcOnly; }
+ bool canUseThreadLocalVariables() const { return fTLVSupport; }
+ bool addVersionLoadCommand() const { return fVersionLoadCommand; }
+ bool addFunctionStarts() const { return fFunctionStartsLoadCommand; }
+ bool addDataInCodeInfo() const { return fDataInCodeInfoLoadCommand; }
+ bool canReExportSymbols() const { return fCanReExportSymbols; }
+ const char* tempLtoObjectPath() const { return fTempLtoObjectPath; }
+ const char* overridePathlibLTO() const { return fOverridePathlibLTO; }
+ bool objcCategoryMerging() const { return fObjcCategoryMerging; }
+ bool pageAlignDataAtoms() const { return fPageAlignDataAtoms; }
+ bool hasWeakBitTweaks() const;
+ bool forceWeak(const char* symbolName) const;
+ bool forceNotWeak(const char* symbolName) const;
+ bool forceWeakNonWildCard(const char* symbolName) const;
+ bool forceNotWeakNonWildcard(const char* symbolName) const;
+ Snapshot& snapshot() const { return fLinkSnapshot; }
+ bool errorBecauseOfWarnings() const;
+ bool needsThreadLoadCommand() const { return fNeedsThreadLoadCommand; }
+ bool needsEntryPointLoadCommand() const { return fEntryPointLoadCommand; }
+ bool needsSourceVersionLoadCommand() const { return fSourceVersionLoadCommand; }
+ bool needsDependentDRInfo() const { return fDependentDRInfo; }
+ uint64_t sourceVersion() const { return fSourceVersion; }
+ uint32_t sdkVersion() const { return fSDKVersion; }
+ const char* demangleSymbol(const char* sym) const;
+ bool pipelineEnabled() const { return fPipelineFifo != NULL; }
+ const char* pipelineFifo() const { return fPipelineFifo; }
+
+private:
+ class CStringEquals
+ {
+ public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+ };
+ typedef __gnu_cxx::hash_map<const char*, unsigned int, __gnu_cxx::hash<const char*>, CStringEquals> NameToOrder;
+ typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> NameSet;
+ enum ExportMode { kExportDefault, kExportSome, kDontExportSome };
+ enum LibrarySearchMode { kSearchDylibAndArchiveInEachDir, kSearchAllDirsForDylibsThenAllDirsForArchives };
+ enum InterposeMode { kInterposeNone, kInterposeAllExternal, kInterposeSome };
+
+ class SetWithWildcards {
+ public:
+ void insert(const char*);
+ bool contains(const char*) const;
+ bool containsNonWildcard(const char*) const;
+ bool empty() const { return fRegular.empty() && fWildCard.empty(); }
+ bool hasWildCards() const { return !fWildCard.empty(); }
+ NameSet::iterator regularBegin() const { return fRegular.begin(); }
+ NameSet::iterator regularEnd() const { return fRegular.end(); }
+ void remove(const NameSet&);
+ private:
+ static bool hasWildCards(const char*);
+ bool wildCardMatch(const char* pattern, const char* candidate) const;
+ bool inCharRange(const char*& range, unsigned char c) const;
+
+ NameSet fRegular;
+ std::vector<const char*> fWildCard;
+ };
+
+
+ void parse(int argc, const char* argv[]);
+ void checkIllegalOptionCombinations();
+ void buildSearchPaths(int argc, const char* argv[]);
+ void parseArch(const char* architecture);
+ FileInfo findLibrary(const char* rootName, bool dylibsOnly=false);
+ FileInfo findFramework(const char* frameworkName);
+ FileInfo findFramework(const char* rootName, const char* suffix);
+ bool checkForFile(const char* format, const char* dir, const char* rootName,
+ FileInfo& result) const;
+ uint64_t parseVersionNumber64(const char*);
+ uint32_t parseVersionNumber32(const char*);
+ void parseSectionOrderFile(const char* segment, const char* section, const char* path);
+ void parseOrderFile(const char* path, bool cstring);
+ void addSection(const char* segment, const char* section, const char* path);
+ void addSubLibrary(const char* name);
+ void loadFileList(const char* fileOfPaths, ld::File::Ordinal baseOrdinal);
+ uint64_t parseAddress(const char* addr);
+ void loadExportFile(const char* fileOfExports, const char* option, SetWithWildcards& set);
+ void parseAliasFile(const char* fileOfAliases);
+ void parsePreCommandLineEnvironmentSettings();
+ void parsePostCommandLineEnvironmentSettings();
+ void setUndefinedTreatment(const char* treatment);
+ void setMacOSXVersionMin(const char* version);
+ void setIOSVersionMin(const char* version);
+ void setWeakReferenceMismatchTreatment(const char* treatment);
+ void addDylibOverride(const char* paths);
+ void addSectionAlignment(const char* segment, const char* section, const char* alignment);
+ CommonsMode parseCommonsTreatment(const char* mode);
+ Treatment parseTreatment(const char* treatment);
+ void reconfigureDefaults();
+ void checkForClassic(int argc, const char* argv[]);
+ void parseSegAddrTable(const char* segAddrPath, const char* installPath);
+ void addLibrary(const FileInfo& info);
+ void warnObsolete(const char* arg);
+ uint32_t parseProtection(const char* prot);
+ void loadSymbolOrderFile(const char* fileOfExports, NameToOrder& orderMapping);
+
+
+
+// ObjectFile::ReaderOptions fReaderOptions;
+ const char* fOutputFile;
+ std::vector<Options::FileInfo> fInputFiles;
+ cpu_type_t fArchitecture;
+ cpu_subtype_t fSubArchitecture;
+ const char* fArchitectureName;
+ OutputKind fOutputKind;
+ bool fHasPreferredSubType;
+ bool fArchSupportsThumb2;
+ bool fPrebind;
+ bool fBindAtLoad;
+ bool fKeepPrivateExterns;
+ bool fNeedsModuleTable;
+ bool fIgnoreOtherArchFiles;
+ bool fErrorOnOtherArchFiles;
+ bool fForceSubtypeAll;
+ InterposeMode fInterposeMode;
+ bool fDeadStrip;
+ NameSpace fNameSpace;
+ uint32_t fDylibCompatVersion;
+ uint64_t fDylibCurrentVersion;
+ const char* fDylibInstallName;
+ const char* fFinalName;
+ const char* fEntryName;
+ uint64_t fBaseAddress;
+ uint64_t fMaxAddress;
+ uint64_t fBaseWritableAddress;
+ bool fSplitSegs;
+ SetWithWildcards fExportSymbols;
+ SetWithWildcards fDontExportSymbols;
+ SetWithWildcards fInterposeList;
+ SetWithWildcards fForceWeakSymbols;
+ SetWithWildcards fForceNotWeakSymbols;
+ SetWithWildcards fReExportSymbols;
+ NameSet fRemovedExports;
+ NameToOrder fExportSymbolsOrder;
+ ExportMode fExportMode;
+ LibrarySearchMode fLibrarySearchMode;
+ UndefinedTreatment fUndefinedTreatment;
+ bool fMessagesPrefixedWithArchitecture;
+ WeakReferenceMismatchTreatment fWeakReferenceMismatchTreatment;
+ std::vector<const char*> fSubUmbellas;
+ std::vector<const char*> fSubLibraries;
+ std::vector<const char*> fAllowableClients;
+ std::vector<const char*> fRPaths;
+ const char* fClientName;
+ const char* fUmbrellaName;
+ const char* fInitFunctionName;
+ const char* fDotOutputFile;
+ const char* fExecutablePath;
+ const char* fBundleLoader;
+ const char* fDtraceScriptName;
+ const char* fSegAddrTablePath;
+ const char* fMapPath;
+ const char* fDyldInstallPath;
+ const char* fTempLtoObjectPath;
+ const char* fOverridePathlibLTO;
+ uint64_t fZeroPageSize;
+ uint64_t fStackSize;
+ uint64_t fStackAddr;
+ uint64_t fSourceVersion;
+ uint32_t fSDKVersion;
+ bool fExecutableStack;
+ bool fNonExecutableHeap;
+ bool fDisableNonExecutableHeap;
+ uint32_t fMinimumHeaderPad;
+ uint64_t fSegmentAlignment;
+ CommonsMode fCommonsMode;
+ enum UUIDMode fUUIDMode;
+ SetWithWildcards fLocalSymbolsIncluded;
+ SetWithWildcards fLocalSymbolsExcluded;
+ LocalSymbolHandling fLocalSymbolHandling;
+ bool fWarnCommons;
+ bool fVerbose;
+ bool fKeepRelocations;
+ bool fWarnStabs;
+ bool fTraceDylibSearching;
+ bool fPause;
+ bool fStatistics;
+ bool fPrintOptions;
+ bool fSharedRegionEligible;
+ bool fPrintOrderFileStatistics;
+ bool fReadOnlyx86Stubs;
+ bool fPositionIndependentExecutable;
+ bool fPIEOnCommandLine;
+ bool fDisablePositionIndependentExecutable;
+ bool fMaxMinimumHeaderPad;
+ bool fDeadStripDylibs;
+ bool fAllowTextRelocs;
+ bool fWarnTextRelocs;
+ bool fKextsUseStubs;
+ bool fUsingLazyDylibLinking;
+ bool fEncryptable;
+ bool fOrderData;
+ bool fMarkDeadStrippableDylib;
+ bool fMakeCompressedDyldInfo;
+ bool fMakeCompressedDyldInfoForceOff;
+ bool fNoEHLabels;
+ bool fAllowCpuSubtypeMismatches;
+ bool fUseSimplifiedDylibReExports;
+ bool fObjCABIVersion2Override;
+ bool fObjCABIVersion1Override;
+ bool fCanUseUpwardDylib;
+ bool fFullyLoadArchives;
+ bool fLoadAllObjcObjectsFromArchives;
+ bool fFlatNamespace;
+ bool fLinkingMainExecutable;
+ bool fForFinalLinkedImage;
+ bool fForStatic;
+ bool fForDyld;
+ bool fMakeTentativeDefinitionsReal;
+ bool fWhyLoad;
+ bool fRootSafe;
+ bool fSetuidSafe;
+ bool fImplicitlyLinkPublicDylibs;
+ bool fAddCompactUnwindEncoding;
+ bool fWarnCompactUnwind;
+ bool fRemoveDwarfUnwindIfCompactExists;
+ bool fAutoOrderInitializers;
+ bool fOptimizeZeroFill;
+ bool fMergeZeroFill;
+ bool fLogObjectFiles;
+ bool fLogAllFiles;
+ bool fTraceDylibs;
+ bool fTraceIndirectDylibs;
+ bool fTraceArchives;
+ bool fOutputSlidable;
+ bool fWarnWeakExports;
+ bool fObjcGcCompaction;
+ bool fObjCGc;
+ bool fObjCGcOnly;
+ bool fDemangle;
+ bool fTLVSupport;
+ bool fVersionLoadCommand;
+ bool fVersionLoadCommandForcedOn;
+ bool fVersionLoadCommandForcedOff;
+ bool fFunctionStartsLoadCommand;
+ bool fFunctionStartsForcedOn;
+ bool fFunctionStartsForcedOff;
+ bool fDataInCodeInfoLoadCommand;
+ bool fDataInCodeInfoLoadCommandForcedOn;
+ bool fDataInCodeInfoLoadCommandForcedOff;
+ bool fCanReExportSymbols;
+ bool fObjcCategoryMerging;
+ bool fPageAlignDataAtoms;
+ bool fNeedsThreadLoadCommand;
+ bool fEntryPointLoadCommand;
+ bool fEntryPointLoadCommandForceOn;
+ bool fEntryPointLoadCommandForceOff;
+ bool fSourceVersionLoadCommand;
+ bool fSourceVersionLoadCommandForceOn;
+ bool fSourceVersionLoadCommandForceOff;
+ bool fDependentDRInfo;
+ bool fDependentDRInfoForcedOn;
+ bool fDependentDRInfoForcedOff;
+ DebugInfoStripping fDebugInfoStripping;
+ const char* fTraceOutputFile;
+ ld::MacVersionMin fMacVersionMin;
+ ld::IOSVersionMin fIOSVersionMin;
+ std::vector<AliasPair> fAliases;
+ std::vector<const char*> fInitialUndefines;
+ NameSet fAllowedUndefined;
+ NameSet fWhyLive;
+ std::vector<ExtraSection> fExtraSections;
+ std::vector<SectionAlignment> fSectionAlignments;
+ std::vector<OrderedSymbol> fOrderedSymbols;
+ std::vector<SegmentStart> fCustomSegmentAddresses;
+ std::vector<SegmentSize> fCustomSegmentSizes;
+ std::vector<SegmentProtect> fCustomSegmentProtections;
+ std::vector<DylibOverride> fDylibOverrides;
+ std::vector<const char*> fLLVMOptions;
+ std::vector<const char*> fLibrarySearchPaths;
+ std::vector<const char*> fFrameworkSearchPaths;
+ std::vector<const char*> fSDKPaths;
+ std::vector<const char*> fDyldEnvironExtras;
+ bool fSaveTempFiles;
+ mutable Snapshot fLinkSnapshot;
+ bool fSnapshotRequested;
+ const char * fPipelineFifo;
+};
+
+
+
+#endif // __OPTIONS__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <uuid/uuid.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+#include <mach-o/fat.h>
+
+#include <string>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+#include <list>
+#include <algorithm>
+#include <ext/hash_map>
+#include <ext/hash_set>
+
+#include <CommonCrypto/CommonDigest.h>
+#include <AvailabilityMacros.h>
+
+#include "MachOTrie.hpp"
+
+#include "Options.h"
+
+#include "OutputFile.h"
+#include "Architectures.hpp"
+#include "HeaderAndLoadCommands.hpp"
+#include "LinkEdit.hpp"
+#include "LinkEditClassic.hpp"
+
+
+namespace ld {
+namespace tool {
+
+
+OutputFile::OutputFile(const Options& opts)
+ :
+ hasWeakExternalSymbols(false), usesWeakExternalSymbols(false), overridesWeakExternalSymbols(false),
+ _noReExportedDylibs(false), hasThreadLocalVariableDefinitions(false), pieDisabled(false), hasDataInCode(false),
+ headerAndLoadCommandsSection(NULL),
+ rebaseSection(NULL), bindingSection(NULL), weakBindingSection(NULL),
+ lazyBindingSection(NULL), exportSection(NULL),
+ splitSegInfoSection(NULL), functionStartsSection(NULL),
+ dataInCodeSection(NULL), dependentDRsSection(NULL),
+ symbolTableSection(NULL), stringPoolSection(NULL),
+ localRelocationsSection(NULL), externalRelocationsSection(NULL),
+ sectionRelocationsSection(NULL),
+ indirectSymbolTableSection(NULL),
+ _options(opts),
+ _hasDyldInfo(opts.makeCompressedDyldInfo()),
+ _hasSymbolTable(true),
+ _hasSectionRelocations(opts.outputKind() == Options::kObjectFile),
+ _hasSplitSegInfo(opts.sharedRegionEligible()),
+ _hasFunctionStartsInfo(opts.addFunctionStarts()),
+ _hasDataInCodeInfo(opts.addDataInCodeInfo()),
+ _hasDependentDRInfo(opts.needsDependentDRInfo()),
+ _hasDynamicSymbolTable(true),
+ _hasLocalRelocations(!opts.makeCompressedDyldInfo()),
+ _hasExternalRelocations(!opts.makeCompressedDyldInfo()),
+ _encryptedTEXTstartOffset(0),
+ _encryptedTEXTendOffset(0),
+ _localSymbolsStartIndex(0),
+ _localSymbolsCount(0),
+ _globalSymbolsStartIndex(0),
+ _globalSymbolsCount(0),
+ _importSymbolsStartIndex(0),
+ _importSymbolsCount(0),
+ _sectionsRelocationsAtom(NULL),
+ _localRelocsAtom(NULL),
+ _externalRelocsAtom(NULL),
+ _symbolTableAtom(NULL),
+ _indirectSymbolTableAtom(NULL),
+ _rebasingInfoAtom(NULL),
+ _bindingInfoAtom(NULL),
+ _lazyBindingInfoAtom(NULL),
+ _weakBindingInfoAtom(NULL),
+ _exportInfoAtom(NULL),
+ _splitSegInfoAtom(NULL),
+ _functionStartsAtom(NULL),
+ _dataInCodeAtom(NULL),
+ _dependentDRInfoAtom(NULL)
+{
+}
+
+void OutputFile::dumpAtomsBySection(ld::Internal& state, bool printAtoms)
+{
+ fprintf(stderr, "SORTED:\n");
+ for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+ fprintf(stderr, "final section %p %s/%s %s start addr=0x%08llX, size=0x%08llX, alignment=%02d, fileOffset=0x%08llX\n",
+ (*it), (*it)->segmentName(), (*it)->sectionName(), (*it)->isSectionHidden() ? "(hidden)" : "",
+ (*it)->address, (*it)->size, (*it)->alignment, (*it)->fileOffset);
+ if ( printAtoms ) {
+ std::vector<const ld::Atom*>& atoms = (*it)->atoms;
+ for (std::vector<const ld::Atom*>::iterator ait = atoms.begin(); ait != atoms.end(); ++ait) {
+ fprintf(stderr, " %p (0x%04llX) %s\n", *ait, (*ait)->size(), (*ait)->name());
+ }
+ }
+ }
+ fprintf(stderr, "DYLIBS:\n");
+ for (std::vector<ld::dylib::File*>::iterator it=state.dylibs.begin(); it != state.dylibs.end(); ++it )
+ fprintf(stderr, " %s\n", (*it)->installPath());
+}
+
+void OutputFile::write(ld::Internal& state)
+{
+ this->buildDylibOrdinalMapping(state);
+ this->addLoadCommands(state);
+ this->addLinkEdit(state);
+ this->setSectionSizesAndAlignments(state);
+ this->setLoadCommandsPadding(state);
+ this->assignFileOffsets(state);
+ this->assignAtomAddresses(state);
+ this->synthesizeDebugNotes(state);
+ this->buildSymbolTable(state);
+ this->generateLinkEditInfo(state);
+ this->makeSplitSegInfo(state);
+ this->updateLINKEDITAddresses(state);
+ //this->dumpAtomsBySection(state, false);
+ this->writeOutputFile(state);
+ this->writeMapFile(state);
+}
+
+bool OutputFile::findSegment(ld::Internal& state, uint64_t addr, uint64_t* start, uint64_t* end, uint32_t* index)
+{
+ uint32_t segIndex = 0;
+ ld::Internal::FinalSection* segFirstSection = NULL;
+ ld::Internal::FinalSection* lastSection = NULL;
+ for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+ ld::Internal::FinalSection* sect = *it;
+ if ( (segFirstSection == NULL ) || strcmp(segFirstSection->segmentName(), sect->segmentName()) != 0 ) {
+ if ( segFirstSection != NULL ) {
+ //fprintf(stderr, "findSegment(0x%llX) seg changed to %s\n", addr, sect->segmentName());
+ if ( (addr >= segFirstSection->address) && (addr < lastSection->address+lastSection->size) ) {
+ *start = segFirstSection->address;
+ *end = lastSection->address+lastSection->size;
+ *index = segIndex;
+ return true;
+ }
+ ++segIndex;
+ }
+ segFirstSection = sect;
+ }
+ lastSection = sect;
+ }
+ return false;
+}
+
+
+void OutputFile::assignAtomAddresses(ld::Internal& state)
+{
+ const bool log = false;
+ if ( log ) fprintf(stderr, "assignAtomAddresses()\n");
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( log ) fprintf(stderr, " section=%s/%s\n", sect->segmentName(), sect->sectionName());
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ if ( log ) fprintf(stderr, " atom=%p, name=%s\n", atom, atom->name());
+ switch ( sect-> type() ) {
+ case ld::Section::typeImportProxies:
+ // want finalAddress() of all proxy atoms to be zero
+ (const_cast<ld::Atom*>(atom))->setSectionStartAddress(0);
+ break;
+ case ld::Section::typeAbsoluteSymbols:
+ // want finalAddress() of all absolute atoms to be value of abs symbol
+ (const_cast<ld::Atom*>(atom))->setSectionStartAddress(0);
+ break;
+ case ld::Section::typeLinkEdit:
+ // linkedit layout is assigned later
+ break;
+ default:
+ (const_cast<ld::Atom*>(atom))->setSectionStartAddress(sect->address);
+ break;
+ }
+ }
+ }
+}
+
+void OutputFile::updateLINKEDITAddresses(ld::Internal& state)
+{
+ if ( _options.makeCompressedDyldInfo() ) {
+ // build dylb rebasing info
+ assert(_rebasingInfoAtom != NULL);
+ _rebasingInfoAtom->encode();
+
+ // build dyld binding info
+ assert(_bindingInfoAtom != NULL);
+ _bindingInfoAtom->encode();
+
+ // build dyld lazy binding info
+ assert(_lazyBindingInfoAtom != NULL);
+ _lazyBindingInfoAtom->encode();
+
+ // build dyld weak binding info
+ assert(_weakBindingInfoAtom != NULL);
+ _weakBindingInfoAtom->encode();
+
+ // build dyld export info
+ assert(_exportInfoAtom != NULL);
+ _exportInfoAtom->encode();
+ }
+
+ if ( _options.sharedRegionEligible() ) {
+ // build split seg info
+ assert(_splitSegInfoAtom != NULL);
+ _splitSegInfoAtom->encode();
+ }
+
+ if ( _options.addFunctionStarts() ) {
+ // build function starts info
+ assert(_functionStartsAtom != NULL);
+ _functionStartsAtom->encode();
+ }
+
+ if ( _options.addDataInCodeInfo() ) {
+ // build data-in-code info
+ assert(_dataInCodeAtom != NULL);
+ _dataInCodeAtom->encode();
+ }
+
+ if ( _options.needsDependentDRInfo() ) {
+ // build dependent dylib DR info
+ assert(_dependentDRInfoAtom != NULL);
+ _dependentDRInfoAtom->encode();
+ }
+
+ // build classic symbol table
+ assert(_symbolTableAtom != NULL);
+ _symbolTableAtom->encode();
+ assert(_indirectSymbolTableAtom != NULL);
+ _indirectSymbolTableAtom->encode();
+
+ // add relocations to .o files
+ if ( _options.outputKind() == Options::kObjectFile ) {
+ assert(_sectionsRelocationsAtom != NULL);
+ _sectionsRelocationsAtom->encode();
+ }
+
+ if ( ! _options.makeCompressedDyldInfo() ) {
+ // build external relocations
+ assert(_externalRelocsAtom != NULL);
+ _externalRelocsAtom->encode();
+ // build local relocations
+ assert(_localRelocsAtom != NULL);
+ _localRelocsAtom->encode();
+ }
+
+ // update address and file offsets now that linkedit content has been generated
+ uint64_t curLinkEditAddress = 0;
+ uint64_t curLinkEditfileOffset = 0;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() != ld::Section::typeLinkEdit )
+ continue;
+ if ( curLinkEditAddress == 0 ) {
+ curLinkEditAddress = sect->address;
+ curLinkEditfileOffset = sect->fileOffset;
+ }
+ uint16_t maxAlignment = 0;
+ uint64_t offset = 0;
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ //fprintf(stderr, "setting linkedit atom offset for %s\n", atom->name());
+ if ( atom->alignment().powerOf2 > maxAlignment )
+ maxAlignment = atom->alignment().powerOf2;
+ // calculate section offset for this atom
+ uint64_t alignment = 1 << atom->alignment().powerOf2;
+ uint64_t currentModulus = (offset % alignment);
+ uint64_t requiredModulus = atom->alignment().modulus;
+ if ( currentModulus != requiredModulus ) {
+ if ( requiredModulus > currentModulus )
+ offset += requiredModulus-currentModulus;
+ else
+ offset += requiredModulus+alignment-currentModulus;
+ }
+ (const_cast<ld::Atom*>(atom))->setSectionOffset(offset);
+ (const_cast<ld::Atom*>(atom))->setSectionStartAddress(curLinkEditAddress);
+ offset += atom->size();
+ }
+ sect->size = offset;
+ // section alignment is that of a contained atom with the greatest alignment
+ sect->alignment = maxAlignment;
+ sect->address = curLinkEditAddress;
+ sect->fileOffset = curLinkEditfileOffset;
+ curLinkEditAddress += sect->size;
+ curLinkEditfileOffset += sect->size;
+ }
+
+ _fileSize = state.sections.back()->fileOffset + state.sections.back()->size;
+}
+
+void OutputFile::setSectionSizesAndAlignments(ld::Internal& state)
+{
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() == ld::Section::typeAbsoluteSymbols ) {
+ // absolute symbols need their finalAddress() to their value
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ (const_cast<ld::Atom*>(atom))->setSectionOffset(atom->objectAddress());
+ }
+ }
+ else {
+ uint16_t maxAlignment = 0;
+ uint64_t offset = 0;
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ bool pagePerAtom = false;
+ uint32_t atomAlignmentPowerOf2 = atom->alignment().powerOf2;
+ if ( _options.pageAlignDataAtoms() && ( strcmp(atom->section().segmentName(), "__DATA") == 0) ) {
+ switch ( atom->section().type() ) {
+ case ld::Section::typeUnclassified:
+ case ld::Section::typeTentativeDefs:
+ case ld::Section::typeZeroFill:
+ pagePerAtom = true;
+ if ( atomAlignmentPowerOf2 < 12 )
+ atomAlignmentPowerOf2 = 12;
+ break;
+ default:
+ break;
+ }
+ }
+ if ( atomAlignmentPowerOf2 > maxAlignment )
+ maxAlignment = atomAlignmentPowerOf2;
+ // calculate section offset for this atom
+ uint64_t alignment = 1 << atomAlignmentPowerOf2;
+ uint64_t currentModulus = (offset % alignment);
+ uint64_t requiredModulus = atom->alignment().modulus;
+ if ( currentModulus != requiredModulus ) {
+ if ( requiredModulus > currentModulus )
+ offset += requiredModulus-currentModulus;
+ else
+ offset += requiredModulus+alignment-currentModulus;
+ }
+ // LINKEDIT atoms are laid out later
+ if ( sect->type() != ld::Section::typeLinkEdit ) {
+ (const_cast<ld::Atom*>(atom))->setSectionOffset(offset);
+ offset += atom->size();
+ if ( pagePerAtom ) {
+ offset = (offset + 4095) & (-4096); // round up to end of page
+ }
+ }
+ if ( (atom->scope() == ld::Atom::scopeGlobal)
+ && (atom->definition() == ld::Atom::definitionRegular)
+ && (atom->combine() == ld::Atom::combineByName)
+ && ((atom->symbolTableInclusion() == ld::Atom::symbolTableIn)
+ || (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)) ) {
+ this->hasWeakExternalSymbols = true;
+ if ( _options.warnWeakExports() )
+ warning("weak external symbol: %s", atom->name());
+ }
+ }
+ sect->size = offset;
+ // section alignment is that of a contained atom with the greatest alignment
+ sect->alignment = maxAlignment;
+ // unless -sectalign command line option overrides
+ if ( _options.hasCustomSectionAlignment(sect->segmentName(), sect->sectionName()) )
+ sect->alignment = _options.customSectionAlignment(sect->segmentName(), sect->sectionName());
+ // each atom in __eh_frame has zero alignment to assure they pack together,
+ // but compilers usually make the CFIs pointer sized, so we want whole section
+ // to start on pointer sized boundary.
+ if ( sect->type() == ld::Section::typeCFI )
+ sect->alignment = 3;
+ if ( sect->type() == ld::Section::typeTLVDefs )
+ this->hasThreadLocalVariableDefinitions = true;
+ }
+ }
+}
+
+void OutputFile::setLoadCommandsPadding(ld::Internal& state)
+{
+ // In other sections, any extra space is put and end of segment.
+ // In __TEXT segment, any extra space is put after load commands to allow post-processing of load commands
+ // Do a reverse layout of __TEXT segment to determine padding size and adjust section size
+ uint64_t paddingSize = 0;
+ switch ( _options.outputKind() ) {
+ case Options::kDyld:
+ // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
+ assert(strcmp(state.sections[1]->sectionName(),"__text") == 0);
+ state.sections[1]->alignment = 12; // page align __text
+ break;
+ case Options::kObjectFile:
+ // mach-o .o files need no padding between load commands and first section
+ // but leave enough room that the object file could be signed
+ paddingSize = 32;
+ break;
+ case Options::kPreload:
+ // mach-o MH_PRELOAD files need no padding between load commands and first section
+ paddingSize = 0;
+ default:
+ // work backwards from end of segment and lay out sections so that extra room goes to padding atom
+ uint64_t addr = 0;
+ for (std::vector<ld::Internal::FinalSection*>::reverse_iterator it = state.sections.rbegin(); it != state.sections.rend(); ++it) {
+ ld::Internal::FinalSection* sect = *it;
+ if ( strcmp(sect->segmentName(), "__TEXT") != 0 )
+ continue;
+ if ( sect == headerAndLoadCommandsSection ) {
+ addr -= headerAndLoadCommandsSection->size;
+ paddingSize = addr % _options.segmentAlignment();
+ break;
+ }
+ addr -= sect->size;
+ addr = addr & (0 - (1 << sect->alignment));
+ }
+
+ // if command line requires more padding than this
+ uint32_t minPad = _options.minimumHeaderPad();
+ if ( _options.maxMminimumHeaderPad() ) {
+ // -headerpad_max_install_names means there should be room for every path load command to grow to 1204 bytes
+ uint32_t altMin = _dylibsToLoad.size() * MAXPATHLEN;
+ if ( _options.outputKind() == Options::kDynamicLibrary )
+ altMin += MAXPATHLEN;
+ if ( altMin > minPad )
+ minPad = altMin;
+ }
+ if ( paddingSize < minPad ) {
+ int extraPages = (minPad - paddingSize + _options.segmentAlignment() - 1)/_options.segmentAlignment();
+ paddingSize += extraPages * _options.segmentAlignment();
+ }
+
+ if ( _options.makeEncryptable() ) {
+ // load commands must be on a separate non-encrypted page
+ int loadCommandsPage = (headerAndLoadCommandsSection->size + minPad)/_options.segmentAlignment();
+ int textPage = (headerAndLoadCommandsSection->size + paddingSize)/_options.segmentAlignment();
+ if ( loadCommandsPage == textPage ) {
+ paddingSize += _options.segmentAlignment();
+ textPage += 1;
+ }
+ // remember start for later use by load command
+ _encryptedTEXTstartOffset = textPage*_options.segmentAlignment();
+ }
+ break;
+ }
+ // add padding to size of section
+ headerAndLoadCommandsSection->size += paddingSize;
+}
+
+
+uint64_t OutputFile::pageAlign(uint64_t addr)
+{
+ const uint64_t alignment = _options.segmentAlignment();
+ return ((addr+alignment-1) & (-alignment));
+}
+
+uint64_t OutputFile::pageAlign(uint64_t addr, uint64_t pageSize)
+{
+ return ((addr+pageSize-1) & (-pageSize));
+}
+
+
+void OutputFile::assignFileOffsets(ld::Internal& state)
+{
+ const bool log = false;
+ const bool hiddenSectionsOccupyAddressSpace = ((_options.outputKind() != Options::kObjectFile)
+ && (_options.outputKind() != Options::kPreload));
+ const bool segmentsArePageAligned = (_options.outputKind() != Options::kObjectFile);
+
+ uint64_t address = 0;
+ const char* lastSegName = "";
+ uint64_t floatingAddressStart = _options.baseAddress();
+
+ // first pass, assign addresses to sections in segments with fixed start addresses
+ if ( log ) fprintf(stderr, "Fixed address segments:\n");
+ for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+ ld::Internal::FinalSection* sect = *it;
+ if ( ! _options.hasCustomSegmentAddress(sect->segmentName()) )
+ continue;
+ if ( segmentsArePageAligned ) {
+ if ( strcmp(lastSegName, sect->segmentName()) != 0 ) {
+ address = _options.customSegmentAddress(sect->segmentName());
+ lastSegName = sect->segmentName();
+ }
+ }
+ // adjust section address based on alignment
+ uint64_t unalignedAddress = address;
+ uint64_t alignment = (1 << sect->alignment);
+ address = ( (unalignedAddress+alignment-1) & (-alignment) );
+
+ // update section info
+ sect->address = address;
+ sect->alignmentPaddingBytes = (address - unalignedAddress);
+
+ // sanity check size
+ if ( ((address + sect->size) > _options.maxAddress()) && (_options.outputKind() != Options::kObjectFile)
+ && (_options.outputKind() != Options::kStaticExecutable) )
+ throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range",
+ sect->sectionName(), address, sect->size);
+
+ if ( log ) fprintf(stderr, " address=0x%08llX, hidden=%d, alignment=%02d, section=%s,%s\n",
+ sect->address, sect->isSectionHidden(), sect->alignment, sect->segmentName(), sect->sectionName());
+ // update running totals
+ if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace )
+ address += sect->size;
+
+ // if TEXT segment address is fixed, then flow other segments after it
+ if ( strcmp(sect->segmentName(), "__TEXT") == 0 ) {
+ floatingAddressStart = address;
+ }
+ }
+
+ // second pass, assign section address to sections in segments that are contiguous with previous segment
+ address = floatingAddressStart;
+ lastSegName = "";
+ ld::Internal::FinalSection* overlappingFixedSection = NULL;
+ ld::Internal::FinalSection* overlappingFlowSection = NULL;
+ if ( log ) fprintf(stderr, "Regular layout segments:\n");
+ for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+ ld::Internal::FinalSection* sect = *it;
+ if ( _options.hasCustomSegmentAddress(sect->segmentName()) )
+ continue;
+ if ( (_options.outputKind() == Options::kPreload) && (sect->type() == ld::Section::typeMachHeader) ) {
+ sect->alignmentPaddingBytes = 0;
+ continue;
+ }
+ if ( segmentsArePageAligned ) {
+ if ( strcmp(lastSegName, sect->segmentName()) != 0 ) {
+ // round up size of last segment if needed
+ if ( *lastSegName != '\0' ) {
+ address = pageAlign(address, _options.segPageSize(lastSegName));
+ }
+ // set segment address based on end of last segment
+ address = pageAlign(address);
+ lastSegName = sect->segmentName();
+ }
+ }
+ // adjust section address based on alignment
+ uint64_t unalignedAddress = address;
+ uint64_t alignment = (1 << sect->alignment);
+ address = ( (unalignedAddress+alignment-1) & (-alignment) );
+
+ // update section info
+ sect->address = address;
+ sect->alignmentPaddingBytes = (address - unalignedAddress);
+
+ // sanity check size
+ if ( ((address + sect->size) > _options.maxAddress()) && (_options.outputKind() != Options::kObjectFile)
+ && (_options.outputKind() != Options::kStaticExecutable) )
+ throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range",
+ sect->sectionName(), address, sect->size);
+
+ // sanity check it does not overlap a fixed address segment
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* otherSect = *sit;
+ if ( ! _options.hasCustomSegmentAddress(otherSect->segmentName()) )
+ continue;
+ if ( sect->address > otherSect->address ) {
+ if ( (otherSect->address+otherSect->size) > sect->address ) {
+ overlappingFixedSection = otherSect;
+ overlappingFlowSection = sect;
+ }
+ }
+ else {
+ if ( (sect->address+sect->size) > otherSect->address ) {
+ overlappingFixedSection = otherSect;
+ overlappingFlowSection = sect;
+ }
+ }
+ }
+
+ if ( log ) fprintf(stderr, " address=0x%08llX, size=0x%08llX, hidden=%d, alignment=%02d, padBytes=%d, section=%s,%s\n",
+ sect->address, sect->size, sect->isSectionHidden(), sect->alignment, sect->alignmentPaddingBytes,
+ sect->segmentName(), sect->sectionName());
+ // update running totals
+ if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace )
+ address += sect->size;
+ }
+ if ( overlappingFixedSection != NULL ) {
+ fprintf(stderr, "Section layout:\n");
+ for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+ ld::Internal::FinalSection* sect = *it;
+ if ( sect->isSectionHidden() )
+ continue;
+ fprintf(stderr, " address:0x%08llX, alignment:2^%d, size:0x%08llX, padBytes:%d, section:%s/%s\n",
+ sect->address, sect->alignment, sect->size, sect->alignmentPaddingBytes,
+ sect->segmentName(), sect->sectionName());
+
+ }
+ throwf("Section (%s/%s) overlaps fixed address section (%s/%s)",
+ overlappingFlowSection->segmentName(), overlappingFlowSection->sectionName(),
+ overlappingFixedSection->segmentName(), overlappingFixedSection->sectionName());
+ }
+
+
+ // third pass, assign section file offsets
+ uint64_t fileOffset = 0;
+ lastSegName = "";
+ if ( log ) fprintf(stderr, "All segments with file offsets:\n");
+ for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+ ld::Internal::FinalSection* sect = *it;
+ if ( hasZeroForFileOffset(sect) ) {
+ // fileoff of zerofill sections is moot, but historically it is set to zero
+ sect->fileOffset = 0;
+
+ // <rdar://problem/10445047> align file offset with address layout
+ fileOffset += sect->alignmentPaddingBytes;
+ }
+ else {
+ // page align file offset at start of each segment
+ if ( segmentsArePageAligned && (*lastSegName != '\0') && (strcmp(lastSegName, sect->segmentName()) != 0) ) {
+ fileOffset = pageAlign(fileOffset, _options.segPageSize(lastSegName));
+ }
+ lastSegName = sect->segmentName();
+
+ // align file offset with address layout
+ fileOffset += sect->alignmentPaddingBytes;
+
+ // update section info
+ sect->fileOffset = fileOffset;
+
+ // update running total
+ fileOffset += sect->size;
+ }
+
+ if ( log ) fprintf(stderr, " fileoffset=0x%08llX, address=0x%08llX, hidden=%d, size=%lld, alignment=%02d, section=%s,%s\n",
+ sect->fileOffset, sect->address, sect->isSectionHidden(), sect->size, sect->alignment,
+ sect->segmentName(), sect->sectionName());
+ }
+
+
+ // for encrypted iPhoneOS apps
+ if ( _options.makeEncryptable() ) {
+ // remember end of __TEXT for later use by load command
+ for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+ ld::Internal::FinalSection* sect = *it;
+ if ( strcmp(sect->segmentName(), "__TEXT") == 0 ) {
+ _encryptedTEXTendOffset = pageAlign(sect->fileOffset + sect->size);
+ }
+ }
+ }
+
+ // remember total file size
+ _fileSize = fileOffset;
+}
+
+
+static const char* makeName(const ld::Atom& atom)
+{
+ static char buffer[4096];
+ switch ( atom.symbolTableInclusion() ) {
+ case ld::Atom::symbolTableNotIn:
+ case ld::Atom::symbolTableNotInFinalLinkedImages:
+ sprintf(buffer, "%s@0x%08llX", atom.name(), atom.objectAddress());
+ break;
+ case ld::Atom::symbolTableIn:
+ case ld::Atom::symbolTableInAndNeverStrip:
+ case ld::Atom::symbolTableInAsAbsolute:
+ case ld::Atom::symbolTableInWithRandomAutoStripLabel:
+ strlcpy(buffer, atom.name(), 4096);
+ break;
+ }
+ return buffer;
+}
+
+static const char* referenceTargetAtomName(ld::Internal& state, const ld::Fixup* ref)
+{
+ switch ( ref->binding ) {
+ case ld::Fixup::bindingNone:
+ return "NO BINDING";
+ case ld::Fixup::bindingByNameUnbound:
+ return (char*)(ref->u.target);
+ case ld::Fixup::bindingByContentBound:
+ case ld::Fixup::bindingDirectlyBound:
+ return makeName(*((ld::Atom*)(ref->u.target)));
+ case ld::Fixup::bindingsIndirectlyBound:
+ return makeName(*state.indirectBindingTable[ref->u.bindingIndex]);
+ }
+ return "BAD BINDING";
+}
+
+bool OutputFile::targetIsThumb(ld::Internal& state, const ld::Fixup* fixup)
+{
+ switch ( fixup->binding ) {
+ case ld::Fixup::bindingByContentBound:
+ case ld::Fixup::bindingDirectlyBound:
+ return fixup->u.target->isThumb();
+ case ld::Fixup::bindingsIndirectlyBound:
+ return state.indirectBindingTable[fixup->u.bindingIndex]->isThumb();
+ default:
+ break;
+ }
+ throw "unexpected binding";
+}
+
+uint64_t OutputFile::addressOf(const ld::Internal& state, const ld::Fixup* fixup, const ld::Atom** target)
+{
+ if ( !_options.makeCompressedDyldInfo() ) {
+ // For external relocations the classic mach-o format
+ // has addend only stored in the content. That means
+ // that the address of the target is not used.
+ if ( fixup->contentAddendOnly )
+ return 0;
+ }
+ switch ( fixup->binding ) {
+ case ld::Fixup::bindingNone:
+ throw "unexpected bindingNone";
+ case ld::Fixup::bindingByNameUnbound:
+ throw "unexpected bindingByNameUnbound";
+ case ld::Fixup::bindingByContentBound:
+ case ld::Fixup::bindingDirectlyBound:
+ *target = fixup->u.target;
+ return (*target)->finalAddress();
+ case ld::Fixup::bindingsIndirectlyBound:
+ *target = state.indirectBindingTable[fixup->u.bindingIndex];
+ #ifndef NDEBUG
+ if ( ! (*target)->finalAddressMode() ) {
+ throwf("reference to symbol (which has not been assigned an address) %s", (*target)->name());
+ }
+ #endif
+ return (*target)->finalAddress();
+ }
+ throw "unexpected binding";
+}
+
+uint64_t OutputFile::sectionOffsetOf(const ld::Internal& state, const ld::Fixup* fixup)
+{
+ const ld::Atom* target = NULL;
+ switch ( fixup->binding ) {
+ case ld::Fixup::bindingNone:
+ throw "unexpected bindingNone";
+ case ld::Fixup::bindingByNameUnbound:
+ throw "unexpected bindingByNameUnbound";
+ case ld::Fixup::bindingByContentBound:
+ case ld::Fixup::bindingDirectlyBound:
+ target = fixup->u.target;
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ target = state.indirectBindingTable[fixup->u.bindingIndex];
+ break;
+ }
+ assert(target != NULL);
+
+ uint64_t targetAddress = target->finalAddress();
+ for (std::vector<ld::Internal::FinalSection*>::const_iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+ const ld::Internal::FinalSection* sect = *it;
+ if ( (sect->address <= targetAddress) && (targetAddress < (sect->address+sect->size)) )
+ return targetAddress - sect->address;
+ }
+ throw "section not found for section offset";
+}
+
+
+
+uint64_t OutputFile::tlvTemplateOffsetOf(const ld::Internal& state, const ld::Fixup* fixup)
+{
+ const ld::Atom* target = NULL;
+ switch ( fixup->binding ) {
+ case ld::Fixup::bindingNone:
+ throw "unexpected bindingNone";
+ case ld::Fixup::bindingByNameUnbound:
+ throw "unexpected bindingByNameUnbound";
+ case ld::Fixup::bindingByContentBound:
+ case ld::Fixup::bindingDirectlyBound:
+ target = fixup->u.target;
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ target = state.indirectBindingTable[fixup->u.bindingIndex];
+ break;
+ }
+ assert(target != NULL);
+
+ for (std::vector<ld::Internal::FinalSection*>::const_iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+ const ld::Internal::FinalSection* sect = *it;
+ switch ( sect->type() ) {
+ case ld::Section::typeTLVInitialValues:
+ case ld::Section::typeTLVZeroFill:
+ return target->finalAddress() - sect->address;
+ default:
+ break;
+ }
+ }
+ throw "section not found for tlvTemplateOffsetOf";
+}
+
+void OutputFile::printSectionLayout(ld::Internal& state)
+{
+ // show layout of final image
+ fprintf(stderr, "final section layout:\n");
+ for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+ if ( (*it)->isSectionHidden() )
+ continue;
+ fprintf(stderr, " %s/%s addr=0x%08llX, size=0x%08llX, fileOffset=0x%08llX, type=%d\n",
+ (*it)->segmentName(), (*it)->sectionName(),
+ (*it)->address, (*it)->size, (*it)->fileOffset, (*it)->type());
+ }
+}
+
+
+void OutputFile::rangeCheck8(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+ if ( (displacement > 127) || (displacement < -128) ) {
+ // show layout of final image
+ printSectionLayout(state);
+
+ const ld::Atom* target;
+ throwf("8-bit reference out of range (%lld max is +/-127B): from %s (0x%08llX) to %s (0x%08llX)",
+ displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),
+ addressOf(state, fixup, &target));
+ }
+}
+
+void OutputFile::rangeCheck16(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+ const int64_t thirtyTwoKLimit = 0x00007FFF;
+ if ( (displacement > thirtyTwoKLimit) || (displacement < (-thirtyTwoKLimit)) ) {
+ // show layout of final image
+ printSectionLayout(state);
+
+ const ld::Atom* target;
+ throwf("16-bit reference out of range (%lld max is +/-32KB): from %s (0x%08llX) to %s (0x%08llX)",
+ displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),
+ addressOf(state, fixup, &target));
+ }
+}
+
+void OutputFile::rangeCheckBranch32(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+ const int64_t twoGigLimit = 0x7FFFFFFF;
+ if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
+ // show layout of final image
+ printSectionLayout(state);
+
+ const ld::Atom* target;
+ throwf("32-bit branch out of range (%lld max is +/-2GB): from %s (0x%08llX) to %s (0x%08llX)",
+ displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),
+ addressOf(state, fixup, &target));
+ }
+}
+
+
+void OutputFile::rangeCheckAbsolute32(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+ const int64_t fourGigLimit = 0xFFFFFFFF;
+ if ( displacement > fourGigLimit ) {
+ // <rdar://problem/9610466> cannot enforce 32-bit range checks on 32-bit archs because assembler loses sign information
+ // .long _foo - 0xC0000000
+ // is encoded in mach-o the same as:
+ // .long _foo + 0x40000000
+ // so if _foo lays out to 0xC0000100, the first is ok, but the second is not.
+ if ( (_options.architecture() == CPU_TYPE_ARM) || (_options.architecture() == CPU_TYPE_I386) ) {
+ // Unlikely userland code does funky stuff like this, so warn for them, but not warn for -preload
+ if ( _options.outputKind() != Options::kPreload ) {
+ warning("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to 0x%08llX",
+ displacement, atom->name(), fixup->offsetInAtom, atom->finalAddress(), displacement);
+ }
+ return;
+ }
+ // show layout of final image
+ printSectionLayout(state);
+
+ const ld::Atom* target;
+ if ( fixup->binding == ld::Fixup::bindingNone )
+ throwf("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to 0x%08llX",
+ displacement, atom->name(), fixup->offsetInAtom, atom->finalAddress(), displacement);
+ else
+ throwf("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to %s (0x%08llX)",
+ displacement, atom->name(), fixup->offsetInAtom, atom->finalAddress(), referenceTargetAtomName(state, fixup),
+ addressOf(state, fixup, &target));
+ }
+}
+
+
+void OutputFile::rangeCheckRIP32(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+ const int64_t twoGigLimit = 0x7FFFFFFF;
+ if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
+ // show layout of final image
+ printSectionLayout(state);
+
+ const ld::Atom* target;
+ throwf("32-bit RIP relative reference out of range (%lld max is +/-4GB): from %s (0x%08llX) to %s (0x%08llX)",
+ displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),
+ addressOf(state, fixup, &target));
+ }
+}
+
+void OutputFile::rangeCheckARM12(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+ if ( (displacement > 4092LL) || (displacement < (-4092LL)) ) {
+ // show layout of final image
+ printSectionLayout(state);
+
+ const ld::Atom* target;
+ throwf("ARM ldr 12-bit displacement out of range (%lld max is +/-4096B): from %s (0x%08llX) to %s (0x%08llX)",
+ displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),
+ addressOf(state, fixup, &target));
+ }
+}
+
+
+void OutputFile::rangeCheckARMBranch24(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+ if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
+ // show layout of final image
+ printSectionLayout(state);
+
+ const ld::Atom* target;
+ throwf("b/bl/blx ARM branch out of range (%lld max is +/-32MB): from %s (0x%08llX) to %s (0x%08llX)",
+ displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),
+ addressOf(state, fixup, &target));
+ }
+}
+
+void OutputFile::rangeCheckThumbBranch22(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+ // thumb2 supports a larger displacement
+ if ( _options.preferSubArchitecture() && _options.archSupportsThumb2() ) {
+ if ( (displacement > 16777214LL) || (displacement < (-16777216LL)) ) {
+ // show layout of final image
+ printSectionLayout(state);
+
+ const ld::Atom* target;
+ throwf("b/bl/blx thumb2 branch out of range (%lld max is +/-16MB): from %s (0x%08llX) to %s (0x%08llX)",
+ displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),
+ addressOf(state, fixup, &target));
+ }
+ }
+ else {
+ if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
+ // show layout of final image
+ printSectionLayout(state);
+
+ const ld::Atom* target;
+ throwf("b/bl/blx thumb1 branch out of range (%lld max is +/-4MB): from %s (0x%08llX) to %s (0x%08llX)",
+ displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),
+ addressOf(state, fixup, &target));
+ }
+ }
+}
+
+
+
+
+
+uint16_t OutputFile::get16LE(uint8_t* loc) { return LittleEndian::get16(*(uint16_t*)loc); }
+void OutputFile::set16LE(uint8_t* loc, uint16_t value) { LittleEndian::set16(*(uint16_t*)loc, value); }
+
+uint32_t OutputFile::get32LE(uint8_t* loc) { return LittleEndian::get32(*(uint32_t*)loc); }
+void OutputFile::set32LE(uint8_t* loc, uint32_t value) { LittleEndian::set32(*(uint32_t*)loc, value); }
+
+uint64_t OutputFile::get64LE(uint8_t* loc) { return LittleEndian::get64(*(uint64_t*)loc); }
+void OutputFile::set64LE(uint8_t* loc, uint64_t value) { LittleEndian::set64(*(uint64_t*)loc, value); }
+
+uint16_t OutputFile::get16BE(uint8_t* loc) { return BigEndian::get16(*(uint16_t*)loc); }
+void OutputFile::set16BE(uint8_t* loc, uint16_t value) { BigEndian::set16(*(uint16_t*)loc, value); }
+
+uint32_t OutputFile::get32BE(uint8_t* loc) { return BigEndian::get32(*(uint32_t*)loc); }
+void OutputFile::set32BE(uint8_t* loc, uint32_t value) { BigEndian::set32(*(uint32_t*)loc, value); }
+
+uint64_t OutputFile::get64BE(uint8_t* loc) { return BigEndian::get64(*(uint64_t*)loc); }
+void OutputFile::set64BE(uint8_t* loc, uint64_t value) { BigEndian::set64(*(uint64_t*)loc, value); }
+
+void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::Atom* atom, uint8_t* buffer)
+{
+ //fprintf(stderr, "applyFixUps() on %s\n", atom->name());
+ int64_t accumulator = 0;
+ const ld::Atom* toTarget = NULL;
+ const ld::Atom* fromTarget;
+ int64_t delta;
+ uint32_t instruction;
+ uint32_t newInstruction;
+ bool is_bl;
+ bool is_blx;
+ bool is_b;
+ bool thumbTarget = false;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ uint8_t* fixUpLocation = &buffer[fit->offsetInAtom];
+ switch ( (ld::Fixup::Kind)(fit->kind) ) {
+ case ld::Fixup::kindNone:
+ case ld::Fixup::kindNoneFollowOn:
+ case ld::Fixup::kindNoneGroupSubordinate:
+ case ld::Fixup::kindNoneGroupSubordinateFDE:
+ case ld::Fixup::kindNoneGroupSubordinateLSDA:
+ case ld::Fixup::kindNoneGroupSubordinatePersonality:
+ break;
+ case ld::Fixup::kindSetTargetAddress:
+ accumulator = addressOf(state, fit, &toTarget);
+ thumbTarget = targetIsThumb(state, fit);
+ if ( thumbTarget )
+ accumulator |= 1;
+ if ( fit->contentAddendOnly || fit->contentDetlaToAddendOnly )
+ accumulator = 0;
+ break;
+ case ld::Fixup::kindSubtractTargetAddress:
+ delta = addressOf(state, fit, &fromTarget);
+ if ( ! fit->contentAddendOnly )
+ accumulator -= delta;
+ break;
+ case ld::Fixup::kindAddAddend:
+ // <rdar://problem/8342028> ARM main executables main contain .long constants pointing
+ // into themselves such as jump tables. These .long should not have thumb bit set
+ // even though the target is a thumb instruction. We can tell it is an interior pointer
+ // because we are processing an addend.
+ if ( thumbTarget && (toTarget == atom) && ((int32_t)fit->u.addend > 0) ) {
+ accumulator &= (-2);
+ //warning("removing thumb bit from intra-atom pointer in %s %s+0x%0X",
+ // atom->section().sectionName(), atom->name(), fit->offsetInAtom);
+ }
+ accumulator += fit->u.addend;
+ break;
+ case ld::Fixup::kindSubtractAddend:
+ accumulator -= fit->u.addend;
+ break;
+ case ld::Fixup::kindSetTargetImageOffset:
+ accumulator = addressOf(state, fit, &toTarget) - mhAddress;
+ break;
+ case ld::Fixup::kindSetTargetSectionOffset:
+ accumulator = sectionOffsetOf(state, fit);
+ break;
+ case ld::Fixup::kindSetTargetTLVTemplateOffset:
+ accumulator = tlvTemplateOffsetOf(state, fit);
+ break;
+ case ld::Fixup::kindStore8:
+ *fixUpLocation += accumulator;
+ break;
+ case ld::Fixup::kindStoreLittleEndian16:
+ set16LE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindStoreLittleEndianLow24of32:
+ set32LE(fixUpLocation, (get32LE(fixUpLocation) & 0xFF000000) | (accumulator & 0x00FFFFFF) );
+ break;
+ case ld::Fixup::kindStoreLittleEndian32:
+ rangeCheckAbsolute32(accumulator, state, atom, fit);
+ set32LE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindStoreLittleEndian64:
+ set64LE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindStoreBigEndian16:
+ set16BE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindStoreBigEndianLow24of32:
+ set32BE(fixUpLocation, (get32BE(fixUpLocation) & 0xFF000000) | (accumulator & 0x00FFFFFF) );
+ break;
+ case ld::Fixup::kindStoreBigEndian32:
+ rangeCheckAbsolute32(accumulator, state, atom, fit);
+ set32BE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindStoreBigEndian64:
+ set64BE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindStoreX86PCRel8:
+ case ld::Fixup::kindStoreX86BranchPCRel8:
+ if ( fit->contentAddendOnly )
+ delta = accumulator;
+ else
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 1);
+ rangeCheck8(delta, state, atom, fit);
+ *fixUpLocation = delta;
+ break;
+ case ld::Fixup::kindStoreX86PCRel16:
+ if ( fit->contentAddendOnly )
+ delta = accumulator;
+ else
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 2);
+ rangeCheck16(delta, state, atom, fit);
+ set16LE(fixUpLocation, delta);
+ break;
+ case ld::Fixup::kindStoreX86BranchPCRel32:
+ if ( fit->contentAddendOnly )
+ delta = accumulator;
+ else
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+ rangeCheckBranch32(delta, state, atom, fit);
+ set32LE(fixUpLocation, delta);
+ break;
+ case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+ case ld::Fixup::kindStoreX86PCRel32GOT:
+ case ld::Fixup::kindStoreX86PCRel32:
+ case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+ if ( fit->contentAddendOnly )
+ delta = accumulator;
+ else
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+ rangeCheckRIP32(delta, state, atom, fit);
+ set32LE(fixUpLocation, delta);
+ break;
+ case ld::Fixup::kindStoreX86PCRel32_1:
+ if ( fit->contentAddendOnly )
+ delta = accumulator - 1;
+ else
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 5);
+ rangeCheckRIP32(delta, state, atom, fit);
+ set32LE(fixUpLocation, delta);
+ break;
+ case ld::Fixup::kindStoreX86PCRel32_2:
+ if ( fit->contentAddendOnly )
+ delta = accumulator - 2;
+ else
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 6);
+ rangeCheckRIP32(delta, state, atom, fit);
+ set32LE(fixUpLocation, delta);
+ break;
+ case ld::Fixup::kindStoreX86PCRel32_4:
+ if ( fit->contentAddendOnly )
+ delta = accumulator - 4;
+ else
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 8);
+ rangeCheckRIP32(delta, state, atom, fit);
+ set32LE(fixUpLocation, delta);
+ break;
+ case ld::Fixup::kindStoreX86Abs32TLVLoad:
+ set32LE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA:
+ assert(_options.outputKind() != Options::kObjectFile);
+ // TLV entry was optimized away, change movl instruction to a leal
+ if ( fixUpLocation[-1] != 0xA1 )
+ throw "TLV load reloc does not point to a movl instruction";
+ fixUpLocation[-1] = 0xB8;
+ set32LE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
+ assert(_options.outputKind() != Options::kObjectFile);
+ // GOT entry was optimized away, change movq instruction to a leaq
+ if ( fixUpLocation[-2] != 0x8B )
+ throw "GOT load reloc does not point to a movq instruction";
+ fixUpLocation[-2] = 0x8D;
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+ rangeCheckRIP32(delta, state, atom, fit);
+ set32LE(fixUpLocation, delta);
+ break;
+ case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
+ assert(_options.outputKind() != Options::kObjectFile);
+ // TLV entry was optimized away, change movq instruction to a leaq
+ if ( fixUpLocation[-2] != 0x8B )
+ throw "TLV load reloc does not point to a movq instruction";
+ fixUpLocation[-2] = 0x8D;
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+ rangeCheckRIP32(delta, state, atom, fit);
+ set32LE(fixUpLocation, delta);
+ break;
+ case ld::Fixup::kindStoreTargetAddressARMLoad12:
+ accumulator = addressOf(state, fit, &toTarget);
+ // fall into kindStoreARMLoad12 case
+ case ld::Fixup::kindStoreARMLoad12:
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 8);
+ rangeCheckARM12(delta, state, atom, fit);
+ instruction = get32LE(fixUpLocation);
+ if ( delta >= 0 ) {
+ newInstruction = instruction & 0xFFFFF000;
+ newInstruction |= ((uint32_t)delta & 0xFFF);
+ }
+ else {
+ newInstruction = instruction & 0xFF7FF000;
+ newInstruction |= ((uint32_t)(-delta) & 0xFFF);
+ }
+ set32LE(fixUpLocation, newInstruction);
+ break;
+ case ld::Fixup::kindDtraceExtra:
+ break;
+ case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+ if ( _options.outputKind() != Options::kObjectFile ) {
+ // change call site to a NOP
+ fixUpLocation[-1] = 0x90; // 1-byte nop
+ fixUpLocation[0] = 0x0F; // 4-byte nop
+ fixUpLocation[1] = 0x1F;
+ fixUpLocation[2] = 0x40;
+ fixUpLocation[3] = 0x00;
+ }
+ break;
+ case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+ if ( _options.outputKind() != Options::kObjectFile ) {
+ // change call site to a clear eax
+ fixUpLocation[-1] = 0x33; // xorl eax,eax
+ fixUpLocation[0] = 0xC0;
+ fixUpLocation[1] = 0x90; // 1-byte nop
+ fixUpLocation[2] = 0x90; // 1-byte nop
+ fixUpLocation[3] = 0x90; // 1-byte nop
+ }
+ break;
+ case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+ if ( _options.outputKind() != Options::kObjectFile ) {
+ // change call site to a NOP
+ set32LE(fixUpLocation, 0xE1A00000);
+ }
+ break;
+ case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+ if ( _options.outputKind() != Options::kObjectFile ) {
+ // change call site to 'eor r0, r0, r0'
+ set32LE(fixUpLocation, 0xE0200000);
+ }
+ break;
+ case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+ if ( _options.outputKind() != Options::kObjectFile ) {
+ // change 32-bit blx call site to two thumb NOPs
+ set32LE(fixUpLocation, 0x46C046C0);
+ }
+ break;
+ case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+ if ( _options.outputKind() != Options::kObjectFile ) {
+ // change 32-bit blx call site to 'nop', 'eor r0, r0'
+ set32LE(fixUpLocation, 0x46C04040);
+ }
+ break;
+ case ld::Fixup::kindLazyTarget:
+ break;
+ case ld::Fixup::kindSetLazyOffset:
+ assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+ accumulator = this->lazyBindingInfoOffsetForLazyPointerAddress(fit->u.target->finalAddress());
+ break;
+ case ld::Fixup::kindDataInCodeStartData:
+ case ld::Fixup::kindDataInCodeStartJT8:
+ case ld::Fixup::kindDataInCodeStartJT16:
+ case ld::Fixup::kindDataInCodeStartJT32:
+ case ld::Fixup::kindDataInCodeStartJTA32:
+ case ld::Fixup::kindDataInCodeEnd:
+ break;
+ case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ accumulator = addressOf(state, fit, &toTarget);
+ thumbTarget = targetIsThumb(state, fit);
+ if ( thumbTarget )
+ accumulator |= 1;
+ if ( fit->contentAddendOnly )
+ accumulator = 0;
+ rangeCheckAbsolute32(accumulator, state, atom, fit);
+ set32LE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+ accumulator = addressOf(state, fit, &toTarget);
+ if ( fit->contentAddendOnly )
+ accumulator = 0;
+ set64LE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindStoreTargetAddressBigEndian32:
+ accumulator = addressOf(state, fit, &toTarget);
+ if ( fit->contentAddendOnly )
+ accumulator = 0;
+ set32BE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindStoreTargetAddressBigEndian64:
+ accumulator = addressOf(state, fit, &toTarget);
+ if ( fit->contentAddendOnly )
+ accumulator = 0;
+ set64BE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32:
+ accumulator = tlvTemplateOffsetOf(state, fit);
+ set32LE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64:
+ accumulator = tlvTemplateOffsetOf(state, fit);
+ set64LE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+ case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+ accumulator = addressOf(state, fit, &toTarget);
+ if ( fit->contentDetlaToAddendOnly )
+ accumulator = 0;
+ if ( fit->contentAddendOnly )
+ delta = 0;
+ else
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+ rangeCheckRIP32(delta, state, atom, fit);
+ set32LE(fixUpLocation, delta);
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+ set32LE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA:
+ // TLV entry was optimized away, change movl instruction to a leal
+ if ( fixUpLocation[-1] != 0xA1 )
+ throw "TLV load reloc does not point to a movl <abs-address>,<reg> instruction";
+ fixUpLocation[-1] = 0xB8;
+ accumulator = addressOf(state, fit, &toTarget);
+ set32LE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+ // GOT entry was optimized away, change movq instruction to a leaq
+ if ( fixUpLocation[-2] != 0x8B )
+ throw "GOT load reloc does not point to a movq instruction";
+ fixUpLocation[-2] = 0x8D;
+ accumulator = addressOf(state, fit, &toTarget);
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+ rangeCheckRIP32(delta, state, atom, fit);
+ set32LE(fixUpLocation, delta);
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
+ // TLV entry was optimized away, change movq instruction to a leaq
+ if ( fixUpLocation[-2] != 0x8B )
+ throw "TLV load reloc does not point to a movq instruction";
+ fixUpLocation[-2] = 0x8D;
+ accumulator = addressOf(state, fit, &toTarget);
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+ rangeCheckRIP32(delta, state, atom, fit);
+ set32LE(fixUpLocation, delta);
+ break;
+ case ld::Fixup::kindStoreTargetAddressARMBranch24:
+ accumulator = addressOf(state, fit, &toTarget);
+ thumbTarget = targetIsThumb(state, fit);
+ if ( thumbTarget )
+ accumulator |= 1;
+ if ( fit->contentDetlaToAddendOnly )
+ accumulator = 0;
+ // fall into kindStoreARMBranch24 case
+ case ld::Fixup::kindStoreARMBranch24:
+ // The pc added will be +8 from the pc
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 8);
+ rangeCheckARMBranch24(delta, state, atom, fit);
+ instruction = get32LE(fixUpLocation);
+ // Make sure we are calling arm with bl, thumb with blx
+ is_bl = ((instruction & 0xFF000000) == 0xEB000000);
+ is_blx = ((instruction & 0xFE000000) == 0xFA000000);
+ is_b = !is_blx && ((instruction & 0x0F000000) == 0x0A000000);
+ if ( is_bl && thumbTarget ) {
+ uint32_t opcode = 0xFA000000;
+ uint32_t disp = (uint32_t)(delta >> 2) & 0x00FFFFFF;
+ uint32_t h_bit = (uint32_t)(delta << 23) & 0x01000000;
+ newInstruction = opcode | h_bit | disp;
+ }
+ else if ( is_blx && !thumbTarget ) {
+ uint32_t opcode = 0xEB000000;
+ uint32_t disp = (uint32_t)(delta >> 2) & 0x00FFFFFF;
+ newInstruction = opcode | disp;
+ }
+ else if ( is_b && thumbTarget ) {
+ if ( fit->contentDetlaToAddendOnly )
+ newInstruction = (instruction & 0xFF000000) | ((uint32_t)(delta >> 2) & 0x00FFFFFF);
+ else
+ throwf("no pc-rel bx arm instruction. Can't fix up branch to %s in %s",
+ referenceTargetAtomName(state, fit), atom->name());
+ }
+ else if ( !is_bl && !is_blx && thumbTarget ) {
+ throwf("don't know how to convert instruction %x referencing %s to thumb",
+ instruction, referenceTargetAtomName(state, fit));
+ }
+ else {
+ newInstruction = (instruction & 0xFF000000) | ((uint32_t)(delta >> 2) & 0x00FFFFFF);
+ }
+ set32LE(fixUpLocation, newInstruction);
+ break;
+ case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+ accumulator = addressOf(state, fit, &toTarget);
+ thumbTarget = targetIsThumb(state, fit);
+ if ( thumbTarget )
+ accumulator |= 1;
+ if ( fit->contentDetlaToAddendOnly )
+ accumulator = 0;
+ // fall into kindStoreThumbBranch22 case
+ case ld::Fixup::kindStoreThumbBranch22:
+ instruction = get32LE(fixUpLocation);
+ is_bl = ((instruction & 0xD000F800) == 0xD000F000);
+ is_blx = ((instruction & 0xD000F800) == 0xC000F000);
+ is_b = ((instruction & 0xD000F800) == 0x9000F000);
+ // If the target is not thumb, we will be generating a blx instruction
+ // Since blx cannot have the low bit set, set bit[1] of the target to
+ // bit[1] of the base address, so that the difference is a multiple of
+ // 4 bytes.
+ if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) {
+ accumulator &= -3ULL;
+ accumulator |= ((atom->finalAddress() + fit->offsetInAtom ) & 2LL);
+ }
+ // The pc added will be +4 from the pc
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+ rangeCheckThumbBranch22(delta, state, atom, fit);
+ if ( _options.preferSubArchitecture() && _options.archSupportsThumb2() ) {
+ // The instruction is really two instructions:
+ // The lower 16 bits are the first instruction, which contains the high
+ // 11 bits of the displacement.
+ // The upper 16 bits are the second instruction, which contains the low
+ // 11 bits of the displacement, as well as differentiating bl and blx.
+ uint32_t s = (uint32_t)(delta >> 24) & 0x1;
+ uint32_t i1 = (uint32_t)(delta >> 23) & 0x1;
+ uint32_t i2 = (uint32_t)(delta >> 22) & 0x1;
+ uint32_t imm10 = (uint32_t)(delta >> 12) & 0x3FF;
+ uint32_t imm11 = (uint32_t)(delta >> 1) & 0x7FF;
+ uint32_t j1 = (i1 == s);
+ uint32_t j2 = (i2 == s);
+ if ( is_bl ) {
+ if ( thumbTarget )
+ instruction = 0xD000F000; // keep bl
+ else
+ instruction = 0xC000F000; // change to blx
+ }
+ else if ( is_blx ) {
+ if ( thumbTarget )
+ instruction = 0xD000F000; // change to bl
+ else
+ instruction = 0xC000F000; // keep blx
+ }
+ else if ( is_b ) {
+ instruction = 0x9000F000; // keep b
+ if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) {
+ throwf("armv7 has no pc-rel bx thumb instruction. Can't fix up branch to %s in %s",
+ referenceTargetAtomName(state, fit), atom->name());
+ }
+ }
+ else {
+ if ( !thumbTarget )
+ throwf("don't know how to convert branch instruction %x referencing %s to bx",
+ instruction, referenceTargetAtomName(state, fit));
+ instruction = 0x9000F000; // keep b
+ }
+ uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
+ uint32_t firstDisp = (s << 10) | imm10;
+ newInstruction = instruction | (nextDisp << 16) | firstDisp;
+ //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
+ // s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, delta, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
+ set32LE(fixUpLocation, newInstruction);
+ }
+ else {
+ // The instruction is really two instructions:
+ // The lower 16 bits are the first instruction, which contains the high
+ // 11 bits of the displacement.
+ // The upper 16 bits are the second instruction, which contains the low
+ // 11 bits of the displacement, as well as differentiating bl and blx.
+ uint32_t firstDisp = (uint32_t)(delta >> 12) & 0x7FF;
+ uint32_t nextDisp = (uint32_t)(delta >> 1) & 0x7FF;
+ if ( is_bl && !thumbTarget ) {
+ instruction = 0xE800F000;
+ }
+ else if ( is_blx && thumbTarget ) {
+ instruction = 0xF800F000;
+ }
+ else if ( is_b ) {
+ instruction = 0x9000F000; // keep b
+ if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) {
+ throwf("armv6 has no pc-rel bx thumb instruction. Can't fix up branch to %s in %s",
+ referenceTargetAtomName(state, fit), atom->name());
+ }
+ }
+ else {
+ instruction = instruction & 0xF800F800;
+ }
+ newInstruction = instruction | (nextDisp << 16) | firstDisp;
+ set32LE(fixUpLocation, newInstruction);
+ }
+ break;
+ case ld::Fixup::kindStoreARMLow16:
+ {
+ uint32_t imm4 = (accumulator & 0x0000F000) >> 12;
+ uint32_t imm12 = accumulator & 0x00000FFF;
+ instruction = get32LE(fixUpLocation);
+ newInstruction = (instruction & 0xFFF0F000) | (imm4 << 16) | imm12;
+ set32LE(fixUpLocation, newInstruction);
+ }
+ break;
+ case ld::Fixup::kindStoreARMHigh16:
+ {
+ uint32_t imm4 = (accumulator & 0xF0000000) >> 28;
+ uint32_t imm12 = (accumulator & 0x0FFF0000) >> 16;
+ instruction = get32LE(fixUpLocation);
+ newInstruction = (instruction & 0xFFF0F000) | (imm4 << 16) | imm12;
+ set32LE(fixUpLocation, newInstruction);
+ }
+ break;
+ case ld::Fixup::kindStoreThumbLow16:
+ {
+ uint32_t imm4 = (accumulator & 0x0000F000) >> 12;
+ uint32_t i = (accumulator & 0x00000800) >> 11;
+ uint32_t imm3 = (accumulator & 0x00000700) >> 8;
+ uint32_t imm8 = accumulator & 0x000000FF;
+ instruction = get32LE(fixUpLocation);
+ newInstruction = (instruction & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
+ set32LE(fixUpLocation, newInstruction);
+ }
+ break;
+ case ld::Fixup::kindStoreThumbHigh16:
+ {
+ uint32_t imm4 = (accumulator & 0xF0000000) >> 28;
+ uint32_t i = (accumulator & 0x08000000) >> 27;
+ uint32_t imm3 = (accumulator & 0x07000000) >> 24;
+ uint32_t imm8 = (accumulator & 0x00FF0000) >> 16;
+ instruction = get32LE(fixUpLocation);
+ newInstruction = (instruction & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
+ set32LE(fixUpLocation, newInstruction);
+ }
+ break;
+ }
+ }
+}
+
+void OutputFile::copyNoOps(uint8_t* from, uint8_t* to, bool thumb)
+{
+ switch ( _options.architecture() ) {
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64:
+ for (uint8_t* p=from; p < to; ++p)
+ *p = 0x90;
+ break;
+ case CPU_TYPE_ARM:
+ if ( thumb ) {
+ for (uint8_t* p=from; p < to; p += 2)
+ OSWriteLittleInt16((uint16_t*)p, 0, 0x46c0);
+ }
+ else {
+ for (uint8_t* p=from; p < to; p += 4)
+ OSWriteLittleInt32((uint32_t*)p, 0, 0xe1a00000);
+ }
+ break;
+ default:
+ for (uint8_t* p=from; p < to; ++p)
+ *p = 0x00;
+ break;
+ }
+}
+
+bool OutputFile::takesNoDiskSpace(const ld::Section* sect)
+{
+ switch ( sect->type() ) {
+ case ld::Section::typeZeroFill:
+ case ld::Section::typeTLVZeroFill:
+ return _options.optimizeZeroFill();
+ case ld::Section::typePageZero:
+ case ld::Section::typeStack:
+ case ld::Section::typeAbsoluteSymbols:
+ case ld::Section::typeTentativeDefs:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool OutputFile::hasZeroForFileOffset(const ld::Section* sect)
+{
+ switch ( sect->type() ) {
+ case ld::Section::typeZeroFill:
+ case ld::Section::typeTLVZeroFill:
+ return _options.optimizeZeroFill();
+ case ld::Section::typePageZero:
+ case ld::Section::typeStack:
+ case ld::Section::typeTentativeDefs:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+void OutputFile::writeAtoms(ld::Internal& state, uint8_t* wholeBuffer)
+{
+ // have each atom write itself
+ uint64_t fileOffsetOfEndOfLastAtom = 0;
+ uint64_t mhAddress = 0;
+ bool lastAtomUsesNoOps = false;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() == ld::Section::typeMachHeader )
+ mhAddress = sect->address;
+ if ( takesNoDiskSpace(sect) )
+ continue;
+ const bool sectionUsesNops = (sect->type() == ld::Section::typeCode);
+ //fprintf(stderr, "file offset=0x%08llX, section %s\n", sect->fileOffset, sect->sectionName());
+ std::vector<const ld::Atom*>& atoms = sect->atoms;
+ bool lastAtomWasThumb = false;
+ for (std::vector<const ld::Atom*>::iterator ait = atoms.begin(); ait != atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ if ( atom->definition() == ld::Atom::definitionProxy )
+ continue;
+ try {
+ uint64_t fileOffset = atom->finalAddress() - sect->address + sect->fileOffset;
+ // check for alignment padding between atoms
+ if ( (fileOffset != fileOffsetOfEndOfLastAtom) && lastAtomUsesNoOps ) {
+ this->copyNoOps(&wholeBuffer[fileOffsetOfEndOfLastAtom], &wholeBuffer[fileOffset], lastAtomWasThumb);
+ }
+ // copy atom content
+ atom->copyRawContent(&wholeBuffer[fileOffset]);
+ // apply fix ups
+ this->applyFixUps(state, mhAddress, atom, &wholeBuffer[fileOffset]);
+ fileOffsetOfEndOfLastAtom = fileOffset+atom->size();
+ lastAtomUsesNoOps = sectionUsesNops;
+ lastAtomWasThumb = atom->isThumb();
+ }
+ catch (const char* msg) {
+ if ( atom->file() != NULL )
+ throwf("%s in %s from %s", msg, atom->name(), atom->file()->path());
+ else
+ throwf("%s in %s", msg, atom->name());
+ }
+ }
+ }
+}
+
+
+void OutputFile::computeContentUUID(ld::Internal& state, uint8_t* wholeBuffer)
+{
+ const bool log = false;
+ if ( (_options.outputKind() != Options::kObjectFile) || state.someObjectFileHasDwarf ) {
+ uint8_t digest[CC_MD5_DIGEST_LENGTH];
+ uint32_t stabsStringsOffsetStart;
+ uint32_t tabsStringsOffsetEnd;
+ uint32_t stabsOffsetStart;
+ uint32_t stabsOffsetEnd;
+ if ( _symbolTableAtom->hasStabs(stabsStringsOffsetStart, tabsStringsOffsetEnd, stabsOffsetStart, stabsOffsetEnd) ) {
+ // find two areas of file that are stabs info and should not contribute to checksum
+ uint64_t stringPoolFileOffset = 0;
+ uint64_t symbolTableFileOffset = 0;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() == ld::Section::typeLinkEdit ) {
+ if ( strcmp(sect->sectionName(), "__string_pool") == 0 )
+ stringPoolFileOffset = sect->fileOffset;
+ else if ( strcmp(sect->sectionName(), "__symbol_table") == 0 )
+ symbolTableFileOffset = sect->fileOffset;
+ }
+ }
+ uint64_t firstStabNlistFileOffset = symbolTableFileOffset + stabsOffsetStart;
+ uint64_t lastStabNlistFileOffset = symbolTableFileOffset + stabsOffsetEnd;
+ uint64_t firstStabStringFileOffset = stringPoolFileOffset + stabsStringsOffsetStart;
+ uint64_t lastStabStringFileOffset = stringPoolFileOffset + tabsStringsOffsetEnd;
+ if ( log ) fprintf(stderr, "firstStabNlistFileOffset=0x%08llX\n", firstStabNlistFileOffset);
+ if ( log ) fprintf(stderr, "lastStabNlistFileOffset=0x%08llX\n", lastStabNlistFileOffset);
+ if ( log ) fprintf(stderr, "firstStabStringFileOffset=0x%08llX\n", firstStabStringFileOffset);
+ if ( log ) fprintf(stderr, "lastStabStringFileOffset=0x%08llX\n", lastStabStringFileOffset);
+ assert(firstStabNlistFileOffset <= firstStabStringFileOffset);
+
+ CC_MD5_CTX md5state;
+ CC_MD5_Init(&md5state);
+ // checksum everything up to first stabs nlist
+ if ( log ) fprintf(stderr, "checksum 0x%08X -> 0x%08llX\n", 0, firstStabNlistFileOffset);
+ CC_MD5_Update(&md5state, &wholeBuffer[0], firstStabNlistFileOffset);
+ // checkusm everything after last stabs nlist and up to first stabs string
+ if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabNlistFileOffset, firstStabStringFileOffset);
+ CC_MD5_Update(&md5state, &wholeBuffer[lastStabNlistFileOffset], firstStabStringFileOffset-lastStabNlistFileOffset);
+ // checksum everything after last stabs string to end of file
+ if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabStringFileOffset, _fileSize);
+ CC_MD5_Update(&md5state, &wholeBuffer[lastStabStringFileOffset], _fileSize-lastStabStringFileOffset);
+ CC_MD5_Final(digest, &md5state);
+ if ( log ) fprintf(stderr, "uuid=%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", digest[0], digest[1], digest[2],
+ digest[3], digest[4], digest[5], digest[6], digest[7]);
+ }
+ else {
+ CC_MD5(wholeBuffer, _fileSize, digest);
+ }
+ // <rdar://problem/6723729> LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
+ digest[6] = ( digest[6] & 0x0F ) | ( 3 << 4 );
+ digest[8] = ( digest[8] & 0x3F ) | 0x80;
+ // update buffer with new UUID
+ _headersAndLoadCommandAtom->setUUID(digest);
+ _headersAndLoadCommandAtom->recopyUUIDCommand();
+ }
+}
+
+
+void OutputFile::writeOutputFile(ld::Internal& state)
+{
+ // for UNIX conformance, error if file exists and is not writable
+ if ( (access(_options.outputFilePath(), F_OK) == 0) && (access(_options.outputFilePath(), W_OK) == -1) )
+ throwf("can't write output file: %s", _options.outputFilePath());
+
+ mode_t permissions = 0777;
+ if ( _options.outputKind() == Options::kObjectFile )
+ permissions = 0666;
+ mode_t umask = ::umask(0);
+ ::umask(umask); // put back the original umask
+ permissions &= ~umask;
+ // Calling unlink first assures the file is gone so that open creates it with correct permissions
+ // It also handles the case where __options.outputFilePath() 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)
+ // Lastly, only delete existing file if it is a normal file (e.g. not /dev/null).
+ struct stat stat_buf;
+ bool outputIsRegularFile = true;
+ if ( stat(_options.outputFilePath(), &stat_buf) != -1 ) {
+ if (stat_buf.st_mode & S_IFREG) {
+ (void)unlink(_options.outputFilePath());
+ } else {
+ outputIsRegularFile = false;
+ }
+ }
+
+ int fd;
+ // Construct a temporary path of the form {outputFilePath}.ld_XXXXXX
+ const char filenameTemplate[] = ".ld_XXXXXX";
+ char tmpOutput[PATH_MAX];
+ uint8_t *wholeBuffer;
+ if (outputIsRegularFile) {
+ strcpy(tmpOutput, _options.outputFilePath());
+ // If the path is too long to add a suffix for a temporary name then
+ // just fall back to using the output path.
+ if (strlen(tmpOutput)+strlen(filenameTemplate) < PATH_MAX) {
+ strcat(tmpOutput, filenameTemplate);
+ fd = mkstemp(tmpOutput);
+ } else {
+ fd = open(tmpOutput, O_RDWR|O_CREAT, permissions);
+ }
+ if ( fd == -1 )
+ throwf("can't open output file for writing: %s, errno=%d", tmpOutput, errno);
+ ftruncate(fd, _fileSize);
+
+ wholeBuffer = (uint8_t *)mmap(NULL, _fileSize, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
+ if ( wholeBuffer == MAP_FAILED )
+ throwf("can't create buffer of %llu bytes for output", _fileSize);
+ } else {
+ fd = open(_options.outputFilePath(), O_WRONLY);
+ if ( fd == -1 )
+ throwf("can't open output file for writing: %s, errno=%d", _options.outputFilePath(), errno);
+ // try to allocate buffer for entire output file content
+ wholeBuffer = (uint8_t*)calloc(_fileSize, 1);
+ if ( wholeBuffer == NULL )
+ throwf("can't create buffer of %llu bytes for output", _fileSize);
+ }
+
+ if ( _options.UUIDMode() == Options::kUUIDRandom ) {
+ uint8_t bits[16];
+ ::uuid_generate_random(bits);
+ _headersAndLoadCommandAtom->setUUID(bits);
+ }
+
+ writeAtoms(state, wholeBuffer);
+
+ // compute UUID
+ if ( _options.UUIDMode() == Options::kUUIDContent )
+ computeContentUUID(state, wholeBuffer);
+
+ if (outputIsRegularFile) {
+ if ( ::chmod(tmpOutput, permissions) == -1 ) {
+ unlink(tmpOutput);
+ throwf("can't set permissions on output file: %s, errno=%d", tmpOutput, errno);
+ }
+ if ( ::rename(tmpOutput, _options.outputFilePath()) == -1 && strcmp(tmpOutput, _options.outputFilePath()) != 0) {
+ unlink(tmpOutput);
+ throwf("can't move output file in place, errno=%d", errno);
+ }
+ } else {
+ if ( ::write(fd, wholeBuffer, _fileSize) == -1 ) {
+ throwf("can't write to output file: %s, errno=%d", _options.outputFilePath(), errno);
+ }
+ }
+}
+
+struct AtomByNameSorter
+{
+ bool operator()(const ld::Atom* left, const ld::Atom* right)
+ {
+ return (strcmp(left->name(), right->name()) < 0);
+ }
+};
+
+class NotInSet
+{
+public:
+ NotInSet(const std::set<const ld::Atom*>& theSet) : _set(theSet) {}
+
+ bool operator()(const ld::Atom* atom) const {
+ return ( _set.count(atom) == 0 );
+ }
+private:
+ const std::set<const ld::Atom*>& _set;
+};
+
+
+void OutputFile::buildSymbolTable(ld::Internal& state)
+{
+ unsigned int machoSectionIndex = 0;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ bool setMachoSectionIndex = !sect->isSectionHidden() && (sect->type() != ld::Section::typeTentativeDefs);
+ if ( setMachoSectionIndex )
+ ++machoSectionIndex;
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ if ( setMachoSectionIndex )
+ (const_cast<ld::Atom*>(atom))->setMachoSection(machoSectionIndex);
+ else if ( sect->type() == ld::Section::typeMachHeader )
+ (const_cast<ld::Atom*>(atom))->setMachoSection(1); // __mh_execute_header is not in any section by needs n_sect==1
+ else if ( sect->type() == ld::Section::typeLastSection )
+ (const_cast<ld::Atom*>(atom))->setMachoSection(machoSectionIndex); // use section index of previous section
+ else if ( sect->type() == ld::Section::typeFirstSection )
+ (const_cast<ld::Atom*>(atom))->setMachoSection(machoSectionIndex+1); // use section index of next section
+
+ // in -r mode, clarify symbolTableNotInFinalLinkedImages
+ if ( _options.outputKind() == Options::kObjectFile ) {
+ if ( _options.architecture() == CPU_TYPE_X86_64 ) {
+ // x86_64 .o files need labels on anonymous literal strings
+ if ( (sect->type() == ld::Section::typeCString) && (atom->combine() == ld::Atom::combineByNameAndContent) ) {
+ (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
+ _localAtoms.push_back(atom);
+ continue;
+ }
+ }
+ if ( sect->type() == ld::Section::typeCFI ) {
+ if ( _options.removeEHLabels() )
+ (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableNotIn);
+ else
+ (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
+ }
+ if ( atom->symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages )
+ (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
+ }
+
+ // TEMP work around until <rdar://problem/7702923> goes in
+ if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)
+ && (atom->scope() == ld::Atom::scopeLinkageUnit)
+ && (_options.outputKind() == Options::kDynamicLibrary) ) {
+ (const_cast<ld::Atom*>(atom))->setScope(ld::Atom::scopeGlobal);
+ }
+
+ // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
+ if ( atom->autoHide() && (_options.outputKind() != Options::kObjectFile) ) {
+ // adding auto-hide symbol to .exp file should keep it global
+ if ( !_options.hasExportMaskList() || !_options.shouldExport(atom->name()) )
+ (const_cast<ld::Atom*>(atom))->setScope(ld::Atom::scopeLinkageUnit);
+ }
+
+ // <rdar://problem/8626058> ld should consistently warn when resolvers are not exported
+ if ( (atom->contentType() == ld::Atom::typeResolver) && (atom->scope() == ld::Atom::scopeLinkageUnit) )
+ warning("resolver functions should be external, but '%s' is hidden", atom->name());
+
+ if ( sect->type() == ld::Section::typeImportProxies ) {
+ if ( atom->combine() == ld::Atom::combineByName )
+ this->usesWeakExternalSymbols = true;
+ // alias proxy is a re-export with a name change, don't import changed name
+ if ( ! atom->isAlias() )
+ _importedAtoms.push_back(atom);
+ // scope of proxies are usually linkage unit, so done
+ // if scope is global, we need to re-export it too
+ if ( atom->scope() == ld::Atom::scopeGlobal )
+ _exportedAtoms.push_back(atom);
+ continue;
+ }
+ if ( atom->symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages ) {
+ assert(_options.outputKind() != Options::kObjectFile);
+ continue; // don't add to symbol table
+ }
+ if ( atom->symbolTableInclusion() == ld::Atom::symbolTableNotIn ) {
+ continue; // don't add to symbol table
+ }
+
+ if ( (atom->definition() == ld::Atom::definitionTentative) && (_options.outputKind() == Options::kObjectFile) ) {
+ if ( _options.makeTentativeDefinitionsReal() ) {
+ // -r -d turns tentative defintions into real def
+ _exportedAtoms.push_back(atom);
+ }
+ else {
+ // in mach-o object files tentative defintions are stored like undefined symbols
+ _importedAtoms.push_back(atom);
+ }
+ continue;
+ }
+
+ switch ( atom->scope() ) {
+ case ld::Atom::scopeTranslationUnit:
+ if ( _options.keepLocalSymbol(atom->name()) ) {
+ _localAtoms.push_back(atom);
+ }
+ else {
+ if ( _options.outputKind() == Options::kObjectFile ) {
+ (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableInWithRandomAutoStripLabel);
+ _localAtoms.push_back(atom);
+ }
+ else
+ (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableNotIn);
+ }
+ break;
+ case ld::Atom::scopeGlobal:
+ _exportedAtoms.push_back(atom);
+ break;
+ case ld::Atom::scopeLinkageUnit:
+ if ( _options.outputKind() == Options::kObjectFile ) {
+ if ( _options.keepPrivateExterns() ) {
+ assert( (atom->combine() == ld::Atom::combineNever) || (atom->combine() == ld::Atom::combineByName) );
+ _exportedAtoms.push_back(atom);
+ }
+ else if ( _options.keepLocalSymbol(atom->name()) ) {
+ _localAtoms.push_back(atom);
+ }
+ else {
+ (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableInWithRandomAutoStripLabel);
+ _localAtoms.push_back(atom);
+ }
+ }
+ else {
+ if ( _options.keepLocalSymbol(atom->name()) )
+ _localAtoms.push_back(atom);
+ // <rdar://problem/5804214> ld should never have a symbol in the non-lazy indirect symbol table with index 0
+ // this works by making __mh_execute_header be a local symbol which takes symbol index 0
+ else if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip) && !_options.makeCompressedDyldInfo() )
+ _localAtoms.push_back(atom);
+ else
+ (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableNotIn);
+ }
+ break;
+ }
+ }
+ }
+
+ // <rdar://problem/6978069> ld adds undefined symbol from .exp file to binary
+ if ( (_options.outputKind() == Options::kKextBundle) && _options.hasExportRestrictList() ) {
+ // search for referenced undefines
+ std::set<const ld::Atom*> referencedProxyAtoms;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingsIndirectlyBound:
+ referencedProxyAtoms.insert(state.indirectBindingTable[fit->u.bindingIndex]);
+ break;
+ case ld::Fixup::bindingDirectlyBound:
+ referencedProxyAtoms.insert(fit->u.target);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ // remove any unreferenced _importedAtoms
+ _importedAtoms.erase(std::remove_if(_importedAtoms.begin(), _importedAtoms.end(), NotInSet(referencedProxyAtoms)), _importedAtoms.end());
+ }
+
+ // sort by name
+ std::sort(_exportedAtoms.begin(), _exportedAtoms.end(), AtomByNameSorter());
+ std::sort(_importedAtoms.begin(), _importedAtoms.end(), AtomByNameSorter());
+}
+
+void OutputFile::addPreloadLinkEdit(ld::Internal& state)
+{
+ switch ( _options.architecture() ) {
+#if SUPPORT_ARCH_i386
+ case CPU_TYPE_I386:
+ if ( _hasLocalRelocations ) {
+ _localRelocsAtom = new LocalRelocationsAtom<x86>(_options, state, *this);
+ localRelocationsSection = state.addAtom(*_localRelocsAtom);
+ }
+ if ( _hasExternalRelocations ) {
+ _externalRelocsAtom = new ExternalRelocationsAtom<x86>(_options, state, *this);
+ externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+ }
+ if ( _hasSymbolTable ) {
+ _indirectSymbolTableAtom = new IndirectSymbolTableAtom<x86>(_options, state, *this);
+ indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+ _symbolTableAtom = new SymbolTableAtom<x86>(_options, state, *this);
+ symbolTableSection = state.addAtom(*_symbolTableAtom);
+ _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+ stringPoolSection = state.addAtom(*_stringPoolAtom);
+ }
+ break;
+#endif
+#if SUPPORT_ARCH_x86_64
+ case CPU_TYPE_X86_64:
+ if ( _hasLocalRelocations ) {
+ _localRelocsAtom = new LocalRelocationsAtom<x86_64>(_options, state, *this);
+ localRelocationsSection = state.addAtom(*_localRelocsAtom);
+ }
+ if ( _hasExternalRelocations ) {
+ _externalRelocsAtom = new ExternalRelocationsAtom<x86_64>(_options, state, *this);
+ externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+ }
+ if ( _hasSymbolTable ) {
+ _indirectSymbolTableAtom = new IndirectSymbolTableAtom<x86_64>(_options, state, *this);
+ indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+ _symbolTableAtom = new SymbolTableAtom<x86_64>(_options, state, *this);
+ symbolTableSection = state.addAtom(*_symbolTableAtom);
+ _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+ stringPoolSection = state.addAtom(*_stringPoolAtom);
+ }
+ break;
+#endif
+#if SUPPORT_ARCH_arm_any
+ case CPU_TYPE_ARM:
+ if ( _hasLocalRelocations ) {
+ _localRelocsAtom = new LocalRelocationsAtom<arm>(_options, state, *this);
+ localRelocationsSection = state.addAtom(*_localRelocsAtom);
+ }
+ if ( _hasExternalRelocations ) {
+ _externalRelocsAtom = new ExternalRelocationsAtom<arm>(_options, state, *this);
+ externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+ }
+ if ( _hasSymbolTable ) {
+ _indirectSymbolTableAtom = new IndirectSymbolTableAtom<arm>(_options, state, *this);
+ indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+ _symbolTableAtom = new SymbolTableAtom<arm>(_options, state, *this);
+ symbolTableSection = state.addAtom(*_symbolTableAtom);
+ _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+ stringPoolSection = state.addAtom(*_stringPoolAtom);
+ }
+ break;
+#endif
+ default:
+ throw "architecture not supported for -preload";
+ }
+
+}
+
+
+void OutputFile::addLinkEdit(ld::Internal& state)
+{
+ // for historical reasons, -preload orders LINKEDIT content differently
+ if ( _options.outputKind() == Options::kPreload )
+ return addPreloadLinkEdit(state);
+
+ switch ( _options.architecture() ) {
+#if SUPPORT_ARCH_i386
+ case CPU_TYPE_I386:
+ if ( _hasSectionRelocations ) {
+ _sectionsRelocationsAtom = new SectionRelocationsAtom<x86>(_options, state, *this);
+ sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
+ }
+ if ( _hasDyldInfo ) {
+ _rebasingInfoAtom = new RebaseInfoAtom<x86>(_options, state, *this);
+ rebaseSection = state.addAtom(*_rebasingInfoAtom);
+
+ _bindingInfoAtom = new BindingInfoAtom<x86>(_options, state, *this);
+ bindingSection = state.addAtom(*_bindingInfoAtom);
+
+ _weakBindingInfoAtom = new WeakBindingInfoAtom<x86>(_options, state, *this);
+ weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
+
+ _lazyBindingInfoAtom = new LazyBindingInfoAtom<x86>(_options, state, *this);
+ lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
+
+ _exportInfoAtom = new ExportInfoAtom<x86>(_options, state, *this);
+ exportSection = state.addAtom(*_exportInfoAtom);
+ }
+ if ( _hasLocalRelocations ) {
+ _localRelocsAtom = new LocalRelocationsAtom<x86>(_options, state, *this);
+ localRelocationsSection = state.addAtom(*_localRelocsAtom);
+ }
+ if ( _hasSplitSegInfo ) {
+ _splitSegInfoAtom = new SplitSegInfoAtom<x86>(_options, state, *this);
+ splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
+ }
+ if ( _hasFunctionStartsInfo ) {
+ _functionStartsAtom = new FunctionStartsAtom<x86>(_options, state, *this);
+ functionStartsSection = state.addAtom(*_functionStartsAtom);
+ }
+ if ( _hasDataInCodeInfo ) {
+ _dataInCodeAtom = new DataInCodeAtom<x86>(_options, state, *this);
+ dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+ }
+ if ( _hasDependentDRInfo ) {
+ _dependentDRInfoAtom = new DependentDRAtom<x86>(_options, state, *this);
+ dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
+ }
+ if ( _hasSymbolTable ) {
+ _symbolTableAtom = new SymbolTableAtom<x86>(_options, state, *this);
+ symbolTableSection = state.addAtom(*_symbolTableAtom);
+ }
+ if ( _hasExternalRelocations ) {
+ _externalRelocsAtom = new ExternalRelocationsAtom<x86>(_options, state, *this);
+ externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+ }
+ if ( _hasSymbolTable ) {
+ _indirectSymbolTableAtom = new IndirectSymbolTableAtom<x86>(_options, state, *this);
+ indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+ _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+ stringPoolSection = state.addAtom(*_stringPoolAtom);
+ }
+ break;
+#endif
+#if SUPPORT_ARCH_x86_64
+ case CPU_TYPE_X86_64:
+ if ( _hasSectionRelocations ) {
+ _sectionsRelocationsAtom = new SectionRelocationsAtom<x86_64>(_options, state, *this);
+ sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
+ }
+ if ( _hasDyldInfo ) {
+ _rebasingInfoAtom = new RebaseInfoAtom<x86_64>(_options, state, *this);
+ rebaseSection = state.addAtom(*_rebasingInfoAtom);
+
+ _bindingInfoAtom = new BindingInfoAtom<x86_64>(_options, state, *this);
+ bindingSection = state.addAtom(*_bindingInfoAtom);
+
+ _weakBindingInfoAtom = new WeakBindingInfoAtom<x86_64>(_options, state, *this);
+ weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
+
+ _lazyBindingInfoAtom = new LazyBindingInfoAtom<x86_64>(_options, state, *this);
+ lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
+
+ _exportInfoAtom = new ExportInfoAtom<x86_64>(_options, state, *this);
+ exportSection = state.addAtom(*_exportInfoAtom);
+ }
+ if ( _hasLocalRelocations ) {
+ _localRelocsAtom = new LocalRelocationsAtom<x86_64>(_options, state, *this);
+ localRelocationsSection = state.addAtom(*_localRelocsAtom);
+ }
+ if ( _hasSplitSegInfo ) {
+ _splitSegInfoAtom = new SplitSegInfoAtom<x86_64>(_options, state, *this);
+ splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
+ }
+ if ( _hasFunctionStartsInfo ) {
+ _functionStartsAtom = new FunctionStartsAtom<x86_64>(_options, state, *this);
+ functionStartsSection = state.addAtom(*_functionStartsAtom);
+ }
+ if ( _hasDataInCodeInfo ) {
+ _dataInCodeAtom = new DataInCodeAtom<x86_64>(_options, state, *this);
+ dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+ }
+ if ( _hasDependentDRInfo ) {
+ _dependentDRInfoAtom = new DependentDRAtom<x86_64>(_options, state, *this);
+ dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
+ }
+ if ( _hasSymbolTable ) {
+ _symbolTableAtom = new SymbolTableAtom<x86_64>(_options, state, *this);
+ symbolTableSection = state.addAtom(*_symbolTableAtom);
+ }
+ if ( _hasExternalRelocations ) {
+ _externalRelocsAtom = new ExternalRelocationsAtom<x86_64>(_options, state, *this);
+ externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+ }
+ if ( _hasSymbolTable ) {
+ _indirectSymbolTableAtom = new IndirectSymbolTableAtom<x86_64>(_options, state, *this);
+ indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+ _stringPoolAtom = new StringPoolAtom(_options, state, *this, 8);
+ stringPoolSection = state.addAtom(*_stringPoolAtom);
+ }
+ break;
+#endif
+#if SUPPORT_ARCH_arm_any
+ case CPU_TYPE_ARM:
+ if ( _hasSectionRelocations ) {
+ _sectionsRelocationsAtom = new SectionRelocationsAtom<arm>(_options, state, *this);
+ sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
+ }
+ if ( _hasDyldInfo ) {
+ _rebasingInfoAtom = new RebaseInfoAtom<arm>(_options, state, *this);
+ rebaseSection = state.addAtom(*_rebasingInfoAtom);
+
+ _bindingInfoAtom = new BindingInfoAtom<arm>(_options, state, *this);
+ bindingSection = state.addAtom(*_bindingInfoAtom);
+
+ _weakBindingInfoAtom = new WeakBindingInfoAtom<arm>(_options, state, *this);
+ weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
+
+ _lazyBindingInfoAtom = new LazyBindingInfoAtom<arm>(_options, state, *this);
+ lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
+
+ _exportInfoAtom = new ExportInfoAtom<arm>(_options, state, *this);
+ exportSection = state.addAtom(*_exportInfoAtom);
+ }
+ if ( _hasLocalRelocations ) {
+ _localRelocsAtom = new LocalRelocationsAtom<arm>(_options, state, *this);
+ localRelocationsSection = state.addAtom(*_localRelocsAtom);
+ }
+ if ( _hasSplitSegInfo ) {
+ _splitSegInfoAtom = new SplitSegInfoAtom<arm>(_options, state, *this);
+ splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
+ }
+ if ( _hasFunctionStartsInfo ) {
+ _functionStartsAtom = new FunctionStartsAtom<arm>(_options, state, *this);
+ functionStartsSection = state.addAtom(*_functionStartsAtom);
+ }
+ if ( _hasDataInCodeInfo ) {
+ _dataInCodeAtom = new DataInCodeAtom<arm>(_options, state, *this);
+ dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+ }
+ if ( _hasDependentDRInfo ) {
+ _dependentDRInfoAtom = new DependentDRAtom<arm>(_options, state, *this);
+ dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
+ }
+ if ( _hasSymbolTable ) {
+ _symbolTableAtom = new SymbolTableAtom<arm>(_options, state, *this);
+ symbolTableSection = state.addAtom(*_symbolTableAtom);
+ }
+ if ( _hasExternalRelocations ) {
+ _externalRelocsAtom = new ExternalRelocationsAtom<arm>(_options, state, *this);
+ externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+ }
+ if ( _hasSymbolTable ) {
+ _indirectSymbolTableAtom = new IndirectSymbolTableAtom<arm>(_options, state, *this);
+ indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+ _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+ stringPoolSection = state.addAtom(*_stringPoolAtom);
+ }
+ break;
+#endif
+ default:
+ throw "unknown architecture";
+ }
+}
+
+void OutputFile::addLoadCommands(ld::Internal& state)
+{
+ switch ( _options.architecture() ) {
+#if SUPPORT_ARCH_x86_64
+ case CPU_TYPE_X86_64:
+ _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86_64>(_options, state, *this);
+ headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
+ break;
+#endif
+#if SUPPORT_ARCH_arm_any
+ case CPU_TYPE_ARM:
+ _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<arm>(_options, state, *this);
+ headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
+ break;
+#endif
+#if SUPPORT_ARCH_i386
+ case CPU_TYPE_I386:
+ _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86>(_options, state, *this);
+ headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
+ break;
+#endif
+ default:
+ throw "unknown architecture";
+ }
+}
+
+uint32_t OutputFile::dylibCount()
+{
+ return _dylibsToLoad.size();
+}
+
+const ld::dylib::File* OutputFile::dylibByOrdinal(unsigned int ordinal)
+{
+ assert( ordinal > 0 );
+ assert( ordinal <= _dylibsToLoad.size() );
+ return _dylibsToLoad[ordinal-1];
+}
+
+bool OutputFile::hasOrdinalForInstallPath(const char* path, int* ordinal)
+{
+ for (std::map<const ld::dylib::File*, int>::const_iterator it = _dylibToOrdinal.begin(); it != _dylibToOrdinal.end(); ++it) {
+ const char* installPath = it->first->installPath();
+ if ( (installPath != NULL) && (strcmp(path, installPath) == 0) ) {
+ *ordinal = it->second;
+ return true;
+ }
+ }
+ return false;
+}
+
+uint32_t OutputFile::dylibToOrdinal(const ld::dylib::File* dylib)
+{
+ return _dylibToOrdinal[dylib];
+}
+
+
+void OutputFile::buildDylibOrdinalMapping(ld::Internal& state)
+{
+ // count non-public re-exported dylibs
+ unsigned int nonPublicReExportCount = 0;
+ for (std::vector<ld::dylib::File*>::iterator it = state.dylibs.begin(); it != state.dylibs.end(); ++it) {
+ ld::dylib::File* aDylib = *it;
+ if ( aDylib->willBeReExported() && ! aDylib->hasPublicInstallName() )
+ ++nonPublicReExportCount;
+ }
+
+ // look at each dylib supplied in state
+ bool hasReExports = false;
+ bool haveLazyDylibs = false;
+ for (std::vector<ld::dylib::File*>::iterator it = state.dylibs.begin(); it != state.dylibs.end(); ++it) {
+ ld::dylib::File* aDylib = *it;
+ int ordinal;
+ if ( aDylib == state.bundleLoader ) {
+ _dylibToOrdinal[aDylib] = BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE;
+ }
+ else if ( this->hasOrdinalForInstallPath(aDylib->installPath(), &ordinal) ) {
+ // already have a dylib with that install path, map all uses to that ordinal
+ _dylibToOrdinal[aDylib] = ordinal;
+ }
+ else if ( aDylib->willBeLazyLoadedDylib() ) {
+ // all lazy dylib need to be at end of ordinals
+ haveLazyDylibs = true;
+ }
+ else if ( aDylib->willBeReExported() && ! aDylib->hasPublicInstallName() && (nonPublicReExportCount >= 2) ) {
+ _dylibsToLoad.push_back(aDylib);
+ _dylibToOrdinal[aDylib] = BIND_SPECIAL_DYLIB_SELF;
+ }
+ else {
+ // first time this install path seen, create new ordinal
+ _dylibsToLoad.push_back(aDylib);
+ _dylibToOrdinal[aDylib] = _dylibsToLoad.size();
+ }
+ if ( aDylib->explicitlyLinked() && aDylib->willBeReExported() )
+ hasReExports = true;
+ }
+ if ( haveLazyDylibs ) {
+ // second pass to determine ordinals for lazy loaded dylibs
+ for (std::vector<ld::dylib::File*>::iterator it = state.dylibs.begin(); it != state.dylibs.end(); ++it) {
+ ld::dylib::File* aDylib = *it;
+ if ( aDylib->willBeLazyLoadedDylib() ) {
+ int ordinal;
+ if ( this->hasOrdinalForInstallPath(aDylib->installPath(), &ordinal) ) {
+ // already have a dylib with that install path, map all uses to that ordinal
+ _dylibToOrdinal[aDylib] = ordinal;
+ }
+ else {
+ // first time this install path seen, create new ordinal
+ _dylibsToLoad.push_back(aDylib);
+ _dylibToOrdinal[aDylib] = _dylibsToLoad.size();
+ }
+ }
+ }
+ }
+ _noReExportedDylibs = !hasReExports;
+ //fprintf(stderr, "dylibs:\n");
+ //for (std::map<const ld::dylib::File*, int>::const_iterator it = _dylibToOrdinal.begin(); it != _dylibToOrdinal.end(); ++it) {
+ // fprintf(stderr, " %p ord=%u, install_name=%s\n",it->first, it->second, it->first->installPath());
+ //}
+}
+
+uint32_t OutputFile::lazyBindingInfoOffsetForLazyPointerAddress(uint64_t lpAddress)
+{
+ return _lazyPointerAddressToInfoOffset[lpAddress];
+}
+
+void OutputFile::setLazyBindingInfoOffset(uint64_t lpAddress, uint32_t lpInfoOffset)
+{
+ _lazyPointerAddressToInfoOffset[lpAddress] = lpInfoOffset;
+}
+
+int OutputFile::compressedOrdinalForAtom(const ld::Atom* target)
+{
+ // flat namespace images use zero for all ordinals
+ if ( _options.nameSpace() != Options::kTwoLevelNameSpace )
+ return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
+
+ // handle -interposable
+ if ( target->definition() == ld::Atom::definitionRegular )
+ return BIND_SPECIAL_DYLIB_SELF;
+
+ // regular ordinal
+ const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
+ if ( dylib != NULL )
+ return _dylibToOrdinal[dylib];
+
+ // handle undefined dynamic_lookup
+ if ( _options.undefinedTreatment() == Options::kUndefinedDynamicLookup )
+ return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
+
+ // handle -U _foo
+ if ( _options.allowedUndefined(target->name()) )
+ return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
+
+ throw "can't find ordinal for imported symbol";
+}
+
+
+bool OutputFile::isPcRelStore(ld::Fixup::Kind kind)
+{
+ switch ( kind ) {
+ case ld::Fixup::kindStoreX86BranchPCRel8:
+ case ld::Fixup::kindStoreX86BranchPCRel32:
+ case ld::Fixup::kindStoreX86PCRel8:
+ case ld::Fixup::kindStoreX86PCRel16:
+ case ld::Fixup::kindStoreX86PCRel32:
+ case ld::Fixup::kindStoreX86PCRel32_1:
+ case ld::Fixup::kindStoreX86PCRel32_2:
+ case ld::Fixup::kindStoreX86PCRel32_4:
+ case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+ case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
+ case ld::Fixup::kindStoreX86PCRel32GOT:
+ case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
+ case ld::Fixup::kindStoreARMBranch24:
+ case ld::Fixup::kindStoreThumbBranch22:
+ case ld::Fixup::kindStoreARMLoad12:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+ case ld::Fixup::kindStoreTargetAddressARMBranch24:
+ case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+ case ld::Fixup::kindStoreTargetAddressARMLoad12:
+ return true;
+ case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+ return (_options.outputKind() != Options::kKextBundle);
+ default:
+ break;
+ }
+ return false;
+}
+
+bool OutputFile::isStore(ld::Fixup::Kind kind)
+{
+ switch ( kind ) {
+ case ld::Fixup::kindNone:
+ case ld::Fixup::kindNoneFollowOn:
+ case ld::Fixup::kindNoneGroupSubordinate:
+ case ld::Fixup::kindNoneGroupSubordinateFDE:
+ case ld::Fixup::kindNoneGroupSubordinateLSDA:
+ case ld::Fixup::kindNoneGroupSubordinatePersonality:
+ case ld::Fixup::kindSetTargetAddress:
+ case ld::Fixup::kindSubtractTargetAddress:
+ case ld::Fixup::kindAddAddend:
+ case ld::Fixup::kindSubtractAddend:
+ case ld::Fixup::kindSetTargetImageOffset:
+ case ld::Fixup::kindSetTargetSectionOffset:
+ return false;
+ default:
+ break;
+ }
+ return true;
+}
+
+
+bool OutputFile::setsTarget(ld::Fixup::Kind kind)
+{
+ switch ( kind ) {
+ case ld::Fixup::kindSetTargetAddress:
+ case ld::Fixup::kindLazyTarget:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+ case ld::Fixup::kindStoreTargetAddressBigEndian32:
+ case ld::Fixup::kindStoreTargetAddressBigEndian64:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+ case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+ case ld::Fixup::kindStoreTargetAddressARMBranch24:
+ case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+ case ld::Fixup::kindStoreTargetAddressARMLoad12:
+ return true;
+ case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+ case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+ case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+ case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+ case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+ case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+ return (_options.outputKind() == Options::kObjectFile);
+ default:
+ break;
+ }
+ return false;
+}
+
+bool OutputFile::isPointerToTarget(ld::Fixup::Kind kind)
+{
+ switch ( kind ) {
+ case ld::Fixup::kindSetTargetAddress:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+ case ld::Fixup::kindStoreTargetAddressBigEndian32:
+ case ld::Fixup::kindStoreTargetAddressBigEndian64:
+ case ld::Fixup::kindLazyTarget:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+bool OutputFile::isPointerFromTarget(ld::Fixup::Kind kind)
+{
+ switch ( kind ) {
+ case ld::Fixup::kindSubtractTargetAddress:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+
+uint64_t OutputFile::lookBackAddend(ld::Fixup::iterator fit)
+{
+ uint64_t addend = 0;
+ switch ( fit->clusterSize ) {
+ case ld::Fixup::k1of1:
+ case ld::Fixup::k1of2:
+ case ld::Fixup::k2of2:
+ break;
+ case ld::Fixup::k2of3:
+ --fit;
+ switch ( fit->kind ) {
+ case ld::Fixup::kindAddAddend:
+ addend += fit->u.addend;
+ break;
+ case ld::Fixup::kindSubtractAddend:
+ addend -= fit->u.addend;
+ break;
+ default:
+ throw "unexpected fixup kind for binding";
+ }
+ break;
+ case ld::Fixup::k1of3:
+ ++fit;
+ switch ( fit->kind ) {
+ case ld::Fixup::kindAddAddend:
+ addend += fit->u.addend;
+ break;
+ case ld::Fixup::kindSubtractAddend:
+ addend -= fit->u.addend;
+ break;
+ default:
+ throw "unexpected fixup kind for binding";
+ }
+ break;
+ default:
+ throw "unexpected fixup cluster size for binding";
+ }
+ return addend;
+}
+
+
+
+
+
+void OutputFile::generateLinkEditInfo(ld::Internal& state)
+{
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ bool objc1ClassRefSection = ( (sect->type() == ld::Section::typeCStringPointer)
+ && (strcmp(sect->sectionName(), "__cls_refs") == 0)
+ && (strcmp(sect->segmentName(), "__OBJC") == 0) );
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+
+ // Record regular atoms that override a dylib's weak definitions
+ if ( (atom->scope() == ld::Atom::scopeGlobal) && atom->overridesDylibsWeakDef() ) {
+ if ( _options.makeCompressedDyldInfo() ) {
+ uint8_t wtype = BIND_TYPE_OVERRIDE_OF_WEAKDEF_IN_DYLIB;
+ bool nonWeakDef = (atom->combine() == ld::Atom::combineNever);
+ _weakBindingInfo.push_back(BindingInfo(wtype, atom->name(), nonWeakDef, atom->finalAddress(), 0));
+ }
+ this->overridesWeakExternalSymbols = true;
+ if ( _options.warnWeakExports() )
+ warning("overrides weak external symbol: %s", atom->name());
+ }
+
+ ld::Fixup* fixupWithTarget = NULL;
+ ld::Fixup* fixupWithMinusTarget = NULL;
+ ld::Fixup* fixupWithStore = NULL;
+ const ld::Atom* target = NULL;
+ const ld::Atom* minusTarget = NULL;
+ uint64_t targetAddend = 0;
+ uint64_t minusTargetAddend = 0;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ if ( fit->firstInCluster() ) {
+ fixupWithTarget = NULL;
+ fixupWithMinusTarget = NULL;
+ fixupWithStore = NULL;
+ target = NULL;
+ minusTarget = NULL;
+ targetAddend = 0;
+ minusTargetAddend = 0;
+ }
+ if ( this->setsTarget(fit->kind) ) {
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingNone:
+ case ld::Fixup::bindingByNameUnbound:
+ break;
+ case ld::Fixup::bindingByContentBound:
+ case ld::Fixup::bindingDirectlyBound:
+ fixupWithTarget = fit;
+ target = fit->u.target;
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ fixupWithTarget = fit;
+ target = state.indirectBindingTable[fit->u.bindingIndex];
+ break;
+ }
+ assert(target != NULL);
+ }
+ switch ( fit->kind ) {
+ case ld::Fixup::kindAddAddend:
+ targetAddend = fit->u.addend;
+ break;
+ case ld::Fixup::kindSubtractAddend:
+ minusTargetAddend = fit->u.addend;
+ break;
+ case ld::Fixup::kindSubtractTargetAddress:
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingNone:
+ case ld::Fixup::bindingByNameUnbound:
+ break;
+ case ld::Fixup::bindingByContentBound:
+ case ld::Fixup::bindingDirectlyBound:
+ fixupWithMinusTarget = fit;
+ minusTarget = fit->u.target;
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ fixupWithMinusTarget = fit;
+ minusTarget = state.indirectBindingTable[fit->u.bindingIndex];
+ break;
+ }
+ assert(minusTarget != NULL);
+ break;
+ case ld::Fixup::kindDataInCodeStartData:
+ case ld::Fixup::kindDataInCodeStartJT8:
+ case ld::Fixup::kindDataInCodeStartJT16:
+ case ld::Fixup::kindDataInCodeStartJT32:
+ case ld::Fixup::kindDataInCodeStartJTA32:
+ case ld::Fixup::kindDataInCodeEnd:
+ hasDataInCode = true;
+ break;
+ default:
+ break;
+ }
+ if ( this->isStore(fit->kind) ) {
+ fixupWithStore = fit;
+ }
+ if ( fit->lastInCluster() ) {
+ if ( (fixupWithStore != NULL) && (target != NULL) ) {
+ if ( _options.outputKind() == Options::kObjectFile ) {
+ this->addSectionRelocs(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithStore,
+ target, minusTarget, targetAddend, minusTargetAddend);
+ }
+ else {
+ if ( _options.makeCompressedDyldInfo() ) {
+ this->addDyldInfo(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithStore,
+ target, minusTarget, targetAddend, minusTargetAddend);
+ }
+ else {
+ this->addClassicRelocs(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithStore,
+ target, minusTarget, targetAddend, minusTargetAddend);
+ }
+ }
+ }
+ else if ( objc1ClassRefSection && (target != NULL) && (fixupWithStore == NULL) ) {
+ // check for class refs to lazy loaded dylibs
+ const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
+ if ( (dylib != NULL) && dylib->willBeLazyLoadedDylib() )
+ throwf("illegal class reference to %s in lazy loaded dylib %s", target->name(), dylib->path());
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void OutputFile::noteTextReloc(const ld::Atom* atom, const ld::Atom* target)
+{
+ if ( (atom->contentType() == ld::Atom::typeStub) || (atom->contentType() == ld::Atom::typeStubHelper) ) {
+ // silently let stubs (synthesized by linker) use text relocs
+ }
+ else if ( _options.allowTextRelocs() ) {
+ if ( _options.warnAboutTextRelocs() )
+ warning("text reloc in %s to %s", atom->name(), target->name());
+ }
+ else if ( _options.positionIndependentExecutable() && (_options.outputKind() == Options::kDynamicExecutable)
+ && ((_options.iOSVersionMin() >= ld::iOS_4_3) || (_options.macosxVersionMin() >= ld::mac10_7)) ) {
+ if ( ! this->pieDisabled ) {
+ warning("PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, "
+ "but used in %s from %s. "
+ "To fix this warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie",
+ atom->name(), atom->file()->path());
+ }
+ this->pieDisabled = true;
+ }
+ else if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) ) {
+ throwf("illegal text-relocoation (direct reference) to (global,weak) %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
+ }
+ else {
+ throwf("illegal text-relocation to %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
+ }
+}
+
+void OutputFile::addDyldInfo(ld::Internal& state, ld::Internal::FinalSection* sect, const ld::Atom* atom,
+ ld::Fixup* fixupWithTarget, ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+ const ld::Atom* target, const ld::Atom* minusTarget,
+ uint64_t targetAddend, uint64_t minusTargetAddend)
+{
+ if ( sect->isSectionHidden() )
+ return;
+
+ // no need to rebase or bind PCRel stores
+ if ( this->isPcRelStore(fixupWithStore->kind) ) {
+ // as long as target is in same linkage unit
+ if ( (target == NULL) || (target->definition() != ld::Atom::definitionProxy) ) {
+ // make sure target is not global and weak
+ if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular)) {
+ if ( (atom->section().type() == ld::Section::typeCFI)
+ || (atom->section().type() == ld::Section::typeDtraceDOF)
+ || (atom->section().type() == ld::Section::typeUnwindInfo) ) {
+ // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
+ return;
+ }
+ // Have direct reference to weak-global. This should be an indrect reference
+ const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
+ warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. "
+ "This was likely caused by different translation units being compiled with different visibility settings.",
+ demangledName, _options.demangleSymbol(target->name()));
+ }
+ return;
+ }
+ }
+
+ // no need to rebase or bind PIC internal pointer diff
+ if ( minusTarget != NULL ) {
+ // with pointer diffs, both need to be in same linkage unit
+ assert(minusTarget->definition() != ld::Atom::definitionProxy);
+ assert(target != NULL);
+ assert(target->definition() != ld::Atom::definitionProxy);
+ if ( target == minusTarget ) {
+ // This is a compile time constant and could have been optimized away by compiler
+ return;
+ }
+
+ // check if target of pointer-diff is global and weak
+ if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular) ) {
+ if ( (atom->section().type() == ld::Section::typeCFI)
+ || (atom->section().type() == ld::Section::typeDtraceDOF)
+ || (atom->section().type() == ld::Section::typeUnwindInfo) ) {
+ // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
+ return;
+ }
+ // Have direct reference to weak-global. This should be an indrect reference
+ const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
+ warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. "
+ "This was likely caused by different translation units being compiled with different visibility settings.",
+ demangledName, _options.demangleSymbol(target->name()));
+ }
+ return;
+ }
+
+ // no need to rebase or bind an atom's references to itself if the output is not slidable
+ if ( (atom == target) && !_options.outputSlidable() )
+ return;
+
+ // cluster has no target, so needs no rebasing or binding
+ if ( target == NULL )
+ return;
+
+ bool inReadOnlySeg = ( strcmp(sect->segmentName(), "__TEXT") == 0 );
+ bool needsRebase = false;
+ bool needsBinding = false;
+ bool needsLazyBinding = false;
+ bool needsWeakBinding = false;
+
+ uint8_t rebaseType = REBASE_TYPE_POINTER;
+ uint8_t type = BIND_TYPE_POINTER;
+ const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
+ bool weak_import = (fixupWithTarget->weakImport || ((dylib != NULL) && dylib->forcedWeakLinked()));
+ uint64_t address = atom->finalAddress() + fixupWithTarget->offsetInAtom;
+ uint64_t addend = targetAddend - minusTargetAddend;
+
+ // special case lazy pointers
+ if ( fixupWithTarget->kind == ld::Fixup::kindLazyTarget ) {
+ assert(fixupWithTarget->u.target == target);
+ assert(addend == 0);
+ // lazy dylib lazy pointers do not have any dyld info
+ if ( atom->section().type() == ld::Section::typeLazyDylibPointer )
+ return;
+ // lazy binding to weak definitions are done differently
+ // they are directly bound to target, then have a weak bind in case of a collision
+ if ( target->combine() == ld::Atom::combineByName ) {
+ if ( target->definition() == ld::Atom::definitionProxy ) {
+ // weak def exported from another dylib
+ // must non-lazy bind to it plus have weak binding info in case of collision
+ needsBinding = true;
+ needsWeakBinding = true;
+ }
+ else {
+ // weak def in this linkage unit.
+ // just rebase, plus have weak binding info in case of collision
+ // this will be done by other cluster on lazy pointer atom
+ }
+ }
+ else if ( (target->contentType() == ld::Atom::typeResolver) && (target->scope() != ld::Atom::scopeGlobal) ) {
+ // <rdar://problem/8553647> Hidden resolver functions should not have lazy binding info
+ needsLazyBinding = false;
+ }
+ else {
+ // normal case of a pointer to non-weak-def symbol, so can lazily bind
+ needsLazyBinding = true;
+ }
+ }
+ else {
+ // everything except lazy pointers
+ switch ( target->definition() ) {
+ case ld::Atom::definitionProxy:
+ if ( (dylib != NULL) && dylib->willBeLazyLoadedDylib() )
+ throwf("illegal data reference to %s in lazy loaded dylib %s", target->name(), dylib->path());
+ if ( target->contentType() == ld::Atom::typeTLV ) {
+ if ( sect->type() != ld::Section::typeTLVPointers )
+ throwf("illegal data reference in %s to thread local variable %s in dylib %s",
+ atom->name(), target->name(), dylib->path());
+ }
+ if ( inReadOnlySeg )
+ type = BIND_TYPE_TEXT_ABSOLUTE32;
+ needsBinding = true;
+ if ( target->combine() == ld::Atom::combineByName )
+ needsWeakBinding = true;
+ break;
+ case ld::Atom::definitionRegular:
+ case ld::Atom::definitionTentative:
+ // only slideable images need rebasing info
+ if ( _options.outputSlidable() ) {
+ needsRebase = true;
+ }
+ // references to internal symbol never need binding
+ if ( target->scope() != ld::Atom::scopeGlobal )
+ break;
+ // reference to global weak def needs weak binding
+ if ( (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular) )
+ needsWeakBinding = true;
+ else if ( _options.outputKind() == Options::kDynamicExecutable ) {
+ // in main executables, the only way regular symbols are indirected is if -interposable is used
+ if ( _options.interposable(target->name()) ) {
+ needsRebase = false;
+ needsBinding = true;
+ }
+ }
+ else {
+ // for flat-namespace or interposable two-level-namespace
+ // all references to exported symbols get indirected
+ if ( (_options.nameSpace() != Options::kTwoLevelNameSpace) || _options.interposable(target->name()) ) {
+ // <rdar://problem/5254468> no external relocs for flat objc classes
+ if ( strncmp(target->name(), ".objc_class_", 12) == 0 )
+ break;
+ // no rebase info for references to global symbols that will have binding info
+ needsRebase = false;
+ needsBinding = true;
+ }
+ }
+ break;
+ case ld::Atom::definitionAbsolute:
+ break;
+ }
+ }
+
+ // record dyld info for this cluster
+ if ( needsRebase ) {
+ if ( inReadOnlySeg ) {
+ noteTextReloc(atom, target);
+ sect->hasLocalRelocs = true; // so dyld knows to change permissions on __TEXT segment
+ rebaseType = REBASE_TYPE_TEXT_ABSOLUTE32;
+ }
+ if ( (addend != 0) && _options.sharedRegionEligible() ) {
+ // make sure the addend does not cause the pointer to point outside the target's segment
+ // if it does, update_dyld_shared_cache will not be able to put this dylib into the shared cache
+ uint64_t targetAddress = target->finalAddress();
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sct = *sit;
+ uint64_t sctEnd = (sct->address+sct->size);
+ if ( (sct->address <= targetAddress) && (targetAddress < sctEnd) ) {
+ if ( (targetAddress+addend) > sctEnd ) {
+ warning("data symbol %s from %s has pointer to %s + 0x%08llX. "
+ "That large of an addend may disable %s from being put in the dyld shared cache.",
+ atom->name(), atom->file()->path(), target->name(), addend, _options.installPath() );
+ }
+ }
+ }
+ }
+ _rebaseInfo.push_back(RebaseInfo(rebaseType, address));
+ }
+ if ( needsBinding ) {
+ if ( inReadOnlySeg ) {
+ noteTextReloc(atom, target);
+ sect->hasExternalRelocs = true; // so dyld knows to change permissions on __TEXT segment
+ }
+ _bindingInfo.push_back(BindingInfo(type, this->compressedOrdinalForAtom(target), target->name(), weak_import, address, addend));
+ }
+ if ( needsLazyBinding ) {
+ if ( _options.bindAtLoad() )
+ _bindingInfo.push_back(BindingInfo(type, this->compressedOrdinalForAtom(target), target->name(), weak_import, address, addend));
+ else
+ _lazyBindingInfo.push_back(BindingInfo(type, this->compressedOrdinalForAtom(target), target->name(), weak_import, address, addend));
+ }
+ if ( needsWeakBinding )
+ _weakBindingInfo.push_back(BindingInfo(type, 0, target->name(), false, address, addend));
+}
+
+
+void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSection* sect, const ld::Atom* atom,
+ ld::Fixup* fixupWithTarget, ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+ const ld::Atom* target, const ld::Atom* minusTarget,
+ uint64_t targetAddend, uint64_t minusTargetAddend)
+{
+ if ( sect->isSectionHidden() )
+ return;
+
+ // non-lazy-pointer section is encoded in indirect symbol table - not using relocations
+ if ( sect->type() == ld::Section::typeNonLazyPointer ) {
+ // except kexts and static pie which *do* use relocations
+ switch (_options.outputKind()) {
+ case Options::kKextBundle:
+ break;
+ case Options::kStaticExecutable:
+ if ( _options.positionIndependentExecutable() )
+ break;
+ // else fall into default case
+ default:
+ assert(target != NULL);
+ assert(fixupWithTarget != NULL);
+ return;
+ }
+ }
+
+ // no need to rebase or bind PCRel stores
+ if ( this->isPcRelStore(fixupWithStore->kind) ) {
+ // as long as target is in same linkage unit
+ if ( (target == NULL) || (target->definition() != ld::Atom::definitionProxy) )
+ return;
+ }
+
+ // no need to rebase or bind PIC internal pointer diff
+ if ( minusTarget != NULL ) {
+ // with pointer diffs, both need to be in same linkage unit
+ assert(minusTarget->definition() != ld::Atom::definitionProxy);
+ assert(target != NULL);
+ assert(target->definition() != ld::Atom::definitionProxy);
+ // make sure target is not global and weak
+ if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName)
+ && (atom->section().type() != ld::Section::typeCFI)
+ && (atom->section().type() != ld::Section::typeDtraceDOF)
+ && (atom->section().type() != ld::Section::typeUnwindInfo)
+ && (minusTarget != target) ) {
+ // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
+ throwf("bad codegen, pointer diff in %s to global weak symbol %s", atom->name(), target->name());
+ }
+ return;
+ }
+
+ // cluster has no target, so needs no rebasing or binding
+ if ( target == NULL )
+ return;
+
+ assert(_localRelocsAtom != NULL);
+ uint64_t relocAddress = atom->finalAddress() + fixupWithTarget->offsetInAtom - _localRelocsAtom->relocBaseAddress(state);
+
+ bool inReadOnlySeg = ( strcmp(sect->segmentName(), "__TEXT") == 0 );
+ bool needsLocalReloc = false;
+ bool needsExternReloc = false;
+
+ switch ( fixupWithStore->kind ) {
+ case ld::Fixup::kindLazyTarget:
+ // lazy pointers don't need relocs
+ break;
+ case ld::Fixup::kindStoreLittleEndian32:
+ case ld::Fixup::kindStoreLittleEndian64:
+ case ld::Fixup::kindStoreBigEndian32:
+ case ld::Fixup::kindStoreBigEndian64:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+ case ld::Fixup::kindStoreTargetAddressBigEndian32:
+ case ld::Fixup::kindStoreTargetAddressBigEndian64:
+ // is pointer
+ switch ( target->definition() ) {
+ case ld::Atom::definitionProxy:
+ needsExternReloc = true;
+ break;
+ case ld::Atom::definitionRegular:
+ case ld::Atom::definitionTentative:
+ // only slideable images need local relocs
+ if ( _options.outputSlidable() )
+ needsLocalReloc = true;
+ // references to internal symbol never need binding
+ if ( target->scope() != ld::Atom::scopeGlobal )
+ break;
+ // reference to global weak def needs weak binding in dynamic images
+ if ( (target->combine() == ld::Atom::combineByName)
+ && (target->definition() == ld::Atom::definitionRegular)
+ && (_options.outputKind() != Options::kStaticExecutable) ) {
+ needsExternReloc = true;
+ }
+ else if ( _options.outputKind() == Options::kDynamicExecutable ) {
+ // in main executables, the only way regular symbols are indirected is if -interposable is used
+ if ( _options.interposable(target->name()) )
+ needsExternReloc = true;
+ }
+ else {
+ // for flat-namespace or interposable two-level-namespace
+ // all references to exported symbols get indirected
+ if ( (_options.nameSpace() != Options::kTwoLevelNameSpace) || _options.interposable(target->name()) ) {
+ // <rdar://problem/5254468> no external relocs for flat objc classes
+ if ( strncmp(target->name(), ".objc_class_", 12) == 0 )
+ break;
+ // no rebase info for references to global symbols that will have binding info
+ needsExternReloc = true;
+ }
+ }
+ if ( needsExternReloc )
+ needsLocalReloc = false;
+ break;
+ case ld::Atom::definitionAbsolute:
+ break;
+ }
+ if ( needsExternReloc ) {
+ if ( inReadOnlySeg )
+ noteTextReloc(atom, target);
+ const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
+ if ( (dylib != NULL) && dylib->willBeLazyLoadedDylib() )
+ throwf("illegal data reference to %s in lazy loaded dylib %s", target->name(), dylib->path());
+ _externalRelocsAtom->addExternalPointerReloc(relocAddress, target);
+ sect->hasExternalRelocs = true;
+ fixupWithTarget->contentAddendOnly = true;
+ }
+ else if ( needsLocalReloc ) {
+ assert(target != NULL);
+ if ( inReadOnlySeg )
+ noteTextReloc(atom, target);
+ _localRelocsAtom->addPointerReloc(relocAddress, target->machoSection());
+ sect->hasLocalRelocs = true;
+ }
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+ if ( _options.outputKind() == Options::kKextBundle ) {
+ assert(target != NULL);
+ if ( target->definition() == ld::Atom::definitionProxy ) {
+ _externalRelocsAtom->addExternalCallSiteReloc(relocAddress, target);
+ fixupWithStore->contentAddendOnly = true;
+ }
+ }
+ break;
+
+ case ld::Fixup::kindStoreARMLow16:
+ case ld::Fixup::kindStoreThumbLow16:
+ // no way to encode rebasing of binding for these instructions
+ if ( _options.outputSlidable() || (target->definition() == ld::Atom::definitionProxy) )
+ throwf("no supported runtime lo16 relocation in %s from %s to %s", atom->name(), atom->file()->path(), target->name());
+ break;
+
+ case ld::Fixup::kindStoreARMHigh16:
+ case ld::Fixup::kindStoreThumbHigh16:
+ // no way to encode rebasing of binding for these instructions
+ if ( _options.outputSlidable() || (target->definition() == ld::Atom::definitionProxy) )
+ throwf("no supported runtime hi16 relocation in %s from %s to %s", atom->name(), atom->file()->path(), target->name());
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+bool OutputFile::useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* target, ld::Fixup* fixupWithTarget)
+{
+ if ( _options.architecture() == CPU_TYPE_X86_64 ) {
+ // x86_64 uses external relocations for everthing that has a symbol
+ return ( target->symbolTableInclusion() != ld::Atom::symbolTableNotIn );
+ }
+
+ // <rdar://problem/9513487> support arm branch interworking in -r mode
+ if ( (_options.architecture() == CPU_TYPE_ARM) && (_options.outputKind() == Options::kObjectFile) ) {
+ if ( atom->isThumb() != target->isThumb() ) {
+ switch ( fixupWithTarget->kind ) {
+ // have branch that switches mode, then might be 'b' not 'bl'
+ // Force external relocation, since no way to do local reloc for 'b'
+ case ld::Fixup::kindStoreTargetAddressThumbBranch22 :
+ case ld::Fixup::kindStoreTargetAddressARMBranch24:
+ return true;
+ default:
+ break;
+ }
+ }
+ }
+
+ if ( (_options.architecture() == CPU_TYPE_I386) && (_options.outputKind() == Options::kObjectFile) ) {
+ if ( target->contentType() == ld::Atom::typeTLV )
+ return true;
+ }
+
+ // most architectures use external relocations only for references
+ // to a symbol in another translation unit or for references to "weak symbols" or tentative definitions
+ assert(target != NULL);
+ if ( target->definition() == ld::Atom::definitionProxy )
+ return true;
+ if ( (target->definition() == ld::Atom::definitionTentative) && ! _options.makeTentativeDefinitionsReal() )
+ return true;
+ if ( target->scope() != ld::Atom::scopeGlobal )
+ return false;
+ if ( (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular) )
+ return true;
+ return false;
+}
+
+
+
+
+void OutputFile::addSectionRelocs(ld::Internal& state, ld::Internal::FinalSection* sect, const ld::Atom* atom,
+ ld::Fixup* fixupWithTarget, ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+ const ld::Atom* target, const ld::Atom* minusTarget,
+ uint64_t targetAddend, uint64_t minusTargetAddend)
+{
+ if ( sect->isSectionHidden() )
+ return;
+
+ // in -r mode where there will be no labels on __eh_frame section, there is no need for relocations
+ if ( (sect->type() == ld::Section::typeCFI) && _options.removeEHLabels() )
+ return;
+
+ // non-lazy-pointer section is encoded in indirect symbol table - not using relocations
+ if ( sect->type() == ld::Section::typeNonLazyPointer )
+ return;
+
+ // tentative defs don't have any relocations
+ if ( sect->type() == ld::Section::typeTentativeDefs )
+ return;
+
+ assert(target != NULL);
+ assert(fixupWithTarget != NULL);
+ bool targetUsesExternalReloc = this->useExternalSectionReloc(atom, target, fixupWithTarget);
+ bool minusTargetUsesExternalReloc = (minusTarget != NULL) && this->useExternalSectionReloc(atom, minusTarget, fixupWithMinusTarget);
+
+ // in x86_64 .o files an external reloc means the content contains just the addend
+ if ( _options.architecture() == CPU_TYPE_X86_64 ) {
+ if ( targetUsesExternalReloc ) {
+ fixupWithTarget->contentAddendOnly = true;
+ fixupWithStore->contentAddendOnly = true;
+ }
+ if ( minusTargetUsesExternalReloc )
+ fixupWithMinusTarget->contentAddendOnly = true;
+ }
+ else {
+ // for other archs, content is addend only with (non pc-rel) pointers
+ // pc-rel instructions are funny. If the target is _foo+8 and _foo is
+ // external, then the pc-rel instruction *evalutates* to the address 8.
+ if ( targetUsesExternalReloc ) {
+ // TLV support for i386 acts like RIP relative addressing
+ // The addend is the offset from the PICBase to the end of the instruction
+ if ( (_options.architecture() == CPU_TYPE_I386)
+ && (_options.outputKind() == Options::kObjectFile)
+ && (fixupWithStore->kind == ld::Fixup::kindStoreX86PCRel32TLVLoad) ) {
+ fixupWithTarget->contentAddendOnly = true;
+ fixupWithStore->contentAddendOnly = true;
+ }
+ else if ( isPcRelStore(fixupWithStore->kind) ) {
+ fixupWithTarget->contentDetlaToAddendOnly = true;
+ fixupWithStore->contentDetlaToAddendOnly = true;
+ }
+ else if ( minusTarget == NULL ){
+ fixupWithTarget->contentAddendOnly = true;
+ fixupWithStore->contentAddendOnly = true;
+ }
+ }
+ }
+
+ if ( fixupWithStore != NULL ) {
+ _sectionsRelocationsAtom->addSectionReloc(sect, fixupWithStore->kind, atom, fixupWithStore->offsetInAtom,
+ targetUsesExternalReloc, minusTargetUsesExternalReloc,
+ target, targetAddend, minusTarget, minusTargetAddend);
+ }
+
+}
+
+
+void OutputFile::makeSplitSegInfo(ld::Internal& state)
+{
+ if ( !_options.sharedRegionEligible() )
+ return;
+
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->isSectionHidden() )
+ continue;
+ if ( strcmp(sect->segmentName(), "__TEXT") != 0 )
+ continue;
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ const ld::Atom* target = NULL;
+ const ld::Atom* fromTarget = NULL;
+ uint64_t accumulator = 0;
+ bool thumbTarget;
+ bool hadSubtract = false;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ if ( fit->firstInCluster() )
+ target = NULL;
+ if ( this->setsTarget(fit->kind) ) {
+ accumulator = addressOf(state, fit, &target);
+ thumbTarget = targetIsThumb(state, fit);
+ if ( thumbTarget )
+ accumulator |= 1;
+ }
+ switch ( fit->kind ) {
+ case ld::Fixup::kindSubtractTargetAddress:
+ accumulator -= addressOf(state, fit, &fromTarget);
+ hadSubtract = true;
+ break;
+ case ld::Fixup::kindAddAddend:
+ accumulator += fit->u.addend;
+ break;
+ case ld::Fixup::kindSubtractAddend:
+ accumulator -= fit->u.addend;
+ break;
+ case ld::Fixup::kindStoreBigEndian32:
+ case ld::Fixup::kindStoreLittleEndian32:
+ case ld::Fixup::kindStoreLittleEndian64:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+ // if no subtract, then this is an absolute pointer which means
+ // there is also a text reloc which update_dyld_shared_cache will use.
+ if ( ! hadSubtract )
+ break;
+ // fall through
+ case ld::Fixup::kindStoreX86PCRel32:
+ case ld::Fixup::kindStoreX86PCRel32_1:
+ case ld::Fixup::kindStoreX86PCRel32_2:
+ case ld::Fixup::kindStoreX86PCRel32_4:
+ case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+ case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
+ case ld::Fixup::kindStoreX86PCRel32GOT:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+ case ld::Fixup::kindStoreARMLow16:
+ case ld::Fixup::kindStoreThumbLow16:
+ assert(target != NULL);
+ if ( strcmp(sect->segmentName(), target->section().segmentName()) != 0 ) {
+ _splitSegInfos.push_back(SplitSegInfoEntry(atom->finalAddress()+fit->offsetInAtom,fit->kind));
+ }
+ break;
+ case ld::Fixup::kindStoreARMHigh16:
+ case ld::Fixup::kindStoreThumbHigh16:
+ assert(target != NULL);
+ if ( strcmp(sect->segmentName(), target->section().segmentName()) != 0 ) {
+ // hi16 needs to know upper 4-bits of low16 to compute carry
+ uint32_t extra = (accumulator >> 12) & 0xF;
+ _splitSegInfos.push_back(SplitSegInfoEntry(atom->finalAddress()+fit->offsetInAtom,fit->kind, extra));
+ }
+ break;
+ case ld::Fixup::kindSetTargetImageOffset:
+ accumulator = addressOf(state, fit, &target);
+ assert(target != NULL);
+ hadSubtract = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+void OutputFile::writeMapFile(ld::Internal& state)
+{
+ if ( _options.generatedMapPath() != NULL ) {
+ FILE* mapFile = fopen(_options.generatedMapPath(), "w");
+ if ( mapFile != NULL ) {
+ // write output path
+ fprintf(mapFile, "# Path: %s\n", _options.outputFilePath());
+ // write output architecure
+ fprintf(mapFile, "# Arch: %s\n", _options.architectureName());
+ // write UUID
+ //if ( fUUIDAtom != NULL ) {
+ // const uint8_t* uuid = fUUIDAtom->getUUID();
+ // fprintf(mapFile, "# UUID: %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X \n",
+ // uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
+ // uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
+ //}
+ // write table of object files
+ std::map<const ld::File*, ld::File::Ordinal> readerToOrdinal;
+ std::map<ld::File::Ordinal, const ld::File*> ordinalToReader;
+ std::map<const ld::File*, uint32_t> readerToFileOrdinal;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->isSectionHidden() )
+ continue;
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ const ld::File* reader = atom->file();
+ if ( reader == NULL )
+ continue;
+ ld::File::Ordinal readerOrdinal = reader->ordinal();
+ std::map<const ld::File*, ld::File::Ordinal>::iterator pos = readerToOrdinal.find(reader);
+ if ( pos == readerToOrdinal.end() ) {
+ readerToOrdinal[reader] = readerOrdinal;
+ ordinalToReader[readerOrdinal] = reader;
+ }
+ }
+ }
+ fprintf(mapFile, "# Object files:\n");
+ fprintf(mapFile, "[%3u] %s\n", 0, "linker synthesized");
+ uint32_t fileIndex = 1;
+ for(std::map<ld::File::Ordinal, const ld::File*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
+ fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->path());
+ readerToFileOrdinal[it->second] = fileIndex++;
+ }
+ // write table of sections
+ fprintf(mapFile, "# Sections:\n");
+ fprintf(mapFile, "# Address\tSize \tSegment\tSection\n");
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->isSectionHidden() )
+ continue;
+ fprintf(mapFile, "0x%08llX\t0x%08llX\t%s\t%s\n", sect->address, sect->size,
+ sect->segmentName(), sect->sectionName());
+ }
+ // write table of symbols
+ fprintf(mapFile, "# Symbols:\n");
+ fprintf(mapFile, "# Address\tSize \tFile Name\n");
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->isSectionHidden() )
+ continue;
+ //bool isCstring = (sect->type() == ld::Section::typeCString);
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ char buffer[4096];
+ const ld::Atom* atom = *ait;
+ const char* name = atom->name();
+ if ( atom->contentType() == ld::Atom::typeCString ) {
+ strcpy(buffer, "literal string: ");
+ strlcat(buffer, (char*)atom->rawContentPointer(), 4096);
+ name = buffer;
+ }
+ else if ( (atom->contentType() == ld::Atom::typeCFI) && (strcmp(name, "FDE") == 0) ) {
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ if ( (fit->kind == ld::Fixup::kindSetTargetAddress) && (fit->clusterSize == ld::Fixup::k1of4) ) {
+ assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+ if ( fit->u.target->section().type() == ld::Section::typeCode) {
+ strcpy(buffer, "FDE for: ");
+ strlcat(buffer, fit->u.target->name(), 4096);
+ name = buffer;
+ }
+ }
+ }
+ }
+ else if ( atom->contentType() == ld::Atom::typeNonLazyPointer ) {
+ strcpy(buffer, "non-lazy-pointer");
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ if ( fit->binding == ld::Fixup::bindingsIndirectlyBound ) {
+ strcpy(buffer, "non-lazy-pointer-to: ");
+ strlcat(buffer, state.indirectBindingTable[fit->u.bindingIndex]->name(), 4096);
+ break;
+ }
+ else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+ strcpy(buffer, "non-lazy-pointer-to-local: ");
+ strlcat(buffer, fit->u.target->name(), 4096);
+ break;
+ }
+ }
+ name = buffer;
+ }
+ fprintf(mapFile, "0x%08llX\t0x%08llX\t[%3u] %s\n", atom->finalAddress(), atom->size(),
+ readerToFileOrdinal[atom->file()], name);
+ }
+ }
+ fclose(mapFile);
+ }
+ else {
+ warning("could not write map file: %s\n", _options.generatedMapPath());
+ }
+ }
+}
+
+
+// used to sort atoms with debug notes
+class DebugNoteSorter
+{
+public:
+ bool operator()(const ld::Atom* left, const ld::Atom* right) const
+ {
+ // first sort by reader
+ ld::File::Ordinal leftFileOrdinal = left->file()->ordinal();
+ ld::File::Ordinal rightFileOrdinal = right->file()->ordinal();
+ if ( leftFileOrdinal!= rightFileOrdinal)
+ return (leftFileOrdinal < rightFileOrdinal);
+
+ // then sort by atom objectAddress
+ uint64_t leftAddr = left->finalAddress();
+ uint64_t rightAddr = right->finalAddress();
+ return leftAddr < rightAddr;
+ }
+};
+
+
+class CStringEquals
+{
+public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+};
+
+const char* OutputFile::assureFullPath(const char* path)
+{
+ if ( path[0] == '/' )
+ return path;
+ char cwdbuff[MAXPATHLEN];
+ if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
+ char* result;
+ asprintf(&result, "%s/%s", cwdbuff, path);
+ if ( result != NULL )
+ return result;
+ }
+ return path;
+}
+
+void OutputFile::synthesizeDebugNotes(ld::Internal& state)
+{
+ // -S means don't synthesize debug map
+ if ( _options.debugInfoStripping() == Options::kDebugInfoNone )
+ return;
+ // make a vector of atoms that come from files compiled with dwarf debug info
+ std::vector<const ld::Atom*> atomsNeedingDebugNotes;
+ std::set<const ld::Atom*> atomsWithStabs;
+ atomsNeedingDebugNotes.reserve(1024);
+ const ld::relocatable::File* objFile = NULL;
+ bool objFileHasDwarf = false;
+ bool objFileHasStabs = false;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ // no stabs for atoms that would not be in the symbol table
+ if ( atom->symbolTableInclusion() == ld::Atom::symbolTableNotIn )
+ continue;
+ if ( atom->symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages )
+ continue;
+ // no stabs for absolute symbols
+ if ( atom->definition() == ld::Atom::definitionAbsolute )
+ continue;
+ // no stabs for .eh atoms
+ if ( atom->contentType() == ld::Atom::typeCFI )
+ continue;
+ const ld::File* file = atom->file();
+ if ( file != NULL ) {
+ if ( file != objFile ) {
+ objFileHasDwarf = false;
+ objFileHasStabs = false;
+ objFile = dynamic_cast<const ld::relocatable::File*>(file);
+ if ( objFile != NULL ) {
+ switch ( objFile->debugInfo() ) {
+ case ld::relocatable::File::kDebugInfoNone:
+ break;
+ case ld::relocatable::File::kDebugInfoDwarf:
+ objFileHasDwarf = true;
+ break;
+ case ld::relocatable::File::kDebugInfoStabs:
+ case ld::relocatable::File::kDebugInfoStabsUUID:
+ objFileHasStabs = true;
+ break;
+ }
+ }
+ }
+ if ( objFileHasDwarf )
+ atomsNeedingDebugNotes.push_back(atom);
+ if ( objFileHasStabs )
+ atomsWithStabs.insert(atom);
+ }
+ }
+ }
+
+ // sort by file ordinal then atom ordinal
+ std::sort(atomsNeedingDebugNotes.begin(), atomsNeedingDebugNotes.end(), DebugNoteSorter());
+
+ // synthesize "debug notes" and add them to master stabs vector
+ const char* dirPath = NULL;
+ const char* filename = NULL;
+ bool wroteStartSO = false;
+ state.stabs.reserve(atomsNeedingDebugNotes.size()*4);
+ __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> seenFiles;
+ for (std::vector<const ld::Atom*>::iterator it=atomsNeedingDebugNotes.begin(); it != atomsNeedingDebugNotes.end(); it++) {
+ const ld::Atom* atom = *it;
+ const ld::File* atomFile = atom->file();
+ const ld::relocatable::File* atomObjFile = dynamic_cast<const ld::relocatable::File*>(atomFile);
+ //fprintf(stderr, "debug note for %s\n", atom->name());
+ const char* newPath = atom->translationUnitSource();
+ if ( newPath != NULL ) {
+ const char* newDirPath;
+ const char* newFilename;
+ const char* lastSlash = strrchr(newPath, '/');
+ if ( lastSlash == NULL )
+ continue;
+ newFilename = lastSlash+1;
+ char* temp = strdup(newPath);
+ newDirPath = temp;
+ // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
+ temp[lastSlash-newPath+1] = '\0';
+ // need SO's whenever the translation unit source file changes
+ if ( (filename == NULL) || (strcmp(newFilename,filename) != 0) ) {
+ if ( filename != NULL ) {
+ // translation unit change, emit ending SO
+ ld::relocatable::File::Stab endFileStab;
+ endFileStab.atom = NULL;
+ endFileStab.type = N_SO;
+ endFileStab.other = 1;
+ endFileStab.desc = 0;
+ endFileStab.value = 0;
+ endFileStab.string = "";
+ state.stabs.push_back(endFileStab);
+ }
+ // new translation unit, emit start SO's
+ ld::relocatable::File::Stab dirPathStab;
+ dirPathStab.atom = NULL;
+ dirPathStab.type = N_SO;
+ dirPathStab.other = 0;
+ dirPathStab.desc = 0;
+ dirPathStab.value = 0;
+ dirPathStab.string = newDirPath;
+ state.stabs.push_back(dirPathStab);
+ ld::relocatable::File::Stab fileStab;
+ fileStab.atom = NULL;
+ fileStab.type = N_SO;
+ fileStab.other = 0;
+ fileStab.desc = 0;
+ fileStab.value = 0;
+ fileStab.string = newFilename;
+ state.stabs.push_back(fileStab);
+ // Synthesize OSO for start of file
+ ld::relocatable::File::Stab objStab;
+ objStab.atom = NULL;
+ objStab.type = N_OSO;
+ // <rdar://problem/6337329> linker should put cpusubtype in n_sect field of nlist entry for N_OSO debug note entries
+ objStab.other = atomFile->cpuSubType();
+ objStab.desc = 1;
+ if ( atomObjFile != NULL ) {
+ objStab.string = assureFullPath(atomObjFile->debugInfoPath());
+ objStab.value = atomObjFile->debugInfoModificationTime();
+ }
+ else {
+ objStab.string = assureFullPath(atomFile->path());
+ objStab.value = atomFile->modificationTime();
+ }
+ state.stabs.push_back(objStab);
+ wroteStartSO = true;
+ // add the source file path to seenFiles so it does not show up in SOLs
+ seenFiles.insert(newFilename);
+ char* fullFilePath;
+ asprintf(&fullFilePath, "%s%s", newDirPath, newFilename);
+ // add both leaf path and full path
+ seenFiles.insert(fullFilePath);
+ }
+ filename = newFilename;
+ dirPath = newDirPath;
+ if ( atom->section().type() == ld::Section::typeCode ) {
+ // Synthesize BNSYM and start FUN stabs
+ ld::relocatable::File::Stab beginSym;
+ beginSym.atom = atom;
+ beginSym.type = N_BNSYM;
+ beginSym.other = 1;
+ beginSym.desc = 0;
+ beginSym.value = 0;
+ beginSym.string = "";
+ state.stabs.push_back(beginSym);
+ ld::relocatable::File::Stab startFun;
+ startFun.atom = atom;
+ startFun.type = N_FUN;
+ startFun.other = 1;
+ startFun.desc = 0;
+ startFun.value = 0;
+ startFun.string = atom->name();
+ state.stabs.push_back(startFun);
+ // Synthesize any SOL stabs needed
+ const char* curFile = NULL;
+ for (ld::Atom::LineInfo::iterator lit = atom->beginLineInfo(); lit != atom->endLineInfo(); ++lit) {
+ if ( lit->fileName != curFile ) {
+ if ( seenFiles.count(lit->fileName) == 0 ) {
+ seenFiles.insert(lit->fileName);
+ ld::relocatable::File::Stab sol;
+ sol.atom = 0;
+ sol.type = N_SOL;
+ sol.other = 0;
+ sol.desc = 0;
+ sol.value = 0;
+ sol.string = lit->fileName;
+ state.stabs.push_back(sol);
+ }
+ curFile = lit->fileName;
+ }
+ }
+ // Synthesize end FUN and ENSYM stabs
+ ld::relocatable::File::Stab endFun;
+ endFun.atom = atom;
+ endFun.type = N_FUN;
+ endFun.other = 0;
+ endFun.desc = 0;
+ endFun.value = 0;
+ endFun.string = "";
+ state.stabs.push_back(endFun);
+ ld::relocatable::File::Stab endSym;
+ endSym.atom = atom;
+ endSym.type = N_ENSYM;
+ endSym.other = 1;
+ endSym.desc = 0;
+ endSym.value = 0;
+ endSym.string = "";
+ state.stabs.push_back(endSym);
+ }
+ else {
+ ld::relocatable::File::Stab globalsStab;
+ const char* name = atom->name();
+ if ( atom->scope() == ld::Atom::scopeTranslationUnit ) {
+ // Synthesize STSYM stab for statics
+ globalsStab.atom = atom;
+ globalsStab.type = N_STSYM;
+ globalsStab.other = 1;
+ globalsStab.desc = 0;
+ globalsStab.value = 0;
+ globalsStab.string = name;
+ state.stabs.push_back(globalsStab);
+ }
+ else {
+ // Synthesize GSYM stab for other globals
+ globalsStab.atom = atom;
+ globalsStab.type = N_GSYM;
+ globalsStab.other = 1;
+ globalsStab.desc = 0;
+ globalsStab.value = 0;
+ globalsStab.string = name;
+ state.stabs.push_back(globalsStab);
+ }
+ }
+ }
+ }
+
+ if ( wroteStartSO ) {
+ // emit ending SO
+ ld::relocatable::File::Stab endFileStab;
+ endFileStab.atom = NULL;
+ endFileStab.type = N_SO;
+ endFileStab.other = 1;
+ endFileStab.desc = 0;
+ endFileStab.value = 0;
+ endFileStab.string = "";
+ state.stabs.push_back(endFileStab);
+ }
+
+ // copy any stabs from .o file
+ std::set<const ld::File*> filesSeenWithStabs;
+ for (std::set<const ld::Atom*>::iterator it=atomsWithStabs.begin(); it != atomsWithStabs.end(); it++) {
+ const ld::Atom* atom = *it;
+ objFile = dynamic_cast<const ld::relocatable::File*>(atom->file());
+ if ( objFile != NULL ) {
+ if ( filesSeenWithStabs.count(objFile) == 0 ) {
+ filesSeenWithStabs.insert(objFile);
+ const std::vector<ld::relocatable::File::Stab>* stabs = objFile->stabs();
+ if ( stabs != NULL ) {
+ for(std::vector<ld::relocatable::File::Stab>::const_iterator sit = stabs->begin(); sit != stabs->end(); ++sit) {
+ ld::relocatable::File::Stab stab = *sit;
+ // ignore stabs associated with atoms that were dead stripped or coalesced away
+ if ( (sit->atom != NULL) && (atomsWithStabs.count(sit->atom) == 0) )
+ continue;
+ // <rdar://problem/8284718> Value of N_SO stabs should be address of first atom from translation unit
+ if ( (stab.type == N_SO) && (stab.string != NULL) && (stab.string[0] != '\0') ) {
+ stab.atom = atom;
+ }
+ state.stabs.push_back(stab);
+ }
+ }
+ }
+ }
+ }
+
+}
+
+
+} // namespace tool
+} // namespace ld
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __OUTPUT_FILE_H__
+#define __OUTPUT_FILE_H__
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+
+#include <vector>
+
+#include "Options.h"
+#include "ld.hpp"
+
+namespace ld {
+namespace tool {
+
+class OutputFile
+{
+public:
+ OutputFile(const Options& opts);
+
+
+ // iterates all atoms in initial files
+ void write(ld::Internal&);
+ bool findSegment(ld::Internal& state, uint64_t addr, uint64_t* start, uint64_t* end, uint32_t* index);
+ void setLazyBindingInfoOffset(uint64_t lpAddress, uint32_t lpInfoOffset);
+ uint32_t dylibCount();
+ const ld::dylib::File* dylibByOrdinal(unsigned int ordinal);
+ uint32_t dylibToOrdinal(const ld::dylib::File*);
+ uint32_t encryptedTextStartOffset() { return _encryptedTEXTstartOffset; }
+ uint32_t encryptedTextEndOffset() { return _encryptedTEXTendOffset; }
+ int compressedOrdinalForAtom(const ld::Atom* target);
+ uint64_t fileSize() const { return _fileSize; }
+
+
+ bool hasWeakExternalSymbols;
+ bool usesWeakExternalSymbols;
+ bool overridesWeakExternalSymbols;
+ bool _noReExportedDylibs;
+ bool hasThreadLocalVariableDefinitions;
+ bool pieDisabled;
+ bool hasDataInCode;
+ ld::Internal::FinalSection* headerAndLoadCommandsSection;
+ ld::Internal::FinalSection* rebaseSection;
+ ld::Internal::FinalSection* bindingSection;
+ ld::Internal::FinalSection* weakBindingSection;
+ ld::Internal::FinalSection* lazyBindingSection;
+ ld::Internal::FinalSection* exportSection;
+ ld::Internal::FinalSection* splitSegInfoSection;
+ ld::Internal::FinalSection* functionStartsSection;
+ ld::Internal::FinalSection* dataInCodeSection;
+ ld::Internal::FinalSection* dependentDRsSection;
+ ld::Internal::FinalSection* symbolTableSection;
+ ld::Internal::FinalSection* stringPoolSection;
+ ld::Internal::FinalSection* localRelocationsSection;
+ ld::Internal::FinalSection* externalRelocationsSection;
+ ld::Internal::FinalSection* sectionRelocationsSection;
+ ld::Internal::FinalSection* indirectSymbolTableSection;
+
+ struct RebaseInfo {
+ RebaseInfo(uint8_t t, uint64_t addr) : _type(t), _address(addr) {}
+ uint8_t _type;
+ uint64_t _address;
+ // for sorting
+ int operator<(const RebaseInfo& rhs) const {
+ // sort by type, then address
+ if ( this->_type != rhs._type )
+ return (this->_type < rhs._type );
+ return (this->_address < rhs._address );
+ }
+ };
+
+ struct BindingInfo {
+ BindingInfo(uint8_t t, int ord, const char* sym, bool weak_import, uint64_t addr, int64_t add)
+ : _type(t), _flags(weak_import ? BIND_SYMBOL_FLAGS_WEAK_IMPORT : 0 ), _libraryOrdinal(ord),
+ _symbolName(sym), _address(addr), _addend(add) {}
+ BindingInfo(uint8_t t, const char* sym, bool non_weak_definition, uint64_t addr, int64_t add)
+ : _type(t), _flags(non_weak_definition ? BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION : 0 ),
+ _libraryOrdinal(0), _symbolName(sym), _address(addr), _addend(add) {}
+ uint8_t _type;
+ uint8_t _flags;
+ int _libraryOrdinal;
+ const char* _symbolName;
+ uint64_t _address;
+ int64_t _addend;
+
+ // for sorting
+ int operator<(const BindingInfo& rhs) const {
+ // sort by library, symbol, type, then address
+ if ( this->_libraryOrdinal != rhs._libraryOrdinal )
+ return (this->_libraryOrdinal < rhs._libraryOrdinal );
+ if ( this->_symbolName != rhs._symbolName )
+ return ( strcmp(this->_symbolName, rhs._symbolName) < 0 );
+ if ( this->_type != rhs._type )
+ return (this->_type < rhs._type );
+ return (this->_address < rhs._address );
+ }
+ };
+
+ struct SplitSegInfoEntry {
+ SplitSegInfoEntry(uint64_t a, ld::Fixup::Kind k, uint32_t e=0) : address(a), kind(k), extra(e) {}
+ uint64_t address;
+ ld::Fixup::Kind kind;
+ uint32_t extra;
+ };
+
+private:
+ void writeAtoms(ld::Internal& state, uint8_t* wholeBuffer);
+ void computeContentUUID(ld::Internal& state, uint8_t* wholeBuffer);
+ void buildDylibOrdinalMapping(ld::Internal&);
+ bool hasOrdinalForInstallPath(const char* path, int* ordinal);
+ void addLoadCommands(ld::Internal& state);
+ void addLinkEdit(ld::Internal& state);
+ void addPreloadLinkEdit(ld::Internal& state);
+ void generateLinkEditInfo(ld::Internal& state);
+ void buildSymbolTable(ld::Internal& state);
+ void writeOutputFile(ld::Internal& state);
+ void assignFileOffsets(ld::Internal& state);
+ void setSectionSizesAndAlignments(ld::Internal& state);
+ void addSectionRelocs(ld::Internal& state, ld::Internal::FinalSection* sect,
+ const ld::Atom* atom, ld::Fixup* fixupWithTarget,
+ ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+ const ld::Atom* target, const ld::Atom* minusTarget,
+ uint64_t targetAddend, uint64_t minusTargetAddend);
+ void addDyldInfo(ld::Internal& state, ld::Internal::FinalSection* sect,
+ const ld::Atom* atom, ld::Fixup* fixupWithTarget,
+ ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+ const ld::Atom* target, const ld::Atom* minusTarget,
+ uint64_t targetAddend, uint64_t minusTargetAddend);
+ void addClassicRelocs(ld::Internal& state, ld::Internal::FinalSection* sect,
+ const ld::Atom* atom, ld::Fixup* fixupWithTarget,
+ ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+ const ld::Atom* target, const ld::Atom* minusTarget,
+ uint64_t targetAddend, uint64_t minusTargetAddend);
+ bool useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* target,
+ ld::Fixup* fixupWithTarget);
+ uint64_t pageAlign(uint64_t addr);
+ uint64_t pageAlign(uint64_t addr, uint64_t pageSize);
+ void setLoadCommandsPadding(ld::Internal& state);
+ void assignAtomAddresses(ld::Internal& state);
+ void addRebaseInfo(const ld::Atom* atom, const ld::Fixup* fixup, const ld::Atom* target);
+ void makeRebasingInfo(ld::Internal& state);
+ void makeBindingInfo(ld::Internal& state);
+ void updateLINKEDITAddresses(ld::Internal& state);
+ void applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::Atom* atom, uint8_t* buffer);
+ uint64_t addressOf(const ld::Internal& state, const ld::Fixup* fixup, const ld::Atom** target);
+ bool targetIsThumb(ld::Internal& state, const ld::Fixup* fixup);
+ uint32_t lazyBindingInfoOffsetForLazyPointerAddress(uint64_t lpAddress);
+ void copyNoOps(uint8_t* from, uint8_t* to, bool thumb);
+ bool isPointerToTarget(ld::Fixup::Kind kind);
+ bool isPointerFromTarget(ld::Fixup::Kind kind);
+ bool isPcRelStore(ld::Fixup::Kind kind);
+ bool isStore(ld::Fixup::Kind kind);
+ bool storeAddendOnly(const ld::Atom* inAtom, const ld::Atom* target, bool pcRel=false);
+ bool setsTarget(ld::Fixup::Kind kind);
+ void addFixupOutInfo(ld::Internal& state);
+ void makeRelocations(ld::Internal& state);
+ void makeSectionRelocations(ld::Internal& state);
+ void makeDyldInfo(ld::Internal& state);
+ void makeSplitSegInfo(ld::Internal& state);
+ void writeMapFile(ld::Internal& state);
+ uint64_t lookBackAddend(ld::Fixup::iterator fit);
+ bool takesNoDiskSpace(const ld::Section* sect);
+ bool hasZeroForFileOffset(const ld::Section* sect);
+
+ void printSectionLayout(ld::Internal& state);
+ void rangeCheck8(int64_t delta, ld::Internal& state, const ld::Atom* atom,
+ const ld::Fixup* fixup);
+ void rangeCheck16(int64_t delta, ld::Internal& state, const ld::Atom* atom,
+ const ld::Fixup* fixup);
+ void rangeCheckBranch32(int64_t delta, ld::Internal& state, const ld::Atom* atom,
+ const ld::Fixup* fixup);
+ void rangeCheckAbsolute32(int64_t delta, ld::Internal& state, const ld::Atom* atom,
+ const ld::Fixup* fixup);
+ void rangeCheckRIP32(int64_t delta, ld::Internal& state, const ld::Atom* atom,
+ const ld::Fixup* fixup);
+ void rangeCheckARM12(int64_t delta, ld::Internal& state, const ld::Atom* atom,
+ const ld::Fixup* fixup);
+ void rangeCheckARMBranch24(int64_t delta, ld::Internal& state, const ld::Atom* atom,
+ const ld::Fixup* fixup);
+ void rangeCheckThumbBranch22(int64_t delta, ld::Internal& state, const ld::Atom* atom,
+ const ld::Fixup* fixup);
+ uint64_t sectionOffsetOf(const ld::Internal& state, const ld::Fixup* fixup);
+ uint64_t tlvTemplateOffsetOf(const ld::Internal& state, const ld::Fixup* fixup);
+ void dumpAtomsBySection(ld::Internal& state, bool);
+ void synthesizeDebugNotes(ld::Internal& state);
+ const char* assureFullPath(const char* path);
+ void noteTextReloc(const ld::Atom* atom, const ld::Atom* target);
+
+
+ static uint16_t get16LE(uint8_t* loc);
+ static void set16LE(uint8_t* loc, uint16_t value);
+ static uint32_t get32LE(uint8_t* loc);
+ static void set32LE(uint8_t* loc, uint32_t value);
+ static uint64_t get64LE(uint8_t* loc);
+ static void set64LE(uint8_t* loc, uint64_t value);
+
+ static uint16_t get16BE(uint8_t* loc);
+ static void set16BE(uint8_t* loc, uint16_t value);
+ static uint32_t get32BE(uint8_t* loc);
+ static void set32BE(uint8_t* loc, uint32_t value);
+ static uint64_t get64BE(uint8_t* loc);
+ static void set64BE(uint8_t* loc, uint64_t value);
+
+
+
+ const Options& _options;
+ std::map<const ld::dylib::File*, int> _dylibToOrdinal;
+ std::vector<const ld::dylib::File*> _dylibsToLoad;
+ std::vector<const char*> _dylibOrdinalPaths;
+ const bool _hasDyldInfo;
+ const bool _hasSymbolTable;
+ const bool _hasSectionRelocations;
+ const bool _hasSplitSegInfo;
+ const bool _hasFunctionStartsInfo;
+ const bool _hasDataInCodeInfo;
+ const bool _hasDependentDRInfo;
+ bool _hasDynamicSymbolTable;
+ bool _hasLocalRelocations;
+ bool _hasExternalRelocations;
+ uint64_t _fileSize;
+ std::map<uint64_t, uint32_t> _lazyPointerAddressToInfoOffset;
+ uint32_t _encryptedTEXTstartOffset;
+ uint32_t _encryptedTEXTendOffset;
+public:
+ std::vector<const ld::Atom*> _localAtoms;
+ std::vector<const ld::Atom*> _exportedAtoms;
+ std::vector<const ld::Atom*> _importedAtoms;
+ uint32_t _localSymbolsStartIndex;
+ uint32_t _localSymbolsCount;
+ uint32_t _globalSymbolsStartIndex;
+ uint32_t _globalSymbolsCount;
+ uint32_t _importSymbolsStartIndex;
+ uint32_t _importSymbolsCount;
+ std::map<const ld::Atom*, uint32_t> _atomToSymbolIndex;
+ std::vector<RebaseInfo> _rebaseInfo;
+ std::vector<BindingInfo> _bindingInfo;
+ std::vector<BindingInfo> _lazyBindingInfo;
+ std::vector<BindingInfo> _weakBindingInfo;
+ std::vector<SplitSegInfoEntry> _splitSegInfos;
+ class HeaderAndLoadCommandsAbtract* _headersAndLoadCommandAtom;
+ class RelocationsAtomAbstract* _sectionsRelocationsAtom;
+ class RelocationsAtomAbstract* _localRelocsAtom;
+ class RelocationsAtomAbstract* _externalRelocsAtom;
+ class ClassicLinkEditAtom* _symbolTableAtom;
+ class ClassicLinkEditAtom* _indirectSymbolTableAtom;
+ class StringPoolAtom* _stringPoolAtom;
+ class LinkEditAtom* _rebasingInfoAtom;
+ class LinkEditAtom* _bindingInfoAtom;
+ class LinkEditAtom* _lazyBindingInfoAtom;
+ class LinkEditAtom* _weakBindingInfoAtom;
+ class LinkEditAtom* _exportInfoAtom;
+ class LinkEditAtom* _splitSegInfoAtom;
+ class LinkEditAtom* _functionStartsAtom;
+ class LinkEditAtom* _dataInCodeAtom;
+ class LinkEditAtom* _dependentDRInfoAtom;
+};
+
+} // namespace tool
+} // namespace ld
+
+#endif // __OUTPUT_FILE_H__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+#include <mach-o/fat.h>
+
+#include <string>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+#include <list>
+#include <algorithm>
+#include <ext/hash_map>
+#include <ext/hash_set>
+#include <dlfcn.h>
+#include <AvailabilityMacros.h>
+
+#include "Options.h"
+
+#include "ld.hpp"
+#include "InputFiles.h"
+#include "SymbolTable.h"
+#include "Resolver.h"
+#include "parsers/lto_file.h"
+
+
+namespace ld {
+namespace tool {
+
+
+//
+// An ExportAtom has no content. It exists so that the linker can track which imported
+// symbols came from which dynamic libraries.
+//
+class UndefinedProxyAtom : public ld::Atom
+{
+public:
+ UndefinedProxyAtom(const char* nm)
+ : ld::Atom(_s_section, ld::Atom::definitionProxy,
+ ld::Atom::combineNever, ld::Atom::scopeLinkageUnit,
+ ld::Atom::typeUnclassified,
+ ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(0)),
+ _name(nm) {}
+ // overrides of ld::Atom
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 0; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+
+protected:
+
+ virtual ~UndefinedProxyAtom() {}
+
+ const char* _name;
+
+ static ld::Section _s_section;
+};
+
+ld::Section UndefinedProxyAtom::_s_section("__TEXT", "__import", ld::Section::typeImportProxies, true);
+
+
+
+
+class AliasAtom : public ld::Atom
+{
+public:
+ AliasAtom(const ld::Atom& target, const char* nm) :
+ ld::Atom(target.section(), target.definition(), ld::Atom::combineNever,
+ ld::Atom::scopeGlobal, target.contentType(),
+ target.symbolTableInclusion(), target.dontDeadStrip(),
+ target.isThumb(), true, target.alignment()),
+ _name(nm),
+ _aliasOf(target),
+ _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, &target) { }
+
+ // overrides of ld::Atom
+ virtual const ld::File* file() const { return _aliasOf.file(); }
+ virtual const char* translationUnitSource() const
+ { return _aliasOf.translationUnitSource(); }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 0; }
+ virtual uint64_t objectAddress() const { return _aliasOf.objectAddress(); }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual const uint8_t* rawContentPointer() const { return NULL; }
+ virtual unsigned long contentHash(const class ld::IndirectBindingTable& ibt) const
+ { return _aliasOf.contentHash(ibt); }
+ virtual bool canCoalesceWith(const ld::Atom& rhs, const class ld::IndirectBindingTable& ibt) const
+ { return _aliasOf.canCoalesceWith(rhs,ibt); }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+ virtual ld::Atom::UnwindInfo::iterator beginUnwind() const { return NULL; }
+ virtual ld::Atom::UnwindInfo::iterator endUnwind() const { return NULL; }
+ virtual ld::Atom::LineInfo::iterator beginLineInfo() const { return NULL; }
+ virtual ld::Atom::LineInfo::iterator endLineInfo() const { return NULL; }
+
+private:
+ const char* _name;
+ const ld::Atom& _aliasOf;
+ ld::Fixup _fixup;
+};
+
+
+
+class SectionBoundaryAtom : public ld::Atom
+{
+public:
+ static SectionBoundaryAtom* makeSectionBoundaryAtom(const char* name, bool start, const char* segSectName);
+ static SectionBoundaryAtom* makeOldSectionBoundaryAtom(const char* name, bool start);
+
+ // overrides of ld::Atom
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual const uint8_t* rawContentPointer() const { return NULL; }
+ virtual uint64_t objectAddress() const { return 0; }
+
+private:
+
+ SectionBoundaryAtom(const char* nm, const ld::Section& sect,
+ ld::Atom::ContentType cont) :
+ ld::Atom(sect,
+ ld::Atom::definitionRegular,
+ ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit,
+ cont,
+ ld::Atom::symbolTableNotIn,
+ false, false, true, ld::Atom::Alignment(0)),
+ _name(nm) { }
+
+ const char* _name;
+};
+
+SectionBoundaryAtom* SectionBoundaryAtom::makeSectionBoundaryAtom(const char* name, bool start, const char* segSectName)
+{
+
+ const char* segSectDividor = strrchr(segSectName, '$');
+ if ( segSectDividor == NULL )
+ throwf("malformed section$ symbol name: %s", name);
+ const char* sectionName = segSectDividor + 1;
+ int segNameLen = segSectDividor - segSectName;
+ if ( segNameLen > 16 )
+ throwf("malformed section$ symbol name: %s", name);
+ char segName[18];
+ strlcpy(segName, segSectName, segNameLen+1);
+
+ const ld::Section* section = new ld::Section(strdup(segName), sectionName, ld::Section::typeUnclassified);
+ return new SectionBoundaryAtom(name, *section, (start ? ld::Atom::typeSectionStart : typeSectionEnd));
+}
+
+SectionBoundaryAtom* SectionBoundaryAtom::makeOldSectionBoundaryAtom(const char* name, bool start)
+{
+ // e.g. __DATA__bss__begin
+ char segName[18];
+ strlcpy(segName, name, 7);
+
+ char sectName[18];
+ int nameLen = strlen(name);
+ strlcpy(sectName, &name[6], (start ? nameLen-12 : nameLen-10));
+ warning("grandfathering in old symbol '%s' as alias for 'section$%s$%s$%s'", name, start ? "start" : "end", segName, sectName);
+ const ld::Section* section = new ld::Section(strdup(segName), strdup(sectName), ld::Section::typeUnclassified);
+ return new SectionBoundaryAtom(name, *section, (start ? ld::Atom::typeSectionStart : typeSectionEnd));
+}
+
+
+
+
+class SegmentBoundaryAtom : public ld::Atom
+{
+public:
+ static SegmentBoundaryAtom* makeSegmentBoundaryAtom(const char* name, bool start, const char* segName);
+ static SegmentBoundaryAtom* makeOldSegmentBoundaryAtom(const char* name, bool start);
+
+ // overrides of ld::Atom
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual const uint8_t* rawContentPointer() const { return NULL; }
+ virtual uint64_t objectAddress() const { return 0; }
+
+private:
+
+ SegmentBoundaryAtom(const char* nm, const ld::Section& sect,
+ ld::Atom::ContentType cont) :
+ ld::Atom(sect,
+ ld::Atom::definitionRegular,
+ ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit,
+ cont,
+ ld::Atom::symbolTableNotIn,
+ false, false, true, ld::Atom::Alignment(0)),
+ _name(nm) { }
+
+ const char* _name;
+};
+
+SegmentBoundaryAtom* SegmentBoundaryAtom::makeSegmentBoundaryAtom(const char* name, bool start, const char* segName)
+{
+ if ( *segName == '\0' )
+ throwf("malformed segment$ symbol name: %s", name);
+ if ( strlen(segName) > 16 )
+ throwf("malformed segment$ symbol name: %s", name);
+
+ if ( start ) {
+ const ld::Section* section = new ld::Section(segName, "__start", ld::Section::typeFirstSection, true);
+ return new SegmentBoundaryAtom(name, *section, ld::Atom::typeSectionStart);
+ }
+ else {
+ const ld::Section* section = new ld::Section(segName, "__end", ld::Section::typeLastSection, true);
+ return new SegmentBoundaryAtom(name, *section, ld::Atom::typeSectionEnd);
+ }
+}
+
+SegmentBoundaryAtom* SegmentBoundaryAtom::makeOldSegmentBoundaryAtom(const char* name, bool start)
+{
+ // e.g. __DATA__begin
+ char temp[18];
+ strlcpy(temp, name, 7);
+ char* segName = strdup(temp);
+
+ warning("grandfathering in old symbol '%s' as alias for 'segment$%s$%s'", name, start ? "start" : "end", segName);
+
+ if ( start ) {
+ const ld::Section* section = new ld::Section(segName, "__start", ld::Section::typeFirstSection, true);
+ return new SegmentBoundaryAtom(name, *section, ld::Atom::typeSectionStart);
+ }
+ else {
+ const ld::Section* section = new ld::Section(segName, "__end", ld::Section::typeLastSection, true);
+ return new SegmentBoundaryAtom(name, *section, ld::Atom::typeSectionEnd);
+ }
+}
+
+void Resolver::initializeState()
+{
+ // set initial objc constraint based on command line options
+ if ( _options.objcGc() )
+ _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseOrGC;
+ else if ( _options.objcGcOnly() )
+ _internal.objcObjectConstraint = ld::File::objcConstraintGC;
+
+ _internal.cpuSubType = _options.subArchitecture();
+}
+
+void Resolver::buildAtomList()
+{
+ // each input files contributes initial atoms
+ _atoms.reserve(1024);
+ _inputFiles.forEachInitialAtom(*this);
+
+ _completedInitialObjectFiles = true;
+
+ //_symbolTable.printStatistics();
+}
+
+
+void Resolver::doFile(const ld::File& file)
+{
+ const ld::relocatable::File* objFile = dynamic_cast<const ld::relocatable::File*>(&file);
+ const ld::dylib::File* dylibFile = dynamic_cast<const ld::dylib::File*>(&file);
+
+ if ( objFile != NULL ) {
+ // update which form of ObjC is being used
+ switch ( file.objCConstraint() ) {
+ case ld::File::objcConstraintNone:
+ break;
+ case ld::File::objcConstraintRetainRelease:
+ if ( _internal.objcObjectConstraint == ld::File::objcConstraintGC )
+ throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", file.path());
+ if ( _options.objcGcOnly() )
+ throwf("command line specified -objc_gc_only, but file is retain/release based: %s", file.path());
+ if ( _options.objcGc() )
+ throwf("command line specified -objc_gc, but file is retain/release based: %s", file.path());
+ _internal.objcObjectConstraint = ld::File::objcConstraintRetainRelease;
+ break;
+ case ld::File::objcConstraintRetainReleaseOrGC:
+ if ( _internal.objcObjectConstraint == ld::File::objcConstraintNone )
+ _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseOrGC;
+ break;
+ case ld::File::objcConstraintGC:
+ if ( _internal.objcObjectConstraint == ld::File::objcConstraintRetainRelease )
+ throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", file.path());
+ _internal.objcObjectConstraint = ld::File::objcConstraintGC;
+ break;
+ }
+
+ // in -r mode, if any .o files have dwarf then add UUID to output .o file
+ if ( objFile->debugInfo() == ld::relocatable::File::kDebugInfoDwarf )
+ _internal.someObjectFileHasDwarf = true;
+
+ // remember if any .o file did not have MH_SUBSECTIONS_VIA_SYMBOLS bit set
+ if ( ! objFile->canScatterAtoms() )
+ _internal.allObjectFilesScatterable = false;
+
+ // update cpu-sub-type
+ cpu_subtype_t nextObjectSubType = file.cpuSubType();
+ switch ( _options.architecture() ) {
+ case CPU_TYPE_ARM:
+ if ( _options.subArchitecture() != nextObjectSubType ) {
+ if ( (_options.subArchitecture() == CPU_SUBTYPE_ARM_ALL) && _options.forceCpuSubtypeAll() ) {
+ // hack to support gcc multillib build that tries to make sub-type-all slice
+ }
+ else if ( nextObjectSubType == CPU_SUBTYPE_ARM_ALL ) {
+ warning("CPU_SUBTYPE_ARM_ALL subtype is deprecated: %s", file.path());
+ }
+ else if ( _options.allowSubArchitectureMismatches() ) {
+ //warning("object file %s was built for different arm sub-type (%d) than link command line (%d)",
+ // file.path(), nextObjectSubType, _options.subArchitecture());
+ }
+ else {
+ throwf("object file %s was built for different arm sub-type (%d) than link command line (%d)",
+ file.path(), nextObjectSubType, _options.subArchitecture());
+ }
+ }
+ break;
+
+ case CPU_TYPE_I386:
+ _internal.cpuSubType = CPU_SUBTYPE_I386_ALL;
+ break;
+
+ case CPU_TYPE_X86_64:
+ _internal.cpuSubType = CPU_SUBTYPE_X86_64_ALL;
+ break;
+ }
+ }
+ if ( dylibFile != NULL ) {
+ // update which form of ObjC dylibs are being linked
+ switch ( dylibFile->objCConstraint() ) {
+ case ld::File::objcConstraintNone:
+ break;
+ case ld::File::objcConstraintRetainRelease:
+ if ( _internal.objcDylibConstraint == ld::File::objcConstraintGC )
+ throwf("%s built with incompatible Garbage Collection settings to link with previous dylibs", file.path());
+ if ( _options.objcGcOnly() )
+ throwf("command line specified -objc_gc_only, but dylib is retain/release based: %s", file.path());
+ if ( _options.objcGc() )
+ throwf("command line specified -objc_gc, but dylib is retain/release based: %s", file.path());
+ _internal.objcDylibConstraint = ld::File::objcConstraintRetainRelease;
+ break;
+ case ld::File::objcConstraintRetainReleaseOrGC:
+ if ( _internal.objcDylibConstraint == ld::File::objcConstraintNone )
+ _internal.objcDylibConstraint = ld::File::objcConstraintRetainReleaseOrGC;
+ break;
+ case ld::File::objcConstraintGC:
+ if ( _internal.objcDylibConstraint == ld::File::objcConstraintRetainRelease )
+ throwf("%s built with incompatible Garbage Collection settings to link with previous dylibs", file.path());
+ _internal.objcDylibConstraint = ld::File::objcConstraintGC;
+ break;
+ }
+ }
+
+}
+
+void Resolver::doAtom(const ld::Atom& atom)
+{
+ //fprintf(stderr, "Resolver::doAtom(%p), name=%s, sect=%s\n", &atom, atom.name(), atom.section().sectionName());
+
+ // add to list of known atoms
+ _atoms.push_back(&atom);
+
+ // adjust scope
+ if ( _options.hasExportRestrictList() || _options.hasReExportList() ) {
+ const char* name = atom.name();
+ switch ( atom.scope() ) {
+ case ld::Atom::scopeTranslationUnit:
+ break;
+ case ld::Atom::scopeLinkageUnit:
+ if ( _options.hasExportMaskList() && _options.shouldExport(name) ) {
+ // <rdar://problem/5062685> ld does not report error when -r is used and exported symbols are not defined.
+ if ( _options.outputKind() == Options::kObjectFile )
+ throwf("cannot export hidden symbol %s", name);
+ // .objc_class_name_* symbols are special
+ if ( atom.section().type() != ld::Section::typeObjC1Classes ) {
+ if ( atom.definition() == ld::Atom::definitionProxy ) {
+ // .exp file says to export a symbol, but that symbol is in some dylib being linked
+ if ( _options.canReExportSymbols() ) {
+ // marking proxy atom as global triggers the re-export
+ (const_cast<ld::Atom*>(&atom))->setScope(ld::Atom::scopeGlobal);
+ }
+ else if ( _options.outputKind() == Options::kDynamicLibrary ) {
+ if ( atom.file() != NULL )
+ warning("target OS does not support re-exporting symbol %s from %s\n", _options.demangleSymbol(name), atom.file()->path());
+ else
+ warning("target OS does not support re-exporting symbol %s\n", _options.demangleSymbol(name));
+ }
+ }
+ else {
+ if ( atom.file() != NULL )
+ warning("cannot export hidden symbol %s from %s", _options.demangleSymbol(name), atom.file()->path());
+ else
+ warning("cannot export hidden symbol %s", _options.demangleSymbol(name));
+ }
+ }
+ }
+ else if ( _options.shouldReExport(name) && _options.canReExportSymbols() ) {
+ if ( atom.definition() == ld::Atom::definitionProxy ) {
+ // marking proxy atom as global triggers the re-export
+ (const_cast<ld::Atom*>(&atom))->setScope(ld::Atom::scopeGlobal);
+ }
+ else {
+ throwf("requested re-export symbol %s is not from a dylib, but from %s\n", _options.demangleSymbol(name), atom.file()->path());
+ }
+ }
+ break;
+ case ld::Atom::scopeGlobal:
+ // check for globals that are downgraded to hidden
+ if ( ! _options.shouldExport(name) ) {
+ (const_cast<ld::Atom*>(&atom))->setScope(ld::Atom::scopeLinkageUnit);
+ //fprintf(stderr, "demote %s to hidden\n", name);
+ }
+ if ( _options.canReExportSymbols() && _options.shouldReExport(name) ) {
+ throwf("requested re-export symbol %s is not from a dylib, but from %s\n", _options.demangleSymbol(name), atom.file()->path());
+ }
+ break;
+ }
+ }
+
+ // work around for kernel that uses 'l' labels in assembly code
+ if ( (atom.symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages)
+ && (atom.name()[0] == 'l') && (_options.outputKind() == Options::kStaticExecutable) )
+ (const_cast<ld::Atom*>(&atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
+
+
+ // tell symbol table about non-static atoms
+ if ( atom.scope() != ld::Atom::scopeTranslationUnit ) {
+ _symbolTable.add(atom, _options.deadCodeStrip() && _completedInitialObjectFiles);
+
+ // add symbol aliases defined on the command line
+ if ( _options.haveCmdLineAliases() ) {
+ const std::vector<Options::AliasPair>& aliases = _options.cmdLineAliases();
+ for (std::vector<Options::AliasPair>::const_iterator it=aliases.begin(); it != aliases.end(); ++it) {
+ if ( strcmp(it->realName, atom.name()) == 0 ) {
+ const ld::Atom* alias = new AliasAtom(atom, it->alias);
+ this->doAtom(*alias);
+ }
+ }
+ }
+ }
+
+ // convert references by-name or by-content to by-slot
+ this->convertReferencesToIndirect(atom);
+
+ // remember if any atoms are proxies that require LTO
+ if ( atom.contentType() == ld::Atom::typeLTOtemporary )
+ _haveLLVMObjs = true;
+
+ if ( _options.deadCodeStrip() ) {
+ // add to set of dead-strip-roots, all symbols that the compiler marks as don't strip
+ if ( atom.dontDeadStrip() )
+ _deadStripRoots.insert(&atom);
+
+ if ( atom.scope() == ld::Atom::scopeGlobal ) {
+ // <rdar://problem/5524973> -exported_symbols_list that has wildcards and -dead_strip
+ // in dylibs, every global atom in initial .o files is a root
+ if ( _options.hasWildCardExportRestrictList() || _options.allGlobalsAreDeadStripRoots() ) {
+ if ( _options.shouldExport(atom.name()) )
+ _deadStripRoots.insert(&atom);
+ }
+ }
+ }
+}
+
+bool Resolver::isDtraceProbe(ld::Fixup::Kind kind)
+{
+ switch (kind) {
+ case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+ case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+ case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+ case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+ case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+ case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+ case ld::Fixup::kindDtraceExtra:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+void Resolver::convertReferencesToIndirect(const ld::Atom& atom)
+{
+ // convert references by-name or by-content to by-slot
+ SymbolTable::IndirectBindingSlot slot;
+ const ld::Atom* dummy;
+ ld::Fixup::iterator end = atom.fixupsEnd();
+ for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != end; ++fit) {
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingByNameUnbound:
+ if ( isDtraceProbe(fit->kind) && (_options.outputKind() != Options::kObjectFile ) ) {
+ // in final linked images, remove reference
+ fit->binding = ld::Fixup::bindingNone;
+ }
+ else {
+ slot = _symbolTable.findSlotForName(fit->u.name);
+ fit->binding = ld::Fixup::bindingsIndirectlyBound;
+ fit->u.bindingIndex = slot;
+ }
+ break;
+ case ld::Fixup::bindingByContentBound:
+ switch ( fit->u.target->combine() ) {
+ case ld::Atom::combineNever:
+ case ld::Atom::combineByName:
+ assert(0 && "wrong combine type for bind by content");
+ break;
+ case ld::Atom::combineByNameAndContent:
+ slot = _symbolTable.findSlotForContent(fit->u.target, &dummy);
+ fit->binding = ld::Fixup::bindingsIndirectlyBound;
+ fit->u.bindingIndex = slot;
+ break;
+ case ld::Atom::combineByNameAndReferences:
+ slot = _symbolTable.findSlotForReferences(fit->u.target, &dummy);
+ fit->binding = ld::Fixup::bindingsIndirectlyBound;
+ fit->u.bindingIndex = slot;
+ break;
+ }
+ break;
+ case ld::Fixup::bindingNone:
+ case ld::Fixup::bindingDirectlyBound:
+ case ld::Fixup::bindingsIndirectlyBound:
+ break;
+ }
+ }
+}
+
+
+void Resolver::addInitialUndefines()
+{
+ // add initial undefines from -u option
+ for (Options::UndefinesIterator it=_options.initialUndefinesBegin(); it != _options.initialUndefinesEnd(); ++it) {
+ _symbolTable.findSlotForName(*it);
+ }
+}
+
+void Resolver::resolveUndefines()
+{
+ // keep looping until no more undefines were added in last loop
+ unsigned int undefineGenCount = 0xFFFFFFFF;
+ while ( undefineGenCount != _symbolTable.updateCount() ) {
+ undefineGenCount = _symbolTable.updateCount();
+ std::vector<const char*> undefineNames;
+ _symbolTable.undefines(undefineNames);
+ for(std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
+ const char* undef = *it;
+ // load for previous undefine may also have loaded this undefine, so check again
+ if ( ! _symbolTable.hasName(undef) ) {
+ _inputFiles.searchLibraries(undef, true, true, false, *this);
+ if ( !_symbolTable.hasName(undef) && (_options.outputKind() != Options::kObjectFile) ) {
+ if ( strncmp(undef, "section$", 8) == 0 ) {
+ if ( strncmp(undef, "section$start$", 14) == 0 ) {
+ this->doAtom(*SectionBoundaryAtom::makeSectionBoundaryAtom(undef, true, &undef[14]));
+ }
+ else if ( strncmp(undef, "section$end$", 12) == 0 ) {
+ this->doAtom(*SectionBoundaryAtom::makeSectionBoundaryAtom(undef, false, &undef[12]));
+ }
+ }
+ else if ( strncmp(undef, "segment$", 8) == 0 ) {
+ if ( strncmp(undef, "segment$start$", 14) == 0 ) {
+ this->doAtom(*SegmentBoundaryAtom::makeSegmentBoundaryAtom(undef, true, &undef[14]));
+ }
+ else if ( strncmp(undef, "segment$end$", 12) == 0 ) {
+ this->doAtom(*SegmentBoundaryAtom::makeSegmentBoundaryAtom(undef, false, &undef[12]));
+ }
+ }
+ else if ( _options.outputKind() == Options::kPreload ) {
+ // for iBoot grandfather in old style section labels
+ int undefLen = strlen(undef);
+ if ( strcmp(&undef[undefLen-7], "__begin") == 0 ) {
+ if ( undefLen > 13 )
+ this->doAtom(*SectionBoundaryAtom::makeOldSectionBoundaryAtom(undef, true));
+ else
+ this->doAtom(*SegmentBoundaryAtom::makeOldSegmentBoundaryAtom(undef, true));
+ }
+ else if ( strcmp(&undef[undefLen-5], "__end") == 0 ) {
+ if ( undefLen > 11 )
+ this->doAtom(*SectionBoundaryAtom::makeOldSectionBoundaryAtom(undef, false));
+ else
+ this->doAtom(*SegmentBoundaryAtom::makeOldSegmentBoundaryAtom(undef, false));
+ }
+ }
+ }
+ }
+ }
+ // <rdar://problem/5894163> need to search archives for overrides of common symbols
+ if ( _symbolTable.hasExternalTentativeDefinitions() ) {
+ bool searchDylibs = (_options.commonsMode() == Options::kCommonsOverriddenByDylibs);
+ std::vector<const char*> tents;
+ _symbolTable.tentativeDefs(tents);
+ for(std::vector<const char*>::iterator it = tents.begin(); it != tents.end(); ++it) {
+ // load for previous tentative may also have loaded this tentative, so check again
+ const ld::Atom* curAtom = _symbolTable.atomForSlot(_symbolTable.findSlotForName(*it));
+ assert(curAtom != NULL);
+ if ( curAtom->definition() == ld::Atom::definitionTentative ) {
+ _inputFiles.searchLibraries(*it, searchDylibs, true, true, *this);
+ }
+ }
+ }
+ }
+
+ // create proxies as needed for undefined symbols
+ if ( (_options.undefinedTreatment() != Options::kUndefinedError) || (_options.outputKind() == Options::kObjectFile) ) {
+ std::vector<const char*> undefineNames;
+ _symbolTable.undefines(undefineNames);
+ for(std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
+ // make proxy
+ this->doAtom(*new UndefinedProxyAtom(*it));
+ }
+ }
+
+ // support -U option
+ if ( _options.someAllowedUndefines() ) {
+ std::vector<const char*> undefineNames;
+ _symbolTable.undefines(undefineNames);
+ for(std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
+ if ( _options.allowedUndefined(*it) ) {
+ // make proxy
+ this->doAtom(*new UndefinedProxyAtom(*it));
+ }
+ }
+ }
+
+}
+
+
+void Resolver::markLive(const ld::Atom& atom, WhyLiveBackChain* previous)
+{
+ //fprintf(stderr, "markLive(%p) %s\n", &atom, atom.name());
+ // if -why_live cares about this symbol, then dump chain
+ if ( (previous->referer != NULL) && _options.printWhyLive(atom.name()) ) {
+ fprintf(stderr, "%s from %s\n", atom.name(), atom.file()->path());
+ int depth = 1;
+ for(WhyLiveBackChain* p = previous; p != NULL; p = p->previous, ++depth) {
+ for(int i=depth; i > 0; --i)
+ fprintf(stderr, " ");
+ fprintf(stderr, "%s from %s\n", p->referer->name(), p->referer->file()->path());
+ }
+ }
+
+ // if already marked live, then done (stop recursion)
+ if ( atom.live() )
+ return;
+
+ // mark this atom is live
+ (const_cast<ld::Atom*>(&atom))->setLive();
+
+ // mark all atoms it references as live
+ WhyLiveBackChain thisChain;
+ thisChain.previous = previous;
+ thisChain.referer = &atom;
+ for (ld::Fixup::iterator fit = atom.fixupsBegin(), end=atom.fixupsEnd(); fit != end; ++fit) {
+ const ld::Atom* target;
+ switch ( fit->kind ) {
+ case ld::Fixup::kindNone:
+ case ld::Fixup::kindNoneFollowOn:
+ case ld::Fixup::kindNoneGroupSubordinate:
+ case ld::Fixup::kindNoneGroupSubordinateFDE:
+ case ld::Fixup::kindNoneGroupSubordinateLSDA:
+ case ld::Fixup::kindSetTargetAddress:
+ case ld::Fixup::kindSubtractTargetAddress:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+ case ld::Fixup::kindStoreTargetAddressBigEndian32:
+ case ld::Fixup::kindStoreTargetAddressBigEndian64:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+ case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
+ case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+ case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA:
+ case ld::Fixup::kindStoreTargetAddressARMBranch24:
+ case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+ if ( fit->binding == ld::Fixup::bindingByContentBound ) {
+ // normally this was done in convertReferencesToIndirect()
+ // but a archive loaded .o file may have a forward reference
+ SymbolTable::IndirectBindingSlot slot;
+ const ld::Atom* dummy;
+ switch ( fit->u.target->combine() ) {
+ case ld::Atom::combineNever:
+ case ld::Atom::combineByName:
+ assert(0 && "wrong combine type for bind by content");
+ break;
+ case ld::Atom::combineByNameAndContent:
+ slot = _symbolTable.findSlotForContent(fit->u.target, &dummy);
+ fit->binding = ld::Fixup::bindingsIndirectlyBound;
+ fit->u.bindingIndex = slot;
+ break;
+ case ld::Atom::combineByNameAndReferences:
+ slot = _symbolTable.findSlotForReferences(fit->u.target, &dummy);
+ fit->binding = ld::Fixup::bindingsIndirectlyBound;
+ fit->u.bindingIndex = slot;
+ break;
+ }
+ }
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingDirectlyBound:
+ markLive(*(fit->u.target), &thisChain);
+ break;
+ case ld::Fixup::bindingByNameUnbound:
+ // doAtom() did not convert to indirect in dead-strip mode, so that now
+ fit->u.bindingIndex = _symbolTable.findSlotForName(fit->u.name);
+ fit->binding = ld::Fixup::bindingsIndirectlyBound;
+ // fall into next case
+ case ld::Fixup::bindingsIndirectlyBound:
+ target = _internal.indirectBindingTable[fit->u.bindingIndex];
+ if ( target == NULL ) {
+ const char* targetName = _symbolTable.indirectName(fit->u.bindingIndex);
+ _inputFiles.searchLibraries(targetName, true, true, false, *this);
+ target = _internal.indirectBindingTable[fit->u.bindingIndex];
+ }
+ if ( target != NULL ) {
+ if ( target->definition() == ld::Atom::definitionTentative ) {
+ // <rdar://problem/5894163> need to search archives for overrides of common symbols
+ bool searchDylibs = (_options.commonsMode() == Options::kCommonsOverriddenByDylibs);
+ _inputFiles.searchLibraries(target->name(), searchDylibs, true, true, *this);
+ // recompute target since it may have been overridden by searchLibraries()
+ target = _internal.indirectBindingTable[fit->u.bindingIndex];
+ }
+ this->markLive(*target, &thisChain);
+ }
+ else {
+ _atomsWithUnresolvedReferences.push_back(&atom);
+ }
+ break;
+ default:
+ assert(0 && "bad binding during dead stripping");
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+}
+
+class NotLiveLTO {
+public:
+ bool operator()(const ld::Atom* atom) const {
+ if (atom->live() || atom->dontDeadStrip() )
+ return false;
+ // don't kill combinable atoms in first pass
+ switch ( atom->combine() ) {
+ case ld::Atom::combineByNameAndContent:
+ case ld::Atom::combineByNameAndReferences:
+ return false;
+ default:
+ return true;
+ }
+ }
+};
+
+void Resolver::deadStripOptimize(bool force)
+{
+ // only do this optimization with -dead_strip
+ if ( ! _options.deadCodeStrip() )
+ return;
+
+ // add entry point (main) to live roots
+ const ld::Atom* entry = this->entryPoint(true);
+ if ( entry != NULL )
+ _deadStripRoots.insert(entry);
+
+ // add -exported_symbols_list, -init, and -u entries to live roots
+ for (Options::UndefinesIterator uit=_options.initialUndefinesBegin(); uit != _options.initialUndefinesEnd(); ++uit) {
+ SymbolTable::IndirectBindingSlot slot = _symbolTable.findSlotForName(*uit);
+ if ( _internal.indirectBindingTable[slot] == NULL ) {
+ _inputFiles.searchLibraries(*uit, false, true, false, *this);
+ }
+ if ( _internal.indirectBindingTable[slot] != NULL )
+ _deadStripRoots.insert(_internal.indirectBindingTable[slot]);
+ }
+
+ // this helper is only referenced by synthesize stubs, assume it will be used
+ if ( _internal.classicBindingHelper != NULL )
+ _deadStripRoots.insert(_internal.classicBindingHelper);
+
+ // this helper is only referenced by synthesize stubs, assume it will be used
+ if ( _internal.compressedFastBinderProxy != NULL )
+ _deadStripRoots.insert(_internal.compressedFastBinderProxy);
+
+ // this helper is only referenced by synthesized lazy stubs, assume it will be used
+ if ( _internal.lazyBindingHelper != NULL )
+ _deadStripRoots.insert(_internal.lazyBindingHelper);
+
+ // add all dont-dead-strip atoms as roots
+ for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ const ld::Atom* atom = *it;
+ if ( atom->dontDeadStrip() ) {
+ //fprintf(stderr, "dont dead strip: %p %s %s\n", atom, atom->section().sectionName(), atom->name());
+ _deadStripRoots.insert(atom);
+ // unset liveness, so markLive() will recurse
+ (const_cast<ld::Atom*>(atom))->setLive(0);
+ }
+ }
+
+ // mark all roots as live, and all atoms they reference
+ for (std::set<const ld::Atom*>::iterator it=_deadStripRoots.begin(); it != _deadStripRoots.end(); ++it) {
+ WhyLiveBackChain rootChain;
+ rootChain.previous = NULL;
+ rootChain.referer = *it;
+ this->markLive(**it, &rootChain);
+ }
+
+ // now remove all non-live atoms from _atoms
+ const bool log = false;
+ if ( log ) {
+ fprintf(stderr, "deadStripOptimize() all %ld atoms with liveness:\n", _atoms.size());
+ for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ const ld::File* file = (*it)->file();
+ fprintf(stderr, " live=%d atom=%p name=%s from=%s\n", (*it)->live(), *it, (*it)->name(), (file ? file->path() : "<internal>"));
+ }
+ }
+
+ if ( _haveLLVMObjs && !force ) {
+ // <rdar://problem/9777977> don't remove combinable atoms, they may come back in lto output
+ _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), NotLiveLTO()), _atoms.end());
+ }
+ else {
+ _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), NotLive()), _atoms.end());
+ }
+
+ if ( log ) {
+ fprintf(stderr, "deadStripOptimize() %ld remaining atoms\n", _atoms.size());
+ for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ fprintf(stderr, " live=%d atom=%p name=%s\n", (*it)->live(), *it, (*it)->name());
+ }
+ }
+}
+
+
+// This is called when LTO is used but -dead_strip is not used.
+// Some undefines were eliminated by LTO, but others were not.
+void Resolver::remainingUndefines(std::vector<const char*>& undefs)
+{
+ StringSet undefSet;
+ // search all atoms for references that are unbound
+ for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ const ld::Atom* atom = *it;
+ for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ switch ( (ld::Fixup::TargetBinding)fit->binding ) {
+ case ld::Fixup::bindingByNameUnbound:
+ assert(0 && "should not be by-name this late");
+ undefSet.insert(fit->u.name);
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ if ( _internal.indirectBindingTable[fit->u.bindingIndex] == NULL ) {
+ undefSet.insert(_symbolTable.indirectName(fit->u.bindingIndex));
+ }
+ break;
+ case ld::Fixup::bindingByContentBound:
+ case ld::Fixup::bindingNone:
+ case ld::Fixup::bindingDirectlyBound:
+ break;
+ }
+ }
+ }
+ // look for any initial undefines that are still undefined
+ for (Options::UndefinesIterator uit=_options.initialUndefinesBegin(); uit != _options.initialUndefinesEnd(); ++uit) {
+ if ( ! _symbolTable.hasName(*uit) ) {
+ undefSet.insert(*uit);
+ }
+ }
+
+ // copy set to vector
+ for (StringSet::const_iterator it=undefSet.begin(); it != undefSet.end(); ++it) {
+ fprintf(stderr, "undef: %s\n", *it);
+ undefs.push_back(*it);
+ }
+}
+
+void Resolver::liveUndefines(std::vector<const char*>& undefs)
+{
+ StringSet undefSet;
+ // search all live atoms for references that are unbound
+ for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ const ld::Atom* atom = *it;
+ if ( ! atom->live() )
+ continue;
+ for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ switch ( (ld::Fixup::TargetBinding)fit->binding ) {
+ case ld::Fixup::bindingByNameUnbound:
+ assert(0 && "should not be by-name this late");
+ undefSet.insert(fit->u.name);
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ if ( _internal.indirectBindingTable[fit->u.bindingIndex] == NULL ) {
+ undefSet.insert(_symbolTable.indirectName(fit->u.bindingIndex));
+ }
+ break;
+ case ld::Fixup::bindingByContentBound:
+ case ld::Fixup::bindingNone:
+ case ld::Fixup::bindingDirectlyBound:
+ break;
+ }
+ }
+ }
+ // look for any initial undefines that are still undefined
+ for (Options::UndefinesIterator uit=_options.initialUndefinesBegin(); uit != _options.initialUndefinesEnd(); ++uit) {
+ if ( ! _symbolTable.hasName(*uit) ) {
+ undefSet.insert(*uit);
+ }
+ }
+
+ // copy set to vector
+ for (StringSet::const_iterator it=undefSet.begin(); it != undefSet.end(); ++it) {
+ undefs.push_back(*it);
+ }
+}
+
+
+
+// <rdar://problem/8252819> warn when .objc_class_name_* symbol missing
+class ExportedObjcClass
+{
+public:
+ ExportedObjcClass(const Options& opt) : _options(opt) {}
+
+ bool operator()(const char* name) const {
+ if ( (strncmp(name, ".objc_class_name_", 17) == 0) && _options.shouldExport(name) ) {
+ warning("ignoring undefined symbol %s from -exported_symbols_list", name);
+ return true;
+ }
+ const char* s = strstr(name, "CLASS_$_");
+ if ( s != NULL ) {
+ char temp[strlen(name)+16];
+ strcpy(temp, ".objc_class_name_");
+ strcat(temp, &s[8]);
+ if ( _options.wasRemovedExport(temp) ) {
+ warning("ignoring undefined symbol %s from -exported_symbols_list", temp);
+ return true;
+ }
+ }
+ return false;
+ }
+private:
+ const Options& _options;
+};
+
+
+// temp hack for undefined aliases
+class UndefinedAlias
+{
+public:
+ UndefinedAlias(const Options& opt) : _aliases(opt.cmdLineAliases()) {}
+
+ bool operator()(const char* name) const {
+ for (std::vector<Options::AliasPair>::const_iterator it=_aliases.begin(); it != _aliases.end(); ++it) {
+ if ( strcmp(it->realName, name) == 0 ) {
+ warning("undefined base symbol '%s' for alias '%s'", name, it->alias);
+ return true;
+ }
+ }
+ return false;
+ }
+private:
+ const std::vector<Options::AliasPair>& _aliases;
+};
+
+
+
+static const char* pathLeafName(const char* path)
+{
+ const char* shortPath = strrchr(path, '/');
+ if ( shortPath == NULL )
+ return path;
+ else
+ return &shortPath[1];
+}
+
+bool Resolver::printReferencedBy(const char* name, SymbolTable::IndirectBindingSlot slot)
+{
+ unsigned foundReferenceCount = 0;
+ for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ const ld::Atom* atom = *it;
+ for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ if ( fit->binding == ld::Fixup::bindingsIndirectlyBound ) {
+ if ( fit->u.bindingIndex == slot ) {
+ if ( atom->contentType() == ld::Atom::typeNonLazyPointer ) {
+ const ld::Atom* existingAtom;
+ unsigned int nlSlot = _symbolTable.findSlotForReferences(atom, &existingAtom);
+ if ( printReferencedBy(name, nlSlot) )
+ ++foundReferenceCount;
+ }
+ else if ( atom->contentType() == ld::Atom::typeCFI ) {
+ fprintf(stderr, " Dwarf Exception Unwind Info (__eh_frame) in %s\n", pathLeafName(atom->file()->path()));
+ ++foundReferenceCount;
+ }
+ else {
+ fprintf(stderr, " %s in %s\n", _options.demangleSymbol(atom->name()), pathLeafName(atom->file()->path()));
+ ++foundReferenceCount;
+ break; // if undefined used twice in a function, only show first
+ }
+ }
+ }
+ }
+ if ( foundReferenceCount > 6 ) {
+ fprintf(stderr, " ...\n");
+ break; // only show first six uses of undefined symbol
+ }
+ }
+ return (foundReferenceCount != 0);
+}
+
+void Resolver::checkUndefines(bool force)
+{
+ // when using LTO, undefines are checked after bitcode is optimized
+ if ( _haveLLVMObjs && !force )
+ return;
+
+ // error out on any remaining undefines
+ bool doPrint = true;
+ bool doError = true;
+ switch ( _options.undefinedTreatment() ) {
+ case Options::kUndefinedError:
+ break;
+ case Options::kUndefinedDynamicLookup:
+ doError = false;
+ break;
+ case Options::kUndefinedWarning:
+ doError = false;
+ break;
+ case Options::kUndefinedSuppress:
+ doError = false;
+ doPrint = false;
+ break;
+ }
+ std::vector<const char*> unresolvableUndefines;
+ if ( _options.deadCodeStrip() )
+ this->liveUndefines(unresolvableUndefines);
+ else if( _haveLLVMObjs )
+ this->remainingUndefines(unresolvableUndefines); // <rdar://problem/10052396> LTO may have eliminated need for some undefines
+ else
+ _symbolTable.undefines(unresolvableUndefines);
+
+ // <rdar://problem/8252819> assert when .objc_class_name_* symbol missing
+ if ( _options.hasExportMaskList() ) {
+ unresolvableUndefines.erase(std::remove_if(unresolvableUndefines.begin(), unresolvableUndefines.end(), ExportedObjcClass(_options)), unresolvableUndefines.end());
+ }
+
+ // hack to temporarily make missing aliases a warning
+ if ( _options.haveCmdLineAliases() ) {
+ unresolvableUndefines.erase(std::remove_if(unresolvableUndefines.begin(), unresolvableUndefines.end(), UndefinedAlias(_options)), unresolvableUndefines.end());
+ }
+
+ const int unresolvableCount = unresolvableUndefines.size();
+ int unresolvableExportsCount = 0;
+ if ( unresolvableCount != 0 ) {
+ if ( doPrint ) {
+ if ( _options.printArchPrefix() )
+ fprintf(stderr, "Undefined symbols for architecture %s:\n", _options.architectureName());
+ else
+ fprintf(stderr, "Undefined symbols:\n");
+ for (int i=0; i < unresolvableCount; ++i) {
+ const char* name = unresolvableUndefines[i];
+ unsigned int slot = _symbolTable.findSlotForName(name);
+ fprintf(stderr, " \"%s\", referenced from:\n", _options.demangleSymbol(name));
+ // scan all atoms for references
+ bool foundAtomReference = printReferencedBy(name, slot);
+ // scan command line options
+ if ( !foundAtomReference ) {
+ // might be from -init command line option
+ if ( (_options.initFunctionName() != NULL) && (strcmp(name, _options.initFunctionName()) == 0) ) {
+ fprintf(stderr, " -init command line option\n");
+ }
+ // or might be from exported symbol option
+ else if ( _options.hasExportMaskList() && _options.shouldExport(name) ) {
+ fprintf(stderr, " -exported_symbol[s_list] command line option\n");
+ }
+ // or might be from re-exported symbol option
+ else if ( _options.hasReExportList() && _options.shouldReExport(name) ) {
+ fprintf(stderr, " -reexported_symbols_list command line option\n");
+ }
+ else {
+ bool isInitialUndefine = false;
+ for (Options::UndefinesIterator uit=_options.initialUndefinesBegin(); uit != _options.initialUndefinesEnd(); ++uit) {
+ if ( strcmp(*uit, name) == 0 ) {
+ isInitialUndefine = true;
+ break;
+ }
+ }
+ if ( isInitialUndefine )
+ fprintf(stderr, " -u command line option\n");
+ }
+ ++unresolvableExportsCount;
+ }
+ // be helpful and check for typos
+ bool printedStart = false;
+ for (SymbolTable::byNameIterator sit=_symbolTable.begin(); sit != _symbolTable.end(); sit++) {
+ const ld::Atom* atom = *sit;
+ if ( (atom != NULL) && (atom->symbolTableInclusion() == ld::Atom::symbolTableIn) && (strstr(atom->name(), name) != NULL) ) {
+ if ( ! printedStart ) {
+ fprintf(stderr, " (maybe you meant: %s", atom->name());
+ printedStart = true;
+ }
+ else {
+ fprintf(stderr, ", %s ", atom->name());
+ }
+ }
+ }
+ if ( printedStart )
+ fprintf(stderr, ")\n");
+ // <rdar://problem/8989530> Add comment to error message when __ZTV symbols are undefined
+ if ( strncmp(name, "__ZTV", 5) == 0 ) {
+ fprintf(stderr, " NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.\n");
+ }
+ }
+ }
+ if ( doError )
+ throw "symbol(s) not found";
+ }
+
+}
+
+
+
+void Resolver::checkDylibSymbolCollisions()
+{
+ for (SymbolTable::byNameIterator it=_symbolTable.begin(); it != _symbolTable.end(); it++) {
+ const ld::Atom* atom = *it;
+ if ( atom == NULL )
+ continue;
+ if ( atom->scope() == ld::Atom::scopeGlobal ) {
+ // <rdar://problem/5048861> No warning about tentative definition conflicting with dylib definition
+ // for each tentative definition in symbol table look for dylib that exports same symbol name
+ if ( atom->definition() == ld::Atom::definitionTentative ) {
+ _inputFiles.searchLibraries(atom->name(), true, false, false, *this);
+ }
+ // record any overrides of weak symbols in any linked dylib
+ if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->symbolTableInclusion() == ld::Atom::symbolTableIn) ) {
+ if ( _inputFiles.searchWeakDefInDylib(atom->name()) )
+ (const_cast<ld::Atom*>(atom))->setOverridesDylibsWeakDef();
+ }
+ }
+ }
+}
+
+
+const ld::Atom* Resolver::entryPoint(bool searchArchives)
+{
+ const char* symbolName = NULL;
+ bool makingDylib = false;
+ switch ( _options.outputKind() ) {
+ case Options::kDynamicExecutable:
+ case Options::kStaticExecutable:
+ case Options::kDyld:
+ case Options::kPreload:
+ symbolName = _options.entryName();
+ break;
+ case Options::kDynamicLibrary:
+ symbolName = _options.initFunctionName();
+ makingDylib = true;
+ break;
+ case Options::kObjectFile:
+ case Options::kDynamicBundle:
+ case Options::kKextBundle:
+ return NULL;
+ break;
+ }
+ if ( symbolName != NULL ) {
+ SymbolTable::IndirectBindingSlot slot = _symbolTable.findSlotForName(symbolName);
+ if ( (_internal.indirectBindingTable[slot] == NULL) && searchArchives ) {
+ // <rdar://problem/7043256> ld64 can not find a -e entry point from an archive
+ _inputFiles.searchLibraries(symbolName, false, true, false, *this);
+ }
+ if ( _internal.indirectBindingTable[slot] == NULL ) {
+ if ( strcmp(symbolName, "start") == 0 )
+ throwf("entry point (%s) undefined. Usually in crt1.o", symbolName);
+ else
+ throwf("entry point (%s) undefined.", symbolName);
+ }
+ else if ( _internal.indirectBindingTable[slot]->definition() == ld::Atom::definitionProxy ) {
+ if ( makingDylib )
+ throwf("-init function (%s) found in linked dylib, must be in dylib being linked", symbolName);
+ }
+ return _internal.indirectBindingTable[slot];
+ }
+ return NULL;
+}
+
+
+void Resolver::fillInHelpersInInternalState()
+{
+ // look up well known atoms
+ bool needsStubHelper = true;
+ switch ( _options.outputKind() ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ needsStubHelper = true;
+ break;
+ case Options::kDyld:
+ case Options::kKextBundle:
+ case Options::kObjectFile:
+ case Options::kStaticExecutable:
+ case Options::kPreload:
+ needsStubHelper = false;
+ break;
+ }
+
+ _internal.classicBindingHelper = NULL;
+ if ( needsStubHelper && !_options.makeCompressedDyldInfo() ) {
+ // "dyld_stub_binding_helper" comes from .o file, so should already exist in symbol table
+ if ( _symbolTable.hasName("dyld_stub_binding_helper") ) {
+ SymbolTable::IndirectBindingSlot slot = _symbolTable.findSlotForName("dyld_stub_binding_helper");
+ _internal.classicBindingHelper = _internal.indirectBindingTable[slot];
+ }
+ }
+
+ _internal.lazyBindingHelper = NULL;
+ if ( _options.usingLazyDylibLinking() ) {
+ // "dyld_lazy_dylib_stub_binding_helper" comes from lazydylib1.o file, so should already exist in symbol table
+ if ( _symbolTable.hasName("dyld_lazy_dylib_stub_binding_helper") ) {
+ SymbolTable::IndirectBindingSlot slot = _symbolTable.findSlotForName("dyld_lazy_dylib_stub_binding_helper");
+ _internal.lazyBindingHelper = _internal.indirectBindingTable[slot];
+ }
+ if ( _internal.lazyBindingHelper == NULL )
+ throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
+ }
+
+ _internal.compressedFastBinderProxy = NULL;
+ if ( needsStubHelper && _options.makeCompressedDyldInfo() ) {
+ // "dyld_stub_binder" comes from libSystem.dylib so will need to manually resolve
+ if ( !_symbolTable.hasName("dyld_stub_binder") ) {
+ _inputFiles.searchLibraries("dyld_stub_binder", true, false, false, *this);
+ }
+ if ( _symbolTable.hasName("dyld_stub_binder") ) {
+ SymbolTable::IndirectBindingSlot slot = _symbolTable.findSlotForName("dyld_stub_binder");
+ _internal.compressedFastBinderProxy = _internal.indirectBindingTable[slot];
+ }
+ if ( _internal.compressedFastBinderProxy == NULL ) {
+ if ( _options.undefinedTreatment() != Options::kUndefinedError ) {
+ // make proxy
+ _internal.compressedFastBinderProxy = new UndefinedProxyAtom("dyld_stub_binder");
+ this->doAtom(*_internal.compressedFastBinderProxy);
+ }
+ }
+ }
+}
+
+
+void Resolver::fillInInternalState()
+{
+ // store atoms into their final section
+ for (std::vector<const ld::Atom*>::iterator it = _atoms.begin(); it != _atoms.end(); ++it) {
+ _internal.addAtom(**it);
+ }
+
+ // <rdar://problem/7783918> make sure there is a __text section so that codesigning works
+ if ( (_options.outputKind() == Options::kDynamicLibrary) || (_options.outputKind() == Options::kDynamicBundle) )
+ _internal.getFinalSection(ld::Section("__TEXT", "__text", ld::Section::typeCode));
+}
+
+void Resolver::fillInEntryPoint()
+{
+ _internal.entryPoint = this->entryPoint(true);
+}
+
+
+
+void Resolver::removeCoalescedAwayAtoms()
+{
+ const bool log = false;
+ if ( log ) {
+ fprintf(stderr, "removeCoalescedAwayAtoms() starts with %lu atoms\n", _atoms.size());
+ }
+ _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), AtomCoalescedAway()), _atoms.end());
+ if ( log ) {
+ fprintf(stderr, "removeCoalescedAwayAtoms() after removing coalesced atoms, %lu remain\n", _atoms.size());
+ for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ fprintf(stderr, " atom=%p %s\n", *it, (*it)->name());
+ }
+ }
+}
+
+void Resolver::linkTimeOptimize()
+{
+ // only do work here if some llvm obj files where loaded
+ if ( ! _haveLLVMObjs )
+ return;
+
+ // run LLVM lto code-gen
+ lto::OptimizeOptions optOpt;
+ optOpt.outputFilePath = _options.outputFilePath();
+ optOpt.tmpObjectFilePath = _options.tempLtoObjectPath();
+ optOpt.preserveAllGlobals = _options.allGlobalsAreDeadStripRoots() || _options.hasExportRestrictList();
+ optOpt.verbose = _options.verbose();
+ optOpt.saveTemps = _options.saveTempFiles();
+ optOpt.pie = _options.positionIndependentExecutable();
+ optOpt.mainExecutable = _options.linkingMainExecutable();;
+ optOpt.staticExecutable = (_options.outputKind() == Options::kStaticExecutable);
+ optOpt.relocatable = (_options.outputKind() == Options::kObjectFile);
+ optOpt.allowTextRelocs = _options.allowTextRelocs();
+ optOpt.linkerDeadStripping = _options.deadCodeStrip();
+ optOpt.arch = _options.architecture();
+ optOpt.llvmOptions = &_options.llvmOptions();
+
+ std::vector<const ld::Atom*> newAtoms;
+ std::vector<const char*> additionalUndefines;
+ if ( ! lto::optimize(_atoms, _internal, optOpt, *this, newAtoms, additionalUndefines) )
+ return; // if nothing done
+
+
+ // add all newly created atoms to _atoms and update symbol table
+ for(std::vector<const ld::Atom*>::iterator it = newAtoms.begin(); it != newAtoms.end(); ++it)
+ this->doAtom(**it);
+
+ // some atoms might have been optimized way (marked coalesced), remove them
+ this->removeCoalescedAwayAtoms();
+
+ // run through all atoms again and make sure newly codegened atoms have refernces bound
+ for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it)
+ this->convertReferencesToIndirect(**it);
+
+ // resolve new undefines (e.g calls to _malloc and _memcpy that llvm compiler conjures up)
+ for(std::vector<const char*>::iterator uit = additionalUndefines.begin(); uit != additionalUndefines.end(); ++uit) {
+ const char *targetName = *uit;
+ // these symbols may or may not already be in linker's symbol table
+ if ( ! _symbolTable.hasName(targetName) ) {
+ _inputFiles.searchLibraries(targetName, true, true, false, *this);
+ }
+ }
+
+ // if -dead_strip on command line
+ if ( _options.deadCodeStrip() ) {
+ // clear liveness bit
+ for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ (const_cast<ld::Atom*>(*it))->setLive((*it)->dontDeadStrip());
+ }
+ // and re-compute dead code
+ this->deadStripOptimize(true);
+ }
+
+ if ( _options.outputKind() == Options::kObjectFile ) {
+ // if -r mode, add proxies for new undefines (e.g. ___stack_chk_fail)
+ this->resolveUndefines();
+ }
+ else {
+ // last chance to check for undefines
+ this->checkUndefines(true);
+
+ // check new code does not override some dylib
+ this->checkDylibSymbolCollisions();
+ }
+}
+
+
+void Resolver::tweakWeakness()
+{
+ // <rdar://problem/7977374> Add command line options to control symbol weak-def bit on exported symbols
+ if ( _options.hasWeakBitTweaks() ) {
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = _internal.sections.begin(); sit != _internal.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ if ( atom->definition() != ld::Atom::definitionRegular )
+ continue;
+ const char* name = atom->name();
+ if ( atom->scope() == ld::Atom::scopeGlobal ) {
+ if ( atom->combine() == ld::Atom::combineNever ) {
+ if ( _options.forceWeak(name) )
+ (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineByName);
+ }
+ else if ( atom->combine() == ld::Atom::combineByName ) {
+ if ( _options.forceNotWeak(name) )
+ (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineNever);
+ }
+ }
+ else {
+ if ( _options.forceWeakNonWildCard(name) )
+ warning("cannot force to be weak, non-external symbol %s", name);
+ else if ( _options.forceNotWeakNonWildcard(name) )
+ warning("cannot force to be not-weak, non-external symbol %s", name);
+ }
+ }
+ }
+ }
+}
+
+
+void Resolver::resolve()
+{
+ this->initializeState();
+ this->buildAtomList();
+ this->addInitialUndefines();
+ this->fillInHelpersInInternalState();
+ this->resolveUndefines();
+ this->deadStripOptimize();
+ this->checkUndefines();
+ this->checkDylibSymbolCollisions();
+ this->removeCoalescedAwayAtoms();
+ this->fillInEntryPoint();
+ this->linkTimeOptimize();
+ this->fillInInternalState();
+ this->tweakWeakness();
+ _symbolTable.checkDuplicateSymbols();
+}
+
+
+
+} // namespace tool
+} // namespace ld
+
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __RESOLVER_H__
+#define __RESOLVER_H__
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+
+#include <vector>
+
+#include "Options.h"
+#include "ld.hpp"
+#include "SymbolTable.h"
+
+
+namespace ld {
+namespace tool {
+
+
+
+
+class Resolver : public ld::File::AtomHandler
+{
+public:
+ Resolver(const Options& opts, InputFiles& inputs, ld::Internal& state)
+ : _options(opts), _inputFiles(inputs), _internal(state),
+ _symbolTable(opts, state.indirectBindingTable),
+ _haveLLVMObjs(false),
+ _completedInitialObjectFiles(false) {}
+
+
+ virtual void doAtom(const ld::Atom&);
+ virtual void doFile(const class File&);
+
+ void resolve();
+
+
+private:
+ struct WhyLiveBackChain
+ {
+ WhyLiveBackChain* previous;
+ const ld::Atom* referer;
+ };
+
+ void initializeState();
+ void buildAtomList();
+ void addInitialUndefines();
+ void deadStripOptimize(bool force=false);
+ void resolveUndefines();
+ void checkUndefines(bool force=false);
+ void checkDylibSymbolCollisions();
+ void tentativeOverrideOfDylib(ld::Atom&);
+ void fillInInternalState();
+ void fillInHelpersInInternalState();
+ void removeCoalescedAwayAtoms();
+ void fillInEntryPoint();
+ void linkTimeOptimize();
+ void convertReferencesToIndirect(const ld::Atom& atom);
+ const ld::Atom* entryPoint(bool searchArchives);
+ void markLive(const ld::Atom& atom, WhyLiveBackChain* previous);
+ bool isDtraceProbe(ld::Fixup::Kind kind);
+ void liveUndefines(std::vector<const char*>&);
+ void remainingUndefines(std::vector<const char*>&);
+ bool printReferencedBy(const char* name, SymbolTable::IndirectBindingSlot slot);
+ void tweakWeakness();
+
+ class CStringEquals {
+ public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+ };
+ typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> StringSet;
+
+ class NotLive {
+ public:
+ bool operator()(const ld::Atom* atom) const {
+ return ! (atom->live() || atom->dontDeadStrip());
+ }
+ };
+
+ class AtomCoalescedAway {
+ public:
+ bool operator()(const ld::Atom* atom) const {
+ return atom->coalescedAway();
+ }
+ };
+
+ const Options& _options;
+ InputFiles& _inputFiles;
+ ld::Internal& _internal;
+ std::vector<const ld::Atom*> _atoms;
+ std::set<const ld::Atom*> _deadStripRoots;
+ std::vector<const ld::Atom*> _atomsWithUnresolvedReferences;
+ SymbolTable _symbolTable;
+ bool _haveLLVMObjs;
+ bool _completedInitialObjectFiles;
+};
+
+
+class DeadStripResolver
+{
+public:
+
+
+private:
+
+};
+
+} // namespace tool
+} // namespace ld
+
+
+
+#endif // __RESOLVER_H__
--- /dev/null
+//
+// Snapshot.cpp
+// ld64
+//
+// Created by Josh Behnke on 8/25/11.
+// Copyright (c) 2011 Apple Inc. All rights reserved.
+//
+
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <libgen.h>
+#include <time.h>
+#include <Block.h>
+
+#include "Snapshot.h"
+#include "Options.h"
+
+#include "compile_stubs.h"
+
+//#define STORE_PID_IN_SNAPSHOT 1
+
+// Well known snapshot file/directory names. These appear in the root of the snapshot.
+// They are collected together here to make managing the namespace easier.
+static const char *frameworksString = "frameworks"; // directory containing framework stubs (mach-o files)
+static const char *dylibsString = "dylibs"; // directory containing dylib stubs (mach-o files)
+static const char *archiveFilesString = "archive_files"; // directory containing .a files
+static const char *origCommandLineString = "orig_command_line"; // text file containing the original command line
+static const char *linkCommandString = "link_command"; // text file containing the snapshot equivalent command line
+static const char *dataFilesString = "data_files"; // arbitrary data files referenced on the command line
+static const char *objectsString = "objects"; // directory containing object files
+static const char *frameworkStubsString = "framework_stubs"; // directory containing framework stub info (text files)
+static const char *dylibStubsString = "dylib_stubs"; // directory containing dylib stub info (text files)
+static const char *assertFileString = "assert_info"; // text file containing assertion failure logs
+static const char *compileFileString = "compile_stubs"; // text file containing compile_stubs script
+
+Snapshot *Snapshot::globalSnapshot = NULL;
+
+Snapshot::Snapshot() : fRecordArgs(false), fRecordObjects(false), fRecordDylibSymbols(false), fRecordArchiveFiles(false), fRecordUmbrellaFiles(false), fRecordDataFiles(false), fFrameworkArgAdded(false), fSnapshotLocation(NULL), fSnapshotName(NULL), fRootDir(NULL), fFilelistFile(-1), fCopiedArchives(NULL)
+{
+ if (globalSnapshot != NULL)
+ throw "only one snapshot supported";
+ globalSnapshot = this;
+}
+
+
+Snapshot::~Snapshot()
+{
+ // Lots of things leak under the assumption the linker is about to exit.
+}
+
+
+void Snapshot::setSnapshotPath(const char *path)
+{
+ if (fRootDir == NULL) {
+ fSnapshotLocation = strdup(path);
+ }
+}
+
+
+void Snapshot::setSnapshotMode(SnapshotMode mode)
+{
+ if (fRootDir == NULL) {
+ fRecordArgs = false;
+ fRecordObjects = false;
+ fRecordDylibSymbols = false;
+ fRecordArchiveFiles = false;
+ fRecordUmbrellaFiles = false;
+ fRecordDataFiles = false;
+
+ switch (mode) {
+ case SNAPSHOT_DISABLED:
+ break;
+ case SNAPSHOT_DEBUG:
+ fRecordArgs = fRecordObjects = fRecordDylibSymbols = fRecordArchiveFiles = fRecordUmbrellaFiles = fRecordDataFiles = true;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void Snapshot::setSnapshotName(const char *path)
+{
+ if (fRootDir == NULL) {
+ const char *base = basename((char *)path);
+ time_t now = time(NULL);
+ struct tm t;
+ localtime_r(&now, &t);
+ char buf[PATH_MAX];
+ snprintf(buf, sizeof(buf)-1, "%s-%4.4d-%2.2d-%2.2d-%2.2d%2.2d%2.2d.ld-snapshot", base, t.tm_year+1900, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
+ fSnapshotName = strdup(buf);
+ }
+}
+
+
+// Construct a path string in the snapshot.
+// subdir - an optional subdirectory name
+// file - the file name
+void Snapshot::buildPath(char *buf, const char *subdir, const char *file)
+{
+ if (fRootDir == NULL)
+ throw "snapshot not created";
+
+ strcpy(buf, fRootDir);
+ strcat(buf, "/");
+ if (subdir) {
+ strcat(buf, subdir);
+ // implicitly create the subdirectory
+ mkdir(buf, S_IRUSR|S_IWUSR|S_IXUSR);
+ strcat(buf, "/");
+ }
+ if (file != NULL)
+ strcat(buf, basename((char *)file));
+}
+
+
+// Construct a unique path string in the snapshot. If a path collision is detected then uniquing
+// is accomplished by appending a counter to the path until there is no preexisting file.
+// subdir - an optional subdirectory name
+// file - the file name
+void Snapshot::buildUniquePath(char *buf, const char *subdir, const char *file)
+{
+ buildPath(buf, subdir, file);
+ struct stat st;
+ if (stat(buf, &st)==0) {
+ // make it unique
+ int counter=1;
+ char *number = strrchr(buf, 0);
+ number[0]='-';
+ number++;
+ do {
+ sprintf(number, "%d", counter++);
+ } while (stat(buf, &st) == 0);
+ }
+}
+
+
+// Copy a file to the snapshot.
+// sourcePath is the original file
+// subdir is an optional subdirectory in the snapshot
+// path is an optional out parameter containing the final uniqued path in the snapshot
+// where the file was copied
+void Snapshot::copyFileToSnapshot(const char *sourcePath, const char *subdir, char *path)
+{
+ const int copyBufSize=(1<<14); // 16kb buffer
+ static void *copyBuf = NULL;
+ if (copyBuf == NULL)
+ copyBuf = malloc(copyBufSize);
+
+ char *file=basename((char *)sourcePath);
+ char buf[PATH_MAX];
+ if (path == NULL) path = buf;
+ buildUniquePath(path, subdir, file);
+ int out_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+ int in_fd = open(sourcePath, O_RDONLY);
+ int len;
+ if (out_fd != -1 && in_fd != -1) {
+ do {
+ len = read(in_fd, copyBuf, copyBufSize);
+ if (len > 0) write(out_fd, copyBuf, len);
+ } while (len == copyBufSize);
+ }
+ close(in_fd);
+ close(out_fd);
+}
+
+
+// Create the snapshot root directory.
+void Snapshot::createSnapshot()
+{
+ if (fRootDir == NULL) {
+ // provide default name and location
+ if (fSnapshotLocation == NULL)
+ fSnapshotLocation = "/tmp";
+ if (fSnapshotName == NULL) {
+ setSnapshotName("ld_snapshot");
+ }
+
+ char buf[PATH_MAX];
+ fRootDir = (char *)fSnapshotLocation;
+ buildUniquePath(buf, NULL, fSnapshotName);
+ fRootDir = strdup(buf);
+ if (mkdir(fRootDir, S_IRUSR|S_IWUSR|S_IXUSR)!=0) {
+ warning("unable to create link snapshot directory: %s", fRootDir);
+ fRootDir = NULL;
+ setSnapshotMode(SNAPSHOT_DISABLED); // don't try to write anything if we can't create snapshot dir
+ }
+
+ buildPath(buf, NULL, compileFileString);
+ int compileScript = open(buf, O_WRONLY|O_CREAT|O_TRUNC, S_IXUSR|S_IRUSR|S_IWUSR);
+ write(compileScript, compile_stubs, strlen(compile_stubs));
+ close(compileScript);
+
+ SnapshotLog::iterator it;
+ for (it = fLog.begin(); it != fLog.end(); it++) {
+ void (^logItem)(void) = *it;
+ logItem();
+ Block_release(logItem);
+ }
+ fLog.erase(fLog.begin(), fLog.end());
+
+ if (fRecordArgs) {
+ writeCommandLine(fRawArgs, origCommandLineString, true);
+ writeCommandLine(fArgs);
+ }
+
+#if STORE_PID_IN_SNAPSHOT
+ char path[PATH_MAX];
+ buildUniquePath(path, NULL, pidString);
+ int pidfile = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+ char pid_buf[32];
+ sprintf(pid_buf, "%lu\n", (long unsigned)getpid());
+ write(pidfile, pid_buf, strlen(pid_buf));
+ write(pidfile, "\n", 1);
+ close(pidfile);
+#endif
+
+ }
+}
+
+
+// Write the current command line vector to filename.
+void Snapshot::writeCommandLine(StringVector &args, const char *filename, bool includeCWD)
+{
+ if (!isLazy() && fRecordArgs) {
+ // Figure out the file name and open it.
+ if (filename == NULL)
+ filename = linkCommandString;
+ char path[PATH_MAX];
+ buildPath(path, NULL, filename);
+ int argsFile = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IXUSR|S_IRUSR|S_IWUSR);
+ FILE *argsStream = fdopen(argsFile, "w");
+
+ if (includeCWD)
+ fprintf(argsStream, "cd %s\n", getcwd(path, sizeof(path)));
+
+ // iterate to write args, quoting as needed
+ StringVector::iterator it;
+ for (it = args.begin(); it != args.end(); it++) {
+ const char *arg = *it;
+ bool needQuotes = false;
+ for (const char *c = arg; *c != 0 && !needQuotes; c++) {
+ if (isspace(*c))
+ needQuotes = true;
+ }
+ if (it != args.begin()) fprintf(argsStream, " ");
+ if (needQuotes) fprintf(argsStream, "\"");
+ fprintf(argsStream, "%s", arg);
+ if (needQuotes) fprintf(argsStream, "\"");
+ }
+ fprintf(argsStream, "\n");
+ fclose(argsStream);
+ }
+}
+
+
+// Store the command line args in the snapshot.
+void Snapshot::recordRawArgs(int argc, const char *argv[])
+{
+ // first store the original command line as-is
+ for (int i=0; i<argc; i++) {
+ fRawArgs.push_back(argv[i]);
+ }
+ fArgs.insert(fArgs.begin(), argv[0]);
+ fArgs.insert(fArgs.begin()+1, "-Z"); // don't search standard paths when running in the snapshot
+}
+
+
+// Adds one or more args to the snapshot link command.
+// argIndex is the index in the original raw args vector to start adding args
+// argCount is the count of args to copy from the raw args vector
+// fileArg is the index relative to argIndex of a file arg. The file is copied into the
+// snapshot and the path is fixed up in the snapshot link command. (skipped if fileArg==-1)
+void Snapshot::addSnapshotLinkArg(int argIndex, int argCount, int fileArg)
+{
+ if (fRootDir == NULL) {
+ fLog.push_back(Block_copy(^{ this->addSnapshotLinkArg(argIndex, argCount, fileArg); }));
+ } else {
+ char buf[PATH_MAX];
+ const char *subdir = dataFilesString;
+ for (int i=0, arg=argIndex; i<argCount && argIndex+1<(int)fRawArgs.size(); i++, arg++) {
+ if (i != fileArg) {
+ fArgs.push_back(fRawArgs[arg]);
+ } else {
+ if (fRecordDataFiles) {
+ copyFileToSnapshot(fRawArgs[arg], subdir, buf);
+ fArgs.push_back(strdup(snapshotRelativePath(buf)));
+ } else {
+ // if we don't copy the file then just record the original path
+ fArgs.push_back(strdup(fRawArgs[arg]));
+ }
+ }
+ }
+ }
+}
+
+// Record the -arch string
+void Snapshot::recordArch(const char *arch)
+{
+ // must be called after recordRawArgs()
+ if (fRawArgs.size() == 0)
+ throw "raw args not set";
+
+ // only need to store the arch explicitly if it is not mentioned on the command line
+ bool archInArgs = false;
+ StringVector::iterator it;
+ for (it = fRawArgs.begin(); it != fRawArgs.end() && !archInArgs; it++) {
+ const char *arg = *it;
+ if (strcmp(arg, "-arch") == 0)
+ archInArgs = true;
+ }
+
+ if (!archInArgs) {
+ if (fRootDir == NULL) {
+ fLog.push_back(Block_copy(^{ this->recordArch(arch); }));
+ } else {
+ char path_buf[PATH_MAX];
+ buildUniquePath(path_buf, NULL, "arch");
+ int fd=open(path_buf, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+ write(fd, arch, strlen(arch));
+ close(fd);
+ }
+ }
+}
+
+// Record an object file in the snapshot.
+// path - the object file's path
+// fileContent - a pointer to the object file content
+// fileLength - the buffer size of fileContent
+void Snapshot::recordObjectFile(const char *path)
+{
+ if (fRootDir == NULL) {
+ fLog.push_back(Block_copy(^{ this->recordObjectFile(path); }));
+ } else {
+ if (fRecordObjects) {
+ char path_buf[PATH_MAX];
+ copyFileToSnapshot(path, objectsString, path_buf);
+
+ // lazily open the filelist file
+ if (fFilelistFile == -1) {
+ char filelist_path[PATH_MAX];
+ buildUniquePath(filelist_path, objectsString, "filelist");
+ fFilelistFile = open(filelist_path, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+ fArgs.push_back("-filelist");
+ fArgs.push_back(strdup(snapshotRelativePath(filelist_path)));
+ writeCommandLine(fArgs);
+ }
+
+ // record the snapshot path in the filelist
+ const char *relative_path = snapshotRelativePath(path_buf);
+ write(fFilelistFile, relative_path, strlen(relative_path));
+ write(fFilelistFile, "\n", 1);
+ }
+ }
+}
+
+void Snapshot::addFrameworkArg(const char *framework)
+{
+ bool found=false;
+ for (unsigned i=0; i<fArgs.size()-1; i++) {
+ if (strcmp(fArgs[i], "-framework") == 0 && strcmp(fArgs[i+1], framework) == 0)
+ found = true;
+ }
+ if (!found) {
+ if (!fFrameworkArgAdded) {
+ fFrameworkArgAdded = true;
+ fArgs.push_back("-Fframeworks");
+ }
+ fArgs.push_back("-framework");
+ fArgs.push_back(strdup(framework));
+ writeCommandLine(fArgs);
+ }
+}
+
+void Snapshot::addDylibArg(const char *dylib)
+{
+ bool found=false;
+ for (unsigned i=0; i<fArgs.size()-1; i++) {
+ if (strcmp(fArgs[i], dylib) == 0)
+ found = true;
+ }
+ if (!found) {
+ char buf[ARG_MAX];
+ sprintf(buf, "%s/%s", dylibsString, dylib);
+ fArgs.push_back(strdup(buf));
+ writeCommandLine(fArgs);
+ }
+}
+
+// Record a dylib symbol reference in the snapshot.
+// (References are not written to the snapshot until writeStubDylibs() is called.)
+void Snapshot::recordDylibSymbol(ld::dylib::File* dylibFile, const char *name)
+{
+ if (fRootDir == NULL) {
+ fLog.push_back(Block_copy(^{ this->recordDylibSymbol(dylibFile, name); }));
+ } else {
+ if (fRecordDylibSymbols) {
+ // find the dylib in the table
+ DylibMap::iterator it;
+ const char *dylibPath = dylibFile->path();
+ it = fDylibSymbols.find(dylibPath);
+ bool isFramework = (strstr(dylibPath, "framework") != NULL);
+ int dylibFd;
+ if (it == fDylibSymbols.end()) {
+ // Didn't find a file descriptor for this dylib. Create one and add it to the dylib map.
+ char path_buf[PATH_MAX];
+ buildUniquePath(path_buf, isFramework ? frameworkStubsString : dylibStubsString, dylibPath);
+ dylibFd = open(path_buf, O_WRONLY|O_APPEND|O_CREAT, S_IRUSR|S_IWUSR);
+ fDylibSymbols.insert(std::pair<const char *, int>(dylibPath, dylibFd));
+ char *base_name = strdup(basename(path_buf));
+ if (isFramework) {
+ addFrameworkArg(base_name);
+ } else {
+ addDylibArg(base_name);
+ }
+ writeCommandLine(fArgs);
+ } else {
+ dylibFd = it->second;
+ }
+ // Record the symbol.
+
+ bool isIdentifier = (name[0] == '_');
+ for (const char *c = name; *c != 0 && isIdentifier; c++)
+ if (!isalnum(*c) && *c!='_')
+ isIdentifier = false;
+ const char *prefix = "void ";
+ const char *weakAttr = "__attribute__ ((weak)) ";
+ const char *suffix = "(void){}\n";
+ if (isIdentifier) {
+ write(dylibFd, prefix, strlen(prefix));
+ if (dylibFile->hasWeakExternals() && dylibFile->hasWeakDefinition(name))
+ write(dylibFd, weakAttr, strlen(weakAttr));
+ if (*name == '_') name++;
+ write(dylibFd, name, strlen(name));
+ write(dylibFd, suffix, strlen(suffix));
+ } else {
+ static int symbolCounter = 0;
+ char buf[64+strlen(name)];
+ sprintf(buf, "void s_%5.5d(void) __asm(\"%s\");\nvoid s_%5.5d(){}\n", symbolCounter, name, symbolCounter);
+ write(dylibFd, buf, strlen(buf));
+ symbolCounter++;
+ }
+ }
+ }
+}
+
+
+// Record a .a archive in the snapshot.
+void Snapshot::recordArchive(const char *archiveFile)
+{
+ if (fRootDir == NULL) {
+ const char *copy = strdup(archiveFile);
+ fLog.push_back(Block_copy(^{ this->recordArchive(archiveFile); ::free((void *)copy); }));
+ } else {
+ if (fRecordArchiveFiles) {
+ // lazily create a vector of .a files that have been added
+ if (fCopiedArchives == NULL) {
+ fCopiedArchives = new StringVector;
+ }
+
+ // See if we have already added this .a
+ StringVector::iterator it;
+ bool found = false;
+ for (it = fCopiedArchives->begin(); it != fCopiedArchives->end() && !found; it++) {
+ if (strcmp(archiveFile, *it) == 0)
+ found = true;
+ }
+
+ // If this is a new .a then copy it to the snapshot and add it to the snapshot link command.
+ if (!found) {
+ char path[PATH_MAX];
+ fCopiedArchives->push_back(archiveFile);
+ copyFileToSnapshot(archiveFile, archiveFilesString, path);
+ fArgs.push_back(strdup(snapshotRelativePath(path)));
+ writeCommandLine(fArgs);
+ }
+ }
+ }
+}
+
+void Snapshot::recordSubUmbrella(const char *frameworkPath)
+{
+ if (fRootDir == NULL) {
+ const char *copy = strdup(frameworkPath);
+ fLog.push_back(Block_copy(^{ this->recordSubUmbrella(copy); ::free((void *)copy); }));
+ } else {
+ if (fRecordUmbrellaFiles) {
+ const char *framework = basename((char *)frameworkPath);
+ char buf[PATH_MAX], wrapper[PATH_MAX];
+ strcpy(wrapper, frameworksString);
+ buildPath(buf, wrapper, NULL); // ensure the frameworks directory exists
+ strcat(wrapper, "/");
+ strcat(wrapper, framework);
+ strcat(wrapper, ".framework");
+ copyFileToSnapshot(frameworkPath, wrapper);
+ addFrameworkArg(framework);
+ }
+ }
+}
+
+void Snapshot::recordSubLibrary(const char *dylibPath)
+{
+ if (fRootDir == NULL) {
+ const char *copy = strdup(dylibPath);
+ fLog.push_back(Block_copy(^{ this->recordSubLibrary(copy); ::free((void *)copy); }));
+ } else {
+ if (fRecordUmbrellaFiles) {
+ copyFileToSnapshot(dylibPath, dylibsString);
+ addDylibArg(basename((char *)dylibPath));
+ }
+ }
+}
+
+void Snapshot::recordAssertionMessage(const char *fmt, ...)
+{
+ char *msg;
+ va_list args;
+ va_start(args, fmt);
+ vasprintf(&msg, fmt, args);
+ va_end(args);
+ if (msg != NULL) {
+ if (fRootDir == NULL) {
+ fLog.push_back(Block_copy(^{ this->recordAssertionMessage("%s", msg); free(msg); }));
+ } else {
+ char path[PATH_MAX];
+ buildPath(path, NULL, assertFileString);
+ int log = open(path, O_WRONLY|O_APPEND|O_CREAT, S_IRUSR|S_IWUSR);
+ write(log, msg, strlen(msg));
+ close(log);
+ free(msg);
+ }
+ }
+}
--- /dev/null
+//
+// Snapshot.h
+// ld64
+//
+// Created by Josh Behnke on 8/25/11.
+// Copyright (c) 2011 Apple Inc. All rights reserved.
+//
+
+#ifndef ld64_Snapshot_h
+#define ld64_Snapshot_h
+#include <stdint.h>
+#include <string.h>
+#include <map>
+#include <vector>
+
+#include "ld.hpp"
+
+class Options;
+class SnapshotLogItem;
+
+class Snapshot {
+
+public:
+ static Snapshot *globalSnapshot;
+
+ typedef enum {
+ SNAPSHOT_DISABLED, // nothing is recorded
+ SNAPSHOT_DEBUG, // records: .o, .dylib, .framework, .a, and other data files
+ } SnapshotMode;
+
+ Snapshot();
+ ~Snapshot();
+
+ // Control the data captured in the snapshot
+ void setSnapshotMode(SnapshotMode mode);
+
+ // Use the basename of path to construct the snapshot name.
+ // Must be called prior to createSnapshot().
+ void setSnapshotName(const char *path);
+
+ // Set the directory in which the snapshot will be created.
+ // Must be called prior to createSnapshot().
+ void setSnapshotPath(const char *path);
+
+ // Stores the linker command line in the snapshot
+ void recordRawArgs(int argc, const char *argv[]);
+
+ // Adds one or more args to the snapshot link command.
+ // argIndex is the index in the original raw args vector to start adding args
+ // argCount is the count of args to copy from the raw args vector
+ // fileArg is the index relative to argIndex of a file arg. The file is copied into the
+ // snapshot and the path is fixed up in the snapshot link command. (skipped if fileArg==-1)
+ // recordRawArgs() must be called prior to the first call to addSnapshotLinkArg()
+ void addSnapshotLinkArg(int argIndex, int argCount=1, int fileArg=-1);
+
+ // record the -arch string
+ void recordArch(const char *arch);
+
+ // Stores an object file in the snapshot, using a unique name in an "objects" subdir.
+ void recordObjectFile(const char *path);
+
+ // Records symbol names used in dylibs. Does not store anything in the snapshot.
+ void recordDylibSymbol(ld::dylib::File* dylibFile, const char *name);
+
+ // Stores an archive (.a) file in the snapshot.
+ void recordArchive(const char *archiveFile);
+
+ // Copies the framework binary into the snapshot frameworks directory.
+ void recordSubUmbrella(const char *frameworkPath);
+
+ // Copies the library binary into the snapshot dylibs directory.
+ void recordSubLibrary(const char *dylibPath);
+
+ // Records arbitrary text messages into a log file in the snapshot.
+ // Used by the assertion failure machienery.
+ void recordAssertionMessage(const char *fmt, ...);
+
+ // Create the snapshot.
+ // Until this is called the snapshot operates lazily, storing minimal data in memory.
+ // When this is called the snapshot is created and any previously recorded data is
+ // immediately copied. Any subsequent additions to the snapshot are copied immediately.
+ void createSnapshot();
+
+ // Returns the snapshot root directory.
+ const char *rootDir() { return fRootDir; }
+
+private:
+
+ friend class SnapshotArchiveFileLog;
+
+ typedef std::vector<void(^)(void)> SnapshotLog;
+
+ struct strcompclass {
+ bool operator() (const char *a, const char *b) const { return ::strcmp(a, b) < 0; }
+ };
+ typedef std::vector<const char *> StringVector;
+ typedef std::map<const char *, int, strcompclass > DylibMap;
+ typedef std::map<const char *, const char *, strcompclass> PathMap;
+
+
+ // Write the current contents of the args vector to a file in the snapshot.
+ // If filename is NULL then "link_command" is used.
+ // This is used to write both the original and the "cooked" versions of the link command
+ void writeCommandLine(StringVector &args, const char *filename=NULL, bool includeCWD=false);
+
+ // Construct a path in the snapshot.
+ // buf is a sring buffer in which the path is constructed
+ // subdir is an optional subdirectory, and file is a file name
+ // Constructs the path <snapshot_root>/<subdir>/<file> in buf
+ void buildPath(char *buf, const char *subdir, const char *file);
+
+ // Similar to buildPath(), except this ensures the returned path
+ // does not reference an existing file in the snapshot.
+ // Performs uniquing by appending a count suffex to the path (ie .../file-XX)
+ void buildUniquePath(char *buf, const char *subdir, const char *file);
+
+ // Copies an arbitrary file to the snapshot. Subdir specifies an optional subdirectory name.
+ // Uses buildUniquePath to construct a unique path. If the result path is needed by the caller
+ // then a path buffer can be supplied in buf. Otherwise an internal buffer is used.
+ void copyFileToSnapshot(const char *sourcePath, const char *subdir, char *buf=NULL);
+
+ // Convert a full path to snapshot relative by constructing an interior pointer at the right offset.
+ const char *snapshotRelativePath(const char *path) { return path+strlen(fRootDir)+1; }
+
+ // returns true if the snapshot has not been created (by createSnapshot()) yet
+ bool isLazy() { return fRootDir == NULL; }
+
+ void addFrameworkArg(const char *framework);
+ void addDylibArg(const char *dylib);
+
+ SnapshotLog fLog; // log of events that recorded data in a snapshot prior to createSnapshot()
+ bool fRecordArgs; // record command line
+ bool fRecordObjects; // record .o files
+ bool fRecordDylibSymbols; // record referenced dylib/framework symbols
+ bool fRecordArchiveFiles; // record .a files
+ bool fRecordUmbrellaFiles; // record re-exported sub frameworks/dylibs
+ bool fRecordDataFiles; // record other data files
+ bool fFrameworkArgAdded;
+
+ const char *fSnapshotLocation; // parent directory of frootDir
+ const char *fSnapshotName; // a string to use in constructing the snapshot name
+ char *fRootDir; // root directory of the snapshot
+ int fFilelistFile; // file descriptor to the open text file used for the -filelist
+
+ StringVector fRawArgs; // stores the raw command line args
+ StringVector fArgs; // stores the "cooked" command line args
+ PathMap fPathMap; // mapping of original paths->snapshot paths for copied files
+
+ DylibMap fDylibSymbols; // map of dylib names to string vector containing referenced symbol names
+ StringVector *fCopiedArchives; // vector of .a files that have been copied to the snapshot
+};
+
+#endif
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <map>
+#include <set>
+#include <vector>
+#include <algorithm>
+#include <ext/hash_map>
+#include <ext/hash_set>
+
+#include "Options.h"
+
+#include "ld.hpp"
+#include "InputFiles.h"
+#include "SymbolTable.h"
+
+
+
+namespace ld {
+namespace tool {
+
+
+// HACK, I can't find a way to pass values in the compare classes (e.g. ContentFuncs)
+// so use global variable to pass info.
+static ld::IndirectBindingTable* _s_indirectBindingTable = NULL;
+
+
+SymbolTable::SymbolTable(const Options& opts, std::vector<const ld::Atom*>& ibt)
+ : _options(opts), _cstringTable(6151), _indirectBindingTable(ibt), _hasExternalTentativeDefinitions(false)
+{
+ _s_indirectBindingTable = this;
+}
+
+
+size_t SymbolTable::ContentFuncs::operator()(const ld::Atom* atom) const
+{
+ return atom->contentHash(*_s_indirectBindingTable);
+}
+
+bool SymbolTable::ContentFuncs::operator()(const ld::Atom* left, const ld::Atom* right) const
+{
+ return (memcmp(left->rawContentPointer(), right->rawContentPointer(), left->size()) == 0);
+}
+
+
+
+size_t SymbolTable::CStringHashFuncs::operator()(const ld::Atom* atom) const
+{
+ return atom->contentHash(*_s_indirectBindingTable);
+}
+
+bool SymbolTable::CStringHashFuncs::operator()(const ld::Atom* left, const ld::Atom* right) const
+{
+ return (strcmp((char*)left->rawContentPointer(), (char*)right->rawContentPointer()) == 0);
+}
+
+
+size_t SymbolTable::UTF16StringHashFuncs::operator()(const ld::Atom* atom) const
+{
+ return atom->contentHash(*_s_indirectBindingTable);
+}
+
+bool SymbolTable::UTF16StringHashFuncs::operator()(const ld::Atom* left, const ld::Atom* right) const
+{
+ if ( left == right )
+ return true;
+ const void* leftContent = left->rawContentPointer();
+ const void* rightContent = right->rawContentPointer();
+ unsigned int amount = left->size()-2;
+ bool result = (memcmp(leftContent, rightContent, amount) == 0);
+ return result;
+}
+
+
+size_t SymbolTable::ReferencesHashFuncs::operator()(const ld::Atom* atom) const
+{
+ return atom->contentHash(*_s_indirectBindingTable);
+}
+
+bool SymbolTable::ReferencesHashFuncs::operator()(const ld::Atom* left, const ld::Atom* right) const
+{
+ return left->canCoalesceWith(*right, *_s_indirectBindingTable);
+}
+
+
+void SymbolTable::addDuplicateSymbol(const char *name, const ld::Atom *atom)
+{
+ // Look up or create the file list for name.
+ DuplicateSymbols::iterator symbolsIterator = _duplicateSymbols.find(name);
+ DuplicatedSymbolAtomList *atoms = NULL;
+ if (symbolsIterator != _duplicateSymbols.end()) {
+ atoms = symbolsIterator->second;
+ } else {
+ atoms = new std::vector<const ld::Atom *>;
+ _duplicateSymbols.insert(std::pair<const char *, DuplicatedSymbolAtomList *>(name, atoms));
+ }
+
+ // check if file is already in the list, add it if not
+ bool found = false;
+ for (DuplicatedSymbolAtomList::iterator it = atoms->begin(); !found && it != atoms->end(); it++)
+ if (strcmp((*it)->file()->path(), atom->file()->path()) == 0)
+ found = true;
+ if (!found)
+ atoms->push_back(atom);
+}
+
+void SymbolTable::checkDuplicateSymbols() const
+{
+ bool foundDuplicate = false;
+ for (DuplicateSymbols::const_iterator symbolIt = _duplicateSymbols.begin(); symbolIt != _duplicateSymbols.end(); symbolIt++) {
+ DuplicatedSymbolAtomList *atoms = symbolIt->second;
+ bool reportDuplicate;
+ if (_options.deadCodeStrip()) {
+ // search for a live atom
+ reportDuplicate = false;
+ for (DuplicatedSymbolAtomList::iterator it = atoms->begin(); !reportDuplicate && it != atoms->end(); it++) {
+ if ((*it)->live())
+ reportDuplicate = true;
+ }
+ } else {
+ reportDuplicate = true;
+ }
+ if (reportDuplicate) {
+ foundDuplicate = true;
+ fprintf(stderr, "duplicate symbol %s in:\n", symbolIt->first);
+ for (DuplicatedSymbolAtomList::iterator atomIt = atoms->begin(); atomIt != atoms->end(); atomIt++) {
+ fprintf(stderr, " %s\n", (*atomIt)->file()->path());
+ }
+ }
+ }
+ if (foundDuplicate)
+ throwf("%d duplicate symbol%s", (int)_duplicateSymbols.size(), _duplicateSymbols.size()==1?"":"s");
+}
+
+// AtomPicker encapsulates the logic for picking which atom to use when adding an atom by name results in a collision
+class NameCollisionResolution {
+public:
+ NameCollisionResolution(const ld::Atom& a, const ld::Atom& b, bool ignoreDuplicates, const Options& options) : _atomA(a), _atomB(b), _options(options), _reportDuplicate(false), _ignoreDuplicates(ignoreDuplicates) {
+ pickAtom();
+ }
+
+ // Returns which atom to use
+ const ld::Atom& chosen() { return *_chosen; }
+ bool choseAtom(const ld::Atom& atom) { return _chosen == &atom; }
+
+ // Returns true if the two atoms should be reported as a duplicate symbol
+ bool reportDuplicate() { return _reportDuplicate; }
+
+private:
+ const ld::Atom& _atomA;
+ const ld::Atom& _atomB;
+ const Options& _options;
+ const ld::Atom* _chosen;
+ bool _reportDuplicate;
+ bool _ignoreDuplicates;
+
+ void pickAtom(const ld::Atom& atom) { _chosen = &atom; } // primitive to set which atom is picked
+ void pickAtomA() { pickAtom(_atomA); } // primitive to pick atom A
+ void pickAtomB() { pickAtom(_atomB); } // primitive to pick atom B
+
+ // use atom A if pickA, otherwise use atom B
+ void pickAOrB(bool pickA) { if (pickA) pickAtomA(); else pickAtomB(); }
+
+ void pickHigherOrdinal() {
+ pickAOrB(_atomA.file()->ordinal() < _atomB.file()->ordinal());
+ }
+
+ void pickLowerOrdinal() {
+ pickAOrB(_atomA.file()->ordinal() > _atomB.file()->ordinal());
+ }
+
+ void pickLargerSize() {
+ if (_atomA.size() == _atomB.size())
+ pickLowerOrdinal();
+ else
+ pickAOrB(_atomA.size() > _atomB.size());
+ }
+
+ void pickGreaterAlignment() {
+ pickAOrB(_atomA.alignment().trailingZeros() > _atomB.alignment().trailingZeros());
+ }
+
+ void pickBetweenRegularAtoms() {
+ if ( _atomA.combine() == ld::Atom::combineByName ) {
+ if ( _atomB.combine() == ld::Atom::combineByName ) {
+ // <rdar://problem/9183821> always choose mach-o over llvm bit code, otherwise LTO may eliminate the llvm atom
+ const bool aIsLTO = (_atomA.contentType() == ld::Atom::typeLTOtemporary);
+ const bool bIsLTO = (_atomB.contentType() == ld::Atom::typeLTOtemporary);
+ // <rdar://problem/9183821> always choose mach-o over llvm bit code, otherwise LTO may eliminate the llvm atom
+ if ( aIsLTO != bIsLTO ) {
+ pickAOrB(!aIsLTO);
+ }
+ else {
+ // both weak, prefer non-auto-hide one
+ if ( _atomA.autoHide() != _atomB.autoHide() ) {
+ // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
+ pickAOrB(!_atomA.autoHide());
+ }
+ else if ( _atomA.autoHide() && _atomB.autoHide() ) {
+ // both have auto-hide, so use one with greater alignment
+ pickGreaterAlignment();
+ }
+ else {
+ // neither auto-hide, check visibility
+ if ( _atomA.scope() != _atomB.scope() ) {
+ // <rdar://problem/8304984> use more visible weak def symbol
+ pickAOrB(_atomA.scope() == ld::Atom::scopeGlobal);
+ }
+ else {
+ // both have same visibility, use one with greater alignment
+ pickGreaterAlignment();
+ }
+ }
+ }
+ }
+ else {
+ pickAtomB(); // pick not-weak
+
+ }
+ }
+ else {
+ if ( _atomB.combine() == ld::Atom::combineByName ) {
+ pickAtomA(); // pick not-weak
+
+ }
+ else {
+ // both are not-weak
+ if ( _atomA.section().type() == ld::Section::typeMachHeader ) {
+ pickAtomA();
+ }
+ else if ( _atomB.section().type() == ld::Section::typeMachHeader ) {
+ pickAtomB();
+ }
+ else {
+ if ( _ignoreDuplicates ) {
+ pickLowerOrdinal();
+ }
+ else {
+ _reportDuplicate = true;
+ }
+ }
+ }
+ }
+ }
+
+ void pickCommonsMode(const ld::Atom& dylib, const ld::Atom& proxy) {
+ assert(dylib.definition() == ld::Atom::definitionTentative);
+ assert(proxy.definition() == ld::Atom::definitionProxy);
+ switch ( _options.commonsMode() ) {
+ case Options::kCommonsIgnoreDylibs:
+ if ( _options.warnCommons() )
+ warning("using common symbol %s from %s and ignoring defintion from dylib %s",
+ proxy.name(), proxy.file()->path(), dylib.file()->path());
+ pickAtom(dylib);
+ break;
+ case Options::kCommonsOverriddenByDylibs:
+ if ( _options.warnCommons() )
+ warning("replacing common symbol %s from %s with true definition from dylib %s",
+ proxy.name(), proxy.file()->path(), dylib.file()->path());
+ pickAtom(proxy);
+ break;
+ case Options::kCommonsConflictsDylibsError:
+ throwf("common symbol %s from %s conflicts with defintion from dylib %s",
+ proxy.name(), proxy.file()->path(), dylib.file()->path());
+ }
+ }
+
+ void pickProxyAtom() {
+ // both atoms are definitionProxy
+ // <rdar://problem/5137732> ld should keep looking when it finds a weak definition in a dylib
+ if ( _atomA.combine() == ld::Atom::combineByName ) {
+ pickAtomB();
+ } else if ( _atomB.combine() == ld::Atom::combineByName ) {
+ pickAtomA();
+ } else {
+ throwf("symbol %s exported from both %s and %s\n", _atomA.name(), _atomA.file()->path(), _atomB.file()->path());
+ }
+ }
+
+ void pickAtom() {
+ // First, discriminate by definition
+ switch (_atomA.definition()) {
+ case ld::Atom::definitionRegular:
+ switch (_atomB.definition()) {
+ case ld::Atom::definitionRegular:
+ pickBetweenRegularAtoms();
+ break;
+ case ld::Atom::definitionTentative:
+ pickAtomA();
+ break;
+ case ld::Atom::definitionAbsolute:
+ _reportDuplicate = true;
+ pickHigherOrdinal();
+ break;
+ case ld::Atom::definitionProxy:
+ pickAtomA();
+ break;
+ }
+ break;
+ case ld::Atom::definitionTentative:
+ switch (_atomB.definition()) {
+ case ld::Atom::definitionRegular:
+ pickAtomB();
+ break;
+ case ld::Atom::definitionTentative:
+ pickLargerSize();
+ break;
+ case ld::Atom::definitionAbsolute:
+ pickHigherOrdinal();
+ break;
+ case ld::Atom::definitionProxy:
+ pickCommonsMode(_atomA, _atomB);
+ break;
+ }
+ break;
+ case ld::Atom::definitionAbsolute:
+ switch (_atomB.definition()) {
+ case ld::Atom::definitionRegular:
+ _reportDuplicate = true;
+ pickHigherOrdinal();
+ break;
+ case ld::Atom::definitionTentative:
+ pickAtomA();
+ break;
+ case ld::Atom::definitionAbsolute:
+ _reportDuplicate = true;
+ pickHigherOrdinal();
+ break;
+ case ld::Atom::definitionProxy:
+ pickAtomA();
+ break;
+ }
+ break;
+ case ld::Atom::definitionProxy:
+ switch (_atomB.definition()) {
+ case ld::Atom::definitionRegular:
+ pickAtomB();
+ break;
+ case ld::Atom::definitionTentative:
+ pickCommonsMode(_atomB, _atomA);
+ break;
+ case ld::Atom::definitionAbsolute:
+ pickAtomB();
+ break;
+ case ld::Atom::definitionProxy:
+ pickProxyAtom();
+ break;
+ }
+ break;
+ }
+ }
+};
+
+bool SymbolTable::addByName(const ld::Atom& newAtom, bool ignoreDuplicates)
+{
+ bool useNew = true;
+ assert(newAtom.name() != NULL);
+ const char* name = newAtom.name();
+ IndirectBindingSlot slot = this->findSlotForName(name);
+ const ld::Atom* existingAtom = _indirectBindingTable[slot];
+ //fprintf(stderr, "addByName(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
+ if ( existingAtom != NULL ) {
+ assert(&newAtom != existingAtom);
+ NameCollisionResolution picker(newAtom, *existingAtom, ignoreDuplicates, _options);
+ if (picker.reportDuplicate()) {
+ addDuplicateSymbol(name, existingAtom);
+ addDuplicateSymbol(name, &newAtom);
+ }
+ useNew = picker.choseAtom(newAtom);
+ }
+ if ( useNew ) {
+ _indirectBindingTable[slot] = &newAtom;
+ if ( existingAtom != NULL ) {
+ markCoalescedAway(existingAtom);
+ }
+ if ( newAtom.scope() == ld::Atom::scopeGlobal ) {
+ if ( newAtom.definition() == ld::Atom::definitionTentative ) {
+ _hasExternalTentativeDefinitions = true;
+ }
+ }
+ }
+ else {
+ markCoalescedAway(&newAtom);
+ }
+ // return if existing atom in symbol table was replaced
+ return useNew && (existingAtom != NULL);
+}
+
+
+bool SymbolTable::addByContent(const ld::Atom& newAtom)
+{
+ bool useNew = true;
+ const ld::Atom* existingAtom;
+ IndirectBindingSlot slot = this->findSlotForContent(&newAtom, &existingAtom);
+ //fprintf(stderr, "addByContent(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
+ if ( existingAtom != NULL ) {
+ // use existing unless new one has greater alignment requirements
+ useNew = ( newAtom.alignment().trailingZeros() > existingAtom->alignment().trailingZeros() );
+ }
+ if ( useNew ) {
+ _indirectBindingTable[slot] = &newAtom;
+ if ( existingAtom != NULL )
+ markCoalescedAway(existingAtom);
+ }
+ else {
+ _indirectBindingTable[slot] = existingAtom;
+ if ( existingAtom != &newAtom )
+ markCoalescedAway(&newAtom);
+ }
+ // return if existing atom in symbol table was replaced
+ return useNew && (existingAtom != NULL);
+}
+
+bool SymbolTable::addByReferences(const ld::Atom& newAtom)
+{
+ bool useNew = true;
+ const ld::Atom* existingAtom;
+ IndirectBindingSlot slot = this->findSlotForReferences(&newAtom, &existingAtom);
+ //fprintf(stderr, "addByReferences(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
+ if ( existingAtom != NULL ) {
+ // use existing unless new one has greater alignment requirements
+ useNew = ( newAtom.alignment().trailingZeros() > existingAtom->alignment().trailingZeros() );
+ }
+ if ( useNew ) {
+ _indirectBindingTable[slot] = &newAtom;
+ if ( existingAtom != NULL )
+ markCoalescedAway(existingAtom);
+ }
+ else {
+ if ( existingAtom != &newAtom )
+ markCoalescedAway(&newAtom);
+ }
+ // return if existing atom in symbol table was replaced
+ return useNew && (existingAtom != NULL);
+}
+
+
+bool SymbolTable::add(const ld::Atom& atom, bool ignoreDuplicates)
+{
+ //fprintf(stderr, "SymbolTable::add(%p), name=%s\n", &atom, atom.name());
+ assert(atom.scope() != ld::Atom::scopeTranslationUnit);
+ switch ( atom.combine() ) {
+ case ld::Atom::combineNever:
+ case ld::Atom::combineByName:
+ return this->addByName(atom, ignoreDuplicates);
+ break;
+ case ld::Atom::combineByNameAndContent:
+ return this->addByContent(atom);
+ break;
+ case ld::Atom::combineByNameAndReferences:
+ return this->addByReferences(atom);
+ break;
+ }
+
+ return false;
+}
+
+void SymbolTable::markCoalescedAway(const ld::Atom* atom)
+{
+ // remove this from list of all atoms used
+ //fprintf(stderr, "markCoalescedAway(%p) from %s\n", atom, atom->file()->path());
+ (const_cast<ld::Atom*>(atom))->setCoalescedAway();
+
+ //
+ // The fixupNoneGroupSubordinate* fixup kind is used to model group comdat.
+ // The "signature" atom in the group has a fixupNoneGroupSubordinate* fixup to
+ // all other members of the group. So, if the signature atom is
+ // coalesced away, all other atoms in the group should also be removed.
+ //
+ for (ld::Fixup::iterator fit=atom->fixupsBegin(), fend=atom->fixupsEnd(); fit != fend; ++fit) {
+ switch ( fit->kind ) {
+ case ld::Fixup::kindNoneGroupSubordinate:
+ case ld::Fixup::kindNoneGroupSubordinateFDE:
+ case ld::Fixup::kindNoneGroupSubordinateLSDA:
+ assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+ this->markCoalescedAway(fit->u.target);
+ break;
+ default:
+ break;
+ }
+ }
+
+}
+
+
+struct StrcmpSorter {
+ bool operator() (const char* i,const char* j) {
+ if (i==NULL)
+ return true;
+ if (j==NULL)
+ return false;
+ return strcmp(i, j)<0;}
+};
+
+void SymbolTable::undefines(std::vector<const char*>& undefs)
+{
+ // return all names in _byNameTable that have no associated atom
+ for (NameToSlot::iterator it=_byNameTable.begin(); it != _byNameTable.end(); ++it) {
+ //fprintf(stderr, " _byNameTable[%s] = slot %d which has atom %p\n", it->first, it->second, _indirectBindingTable[it->second]);
+ if ( _indirectBindingTable[it->second] == NULL )
+ undefs.push_back(it->first);
+ }
+ // sort so that undefines are in a stable order (not dependent on hashing functions)
+ struct StrcmpSorter strcmpSorter;
+ std::sort(undefs.begin(), undefs.end(), strcmpSorter);
+}
+
+
+void SymbolTable::tentativeDefs(std::vector<const char*>& tents)
+{
+ // return all names in _byNameTable that have no associated atom
+ for (NameToSlot::iterator it=_byNameTable.begin(); it != _byNameTable.end(); ++it) {
+ const char* name = it->first;
+ const ld::Atom* atom = _indirectBindingTable[it->second];
+ if ( (atom != NULL) && (atom->definition() == ld::Atom::definitionTentative) )
+ tents.push_back(name);
+ }
+ std::sort(tents.begin(), tents.end());
+}
+
+
+bool SymbolTable::hasName(const char* name)
+{
+ NameToSlot::iterator pos = _byNameTable.find(name);
+ if ( pos == _byNameTable.end() )
+ return false;
+ return (_indirectBindingTable[pos->second] != NULL);
+}
+
+// find existing or create new slot
+SymbolTable::IndirectBindingSlot SymbolTable::findSlotForName(const char* name)
+{
+ NameToSlot::iterator pos = _byNameTable.find(name);
+ if ( pos != _byNameTable.end() )
+ return pos->second;
+ // create new slot for this name
+ SymbolTable::IndirectBindingSlot slot = _indirectBindingTable.size();
+ _indirectBindingTable.push_back(NULL);
+ _byNameTable[name] = slot;
+ _byNameReverseTable[slot] = name;
+ return slot;
+}
+
+
+// find existing or create new slot
+SymbolTable::IndirectBindingSlot SymbolTable::findSlotForContent(const ld::Atom* atom, const ld::Atom** existingAtom)
+{
+ //fprintf(stderr, "findSlotForContent(%p)\n", atom);
+ SymbolTable::IndirectBindingSlot slot = 0;
+ UTF16StringToSlot::iterator upos;
+ CStringToSlot::iterator cspos;
+ ContentToSlot::iterator pos;
+ switch ( atom->section().type() ) {
+ case ld::Section::typeCString:
+ cspos = _cstringTable.find(atom);
+ if ( cspos != _cstringTable.end() ) {
+ *existingAtom = _indirectBindingTable[cspos->second];
+ return cspos->second;
+ }
+ slot = _indirectBindingTable.size();
+ _cstringTable[atom] = slot;
+ break;
+ case ld::Section::typeNonStdCString:
+ {
+ // use seg/sect name is key to map to avoid coalescing across segments and sections
+ char segsect[64];
+ sprintf(segsect, "%s/%s", atom->section().segmentName(), atom->section().sectionName());
+ NameToMap::iterator mpos = _nonStdCStringSectionToMap.find(segsect);
+ CStringToSlot* map = NULL;
+ if ( mpos == _nonStdCStringSectionToMap.end() ) {
+ map = new CStringToSlot();
+ _nonStdCStringSectionToMap[strdup(segsect)] = map;
+ }
+ else {
+ map = mpos->second;
+ }
+ cspos = map->find(atom);
+ if ( cspos != map->end() ) {
+ *existingAtom = _indirectBindingTable[cspos->second];
+ return cspos->second;
+ }
+ slot = _indirectBindingTable.size();
+ map->operator[](atom) = slot;
+ }
+ break;
+ case ld::Section::typeUTF16Strings:
+ upos = _utf16Table.find(atom);
+ if ( upos != _utf16Table.end() ) {
+ *existingAtom = _indirectBindingTable[upos->second];
+ return upos->second;
+ }
+ slot = _indirectBindingTable.size();
+ _utf16Table[atom] = slot;
+ break;
+ case ld::Section::typeLiteral4:
+ pos = _literal4Table.find(atom);
+ if ( pos != _literal4Table.end() ) {
+ *existingAtom = _indirectBindingTable[pos->second];
+ return pos->second;
+ }
+ slot = _indirectBindingTable.size();
+ _literal4Table[atom] = slot;
+ break;
+ case ld::Section::typeLiteral8:
+ pos = _literal8Table.find(atom);
+ if ( pos != _literal8Table.end() ) {
+ *existingAtom = _indirectBindingTable[pos->second];
+ return pos->second;
+ }
+ slot = _indirectBindingTable.size();
+ _literal8Table[atom] = slot;
+ break;
+ case ld::Section::typeLiteral16:
+ pos = _literal16Table.find(atom);
+ if ( pos != _literal16Table.end() ) {
+ *existingAtom = _indirectBindingTable[pos->second];
+ return pos->second;
+ }
+ slot = _indirectBindingTable.size();
+ _literal16Table[atom] = slot;
+ break;
+ default:
+ assert(0 && "section type does not support coalescing by content");
+ }
+ _indirectBindingTable.push_back(atom);
+ *existingAtom = NULL;
+ return slot;
+}
+
+
+
+// find existing or create new slot
+SymbolTable::IndirectBindingSlot SymbolTable::findSlotForReferences(const ld::Atom* atom, const ld::Atom** existingAtom)
+{
+ //fprintf(stderr, "findSlotForReferences(%p)\n", atom);
+
+ SymbolTable::IndirectBindingSlot slot = 0;
+ ReferencesToSlot::iterator pos;
+ switch ( atom->section().type() ) {
+ case ld::Section::typeNonLazyPointer:
+ pos = _nonLazyPointerTable.find(atom);
+ if ( pos != _nonLazyPointerTable.end() ) {
+ *existingAtom = _indirectBindingTable[pos->second];
+ return pos->second;
+ }
+ slot = _indirectBindingTable.size();
+ _nonLazyPointerTable[atom] = slot;
+ break;
+ case ld::Section::typeCFString:
+ pos = _cfStringTable.find(atom);
+ if ( pos != _cfStringTable.end() ) {
+ *existingAtom = _indirectBindingTable[pos->second];
+ return pos->second;
+ }
+ slot = _indirectBindingTable.size();
+ _cfStringTable[atom] = slot;
+ break;
+ case ld::Section::typeObjCClassRefs:
+ pos = _objc2ClassRefTable.find(atom);
+ if ( pos != _objc2ClassRefTable.end() ) {
+ *existingAtom = _indirectBindingTable[pos->second];
+ return pos->second;
+ }
+ slot = _indirectBindingTable.size();
+ _objc2ClassRefTable[atom] = slot;
+ break;
+ case ld::Section::typeCStringPointer:
+ pos = _pointerToCStringTable.find(atom);
+ if ( pos != _pointerToCStringTable.end() ) {
+ *existingAtom = _indirectBindingTable[pos->second];
+ return pos->second;
+ }
+ slot = _indirectBindingTable.size();
+ _pointerToCStringTable[atom] = slot;
+ break;
+ default:
+ assert(0 && "section type does not support coalescing by references");
+ }
+ _indirectBindingTable.push_back(atom);
+ *existingAtom = NULL;
+ return slot;
+}
+
+
+const char* SymbolTable::indirectName(IndirectBindingSlot slot) const
+{
+ assert(slot < _indirectBindingTable.size());
+ const ld::Atom* target = _indirectBindingTable[slot];
+ if ( target != NULL ) {
+ return target->name();
+ }
+ // handle case when by-name reference is indirected and no atom yet in _byNameTable
+ SlotToName::const_iterator pos = _byNameReverseTable.find(slot);
+ if ( pos != _byNameReverseTable.end() )
+ return pos->second;
+ assert(0);
+ return NULL;
+}
+
+const ld::Atom* SymbolTable::indirectAtom(IndirectBindingSlot slot) const
+{
+ assert(slot < _indirectBindingTable.size());
+ return _indirectBindingTable[slot];
+}
+
+void SymbolTable::printStatistics()
+{
+// fprintf(stderr, "cstring table size: %lu, bucket count: %lu, hash func called %u times\n",
+// _cstringTable.size(), _cstringTable.bucket_count(), cstringHashCount);
+ int count[11];
+ for(unsigned int b=0; b < 11; ++b) {
+ count[b] = 0;
+ }
+ for(unsigned int i=0; i < _cstringTable.bucket_count(); ++i) {
+ unsigned int n = _cstringTable.elems_in_bucket(i);
+ if ( n < 10 )
+ count[n] += 1;
+ else
+ count[10] += 1;
+ }
+ fprintf(stderr, "cstring table distribution\n");
+ for(unsigned int b=0; b < 11; ++b) {
+ fprintf(stderr, "%u buckets have %u elements\n", count[b], b);
+ }
+ fprintf(stderr, "indirect table size: %lu\n", _indirectBindingTable.size());
+ fprintf(stderr, "by-name table size: %lu\n", _byNameTable.size());
+// fprintf(stderr, "by-content table size: %lu, hash count: %u, equals count: %u, lookup count: %u\n",
+// _byContentTable.size(), contentHashCount, contentEqualCount, contentLookupCount);
+// fprintf(stderr, "by-ref table size: %lu, hashed count: %u, equals count: %u, lookup count: %u, insert count: %u\n",
+// _byReferencesTable.size(), refHashCount, refEqualsCount, refLookupCount, refInsertCount);
+
+ //ReferencesHash obj;
+ //for(ReferencesHashToSlot::iterator it=_byReferencesTable.begin(); it != _byReferencesTable.end(); ++it) {
+ // if ( obj.operator()(it->first) == 0x2F3AC0EAC744EA70 ) {
+ // fprintf(stderr, "hash=0x2F3AC0EAC744EA70 for %p %s from %s\n", it->first, it->first->name(), it->first->file()->path());
+ //
+ // }
+ //}
+
+}
+
+} // namespace tool
+} // namespace ld
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __SYMBOL_TABLE_H__
+#define __SYMBOL_TABLE_H__
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+
+#include <vector>
+#include <ext/hash_map>
+
+#include "Options.h"
+#include "ld.hpp"
+
+namespace ld {
+namespace tool {
+
+
+class SymbolTable : public ld::IndirectBindingTable
+{
+public:
+ typedef uint32_t IndirectBindingSlot;
+
+private:
+ class CStringEquals {
+ public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+ };
+ typedef __gnu_cxx::hash_map<const char*, IndirectBindingSlot, __gnu_cxx::hash<const char*>, CStringEquals> NameToSlot;
+
+ class ContentFuncs {
+ public:
+ size_t operator()(const ld::Atom*) const;
+ bool operator()(const ld::Atom* left, const ld::Atom* right) const;
+ };
+ typedef __gnu_cxx::hash_map<const ld::Atom*, IndirectBindingSlot, ContentFuncs, ContentFuncs> ContentToSlot;
+
+ class ReferencesHashFuncs {
+ public:
+ size_t operator()(const ld::Atom*) const;
+ bool operator()(const ld::Atom* left, const ld::Atom* right) const;
+ };
+ typedef __gnu_cxx::hash_map<const ld::Atom*, IndirectBindingSlot, ReferencesHashFuncs, ReferencesHashFuncs> ReferencesToSlot;
+
+ class CStringHashFuncs {
+ public:
+ size_t operator()(const ld::Atom*) const;
+ bool operator()(const ld::Atom* left, const ld::Atom* right) const;
+ };
+ typedef __gnu_cxx::hash_map<const ld::Atom*, IndirectBindingSlot, CStringHashFuncs, CStringHashFuncs> CStringToSlot;
+
+ class UTF16StringHashFuncs {
+ public:
+ size_t operator()(const ld::Atom*) const;
+ bool operator()(const ld::Atom* left, const ld::Atom* right) const;
+ };
+ typedef __gnu_cxx::hash_map<const ld::Atom*, IndirectBindingSlot, UTF16StringHashFuncs, UTF16StringHashFuncs> UTF16StringToSlot;
+
+ typedef std::map<IndirectBindingSlot, const char*> SlotToName;
+ typedef __gnu_cxx::hash_map<const char*, CStringToSlot*, __gnu_cxx::hash<const char*>, CStringEquals> NameToMap;
+
+ typedef std::vector<const ld::Atom *> DuplicatedSymbolAtomList;
+ typedef std::map<const char *, DuplicatedSymbolAtomList * > DuplicateSymbols;
+
+public:
+
+ class byNameIterator {
+ public:
+ byNameIterator& operator++(int) { ++_nameTableIterator; return *this; }
+ const ld::Atom* operator*() { return _slotTable[_nameTableIterator->second]; }
+ bool operator!=(const byNameIterator& lhs) { return _nameTableIterator != lhs._nameTableIterator; }
+
+ private:
+ friend class SymbolTable;
+ byNameIterator(NameToSlot::iterator it, std::vector<const ld::Atom*>& indirectTable)
+ : _nameTableIterator(it), _slotTable(indirectTable) {}
+
+ NameToSlot::iterator _nameTableIterator;
+ std::vector<const ld::Atom*>& _slotTable;
+ };
+
+ SymbolTable(const Options& opts, std::vector<const ld::Atom*>& ibt);
+
+ bool add(const ld::Atom& atom, bool ignoreDuplicates);
+ IndirectBindingSlot findSlotForName(const char* name);
+ IndirectBindingSlot findSlotForContent(const ld::Atom* atom, const ld::Atom** existingAtom);
+ IndirectBindingSlot findSlotForReferences(const ld::Atom* atom, const ld::Atom** existingAtom);
+ const ld::Atom* atomForSlot(IndirectBindingSlot s) { return _indirectBindingTable[s]; }
+ unsigned int updateCount() { return _indirectBindingTable.size(); }
+ void undefines(std::vector<const char*>& undefines);
+ void tentativeDefs(std::vector<const char*>& undefines);
+ bool hasName(const char* name);
+ bool hasExternalTentativeDefinitions() { return _hasExternalTentativeDefinitions; }
+ byNameIterator begin() { return byNameIterator(_byNameTable.begin(),_indirectBindingTable); }
+ byNameIterator end() { return byNameIterator(_byNameTable.end(),_indirectBindingTable); }
+ void printStatistics();
+
+ // from ld::IndirectBindingTable
+ virtual const char* indirectName(IndirectBindingSlot slot) const;
+ virtual const ld::Atom* indirectAtom(IndirectBindingSlot slot) const;
+
+ // Prints the duplicated symbols to stderr and throws. Only valid to call if hasDuplicateSymbols() returns true.
+ void checkDuplicateSymbols() const;
+
+
+private:
+ bool addByName(const ld::Atom& atom, bool ignoreDuplicates);
+ bool addByContent(const ld::Atom& atom);
+ bool addByReferences(const ld::Atom& atom);
+ void markCoalescedAway(const ld::Atom* atom);
+
+ // Tracks duplicated symbols. Each call adds file to the list of files defining symbol.
+ // The file list is uniqued per symbol, so calling multiple times for the same symbol/file pair is permitted.
+ void addDuplicateSymbol(const char *symbol, const ld::Atom* atom);
+
+ const Options& _options;
+ NameToSlot _byNameTable;
+ SlotToName _byNameReverseTable;
+ ContentToSlot _literal4Table;
+ ContentToSlot _literal8Table;
+ ContentToSlot _literal16Table;
+ UTF16StringToSlot _utf16Table;
+ CStringToSlot _cstringTable;
+ NameToMap _nonStdCStringSectionToMap;
+ ReferencesToSlot _nonLazyPointerTable;
+ ReferencesToSlot _cfStringTable;
+ ReferencesToSlot _objc2ClassRefTable;
+ ReferencesToSlot _pointerToCStringTable;
+ std::vector<const ld::Atom*>& _indirectBindingTable;
+ bool _hasExternalTentativeDefinitions;
+
+ DuplicateSymbols _duplicateSymbols;
+
+};
+
+} // namespace tool
+} // namespace ld
+
+
+#endif // __SYMBOL_TABLE_H__
--- /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@
+ */
+
+
+//
+// blob - generic extensible binary blob frame
+//
+#include "blob.h"
+
+namespace Security {
+
+
+//
+// Content access and validation calls
+//
+char *BlobCore::stringAt(Offset offset)
+{
+ char *s = at<char>(offset);
+ if (offset < this->length() && memchr(s, 0, this->length() - offset))
+ return s;
+ else
+ return NULL;
+}
+
+const char *BlobCore::stringAt(Offset offset) const
+{
+ const char *s = at<const char>(offset);
+ if (offset < this->length() && memchr(s, 0, this->length() - offset))
+ return s;
+ else
+ return NULL;
+}
+
+
+//
+// Read a blob from a standard file stream.
+// Reads in one pass, so it's suitable for transmission over pipes and networks.
+// The blob is allocated with malloc(3).
+// On error, sets errno and returns NULL; in which case the input stream may
+// be partially consumed.
+//
+BlobCore *BlobCore::readBlob(int fd, size_t offset, uint32_t magic, size_t minSize, size_t maxSize)
+{
+ BlobCore header;
+ if (::pread(fd, &header, sizeof(header), offset) == sizeof(header))
+ if (header.validateBlob(magic, minSize, maxSize))
+ if (BlobCore *blob = (BlobCore *)malloc(header.length())) {
+ memcpy(blob, &header, sizeof(header));
+ size_t remainder = header.length() - sizeof(header);
+ if (::pread(fd, blob+1, remainder, offset + sizeof(header)) == ssize_t(remainder))
+ return blob;
+ free(blob);
+ errno = EINVAL;
+ }
+ return NULL;
+}
+
+BlobCore *BlobCore::readBlob(int fd, uint32_t magic, size_t minSize, size_t maxSize)
+{
+ BlobCore header;
+ if (::read(fd, &header, sizeof(header)) == sizeof(header))
+ if (header.validateBlob(magic, minSize, maxSize))
+ if (BlobCore *blob = (BlobCore *)malloc(header.length())) {
+ memcpy(blob, &header, sizeof(header));
+ size_t remainder = header.length() - sizeof(header);
+ if (::read(fd, blob+1, remainder) == ssize_t(remainder))
+ return blob;
+ free(blob);
+ errno = EINVAL;
+ }
+ return NULL;
+}
+
+BlobCore *BlobCore::readBlob(std::FILE *file, uint32_t magic, size_t minSize, size_t maxSize)
+{
+ BlobCore header;
+ if (::fread(&header, sizeof(header), 1, file) == 1)
+ if (header.validateBlob(magic, minSize, maxSize))
+ if (BlobCore *blob = (BlobCore *)malloc(header.length())) {
+ memcpy(blob, &header, sizeof(header));
+ if (::fread(blob+1, header.length() - sizeof(header), 1, file) == 1)
+ return blob;
+ free(blob);
+ errno = EINVAL;
+ }
+ return NULL;
+}
+
+
+//
+// BlobWrappers
+//
+BlobWrapper *BlobWrapper::alloc(size_t length, Magic magic /* = _magic */)
+{
+ size_t wrapLength = length + sizeof(BlobCore);
+ BlobWrapper *w = (BlobWrapper *)malloc(wrapLength);
+ w->BlobCore::initialize(magic, wrapLength);
+ return w;
+}
+
+BlobWrapper *BlobWrapper::alloc(const void *data, size_t length, Magic magic /* = _magic */)
+{
+ BlobWrapper *w = alloc(length, magic);
+ memcpy(w->data(), data, w->length());
+ return w;
+}
+
+
+} // Security
--- /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@
+ */
+
+//
+// blob - generic extensible binary blob frame
+//
+// To define a new type of binary blob:
+// class MyBlob : public Blob<MyBlob, magic number> { ... }
+// Pick a unique magic number (32-bit). Blobs are understood to be a MyBlob
+// header possibly followed by more data as a contiguous memory area. Length
+// is overall (including the header), so a fixed-size blob would have length
+// sizeof(MyBlob). Both length and magic are stored in NBO.
+//
+// You are highly encouraged to follow these rules:
+// Store all integers in NBO, including offsets.
+// Use internal offsets to "point to" dynamically-sized elements past the
+// header (using the at<Type>(offset) method for access).
+// Don't use pointers in your blob.
+// If you follow those rules, your blobs will be fully relocatable, byte-order
+// independent, and generally spreading happiness around your code.
+//
+#ifndef _H_BLOB
+#define _H_BLOB
+
+#include "endian.h"
+#include "memutils.h"
+#include <errno.h>
+
+namespace Security {
+
+enum {
+ // CodeDirectory slot numbers, used to index the EmbeddedSignatureBlob (from codedirectory.h, internal)
+ cdRequirementsSlot = 2 // embedded signature: internal requirements
+};
+
+enum {
+ // Code Signing magic blob types (from <Security/CSCommonPriv.h>)
+ kSecCodeMagicRequirement = 0xfade0c00, /* single requirement */
+ kSecCodeMagicRequirementSet = 0xfade0c01, /* requirement set */
+ kSecCodeMagicEmbeddedSignature = 0xfade0cc0, /* single-architecture embedded signature */
+
+ kSecCodeMagicDRList = 0xfade0c05
+};
+
+enum {
+ // from CSCommon.h
+ kSecDesignatedRequirementType = 3 /* designated requirement */
+};
+
+//
+// All blobs in memory have this form.
+// You can have polymorphic memory blobs (C style) using different magics numbers.
+//
+class BlobCore {
+public:
+ typedef uint32_t Offset;
+ typedef uint32_t Magic;
+
+ Magic magic() const { return mMagic; }
+ size_t length() const { return mLength; }
+
+ void initialize(Magic mag, size_t len = 0)
+ { mMagic = mag; mLength = len; }
+
+ bool validateBlob(Magic magic, size_t minSize = 0, size_t maxSize = 0) const;
+
+ template <class T, class Offset>
+ T *at(Offset offset)
+ { return LowLevelMemoryUtilities::increment<T>(this, offset); }
+
+ template <class T, class Offset>
+ const T *at(Offset offset) const
+ { return LowLevelMemoryUtilities::increment<const T>(this, offset); }
+
+ template <class Offset1, class Offset2>
+ bool contains(Offset1 offset, Offset2 size) const
+ { return offset >= 0 && size_t(offset) >= sizeof(BlobCore) && (size_t(offset) + size) <= this->length(); }
+
+ template <class Base, class Offset>
+ bool contains(Base *ptr, Offset size) const
+ { return contains(LowLevelMemoryUtilities::difference(ptr, this), size); }
+
+ char *stringAt(Offset offset);
+ const char *stringAt(Offset offset) const;
+
+ void *data() { return this; }
+ const void *data() const { return this; }
+ void length(size_t size) { mLength = size; }
+
+ template <class BlobType>
+ bool is() const { return magic() == BlobType::typeMagic; }
+
+ static BlobCore *readBlob(std::FILE *file) { return readBlob(file, 0, 0, 0); }
+ static BlobCore *readBlob(int fd) { return readBlob(fd, 0, 0, 0); }
+
+protected:
+ static BlobCore *readBlob(std::FILE *file, uint32_t magic, size_t minSize, size_t maxSize); // streaming
+ static BlobCore *readBlob(int fd, uint32_t magic, size_t minSize, size_t maxSize); // streaming
+ static BlobCore *readBlob(int fd, size_t offset, uint32_t magic, size_t minSize, size_t maxSize); // pread(2)@offset
+
+protected:
+ Endian<uint32_t> mMagic;
+ Endian<uint32_t> mLength;
+};
+
+
+// basic validation helper
+inline bool BlobCore::validateBlob(Magic mag, size_t minSize /* = 0 */, size_t maxSize /* = 0 */) const
+{
+ uint32_t len = this->mLength;
+ if (mag && (mag != this->mMagic)) {
+ errno = EINVAL;
+ return false;
+ }
+ if (minSize ? (len < minSize) : (len < sizeof(BlobCore))) {
+ errno = EINVAL;
+ return false;
+ }
+ if (maxSize && len > maxSize) {
+ errno = ENOMEM;
+ return false;
+ }
+ return true;
+}
+
+
+//
+// Typed Blobs (BlobCores that know their real type and magic)
+//
+template <class BlobType, uint32_t _magic>
+class Blob: public BlobCore {
+public:
+ void initialize(size_t size = 0) { BlobCore::initialize(_magic, size); }
+
+ static const Magic typeMagic = _magic;
+
+ bool validateBlob() const
+ { return BlobCore::validateBlob(_magic, sizeof(BlobType)); }
+
+ bool validateBlob(size_t extLength) const
+ { return validateBlob() && mLength == extLength; }
+
+ static BlobType *specific(BlobCore *blob, bool unalloc = false)
+ {
+ if (BlobType *p = static_cast<BlobType *>(blob)) {
+ if (p->validateBlob())
+ return p;
+ if (unalloc)
+ ::free(p);
+ }
+ return NULL;
+ }
+
+ static const BlobType *specific(const BlobCore *blob)
+ {
+ const BlobType *p = static_cast<const BlobType *>(blob);
+ if (p && p->validateBlob())
+ return p;
+ return NULL;
+ }
+
+ BlobType *clone() const
+ { assert(validateBlob()); return specific(this->BlobCore::clone()); }
+
+ static BlobType *readBlob(int fd)
+ { return specific(BlobCore::readBlob(fd, _magic, sizeof(BlobType), 0), true); }
+
+ static BlobType *readBlob(int fd, size_t offset, size_t maxSize = 0)
+ { return specific(BlobCore::readBlob(fd, offset, _magic, sizeof(BlobType), maxSize), true); }
+
+ static BlobType *readBlob(std::FILE *file)
+ { return specific(BlobCore::readBlob(file, _magic, sizeof(BlobType), 0), true); }
+};
+
+
+//
+// A generic blob wrapped around arbitrary (flat) binary data.
+// This can be used to "regularize" plain binary data, so it can be handled
+// as a genuine Blob (e.g. for insertion into a SuperBlob).
+//
+class BlobWrapper : public Blob<BlobWrapper, 0xfade0b01> {
+public:
+ static BlobWrapper *alloc(size_t length, Magic magic = BlobWrapper::typeMagic);
+ static BlobWrapper *alloc(const void *data, size_t length, Magic magic = BlobWrapper::typeMagic);
+
+ unsigned char dataArea[0];
+
+ // override data/length to point to the payload (only)
+ void *data() { return dataArea; }
+ const void *data() const { return dataArea; }
+ size_t length() const { return BlobCore::length() - sizeof(BlobCore); }
+};
+
+
+} // Security
+
+#endif //_H_BLOB
--- /dev/null
+/*
+ * Copyright (c) 2002-2004 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@
+ */
+
+
+/*
+ * cssm utilities
+ */
+#ifndef _H_ENDIAN
+#define _H_ENDIAN
+
+#include <machine/endian.h>
+#include <libkern/OSByteOrder.h>
+//#include <security_utilities/utilities.h>
+#include "memutils.h"
+
+namespace Security {
+
+
+//
+// Encode/decode operations by type, overloaded.
+// You can use these functions directly, but consider using
+// the higher-level constructs below instead.
+//
+#ifdef __LP64__
+static inline unsigned long h2n(unsigned long v) { return OSSwapHostToBigInt64(v); }
+static inline unsigned long n2h(unsigned long v) { return OSSwapBigToHostInt64(v); }
+static inline unsigned long flip(unsigned long v) { return OSSwapInt64(v); }
+static inline signed long h2n(signed long v) { return OSSwapHostToBigInt64(v); }
+static inline signed long n2h(signed long v) { return OSSwapBigToHostInt64(v); }
+static inline signed long flip(signed long v) { return OSSwapInt64(v); }
+#else
+static inline unsigned long h2n(unsigned long v) { return htonl(v); }
+static inline unsigned long n2h(unsigned long v) { return ntohl(v); }
+static inline unsigned long flip(unsigned long v) { return OSSwapInt32(v); }
+static inline signed long h2n(signed long v) { return htonl(v); }
+static inline signed long n2h(signed long v) { return ntohl(v); }
+static inline signed long flip(signed long v) { return OSSwapInt32(v); }
+#endif
+
+static inline unsigned long long h2n(unsigned long long v) { return OSSwapHostToBigInt64(v); }
+static inline unsigned long long n2h(unsigned long long v) { return OSSwapBigToHostInt64(v); }
+static inline unsigned long long flip(unsigned long long v) { return OSSwapInt64(v); }
+static inline long long h2n(long long v) { return OSSwapHostToBigInt64(v); }
+static inline long long n2h(long long v) { return OSSwapBigToHostInt64(v); }
+static inline long long flip(long long v) { return OSSwapInt64(v); }
+
+static inline unsigned int h2n(unsigned int v) { return htonl(v); }
+static inline unsigned int n2h(unsigned int v) { return ntohl(v); }
+static inline unsigned int flip(unsigned int v) { return OSSwapInt32(v); }
+static inline signed int h2n(int v) { return htonl(v); }
+static inline signed int n2h(int v) { return ntohl(v); }
+static inline signed int flip(int v) { return OSSwapInt32(v); }
+
+static inline unsigned short h2n(unsigned short v) { return htons(v); }
+static inline unsigned short n2h(unsigned short v) { return ntohs(v); }
+static inline unsigned short flip(unsigned short v) { return OSSwapInt16(v); }
+static inline signed short h2n(signed short v) { return htons(v); }
+static inline signed short n2h(signed short v) { return ntohs(v); }
+static inline signed short flip(signed short v) { return OSSwapInt16(v); }
+
+static inline unsigned char h2n(unsigned char v) { return v; }
+static inline unsigned char n2h(unsigned char v) { return v; }
+static inline unsigned char flip(unsigned char v) { return v; }
+static inline signed char h2n(signed char v) { return v; }
+static inline signed char n2h(signed char v) { return v; }
+static inline signed char flip(signed char v) { return v; }
+
+
+//
+// Flip pointers
+//
+template <class Base>
+static inline Base *h2n(Base *p) { return (Base *)h2n(uintptr_t(p)); }
+
+template <class Base>
+static inline Base *n2h(Base *p) { return (Base *)n2h(uintptr_t(p)); }
+
+
+//
+// In-place fix operations
+//
+template <class Type>
+static inline void h2ni(Type &v) { v = h2n(v); }
+
+template <class Type>
+static inline void n2hi(Type &v) { v = n2h(v); }
+
+//
+// Endian<SomeType> keeps NBO values in memory and converts
+// during loads and stores. This presumes that you are using
+// memory blocks thare are read/written/mapped as amorphous byte
+// streams, but want to be byte-order clean using them.
+//
+// The generic definition uses h2n/n2h to flip bytes. Feel free
+// to declare specializations of Endian<T> as appropriate.
+//
+// Note well that the address of an Endian<T> is not an address-of-T,
+// and there is no conversion available.
+//
+template <class Type>
+class Endian {
+public:
+ typedef Type Value;
+ Endian() : mValue(Type(0)) { }
+ Endian(Value v) : mValue(h2n(v)) { }
+
+ operator Value () const { return n2h(mValue); }
+ Endian &operator = (Value v) { mValue = h2n(v); return *this; }
+
+private:
+ Value mValue;
+};
+
+
+} // end namespace Security
+
+
+#endif //_H_ENDIAN
--- /dev/null
+/*
+ * Copyright (c) 2000-2004 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@
+ */
+
+
+//
+// memutils - memory-related low-level utilities for easier living
+//
+#ifndef _H_MEMUTILS
+#define _H_MEMUTILS
+
+//#include <security_utilities/utilities.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <algorithm>
+
+
+//
+// Encapsulate these very sharp tools in a separate (ugly-named) namespace
+//
+namespace Security {
+namespace LowLevelMemoryUtilities {
+
+
+//
+// The default system alignment.
+//
+static const size_t systemAlignment = 4;
+
+
+//
+// Get the local alignment for a type, as used by the acting compiler.
+//
+template <class T>
+inline size_t alignof() { struct { char c; T t; } s; return sizeof(s) - sizeof(T); }
+
+
+//
+// Get the local offset of a field in a (struct or class) type, as layed out
+// by the acting compiler.
+// NB: "offsetof" is a standard-defined macro. Don't use that.
+//
+template <class Type, class Field>
+inline size_t fieldOffsetOf(Field (Type::*field))
+{
+ Type *object = 0; // we don't REALLY need this, but it's easier to read
+ return uintptr_t(&(object->*field)) - uintptr_t(object);
+}
+
+
+//
+// Round up a size or pointer to an alignment boundary.
+// Alignment must be a power of two; default is default alignment.
+//
+inline size_t alignUp(size_t size, size_t alignment = systemAlignment)
+{
+ return ((size - 1) & ~(alignment - 1)) + alignment;
+}
+
+inline void *alignUp(void *p, size_t alignment = systemAlignment)
+{
+ return reinterpret_cast<void *>(alignUp(uintptr_t(p), alignment));
+}
+
+inline const void *alignUp(const void *p, size_t alignment = systemAlignment)
+{
+ return reinterpret_cast<const void *>(alignUp(uintptr_t(p), alignment));
+}
+
+template <class T>
+inline const T *increment(const void *p, ptrdiff_t offset)
+{ return reinterpret_cast<const T *>(uintptr_t(p) + offset); }
+
+template <class T>
+inline T *increment(void *p, ptrdiff_t offset)
+{ return reinterpret_cast<T *>(uintptr_t(p) + offset); }
+
+inline const void *increment(const void *p, ptrdiff_t offset)
+{ return increment<const void>(p, offset); }
+
+inline void *increment(void *p, ptrdiff_t offset)
+{ return increment<void>(p, offset); }
+
+template <class T>
+inline const T *increment(const void *p, ptrdiff_t offset, size_t alignment)
+{ return increment<const T>(alignUp(p, alignment), offset); }
+
+template <class T>
+inline T *increment(void *p, ptrdiff_t offset, size_t alignment)
+{ return increment<T>(alignUp(p, alignment), offset); }
+
+inline const void *increment(const void *p, ptrdiff_t offset, size_t alignment)
+{ return increment<const void>(p, offset, alignment); }
+
+inline void *increment(void *p, ptrdiff_t offset, size_t alignment)
+{ return increment<void>(p, offset, alignment); }
+
+inline ptrdiff_t difference(const void *p1, const void *p2)
+{ return uintptr_t(p1) - uintptr_t(p2); }
+
+
+} // end namespace LowLevelMemoryUtilities
+} // end namespace Security
+
+#endif //_H_MEMUTILS
--- /dev/null
+//
+// SuperBlob - a typed bag of Blobs
+//
+#ifndef _H_SUPERBLOB
+#define _H_SUPERBLOB
+
+#include "blob.h"
+#include <assert.h>
+#include <utility>
+#include <map>
+
+using namespace std;
+
+namespace Security {
+
+
+//
+// A SuperBlob is a Blob that contains multiple sub-Blobs of varying type.
+// The SuperBlob is contiguous and contains a directory of its sub-blobs.
+// A Maker is included.
+//
+// SuperBlobCore lets you define your own SuperBlob type. To just use a generic
+// SuperBlob, use SuperBlob<> below.
+//
+template <class _BlobType, uint32_t _magic, class _Type>
+class SuperBlobCore: public Blob<_BlobType, _magic> {
+public:
+ class Maker; friend class Maker;
+
+ typedef _Type Type;
+
+ // echoes from parent BlobCore (the C++ type system is too restrictive here)
+ typedef BlobCore::Offset Offset;
+ template <class BlobType> BlobType *at(Offset offset) { return BlobCore::at<BlobType>(offset); }
+ template <class BlobType> const BlobType *at(Offset offset) const { return BlobCore::at<BlobType>(offset); }
+
+ void setup(size_t size, unsigned cnt)
+ { this->initialize(size); this->mCount = cnt; }
+
+ struct Index {
+ Endian<Type> type; // type of sub-Blob
+ Endian<Offset> offset; // starting offset
+ };
+
+ bool validateBlob(size_t maxSize = 0) const;
+
+ unsigned count() const { return mCount; }
+
+ // access by index number
+ Type type(unsigned n) const { assert(n < mCount); return mIndex[n].type; }
+ const BlobCore *blob(unsigned n) const { assert(n < mCount); Offset off=mIndex[n].offset; return off ? at<const BlobCore>(off) : NULL; }
+
+ template <class BlobType>
+ const BlobType *blob(unsigned n) const { return BlobType::specific(blob(n)); }
+
+ // access by index type (assumes unique types)
+ const BlobCore *find(Type type) const;
+ template <class BlobType>
+ const BlobType *find(Type t) const { return BlobType::specific(find(t)); }
+
+private:
+ Endian<uint32_t> mCount; // number of sub-Blobs following
+ Index mIndex[0]; // <count> IndexSlot structures
+ // followed by sub-Blobs, packed and ordered in an undefined way
+};
+
+
+template <class _BlobType, uint32_t _magic, class _Type>
+inline bool SuperBlobCore<_BlobType, _magic, _Type>::validateBlob(size_t maxSize /* = 0 */) const
+{
+ unsigned cnt = mCount;
+ size_t ixLimit = sizeof(SuperBlobCore) + cnt * sizeof(Index); // end of index vector
+ if (!BlobCore::validateBlob(_magic, ixLimit, maxSize))
+ return false;
+
+ for (const Index *ix = mIndex + cnt - 1; ix >= mIndex; ix--) {
+ Offset offset = ix->offset;
+ if ( offset == 0 )
+ continue; // offset==0 means unused entry
+ if (offset < ixLimit // offset not too small
+ || offset + sizeof(BlobCore) > this->length() // fits Blob header (including length field)
+ || offset + at<const BlobCore>(offset)->length() > this->length()) // fits entire blob
+ return false;
+ }
+ return true;
+}
+
+
+//
+// A generic SuperBlob ready for use. You still need to specify a magic number.
+//
+template <uint32_t _magic, class _Type = uint32_t>
+class SuperBlob : public SuperBlobCore<SuperBlob<_magic, _Type>, _magic, _Type> {
+};
+
+
+template <class _BlobType, uint32_t _magic, class _Type>
+const BlobCore *SuperBlobCore<_BlobType, _magic, _Type>::find(Type t) const
+{
+ for (unsigned slot = 0; slot < mCount; slot++) {
+ if (mIndex[slot].type == t) {
+ uint32_t off = mIndex[slot].offset;
+ if ( off == 0 )
+ return NULL;
+ else
+ return at<const BlobCore>(off);
+ }
+ }
+ return NULL; // not found
+}
+
+
+//
+// A SuperBlob::Maker simply assembles multiple Blobs into a single, indexed
+// super-blob. Just add() sub-Blobs by type and call build() to get
+// the result, malloc'ed. A Maker is not reusable.
+// Maker can repeatedly make SuperBlobs from the same (cached) inputs.
+// It can also tell you how big its output will be, given established contents
+// plus (optional) additional sizes of blobs yet to come.
+//
+template <class _BlobType, uint32_t _magic, class _Type>
+class SuperBlobCore<_BlobType, _magic, _Type>::Maker {
+public:
+ Maker() { }
+
+ Maker(const Maker &src)
+ {
+ for (typename BlobMap::iterator it = mPieces.begin(); it != mPieces.end(); ++it)
+ mPieces.insert(make_pair(it->first, it->second->clone()));
+ }
+
+ ~Maker()
+ {
+ for (typename BlobMap::iterator it = mPieces.begin(); it != mPieces.end(); ++it)
+ ::free(it->second);
+ }
+
+ void add(Type type, BlobCore *blob); // takes ownership of blob
+ void add(const _BlobType *blobs); // copies all blobs
+ void add(const Maker &maker); // ditto
+
+ size_t size(size_t size1 = 0, ...) const; // size with optional additional blob sizes
+ _BlobType *make() const; // create (malloc) and return SuperBlob
+ _BlobType *operator () () const { return make(); }
+
+private:
+ typedef std::map<Type, BlobCore *> BlobMap;
+ BlobMap mPieces;
+};
+
+
+//
+// Add a Blob to a SuperBlob::Maker.
+// This takes ownership of the blob, which must have been malloc'ed.
+// Any previous value set for this Type will be freed immediately.
+//
+template <class _BlobType, uint32_t _magic, class _Type>
+void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(Type type, BlobCore *blob)
+{
+ pair<typename BlobMap::iterator, bool> r = mPieces.insert(make_pair(type, blob));
+ if (!r.second) { // already there
+ //secdebug("superblob", "Maker %p replaces type=%d", this, type);
+ ::free(r.first->second);
+ r.first->second = blob;
+ }
+}
+
+template <class _BlobType, uint32_t _magic, class _Type>
+void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(const _BlobType *blobs)
+{
+ for (uint32_t ix = 0; ix < blobs->mCount; ix++)
+ this->add(blobs->mIndex[ix].type, blobs->blob(ix)->clone());
+}
+
+template <class _BlobType, uint32_t _magic, class _Type>
+void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(const Maker &maker)
+{
+ for (typename BlobMap::const_iterator it = maker.mPieces.begin(); it != maker.mPieces.end(); ++it)
+ this->add(it->first, it->second->clone());
+}
+
+
+//
+// Calculate the size the new SuperBlob would have, given the contents of the Maker
+// so far, plus additional blobs with the sizes given.
+//
+template <class _BlobType, uint32_t _magic, class _Type>
+size_t SuperBlobCore<_BlobType, _magic, _Type>::Maker::size(size_t size1, ...) const
+{
+ // count established blobs
+ unsigned count = mPieces.size();
+ size_t total = 0;
+ for (typename BlobMap::const_iterator it = mPieces.begin(); it != mPieces.end(); ++it) {
+ if ( it->second != NULL )
+ total += (it->second->length() + 3) & (-4); // 4-byte align each element
+ }
+
+ // add preview blob sizes to calculation (if any)
+ if (size1) {
+ va_list args;
+ va_start(args, size1);
+ do {
+ count++;
+ total += size1;
+ size1 = va_arg(args, size_t);
+ } while (size1);
+ va_end(args);
+ }
+
+ return sizeof(SuperBlobCore) + count * sizeof(Index) + total;
+}
+
+
+//
+// Finish SuperBlob construction and return the new, malloc'ed, SuperBlob.
+// This can be done repeatedly.
+//
+template <class _BlobType, uint32_t _magic, class _Type>
+_BlobType *SuperBlobCore<_BlobType, _magic, _Type>::Maker::make() const
+{
+ Offset pc = sizeof(SuperBlobCore) + mPieces.size() * sizeof(Index);
+ Offset total = size();
+ _BlobType *result = (_BlobType *)calloc(1, total);
+ if (!result)
+ throw ENOMEM;
+ result->setup(total, mPieces.size());
+ unsigned n = 0;
+ for (typename BlobMap::const_iterator it = mPieces.begin(); it != mPieces.end(); ++it) {
+ result->mIndex[n].type = it->first;
+ BlobCore* b = it->second;
+ if ( b != NULL ) {
+ result->mIndex[n].offset = pc;
+ memcpy(result->template at<unsigned char>(pc), b, b->length());
+ pc += ((b->length() + 3) & (-4)); // 4-byte align each element
+ }
+ else {
+ result->mIndex[n].offset = 0;
+ }
+ n++;
+ }
+ //secdebug("superblob", "Maker %p assembles %ld blob(s) into %p (size=%d)",
+ // this, mPieces.size(), result, total);
+ return result;
+}
+
+
+} // Security
+
+#endif //_H_SUPERBLOB
--- /dev/null
+/*
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#ifndef KLD
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include "dwarf2.h"
+#include "debugline.h"
+
+struct line_reader_data
+{
+ bool little_endian;
+
+ /* From the line number information header. */
+ uint8_t minimum_instruction_length;
+ int8_t line_base;
+ uint8_t line_range;
+ uint8_t opcode_base;
+ const uint8_t * standard_opcode_lengths;
+ size_t numdir;
+ const uint8_t * * dirnames;
+ size_t numfile_orig;
+ size_t numfile; /* As updated during execution of the table. */
+ const uint8_t * * filenames;
+
+ /* Current position in the line table. */
+ const uint8_t * cpos;
+ /* End of this part of the line table. */
+ const uint8_t * end;
+ /* Start of the line table. */
+ const uint8_t * init;
+
+ struct line_info cur;
+};
+
+/* Read in a word of fixed size, which may be unaligned, in the
+ appropriate endianness. */
+#define read_16(p) (lnd->little_endian \
+ ? ((p)[1] << 8 | (p)[0]) \
+ : ((p)[0] << 8 | (p)[1]))
+#define read_32(p) (lnd->little_endian \
+ ? ((p)[3] << 24 | (p)[2] << 16 | (p)[1] << 8 | (p)[0]) \
+ : ((p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3]))
+#define read_64(p) (lnd->little_endian \
+ ? ((uint64_t) (p)[7] << 56 | (uint64_t) (p)[6] << 48 \
+ | (uint64_t) (p)[5] << 40 | (uint64_t) (p)[4] << 32 \
+ | (uint64_t) (p)[3] << 24 | (uint64_t) (p)[2] << 16u \
+ | (uint64_t) (p)[1] << 8 | (uint64_t) (p)[0]) \
+ : ((uint64_t) (p)[0] << 56 | (uint64_t) (p)[1] << 48 \
+ | (uint64_t) (p)[2] << 40 | (uint64_t) (p)[3] << 32 \
+ | (uint64_t) (p)[4] << 24 | (uint64_t) (p)[5] << 16u \
+ | (uint64_t) (p)[6] << 8 | (uint64_t) (p)[7]))
+
+/* Skip over a LEB128 value (signed or unsigned). */
+static void
+skip_leb128 (struct line_reader_data * leb)
+{
+ while (leb->cpos != leb->end && *leb->cpos >= 0x80)
+ leb->cpos++;
+ if (leb->cpos != leb->end)
+ leb->cpos++;
+}
+
+/* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow
+ or error. On overflow, skip past the rest of the uleb128. */
+static uint64_t
+read_uleb128 (struct line_reader_data * leb)
+{
+ uint64_t result = 0;
+ int bit = 0;
+
+ do {
+ uint64_t b;
+
+ if (leb->cpos == leb->end)
+ return (uint64_t) -1;
+
+ b = *leb->cpos & 0x7f;
+
+ if (bit >= 64 || b << bit >> bit != b)
+ result = (uint64_t) -1;
+ else
+ result |= b << bit, bit += 7;
+ } while (*leb->cpos++ >= 0x80);
+ return result;
+}
+
+
+/* Read a SLEB128 into a 64-bit word. Return 0 on overflow or error
+ (which is not very helpful). On overflow, skip past the rest of
+ the SLEB128. For negative numbers, this actually overflows when
+ under -2^62, but since this is used for line numbers that ought to
+ be OK... */
+static int64_t
+read_sleb128 (struct line_reader_data * leb)
+{
+ const uint8_t * start_pos = leb->cpos;
+ uint64_t v = read_uleb128 (leb);
+ uint64_t signbit;
+
+ if (v >= 1ull << 63)
+ return 0;
+ if (leb->cpos - start_pos > 9)
+ return v;
+
+ signbit = 1ull << ((leb->cpos - start_pos) * 7 - 1);
+
+ return v | -(v & signbit);
+}
+
+/* Free a line_reader_data structure. */
+void
+line_free (struct line_reader_data * lnd)
+{
+ if (! lnd)
+ return;
+ if (lnd->dirnames)
+ free (lnd->dirnames);
+ if (lnd->filenames)
+ free (lnd->filenames);
+ free (lnd);
+}
+
+/* Return the pathname of the file in S, or NULL on error.
+ The result will have been allocated with malloc. */
+
+char *
+line_file (struct line_reader_data *lnd, uint64_t n)
+{
+ const uint8_t * prev_pos = lnd->cpos;
+ size_t filelen, dirlen;
+ uint64_t dir;
+ char * result;
+ const char * dirpath;
+
+ /* I'm not sure if this is actually an error. */
+ if (n == 0
+ || n > lnd->numfile)
+ return NULL;
+
+ filelen = strlen ((const char *)lnd->filenames[n - 1]);
+ lnd->cpos = lnd->filenames[n - 1] + filelen + 1;
+ dir = read_uleb128 (lnd);
+ lnd->cpos = prev_pos;
+ if (dir == 0
+ || lnd->filenames[n - 1][0] == '/')
+ return strdup ((const char *)lnd->filenames[n - 1]);
+ else if (dir > lnd->numdir)
+ return NULL;
+
+ dirpath = (const char *)lnd->dirnames[dir - 1];
+ dirlen = strlen (dirpath);
+ if ( dirpath[dirlen-1] == '/' )
+ --dirlen;
+ if ( (dirpath[dirlen-1] == '.') && (dirpath[dirlen-2] == '/') )
+ dirlen -= 2;
+ result = malloc (dirlen + filelen + 2);
+ memcpy (result, dirpath, dirlen);
+ result[dirlen] = '/';
+ memcpy (result + dirlen + 1, lnd->filenames[n - 1], filelen);
+ result[dirlen + 1 + filelen] = '\0';
+ return result;
+}
+
+/* Initialize a state S. Return FALSE on error. */
+
+static void
+init_state (struct line_info *s)
+{
+ s->file = 1;
+ s->line = 1;
+ s->col = 0;
+ s->pc = 0;
+ s->end_of_sequence = false;
+}
+
+/* Read a debug_line section. */
+
+struct line_reader_data *
+line_open (const uint8_t * debug_line, size_t debug_line_size,
+ int little_endian)
+{
+ struct line_reader_data * lnd = NULL;
+ bool dwarf_size_64;
+
+ uint64_t lnd_length, header_length;
+ const uint8_t * table_start;
+
+ if (debug_line_size < 12)
+ return NULL;
+
+ lnd = malloc (sizeof (struct line_reader_data));
+ if (! lnd)
+ return NULL;
+ bzero(lnd, sizeof(struct line_reader_data));
+
+ lnd->little_endian = little_endian;
+ lnd->cpos = debug_line;
+
+ lnd_length = read_32 (lnd->cpos);
+ lnd->cpos += 4;
+ if (lnd_length == 0xffffffff)
+ {
+ lnd_length = read_64 (lnd->cpos);
+ lnd->cpos += 8;
+ dwarf_size_64 = true;
+ }
+ else if (lnd_length > 0xfffffff0)
+ /* Not a format we understand. */
+ goto error;
+ else
+ dwarf_size_64 = false;
+
+ if (debug_line_size < lnd_length + (dwarf_size_64 ? 12 : 4)
+ || lnd_length < (dwarf_size_64 ? 15 : 11))
+ /* Too small. */
+ goto error;
+
+ if (read_16 (lnd->cpos) != 2)
+ /* Unknown line number format. */
+ goto error;
+ lnd->cpos += 2;
+
+ header_length = dwarf_size_64 ? (uint64_t)read_64(lnd->cpos) : (uint64_t)read_32(lnd->cpos);
+ lnd->cpos += dwarf_size_64 ? 8 : 4;
+ if (lnd_length < header_length + (lnd->cpos - debug_line)
+ || header_length < 7)
+ goto error;
+
+ lnd->minimum_instruction_length = lnd->cpos[0];
+ /* Ignore default_is_stmt. */
+ lnd->line_base = lnd->cpos[2];
+ lnd->line_range = lnd->cpos[3];
+ lnd->opcode_base = lnd->cpos[4];
+
+ if (lnd->opcode_base == 0)
+ /* Every valid line number program must use at least opcode 0
+ for DW_LNE_end_sequence. */
+ goto error;
+
+ lnd->standard_opcode_lengths = lnd->cpos + 5;
+ if (header_length < (uint64_t)(5 + (lnd->opcode_base - 1)))
+ /* Header not long enough. */
+ goto error;
+ lnd->cpos += 5 + lnd->opcode_base - 1;
+ lnd->end = debug_line + header_length + (dwarf_size_64 ? 22 : 10);
+
+ /* Make table of offsets to directory names. */
+ table_start = lnd->cpos;
+ lnd->numdir = 0;
+ while (lnd->cpos != lnd->end && *lnd->cpos)
+ {
+ lnd->cpos = memchr (lnd->cpos, 0, lnd->end - lnd->cpos);
+ if (! lnd->cpos)
+ goto error;
+ lnd->cpos++;
+ lnd->numdir++;
+ }
+ if (lnd->cpos == lnd->end)
+ goto error;
+ lnd->dirnames = malloc (lnd->numdir * sizeof (const uint8_t *));
+ if (! lnd->dirnames)
+ goto error;
+ lnd->numdir = 0;
+ lnd->cpos = table_start;
+ while (*lnd->cpos)
+ {
+ lnd->dirnames[lnd->numdir++] = lnd->cpos;
+ lnd->cpos = memchr (lnd->cpos, 0, lnd->end - lnd->cpos) + 1;
+ }
+ lnd->cpos++;
+
+ /* Make table of offsets to file entries. */
+ table_start = lnd->cpos;
+ lnd->numfile = 0;
+ while (lnd->cpos != lnd->end && *lnd->cpos)
+ {
+ lnd->cpos = memchr (lnd->cpos, 0, lnd->end - lnd->cpos);
+ if (! lnd->cpos)
+ goto error;
+ lnd->cpos++;
+ skip_leb128 (lnd);
+ skip_leb128 (lnd);
+ skip_leb128 (lnd);
+ lnd->numfile++;
+ }
+ if (lnd->cpos == lnd->end)
+ goto error;
+ lnd->filenames = malloc (lnd->numfile * sizeof (const uint8_t *));
+ if (! lnd->filenames)
+ goto error;
+ lnd->numfile = 0;
+ lnd->cpos = table_start;
+ while (*lnd->cpos)
+ {
+ lnd->filenames[lnd->numfile++] = lnd->cpos;
+ lnd->cpos = memchr (lnd->cpos, 0, lnd->end - lnd->cpos) + 1;
+ skip_leb128 (lnd);
+ skip_leb128 (lnd);
+ skip_leb128 (lnd);
+ }
+ lnd->cpos++;
+
+ lnd->numfile_orig = lnd->numfile;
+ lnd->cpos = lnd->init = lnd->end;
+ lnd->end = debug_line + lnd_length + (dwarf_size_64 ? 12 : 4);
+
+ init_state (&lnd->cur);
+
+ return lnd;
+
+ error:
+ line_free (lnd);
+ return NULL;
+}
+
+/* Reset back to the beginning. */
+void
+line_reset (struct line_reader_data * lnd)
+{
+ lnd->cpos = lnd->init;
+ lnd->numfile = lnd->numfile_orig;
+ init_state (&lnd->cur);
+}
+
+/* Is there no more line data available? */
+int
+line_at_eof (struct line_reader_data * lnd)
+{
+ return lnd->cpos == lnd->end;
+}
+
+static const bool verbose = false;
+
+static bool
+next_state (struct line_reader_data *lnd)
+{
+ if (lnd->cur.end_of_sequence)
+ init_state (&lnd->cur);
+
+ for (;;)
+ {
+ uint8_t op;
+ uint64_t tmp;
+
+ if (lnd->cpos == lnd->end)
+ return false;
+ op = *lnd->cpos++;
+ if (op >= lnd->opcode_base)
+ {
+ op -= lnd->opcode_base;
+
+ lnd->cur.line += op % lnd->line_range + lnd->line_base;
+ lnd->cur.pc += (op / lnd->line_range
+ * lnd->minimum_instruction_length);
+ return true;
+ }
+ else switch (op)
+ {
+ case DW_LNS_extended_op:
+ {
+ uint64_t sz = read_uleb128 (lnd);
+ const uint8_t * eop = lnd->cpos;
+
+ if ((uint64_t)(lnd->end - eop) < sz || sz == 0)
+ return false;
+ lnd->cpos += sz;
+ switch (*eop++)
+ {
+ case DW_LNE_end_sequence:
+ if (verbose) fprintf(stderr, "DW_LNE_end_sequence\n");
+ lnd->cur.end_of_sequence = true;
+ return true;
+
+ case DW_LNE_set_address:
+ if (sz == 9) {
+ lnd->cur.pc = read_64 (eop);
+ if (verbose) fprintf(stderr, "DW_LNE_set_address(0x%08llX)\n", lnd->cur.pc);
+ }
+ else if (sz == 5) {
+ lnd->cur.pc = read_32 (eop);
+ if (verbose) fprintf(stderr, "DW_LNE_set_address(0x%08llX)\n", lnd->cur.pc);
+ }
+ else
+ return false;
+ break;
+
+ case DW_LNE_define_file:
+ {
+ if (verbose) fprintf(stderr, "DW_LNE_define_file\n");
+ const uint8_t * * filenames;
+ filenames = realloc
+ (lnd->filenames,
+ (lnd->numfile + 1) * sizeof (const uint8_t *));
+ if (! filenames)
+ return false;
+ /* Check for zero-termination. */
+ if (! memchr (eop, 0, lnd->cpos - eop))
+ return false;
+ filenames[lnd->numfile++] = eop;
+ lnd->filenames = filenames;
+
+ /* There's other data here, like file sizes and modification
+ times, but we don't need to read it so skip it. */
+ }
+ break;
+
+ default:
+ /* Don't understand it, so skip it. */
+ if (verbose) fprintf(stderr, "DW_LNS_extended_op unknown\n");
+ break;
+ }
+ break;
+ }
+
+ case DW_LNS_copy:
+ if (verbose) fprintf(stderr, "DW_LNS_copy\n");
+ return true;
+ case DW_LNS_advance_pc:
+ tmp = read_uleb128 (lnd);
+ if (tmp == (uint64_t) -1)
+ return false;
+ lnd->cur.pc += tmp * lnd->minimum_instruction_length;
+ if (verbose) fprintf(stderr, "DW_LNS_advance_pc(0x%08llX)\n", lnd->cur.pc);
+ break;
+ case DW_LNS_advance_line:
+ lnd->cur.line += read_sleb128 (lnd);
+ if (verbose) fprintf(stderr, "DW_LNS_advance_line(%lld)\n", lnd->cur.line);
+ break;
+ case DW_LNS_set_file:
+ if (verbose) fprintf(stderr, "DW_LNS_set_file\n");
+ lnd->cur.file = read_uleb128 (lnd);
+ break;
+ case DW_LNS_set_column:
+ if (verbose) fprintf(stderr, "DW_LNS_set_column\n");
+ lnd->cur.col = read_uleb128 (lnd);
+ break;
+ case DW_LNS_const_add_pc:
+ if (verbose) fprintf(stderr, "DW_LNS_const_add_pc\n");
+ lnd->cur.pc += ((255 - lnd->opcode_base) / lnd->line_range
+ * lnd->minimum_instruction_length);
+ break;
+ case DW_LNS_fixed_advance_pc:
+ if (verbose) fprintf(stderr, "DW_LNS_fixed_advance_pc\n");
+ if (lnd->end - lnd->cpos < 2)
+ return false;
+ lnd->cur.pc += read_16 (lnd->cpos);
+ lnd->cpos += 2;
+ break;
+ default:
+ {
+ /* Don't know what it is, so skip it. */
+ if (verbose) fprintf(stderr, "unknown opcode\n");
+ int i;
+ for (i = 0; i < lnd->standard_opcode_lengths[op - 1]; i++)
+ skip_leb128 (lnd);
+ break;
+ }
+ }
+ }
+}
+
+
+/* Set RESULT to the next 'interesting' line state, as indicated
+ by STOP, or return FALSE on error. The final (end-of-sequence)
+ line state is always considered interesting. */
+int
+line_next (struct line_reader_data * lnd,
+ struct line_info * result,
+ enum line_stop_constants stop)
+{
+ for (;;)
+ {
+ struct line_info prev = lnd->cur;
+
+ if (! next_state (lnd))
+ return false;
+
+ if (lnd->cur.end_of_sequence)
+ break;
+ if (stop == line_stop_always)
+ break;
+ if ((stop & line_stop_pc) && lnd->cur.pc != prev.pc)
+ break;
+ if ((stop & line_stop_pos_mask) && lnd->cur.file != prev.file)
+ break;
+ if ((stop & line_stop_pos_mask) >= line_stop_line
+ && lnd->cur.line != prev.line)
+ break;
+ if ((stop & line_stop_pos_mask) >= line_stop_col
+ && lnd->cur.col != prev.col)
+ break;
+ }
+ *result = lnd->cur;
+ return true;
+}
+
+/* Find the region (START->pc through END->pc) in the debug_line
+ information which contains PC. This routine starts searching at
+ the current position (which is returned as END), and will go all
+ the way around the debug_line information. It will return false if
+ an error occurs or if there is no matching region; these may be
+ distinguished by looking at START->end_of_sequence, which will be
+ false on error and true if there was no matching region.
+ You could write this routine using line_next, but this version
+ will be slightly more efficient, and of course more convenient. */
+
+int
+line_find_addr (struct line_reader_data * lnd,
+ struct line_info * start,
+ struct line_info * end,
+ uint64_t pc)
+{
+ const uint8_t * startpos;
+ struct line_info prev;
+
+ if (lnd->cur.end_of_sequence && lnd->cpos == lnd->end)
+ line_reset (lnd);
+
+ startpos = lnd->cpos;
+
+ do {
+ prev = lnd->cur;
+ if (! next_state (lnd))
+ {
+ start->end_of_sequence = false;
+ return false;
+ }
+ if (lnd->cur.end_of_sequence && lnd->cpos == lnd->end)
+ line_reset (lnd);
+ if (lnd->cpos == startpos)
+ {
+ start->end_of_sequence = true;
+ return false;
+ }
+ } while (lnd->cur.pc <= pc || prev.pc > pc || prev.end_of_sequence);
+ *start = prev;
+ *end = lnd->cur;
+ return true;
+}
+#endif /* ! KLD */
+
--- /dev/null
+/*
+ * Copyright (c) 2006 Apple, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#ifndef __DEBUG_LINE_H__
+#define __DEBUG_LINE_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Information about a line.
+ DIRECTORY is to be ignored if FILENAME is absolute.
+ PC will be relative to the file the debug_line section is in. */
+struct line_info
+{
+ uint64_t file;
+ int64_t line;
+ uint64_t col;
+ uint64_t pc;
+ int end_of_sequence;
+};
+
+/* Opaque status structure for the line readers. */
+struct line_reader_data;
+
+/* Create a line_reader_data, given address and size of the debug_line section.
+ SIZE may be (size_t)-1 if unknown, although this suppresses checking
+ for an incorrectly large size in the debug_line section.
+ LITTLE_ENDIAN is set if the debug_line section is for a little-endian
+ machine.
+ Returns NULL on error. */
+struct line_reader_data * line_open (const uint8_t * debug_line,
+ size_t debug_line_size,
+ int little_endian);
+
+/* The STOP parameter to line_next is one of line_stop_{file,line,col},
+ perhaps ORed with line_stop_pc; or line_stop_atend, or line_stop_always. */
+enum line_stop_constants {
+ line_stop_atend = 0, /* Stop only at the end of a sequence. */
+ line_stop_file = 1, /* Stop if DIRECTORY or FILENAME change. */
+ line_stop_line = 2, /* Stop if LINE, DIRECTORY, or FILENAME change. */
+ line_stop_col = 3, /* Stop if COL, LINE, DIRECTORY, or FILENAME change. */
+ line_stop_pos_mask = 3,
+ line_stop_pc = 4, /* Stop if PC changes. */
+ line_stop_always = 8 /* Stop always. */
+};
+
+/* Either return FALSE on an error, in which case the line_reader_data
+ may be invalid and should be passed immediately to line_free; or
+ fill RESULT with the first 'interesting' line, as determined by STOP.
+ The last line data in a sequence is always considered 'interesting'. */
+int line_next (struct line_reader_data * lnd,
+ struct line_info * result,
+ enum line_stop_constants stop);
+
+/* Find the region (START->pc through END->pc) in the debug_line
+ information which contains PC. This routine starts searching at
+ the current position (which is returned as END), and will go all
+ the way around the debug_line information. It will return false if
+ an error occurs or if there is no matching region; these may be
+ distinguished by looking at START->end_of_sequence, which will be
+ false on error and true if there was no matching region.
+ You could write this routine using line_next, but this version
+ will be slightly more efficient, and of course more convenient. */
+
+int line_find_addr (struct line_reader_data * lnd,
+ struct line_info * start,
+ struct line_info * end,
+ uint64_t pc);
+
+/* Return TRUE if there is more line data to be fetched.
+ If line_next has not been called or it has been called but did not
+ set END_OF_SEQUENCE, you can assume there is more line data,
+ but it's safe to call this routine anyway. */
+int line_at_eof (struct line_reader_data * lnd);
+
+/* Return the pathname of the file in S, or NULL on error.
+ The result will have been allocated with malloc. */
+char * line_file (struct line_reader_data *lnd, uint64_t file);
+
+/* Reset the line_reader_data: go back to the beginning. */
+void line_reset (struct line_reader_data * lnd);
+
+/* Free a line_reader_data structure. */
+void line_free (struct line_reader_data * lnd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DEBUG_LINE_H__
+
--- /dev/null
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/* These constants were taken from version 3 of the DWARF standard,
+ which is Copyright (c) 2005 Free Standards Group, and
+ Copyright (c) 1992, 1993 UNIX International, Inc. */
+
+#ifndef __DWARF2_H__
+#define __DWARF2_H__
+
+/* This is not a complete list. */
+enum {
+ DW_TAG_compile_unit = 17,
+ DW_TAG_partial_unit = 60
+};
+
+/* This is not a complete list. */
+enum {
+ DW_AT_sibling = 1,
+ DW_AT_name = 3,
+ DW_AT_stmt_list = 16,
+ DW_AT_comp_dir = 27
+};
+
+enum {
+ DW_FORM_addr = 1,
+ DW_FORM_block2 = 3,
+ DW_FORM_block4,
+ DW_FORM_data2,
+ DW_FORM_data4,
+ DW_FORM_data8,
+ DW_FORM_string,
+ DW_FORM_block,
+ DW_FORM_block1,
+ DW_FORM_data1,
+ DW_FORM_flag,
+ DW_FORM_sdata,
+ DW_FORM_strp,
+ DW_FORM_udata,
+ DW_FORM_ref_addr,
+ DW_FORM_ref1,
+ DW_FORM_ref2,
+ DW_FORM_ref4,
+ DW_FORM_ref8,
+ DW_FORM_ref_udata,
+ DW_FORM_indirect /* 22 */
+};
+
+enum {
+ DW_LNS_extended_op = 0,
+ DW_LNS_copy,
+ DW_LNS_advance_pc,
+ DW_LNS_advance_line,
+ DW_LNS_set_file,
+ DW_LNS_set_column,
+ DW_LNS_negate_stmt,
+ DW_LNS_set_basic_block,
+ DW_LNS_const_add_pc,
+ DW_LNS_fixed_advance_pc,
+ DW_LNS_set_prologue_end,
+ DW_LNS_set_epilogue_begin,
+ DW_LNS_set_isa
+};
+
+enum {
+ DW_LNE_end_sequence = 1,
+ DW_LNE_set_address,
+ DW_LNE_define_file
+};
+
+
+// dwarf unwind instructions
+enum {
+ DW_CFA_nop = 0x0,
+ DW_CFA_set_loc = 0x1,
+ DW_CFA_advance_loc1 = 0x2,
+ DW_CFA_advance_loc2 = 0x3,
+ DW_CFA_advance_loc4 = 0x4,
+ DW_CFA_offset_extended = 0x5,
+ DW_CFA_restore_extended = 0x6,
+ DW_CFA_undefined = 0x7,
+ DW_CFA_same_value = 0x8,
+ DW_CFA_register = 0x9,
+ DW_CFA_remember_state = 0xA,
+ DW_CFA_restore_state = 0xB,
+ DW_CFA_def_cfa = 0xC,
+ DW_CFA_def_cfa_register = 0xD,
+ DW_CFA_def_cfa_offset = 0xE,
+ DW_CFA_def_cfa_expression = 0xF,
+ DW_CFA_expression = 0x10,
+ DW_CFA_offset_extended_sf = 0x11,
+ DW_CFA_def_cfa_sf = 0x12,
+ DW_CFA_def_cfa_offset_sf = 0x13,
+ DW_CFA_val_offset = 0x14,
+ DW_CFA_val_offset_sf = 0x15,
+ DW_CFA_val_expression = 0x16,
+ DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta
+ DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register
+ DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register
+
+ // GNU extensions
+ DW_CFA_GNU_window_save = 0x2D,
+ DW_CFA_GNU_args_size = 0x2E,
+ DW_CFA_GNU_negative_offset_extended = 0x2F
+};
+
+
+// FSF exception handling Pointer-Encoding constants
+// Used in CFI augmentation by gcc compiler
+enum {
+ DW_EH_PE_ptr = 0x00,
+ DW_EH_PE_uleb128 = 0x01,
+ DW_EH_PE_udata2 = 0x02,
+ DW_EH_PE_udata4 = 0x03,
+ DW_EH_PE_udata8 = 0x04,
+ DW_EH_PE_signed = 0x08,
+ DW_EH_PE_sleb128 = 0x09,
+ DW_EH_PE_sdata2 = 0x0A,
+ DW_EH_PE_sdata4 = 0x0B,
+ DW_EH_PE_sdata8 = 0x0C,
+ DW_EH_PE_absptr = 0x00,
+ DW_EH_PE_pcrel = 0x10,
+ DW_EH_PE_textrel = 0x20,
+ DW_EH_PE_datarel = 0x30,
+ DW_EH_PE_funcrel = 0x40,
+ DW_EH_PE_aligned = 0x50,
+ DW_EH_PE_indirect = 0x80,
+ DW_EH_PE_omit = 0xFF
+};
+
+
+// DWARF expressions
+enum {
+ DW_OP_addr = 0x03, // constant address (size target specific)
+ DW_OP_deref = 0x06,
+ DW_OP_const1u = 0x08, // 1-byte constant
+ DW_OP_const1s = 0x09, // 1-byte constant
+ DW_OP_const2u = 0x0A, // 2-byte constant
+ DW_OP_const2s = 0x0B, // 2-byte constant
+ DW_OP_const4u = 0x0C, // 4-byte constant
+ DW_OP_const4s = 0x0D, // 4-byte constant
+ DW_OP_const8u = 0x0E, // 8-byte constant
+ DW_OP_const8s = 0x0F, // 8-byte constant
+ DW_OP_constu = 0x10, // ULEB128 constant
+ DW_OP_consts = 0x11, // SLEB128 constant
+ DW_OP_dup = 0x12,
+ DW_OP_drop = 0x13,
+ DW_OP_over = 0x14,
+ DW_OP_pick = 0x15, // 1-byte stack index
+ DW_OP_swap = 0x16,
+ DW_OP_rot = 0x17,
+ DW_OP_xderef = 0x18,
+ DW_OP_abs = 0x19,
+ DW_OP_and = 0x1A,
+ DW_OP_div = 0x1B,
+ DW_OP_minus = 0x1C,
+ DW_OP_mod = 0x1D,
+ DW_OP_mul = 0x1E,
+ DW_OP_neg = 0x1F,
+ DW_OP_not = 0x20,
+ DW_OP_or = 0x21,
+ DW_OP_plus = 0x22,
+ DW_OP_plus_uconst = 0x23, // ULEB128 addend
+ DW_OP_shl = 0x24,
+ DW_OP_shr = 0x25,
+ DW_OP_shra = 0x26,
+ DW_OP_xor = 0x27,
+ DW_OP_skip = 0x2F, // signed 2-byte constant
+ DW_OP_bra = 0x28, // signed 2-byte constant
+ DW_OP_eq = 0x29,
+ DW_OP_ge = 0x2A,
+ DW_OP_gt = 0x2B,
+ DW_OP_le = 0x2C,
+ DW_OP_lt = 0x2D,
+ DW_OP_ne = 0x2E,
+ DW_OP_lit0 = 0x30, // Literal 0
+ DW_OP_lit1 = 0x31, // Literal 1
+ DW_OP_lit2 = 0x32, // Literal 2
+ DW_OP_lit3 = 0x33, // Literal 3
+ DW_OP_lit4 = 0x34, // Literal 4
+ DW_OP_lit5 = 0x35, // Literal 5
+ DW_OP_lit6 = 0x36, // Literal 6
+ DW_OP_lit7 = 0x37, // Literal 7
+ DW_OP_lit8 = 0x38, // Literal 8
+ DW_OP_lit9 = 0x39, // Literal 9
+ DW_OP_lit10 = 0x3A, // Literal 10
+ DW_OP_lit11 = 0x3B, // Literal 11
+ DW_OP_lit12 = 0x3C, // Literal 12
+ DW_OP_lit13 = 0x3D, // Literal 13
+ DW_OP_lit14 = 0x3E, // Literal 14
+ DW_OP_lit15 = 0x3F, // Literal 15
+ DW_OP_lit16 = 0x40, // Literal 16
+ DW_OP_lit17 = 0x41, // Literal 17
+ DW_OP_lit18 = 0x42, // Literal 18
+ DW_OP_lit19 = 0x43, // Literal 19
+ DW_OP_lit20 = 0x44, // Literal 20
+ DW_OP_lit21 = 0x45, // Literal 21
+ DW_OP_lit22 = 0x46, // Literal 22
+ DW_OP_lit23 = 0x47, // Literal 23
+ DW_OP_lit24 = 0x48, // Literal 24
+ DW_OP_lit25 = 0x49, // Literal 25
+ DW_OP_lit26 = 0x4A, // Literal 26
+ DW_OP_lit27 = 0x4B, // Literal 27
+ DW_OP_lit28 = 0x4C, // Literal 28
+ DW_OP_lit29 = 0x4D, // Literal 29
+ DW_OP_lit30 = 0x4E, // Literal 30
+ DW_OP_lit31 = 0x4F, // Literal 31
+ DW_OP_reg0 = 0x50, // Contents of reg0
+ DW_OP_reg1 = 0x51, // Contents of reg1
+ DW_OP_reg2 = 0x52, // Contents of reg2
+ DW_OP_reg3 = 0x53, // Contents of reg3
+ DW_OP_reg4 = 0x54, // Contents of reg4
+ DW_OP_reg5 = 0x55, // Contents of reg5
+ DW_OP_reg6 = 0x56, // Contents of reg6
+ DW_OP_reg7 = 0x57, // Contents of reg7
+ DW_OP_reg8 = 0x58, // Contents of reg8
+ DW_OP_reg9 = 0x59, // Contents of reg9
+ DW_OP_reg10 = 0x5A, // Contents of reg10
+ DW_OP_reg11 = 0x5B, // Contents of reg11
+ DW_OP_reg12 = 0x5C, // Contents of reg12
+ DW_OP_reg13 = 0x5D, // Contents of reg13
+ DW_OP_reg14 = 0x5E, // Contents of reg14
+ DW_OP_reg15 = 0x5F, // Contents of reg15
+ DW_OP_reg16 = 0x60, // Contents of reg16
+ DW_OP_reg17 = 0x61, // Contents of reg17
+ DW_OP_reg18 = 0x62, // Contents of reg18
+ DW_OP_reg19 = 0x63, // Contents of reg19
+ DW_OP_reg20 = 0x64, // Contents of reg20
+ DW_OP_reg21 = 0x65, // Contents of reg21
+ DW_OP_reg22 = 0x66, // Contents of reg22
+ DW_OP_reg23 = 0x67, // Contents of reg23
+ DW_OP_reg24 = 0x68, // Contents of reg24
+ DW_OP_reg25 = 0x69, // Contents of reg25
+ DW_OP_reg26 = 0x6A, // Contents of reg26
+ DW_OP_reg27 = 0x6B, // Contents of reg27
+ DW_OP_reg28 = 0x6C, // Contents of reg28
+ DW_OP_reg29 = 0x6D, // Contents of reg29
+ DW_OP_reg30 = 0x6E, // Contents of reg30
+ DW_OP_reg31 = 0x6F, // Contents of reg31
+ DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset
+ DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset
+ DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset
+ DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset
+ DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset
+ DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset
+ DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset
+ DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset
+ DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset
+ DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset
+ DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset
+ DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset
+ DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset
+ DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset
+ DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset
+ DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset
+ DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset
+ DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset
+ DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset
+ DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset
+ DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset
+ DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset
+ DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset
+ DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset
+ DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset
+ DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset
+ DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset
+ DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset
+ DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset
+ DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset
+ DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset
+ DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset
+ DW_OP_regx = 0x90, // ULEB128 register
+ DW_OP_fbreg = 0x91, // SLEB128 offset
+ DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset
+ DW_OP_piece = 0x93, // ULEB128 size of piece addressed
+ DW_OP_deref_size = 0x94, // 1-byte size of data retrieved
+ DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved
+ DW_OP_nop = 0x96,
+ DW_OP_push_object_addres = 0x97,
+ DW_OP_call2 = 0x98, // 2-byte offset of DIE
+ DW_OP_call4 = 0x99, // 4-byte offset of DIE
+ DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE
+ DW_OP_lo_user = 0xE0,
+ DW_OP_APPLE_uninit = 0xF0,
+ DW_OP_hi_user = 0xFF
+};
+
+
+
+#endif
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+// start temp HACK for cross builds
+extern "C" double log2 ( double );
+//#define __MATH__
+// end temp HACK for cross builds
+
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <execinfo.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+#include <dlfcn.h>
+#include <AvailabilityMacros.h>
+
+#include <string>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+#include <list>
+#include <algorithm>
+#include <ext/hash_map>
+#include <ext/hash_set>
+#include <cxxabi.h>
+
+#include "Options.h"
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+#include "ld.hpp"
+
+#include "InputFiles.h"
+#include "Resolver.h"
+#include "OutputFile.h"
+#include "Snapshot.h"
+
+#include "passes/stubs/make_stubs.h"
+#include "passes/dtrace_dof.h"
+#include "passes/got.h"
+#include "passes/tlvp.h"
+#include "passes/huge.h"
+#include "passes/compact_unwind.h"
+#include "passes/order.h"
+#include "passes/branch_island.h"
+#include "passes/branch_shim.h"
+#include "passes/objc.h"
+#include "passes/dylibs.h"
+
+#include "parsers/archive_file.h"
+#include "parsers/macho_relocatable_file.h"
+#include "parsers/macho_dylib_file.h"
+#include "parsers/lto_file.h"
+#include "parsers/opaque_section_file.h"
+
+
+struct PerformanceStatistics {
+ uint64_t startTool;
+ uint64_t startInputFileProcessing;
+ uint64_t startResolver;
+ uint64_t startDylibs;
+ uint64_t startPasses;
+ uint64_t startOutput;
+ uint64_t startDone;
+ vm_statistics_data_t vmStart;
+ vm_statistics_data_t vmEnd;
+};
+
+
+
+
+
+class InternalState : public ld::Internal
+{
+public:
+ InternalState(const Options& opts) : _options(opts), _atomsOrderedInSections(false) { }
+ virtual ld::Internal::FinalSection* addAtom(const ld::Atom& atom);
+ virtual ld::Internal::FinalSection* getFinalSection(const ld::Section&);
+
+ void sortSections();
+ void markAtomsOrdered() { _atomsOrderedInSections = true; }
+ virtual ~InternalState() {}
+private:
+
+ class FinalSection : public ld::Internal::FinalSection
+ {
+ public:
+ FinalSection(const ld::Section& sect, uint32_t sectionsSeen, bool objFile);
+ static int sectionComparer(const void* l, const void* r);
+ static const ld::Section& outputSection(const ld::Section& sect, bool mergeZeroFill);
+ static const ld::Section& objectOutputSection(const ld::Section& sect, bool makeTentativeDefsReal);
+ private:
+ friend class InternalState;
+ static uint32_t sectionOrder(const ld::Section& sect, uint32_t sectionsSeen);
+ static uint32_t segmentOrder(const ld::Section& sect, bool objFile);
+ uint32_t _segmentOrder;
+ uint32_t _sectionOrder;
+
+ static std::vector<const char*> _s_segmentsSeen;
+ static ld::Section _s_DATA_data;
+ static ld::Section _s_DATA_const;
+ static ld::Section _s_TEXT_text;
+ static ld::Section _s_TEXT_const;
+ static ld::Section _s_DATA_nl_symbol_ptr;
+ static ld::Section _s_DATA_common;
+ static ld::Section _s_DATA_zerofill;
+ };
+
+
+ struct SectionHash {
+ size_t operator()(const ld::Section*) const;
+ };
+ struct SectionEquals {
+ bool operator()(const ld::Section* left, const ld::Section* right) const;
+ };
+ typedef __gnu_cxx::hash_map<const ld::Section*, FinalSection*, SectionHash, SectionEquals> SectionInToOut;
+
+
+ SectionInToOut _sectionInToFinalMap;
+ const Options& _options;
+ bool _atomsOrderedInSections;
+};
+
+ld::Section InternalState::FinalSection::_s_DATA_data( "__DATA", "__data", ld::Section::typeUnclassified);
+ld::Section InternalState::FinalSection::_s_DATA_const("__DATA", "__const", ld::Section::typeUnclassified);
+ld::Section InternalState::FinalSection::_s_TEXT_text( "__TEXT", "__text", ld::Section::typeCode);
+ld::Section InternalState::FinalSection::_s_TEXT_const("__TEXT", "__const", ld::Section::typeUnclassified);
+ld::Section InternalState::FinalSection::_s_DATA_nl_symbol_ptr("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+ld::Section InternalState::FinalSection::_s_DATA_common("__DATA", "__common", ld::Section::typeZeroFill);
+ld::Section InternalState::FinalSection::_s_DATA_zerofill("__DATA", "__zerofill", ld::Section::typeZeroFill);
+std::vector<const char*> InternalState::FinalSection::_s_segmentsSeen;
+
+
+size_t InternalState::SectionHash::operator()(const ld::Section* sect) const
+{
+ size_t hash = 0;
+ __gnu_cxx::hash<const char*> temp;
+ hash += temp.operator()(sect->segmentName());
+ hash += temp.operator()(sect->sectionName());
+ return hash;
+}
+
+bool InternalState::SectionEquals::operator()(const ld::Section* left, const ld::Section* right) const
+{
+ return (*left == *right);
+}
+
+
+InternalState::FinalSection::FinalSection(const ld::Section& sect, uint32_t sectionsSeen, bool objFile)
+ : ld::Internal::FinalSection(sect),
+ _segmentOrder(segmentOrder(sect, objFile)),
+ _sectionOrder(sectionOrder(sect, sectionsSeen))
+{
+ //fprintf(stderr, "FinalSection(%s, %s) _segmentOrder=%d, _sectionOrder=%d\n",
+ // this->segmentName(), this->sectionName(), _segmentOrder, _sectionOrder);
+}
+
+const ld::Section& InternalState::FinalSection::outputSection(const ld::Section& sect, bool mergeZeroFill)
+{
+ // merge sections in final linked image
+ switch ( sect.type() ) {
+ case ld::Section::typeLiteral4:
+ case ld::Section::typeLiteral8:
+ case ld::Section::typeLiteral16:
+ return _s_TEXT_const;
+ case ld::Section::typeUnclassified:
+ if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
+ if ( strcmp(sect.sectionName(), "__datacoal_nt") == 0 )
+ return _s_DATA_data;
+ if ( strcmp(sect.sectionName(), "__const_coal") == 0 )
+ return _s_DATA_const;
+ }
+ else if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
+ if ( strcmp(sect.sectionName(), "__const_coal") == 0 )
+ return _s_TEXT_const;
+ }
+ break;
+ case ld::Section::typeZeroFill:
+ if ( mergeZeroFill )
+ return _s_DATA_zerofill;
+ break;
+ case ld::Section::typeCode:
+ if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
+ if ( strcmp(sect.sectionName(), "__textcoal_nt") == 0 )
+ return _s_TEXT_text;
+ else if ( strcmp(sect.sectionName(), "__StaticInit") == 0 )
+ return _s_TEXT_text;
+ }
+ break;
+ case ld::Section::typeNonLazyPointer:
+ if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
+ if ( strcmp(sect.sectionName(), "__nl_symbol_ptr") == 0 )
+ return _s_DATA_nl_symbol_ptr;
+ }
+ else if ( strcmp(sect.segmentName(), "__IMPORT") == 0 ) {
+ if ( strcmp(sect.sectionName(), "__pointers") == 0 )
+ return _s_DATA_nl_symbol_ptr;
+ }
+ break;
+ case ld::Section::typeTentativeDefs:
+ if ( mergeZeroFill )
+ return _s_DATA_zerofill;
+ else
+ return _s_DATA_common;
+ break;
+ // FIX ME: more
+ default:
+ break;
+ }
+ return sect;
+}
+
+const ld::Section& InternalState::FinalSection::objectOutputSection(const ld::Section& sect, bool makeTentativeDefsReal)
+{
+ // in -r mode the only section that ever changes is __tenative -> __common with -d option
+ if ( (sect.type() == ld::Section::typeTentativeDefs) && makeTentativeDefsReal)
+ return _s_DATA_common;
+ return sect;
+}
+
+uint32_t InternalState::FinalSection::segmentOrder(const ld::Section& sect, bool objFile)
+{
+ if ( strcmp(sect.segmentName(), "__PAGEZERO") == 0 )
+ return 0;
+ if ( strcmp(sect.segmentName(), "__HEADER") == 0 ) // only used with -preload
+ return 0;
+ if ( strcmp(sect.segmentName(), "__TEXT") == 0 )
+ return 1;
+ // in -r mode, want __DATA last so zerofill sections are at end
+ if ( strcmp(sect.segmentName(), "__DATA") == 0 )
+ return (objFile ? 5 : 2);
+ if ( strcmp(sect.segmentName(), "__OBJC") == 0 )
+ return 3;
+ if ( strcmp(sect.segmentName(), "__IMPORT") == 0 )
+ return 4;
+
+ // layout non-standard segments in order seen (+10 to shift beyond standard segments)
+ for (uint32_t i=0; i < _s_segmentsSeen.size(); ++i) {
+ if ( strcmp(_s_segmentsSeen[i], sect.segmentName()) == 0 )
+ return i+10;
+ }
+ _s_segmentsSeen.push_back(sect.segmentName());
+ return _s_segmentsSeen.size()-1+10;
+}
+
+uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint32_t sectionsSeen)
+{
+ if ( sect.type() == ld::Section::typeFirstSection )
+ return 0;
+ if ( sect.type() == ld::Section::typeMachHeader )
+ return 1;
+ if ( sect.type() == ld::Section::typeLastSection )
+ return INT_MAX;
+ if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
+ switch ( sect.type() ) {
+ case ld::Section::typeCode:
+ // <rdar://problem/8346444> make __text always be first "code" section
+ if ( strcmp(sect.sectionName(), "__text") == 0 )
+ return 10;
+ else
+ return 11;
+ case ld::Section::typeStub:
+ return 12;
+ case ld::Section::typeStubHelper:
+ return 13;
+ case ld::Section::typeLSDA:
+ return INT_MAX-3;
+ case ld::Section::typeUnwindInfo:
+ return INT_MAX-2;
+ case ld::Section::typeCFI:
+ return INT_MAX-1;
+ case ld::Section::typeStubClose:
+ return INT_MAX;
+ default:
+ return sectionsSeen+20;
+ }
+ }
+ else if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
+ switch ( sect.type() ) {
+ case ld::Section::typeLazyPointerClose:
+ return 8;
+ case ld::Section::typeDyldInfo:
+ return 9;
+ case ld::Section::typeNonLazyPointer:
+ return 10;
+ case ld::Section::typeLazyPointer:
+ return 11;
+ case ld::Section::typeInitializerPointers:
+ return 12;
+ case ld::Section::typeTerminatorPointers:
+ return 13;
+ case ld::Section::typeTLVInitialValues:
+ return INT_MAX-4; // need TLV zero-fill to follow TLV init values
+ case ld::Section::typeTLVZeroFill:
+ return INT_MAX-3;
+ case ld::Section::typeZeroFill:
+ // make sure __huge is always last zerofill section
+ if ( strcmp(sect.sectionName(), "__huge") == 0 )
+ return INT_MAX-1;
+ else
+ return INT_MAX-2;
+ default:
+ // <rdar://problem/7435296> Reorder sections to reduce page faults in object files
+ if ( strcmp(sect.sectionName(), "__objc_classlist") == 0 )
+ return 20;
+ else if ( strcmp(sect.sectionName(), "__objc_nlclslist") == 0 )
+ return 21;
+ else if ( strcmp(sect.sectionName(), "__objc_catlist") == 0 )
+ return 22;
+ else if ( strcmp(sect.sectionName(), "__objc_protolist") == 0 )
+ return 23;
+ else if ( strcmp(sect.sectionName(), "__objc_imageinfo") == 0 )
+ return 24;
+ else if ( strcmp(sect.sectionName(), "__objc_const") == 0 )
+ return 25;
+ else if ( strcmp(sect.sectionName(), "__objc_selrefs") == 0 )
+ return 26;
+ else if ( strcmp(sect.sectionName(), "__objc_msgrefs") == 0 )
+ return 27;
+ else if ( strcmp(sect.sectionName(), "__objc_protorefs") == 0 )
+ return 28;
+ else if ( strcmp(sect.sectionName(), "__objc_classrefs") == 0 )
+ return 29;
+ else if ( strcmp(sect.sectionName(), "__objc_superrefs") == 0 )
+ return 30;
+ else if ( strcmp(sect.sectionName(), "__objc_data") == 0 )
+ return 31;
+ else
+ return sectionsSeen+40;
+ }
+ }
+ // make sure zerofill in any other section is at end of segment
+ if ( sect.type() == ld::Section::typeZeroFill )
+ return INT_MAX-1;
+ return sectionsSeen+20;
+}
+
+#ifndef NDEBUG
+static void validateFixups(const ld::Atom& atom)
+{
+ //fprintf(stderr, "validateFixups %s\n", atom.name());
+ bool lastWasClusterEnd = true;
+ ld::Fixup::Cluster lastClusterSize = ld::Fixup::k1of1;
+ uint32_t curClusterOffsetInAtom = 0;
+ for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
+ //fprintf(stderr, " fixup offset=%d, cluster=%d\n", fit->offsetInAtom, fit->clusterSize);
+ assert((fit->offsetInAtom <= atom.size()) || (fit->offsetInAtom == 0));
+ if ( fit->firstInCluster() ) {
+ assert(lastWasClusterEnd);
+ curClusterOffsetInAtom = fit->offsetInAtom;
+ lastWasClusterEnd = (fit->clusterSize == ld::Fixup::k1of1);
+ }
+ else {
+ assert(!lastWasClusterEnd);
+ assert(fit->offsetInAtom == curClusterOffsetInAtom);
+ switch ((ld::Fixup::Cluster)fit->clusterSize) {
+ case ld::Fixup::k1of1:
+ case ld::Fixup::k1of2:
+ case ld::Fixup::k1of3:
+ case ld::Fixup::k1of4:
+ case ld::Fixup::k1of5:
+ lastWasClusterEnd = false;
+ break;
+ case ld::Fixup::k2of2:
+ assert(lastClusterSize = ld::Fixup::k1of2);
+ lastWasClusterEnd = true;
+ break;
+ case ld::Fixup::k2of3:
+ assert(lastClusterSize = ld::Fixup::k1of3);
+ lastWasClusterEnd = false;
+ break;
+ case ld::Fixup::k2of4:
+ assert(lastClusterSize = ld::Fixup::k1of4);
+ lastWasClusterEnd = false;
+ break;
+ case ld::Fixup::k2of5:
+ assert(lastClusterSize = ld::Fixup::k1of5);
+ lastWasClusterEnd = false;
+ break;
+ case ld::Fixup::k3of3:
+ assert(lastClusterSize = ld::Fixup::k2of3);
+ lastWasClusterEnd = true;
+ break;
+ case ld::Fixup::k3of4:
+ assert(lastClusterSize = ld::Fixup::k2of4);
+ lastWasClusterEnd = false;
+ break;
+ case ld::Fixup::k3of5:
+ assert(lastClusterSize = ld::Fixup::k2of5);
+ lastWasClusterEnd = false;
+ break;
+ case ld::Fixup::k4of4:
+ assert(lastClusterSize = ld::Fixup::k3of4);
+ lastWasClusterEnd = true;
+ break;
+ case ld::Fixup::k4of5:
+ assert(lastClusterSize = ld::Fixup::k3of5);
+ lastWasClusterEnd = false;
+ break;
+ case ld::Fixup::k5of5:
+ assert(lastClusterSize = ld::Fixup::k4of5);
+ lastWasClusterEnd = true;
+ break;
+ }
+ }
+ lastClusterSize = fit->clusterSize;
+ if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+ assert(fit->u.target != NULL);
+ }
+ }
+ switch (lastClusterSize) {
+ case ld::Fixup::k1of1:
+ case ld::Fixup::k2of2:
+ case ld::Fixup::k3of3:
+ case ld::Fixup::k4of4:
+ case ld::Fixup::k5of5:
+ break;
+ default:
+ assert(0 && "last fixup was not end of cluster");
+ break;
+ }
+}
+#endif
+
+ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
+{
+ ld::Internal::FinalSection* fs = this->getFinalSection(atom.section());
+ //fprintf(stderr, "InternalState::doAtom(%p), name=%s, sect=%s, finalsect=%p\n", &atom, atom.name(), atom.section().sectionName(), fs);
+#ifndef NDEBUG
+ validateFixups(atom);
+#endif
+ if ( _atomsOrderedInSections ) {
+ // make sure this atom is placed before any trailing section$end$ atom
+ if ( (fs->atoms.size() > 1) && (fs->atoms.back()->contentType() == ld::Atom::typeSectionEnd) ) {
+ // last atom in section$end$ atom, insert before it
+ const ld::Atom* endAtom = fs->atoms.back();
+ fs->atoms.pop_back();
+ fs->atoms.push_back(&atom);
+ fs->atoms.push_back(endAtom);
+ }
+ else {
+ // not end atom, just append new atom
+ fs->atoms.push_back(&atom);
+ }
+ }
+ else {
+ // normal case
+ fs->atoms.push_back(&atom);
+ }
+ return fs;
+}
+
+ld::Internal::FinalSection* InternalState::getFinalSection(const ld::Section& inputSection)
+{
+ const ld::Section* baseForFinalSection = &inputSection;
+
+ // see if input section already has a FinalSection
+ SectionInToOut::iterator pos = _sectionInToFinalMap.find(&inputSection);
+ if ( pos != _sectionInToFinalMap.end() ) {
+ return pos->second;
+ }
+
+ // otherwise, create a new final section
+ bool objFile = false;
+ switch ( _options.outputKind() ) {
+ case Options::kStaticExecutable:
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kDyld:
+ case Options::kKextBundle:
+ case Options::kPreload:
+ {
+ // coalesce some sections
+ const ld::Section& outSect = FinalSection::outputSection(inputSection, _options.mergeZeroFill());
+ pos = _sectionInToFinalMap.find(&outSect);
+ if ( pos != _sectionInToFinalMap.end() ) {
+ _sectionInToFinalMap[&inputSection] = pos->second;
+ //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", &inputSection, pos->second);
+ return pos->second;
+ }
+ else if ( outSect != inputSection ) {
+ // new output section created, but not in map
+ baseForFinalSection = &outSect;
+ }
+ }
+ break;
+ case Options::kObjectFile:
+ baseForFinalSection = &FinalSection::objectOutputSection(inputSection, _options.makeTentativeDefinitionsReal());
+ pos = _sectionInToFinalMap.find(baseForFinalSection);
+ if ( pos != _sectionInToFinalMap.end() ) {
+ _sectionInToFinalMap[&inputSection] = pos->second;
+ //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", &inputSection, pos->second);
+ return pos->second;
+ }
+ objFile = true;
+ break;
+ }
+
+ InternalState::FinalSection* result = new InternalState::FinalSection(*baseForFinalSection,
+ _sectionInToFinalMap.size(), objFile);
+ _sectionInToFinalMap[baseForFinalSection] = result;
+ //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", baseForFinalSection, result);
+ sections.push_back(result);
+ return result;
+}
+
+
+int InternalState::FinalSection::sectionComparer(const void* l, const void* r)
+{
+ const FinalSection* left = *(FinalSection**)l;
+ const FinalSection* right = *(FinalSection**)r;
+ if ( left->_segmentOrder != right->_segmentOrder )
+ return (left->_segmentOrder - right->_segmentOrder);
+ return (left->_sectionOrder - right->_sectionOrder);
+}
+
+void InternalState::sortSections()
+{
+ //fprintf(stderr, "UNSORTED final sections:\n");
+ //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
+ // fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName());
+ //}
+ qsort(§ions[0], sections.size(), sizeof(FinalSection*), &InternalState::FinalSection::sectionComparer);
+ //fprintf(stderr, "SORTED final sections:\n");
+ //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
+ // fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName());
+ //}
+ assert((sections[0]->type() == ld::Section::typeMachHeader)
+ || ((sections[0]->type() == ld::Section::typeFirstSection) && (sections[1]->type() == ld::Section::typeMachHeader))
+ || ((sections[0]->type() == ld::Section::typePageZero) && (sections[1]->type() == ld::Section::typeMachHeader))
+ || ((sections[0]->type() == ld::Section::typePageZero) && (sections[1]->type() == ld::Section::typeFirstSection) && (sections[2]->type() == ld::Section::typeMachHeader)) );
+
+}
+
+static char* commatize(uint64_t in, char* out)
+{
+ char* result = out;
+ char rawNum[30];
+ sprintf(rawNum, "%llu", in);
+ const int rawNumLen = strlen(rawNum);
+ for(int i=0; i < rawNumLen-1; ++i) {
+ *out++ = rawNum[i];
+ if ( ((rawNumLen-i) % 3) == 1 )
+ *out++ = ',';
+ }
+ *out++ = rawNum[rawNumLen-1];
+ *out = '\0';
+ return result;
+}
+
+static void printTime(const char* msg, uint64_t partTime, uint64_t totalTime)
+{
+ static uint64_t sUnitsPerSecond = 0;
+ if ( sUnitsPerSecond == 0 ) {
+ struct mach_timebase_info timeBaseInfo;
+ if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) {
+ sUnitsPerSecond = 1000000000ULL * timeBaseInfo.denom / timeBaseInfo.numer;
+ //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond);
+ }
+ }
+ if ( partTime < sUnitsPerSecond ) {
+ uint32_t milliSecondsTimeTen = (partTime*10000)/sUnitsPerSecond;
+ uint32_t milliSeconds = milliSecondsTimeTen/10;
+ uint32_t percentTimesTen = (partTime*1000)/totalTime;
+ uint32_t percent = percentTimesTen/10;
+ fprintf(stderr, "%24s: % 4d.%d milliseconds (% 4d.%d%%)\n", msg, milliSeconds, milliSecondsTimeTen-milliSeconds*10, percent, percentTimesTen-percent*10);
+ }
+ else {
+ uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond;
+ uint32_t seconds = secondsTimeTen/10;
+ uint32_t percentTimesTen = (partTime*1000)/totalTime;
+ uint32_t percent = percentTimesTen/10;
+ fprintf(stderr, "%24s: % 4d.%d seconds (% 4d.%d%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10);
+ }
+}
+
+
+static void getVMInfo(vm_statistics_data_t& info)
+{
+ mach_msg_type_number_t count = sizeof(vm_statistics_data_t) / sizeof(natural_t);
+ kern_return_t error = host_statistics(mach_host_self(), HOST_VM_INFO,
+ (host_info_t)&info, &count);
+ if (error != KERN_SUCCESS) {
+ bzero(&info, sizeof(vm_statistics_data_t));
+ }
+}
+
+
+
+static const char* sOverridePathlibLTO = NULL;
+
+//
+// This is magic glue that overrides the default behaviour
+// of lazydylib1.o which is used to lazily load libLTO.dylib.
+//
+extern "C" const char* dyld_lazy_dylib_path_fix(const char* path);
+const char* dyld_lazy_dylib_path_fix(const char* path)
+{
+ if ( sOverridePathlibLTO != NULL )
+ return sOverridePathlibLTO;
+ else
+ return path;
+}
+
+
+
+int main(int argc, const char* argv[])
+{
+ const char* archName = NULL;
+ bool showArch = false;
+ bool archInferred = false;
+ try {
+ PerformanceStatistics statistics;
+ statistics.startTool = mach_absolute_time();
+
+ // create object to track command line arguments
+ Options options(argc, argv);
+ InternalState state(options);
+
+ // allow libLTO to be overridden by command line -lto_library
+ sOverridePathlibLTO = options.overridePathlibLTO();
+
+ // gather vm stats
+ if ( options.printStatistics() )
+ getVMInfo(statistics.vmStart);
+
+ // update strings for error messages
+ showArch = options.printArchPrefix();
+ archName = options.architectureName();
+ archInferred = (options.architecture() == 0);
+
+ // open and parse input files
+ statistics.startInputFileProcessing = mach_absolute_time();
+ ld::tool::InputFiles inputFiles(options, &archName);
+
+ // load and resolve all references
+ statistics.startResolver = mach_absolute_time();
+ ld::tool::Resolver resolver(options, inputFiles, state);
+ resolver.resolve();
+
+ // add dylibs used
+ statistics.startDylibs = mach_absolute_time();
+ inputFiles.dylibs(state);
+
+ // do initial section sorting so passes have rough idea of the layout
+ state.sortSections();
+
+ // run passes
+ statistics.startPasses = mach_absolute_time();
+ ld::passes::objc::doPass(options, state);
+ ld::passes::stubs::doPass(options, state);
+ ld::passes::huge::doPass(options, state);
+ ld::passes::got::doPass(options, state);
+ ld::passes::tlvp::doPass(options, state);
+ ld::passes::dylibs::doPass(options, state); // must be after stubs and GOT passes
+ ld::passes::order::doPass(options, state);
+ state.markAtomsOrdered();
+ ld::passes::branch_shim::doPass(options, state); // must be after stubs
+ ld::passes::branch_island::doPass(options, state); // must be after stubs and order pass
+ ld::passes::dtrace::doPass(options, state);
+ ld::passes::compact_unwind::doPass(options, state); // must be after order pass
+
+ // sort final sections
+ state.sortSections();
+
+ // write output file
+ statistics.startOutput = mach_absolute_time();
+ ld::tool::OutputFile out(options);
+ out.write(state);
+ statistics.startDone = mach_absolute_time();
+
+ // print statistics
+ //mach_o::relocatable::printCounts();
+ if ( options.printStatistics() ) {
+ getVMInfo(statistics.vmEnd);
+ uint64_t totalTime = statistics.startDone - statistics.startTool;
+ printTime("ld total time", totalTime, totalTime);
+ printTime(" option parsing time", statistics.startInputFileProcessing - statistics.startTool, totalTime);
+ printTime(" object file processing", statistics.startResolver - statistics.startInputFileProcessing,totalTime);
+ printTime(" resolve symbols", statistics.startDylibs - statistics.startResolver, totalTime);
+ printTime(" build atom list", statistics.startPasses - statistics.startDylibs, totalTime);
+ printTime(" passess", statistics.startOutput - statistics.startPasses, totalTime);
+ printTime(" write output", statistics.startDone - statistics.startOutput, totalTime);
+ fprintf(stderr, "pageins=%u, pageouts=%u, faults=%u\n",
+ statistics.vmEnd.pageins-statistics.vmStart.pageins,
+ statistics.vmEnd.pageouts-statistics.vmStart.pageouts,
+ statistics.vmEnd.faults-statistics.vmStart.faults);
+ char temp[40];
+ fprintf(stderr, "processed %3u object files, totaling %15s bytes\n", inputFiles._totalObjectLoaded, commatize(inputFiles._totalObjectSize, temp));
+ fprintf(stderr, "processed %3u archive files, totaling %15s bytes\n", inputFiles._totalArchivesLoaded, commatize(inputFiles._totalArchiveSize, temp));
+ fprintf(stderr, "processed %3u dylib files\n", inputFiles._totalDylibsLoaded);
+ fprintf(stderr, "wrote output file totaling %15s bytes\n", commatize(out.fileSize(), temp));
+ }
+ // <rdar://problem/6780050> Would like linker warning to be build error.
+ if ( options.errorBecauseOfWarnings() ) {
+ fprintf(stderr, "ld: fatal warning(s) induced error (-fatal_warnings)\n");
+ return 1;
+ }
+ }
+ catch (const char* msg) {
+ if ( archInferred )
+ fprintf(stderr, "ld: %s for inferred architecture %s\n", msg, archName);
+ else if ( showArch )
+ fprintf(stderr, "ld: %s for architecture %s\n", msg, archName);
+ else
+ fprintf(stderr, "ld: %s\n", msg);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+#ifndef NDEBUG
+// implement assert() function to print out a backtrace before aborting
+void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr)
+{
+ Snapshot *snapshot = Snapshot::globalSnapshot;
+
+ snapshot->setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
+ snapshot->createSnapshot();
+ snapshot->recordAssertionMessage("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line);
+
+ void* callStack[128];
+ int depth = ::backtrace(callStack, 128);
+ char* buffer = (char*)malloc(1024);
+ for(int i=0; i < depth-1; ++i) {
+ Dl_info info;
+ dladdr(callStack[i], &info);
+ const char* symboName = info.dli_sname;
+ if ( (symboName != NULL) && (strncmp(symboName, "_Z", 2) == 0) ) {
+ size_t bufLen = 1024;
+ int result;
+ char* unmangled = abi::__cxa_demangle(symboName, buffer, &bufLen, &result);
+ if ( unmangled != NULL )
+ symboName = unmangled;
+ }
+ long offset = (uintptr_t)callStack[i] - (uintptr_t)info.dli_saddr;
+ fprintf(stderr, "%d %p %s + %ld\n", i, callStack[i], symboName, offset);
+ snapshot->recordAssertionMessage("%d %p %s + %ld\n", i, callStack[i], symboName, offset);
+ }
+ fprintf(stderr, "A linker snapshot was created at:\n\t%s\n", snapshot->rootDir());
+ fprintf(stderr, "ld: Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line);
+ exit(1);
+}
+#endif
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __LD_HPP__
+#define __LD_HPP__
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <vector>
+#include <set>
+
+
+namespace ld {
+
+//
+// ld::File
+//
+// Abstract base class for all object or library files the linker processes.
+//
+// forEachAtom() iterates over the Atoms in the order they occur in the file.
+//
+// justInTimeforEachAtom(name) iterates over lazily created Atoms. For instance if
+// File is a static library, justInTimeforEachAtom() will iterate over the base set
+// of Atoms from the archive member implementing 'name'.
+//
+class File
+{
+public:
+ enum ObjcConstraint { objcConstraintNone, objcConstraintRetainRelease, objcConstraintRetainReleaseOrGC, objcConstraintGC };
+
+ class AtomHandler {
+ public:
+ virtual ~AtomHandler() {}
+ virtual void doAtom(const class Atom&) = 0;
+ virtual void doFile(const class File&) = 0;
+ };
+
+ //
+ // ld::File::Ordinal
+ //
+ // Codifies the rules of ordering input files for symbol precedence. These are:
+ // - Input files listed on the command line are ordered according to their index in the argument list.
+ // - Input files listed in a file list are ordered first at the index of the file list argument, then
+ // by index in the file list
+ // - Input files extracted from archives are ordered using the ordinal of the archive itself plus the
+ // index of the object file within the archive
+ // - Indirect dylibs are ordered after all input files derived from the command line, in the order that
+ // they are discovered.
+ // - The LTO object file is last.
+ //
+ class Ordinal
+ {
+ private:
+ // The actual numeric ordinal. Lower values have higher precedence and a zero value is invalid.
+ // The 64 bit ordinal is broken into 4 16 bit chunks. The high 16 bits are a "partition" that
+ // is used to distinguish major ordinal groups: command line, indirect dylib, LTO.
+ // The remaining chunks are used according to the partition (see below).
+ uint64_t _ordinal;
+
+ Ordinal (uint64_t ordinal) : _ordinal(ordinal) {}
+
+ enum { ArgListPartition=0, IndirectDylibPartition=1, LTOPartition = 2, InvalidParition=0xffff };
+ Ordinal(uint16_t partition, uint16_t majorIndex, uint16_t minorIndex, uint16_t counter) {
+ _ordinal = ((uint64_t)partition<<48) | ((uint64_t)majorIndex<<32) | ((uint64_t)minorIndex<<16) | ((uint64_t)counter<<0);
+ }
+
+ const uint16_t partition() const { return (_ordinal>>48)&0xffff; }
+ const uint16_t majorIndex() const { return (_ordinal>>32)&0xffff; }
+ const uint16_t minorIndex() const { return (_ordinal>>16)&0xffff; }
+ const uint16_t counter() const { return (_ordinal>>00)&0xffff; }
+
+ const Ordinal nextMajorIndex() const { assert(majorIndex() < 0xffff); return Ordinal(_ordinal+((uint64_t)1<<32)); }
+ const Ordinal nextMinorIndex() const { assert(minorIndex() < 0xffff); return Ordinal(_ordinal+((uint64_t)1<<16)); }
+ const Ordinal nextCounter() const { assert(counter() < 0xffff); return Ordinal(_ordinal+((uint64_t)1<<0)); }
+
+ public:
+ Ordinal() : _ordinal(0) {};
+
+ static const Ordinal NullOrdinal() { return Ordinal((uint64_t)0); }
+
+ const bool validOrdinal() const { return _ordinal != 0; }
+
+ bool operator ==(const Ordinal& rhs) const { return _ordinal == rhs._ordinal; }
+ bool operator !=(const Ordinal& rhs) const { return _ordinal != rhs._ordinal; }
+ bool operator < (const Ordinal& rhs) const { return _ordinal < rhs._ordinal; }
+ bool operator > (const Ordinal& rhs) const { return _ordinal > rhs._ordinal; }
+
+ // For ordinals derived from the command line args the partition is ArgListPartition
+ // The majorIndex is the arg index that pulls in the file, file list, or archive.
+ // The minorIndex is used for files pulled in by a file list and the value is the index of the file in the file list.
+ // The counter is used for .a files and the value is the index of the object in the archive.
+ // Thus, an object pulled in from a .a that was listed in a file list could use all three fields.
+ static const Ordinal makeArgOrdinal(uint16_t argIndex) { return Ordinal(ArgListPartition, argIndex, 0, 0); };
+ const Ordinal nextFileListOrdinal() const { return nextMinorIndex(); }
+ const Ordinal archiveOrdinalWithMemberIndex(uint16_t index) const { return Ordinal(ArgListPartition, majorIndex(), minorIndex(), index); }
+
+ // For indirect libraries the partition is IndirectDylibPartition and the counter is used or order the libraries.
+ static const ld::File::Ordinal indirectDylibBase() { return Ordinal(IndirectDylibPartition, 0, 0, 0); }
+ const Ordinal nextIndirectDylibOrdinal() const { return nextCounter(); }
+
+ // For the LTO mach-o the partition is LTOPartition. As there is only one LTO file no other fields are needed.
+ static const ld::File::Ordinal LTOOrdinal() { return Ordinal(LTOPartition, 0, 0, 0); }
+ };
+
+ typedef enum { Reloc, Dylib, Archive, Other } Type;
+
+ File(const char* pth, time_t modTime, Ordinal ord, Type type)
+ : _path(pth), _modTime(modTime), _ordinal(ord), _type(type) { }
+ virtual ~File() {}
+ const char* path() const { return _path; }
+ time_t modificationTime() const{ return _modTime; }
+ Ordinal ordinal() const { return _ordinal; }
+ virtual bool forEachAtom(AtomHandler&) const = 0;
+ virtual bool justInTimeforEachAtom(const char* name, AtomHandler&) const = 0;
+ virtual ObjcConstraint objCConstraint() const { return objcConstraintNone; }
+ virtual uint32_t cpuSubType() const { return 0; }
+ virtual uint32_t subFileCount() const { return 1; }
+ bool fileExists() const { return _modTime != 0; }
+ Type type() const { return _type; }
+private:
+ const char* _path;
+ time_t _modTime;
+ const Ordinal _ordinal;
+ const Type _type;
+};
+
+
+//
+// minumum OS versions
+//
+enum MacVersionMin { macVersionUnset=0, mac10_4=0x000A0400, mac10_5=0x000A0500,
+ mac10_6=0x000A0600, mac10_7=0x000A0700, mac10_8=0x000A0800,
+ mac10_Future=0x10000000 };
+enum IOSVersionMin { iOSVersionUnset=0, iOS_2_0=0x00020000, iOS_3_1=0x00030100,
+ iOS_4_2=0x00040200, iOS_4_3=0x00040300, iOS_5_0=0x00050000,
+ iOS_6_0=0x00060000, iOS_Future=0x10000000};
+
+namespace relocatable {
+ //
+ // ld::relocatable::File
+ //
+ // Abstract base class for object files the linker processes.
+ //
+ // debugInfo() returns if the object file contains debugger information (stabs or dwarf).
+ //
+ // stabs() lazily creates a vector of Stab objects for each atom
+ //
+ // canScatterAtoms() true for all compiler generated code. Hand written assembly can opt-in
+ // via .subsections_via_symbols directive. When true it means the linker can break up section
+ // content at symbol boundaries and do optimizations like coalescing, dead code stripping, or
+ // apply order files.
+ //
+ // optimize() used by libLTO to lazily generate code from llvm bit-code files
+ //
+ class File : public ld::File
+ {
+ public:
+ enum DebugInfoKind { kDebugInfoNone=0, kDebugInfoStabs=1, kDebugInfoDwarf=2, kDebugInfoStabsUUID=3 };
+ struct Stab {
+ const class Atom* atom;
+ uint8_t type;
+ uint8_t other;
+ uint16_t desc;
+ uint32_t value;
+ const char* string;
+ };
+
+ File(const char* pth, time_t modTime, Ordinal ord)
+ : ld::File(pth, modTime, ord, Reloc) { }
+ virtual ~File() {}
+ virtual DebugInfoKind debugInfo() const = 0;
+ virtual const char* debugInfoPath() const { return path(); }
+ virtual time_t debugInfoModificationTime() const { return modificationTime(); }
+ virtual const std::vector<Stab>* stabs() const = 0;
+ virtual bool canScatterAtoms() const = 0;
+ virtual bool hasLongBranchStubs() { return false; }
+ };
+} // namespace relocatable
+
+
+namespace dylib {
+
+ //
+ // ld::dylib::File
+ //
+ // Abstract base class for dynamic shared libraries read by the linker processes.
+ //
+ class File : public ld::File
+ {
+ public:
+ class DylibHandler
+ {
+ public:
+ virtual ~DylibHandler() {}
+ virtual File* findDylib(const char* installPath, const char* fromPath) = 0;
+ };
+
+ File(const char* pth, time_t modTime, Ordinal ord)
+ : ld::File(pth, modTime, ord, Dylib), _dylibInstallPath(NULL),
+ _dylibTimeStamp(0), _dylibCurrentVersion(0), _dylibCompatibilityVersion(0),
+ _explicitlyLinked(false), _implicitlyLinked(false),
+ _lazyLoadedDylib(false), _forcedWeakLinked(false), _reExported(false),
+ _upward(false), _dead(false) { }
+ const char* installPath() const { return _dylibInstallPath; }
+ uint32_t timestamp() const { return _dylibTimeStamp; }
+ uint32_t currentVersion() const { return _dylibCurrentVersion; }
+ uint32_t compatibilityVersion() const{ return _dylibCompatibilityVersion; }
+ void setExplicitlyLinked() { _explicitlyLinked = true; }
+ bool explicitlyLinked() const { return _explicitlyLinked; }
+ void setImplicitlyLinked() { _implicitlyLinked = true; }
+ bool implicitlyLinked() const { return _implicitlyLinked; }
+
+ // attributes of how dylib will be used when linked
+ void setWillBeLazyLoadedDylb() { _lazyLoadedDylib = true; }
+ bool willBeLazyLoadedDylib() const { return _lazyLoadedDylib; }
+ void setForcedWeakLinked() { _forcedWeakLinked = true; }
+ bool forcedWeakLinked() const { return _forcedWeakLinked; }
+
+ void setWillBeReExported() { _reExported = true; }
+ bool willBeReExported() const { return _reExported; }
+ void setWillBeUpwardDylib() { _upward = true; }
+ bool willBeUpwardDylib() const { return _upward; }
+ void setWillBeRemoved(bool value) { _dead = value; }
+ bool willRemoved() const { return _dead; }
+
+ virtual void processIndirectLibraries(DylibHandler* handler, bool addImplicitDylibs) = 0;
+ virtual bool providedExportAtom() const = 0;
+ virtual const char* parentUmbrella() const = 0;
+ virtual const std::vector<const char*>* allowableClients() const = 0;
+ virtual bool hasWeakExternals() const = 0;
+ virtual bool deadStrippable() const = 0;
+ virtual bool hasWeakDefinition(const char* name) const = 0;
+ virtual bool hasPublicInstallName() const = 0;
+ virtual bool allSymbolsAreWeakImported() const = 0;
+ virtual const void* codeSignatureDR() const = 0;
+ protected:
+ const char* _dylibInstallPath;
+ uint32_t _dylibTimeStamp;
+ uint32_t _dylibCurrentVersion;
+ uint32_t _dylibCompatibilityVersion;
+ bool _explicitlyLinked;
+ bool _implicitlyLinked;
+ bool _lazyLoadedDylib;
+ bool _forcedWeakLinked;
+ bool _reExported;
+ bool _upward;
+ bool _dead;
+ };
+} // namespace dylib
+
+
+namespace archive {
+ //
+ // ld::archive::File
+ //
+ // Abstract base class for static libraries read by the linker processes.
+ //
+ class File : public ld::File
+ {
+ public:
+ File(const char* pth, time_t modTime, Ordinal ord)
+ : ld::File(pth, modTime, ord, Archive) { }
+ virtual ~File() {}
+ virtual bool justInTimeDataOnlyforEachAtom(const char* name, AtomHandler&) const = 0;
+ };
+} // namespace archive
+
+
+//
+// ld::Section
+//
+class Section
+{
+public:
+ enum Type { typeUnclassified, typeCode, typePageZero, typeImportProxies, typeLinkEdit, typeMachHeader, typeStack,
+ typeLiteral4, typeLiteral8, typeLiteral16, typeConstants, typeTempLTO,
+ typeCString, typeNonStdCString, typeCStringPointer, typeUTF16Strings, typeCFString, typeObjC1Classes,
+ typeCFI, typeLSDA, typeDtraceDOF, typeUnwindInfo, typeObjCClassRefs, typeObjC2CategoryList,
+ typeZeroFill, typeTentativeDefs, typeLazyPointer, typeStub, typeNonLazyPointer, typeDyldInfo,
+ typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers,
+ typeStubClose, typeLazyPointerClose, typeAbsoluteSymbols,
+ typeTLVDefs, typeTLVZeroFill, typeTLVInitialValues, typeTLVInitializerPointers, typeTLVPointers,
+ typeFirstSection, typeLastSection, typeDebug };
+
+
+ Section(const char* sgName, const char* sctName,
+ Type t, bool hidden=false)
+ : _segmentName(sgName), _sectionName(sctName),
+ _type(t), _hidden(hidden) {}
+ Section(const Section& sect)
+ : _segmentName(sect.segmentName()), _sectionName(sect.sectionName()),
+ _type(sect.type()), _hidden(sect.isSectionHidden()) {}
+
+ bool operator==(const Section& rhs) const { return ( (_hidden==rhs._hidden) &&
+ (strcmp(_segmentName, rhs._segmentName)==0) &&
+ (strcmp(_sectionName, rhs._sectionName)==0) ); }
+ bool operator!=(const Section& rhs) const { return ! (*this == rhs); }
+ const char* segmentName() const { return _segmentName; }
+ const char* sectionName() const { return _sectionName; }
+ Type type() const { return _type; }
+ bool isSectionHidden() const { return _hidden; }
+
+private:
+ const char* _segmentName;
+ const char* _sectionName;
+ Type _type;
+ bool _hidden;
+};
+
+
+
+//
+// ld::Fixup
+//
+// A Fixup describes how part of an Atom's content must be fixed up. For instance,
+// an instruction may contain a displacement to another Atom that must be
+// fixed up by the linker.
+//
+// A Fixup my reference another Atom. There are two kinds of references: direct and by-name.
+// With a direct reference, the target is bound by the File that created it.
+// For instance a reference to a static would produce a direct reference.
+// A by-name reference requires the linker to find the target Atom with the
+// required name in order to be bound.
+//
+// For a link to succeed all Fixup must be bound.
+//
+// A Reference also has a fix-up-offset. This is the offset into the content of the
+// Atom holding the reference where the fix-up (relocation) will be applied.
+//
+//
+struct Fixup
+{
+ enum TargetBinding { bindingNone, bindingByNameUnbound, bindingDirectlyBound, bindingByContentBound, bindingsIndirectlyBound };
+ enum Cluster { k1of1, k1of2, k2of2, k1of3, k2of3, k3of3, k1of4, k2of4, k3of4, k4of4, k1of5, k2of5, k3of5, k4of5, k5of5 };
+ enum Kind { kindNone, kindNoneFollowOn,
+ // grouping
+ kindNoneGroupSubordinate,
+ kindNoneGroupSubordinateFDE, kindNoneGroupSubordinateLSDA, kindNoneGroupSubordinatePersonality,
+ // value calculations
+ kindSetTargetAddress,
+ kindSubtractTargetAddress,
+ kindAddAddend,
+ kindSubtractAddend,
+ kindSetTargetImageOffset,
+ kindSetTargetSectionOffset,
+ kindSetTargetTLVTemplateOffset,
+ // pointer store kinds (of current calculated value)
+ kindStore8,
+ kindStoreLittleEndian16,
+ kindStoreLittleEndianLow24of32,
+ kindStoreLittleEndian32,
+ kindStoreLittleEndian64,
+ kindStoreBigEndian16,
+ kindStoreBigEndianLow24of32,
+ kindStoreBigEndian32,
+ kindStoreBigEndian64,
+ // Intel specific store kinds
+ kindStoreX86BranchPCRel8, kindStoreX86BranchPCRel32,
+ kindStoreX86PCRel8, kindStoreX86PCRel16,
+ kindStoreX86PCRel32, kindStoreX86PCRel32_1, kindStoreX86PCRel32_2, kindStoreX86PCRel32_4,
+ kindStoreX86PCRel32GOTLoad, kindStoreX86PCRel32GOTLoadNowLEA, kindStoreX86PCRel32GOT,
+ kindStoreX86PCRel32TLVLoad, kindStoreX86PCRel32TLVLoadNowLEA,
+ kindStoreX86Abs32TLVLoad, kindStoreX86Abs32TLVLoadNowLEA,
+ // ARM specific store kinds
+ kindStoreARMBranch24, kindStoreThumbBranch22,
+ kindStoreARMLoad12,
+ kindStoreARMLow16, kindStoreARMHigh16,
+ kindStoreThumbLow16, kindStoreThumbHigh16,
+ // dtrace probes
+ kindDtraceExtra,
+ kindStoreX86DtraceCallSiteNop, kindStoreX86DtraceIsEnableSiteClear,
+ kindStoreARMDtraceCallSiteNop, kindStoreARMDtraceIsEnableSiteClear,
+ kindStoreThumbDtraceCallSiteNop, kindStoreThumbDtraceIsEnableSiteClear,
+ // lazy binding
+ kindLazyTarget, kindSetLazyOffset,
+ // data-in-code markers
+ kindDataInCodeStartData, kindDataInCodeStartJT8, kindDataInCodeStartJT16,
+ kindDataInCodeStartJT32, kindDataInCodeStartJTA32, kindDataInCodeEnd,
+ // pointer store combinations
+ kindStoreTargetAddressLittleEndian32, // kindSetTargetAddress + kindStoreLittleEndian32
+ kindStoreTargetAddressLittleEndian64, // kindSetTargetAddress + kindStoreLittleEndian64
+ kindStoreTargetAddressBigEndian32, // kindSetTargetAddress + kindStoreBigEndian32
+ kindStoreTargetAddressBigEndian64, // kindSetTargetAddress + kindStoreBigEndian364
+ kindSetTargetTLVTemplateOffsetLittleEndian32, // kindSetTargetTLVTemplateOffset + kindStoreLittleEndian32
+ kindSetTargetTLVTemplateOffsetLittleEndian64, // kindSetTargetTLVTemplateOffset + kindStoreLittleEndian64
+ // Intel value calculation and store combinations
+ kindStoreTargetAddressX86PCRel32, // kindSetTargetAddress + kindStoreX86PCRel32
+ kindStoreTargetAddressX86BranchPCRel32, // kindSetTargetAddress + kindStoreX86BranchPCRel32
+ kindStoreTargetAddressX86PCRel32GOTLoad,// kindSetTargetAddress + kindStoreX86PCRel32GOTLoad
+ kindStoreTargetAddressX86PCRel32GOTLoadNowLEA,// kindSetTargetAddress + kindStoreX86PCRel32GOTLoadNowLEA
+ kindStoreTargetAddressX86PCRel32TLVLoad, // kindSetTargetAddress + kindStoreX86PCRel32TLVLoad
+ kindStoreTargetAddressX86PCRel32TLVLoadNowLEA, // kindSetTargetAddress + kindStoreX86PCRel32TLVLoadNowLEA
+ kindStoreTargetAddressX86Abs32TLVLoad, // kindSetTargetAddress + kindStoreX86Abs32TLVLoad
+ kindStoreTargetAddressX86Abs32TLVLoadNowLEA, // kindSetTargetAddress + kindStoreX86Abs32TLVLoadNowLEA
+ // ARM value calculation and store combinations
+ kindStoreTargetAddressARMBranch24, // kindSetTargetAddress + kindStoreARMBranch24
+ kindStoreTargetAddressThumbBranch22, // kindSetTargetAddress + kindStoreThumbBranch22
+ kindStoreTargetAddressARMLoad12, // kindSetTargetAddress + kindStoreARMLoad12
+ };
+
+ union {
+ const Atom* target;
+ const char* name;
+ uint64_t addend;
+ uint32_t bindingIndex;
+ } u;
+ uint32_t offsetInAtom;
+ Kind kind : 8;
+ Cluster clusterSize : 4;
+ bool weakImport : 1;
+ TargetBinding binding : 3;
+ bool contentAddendOnly : 1;
+ bool contentDetlaToAddendOnly : 1;
+
+ typedef Fixup* iterator;
+
+ Fixup() :
+ offsetInAtom(0), kind(kindNone), clusterSize(k1of1), weakImport(false),
+ binding(bindingNone),
+ contentAddendOnly(false), contentDetlaToAddendOnly(false) { u.target = NULL; }
+
+ Fixup(Kind k, Atom* targetAtom) :
+ offsetInAtom(0), kind(k), clusterSize(k1of1), weakImport(false),
+ binding(Fixup::bindingDirectlyBound),
+ contentAddendOnly(false), contentDetlaToAddendOnly(false)
+ { assert(targetAtom != NULL); u.target = targetAtom; }
+
+ Fixup(uint32_t off, Cluster c, Kind k) :
+ offsetInAtom(off), kind(k), clusterSize(c), weakImport(false),
+ binding(Fixup::bindingNone),
+ contentAddendOnly(false), contentDetlaToAddendOnly(false)
+ { u.addend = 0; }
+
+ Fixup(uint32_t off, Cluster c, Kind k, bool weakIm, const char* name) :
+ offsetInAtom(off), kind(k), clusterSize(c), weakImport(weakIm),
+ binding(Fixup::bindingByNameUnbound),
+ contentAddendOnly(false), contentDetlaToAddendOnly(false)
+ { assert(name != NULL); u.name = name; }
+
+ Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const char* name) :
+ offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b),
+ contentAddendOnly(false), contentDetlaToAddendOnly(false)
+ { assert(name != NULL); u.name = name; }
+
+ Fixup(uint32_t off, Cluster c, Kind k, const Atom* targetAtom) :
+ offsetInAtom(off), kind(k), clusterSize(c), weakImport(false),
+ binding(Fixup::bindingDirectlyBound),
+ contentAddendOnly(false), contentDetlaToAddendOnly(false)
+ { assert(targetAtom != NULL); u.target = targetAtom; }
+
+ Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const Atom* targetAtom) :
+ offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b),
+ contentAddendOnly(false), contentDetlaToAddendOnly(false)
+ { assert(targetAtom != NULL); u.target = targetAtom; }
+
+ Fixup(uint32_t off, Cluster c, Kind k, uint64_t addend) :
+ offsetInAtom(off), kind(k), clusterSize(c), weakImport(false),
+ binding(Fixup::bindingNone),
+ contentAddendOnly(false), contentDetlaToAddendOnly(false)
+ { u.addend = addend; }
+
+ bool firstInCluster() const {
+ switch (clusterSize) {
+ case k1of1:
+ case k1of2:
+ case k1of3:
+ case k1of4:
+ case k1of5:
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ bool lastInCluster() const {
+ switch (clusterSize) {
+ case k1of1:
+ case k2of2:
+ case k3of3:
+ case k4of4:
+ case k5of5:
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+};
+
+//
+// ld::Atom
+//
+// An atom is the fundamental unit of linking. A C function or global variable is an atom.
+// An atom has content and attributes. The content of a function atom is the instructions
+// that implement the function. The content of a global variable atom is its initial bits.
+//
+// Name:
+// The name of an atom is the label name generated by the compiler. A C compiler names foo()
+// as _foo. A C++ compiler names foo() as __Z3foov.
+// The name refers to the first byte of the content. An atom cannot have multiple entry points.
+// Such code is modeled as multiple atoms, each having a "follow on" reference to the next.
+// A "follow on" reference is a contraint to the linker to the atoms must be laid out contiguously.
+//
+// Scope:
+// An atom is in one of three scopes: translation-unit, linkage-unit, or global. These correspond
+// to the C visibility of static, hidden, default.
+//
+// DefinitionKind:
+// An atom is one of five defintion kinds:
+// regular Most atoms.
+// weak C++ compiler makes some functions weak if there might be multiple copies
+// that the linker needs to coalesce.
+// tentative A straggler from ancient C when the extern did not exist. "int foo;" is ambiguous.
+// It could be a prototype or it could be a definition.
+// external This is a "proxy" atom produced by a dylib reader. It has no content. It exists
+// so that the graph of Atoms can be complete.
+// external-weak Same as external, but the definition in the dylib is weak.
+//
+// SymbolTableInclusion:
+// An atom may or may not be in the symbol table in an object file.
+// in Most atoms for functions or global data
+// not-in Anonymous atoms such literal c-strings, or other compiler generated data
+// not-in-final Atom whose name should not be in the symbol table of final linkd image (e.g. 'l' labels .eh labels)
+// in-never-strip Atom whose name the strip tool should never remove (e.g. REFERENCED_DYNAMICALLY in mach-o)
+//
+// ContentType:
+// Some atoms require specially processing by the linker based on their content. For instance, zero-fill data
+// atom are group together at the end of the DATA segment to reduce disk size.
+//
+// ObjectAddress:
+// For reproducability, the linker lays out atoms in the order they occurred in the source (object) files.
+// The objectAddress() method returns the address of an atom in the object file so that the linker
+// can arrange the atoms.
+//
+//
+class Atom
+{
+public:
+ enum Scope { scopeTranslationUnit, scopeLinkageUnit, scopeGlobal };
+ enum Definition { definitionRegular, definitionTentative, definitionAbsolute, definitionProxy };
+ enum Combine { combineNever, combineByName, combineByNameAndContent, combineByNameAndReferences };
+ enum ContentType { typeUnclassified, typeZeroFill, typeCString, typeCFI, typeLSDA, typeSectionStart,
+ typeSectionEnd, typeBranchIsland, typeLazyPointer, typeStub, typeNonLazyPointer,
+ typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers,
+ typeLTOtemporary, typeResolver,
+ typeTLV, typeTLVZeroFill, typeTLVInitialValue, typeTLVInitializerPointers };
+
+ enum SymbolTableInclusion { symbolTableNotIn, symbolTableNotInFinalLinkedImages, symbolTableIn,
+ symbolTableInAndNeverStrip, symbolTableInAsAbsolute,
+ symbolTableInWithRandomAutoStripLabel };
+ enum WeakImportState { weakImportUnset, weakImportTrue, weakImportFalse };
+
+ struct Alignment {
+ Alignment(int p2, int m=0) : powerOf2(p2), modulus(m) {}
+ uint8_t trailingZeros() const { return (modulus==0) ? powerOf2 : __builtin_ctz(modulus); }
+ uint16_t powerOf2;
+ uint16_t modulus;
+ };
+ struct LineInfo {
+ const char* fileName;
+ uint32_t atomOffset;
+ uint32_t lineNumber;
+
+ typedef LineInfo* iterator;
+ };
+ struct UnwindInfo {
+ uint32_t startOffset;
+ uint32_t unwindInfo;
+
+ typedef UnwindInfo* iterator;
+ };
+
+ Atom(const Section& sect, Definition d, Combine c, Scope s, ContentType ct,
+ SymbolTableInclusion i, bool dds, bool thumb, bool al, Alignment a) :
+ _section(§), _address(0), _alignmentModulus(a.modulus),
+ _alignmentPowerOf2(a.powerOf2), _definition(d), _combine(c),
+ _dontDeadStrip(dds), _thumb(thumb), _alias(al), _autoHide(false),
+ _contentType(ct), _symbolTableInclusion(i),
+ _scope(s), _mode(modeSectionOffset),
+ _overridesADylibsWeakDef(false), _coalescedAway(false),
+ _live(false), _machoSection(0), _weakImportState(weakImportUnset)
+ {
+ #ifndef NDEBUG
+ switch ( _combine ) {
+ case combineByNameAndContent:
+ case combineByNameAndReferences:
+ assert(_symbolTableInclusion == symbolTableNotIn);
+ assert(_scope != scopeGlobal);
+ break;
+ case combineByName:
+ case combineNever:
+ break;
+ };
+ #endif
+ }
+ virtual ~Atom() {}
+
+ const Section& section() const { return *_section; }
+ Definition definition() const { return _definition; }
+ Combine combine() const { return _combine; }
+ Scope scope() const { return _scope; }
+ ContentType contentType() const { return _contentType; }
+ SymbolTableInclusion symbolTableInclusion() const{ return _symbolTableInclusion; }
+ bool dontDeadStrip() const { return _dontDeadStrip; }
+ bool isThumb() const { return _thumb; }
+ bool isAlias() const { return _alias; }
+ Alignment alignment() const { return Alignment(_alignmentPowerOf2, _alignmentModulus); }
+ bool overridesDylibsWeakDef() const { return _overridesADylibsWeakDef; }
+ bool coalescedAway() const { return _coalescedAway; }
+ bool weakImported() const { return _weakImportState == weakImportTrue; }
+ WeakImportState weakImportState() const { return _weakImportState; }
+ bool autoHide() const { return _autoHide; }
+ bool live() const { return _live; }
+ uint8_t machoSection() const { assert(_machoSection != 0); return _machoSection; }
+
+ void setScope(Scope s) { _scope = s; }
+ void setSymbolTableInclusion(SymbolTableInclusion i)
+ { _symbolTableInclusion = i; }
+ void setCombine(Combine c) { _combine = c; }
+ void setOverridesDylibsWeakDef() { _overridesADylibsWeakDef = true; }
+ void setCoalescedAway() { _coalescedAway = true; }
+ void setWeakImportState(bool w) { assert(_definition == definitionProxy); _weakImportState = ( w ? weakImportTrue : weakImportFalse); }
+ void setAutoHide() { _autoHide = true; }
+ void setLive() { _live = true; }
+ void setLive(bool value) { _live = value; }
+ void setMachoSection(unsigned x) { assert(x != 0); assert(x < 256); _machoSection = x; }
+ void setSectionOffset(uint64_t o){ assert(_mode == modeSectionOffset); _address = o; _mode = modeSectionOffset; }
+ void setSectionStartAddress(uint64_t a) { assert(_mode == modeSectionOffset); _address += a; _mode = modeFinalAddress; }
+ uint64_t sectionOffset() const { assert(_mode == modeSectionOffset); return _address; }
+ uint64_t finalAddress() const { assert(_mode == modeFinalAddress); return _address; }
+#ifndef NDEBUG
+ bool finalAddressMode() const { return (_mode == modeFinalAddress); }
+#endif
+ virtual const File* file() const = 0;
+ virtual const char* translationUnitSource() const { return NULL; }
+ virtual const char* name() const = 0;
+ virtual uint64_t objectAddress() const = 0;
+ virtual uint64_t size() const = 0;
+ virtual void copyRawContent(uint8_t buffer[]) const = 0;
+ virtual const uint8_t* rawContentPointer() const { return NULL; }
+ virtual unsigned long contentHash(const class IndirectBindingTable&) const { return 0; }
+ virtual bool canCoalesceWith(const Atom& rhs, const class IndirectBindingTable&) const { return false; }
+ virtual Fixup::iterator fixupsBegin() const { return NULL; }
+ virtual Fixup::iterator fixupsEnd() const { return NULL; }
+ bool hasFixupsOfKind(Fixup::Kind kind) const {
+ for (ld::Fixup::iterator fit = fixupsBegin(), end=fixupsEnd(); fit != end; ++fit) {
+ if ( fit->kind == kind ) return true;
+ }
+ return false;
+ }
+
+ virtual UnwindInfo::iterator beginUnwind() const { return NULL; }
+ virtual UnwindInfo::iterator endUnwind() const { return NULL; }
+ virtual LineInfo::iterator beginLineInfo() const { return NULL; }
+ virtual LineInfo::iterator endLineInfo() const { return NULL; }
+
+protected:
+ enum AddressMode { modeSectionOffset, modeFinalAddress };
+
+ void setAttributesFromAtom(const Atom& a) {
+ _section = a._section;
+ _alignmentModulus = a._alignmentModulus;
+ _alignmentPowerOf2 = a._alignmentPowerOf2;
+ _definition = a._definition;
+ _combine = a._combine;
+ _dontDeadStrip = a._dontDeadStrip;
+ _thumb = a._thumb;
+ _alias = a._alias;
+ _autoHide = a._autoHide;
+ _contentType = a._contentType;
+ _symbolTableInclusion = a._symbolTableInclusion;
+ _scope = a._scope;
+ _mode = a._mode;
+ _overridesADylibsWeakDef = a._overridesADylibsWeakDef;
+ _coalescedAway = a._coalescedAway;
+ _weakImportState = a._weakImportState;
+ }
+
+ const Section * _section;
+ uint64_t _address;
+ uint16_t _alignmentModulus;
+ uint8_t _alignmentPowerOf2;
+ Definition _definition : 2;
+ Combine _combine : 2;
+ bool _dontDeadStrip : 1;
+ bool _thumb : 1;
+ bool _alias : 1;
+ int _autoHide : 1;
+ ContentType _contentType : 5;
+ SymbolTableInclusion _symbolTableInclusion : 3;
+ Scope _scope : 2;
+ AddressMode _mode: 2;
+ bool _overridesADylibsWeakDef : 1;
+ bool _coalescedAway : 1;
+ bool _live : 1;
+ unsigned _machoSection : 8;
+ WeakImportState _weakImportState : 2;
+};
+
+
+class IndirectBindingTable
+{
+public:
+ virtual const char* indirectName(uint32_t bindingIndex) const = 0;
+ virtual const ld::Atom* indirectAtom(uint32_t bindingIndex) const = 0;
+};
+
+
+class Internal
+{
+public:
+ class FinalSection : public ld::Section {
+ public:
+ FinalSection(const Section& sect) : Section(sect), address(0),
+ fileOffset(0), size(0), alignment(0),
+ indirectSymTabStartIndex(0), indirectSymTabElementSize(0),
+ relocStart(0), relocCount(0),
+ hasLocalRelocs(false), hasExternalRelocs(false) {}
+ std::vector<const Atom*> atoms;
+ uint64_t address;
+ uint64_t fileOffset;
+ uint64_t size;
+ uint32_t alignmentPaddingBytes;
+ uint8_t alignment;
+ uint32_t indirectSymTabStartIndex;
+ uint32_t indirectSymTabElementSize;
+ uint32_t relocStart;
+ uint32_t relocCount;
+ bool hasLocalRelocs;
+ bool hasExternalRelocs;
+ };
+
+ virtual ld::Internal::FinalSection* addAtom(const Atom&) = 0;
+ virtual ld::Internal::FinalSection* getFinalSection(const ld::Section& inputSection) = 0;
+ virtual ~Internal() {}
+ Internal() : bundleLoader(NULL),
+ entryPoint(NULL), classicBindingHelper(NULL),
+ lazyBindingHelper(NULL), compressedFastBinderProxy(NULL),
+ objcObjectConstraint(ld::File::objcConstraintNone),
+ objcDylibConstraint(ld::File::objcConstraintNone),
+ cpuSubType(0),
+ allObjectFilesScatterable(true),
+ someObjectFileHasDwarf(false), usingHugeSections(false) { }
+
+ std::vector<FinalSection*> sections;
+ std::vector<ld::dylib::File*> dylibs;
+ std::vector<ld::relocatable::File::Stab> stabs;
+ std::vector<const ld::Atom*> indirectBindingTable;
+ const ld::dylib::File* bundleLoader;
+ const Atom* entryPoint;
+ const Atom* classicBindingHelper;
+ const Atom* lazyBindingHelper;
+ const Atom* compressedFastBinderProxy;
+ ld::File::ObjcConstraint objcObjectConstraint;
+ ld::File::ObjcConstraint objcDylibConstraint;
+ uint32_t cpuSubType;
+ bool allObjectFilesScatterable;
+ bool someObjectFileHasDwarf;
+ bool usingHugeSections;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+} // namespace ld
+
+#endif // __LD_HPP__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __LTO_READER_H__
+#define __LTO_READER_H__
+
+#include <stdlib.h>
+#include <mach-o/dyld.h>
+#include <vector>
+#include <ext/hash_set>
+#include <ext/hash_map>
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+#include "ld.hpp"
+
+#include "llvm-c/lto.h"
+
+
+namespace lto {
+
+
+//
+// ld64 only tracks non-internal symbols from an llvm bitcode file.
+// We model this by having an InternalAtom which represent all internal functions and data.
+// All non-interal symbols from a bitcode file are represented by an Atom
+// and each Atom has a reference to the InternalAtom. The InternalAtom
+// also has references to each symbol external to the bitcode file.
+//
+class InternalAtom : public ld::Atom
+{
+public:
+ InternalAtom(class File& f);
+ // overrides of ld::Atom
+ virtual ld::File* file() const { return &_file; }
+ virtual bool translationUnitSource(const char** dir, const char** nm) const
+ { return false; }
+ virtual const char* name() const { return "import-atom"; }
+ virtual uint64_t size() const { return 0; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() { return &_undefs[0]; }
+ virtual ld::Fixup::iterator fixupsEnd() { return &_undefs[_undefs.size()]; }
+
+ // for adding references to symbols outside bitcode file
+ void addReference(const char* name)
+ { _undefs.push_back(ld::Fixup(0, ld::Fixup::k1of1,
+ ld::Fixup::fixupNone, false, name)); }
+private:
+
+ ld::File& _file;
+ std::vector<ld::Fixup> _undefs;
+};
+
+
+//
+// LLVM bitcode file
+//
+class File : public ld::relocatable::File
+{
+public:
+ File(const char* path, time_t mTime, const uint8_t* content,
+ uint32_t contentLength, uint32_t ordinal, cpu_type_t arch);
+ virtual ~File();
+
+ // overrides of ld::File
+ virtual bool forEachAtom(ld::File::AtomHandler&);
+ virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&)
+ { return false; }
+
+ // overrides of ld::relocatable::File
+ virtual bool objcReplacementClasses() { return false; }
+ virtual DebugInfoKind debugInfo() { return ld::relocatable::File::kDebugInfoNone; }
+ virtual std::vector<ld::relocatable::File::Stab>* stabs() { return NULL; }
+ virtual bool canScatterAtoms() { return true; }
+
+ lto_module_t module() { return _module; }
+ class InternalAtom& internalAtom() { return _internalAtom; }
+private:
+ friend class Atom;
+ friend class InternalAtom;
+
+ cpu_type_t _architecture;
+ class InternalAtom _internalAtom;
+ class Atom* _atomArray;
+ uint32_t _atomArrayCount;
+ lto_module_t _module;
+ ld::Section _section;
+};
+
+//
+// Atom acts as a proxy Atom for the symbols that are exported by LLVM bitcode file. Initially,
+// Reader creates Atoms to allow linker proceed with usual symbol resolution phase. After
+// optimization is performed, real Atoms are created for these symobls. However these real Atoms
+// are not inserted into global symbol table. Atom holds real Atom and forwards appropriate
+// methods to real atom.
+//
+class Atom : public ld::Atom
+{
+public:
+ Atom(File& f, const char* name, ld::Atom::Scope s,
+ ld::Atom::Definition d, ld::Atom::Alignment a);
+
+ // overrides of ld::Atom
+ virtual ld::File* file() const { return &_file; }
+ virtual bool translationUnitSource(const char** dir, const char** nm) const
+ { return (_compiledAtom ? _compiledAtom->translationUnitSource(dir, nm) : false); }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return (_compiledAtom ? _compiledAtom->size() : 0); }
+ virtual uint64_t objectAddress() const { return (_compiledAtom ? _compiledAtom->objectAddress() : 0); }
+ virtual void copyRawContent(uint8_t buffer[]) const
+ { if (_compiledAtom) _compiledAtom->copyRawContent(buffer); }
+
+ ld::Atom* compiledAtom() { return _compiledAtom; }
+ void setCompiledAtom(ld::Atom& atom)
+ { _compiledAtom = &atom; }
+private:
+
+ File& _file;
+ const char* _name;
+ ld::Atom* _compiledAtom;
+};
+
+
+
+
+
+
+
+class Parser
+{
+public:
+ static bool validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture);
+ static const char* fileKind(const uint8_t* fileContent);
+ static File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
+ time_t modTime, uint32_t ordinal, cpu_type_t architecture);
+ static bool libLTOisLoaded() { return (::lto_get_version() != NULL); }
+ static bool optimize(const std::vector<ld::Atom*>& allAtoms, std::vector<ld::Atom*>& newAtoms,
+ std::vector<const char*>& additionalUndefines,
+ const std::set<ld::Atom*>&,
+ std::vector<ld::Atom*>& newDeadAtoms,
+ uint32_t nextInputOrdinal,
+ ld::OutFile* writer, ld::Atom* entryPointAtom,
+ const std::vector<const char*>& llvmOptions,
+ bool allGlobalsAReDeadStripRoots,
+ bool verbose, bool saveTemps,
+ const char* outputFilePath,
+ bool pie, bool mainExecutable, bool staticExecutable, bool relocatable,
+ bool allowTextRelocs, cpu_type_t arch);
+
+ static const char* ltoVersion() { return ::lto_get_version(); }
+
+private:
+ static const char* tripletPrefixForArch(cpu_type_t arch);
+ static ld::relocatable::File* parseMachOFile(const uint8_t* p, size_t len, uint32_t nextInputOrdinal, cpu_type_t arch);
+
+ class CStringEquals
+ {
+ public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+ };
+ typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> CStringSet;
+ typedef __gnu_cxx::hash_map<const char*, Atom*, __gnu_cxx::hash<const char*>, CStringEquals> CStringToAtom;
+
+ class AtomSyncer : public ld::File::AtomHandler {
+ public:
+ AtomSyncer(std::vector<const char*>& a, std::vector<ld::Atom*>&na,
+ CStringToAtom la, CStringToAtom dla) :
+ additionalUndefines(a), newAtoms(na), llvmAtoms(la), deadllvmAtoms(dla) { }
+ virtual void doAtom(class ld::Atom&);
+
+ std::vector<const char*>& additionalUndefines;
+ std::vector<ld::Atom*>& newAtoms;
+ CStringToAtom llvmAtoms;
+ CStringToAtom deadllvmAtoms;
+ };
+
+ static std::vector<File*> _s_files;
+};
+
+std::vector<File*> Parser::_s_files;
+
+
+const char* Parser::tripletPrefixForArch(cpu_type_t arch)
+{
+ switch (arch) {
+ case CPU_TYPE_POWERPC:
+ return "powerpc-";
+ case CPU_TYPE_POWERPC64:
+ return "powerpc64-";
+ case CPU_TYPE_I386:
+ return "i386-";
+ case CPU_TYPE_X86_64:
+ return "x86_64-";
+ case CPU_TYPE_ARM:
+ return "arm";
+ }
+ return "";
+}
+
+bool Parser::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture)
+{
+ return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, tripletPrefixForArch(architecture));
+}
+
+const char* Parser::fileKind(const uint8_t* p)
+{
+ if ( (p[0] == 0xDE) && (p[1] == 0xC0) && (p[2] == 0x17) && (p[3] == 0x0B) ) {
+ uint32_t arch = LittleEndian::get32(*((uint32_t*)(&p[16])));
+ switch (arch) {
+ case CPU_TYPE_POWERPC:
+ return "ppc";
+ case CPU_TYPE_I386:
+ return "i386";
+ case CPU_TYPE_X86_64:
+ return "x86_64";
+ case CPU_TYPE_ARM:
+ return "arm";
+ }
+ return "unknown bitcode architecture";
+ }
+ return NULL;
+}
+
+File* Parser::parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime,
+ uint32_t ordinal, cpu_type_t architecture)
+{
+ File* f = new File(path, modTime, fileContent, fileLength, ordinal, architecture);
+ _s_files.push_back(f);
+ return f;
+}
+
+
+ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, uint32_t nextInputOrdinal, cpu_type_t arch)
+{
+ switch ( arch ) {
+ case CPU_TYPE_POWERPC:
+ if ( mach_o::relocatable::Parser<ppc>::validFile(p) )
+ return mach_o::relocatable::Parser<ppc>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal);
+ break;
+ case CPU_TYPE_POWERPC64:
+ if ( mach_o::relocatable::Parser<ppc64>::validFile(p) )
+ return mach_o::relocatable::Parser<ppc64>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal);
+ break;
+ case CPU_TYPE_I386:
+ if ( mach_o::relocatable::Parser<x86>::validFile(p) )
+ return mach_o::relocatable::Parser<x86>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal);
+ break;
+ case CPU_TYPE_X86_64:
+ if ( mach_o::relocatable::Parser<x86_64>::validFile(p) )
+ return mach_o::relocatable::Parser<x86_64>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal);
+ break;
+ case CPU_TYPE_ARM:
+ if ( mach_o::relocatable::Parser<arm>::validFile(p) )
+ return mach_o::relocatable::Parser<arm>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal);
+ break;
+ }
+ throw "LLVM LTO, file is not of required architecture";
+}
+
+
+
+File::File(const char* path, time_t mTime, const uint8_t* content, uint32_t contentLength, uint32_t ordinal, cpu_type_t arch)
+ : ld::relocatable::File(path,mTime,ordinal), _architecture(arch), _internalAtom(*this),
+ _atomArray(NULL), _atomArrayCount(0), _module(NULL),
+ _section("__TEXT_", "__tmp_lto", ld::Section::typeUnclassified)
+{
+ // create llvm module
+ _module = ::lto_module_create_from_memory(content, contentLength);
+ if ( _module == NULL )
+ throwf("could not parse object file %s: %s", path, lto_get_error_message());
+
+ // create atom for each global symbol in module
+ uint32_t count = ::lto_module_get_num_symbols(_module);
+ _atomArray = (Atom*)malloc(sizeof(Atom)*count);
+ for (uint32_t i=0; i < count; ++i) {
+ const char* name = ::lto_module_get_symbol_name(_module, i);
+ lto_symbol_attributes attr = lto_module_get_symbol_attribute(_module, i);
+
+ // <rdar://problem/6378110> LTO doesn't like dtrace symbols
+ // ignore dtrace static probes for now
+ // later when codegen is done and a mach-o file is produces the probes will be processed
+ if ( (strncmp(name, "___dtrace_probe$", 16) == 0) || (strncmp(name, "___dtrace_isenabled$", 20) == 0) )
+ continue;
+
+ ld::Atom::Definition def;
+ switch ( attr & LTO_SYMBOL_DEFINITION_MASK ) {
+ case LTO_SYMBOL_DEFINITION_REGULAR:
+ def = ld::Atom::definitionRegular;
+ break;
+ case LTO_SYMBOL_DEFINITION_TENTATIVE:
+ def = ld::Atom::definitionTentative;
+ break;
+ case LTO_SYMBOL_DEFINITION_WEAK:
+ def = ld::Atom::definitionRegular;
+ break;
+ case LTO_SYMBOL_DEFINITION_UNDEFINED:
+ case LTO_SYMBOL_DEFINITION_WEAKUNDEF:
+ def = ld::Atom::definitionProxy;
+ break;
+ default:
+ throwf("unknown definition kind for symbol %s in bitcode file %s", name, path);
+ }
+
+ // make LLVM atoms for definitions and a reference for undefines
+ if ( def != ld::Atom::definitionProxy ) {
+ ld::Atom::Scope scope;
+ switch ( attr & LTO_SYMBOL_SCOPE_MASK) {
+ case LTO_SYMBOL_SCOPE_INTERNAL:
+ scope = ld::Atom::scopeTranslationUnit;
+ break;
+ case LTO_SYMBOL_SCOPE_HIDDEN:
+ scope = ld::Atom::scopeLinkageUnit;
+ break;
+ case LTO_SYMBOL_SCOPE_DEFAULT:
+ scope = ld::Atom::scopeGlobal;
+ break;
+ default:
+ throwf("unknown scope for symbol %s in bitcode file %s", name, path);
+ }
+ // only make atoms for non-internal symbols
+ if ( scope == ld::Atom::scopeTranslationUnit )
+ continue;
+ uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK);
+ // make Atom using placement new operator
+ new (&_atomArray[_atomArrayCount++]) Atom(*this, name, scope, def, alignment);
+ }
+ else {
+ // add to list of external references
+ _internalAtom.addReference(name);
+ }
+ }
+}
+
+File::~File()
+{
+ if ( _module != NULL )
+ ::lto_module_dispose(_module);
+}
+
+bool File::forEachAtom(ld::File::AtomHandler& handler)
+{
+ handler.doAtom(_internalAtom);
+ for(uint32_t i=0; i < _atomArrayCount; ++i) {
+ handler.doAtom(_atomArray[i]);
+ }
+ return true;
+}
+
+InternalAtom::InternalAtom(File& f)
+ : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit,
+ ld::Atom::typeLTOtemporary, ld::Atom::symbolTableNotIn, false, false, ld::Atom::Alignment(0)),
+ _file(f)
+{
+}
+
+Atom::Atom(File& f, const char* name, ld::Atom::Scope s, ld::Atom::Definition d, ld::Atom::Alignment a)
+ : ld::Atom(f._section, d, ld::Atom::combineNever, s, ld::Atom::typeLTOtemporary, ld::Atom::symbolTableIn, false, false, a),
+ _file(f), _name(name), _compiledAtom(NULL)
+{
+}
+
+
+
+
+bool Parser::optimize(const std::vector<ld::Atom*>& allAtoms, std::vector<ld::Atom*>& newAtoms,
+ std::vector<const char*>& additionalUndefines,
+ const std::set<ld::Atom*>& deadAtoms,
+ std::vector<ld::Atom*>& newlyDeadAtoms,
+ uint32_t nextInputOrdinal,
+ ld::OutFile* writer, ld::Atom* entryPointAtom,
+ const std::vector<const char*>& llvmOptions,
+ bool allGlobalsAReDeadStripRoots,
+ bool verbose, bool saveTemps,
+ const char* outputFilePath,
+ bool pie, bool mainExecutable, bool staticExecutable, bool relocatable,
+ bool allowTextRelocs, cpu_type_t arch)
+{
+ // exit quickly if nothing to do
+ if ( _s_files.size() == 0 )
+ return false;
+
+ // print out LTO version string if -v was used
+ if ( verbose )
+ fprintf(stderr, "%s\n", lto_get_version());
+
+ // create optimizer and add each Reader
+ lto_code_gen_t generator = ::lto_codegen_create();
+ for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
+ if ( ::lto_codegen_add_module(generator, (*it)->module()) )
+ throwf("lto: could not merge in %s because %s", (*it)->path(), ::lto_get_error_message());
+ }
+
+ // add any -mllvm command line options
+ for (std::vector<const char*>::const_iterator it=llvmOptions.begin(); it != llvmOptions.end(); ++it) {
+ ::lto_codegen_debug_options(generator, *it);
+ }
+
+ // The atom graph uses directed edges (references). Collect all references where
+ // originating atom is not part of any LTO Reader. This allows optimizer to optimize an
+ // external (i.e. not originated from same .o file) reference if all originating atoms are also
+ // defined in llvm bitcode file.
+ CStringSet nonLLVMRefs;
+ CStringToAtom llvmAtoms;
+ bool hasNonllvmAtoms = false;
+ for (std::vector<ld::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) {
+ ld::Atom* atom = *it;
+ // only look at references that come from an atom that is not an llvm atom
+ if ( atom->contentType() != ld::Atom::typeLTOtemporary ) {
+ // remember if we've seen any atoms not from an llvm reader and not from the writer
+// if ( atom->getFile() != writer )
+// hasNonllvmAtoms = true;
+ for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ if ( fit->binding != ld::Fixup::bindingByNameBound )
+ continue;
+ // and reference an llvm atom
+ if ( fit->u.target->contentType() == ld::Atom::typeLTOtemporary )
+ nonLLVMRefs.insert(fit->u.target->name());
+ }
+ }
+ else {
+ llvmAtoms[atom->name()] = (Atom*)atom;
+ }
+ }
+ // if entry point is in a llvm bitcode file, it must be preserved by LTO
+ if ( entryPointAtom != NULL ) {
+ if ( entryPointAtom->contentType() == ld::Atom::typeLTOtemporary )
+ nonLLVMRefs.insert(entryPointAtom->name());
+ }
+
+ // deadAtoms are the atoms that the linker coalesced. For instance weak or tentative definitions
+ // overriden by another atom. If any of these deadAtoms are llvm atoms and they were replaced
+ // with a mach-o atom, we need to tell the lto engine to preserve (not optimize away) its dead
+ // atom so that the linker can replace it with the mach-o one later.
+ CStringToAtom deadllvmAtoms;
+ for (std::set<ld::Atom*>::iterator it = deadAtoms.begin(); it != deadAtoms.end(); ++it) {
+ ld::Atom* atom = *it;
+ if ( atom->contentType() == ld::Atom::typeLTOtemporary ) {
+ const char* name = atom->name();
+ ::lto_codegen_add_must_preserve_symbol(generator, name);
+ deadllvmAtoms[name] = (Atom*)atom;
+ }
+ }
+
+
+ // tell code generator about symbols that must be preserved
+ for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) {
+ const char* name = it->first;
+ Atom* atom = it->second;
+ // Include llvm Symbol in export list if it meets one of following two conditions
+ // 1 - atom scope is global (and not linkage unit).
+ // 2 - included in nonLLVMRefs set.
+ // If a symbol is not listed in exportList then LTO is free to optimize it away.
+ if ( (atom->scope() == ld::Atom::scopeGlobal) )
+ ::lto_codegen_add_must_preserve_symbol(generator, name);
+ else if ( nonLLVMRefs.find(name) != nonLLVMRefs.end() )
+ ::lto_codegen_add_must_preserve_symbol(generator, name);
+ }
+
+ // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o)
+ if ( relocatable && !hasNonllvmAtoms ) {
+ if ( ! ::lto_codegen_write_merged_modules(generator, outputFilePath) ) {
+ // HACK, no good way to tell linker we are all done, so just quit
+ exit(0);
+ }
+ warning("could not produce merged bitcode file");
+ }
+
+ // set code-gen model
+ lto_codegen_model model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+ if ( mainExecutable ) {
+ if ( staticExecutable ) {
+ // darwin x86_64 "static" code model is really dynamic code model
+ if ( arch == CPU_TYPE_X86_64 )
+ model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+ else
+ model = LTO_CODEGEN_PIC_MODEL_STATIC;
+ }
+ else {
+ if ( pie )
+ model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+ else
+ model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
+ }
+ }
+ else {
+ if ( allowTextRelocs )
+ model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
+ else
+ model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+ }
+ if ( ::lto_codegen_set_pic_model(generator, model) )
+ throwf("could not create set codegen model: %s", lto_get_error_message());
+
+ // if requested, save off merged bitcode file
+ if ( saveTemps ) {
+ char tempBitcodePath[MAXPATHLEN];
+ strcpy(tempBitcodePath, outputFilePath);
+ strcat(tempBitcodePath, ".lto.bc");
+ ::lto_codegen_write_merged_modules(generator, tempBitcodePath);
+ }
+
+#if LTO_API_VERSION >= 3
+ // find assembler next to linker
+ char path[PATH_MAX];
+ uint32_t bufSize = PATH_MAX;
+ if ( _NSGetExecutablePath(path, &bufSize) != -1 ) {
+ char* lastSlash = strrchr(path, '/');
+ if ( lastSlash != NULL ) {
+ strcpy(lastSlash+1, "as");
+ struct stat statInfo;
+ if ( stat(path, &statInfo) == 0 )
+ ::lto_codegen_set_assembler_path(generator, path);
+ }
+ }
+#endif
+ // run code generator
+ size_t machOFileLen;
+ const uint8_t* machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen);
+ if ( machOFile == NULL )
+ throwf("could not do LTO codegen: %s", ::lto_get_error_message());
+
+ // if requested, save off temp mach-o file
+ if ( saveTemps ) {
+ char tempMachoPath[MAXPATHLEN];
+ strcpy(tempMachoPath, outputFilePath);
+ strcat(tempMachoPath, ".lto.o");
+ int fd = ::open(tempMachoPath, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+ if ( fd != -1) {
+ ::write(fd, machOFile, machOFileLen);
+ ::close(fd);
+ }
+ // save off merged bitcode file
+ char tempOptBitcodePath[MAXPATHLEN];
+ strcpy(tempOptBitcodePath, outputFilePath);
+ strcat(tempOptBitcodePath, ".lto.opt.bc");
+ ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath);
+ }
+
+ // parse generated mach-o file into a MachOReader
+ ld::File* machoFile = parseMachOFile(machOFile, machOFileLen, nextInputOrdinal, arch);
+
+ // sync generated mach-o atoms with existing atoms ld knows about
+ AtomSyncer syncer(additionalUndefines,newAtoms,llvmAtoms,deadllvmAtoms);
+ machoFile->forEachAtom(syncer);
+
+ // Remove InternalAtoms from ld
+ for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
+ newlyDeadAtoms.push_back(&((*it)->internalAtom()));
+ }
+ // Remove Atoms from ld if code generator optimized them away
+ for (CStringToAtom::iterator li = llvmAtoms.begin(), le = llvmAtoms.end(); li != le; ++li) {
+ // check if setRealAtom() called on this Atom
+ if ( li->second->compiledAtom() == NULL )
+ newlyDeadAtoms.push_back(li->second);
+ }
+
+ return true;
+}
+
+
+void Parser::AtomSyncer::doAtom(ld::Atom& machoAtom)
+{
+ // update proxy atoms to point to real atoms and find new atoms
+ const char* name = machoAtom.name();
+ if ( machoAtom.scope() >= ld::Atom::scopeLinkageUnit ) {
+ CStringToAtom::iterator pos = llvmAtoms.find(name);
+ if ( pos != llvmAtoms.end() ) {
+ // turn Atom into a proxy for this mach-o atom
+ pos->second->setCompiledAtom(machoAtom);
+ }
+ else {
+ // an atom of this name was not in the allAtoms list the linker gave us
+ if ( deadllvmAtoms.find(name) != deadllvmAtoms.end() ) {
+ // this corresponding to an atom that the linker coalesced away.
+ // Don't pass it back as a new atom
+ }
+ else
+ {
+ // this is something new that lto conjured up, tell ld its new
+ newAtoms.push_back(&machoAtom);
+ }
+ }
+ }
+ else {
+ // ld only knew about non-satic atoms, so this one must be new
+ newAtoms.push_back(&machoAtom);
+ }
+
+ // adjust fixups to go through proxy atoms
+ for (ld::Fixup::iterator fit=machoAtom.fixupsBegin(); fit != machoAtom.fixupsEnd(); ++fit) {
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingNone:
+ break;
+ case ld::Fixup::bindingByNameUnbound:
+ // don't know if this target has been seen by linker before or if it is new
+ // be conservitive and tell linker it is new
+ additionalUndefines.push_back(fit->u.name);
+ break;
+ case ld::Fixup::bindingByNameBound:
+ break;
+ case ld::Fixup::bindingDirectlyBound:
+ // If mach-o atom is referencing another mach-o atom then
+ // reference is not going through Atom proxy. Fix it here to ensure that all
+ // llvm symbol references always go through Atom proxy.
+ break;
+ case ld::Fixup::bindingByContentBound:
+ break;
+ }
+ }
+
+}
+
+
+
+}; // namespace lto
+
+
+#endif
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <mach-o/ranlib.h>
+#include <ar.h>
+
+#include <vector>
+#include <set>
+#include <map>
+#include <algorithm>
+#include <ext/hash_map>
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+
+#include "macho_relocatable_file.h"
+#include "lto_file.h"
+#include "archive_file.h"
+
+
+namespace archive {
+
+typedef const struct ranlib* ConstRanLibPtr;
+
+// forward reference
+template <typename A> class File;
+
+
+template <typename A>
+class Parser
+{
+public:
+ typedef typename A::P P;
+
+ static bool validFile(const uint8_t* fileContent, uint64_t fileLength,
+ const mach_o::relocatable::ParserOptions& opts) {
+ return File<A>::validFile(fileContent, fileLength, opts); }
+ static File<A>* parse(const uint8_t* fileContent, uint64_t fileLength,
+ const char* path, time_t mTime,
+ ld::File::Ordinal ordinal, const ParserOptions& opts) {
+ return new File<A>(fileContent, fileLength, path, mTime,
+ ordinal, opts);
+ }
+
+};
+
+template <typename A>
+class File : public ld::archive::File
+{
+public:
+ static bool validFile(const uint8_t* fileContent, uint64_t fileLength,
+ const mach_o::relocatable::ParserOptions& opts);
+ File(const uint8_t* fileContent, uint64_t fileLength,
+ const char* pth, time_t modTime,
+ ld::File::Ordinal ord, const ParserOptions& opts);
+ virtual ~File() {}
+
+ // overrides of ld::File
+ virtual bool forEachAtom(ld::File::AtomHandler&) const;
+ virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const;
+ virtual uint32_t subFileCount() const { return _archiveFilelength/sizeof(ar_hdr); }
+
+ // overrides of ld::archive::File
+ virtual bool justInTimeDataOnlyforEachAtom(const char* name, ld::File::AtomHandler& handler) const;
+
+private:
+ static bool validMachOFile(const uint8_t* fileContent, uint64_t fileLength,
+ const mach_o::relocatable::ParserOptions& opts);
+ static bool validLTOFile(const uint8_t* fileContent, uint64_t fileLength,
+ const mach_o::relocatable::ParserOptions& opts);
+ static cpu_type_t architecture();
+
+ class Entry : ar_hdr
+ {
+ public:
+ void getName(char *, int) const;
+ time_t modificationTime() const;
+ const uint8_t* content() const;
+ uint32_t contentSize() const;
+ const Entry* next() const;
+ private:
+ bool hasLongName() const;
+ unsigned int getLongNameSpace() const;
+
+ };
+
+ struct MemberState { ld::relocatable::File* file; const Entry *entry; bool logged; bool loaded; uint16_t index;};
+ bool loadMember(MemberState& state, ld::File::AtomHandler& handler, const char *format, ...) const;
+
+ class CStringEquals
+ {
+ public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+ };
+ typedef __gnu_cxx::hash_map<const char*, const struct ranlib*, __gnu_cxx::hash<const char*>, CStringEquals> NameToEntryMap;
+
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+
+ typedef std::map<const class Entry*, MemberState> MemberToStateMap;
+
+ const struct ranlib* ranlibHashSearch(const char* name) const;
+ MemberState& makeObjectFileForMember(const Entry* member) const;
+ bool memberHasObjCCategories(const Entry* member) const;
+ void dumpTableOfContents();
+ void buildHashTable();
+
+ const uint8_t* _archiveFileContent;
+ uint64_t _archiveFilelength;
+ const struct ranlib* _tableOfContents;
+ uint32_t _tableOfContentCount;
+ const char* _tableOfContentStrings;
+ mutable MemberToStateMap _instantiatedEntries;
+ NameToEntryMap _hashTable;
+ const bool _forceLoadAll;
+ const bool _forceLoadObjC;
+ const bool _forceLoadThis;
+ const bool _objc2ABI;
+ const bool _verboseLoad;
+ const bool _logAllFiles;
+ const mach_o::relocatable::ParserOptions _objOpts;
+};
+
+
+template <typename A>
+bool File<A>::Entry::hasLongName() const
+{
+ return ( strncmp(this->ar_name, AR_EFMT1, strlen(AR_EFMT1)) == 0 );
+}
+
+template <typename A>
+unsigned int File<A>::Entry::getLongNameSpace() const
+{
+ char* endptr;
+ long result = strtol(&this->ar_name[strlen(AR_EFMT1)], &endptr, 10);
+ return result;
+}
+
+template <typename A>
+void File<A>::Entry::getName(char *buf, int bufsz) const
+{
+ if ( this->hasLongName() ) {
+ int len = this->getLongNameSpace();
+ assert(bufsz >= len+1);
+ strncpy(buf, ((char*)this)+sizeof(ar_hdr), len);
+ buf[len] = '\0';
+ }
+ else {
+ assert(bufsz >= 16+1);
+ strncpy(buf, this->ar_name, 16);
+ buf[16] = '\0';
+ char* space = strchr(buf, ' ');
+ if ( space != NULL )
+ *space = '\0';
+ }
+}
+
+template <typename A>
+time_t File<A>::Entry::modificationTime() const
+{
+ char temp[14];
+ strncpy(temp, this->ar_date, 12);
+ temp[12] = '\0';
+ char* endptr;
+ return (time_t)strtol(temp, &endptr, 10);
+}
+
+
+template <typename A>
+const uint8_t* File<A>::Entry::content() const
+{
+ if ( this->hasLongName() )
+ return ((uint8_t*)this) + sizeof(ar_hdr) + this->getLongNameSpace();
+ else
+ return ((uint8_t*)this) + sizeof(ar_hdr);
+}
+
+
+template <typename A>
+uint32_t File<A>::Entry::contentSize() const
+{
+ char temp[12];
+ strncpy(temp, this->ar_size, 10);
+ temp[10] = '\0';
+ char* endptr;
+ long size = strtol(temp, &endptr, 10);
+ // long name is included in ar_size
+ if ( this->hasLongName() )
+ size -= this->getLongNameSpace();
+ return size;
+}
+
+
+template <typename A>
+const class File<A>::Entry* File<A>::Entry::next() const
+{
+ const uint8_t* p = this->content() + contentSize();
+ p = (const uint8_t*)(((uintptr_t)p+3) & (-4)); // 4-byte align
+ return (class File<A>::Entry*)p;
+}
+
+
+template <> cpu_type_t File<x86>::architecture() { return CPU_TYPE_I386; }
+template <> cpu_type_t File<x86_64>::architecture() { return CPU_TYPE_X86_64; }
+template <> cpu_type_t File<arm>::architecture() { return CPU_TYPE_ARM; }
+
+
+template <typename A>
+bool File<A>::validMachOFile(const uint8_t* fileContent, uint64_t fileLength, const mach_o::relocatable::ParserOptions& opts)
+{
+ return mach_o::relocatable::isObjectFile(fileContent, fileLength, opts);
+}
+
+template <typename A>
+bool File<A>::validLTOFile(const uint8_t* fileContent, uint64_t fileLength, const mach_o::relocatable::ParserOptions& opts)
+{
+ return lto::isObjectFile(fileContent, fileLength, opts.architecture, opts.subType);
+}
+
+
+
+template <typename A>
+bool File<A>::validFile(const uint8_t* fileContent, uint64_t fileLength, const mach_o::relocatable::ParserOptions& opts)
+{
+ // must have valid archive header
+ if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
+ return false;
+
+ // peak at first .o file and verify it is correct architecture
+ const Entry* const start = (Entry*)&fileContent[8];
+ const Entry* const end = (Entry*)&fileContent[fileLength];
+ for (const Entry* p=start; p < end; p = p->next()) {
+ char memberName[256];
+ p->getName(memberName, sizeof(memberName));
+ // skip option table-of-content member
+ if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) )
+ continue;
+ // archive is valid if first .o file is valid
+ return (validMachOFile(p->content(), p->contentSize(), opts) || validLTOFile(p->content(), p->contentSize(), opts));
+ }
+ // empty archive
+ return true;
+}
+
+
+template <typename A>
+File<A>::File(const uint8_t fileContent[], uint64_t fileLength, const char* pth, time_t modTime,
+ ld::File::Ordinal ord, const ParserOptions& opts)
+ : ld::archive::File(strdup(pth), modTime, ord),
+ _archiveFileContent(fileContent), _archiveFilelength(fileLength),
+ _tableOfContents(NULL), _tableOfContentCount(0), _tableOfContentStrings(NULL),
+ _forceLoadAll(opts.forceLoadAll), _forceLoadObjC(opts.forceLoadObjC),
+ _forceLoadThis(opts.forceLoadThisArchive), _objc2ABI(opts.objcABI2), _verboseLoad(opts.verboseLoad),
+ _logAllFiles(opts.logAllFiles), _objOpts(opts.objOpts)
+{
+ if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
+ throw "not an archive";
+
+ if ( !_forceLoadAll ) {
+ const Entry* const firstMember = (Entry*)&_archiveFileContent[8];
+ char memberName[256];
+ firstMember->getName(memberName, sizeof(memberName));
+ if ( (strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0) ) {
+ const uint8_t* contents = firstMember->content();
+ uint32_t ranlibArrayLen = E::get32(*((uint32_t*)contents));
+ _tableOfContents = (const struct ranlib*)&contents[4];
+ _tableOfContentCount = ranlibArrayLen / sizeof(struct ranlib);
+ _tableOfContentStrings = (const char*)&contents[ranlibArrayLen+8];
+ if ( ((uint8_t*)(&_tableOfContents[_tableOfContentCount]) > &fileContent[fileLength])
+ || ((uint8_t*)_tableOfContentStrings > &fileContent[fileLength]) )
+ throw "malformed archive, perhaps wrong architecture";
+ this->buildHashTable();
+ }
+ else
+ throw "archive has no table of contents";
+ }
+}
+
+template <>
+bool File<x86>::memberHasObjCCategories(const Entry* member) const
+{
+ if ( _objc2ABI ) {
+ // i386 for iOS simulator uses ObjC2 which has no global symbol for categories
+ return mach_o::relocatable::hasObjC2Categories(member->content());
+ }
+ else {
+ // i386 uses ObjC1 ABI which has .objc_category* global symbols
+ // <rdar://problem/11342022> strip -S on i386 pulls out .objc_category_name symbols from static frameworks
+ return mach_o::relocatable::hasObjC1Categories(member->content());
+ }
+}
+
+
+
+template <typename A>
+bool File<A>::memberHasObjCCategories(const Entry* member) const
+{
+ // x86_64 and ARM use ObjC2 which has no global symbol for categories
+ return mach_o::relocatable::hasObjC2Categories(member->content());
+}
+
+
+template <typename A>
+typename File<A>::MemberState& File<A>::makeObjectFileForMember(const Entry* member) const
+{
+ uint16_t memberIndex = 0;
+ // in case member was instantiated earlier but not needed yet
+ typename MemberToStateMap::iterator pos = _instantiatedEntries.find(member);
+ if ( pos == _instantiatedEntries.end() ) {
+ // Have to find the index of this member
+ const Entry* start;
+ uint16_t index;
+ if (_instantiatedEntries.size() == 0) {
+ start = (Entry*)&_archiveFileContent[8];
+ index = 1;
+ } else {
+ MemberState &lastKnown = _instantiatedEntries.rbegin()->second;
+ start = lastKnown.entry->next();
+ index = lastKnown.index+1;
+ }
+ for (const Entry* p=start; p <= member; p = p->next(), index++) {
+ MemberState state = {NULL, p, false, false, index};
+ _instantiatedEntries[p] = state;
+ if (member == p) {
+ memberIndex = index;
+ }
+ }
+ } else {
+ MemberState& state = pos->second;
+ if (state.file)
+ return state;
+ memberIndex = state.index;
+ }
+ assert(memberIndex != 0);
+ char memberName[256];
+ member->getName(memberName, sizeof(memberName));
+ char memberPath[strlen(this->path()) + strlen(memberName)+4];
+ strcpy(memberPath, this->path());
+ strcat(memberPath, "(");
+ strcat(memberPath, memberName);
+ strcat(memberPath, ")");
+ //fprintf(stderr, "using %s from %s\n", memberName, this->path());
+ try {
+ // range check
+ if ( member > (Entry*)(_archiveFileContent+_archiveFilelength) )
+ throwf("corrupt archive, member starts past end of file");
+ if ( (member->content() + member->contentSize()) > (_archiveFileContent+_archiveFilelength) )
+ throwf("corrupt archive, member contents extends past end of file");
+ const char* mPath = strdup(memberPath);
+ // see if member is mach-o file
+ ld::File::Ordinal ordinal = this->ordinal().archiveOrdinalWithMemberIndex(memberIndex);
+ ld::relocatable::File* result = mach_o::relocatable::parse(member->content(), member->contentSize(),
+ mPath, member->modificationTime(),
+ ordinal, _objOpts);
+ if ( result != NULL ) {
+ MemberState state = {result, member, false, false, memberIndex};
+ _instantiatedEntries[member] = state;
+ return _instantiatedEntries[member];
+ }
+ // see if member is llvm bitcode file
+ result = lto::parse(member->content(), member->contentSize(),
+ mPath, member->modificationTime(), ordinal,
+ _objOpts.architecture, _objOpts.subType, _logAllFiles);
+ if ( result != NULL ) {
+ MemberState state = {result, member, false, false, memberIndex};
+ _instantiatedEntries[member] = state;
+ return _instantiatedEntries[member];
+ }
+
+ throwf("archive member '%s' with length %d is not mach-o or llvm bitcode", memberName, member->contentSize());
+ }
+ catch (const char* msg) {
+ throwf("in %s, %s", memberPath, msg);
+ }
+}
+
+
+template <typename A>
+bool File<A>::loadMember(MemberState& state, ld::File::AtomHandler& handler, const char *format, ...) const
+{
+ bool didSomething = false;
+ if (!state.loaded) {
+ if ( _verboseLoad && !state.logged ) {
+ va_list list;
+ va_start(list, format);
+ vprintf(format, list);
+ va_end(list);
+ state.logged = true;
+ }
+ state.loaded = true;
+ didSomething = state.file->forEachAtom(handler);
+ }
+ return didSomething;
+}
+
+
+template <typename A>
+bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
+{
+ bool didSome = false;
+ if ( _forceLoadAll || _forceLoadThis ) {
+ // call handler on all .o files in this archive
+ const Entry* const start = (Entry*)&_archiveFileContent[8];
+ const Entry* const end = (Entry*)&_archiveFileContent[_archiveFilelength];
+ for (const Entry* p=start; p < end; p = p->next()) {
+ char memberName[256];
+ p->getName(memberName, sizeof(memberName));
+ if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) )
+ continue;
+ MemberState& state = this->makeObjectFileForMember(p);
+ didSome |= loadMember(state, handler, "%s forced load of %s(%s)\n", _forceLoadThis ? "-force_load" : "-all_load", this->path(), memberName);
+ }
+ }
+ else if ( _forceLoadObjC ) {
+ // call handler on all .o files in this archive containing objc classes
+ for(typename NameToEntryMap::const_iterator it = _hashTable.begin(); it != _hashTable.end(); ++it) {
+ if ( (strncmp(it->first, ".objc_c", 7) == 0) || (strncmp(it->first, "_OBJC_CLASS_$_", 14) == 0) ) {
+ const Entry* member = (Entry*)&_archiveFileContent[E::get32(it->second->ran_off)];
+ MemberState& state = this->makeObjectFileForMember(member);
+ char memberName[256];
+ member->getName(memberName, sizeof(memberName));
+ didSome |= loadMember(state, handler, "-ObjC forced load of %s(%s)\n", this->path(), memberName);
+ }
+ }
+ // ObjC2 has no symbols in .o files with categories but not classes, look deeper for those
+ const Entry* const start = (Entry*)&_archiveFileContent[8];
+ const Entry* const end = (Entry*)&_archiveFileContent[_archiveFilelength];
+ for (const Entry* member=start; member < end; member = member->next()) {
+ char mname[256];
+ member->getName(mname, sizeof(mname));
+ // skip table-of-content member
+ if ( (member==start) && ((strcmp(mname, SYMDEF_SORTED) == 0) || (strcmp(mname, SYMDEF) == 0)) )
+ continue;
+ MemberState& state = this->makeObjectFileForMember(member);
+ // only look at files not already loaded
+ if ( ! state.loaded ) {
+ if ( this->memberHasObjCCategories(member) ) {
+ MemberState& state = this->makeObjectFileForMember(member);
+ char memberName[256];
+ member->getName(memberName, sizeof(memberName));
+ didSome |= loadMember(state, handler, "-ObjC forced load of %s(%s)\n", this->path(), memberName);
+ }
+ }
+ }
+ }
+ return didSome;
+}
+
+template <typename A>
+bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& handler) const
+{
+ // in force load case, all members already loaded
+ if ( _forceLoadAll || _forceLoadThis )
+ return false;
+
+ // do a hash search of table of contents looking for requested symbol
+ const struct ranlib* result = ranlibHashSearch(name);
+ if ( result != NULL ) {
+ const Entry* member = (Entry*)&_archiveFileContent[E::get32(result->ran_off)];
+ MemberState& state = this->makeObjectFileForMember(member);
+ char memberName[256];
+ member->getName(memberName, sizeof(memberName));
+ return loadMember(state, handler, "%s forced load of %s(%s)\n", name, this->path(), memberName);
+ }
+ //fprintf(stderr, "%s NOT found in archive %s\n", name, this->path());
+ return false;
+}
+
+class CheckIsDataSymbolHandler : public ld::File::AtomHandler
+{
+public:
+ CheckIsDataSymbolHandler(const char* n) : _name(n), _isData(false) {}
+ virtual void doAtom(const class ld::Atom& atom) {
+ if ( strcmp(atom.name(), _name) == 0 ) {
+ if ( atom.section().type() != ld::Section::typeCode )
+ _isData = true;
+ }
+ }
+ virtual void doFile(const class ld::File&) {}
+ bool symbolIsDataDefinition() { return _isData; }
+
+private:
+ const char* _name;
+ bool _isData;
+
+};
+
+template <typename A>
+bool File<A>::justInTimeDataOnlyforEachAtom(const char* name, ld::File::AtomHandler& handler) const
+{
+ // in force load case, all members already loaded
+ if ( _forceLoadAll || _forceLoadThis )
+ return false;
+
+ // do a hash search of table of contents looking for requested symbol
+ const struct ranlib* result = ranlibHashSearch(name);
+ if ( result != NULL ) {
+ const Entry* member = (Entry*)&_archiveFileContent[E::get32(result->ran_off)];
+ MemberState& state = this->makeObjectFileForMember(member);
+ // only call handler for each member once
+ if ( ! state.loaded ) {
+ CheckIsDataSymbolHandler checker(name);
+ state.file->forEachAtom(checker);
+ if ( checker.symbolIsDataDefinition() ) {
+ char memberName[256];
+ member->getName(memberName, sizeof(memberName));
+ return loadMember(state, handler, "%s forced load of %s(%s)\n", name, this->path(), memberName);
+ }
+ }
+ }
+ //fprintf(stderr, "%s NOT found in archive %s\n", name, this->path());
+ return false;
+}
+
+
+typedef const struct ranlib* ConstRanLibPtr;
+
+template <typename A>
+ConstRanLibPtr File<A>::ranlibHashSearch(const char* name) const
+{
+ typename NameToEntryMap::const_iterator pos = _hashTable.find(name);
+ if ( pos != _hashTable.end() )
+ return pos->second;
+ else
+ return NULL;
+}
+
+template <typename A>
+void File<A>::buildHashTable()
+{
+ // walk through list backwards, adding/overwriting entries
+ // this assures that with duplicates those earliest in the list will be found
+ for (int i = _tableOfContentCount-1; i >= 0; --i) {
+ const struct ranlib* entry = &_tableOfContents[i];
+ const char* entryName = &_tableOfContentStrings[E::get32(entry->ran_un.ran_strx)];
+ if ( E::get32(entry->ran_off) > _archiveFilelength ) {
+ throwf("malformed archive TOC entry for %s, offset %d is beyond end of file %lld\n",
+ entryName, entry->ran_off, _archiveFilelength);
+ }
+
+ //const Entry* member = (Entry*)&_archiveFileContent[E::get32(entry->ran_off)];
+ //fprintf(stderr, "adding hash %d, %s -> %p\n", i, entryName, entry);
+ _hashTable[entryName] = entry;
+ }
+}
+
+template <typename A>
+void File<A>::dumpTableOfContents()
+{
+ for (unsigned int i=0; i < _tableOfContentCount; ++i) {
+ const struct ranlib* e = &_tableOfContents[i];
+ printf("%s in %s\n", &_tableOfContentStrings[E::get32(e->ran_un.ran_strx)], ((Entry*)&_archiveFileContent[E::get32(e->ran_off)])->name());
+ }
+}
+
+
+//
+// main function used by linker to instantiate archive files
+//
+ld::archive::File* parse(const uint8_t* fileContent, uint64_t fileLength,
+ const char* path, time_t modTime, ld::File::Ordinal ordinal, const ParserOptions& opts)
+{
+ switch ( opts.objOpts.architecture ) {
+#if SUPPORT_ARCH_x86_64
+ case CPU_TYPE_X86_64:
+ if ( archive::Parser<x86_64>::validFile(fileContent, fileLength, opts.objOpts) )
+ return archive::Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+ break;
+#endif
+#if SUPPORT_ARCH_i386
+ case CPU_TYPE_I386:
+ if ( archive::Parser<x86>::validFile(fileContent, fileLength, opts.objOpts) )
+ return archive::Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+ break;
+#endif
+#if SUPPORT_ARCH_arm_any
+ case CPU_TYPE_ARM:
+ if ( archive::Parser<arm>::validFile(fileContent, fileLength, opts.objOpts) )
+ return archive::Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+ break;
+#endif
+ }
+ return NULL;
+}
+
+
+
+}; // namespace archive
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __ARCHIVE_FILE_H__
+#define __ARCHIVE_FILE_H__
+
+#include "ld.hpp"
+#include "macho_relocatable_file.h"
+
+namespace archive {
+
+struct ParserOptions {
+ mach_o::relocatable::ParserOptions objOpts;
+ bool forceLoadThisArchive;
+ bool forceLoadAll;
+ bool forceLoadObjC;
+ bool objcABI2;
+ bool verboseLoad;
+ bool logAllFiles;
+};
+
+extern ld::archive::File* parse(const uint8_t* fileContent, uint64_t fileLength,
+ const char* path, time_t modTime, ld::File::Ordinal ordinal, const ParserOptions& opts);
+
+} // namespace archive
+
+
+#endif // __ARCHIVE_FILE_H__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// C++ interface to lower levels of libuwind
+//
+
+#ifndef __ADDRESSSPACE_HPP__
+#define __ADDRESSSPACE_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <mach-o/loader.h>
+#include <mach-o/getsect.h>
+#include <mach-o/dyld_priv.h>
+#include <mach/i386/thread_status.h>
+#include <Availability.h>
+
+#include "FileAbstraction.hpp"
+#include "libunwind.h"
+#include "InternalMacros.h"
+#include "dwarf2.h"
+
+
+#if 0
+#if __i386__ || __x86_64__
+// In 10.6 and later i386 and x86_64 don't have a __dyld section
+// We need one to access private _dyld_func_lookup function.
+
+struct __DATA__dyld { long lazy; int (*lookup)(const char*, void**); };
+
+static volatile struct __DATA__dyld myDyldSection __attribute__ ((section ("__DATA,__dyld"))) = { 0, NULL };
+
+
+static int my_dyld_func_lookup(const char* dyld_func_name, void **address)
+{
+ return (*myDyldSection.lookup)(dyld_func_name, address);
+}
+#else
+ #define my_dyld_func_lookup _dyld_func_lookup
+#endif
+
+
+bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
+{
+ static void* (*p)(void*, dyld_unwind_sections*) = NULL;
+
+ if(p == NULL)
+ my_dyld_func_lookup("__dyld_find_unwind_sections", (void**)&p);
+ return p(addr, info);
+}
+#endif // 0
+
+
+
+namespace libunwind {
+
+///
+/// LocalAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread
+/// in the same process. It compiles away and making local unwinds very fast.
+///
+class LocalAddressSpace
+{
+public:
+
+ #if __LP64__
+ typedef uint64_t pint_t;
+ typedef int64_t sint_t;
+ #else
+ typedef uint32_t pint_t;
+ typedef int32_t sint_t;
+ #endif
+ uint8_t get8(pint_t addr) { return *((uint8_t*)addr); }
+ uint16_t get16(pint_t addr) { return *((uint16_t*)addr); }
+ uint32_t get32(pint_t addr) { return *((uint32_t*)addr); }
+ uint64_t get64(pint_t addr) { return *((uint64_t*)addr); }
+ double getDouble(pint_t addr) { return *((double*)addr); }
+ v128 getVector(pint_t addr) { return *((v128*)addr); }
+ uintptr_t getP(pint_t addr);
+ static uint64_t getULEB128(pint_t& addr, pint_t end);
+ static int64_t getSLEB128(pint_t& addr, pint_t end);
+
+ pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
+ bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset);
+ bool findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart);
+
+};
+
+LocalAddressSpace sThisAddress;
+
+inline uintptr_t LocalAddressSpace::getP(pint_t addr)
+{
+#if __LP64__
+ return get64(addr);
+#else
+ return get32(addr);
+#endif
+}
+
+/* Read a ULEB128 into a 64-bit word. */
+inline uint64_t
+LocalAddressSpace::getULEB128(pint_t& addr, pint_t end)
+{
+ const uint8_t* p = (uint8_t*)addr;
+ const uint8_t* pend = (uint8_t*)end;
+ uint64_t result = 0;
+ int bit = 0;
+ do {
+ uint64_t b;
+
+ if ( p == pend )
+ ABORT("truncated uleb128 expression");
+
+ b = *p & 0x7f;
+
+ if (bit >= 64 || b << bit >> bit != b) {
+ ABORT("malformed uleb128 expression");
+ }
+ else {
+ result |= b << bit;
+ bit += 7;
+ }
+ } while ( *p++ >= 0x80 );
+ addr = (pint_t)p;
+ return result;
+}
+
+/* Read a SLEB128 into a 64-bit word. */
+inline int64_t
+LocalAddressSpace::getSLEB128(pint_t& addr, pint_t end)
+{
+ const uint8_t* p = (uint8_t*)addr;
+ int64_t result = 0;
+ int bit = 0;
+ uint8_t byte;
+ do {
+ byte = *p++;
+ result |= ((byte & 0x7f) << bit);
+ bit += 7;
+ } while (byte & 0x80);
+ // sign extend negative numbers
+ if ( (byte & 0x40) != 0 )
+ result |= (-1LL) << bit;
+ addr = (pint_t)p;
+ return result;
+}
+
+LocalAddressSpace::pint_t
+LocalAddressSpace::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
+{
+ pint_t startAddr = addr;
+ const uint8_t* p = (uint8_t*)addr;
+ pint_t result;
+
+ // first get value
+ switch (encoding & 0x0F) {
+ case DW_EH_PE_ptr:
+ result = getP(addr);
+ p += sizeof(pint_t);
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_uleb128:
+ result = getULEB128(addr, end);
+ break;
+ case DW_EH_PE_udata2:
+ result = get16(addr);
+ p += 2;
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_udata4:
+ result = get32(addr);
+ p += 4;
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_udata8:
+ result = get64(addr);
+ p += 8;
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_sleb128:
+ result = getSLEB128(addr, end);
+ break;
+ case DW_EH_PE_sdata2:
+ result = (int16_t)get16(addr);
+ p += 2;
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_sdata4:
+ result = (int32_t)get32(addr);
+ p += 4;
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_sdata8:
+ result = get64(addr);
+ p += 8;
+ addr = (pint_t)p;
+ break;
+ default:
+ ABORT("unknown pointer encoding");
+ }
+
+ // then add relative offset
+ switch ( encoding & 0x70 ) {
+ case DW_EH_PE_absptr:
+ // do nothing
+ break;
+ case DW_EH_PE_pcrel:
+ result += startAddr;
+ break;
+ case DW_EH_PE_textrel:
+ ABORT("DW_EH_PE_textrel pointer encoding not supported");
+ break;
+ case DW_EH_PE_datarel:
+ ABORT("DW_EH_PE_datarel pointer encoding not supported");
+ break;
+ case DW_EH_PE_funcrel:
+ ABORT("DW_EH_PE_funcrel pointer encoding not supported");
+ break;
+ case DW_EH_PE_aligned:
+ ABORT("DW_EH_PE_aligned pointer encoding not supported");
+ break;
+ default:
+ ABORT("unknown pointer encoding");
+ break;
+ }
+
+ if ( encoding & DW_EH_PE_indirect )
+ result = getP(result);
+
+ return result;
+}
+
+
+inline bool LocalAddressSpace::findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart)
+{
+ dyld_unwind_sections info;
+ if ( _dyld_find_unwind_sections((void*)addr, &info) ) {
+ mh = (pint_t)info.mh;
+ dwarfStart = (pint_t)info.dwarf_section;
+ dwarfLen = (pint_t)info.dwarf_section_length;
+ compactStart = (pint_t)info.compact_unwind_section;
+ return true;
+ }
+ return false;
+}
+
+
+inline bool LocalAddressSpace::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
+{
+ dl_info dyldInfo;
+ if ( dladdr((void*)addr, &dyldInfo) ) {
+ if ( dyldInfo.dli_sname != NULL ) {
+ strlcpy(buf, dyldInfo.dli_sname, bufLen);
+ *offset = (addr - (pint_t)dyldInfo.dli_saddr);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+#if UNW_REMOTE
+
+///
+/// OtherAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread
+/// in the another process. The other process can be a different endianness and a different
+/// pointer size and is handled by the P template parameter.
+///
+template <typename P>
+class OtherAddressSpace
+{
+public:
+ OtherAddressSpace(task_t task) : fTask(task) {}
+
+ typedef typename P::uint_t pint_t;
+
+ uint8_t get8(pint_t addr);
+ uint16_t get16(pint_t addr);
+ uint32_t get32(pint_t addr);
+ uint64_t get64(pint_t addr);
+ pint_t getP(pint_t addr);
+ uint64_t getULEB128(pint_t& addr, pint_t end);
+ int64_t getSLEB128(pint_t& addr, pint_t end);
+ pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
+ bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset);
+ bool findUnwindSections(pint_t addr, unwind_sections& info);
+private:
+ void* localCopy(pint_t addr);
+
+
+ task_t fTask;
+};
+
+
+template <typename P>
+uint8_t OtherAddressSpace<P>::get8(pint_t addr)
+{
+ return *((uint8_t*)localCopy(addr));
+}
+
+template <typename P>
+uint16_t OtherAddressSpace<P>::get16(pint_t addr)
+{
+ return P::E::get16(*(uint16_t*)localCopy(addr));
+}
+
+template <typename P>
+uint32_t OtherAddressSpace<P>::get32(pint_t addr)
+{
+ return P::E::get32(*(uint32_t*)localCopy(addr));
+}
+
+template <typename P>
+uint64_t OtherAddressSpace<P>::get64(pint_t addr)
+{
+ return P::E::get64(*(uint64_t*)localCopy(addr));
+}
+
+template <typename P>
+typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr)
+{
+ return P::getP(*(uint64_t*)localCopy(addr));
+}
+
+template <typename P>
+uint64_t OtherAddressSpace<P>::getULEB128(pint_t& addr, pint_t end)
+{
+ uintptr_t size = (end - addr);
+ LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t)localCopy(addr);
+ LocalAddressSpace::pint_t sladdr = laddr;
+ uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr+size);
+ addr += (laddr-sladdr);
+ return result;
+}
+
+template <typename P>
+int64_t OtherAddressSpace<P>::getSLEB128(pint_t& addr, pint_t end)
+{
+ uintptr_t size = (end - addr);
+ LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t)localCopy(addr);
+ LocalAddressSpace::pint_t sladdr = laddr;
+ uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr+size);
+ addr += (laddr-sladdr);
+ return result;
+}
+
+template <typename P>
+void* OtherAddressSpace<P>::localCopy(pint_t addr)
+{
+ // FIX ME
+}
+
+template <typename P>
+bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
+{
+ // FIX ME
+}
+
+
+
+///
+/// unw_addr_space is the base class that abstract unw_addr_space_t type in libunwind.h points to.
+///
+struct unw_addr_space
+{
+ cpu_type_t cpuType;
+ task_t taskPort;
+};
+
+
+///
+/// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points to when examining
+/// a 32-bit intel process.
+///
+struct unw_addr_space_i386 : public unw_addr_space
+{
+ unw_addr_space_i386(task_t task) : oas(task) {}
+ OtherAddressSpace<Pointer32<LittleEndian> > oas;
+};
+
+
+///
+/// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t points to when examining
+/// a 64-bit intel process.
+///
+struct unw_addr_space_x86_64 : public unw_addr_space
+{
+ unw_addr_space_x86_64(task_t task) : oas(task) {}
+ OtherAddressSpace<Pointer64<LittleEndian> > oas;
+};
+
+
+///
+/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points to when examining
+/// a 32-bit PowerPC process.
+///
+struct unw_addr_space_ppc : public unw_addr_space
+{
+ unw_addr_space_ppc(task_t task) : oas(task) {}
+ OtherAddressSpace<Pointer32<BigEndian> > oas;
+};
+
+
+#endif // UNW_REMOTE
+
+
+} // namespace libunwind
+
+
+
+#endif // __ADDRESSSPACE_HPP__
+
+
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// processor specific parsing of dwarf unwind instructions
+//
+
+#ifndef __DWARF_INSTRUCTIONS_HPP__
+#define __DWARF_INSTRUCTIONS_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <algorithm>
+#include <vector>
+
+#include <libunwind.h>
+#include <mach-o/compact_unwind_encoding.h>
+
+#include "dwarf2.h"
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+#include "DwarfParser.hpp"
+#include "InternalMacros.h"
+//#include "CompactUnwinder.hpp"
+
+#define EXTRACT_BITS(value, mask) \
+ ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
+
+#define CFI_INVALID_ADDRESS ((pint_t)(-1))
+
+namespace libunwind {
+
+///
+/// Used by linker when parsing __eh_frame section
+///
+template <typename A>
+struct CFI_Reference {
+ typedef typename A::pint_t pint_t;
+ uint8_t encodingOfTargetAddress;
+ uint32_t offsetInCFI;
+ pint_t targetAddress;
+};
+template <typename A>
+struct CFI_Atom_Info {
+ typedef typename A::pint_t pint_t;
+ pint_t address;
+ uint32_t size;
+ bool isCIE;
+ union {
+ struct {
+ CFI_Reference<A> function;
+ CFI_Reference<A> cie;
+ CFI_Reference<A> lsda;
+ uint32_t compactUnwindInfo;
+ } fdeInfo;
+ struct {
+ CFI_Reference<A> personality;
+ } cieInfo;
+ } u;
+};
+
+typedef void (*WarnFunc)(void* ref, uint64_t funcAddr, const char* msg);
+
+///
+/// DwarfInstructions maps abtract dwarf unwind instructions to a particular architecture
+///
+template <typename A, typename R>
+class DwarfInstructions
+{
+public:
+ typedef typename A::pint_t pint_t;
+ typedef typename A::sint_t sint_t;
+
+ static const char* parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
+ CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn);
+
+
+ static compact_unwind_encoding_t createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart,
+ pint_t* lsda, pint_t* personality,
+ char warningBuffer[1024]);
+
+ static int stepWithDwarf(A& addressSpace, pint_t pc, pint_t fdeStart, R& registers);
+
+private:
+
+ enum {
+ DW_X86_64_RET_ADDR = 16
+ };
+
+ enum {
+ DW_X86_RET_ADDR = 8
+ };
+
+ static pint_t evaluateExpression(pint_t expression, A& addressSpace, const R& registers, pint_t initialStackValue);
+ static pint_t getSavedRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg);
+ static double getSavedFloatRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg);
+ static v128 getSavedVectorRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg);
+
+ // x86 specific variants
+ static int lastRestoreReg(const Registers_x86&);
+ static bool isReturnAddressRegister(int regNum, const Registers_x86&);
+ static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_x86&);
+
+ static uint32_t getEBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure);
+ static compact_unwind_encoding_t encodeToUseDwarf(const Registers_x86&);
+ static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_x86&, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024]);
+
+ // x86_64 specific variants
+ static int lastRestoreReg(const Registers_x86_64&);
+ static bool isReturnAddressRegister(int regNum, const Registers_x86_64&);
+ static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_x86_64&);
+
+ static uint32_t getRBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure);
+ static compact_unwind_encoding_t encodeToUseDwarf(const Registers_x86_64&);
+ static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_x86_64&, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024]);
+
+ // ppc specific variants
+ static int lastRestoreReg(const Registers_ppc&);
+ static bool isReturnAddressRegister(int regNum, const Registers_ppc&);
+ static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_ppc&);
+ static compact_unwind_encoding_t encodeToUseDwarf(const Registers_ppc&);
+ static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_ppc&, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024]);
+};
+
+
+
+
+template <typename A, typename R>
+const char* DwarfInstructions<A,R>::parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
+ CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn)
+{
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ CFI_Atom_Info<A>* entry = infos;
+ CFI_Atom_Info<A>* end = &infos[infosCount];
+ const pint_t ehSectionEnd = ehSectionStart + sectionLength;
+ for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
+ pint_t currentCFI = p;
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return NULL; // end marker
+ if ( entry >= end )
+ return "too little space allocated for parseCFIs";
+ pint_t nextCFI = p + cfiLength;
+ uint32_t id = addressSpace.get32(p);
+ if ( id == 0 ) {
+ // is CIE
+ const char* err = CFI_Parser<A>::parseCIE(addressSpace, currentCFI, &cieInfo);
+ if ( err != NULL )
+ return err;
+ entry->address = currentCFI;
+ entry->size = nextCFI - currentCFI;
+ entry->isCIE = true;
+ entry->u.cieInfo.personality.targetAddress = cieInfo.personality;
+ entry->u.cieInfo.personality.offsetInCFI = cieInfo.personalityOffsetInCIE;
+ entry->u.cieInfo.personality.encodingOfTargetAddress = cieInfo.personalityEncoding;
+ ++entry;
+ }
+ else {
+ // is FDE
+ entry->address = currentCFI;
+ entry->size = nextCFI - currentCFI;
+ entry->isCIE = false;
+ entry->u.fdeInfo.function.targetAddress = CFI_INVALID_ADDRESS;
+ entry->u.fdeInfo.cie.targetAddress = CFI_INVALID_ADDRESS;
+ entry->u.fdeInfo.lsda.targetAddress = CFI_INVALID_ADDRESS;
+ uint32_t ciePointer = addressSpace.get32(p);
+ pint_t cieStart = p-ciePointer;
+ // validate pointer to CIE is within section
+ if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) )
+ return "FDE points to CIE outside __eh_frame section";
+ // optimize usual case where cie is same for all FDEs
+ if ( cieStart != cieInfo.cieStart ) {
+ const char* err = CFI_Parser<A>::parseCIE(addressSpace, cieStart, &cieInfo);
+ if ( err != NULL )
+ return err;
+ }
+ entry->u.fdeInfo.cie.targetAddress = cieStart;
+ entry->u.fdeInfo.cie.offsetInCFI = p-currentCFI;
+ entry->u.fdeInfo.cie.encodingOfTargetAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
+ p += 4;
+ // parse pc begin and range
+ pint_t offsetOfFunctionAddress = p-currentCFI;
+ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
+ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
+ //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ // test if pc is within the function this FDE covers
+ entry->u.fdeInfo.function.targetAddress = pcStart;
+ entry->u.fdeInfo.function.offsetInCFI = offsetOfFunctionAddress;
+ entry->u.fdeInfo.function.encodingOfTargetAddress = cieInfo.pointerEncoding;
+ // check for augmentation length
+ if ( cieInfo.fdesHaveAugmentationData ) {
+ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+ pint_t endOfAug = p + augLen;
+ if ( cieInfo.lsdaEncoding != 0 ) {
+ // peek at value (without indirection). Zero means no lsda
+ pint_t lsdaStart = p;
+ if ( addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding & 0x0F) != 0 ) {
+ // reset pointer and re-parse lsda address
+ p = lsdaStart;
+ pint_t offsetOfLSDAAddress = p-currentCFI;
+ entry->u.fdeInfo.lsda.targetAddress = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding);
+ entry->u.fdeInfo.lsda.offsetInCFI = offsetOfLSDAAddress;
+ entry->u.fdeInfo.lsda.encodingOfTargetAddress = cieInfo.lsdaEncoding;
+ }
+ }
+ p = endOfAug;
+ }
+ // compute compact unwind encoding
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ fdeInfo.fdeStart = currentCFI;
+ fdeInfo.fdeLength = nextCFI - currentCFI;
+ fdeInfo.fdeInstructions = p;
+ fdeInfo.pcStart = pcStart;
+ fdeInfo.pcEnd = pcStart + pcRange;
+ fdeInfo.lsda = entry->u.fdeInfo.lsda.targetAddress;
+ typename CFI_Parser<A>::PrologInfo prolog;
+ R dummy; // for proper selection of architecture specific functions
+ if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) {
+ char warningBuffer[1024];
+ entry->u.fdeInfo.compactUnwindInfo = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer);
+ if ( fdeInfo.lsda != CFI_INVALID_ADDRESS )
+ entry->u.fdeInfo.compactUnwindInfo |= UNWIND_HAS_LSDA;
+ if ( warningBuffer[0] != '\0' )
+ warn(ref, fdeInfo.pcStart, warningBuffer);
+ }
+ else {
+ warn(ref, CFI_INVALID_ADDRESS, "dwarf unwind instructions could not be parsed");
+ entry->u.fdeInfo.compactUnwindInfo = encodeToUseDwarf(dummy);
+ }
+ ++entry;
+ }
+ p = nextCFI;
+ }
+ if ( entry != end )
+ return "wrong entry count for parseCFIs";
+ return NULL; // success
+}
+
+
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart,
+ pint_t* lsda, pint_t* personality,
+ char warningBuffer[1024])
+{
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ R dummy; // for proper selection of architecture specific functions
+ if ( CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo) == NULL ) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) {
+ *lsda = fdeInfo.lsda;
+ *personality = cieInfo.personality;
+ compact_unwind_encoding_t encoding;
+ encoding = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer);
+ if ( fdeInfo.lsda != 0 )
+ encoding |= UNWIND_HAS_LSDA;
+ return encoding;
+ }
+ else {
+ strcpy(warningBuffer, "dwarf unwind instructions could not be parsed");
+ return encodeToUseDwarf(dummy);
+ }
+ }
+ else {
+ strcpy(warningBuffer, "dwarf FDE could not be parsed");
+ return encodeToUseDwarf(dummy);
+ }
+}
+
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getSavedRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg)
+{
+ switch ( savedReg.location ) {
+ case CFI_Parser<A>::kRegisterInCFA:
+ return addressSpace.getP(cfa + savedReg.value);
+
+ case CFI_Parser<A>::kRegisterAtExpression:
+ return addressSpace.getP(evaluateExpression(savedReg.value, addressSpace, registers, cfa));
+
+ case CFI_Parser<A>::kRegisterIsExpression:
+ return evaluateExpression(savedReg.value, addressSpace, registers, cfa);
+
+ case CFI_Parser<A>::kRegisterInRegister:
+ return registers.getRegister(savedReg.value);
+
+ case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterOffsetFromCFA:
+ // FIX ME
+ break;
+ }
+ ABORT("unsupported restore location for register");
+}
+
+template <typename A, typename R>
+double DwarfInstructions<A,R>::getSavedFloatRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg)
+{
+ switch ( savedReg.location ) {
+ case CFI_Parser<A>::kRegisterInCFA:
+ return addressSpace.getDouble(cfa + savedReg.value);
+
+ case CFI_Parser<A>::kRegisterAtExpression:
+ return addressSpace.getDouble(evaluateExpression(savedReg.value, addressSpace, registers, cfa));
+
+ case CFI_Parser<A>::kRegisterIsExpression:
+ case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterOffsetFromCFA:
+ case CFI_Parser<A>::kRegisterInRegister:
+ // FIX ME
+ break;
+ }
+ ABORT("unsupported restore location for float register");
+}
+
+template <typename A, typename R>
+v128 DwarfInstructions<A,R>::getSavedVectorRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg)
+{
+ switch ( savedReg.location ) {
+ case CFI_Parser<A>::kRegisterInCFA:
+ return addressSpace.getVector(cfa + savedReg.value);
+
+ case CFI_Parser<A>::kRegisterAtExpression:
+ return addressSpace.getVector(evaluateExpression(savedReg.value, addressSpace, registers, cfa));
+
+ case CFI_Parser<A>::kRegisterIsExpression:
+ case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterOffsetFromCFA:
+ case CFI_Parser<A>::kRegisterInRegister:
+ // FIX ME
+ break;
+ }
+ ABORT("unsupported restore location for vector register");
+}
+
+
+template <typename A, typename R>
+int DwarfInstructions<A,R>::stepWithDwarf(A& addressSpace, pint_t pc, pint_t fdeStart, R& registers)
+{
+ //fprintf(stderr, "stepWithDwarf(pc=0x%0llX, fdeStart=0x%0llX)\n", (uint64_t)pc, (uint64_t)fdeStart);
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ if ( CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo) == NULL ) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
+ R newRegisters = registers;
+
+ // get pointer to cfa (architecture specific)
+ pint_t cfa = getCFA(addressSpace, prolog, registers);
+
+ // restore registers that dwarf says were saved
+ pint_t returnAddress = 0;
+ for (int i=0; i <= lastRestoreReg(newRegisters); ++i) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+ if ( registers.validFloatRegister(i) )
+ newRegisters.setFloatRegister(i, getSavedFloatRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]));
+ else if ( registers.validVectorRegister(i) )
+ newRegisters.setVectorRegister(i, getSavedVectorRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]));
+ else if ( isReturnAddressRegister(i, registers) )
+ returnAddress = getSavedRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]);
+ else if ( registers.validRegister(i) )
+ newRegisters.setRegister(i, getSavedRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]));
+ else
+ return UNW_EBADREG;
+ }
+ }
+
+ // by definition the CFA is the stack pointer at the call site, so restoring SP means setting it to CFA
+ newRegisters.setSP(cfa);
+
+ // return address is address after call site instruction, so setting IP to that does a return
+ newRegisters.setIP(returnAddress);
+
+ // do the actual step by replacing the register set with the new ones
+ registers = newRegisters;
+
+ return UNW_STEP_SUCCESS;
+ }
+ }
+ return UNW_EBADFRAME;
+}
+
+
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::evaluateExpression(pint_t expression, A& addressSpace,
+ const R& registers, pint_t initialStackValue)
+{
+ const bool log = false;
+ pint_t p = expression;
+ pint_t expressionEnd = expression+20; // just need something until length is read
+ uint64_t length = addressSpace.getULEB128(p, expressionEnd);
+ expressionEnd = p + length;
+ if (log) fprintf(stderr, "evaluateExpression(): length=%llu\n", length);
+ pint_t stack[100];
+ pint_t* sp = stack;
+ *(++sp) = initialStackValue;
+
+ while ( p < expressionEnd ) {
+ if (log) {
+ for(pint_t* t = sp; t > stack; --t) {
+ fprintf(stderr, "sp[] = 0x%llX\n", (uint64_t)(*t));
+ }
+ }
+ uint8_t opcode = addressSpace.get8(p++);
+ sint_t svalue;
+ pint_t value;
+ uint32_t reg;
+ switch (opcode) {
+ case DW_OP_addr:
+ // push immediate address sized value
+ value = addressSpace.getP(p);
+ p += sizeof(pint_t);
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_deref:
+ // pop stack, dereference, push result
+ value = *sp--;
+ *(++sp) = addressSpace.getP(value);
+ if (log) fprintf(stderr, "dereference 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const1u:
+ // push immediate 1 byte value
+ value = addressSpace.get8(p);
+ p += 1;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const1s:
+ // push immediate 1 byte signed value
+ svalue = (int8_t)addressSpace.get8(p);
+ p += 1;
+ *(++sp) = svalue;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_const2u:
+ // push immediate 2 byte value
+ value = addressSpace.get16(p);
+ p += 2;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const2s:
+ // push immediate 2 byte signed value
+ svalue = (int16_t)addressSpace.get16(p);
+ p += 2;
+ *(++sp) = svalue;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_const4u:
+ // push immediate 4 byte value
+ value = addressSpace.get32(p);
+ p += 4;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const4s:
+ // push immediate 4 byte signed value
+ svalue = (int32_t)addressSpace.get32(p);
+ p += 4;
+ *(++sp) = svalue;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_const8u:
+ // push immediate 8 byte value
+ value = addressSpace.get64(p);
+ p += 8;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const8s:
+ // push immediate 8 byte signed value
+ value = (int32_t)addressSpace.get64(p);
+ p += 8;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_constu:
+ // push immediate ULEB128 value
+ value = addressSpace.getULEB128(p, expressionEnd);
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_consts:
+ // push immediate SLEB128 value
+ svalue = addressSpace.getSLEB128(p, expressionEnd);
+ *(++sp) = svalue;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_dup:
+ // push top of stack
+ value = *sp;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "duplicate top of stack\n");
+ break;
+
+ case DW_OP_drop:
+ // pop
+ --sp;
+ if (log) fprintf(stderr, "pop top of stack\n");
+ break;
+
+ case DW_OP_over:
+ // dup second
+ value = sp[-1];
+ *(++sp) = value;
+ if (log) fprintf(stderr, "duplicate second in stack\n");
+ break;
+
+ case DW_OP_pick:
+ // pick from
+ reg = addressSpace.get8(p);
+ p += 1;
+ value = sp[-reg];
+ *(++sp) = value;
+ if (log) fprintf(stderr, "duplicate %d in stack\n", reg);
+ break;
+
+ case DW_OP_swap:
+ // swap top two
+ value = sp[0];
+ sp[0] = sp[-1];
+ sp[-1] = value;
+ if (log) fprintf(stderr, "swap top of stack\n");
+ break;
+
+ case DW_OP_rot:
+ // rotate top three
+ value = sp[0];
+ sp[0] = sp[-1];
+ sp[-1] = sp[-2];
+ sp[-2] = value;
+ if (log) fprintf(stderr, "rotate top three of stack\n");
+ break;
+
+ case DW_OP_xderef:
+ // pop stack, dereference, push result
+ value = *sp--;
+ *sp = *((uint64_t*)value);
+ if (log) fprintf(stderr, "x-dereference 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_abs:
+ svalue = *sp;
+ if ( svalue < 0 )
+ *sp = -svalue;
+ if (log) fprintf(stderr, "abs\n");
+ break;
+
+ case DW_OP_and:
+ value = *sp--;
+ *sp &= value;
+ if (log) fprintf(stderr, "and\n");
+ break;
+
+ case DW_OP_div:
+ svalue = *sp--;
+ *sp = *sp / svalue;
+ if (log) fprintf(stderr, "div\n");
+ break;
+
+ case DW_OP_minus:
+ svalue = *sp--;
+ *sp = *sp - svalue;
+ if (log) fprintf(stderr, "minus\n");
+ break;
+
+ case DW_OP_mod:
+ svalue = *sp--;
+ *sp = *sp % svalue;
+ if (log) fprintf(stderr, "module\n");
+ break;
+
+ case DW_OP_mul:
+ svalue = *sp--;
+ *sp = *sp * svalue;
+ if (log) fprintf(stderr, "mul\n");
+ break;
+
+ case DW_OP_neg:
+ *sp = 0 - *sp;
+ if (log) fprintf(stderr, "neg\n");
+ break;
+
+ case DW_OP_not:
+ svalue = *sp;
+ *sp = ~svalue;
+ if (log) fprintf(stderr, "not\n");
+ break;
+
+ case DW_OP_or:
+ value = *sp--;
+ *sp |= value;
+ if (log) fprintf(stderr, "or\n");
+ break;
+
+ case DW_OP_plus:
+ value = *sp--;
+ *sp += value;
+ if (log) fprintf(stderr, "plus\n");
+ break;
+
+ case DW_OP_plus_uconst:
+ // pop stack, add uelb128 constant, push result
+ *sp += addressSpace.getULEB128(p, expressionEnd);
+ if (log) fprintf(stderr, "add constant\n");
+ break;
+
+ case DW_OP_shl:
+ value = *sp--;
+ *sp = *sp << value;
+ if (log) fprintf(stderr, "shift left\n");
+ break;
+
+ case DW_OP_shr:
+ value = *sp--;
+ *sp = *sp >> value;
+ if (log) fprintf(stderr, "shift left\n");
+ break;
+
+ case DW_OP_shra:
+ value = *sp--;
+ svalue = *sp;
+ *sp = svalue >> value;
+ if (log) fprintf(stderr, "shift left arithmetric\n");
+ break;
+
+ case DW_OP_xor:
+ value = *sp--;
+ *sp ^= value;
+ if (log) fprintf(stderr, "xor\n");
+ break;
+
+ case DW_OP_skip:
+ svalue = (int16_t)addressSpace.get16(p);
+ p += 2;
+ p += svalue;
+ if (log) fprintf(stderr, "skip %lld\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_bra:
+ svalue = (int16_t)addressSpace.get16(p);
+ p += 2;
+ if ( *sp-- )
+ p += svalue;
+ if (log) fprintf(stderr, "bra %lld\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_eq:
+ value = *sp--;
+ *sp = (*sp == value);
+ if (log) fprintf(stderr, "eq\n");
+ break;
+
+ case DW_OP_ge:
+ value = *sp--;
+ *sp = (*sp >= value);
+ if (log) fprintf(stderr, "ge\n");
+ break;
+
+ case DW_OP_gt:
+ value = *sp--;
+ *sp = (*sp > value);
+ if (log) fprintf(stderr, "gt\n");
+ break;
+
+ case DW_OP_le:
+ value = *sp--;
+ *sp = (*sp <= value);
+ if (log) fprintf(stderr, "le\n");
+ break;
+
+ case DW_OP_lt:
+ value = *sp--;
+ *sp = (*sp < value);
+ if (log) fprintf(stderr, "lt\n");
+ break;
+
+ case DW_OP_ne:
+ value = *sp--;
+ *sp = (*sp != value);
+ if (log) fprintf(stderr, "ne\n");
+ break;
+
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ value = opcode - DW_OP_lit0;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push literal 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ reg = opcode - DW_OP_reg0;
+ *(++sp) = registers.getRegister(reg);
+ if (log) fprintf(stderr, "push reg %d\n", reg);
+ break;
+
+ case DW_OP_regx:
+ reg = addressSpace.getULEB128(p, expressionEnd);
+ *(++sp) = registers.getRegister(reg);
+ if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue);
+ break;
+
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ reg = opcode - DW_OP_breg0;
+ svalue = addressSpace.getSLEB128(p, expressionEnd);
+ *(++sp) = registers.getRegister(reg) + svalue;
+ if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue);
+ break;
+
+ case DW_OP_bregx:
+ reg = addressSpace.getULEB128(p, expressionEnd);
+ svalue = addressSpace.getSLEB128(p, expressionEnd);
+ *(++sp) = registers.getRegister(reg) + svalue;
+ if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue);
+ break;
+
+ case DW_OP_fbreg:
+ ABORT("DW_OP_fbreg not implemented");
+ break;
+
+ case DW_OP_piece:
+ ABORT("DW_OP_piece not implemented");
+ break;
+
+ case DW_OP_deref_size:
+ // pop stack, dereference, push result
+ value = *sp--;
+ switch ( addressSpace.get8(p++) ) {
+ case 1:
+ value = addressSpace.get8(value);
+ break;
+ case 2:
+ value = addressSpace.get16(value);
+ break;
+ case 4:
+ value = addressSpace.get32(value);
+ break;
+ case 8:
+ value = addressSpace.get64(value);
+ break;
+ default:
+ ABORT("DW_OP_deref_size with bad size");
+ }
+ *(++sp) = value;
+ if (log) fprintf(stderr, "sized dereference 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_xderef_size:
+ case DW_OP_nop:
+ case DW_OP_push_object_addres:
+ case DW_OP_call2:
+ case DW_OP_call4:
+ case DW_OP_call_ref:
+ default:
+ ABORT("dwarf opcode not implemented");
+ }
+
+ }
+ if (log) fprintf(stderr, "expression evaluates to 0x%llX\n", (uint64_t)*sp);
+ return *sp;
+}
+
+
+
+//
+// x86_64 specific functions
+//
+
+template <typename A, typename R>
+int DwarfInstructions<A,R>::lastRestoreReg(const Registers_x86_64&)
+{
+ COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)DW_X86_64_RET_ADDR );
+ return DW_X86_64_RET_ADDR;
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_x86_64&)
+{
+ return (regNum == DW_X86_64_RET_ADDR);
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog,
+ const Registers_x86_64& registers)
+{
+ if ( prolog.cfaRegister != 0 )
+ return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+ else if ( prolog.cfaExpression != 0 )
+ return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0);
+ else
+ ABORT("getCFA(): unknown location for x86_64 cfa");
+}
+
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_x86_64&)
+{
+ return UNWIND_X86_64_MODE_DWARF;
+}
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_x86&)
+{
+ return UNWIND_X86_MODE_DWARF;
+}
+
+
+
+template <typename A, typename R>
+uint32_t DwarfInstructions<A,R>::getRBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure)
+{
+ if ( (regOffsetFromBaseOffset < 0) || (regOffsetFromBaseOffset > 32) ) {
+ failure = true;
+ return 0;
+ }
+ unsigned int slotIndex = regOffsetFromBaseOffset/8;
+
+ switch ( reg ) {
+ case UNW_X86_64_RBX:
+ return UNWIND_X86_64_REG_RBX << (slotIndex*3);
+ case UNW_X86_64_R12:
+ return UNWIND_X86_64_REG_R12 << (slotIndex*3);
+ case UNW_X86_64_R13:
+ return UNWIND_X86_64_REG_R13 << (slotIndex*3);
+ case UNW_X86_64_R14:
+ return UNWIND_X86_64_REG_R14 << (slotIndex*3);
+ case UNW_X86_64_R15:
+ return UNWIND_X86_64_REG_R15 << (slotIndex*3);
+ }
+
+ // invalid register
+ failure = true;
+ return 0;
+}
+
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_x86_64& r, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024])
+{
+ warningBuffer[0] = '\0';
+
+ if ( prolog.registerSavedTwiceInCIE == DW_X86_64_RET_ADDR ) {
+ warningBuffer[0] = '\0'; // silently disable conversion to compact unwind by linker
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ // don't create compact unwind info for unsupported dwarf kinds
+ if ( prolog.registerSavedMoreThanOnce ) {
+ strcpy(warningBuffer, "register saved more than once (might be shrink wrap)");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ if ( prolog.cfaOffsetWasNegative ) {
+ strcpy(warningBuffer, "cfa had negative offset (dwarf might contain epilog)");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ if ( prolog.spExtraArgSize != 0 ) {
+ strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ if ( prolog.sameValueUsed ) {
+ strcpy(warningBuffer, "dwarf uses DW_CFA_same_value");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+
+ // figure out which kind of frame this function uses
+ bool standardRBPframe = (
+ (prolog.cfaRegister == UNW_X86_64_RBP)
+ && (prolog.cfaRegisterOffset == 16)
+ && (prolog.savedRegisters[UNW_X86_64_RBP].location == CFI_Parser<A>::kRegisterInCFA)
+ && (prolog.savedRegisters[UNW_X86_64_RBP].value == -16) );
+ bool standardRSPframe = (prolog.cfaRegister == UNW_X86_64_RSP);
+ if ( !standardRBPframe && !standardRSPframe ) {
+ // no compact encoding for this
+ strcpy(warningBuffer, "does not use RBP or RSP based frame");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+
+ // scan which registers are saved
+ int saveRegisterCount = 0;
+ bool rbxSaved = false;
+ bool r12Saved = false;
+ bool r13Saved = false;
+ bool r14Saved = false;
+ bool r15Saved = false;
+ bool rbpSaved = false;
+ for (int i=0; i < 64; ++i) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
+ sprintf(warningBuffer, "register %d saved somewhere other that in frame", i);
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ switch (i) {
+ case UNW_X86_64_RBX:
+ rbxSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_64_R12:
+ r12Saved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_64_R13:
+ r13Saved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_64_R14:
+ r14Saved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_64_R15:
+ r15Saved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_64_RBP:
+ rbpSaved = true;
+ ++saveRegisterCount;
+ break;
+ case DW_X86_64_RET_ADDR:
+ break;
+ default:
+ sprintf(warningBuffer, "non-standard register %d being saved in prolog", i);
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ }
+ }
+ const int64_t cfaOffsetRBX = prolog.savedRegisters[UNW_X86_64_RBX].value;
+ const int64_t cfaOffsetR12 = prolog.savedRegisters[UNW_X86_64_R12].value;
+ const int64_t cfaOffsetR13 = prolog.savedRegisters[UNW_X86_64_R13].value;
+ const int64_t cfaOffsetR14 = prolog.savedRegisters[UNW_X86_64_R14].value;
+ const int64_t cfaOffsetR15 = prolog.savedRegisters[UNW_X86_64_R15].value;
+ const int64_t cfaOffsetRBP = prolog.savedRegisters[UNW_X86_64_RBP].value;
+
+ // encode standard RBP frames
+ compact_unwind_encoding_t encoding = 0;
+ if ( standardRBPframe ) {
+ // | |
+ // +--------------+ <- CFA
+ // | ret addr |
+ // +--------------+
+ // | rbp |
+ // +--------------+ <- rbp
+ // ~ ~
+ // +--------------+
+ // | saved reg3 |
+ // +--------------+ <- CFA - offset+16
+ // | saved reg2 |
+ // +--------------+ <- CFA - offset+8
+ // | saved reg1 |
+ // +--------------+ <- CFA - offset
+ // | |
+ // +--------------+
+ // | |
+ // <- rsp
+ //
+ encoding = UNWIND_X86_64_MODE_RBP_FRAME;
+
+ // find save location of farthest register from rbp
+ int furthestCfaOffset = 0;
+ if ( rbxSaved & (cfaOffsetRBX < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetRBX;
+ if ( r12Saved & (cfaOffsetR12 < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetR12;
+ if ( r13Saved & (cfaOffsetR13 < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetR13;
+ if ( r14Saved & (cfaOffsetR14 < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetR14;
+ if ( r15Saved & (cfaOffsetR15 < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetR15;
+
+ if ( furthestCfaOffset == 0 ) {
+ // no registers saved, nothing more to encode
+ return encoding;
+ }
+
+ // add stack offset to encoding
+ int rbpOffset = furthestCfaOffset + 16;
+ int encodedOffset = rbpOffset/(-8);
+ if ( encodedOffset > 255 ) {
+ strcpy(warningBuffer, "offset of saved registers too far to encode");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ encoding |= (encodedOffset << __builtin_ctz(UNWIND_X86_64_RBP_FRAME_OFFSET));
+
+ // add register saved from each stack location
+ bool encodingFailure = false;
+ if ( rbxSaved )
+ encoding |= getRBPEncodedRegister(UNW_X86_64_RBX, cfaOffsetRBX - furthestCfaOffset, encodingFailure);
+ if ( r12Saved )
+ encoding |= getRBPEncodedRegister(UNW_X86_64_R12, cfaOffsetR12 - furthestCfaOffset, encodingFailure);
+ if ( r13Saved )
+ encoding |= getRBPEncodedRegister(UNW_X86_64_R13, cfaOffsetR13 - furthestCfaOffset, encodingFailure);
+ if ( r14Saved )
+ encoding |= getRBPEncodedRegister(UNW_X86_64_R14, cfaOffsetR14 - furthestCfaOffset, encodingFailure);
+ if ( r15Saved )
+ encoding |= getRBPEncodedRegister(UNW_X86_64_R15, cfaOffsetR15 - furthestCfaOffset, encodingFailure);
+
+ if ( encodingFailure ){
+ strcpy(warningBuffer, "saved registers not contiguous");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+
+ return encoding;
+ }
+ else {
+ // | |
+ // +--------------+ <- CFA
+ // | ret addr |
+ // +--------------+
+ // | saved reg1 |
+ // +--------------+ <- CFA - 16
+ // | saved reg2 |
+ // +--------------+ <- CFA - 24
+ // | saved reg3 |
+ // +--------------+ <- CFA - 32
+ // | saved reg4 |
+ // +--------------+ <- CFA - 40
+ // | saved reg5 |
+ // +--------------+ <- CFA - 48
+ // | saved reg6 |
+ // +--------------+ <- CFA - 56
+ // | |
+ // <- esp
+ //
+
+ // for RSP based frames we need to encode stack size in unwind info
+ encoding = UNWIND_X86_64_MODE_STACK_IMMD;
+ uint64_t stackValue = prolog.cfaRegisterOffset / 8;
+ uint32_t stackAdjust = 0;
+ bool immedStackSize = true;
+ const uint32_t stackMaxImmedValue = EXTRACT_BITS(0xFFFFFFFF,UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+ if ( stackValue > stackMaxImmedValue ) {
+ // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function
+ if ( prolog.codeOffsetAtStackDecrement == 0 ) {
+ strcpy(warningBuffer, "stack size is large but stack subq instruction not found");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;
+ try {
+ uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
+ stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/8;
+ }
+ catch (...) {
+ strcpy(warningBuffer, "stack size is large but stack subq instruction not found");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ stackValue = functionContentAdjustStackIns - funcAddr;
+ immedStackSize = false;
+ if ( stackAdjust > 7 ) {
+ strcpy(warningBuffer, "stack subq instruction is too different from dwarf stack size");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ encoding = UNWIND_X86_64_MODE_STACK_IND;
+ }
+
+
+ // validate that saved registers are all within 6 slots abutting return address
+ int registers[6];
+ for (int i=0; i < 6;++i)
+ registers[i] = 0;
+ if ( r15Saved ) {
+ if ( cfaOffsetR15 < -56 ) {
+ strcpy(warningBuffer, "r15 is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetR15+56)/8] = UNWIND_X86_64_REG_R15;
+ }
+ if ( r14Saved ) {
+ if ( cfaOffsetR14 < -56 ) {
+ strcpy(warningBuffer, "r14 is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetR14+56)/8] = UNWIND_X86_64_REG_R14;
+ }
+ if ( r13Saved ) {
+ if ( cfaOffsetR13 < -56 ) {
+ strcpy(warningBuffer, "r13 is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetR13+56)/8] = UNWIND_X86_64_REG_R13;
+ }
+ if ( r12Saved ) {
+ if ( cfaOffsetR12 < -56 ) {
+ strcpy(warningBuffer, "r12 is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetR12+56)/8] = UNWIND_X86_64_REG_R12;
+ }
+ if ( rbxSaved ) {
+ if ( cfaOffsetRBX < -56 ) {
+ strcpy(warningBuffer, "rbx is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetRBX+56)/8] = UNWIND_X86_64_REG_RBX;
+ }
+ if ( rbpSaved ) {
+ if ( cfaOffsetRBP < -56 ) {
+ strcpy(warningBuffer, "rbp is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetRBP+56)/8] = UNWIND_X86_64_REG_RBP;
+ }
+
+ // validate that saved registers are contiguous and abut return address on stack
+ for (int i=0; i < saveRegisterCount; ++i) {
+ if ( registers[5-i] == 0 ) {
+ strcpy(warningBuffer, "registers not save contiguously in stack");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ }
+
+ // encode register permutation
+ // the 10-bits are encoded differently depending on the number of registers saved
+ int renumregs[6];
+ for (int i=6-saveRegisterCount; i < 6; ++i) {
+ int countless = 0;
+ for (int j=6-saveRegisterCount; j < i; ++j) {
+ if ( registers[j] < registers[i] )
+ ++countless;
+ }
+ renumregs[i] = registers[i] - countless -1;
+ }
+ uint32_t permutationEncoding = 0;
+ switch ( saveRegisterCount ) {
+ case 6:
+ permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] + 6*renumregs[2] + 2*renumregs[3] + renumregs[4]);
+ break;
+ case 5:
+ permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] + 6*renumregs[3] + 2*renumregs[4] + renumregs[5]);
+ break;
+ case 4:
+ permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] + 3*renumregs[4] + renumregs[5]);
+ break;
+ case 3:
+ permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] + renumregs[5]);
+ break;
+ case 2:
+ permutationEncoding |= (5*renumregs[4] + renumregs[5]);
+ break;
+ case 1:
+ permutationEncoding |= (renumregs[5]);
+ break;
+ }
+
+ encoding |= (stackValue << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_SIZE));
+ encoding |= (stackAdjust << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_ADJUST));
+ encoding |= (saveRegisterCount << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT));
+ encoding |= (permutationEncoding << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION));
+ return encoding;
+ }
+}
+
+
+
+
+//
+// x86 specific functions
+//
+template <typename A, typename R>
+int DwarfInstructions<A,R>::lastRestoreReg(const Registers_x86&)
+{
+ COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)DW_X86_RET_ADDR );
+ return DW_X86_RET_ADDR;
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_x86&)
+{
+ return (regNum == DW_X86_RET_ADDR);
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog,
+ const Registers_x86& registers)
+{
+ if ( prolog.cfaRegister != 0 )
+ return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+ else if ( prolog.cfaExpression != 0 )
+ return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0);
+ else
+ ABORT("getCFA(): unknown location for x86 cfa");
+}
+
+
+
+
+
+template <typename A, typename R>
+uint32_t DwarfInstructions<A,R>::getEBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure)
+{
+ if ( (regOffsetFromBaseOffset < 0) || (regOffsetFromBaseOffset > 16) ) {
+ failure = true;
+ return 0;
+ }
+ unsigned int slotIndex = regOffsetFromBaseOffset/4;
+
+ switch ( reg ) {
+ case UNW_X86_EBX:
+ return UNWIND_X86_REG_EBX << (slotIndex*3);
+ case UNW_X86_ECX:
+ return UNWIND_X86_REG_ECX << (slotIndex*3);
+ case UNW_X86_EDX:
+ return UNWIND_X86_REG_EDX << (slotIndex*3);
+ case UNW_X86_EDI:
+ return UNWIND_X86_REG_EDI << (slotIndex*3);
+ case UNW_X86_ESI:
+ return UNWIND_X86_REG_ESI << (slotIndex*3);
+ }
+
+ // invalid register
+ failure = true;
+ return 0;
+}
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_x86& r, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024])
+{
+ warningBuffer[0] = '\0';
+
+ if ( prolog.registerSavedTwiceInCIE == DW_X86_RET_ADDR ) {
+ warningBuffer[0] = '\0'; // silently disable conversion to compact unwind by linker
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ // don't create compact unwind info for unsupported dwarf kinds
+ if ( prolog.registerSavedMoreThanOnce ) {
+ strcpy(warningBuffer, "register saved more than once (might be shrink wrap)");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ if ( prolog.spExtraArgSize != 0 ) {
+ strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ if ( prolog.sameValueUsed ) {
+ strcpy(warningBuffer, "dwarf uses DW_CFA_same_value");
+ return UNWIND_X86_MODE_DWARF;
+ }
+
+ // figure out which kind of frame this function uses
+ bool standardEBPframe = (
+ (prolog.cfaRegister == UNW_X86_EBP)
+ && (prolog.cfaRegisterOffset == 8)
+ && (prolog.savedRegisters[UNW_X86_EBP].location == CFI_Parser<A>::kRegisterInCFA)
+ && (prolog.savedRegisters[UNW_X86_EBP].value == -8) );
+ bool standardESPframe = (prolog.cfaRegister == UNW_X86_ESP);
+ if ( !standardEBPframe && !standardESPframe ) {
+ // no compact encoding for this
+ strcpy(warningBuffer, "does not use EBP or ESP based frame");
+ return UNWIND_X86_MODE_DWARF;
+ }
+
+ // scan which registers are saved
+ int saveRegisterCount = 0;
+ bool ebxSaved = false;
+ bool ecxSaved = false;
+ bool edxSaved = false;
+ bool esiSaved = false;
+ bool ediSaved = false;
+ bool ebpSaved = false;
+ for (int i=0; i < 64; ++i) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
+ sprintf(warningBuffer, "register %d saved somewhere other that in frame", i);
+ return UNWIND_X86_MODE_DWARF;
+ }
+ switch (i) {
+ case UNW_X86_EBX:
+ ebxSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_ECX:
+ ecxSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_EDX:
+ edxSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_ESI:
+ esiSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_EDI:
+ ediSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_EBP:
+ ebpSaved = true;
+ ++saveRegisterCount;
+ break;
+ case DW_X86_RET_ADDR:
+ break;
+ default:
+ sprintf(warningBuffer, "non-standard register %d being saved in prolog", i);
+ return UNWIND_X86_MODE_DWARF;
+ }
+ }
+ }
+ const int32_t cfaOffsetEBX = prolog.savedRegisters[UNW_X86_EBX].value;
+ const int32_t cfaOffsetECX = prolog.savedRegisters[UNW_X86_ECX].value;
+ const int32_t cfaOffsetEDX = prolog.savedRegisters[UNW_X86_EDX].value;
+ const int32_t cfaOffsetEDI = prolog.savedRegisters[UNW_X86_EDI].value;
+ const int32_t cfaOffsetESI = prolog.savedRegisters[UNW_X86_ESI].value;
+ const int32_t cfaOffsetEBP = prolog.savedRegisters[UNW_X86_EBP].value;
+
+ // encode standard RBP frames
+ compact_unwind_encoding_t encoding = 0;
+ if ( standardEBPframe ) {
+ // | |
+ // +--------------+ <- CFA
+ // | ret addr |
+ // +--------------+
+ // | ebp |
+ // +--------------+ <- ebp
+ // ~ ~
+ // +--------------+
+ // | saved reg3 |
+ // +--------------+ <- CFA - offset+8
+ // | saved reg2 |
+ // +--------------+ <- CFA - offset+e
+ // | saved reg1 |
+ // +--------------+ <- CFA - offset
+ // | |
+ // +--------------+
+ // | |
+ // <- esp
+ //
+ encoding = UNWIND_X86_MODE_EBP_FRAME;
+
+ // find save location of farthest register from ebp
+ int furthestCfaOffset = 0;
+ if ( ebxSaved & (cfaOffsetEBX < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetEBX;
+ if ( ecxSaved & (cfaOffsetECX < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetECX;
+ if ( edxSaved & (cfaOffsetEDX < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetEDX;
+ if ( ediSaved & (cfaOffsetEDI < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetEDI;
+ if ( esiSaved & (cfaOffsetESI < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetESI;
+
+ if ( furthestCfaOffset == 0 ) {
+ // no registers saved, nothing more to encode
+ return encoding;
+ }
+
+ // add stack offset to encoding
+ int ebpOffset = furthestCfaOffset + 8;
+ int encodedOffset = ebpOffset/(-4);
+ if ( encodedOffset > 255 ) {
+ strcpy(warningBuffer, "offset of saved registers too far to encode");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ encoding |= (encodedOffset << __builtin_ctz(UNWIND_X86_EBP_FRAME_OFFSET));
+
+ // add register saved from each stack location
+ bool encodingFailure = false;
+ if ( ebxSaved )
+ encoding |= getEBPEncodedRegister(UNW_X86_EBX, cfaOffsetEBX - furthestCfaOffset, encodingFailure);
+ if ( ecxSaved )
+ encoding |= getEBPEncodedRegister(UNW_X86_ECX, cfaOffsetECX - furthestCfaOffset, encodingFailure);
+ if ( edxSaved )
+ encoding |= getEBPEncodedRegister(UNW_X86_EDX, cfaOffsetEDX - furthestCfaOffset, encodingFailure);
+ if ( ediSaved )
+ encoding |= getEBPEncodedRegister(UNW_X86_EDI, cfaOffsetEDI - furthestCfaOffset, encodingFailure);
+ if ( esiSaved )
+ encoding |= getEBPEncodedRegister(UNW_X86_ESI, cfaOffsetESI - furthestCfaOffset, encodingFailure);
+
+ if ( encodingFailure ){
+ strcpy(warningBuffer, "saved registers not contiguous");
+ return UNWIND_X86_MODE_DWARF;
+ }
+
+ return encoding;
+ }
+ else {
+ // | |
+ // +--------------+ <- CFA
+ // | ret addr |
+ // +--------------+
+ // | saved reg1 |
+ // +--------------+ <- CFA - 8
+ // | saved reg2 |
+ // +--------------+ <- CFA - 12
+ // | saved reg3 |
+ // +--------------+ <- CFA - 16
+ // | saved reg4 |
+ // +--------------+ <- CFA - 20
+ // | saved reg5 |
+ // +--------------+ <- CFA - 24
+ // | saved reg6 |
+ // +--------------+ <- CFA - 28
+ // | |
+ // <- esp
+ //
+
+ // for ESP based frames we need to encode stack size in unwind info
+ encoding = UNWIND_X86_MODE_STACK_IMMD;
+ uint64_t stackValue = prolog.cfaRegisterOffset / 4;
+ uint32_t stackAdjust = 0;
+ bool immedStackSize = true;
+ const uint32_t stackMaxImmedValue = EXTRACT_BITS(0xFFFFFFFF,UNWIND_X86_FRAMELESS_STACK_SIZE);
+ if ( stackValue > stackMaxImmedValue ) {
+ // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function
+ pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;
+ uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
+ stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/4;
+ stackValue = functionContentAdjustStackIns - funcAddr;
+ immedStackSize = false;
+ if ( stackAdjust > 7 ) {
+ strcpy(warningBuffer, "stack subq instruction is too different from dwarf stack size");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ encoding = UNWIND_X86_MODE_STACK_IND;
+ }
+
+
+ // validate that saved registers are all within 6 slots abutting return address
+ int registers[6];
+ for (int i=0; i < 6;++i)
+ registers[i] = 0;
+ if ( ebxSaved ) {
+ if ( cfaOffsetEBX < -28 ) {
+ strcpy(warningBuffer, "ebx is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetEBX+28)/4] = UNWIND_X86_REG_EBX;
+ }
+ if ( ecxSaved ) {
+ if ( cfaOffsetECX < -28 ) {
+ strcpy(warningBuffer, "ecx is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetECX+28)/4] = UNWIND_X86_REG_ECX;
+ }
+ if ( edxSaved ) {
+ if ( cfaOffsetEDX < -28 ) {
+ strcpy(warningBuffer, "edx is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetEDX+28)/4] = UNWIND_X86_REG_EDX;
+ }
+ if ( ediSaved ) {
+ if ( cfaOffsetEDI < -28 ) {
+ strcpy(warningBuffer, "edi is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetEDI+28)/4] = UNWIND_X86_REG_EDI;
+ }
+ if ( esiSaved ) {
+ if ( cfaOffsetESI < -28 ) {
+ strcpy(warningBuffer, "esi is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetESI+28)/4] = UNWIND_X86_REG_ESI;
+ }
+ if ( ebpSaved ) {
+ if ( cfaOffsetEBP < -28 ) {
+ strcpy(warningBuffer, "ebp is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetEBP+28)/4] = UNWIND_X86_REG_EBP;
+ }
+
+ // validate that saved registers are contiguous and abut return address on stack
+ for (int i=0; i < saveRegisterCount; ++i) {
+ if ( registers[5-i] == 0 ) {
+ strcpy(warningBuffer, "registers not save contiguously in stack");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ }
+
+ // encode register permutation
+ // the 10-bits are encoded differently depending on the number of registers saved
+ int renumregs[6];
+ for (int i=6-saveRegisterCount; i < 6; ++i) {
+ int countless = 0;
+ for (int j=6-saveRegisterCount; j < i; ++j) {
+ if ( registers[j] < registers[i] )
+ ++countless;
+ }
+ renumregs[i] = registers[i] - countless -1;
+ }
+ uint32_t permutationEncoding = 0;
+ switch ( saveRegisterCount ) {
+ case 6:
+ permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] + 6*renumregs[2] + 2*renumregs[3] + renumregs[4]);
+ break;
+ case 5:
+ permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] + 6*renumregs[3] + 2*renumregs[4] + renumregs[5]);
+ break;
+ case 4:
+ permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] + 3*renumregs[4] + renumregs[5]);
+ break;
+ case 3:
+ permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] + renumregs[5]);
+ break;
+ case 2:
+ permutationEncoding |= (5*renumregs[4] + renumregs[5]);
+ break;
+ case 1:
+ permutationEncoding |= (renumregs[5]);
+ break;
+ }
+
+ encoding |= (stackValue << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_SIZE));
+ encoding |= (stackAdjust << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_ADJUST));
+ encoding |= (saveRegisterCount << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_REG_COUNT));
+ encoding |= (permutationEncoding << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION));
+ return encoding;
+ }
+}
+
+
+
+
+
+
+
+//
+// ppc specific functions
+//
+template <typename A, typename R>
+int DwarfInstructions<A,R>::lastRestoreReg(const Registers_ppc&)
+{
+ COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)UNW_PPC_SPEFSCR );
+ return UNW_PPC_SPEFSCR;
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_ppc&)
+{
+ return (regNum == UNW_PPC_LR);
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog,
+ const Registers_ppc& registers)
+{
+ if ( prolog.cfaRegister != 0 )
+ return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+ else if ( prolog.cfaExpression != 0 )
+ return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0);
+ else
+ ABORT("getCFA(): unknown location for ppc cfa");
+}
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_ppc&)
+{
+ return UNWIND_X86_MODE_DWARF;
+}
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_ppc& r, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024])
+{
+ warningBuffer[0] = '\0';
+ return UNWIND_X86_MODE_DWARF;
+}
+
+
+
+
+} // namespace libunwind
+
+
+#endif // __DWARF_INSTRUCTIONS_HPP__
+
+
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// processor specific parsing of dwarf unwind instructions
+//
+
+#ifndef __DWARF_PARSER_HPP__
+#define __DWARF_PARSER_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <vector>
+
+#include "libunwind.h"
+#include "dwarf2.h"
+
+#include "AddressSpace.hpp"
+
+
+namespace libunwind {
+
+
+///
+/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
+/// See Dwarf Spec for details:
+/// http://www.linux-foundation.org/spec/booksets/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
+///
+template <typename A>
+class CFI_Parser
+{
+public:
+ typedef typename A::pint_t pint_t;
+
+ ///
+ /// Information encoded in a CIE (Common Information Entry)
+ ///
+ struct CIE_Info {
+ pint_t cieStart;
+ pint_t cieLength;
+ pint_t cieInstructions;
+ uint8_t pointerEncoding;
+ uint8_t lsdaEncoding;
+ uint8_t personalityEncoding;
+ uint8_t personalityOffsetInCIE;
+ pint_t personality;
+ int codeAlignFactor;
+ int dataAlignFactor;
+ bool isSignalFrame;
+ bool fdesHaveAugmentationData;
+ };
+
+ ///
+ /// Information about an FDE (Frame Description Entry)
+ ///
+ struct FDE_Info {
+ pint_t fdeStart;
+ pint_t fdeLength;
+ pint_t fdeInstructions;
+ pint_t pcStart;
+ pint_t pcEnd;
+ pint_t lsda;
+ };
+
+ ///
+ /// Used by linker when parsing __eh_frame section
+ ///
+ struct FDE_Reference {
+ pint_t address;
+ uint32_t offsetInFDE;
+ uint8_t encodingOfAddress;
+ };
+ struct FDE_Atom_Info {
+ pint_t fdeAddress;
+ FDE_Reference function;
+ FDE_Reference cie;
+ FDE_Reference lsda;
+ };
+ struct CIE_Atom_Info {
+ pint_t cieAddress;
+ FDE_Reference personality;
+ };
+
+
+ ///
+ /// Information about a frame layout and registers saved determined
+ /// by "running" the dwarf FDE "instructions"
+ ///
+ enum { kMaxRegisterNumber = 120 };
+ enum RegisterSavedWhere { kRegisterUnused, kRegisterInCFA, kRegisterOffsetFromCFA,
+ kRegisterInRegister, kRegisterAtExpression, kRegisterIsExpression } ;
+ struct RegisterLocation {
+ RegisterSavedWhere location;
+ int64_t value;
+ };
+ struct PrologInfo {
+ uint32_t cfaRegister;
+ int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
+ int64_t cfaExpression; // CFA = expression
+ uint32_t spExtraArgSize;
+ uint32_t codeOffsetAtStackDecrement;
+ uint8_t registerSavedTwiceInCIE;
+ bool registersInOtherRegisters;
+ bool registerSavedMoreThanOnce;
+ bool cfaOffsetWasNegative;
+ bool sameValueUsed;
+ RegisterLocation savedRegisters[kMaxRegisterNumber]; // from where to restore registers
+ };
+
+ struct PrologInfoStackEntry {
+ PrologInfoStackEntry(PrologInfoStackEntry* n, const PrologInfo& i)
+ : next(n), info(i) {}
+ PrologInfoStackEntry* next;
+ PrologInfo info;
+ };
+
+ static bool findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo);
+ static const char* decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo);
+ static bool parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results);
+ static const char* getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
+ std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies);
+ static uint32_t getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength);
+
+ static const char* parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo);
+
+private:
+ static bool parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo,
+ pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results);
+};
+
+
+///
+/// Parse a FDE into a CIE_Info and an FDE_Info
+///
+template <typename A>
+const char* CFI_Parser<A>::decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo)
+{
+ pint_t p = fdeStart;
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return "FDE has zero length"; // end marker
+ uint32_t ciePointer = addressSpace.get32(p);
+ if ( ciePointer == 0 )
+ return "FDE is really a CIE"; // this is a CIE not an FDE
+ pint_t nextCFI = p + cfiLength;
+ pint_t cieStart = p-ciePointer;
+ const char* err = parseCIE(addressSpace, cieStart, cieInfo);
+ if (err != NULL)
+ return err;
+ p += 4;
+ // parse pc begin and range
+ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
+ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
+ // parse rest of info
+ fdeInfo->lsda = 0;
+ // check for augmentation length
+ if ( cieInfo->fdesHaveAugmentationData ) {
+ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+ pint_t endOfAug = p + augLen;
+ if ( cieInfo->lsdaEncoding != 0 ) {
+ // peek at value (without indirection). Zero means no lsda
+ pint_t lsdaStart = p;
+ if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
+ // reset pointer and re-parse lsda address
+ p = lsdaStart;
+ fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
+ }
+ }
+ p = endOfAug;
+ }
+ fdeInfo->fdeStart = fdeStart;
+ fdeInfo->fdeLength = nextCFI - fdeStart;
+ fdeInfo->fdeInstructions = p;
+ fdeInfo->pcStart = pcStart;
+ fdeInfo->pcEnd = pcStart+pcRange;
+ return NULL; // success
+}
+
+
+///
+/// Scan an eh_frame section to find an FDE for a pc
+///
+template <typename A>
+bool CFI_Parser<A>::findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo)
+{
+ //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
+ pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
+ const pint_t ehSectionEnd = p + sectionLength;
+ while ( p < ehSectionEnd ) {
+ pint_t currentCFI = p;
+ //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return false; // end marker
+ uint32_t id = addressSpace.get32(p);
+ if ( id == 0 ) {
+ // skip over CIEs
+ p += cfiLength;
+ }
+ else {
+ // process FDE to see if it covers pc
+ pint_t nextCFI = p + cfiLength;
+ uint32_t ciePointer = addressSpace.get32(p);
+ pint_t cieStart = p-ciePointer;
+ // validate pointer to CIE is within section
+ if ( (ehSectionStart <= cieStart) && (cieStart < ehSectionEnd) ) {
+ if ( parseCIE(addressSpace, cieStart, cieInfo) == NULL ) {
+ p += 4;
+ // parse pc begin and range
+ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
+ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
+ //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ // test if pc is within the function this FDE covers
+ if ( (pcStart < pc) && (pc <= pcStart+pcRange) ) {
+ // parse rest of info
+ fdeInfo->lsda = 0;
+ // check for augmentation length
+ if ( cieInfo->fdesHaveAugmentationData ) {
+ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+ pint_t endOfAug = p + augLen;
+ if ( cieInfo->lsdaEncoding != 0 ) {
+ // peek at value (without indirection). Zero means no lsda
+ pint_t lsdaStart = p;
+ if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
+ // reset pointer and re-parse lsda address
+ p = lsdaStart;
+ fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
+ }
+ }
+ p = endOfAug;
+ }
+ fdeInfo->fdeStart = currentCFI;
+ fdeInfo->fdeLength = nextCFI - currentCFI;
+ fdeInfo->fdeInstructions = p;
+ fdeInfo->pcStart = pcStart;
+ fdeInfo->pcEnd = pcStart+pcRange;
+ //fprintf(stderr, "findFDE(pc=0x%llX) found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ return true;
+ }
+ else {
+ //fprintf(stderr, "findFDE(pc=0x%llX) not found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ // pc is not in begin/range, skip this FDE
+ }
+ }
+ else {
+ // malformed CIE, now augmentation describing pc range encoding
+ //fprintf(stderr, "malformed CIE\n");
+ }
+ }
+ else {
+ // malformed FDE. CIE is bad
+ //fprintf(stderr, "malformed FDE, cieStart=0x%llX, ehSectionStart=0x%llX, ehSectionEnd=0x%llX\n",
+ // (uint64_t)cieStart, (uint64_t)ehSectionStart, (uint64_t)ehSectionEnd);
+ }
+ p = nextCFI;
+ }
+ }
+ //fprintf(stderr, "findFDE(pc=0x%llX) not found\n",(uint64_t)pc);
+ return false;
+}
+
+
+
+///
+/// Extract info from a CIE
+///
+template <typename A>
+const char* CFI_Parser<A>::parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo)
+{
+ //fprintf(stderr, "parseCIE(0x%llX)\n", (long long)cie);
+ cieInfo->pointerEncoding = 0;
+ cieInfo->lsdaEncoding = 0;
+ cieInfo->personalityEncoding = 0;
+ cieInfo->personalityOffsetInCIE = 0;
+ cieInfo->personality = 0;
+ cieInfo->codeAlignFactor = 0;
+ cieInfo->dataAlignFactor = 0;
+ cieInfo->isSignalFrame = false;
+ cieInfo->fdesHaveAugmentationData = false;
+ cieInfo->cieStart = cie;
+ pint_t p = cie;
+ uint64_t cieLength = addressSpace.get32(p);
+ p += 4;
+ pint_t cieContentEnd = p + cieLength;
+ if ( cieLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cieLength = addressSpace.get64(p);
+ p += 8;
+ cieContentEnd = p + cieLength;
+ }
+ if ( cieLength == 0 )
+ return NULL;
+ // CIE ID is always 0
+ if ( addressSpace.get32(p) != 0 )
+ return "CIE ID is not zero";
+ p += 4;
+ // Version is always 1 or 3
+ uint8_t version = addressSpace.get8(p);
+ if ( (version != 1) && (version != 3) )
+ return "CIE version is not 1 or 3";
+ ++p;
+ // save start of augmentation string and find end
+ pint_t strStart = p;
+ while ( addressSpace.get8(p) != 0 )
+ ++p;
+ ++p;
+ // parse code aligment factor
+ cieInfo->codeAlignFactor = addressSpace.getULEB128(p, cieContentEnd);
+ // parse data alignment factor
+ cieInfo->dataAlignFactor = addressSpace.getSLEB128(p, cieContentEnd);
+ // parse return address register
+ addressSpace.getULEB128(p, cieContentEnd);
+ // parse augmentation data based on augmentation string
+ const char* result = NULL;
+ if ( addressSpace.get8(strStart) == 'z' ) {
+ // parse augmentation data length
+ addressSpace.getULEB128(p, cieContentEnd);
+ for (pint_t s=strStart; addressSpace.get8(s) != '\0'; ++s) {
+ switch ( addressSpace.get8(s) ) {
+ case 'z':
+ cieInfo->fdesHaveAugmentationData = true;
+ break;
+ case 'P':
+ cieInfo->personalityEncoding = addressSpace.get8(p);
+ ++p;
+ cieInfo->personalityOffsetInCIE = p-cie;
+ cieInfo->personality = addressSpace.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
+ break;
+ case 'L':
+ cieInfo->lsdaEncoding = addressSpace.get8(p);
+ ++p;
+ break;
+ case 'R':
+ cieInfo->pointerEncoding = addressSpace.get8(p);
+ ++p;
+ break;
+ case 'S':
+ cieInfo->isSignalFrame = true;
+ break;
+ default:
+ // ignore unknown letters
+ break;
+ }
+ }
+ }
+ cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
+ cieInfo->cieInstructions = p;
+ return result;
+}
+
+
+template <typename A>
+uint32_t CFI_Parser<A>::getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength)
+{
+ uint32_t count = 0;
+ const pint_t ehSectionEnd = ehSectionStart + sectionLength;
+ for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return count; // end marker
+ ++count;
+ p += cfiLength;
+ }
+ return count;
+}
+
+
+
+template <typename A>
+const char* CFI_Parser<A>::getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
+ std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies)
+{
+ const pint_t ehSectionEnd = ehSectionStart + sectionLength;
+ for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
+ pint_t currentCFI = p;
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return NULL; // end marker
+ uint32_t id = addressSpace.get32(p);
+ if ( id == 0 ) {
+ // is CIE
+ CIE_Info cieInfo;
+ const char* err = parseCIE(addressSpace, currentCFI, &cieInfo);
+ if ( err != NULL )
+ return err;
+ CIE_Atom_Info entry;
+ entry.cieAddress = currentCFI;
+ entry.personality.address = cieInfo.personality;
+ entry.personality.offsetInFDE = cieInfo.personalityOffsetInCIE;
+ entry.personality.encodingOfAddress = cieInfo.personalityEncoding;
+ cies.push_back(entry);
+ p += cfiLength;
+ }
+ else {
+ // is FDE
+ FDE_Atom_Info entry;
+ entry.fdeAddress = currentCFI;
+ entry.function.address = 0;
+ entry.cie.address = 0;
+ entry.lsda.address = 0;
+ pint_t nextCFI = p + cfiLength;
+ uint32_t ciePointer = addressSpace.get32(p);
+ pint_t cieStart = p-ciePointer;
+ // validate pointer to CIE is within section
+ if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) )
+ return "FDE points to CIE outside __eh_frame section";
+ CIE_Info cieInfo;
+ const char* err = parseCIE(addressSpace, cieStart, &cieInfo);
+ if ( err != NULL )
+ return err;
+ entry.cie.address = cieStart;
+ entry.cie.offsetInFDE = p-currentCFI;
+ entry.cie.encodingOfAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
+ p += 4;
+ // parse pc begin and range
+ pint_t offsetOfFunctionAddress = p-currentCFI;
+ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
+ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
+ //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ // test if pc is within the function this FDE covers
+ entry.function.address = pcStart;
+ entry.function.offsetInFDE = offsetOfFunctionAddress;
+ entry.function.encodingOfAddress = cieInfo.pointerEncoding;
+ // skip over augmentation length
+ if ( cieInfo.fdesHaveAugmentationData ) {
+ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+ pint_t endOfAug = p + augLen;
+ if ( (cieInfo.lsdaEncoding != 0) && (addressSpace.getP(p) != 0) ) {
+ pint_t offsetOfLSDAAddress = p-currentCFI;
+ entry.lsda.address = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding);
+ entry.lsda.offsetInFDE = offsetOfLSDAAddress;
+ entry.lsda.encodingOfAddress = cieInfo.lsdaEncoding;
+ }
+ p = endOfAug;
+ }
+ fdes.push_back(entry);
+ p = nextCFI;
+ }
+ }
+ return NULL; // success
+}
+
+
+
+///
+/// "run" the dwarf instructions and create the abstact PrologInfo for an FDE
+///
+template <typename A>
+bool CFI_Parser<A>::parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results)
+{
+ // clear results
+ bzero(results, sizeof(PrologInfo));
+ PrologInfoStackEntry* rememberStack = NULL;
+
+ // parse CIE then FDE instructions
+ return parseInstructions(addressSpace, cieInfo.cieInstructions, cieInfo.cieStart+cieInfo.cieLength,
+ cieInfo, (pint_t)(-1), rememberStack, results)
+ && parseInstructions(addressSpace, fdeInfo.fdeInstructions, fdeInfo.fdeStart+fdeInfo.fdeLength,
+ cieInfo, upToPC-fdeInfo.pcStart, rememberStack, results);
+}
+
+
+///
+/// "run" the dwarf instructions
+///
+template <typename A>
+bool CFI_Parser<A>::parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo,
+ pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results)
+{
+ const bool logDwarf = false;
+ pint_t p = instructions;
+ uint32_t codeOffset = 0;
+ PrologInfo initialState = *results;
+ if ( logDwarf ) fprintf(stderr, "parseInstructions(instructions=0x%0llX)\n", (uint64_t)instructionsEnd);
+
+ // see Dwarf Spec, section 6.4.2 for details on unwind opcodes
+ while ( (p < instructionsEnd) && (codeOffset < pcoffset) ) {
+ uint64_t reg;
+ uint64_t reg2;
+ int64_t offset;
+ uint64_t length;
+ uint8_t opcode = addressSpace.get8(p);
+ uint8_t operand;
+ PrologInfoStackEntry* entry;
+ ++p;
+ switch (opcode) {
+ case DW_CFA_nop:
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_nop\n");
+ break;
+ case DW_CFA_set_loc:
+ codeOffset = addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_set_loc\n");
+ break;
+ case DW_CFA_advance_loc1:
+ codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
+ p += 1;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc1: new offset=%u\n", codeOffset);
+ break;
+ case DW_CFA_advance_loc2:
+ codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
+ p += 2;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc2: new offset=%u\n", codeOffset);
+ break;
+ case DW_CFA_advance_loc4:
+ codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
+ p += 4;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc4: new offset=%u\n", codeOffset);
+ break;
+ case DW_CFA_offset_extended:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n");
+ return false;
+ }
+ if ( results->savedRegisters[reg].location != kRegisterUnused )
+ results->registerSavedMoreThanOnce = true;
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended(reg=%lld, offset=%lld)\n", reg, offset);
+ break;
+ case DW_CFA_restore_extended:
+ reg = addressSpace.getULEB128(p, instructionsEnd);;
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg] = initialState.savedRegisters[reg];
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_extended(reg=%lld)\n", reg);
+ break;
+ case DW_CFA_undefined:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_undefined dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterUnused;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_undefined(reg=%lld)\n", reg);
+ break;
+ case DW_CFA_same_value:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_same_value dwarf unwind, reg too big\n");
+ return false;
+ }
+ // <rdar://problem/8456377> DW_CFA_same_value unsupported
+ // "same value" means register was stored in frame, but its current
+ // value has not changed, so no need to restore from frame.
+ // We model this as if the register was never saved.
+ results->savedRegisters[reg].location = kRegisterUnused;
+ // set flag to disable conversion to compact unwind
+ results->sameValueUsed = true;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_same_value(reg=%lld)\n", reg);
+ break;
+ case DW_CFA_register:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ reg2 = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg too big\n");
+ return false;
+ }
+ if ( reg2 > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg2 too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterInRegister;
+ results->savedRegisters[reg].value = reg2;
+ // set flag to disable conversion to compact unwind
+ results->registersInOtherRegisters = true;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_register(reg=%lld, reg2=%lld)\n", reg, reg2);
+ break;
+ case DW_CFA_remember_state:
+ // avoid operator new, because that would be an upward dependency
+ entry = (PrologInfoStackEntry*)malloc(sizeof(PrologInfoStackEntry));
+ if ( entry != NULL ) {
+ entry->next = rememberStack;
+ entry->info = *results;
+ rememberStack = entry;
+ }
+ else {
+ return false;
+ }
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_remember_state\n");
+ break;
+ case DW_CFA_restore_state:
+ if ( rememberStack != NULL ) {
+ PrologInfoStackEntry* top = rememberStack;
+ *results = top->info;
+ rememberStack = top->next;
+ free((char*)top);
+ }
+ else {
+ return false;
+ }
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_state\n");
+ break;
+ case DW_CFA_def_cfa:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->cfaRegister = reg;
+ results->cfaRegisterOffset = offset;
+ if ( offset > 0x80000000 )
+ results->cfaOffsetWasNegative = true;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa(reg=%lld, offset=%lld)\n", reg, offset);
+ break;
+ case DW_CFA_def_cfa_register:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->cfaRegister = reg;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_register(%lld)\n", reg);
+ break;
+ case DW_CFA_def_cfa_offset:
+ results->cfaRegisterOffset = addressSpace.getULEB128(p, instructionsEnd);
+ results->codeOffsetAtStackDecrement = codeOffset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", results->cfaRegisterOffset);
+ break;
+ case DW_CFA_def_cfa_expression:
+ results->cfaRegister = 0;
+ results->cfaExpression = p;
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ p += length;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%llX, length=%llu)\n",
+ results->cfaExpression, length);
+ break;
+ case DW_CFA_expression:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_expression dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterAtExpression;
+ results->savedRegisters[reg].value = p;
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ p += length;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_expression(reg=%lld, expression=0x%llX, length=%llu)\n",
+ reg, results->savedRegisters[reg].value, length);
+ break;
+ case DW_CFA_offset_extended_sf:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n");
+ return false;
+ }
+ offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if ( results->savedRegisters[reg].location != kRegisterUnused )
+ results->registerSavedMoreThanOnce = true;
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%lld, offset=%lld)\n", reg, offset);
+ break;
+ case DW_CFA_def_cfa_sf:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->cfaRegister = reg;
+ results->cfaRegisterOffset = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_sf(reg=%lld, offset=%lld)\n", reg, offset);
+ break;
+ case DW_CFA_def_cfa_offset_sf:
+ results->cfaRegisterOffset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ results->codeOffsetAtStackDecrement = codeOffset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", results->cfaRegisterOffset);
+ break;
+ case DW_CFA_val_offset:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
+ results->savedRegisters[reg].value = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset(reg=%lld, offset=%lld\n", reg, offset);
+ break;
+ case DW_CFA_val_offset_sf:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n");
+ return false;
+ }
+ offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
+ results->savedRegisters[reg].value = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset_sf(reg=%lld, offset=%lld\n", reg, offset);
+ break;
+ case DW_CFA_val_expression:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_val_expression dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterIsExpression;
+ results->savedRegisters[reg].value = p;
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ p += length;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_val_expression(reg=%lld, expression=0x%llX, length=%lld)\n",
+ reg, results->savedRegisters[reg].value, length);
+ break;
+ case DW_CFA_GNU_args_size:
+ offset = addressSpace.getULEB128(p, instructionsEnd);
+ results->spExtraArgSize = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_args_size(%lld)\n", offset);
+ break;
+ case DW_CFA_GNU_negative_offset_extended:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf unwind, reg too big\n");
+ return false;
+ }
+ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if ( results->savedRegisters[reg].location != kRegisterUnused )
+ results->registerSavedMoreThanOnce = true;
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = -offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%lld)\n", offset);
+ break;
+ default:
+ operand = opcode & 0x3F;
+ switch ( opcode & 0xC0 ) {
+ case DW_CFA_offset:
+ reg = operand;
+ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if ( results->savedRegisters[reg].location != kRegisterUnused ) {
+ // look for idiom of PC saved twice in CIE to mean disable compact unwind encoding
+ if ( (pcoffset == (pint_t)(-1))
+ && (results->savedRegisters[reg].location == kRegisterInCFA)
+ && (results->savedRegisters[reg].value == offset) )
+ results->registerSavedTwiceInCIE = reg;
+ else
+ results->registerSavedMoreThanOnce = true;
+ }
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%lld)\n", operand, offset);
+ break;
+ case DW_CFA_advance_loc:
+ codeOffset += operand * cieInfo.codeAlignFactor;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc: new offset=%u\n", codeOffset);
+ break;
+ case DW_CFA_restore:
+ // <rdar://problem/7503075> Python crashes when handling an exception thrown by an obj-c object
+ // libffi uses DW_CFA_restore in the middle of some custom dwarf, so it is not a good epilog flag
+ //return true; // gcc-4.5 starts the epilog with this
+ reg = operand;
+ results->savedRegisters[reg] = initialState.savedRegisters[reg];
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_restore(reg=%lld)\n", reg);
+ break;
+ default:
+ if ( logDwarf ) fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+} // namespace libunwind
+
+
+#endif // __DWARF_PARSER_HPP__
+
+
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+
+#ifndef INTERNAL_MACROS_H
+#define INTERNAL_MACROS_H
+
+#include <assert.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ extern void __assert_rtn(const char *, const char *, int, const char *) __attribute__((noreturn));
+#ifdef __cplusplus
+}
+#endif
+
+#define UNW_STEP_SUCCESS 1
+#define UNW_STEP_END 0
+
+
+struct v128 { unsigned int vec[4]; };
+
+
+#define EXPORT __attribute__((visibility("default")))
+
+#define COMPILE_TIME_ASSERT( expr ) \
+ extern int compile_time_assert_failed[ ( expr ) ? 1 : -1 ] __attribute__( ( unused ) );
+
+#define ABORT(msg) __assert_rtn(__func__, __FILE__, __LINE__, msg)
+
+#if NDEBUG
+ #define DEBUG_MESSAGE(msg, ...)
+ #define DEBUG_PRINT_API(msg, ...)
+ #define DEBUG_PRINT_UNWINDING_TEST 0
+ #define DEBUG_PRINT_UNWINDING(msg, ...)
+ #define DEBUG_LOG_NON_ZERO(x) x;
+ #define INITIALIZE_DEBUG_PRINT_API
+ #define INITIALIZE_DEBUG_PRINT_UNWINDING
+#else
+ #define DEBUG_MESSAGE(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__)
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ extern bool logAPIs();
+ extern bool logUnwinding();
+ #ifdef __cplusplus
+ }
+ #endif
+ #define DEBUG_LOG_NON_ZERO(x) { int _err = x; if ( _err != 0 ) fprintf(stderr, "libuwind: " #x "=%d in %s", _err, __FUNCTION__); }
+ #define DEBUG_PRINT_API(msg, ...) do { if ( logAPIs() ) fprintf(stderr, msg, __VA_ARGS__); } while(0)
+ #define DEBUG_PRINT_UNWINDING(msg, ...) do { if ( logUnwinding() ) fprintf(stderr, msg, __VA_ARGS__); } while(0)
+ #define DEBUG_PRINT_UNWINDING_TEST logUnwinding()
+ #define INITIALIZE_DEBUG_PRINT_API bool logAPIs() { static bool log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); return log; }
+ #define INITIALIZE_DEBUG_PRINT_UNWINDING bool logUnwinding() { static bool log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); return log; }
+#endif
+
+
+// note hack for <rdar://problem/6175741>
+// Once libgcc_s.dylib vectors to libSystem, then we can remove the $ld$hide$os10.6$ lines
+#if __ppc__
+ #define NOT_HERE_BEFORE_10_6(sym) \
+ extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
+ #define NEVER_HERE(sym) \
+ extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
+ extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
+#else
+ #define NOT_HERE_BEFORE_10_6(sym) \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
+ #define NEVER_HERE(sym) \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
+ extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
+#endif
+
+
+
+#endif // INTERNAL_MACROS_H
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// C++ interface to lower levels of libuwind
+//
+
+#ifndef __REGISTERS_HPP__
+#define __REGISTERS_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <mach-o/loader.h>
+#include <mach-o/getsect.h>
+#include <mach/i386/thread_status.h>
+
+#include "libunwind.h"
+#include "InternalMacros.h"
+
+namespace libunwind {
+
+
+///
+/// Registers_x86 holds the register state of a thread in a 32-bit intel process.
+///
+class Registers_x86
+{
+public:
+ Registers_x86();
+ Registers_x86(const void* registers);
+
+ bool validRegister(int num) const;
+ uint32_t getRegister(int num) const;
+ void setRegister(int num, uint32_t value);
+ bool validFloatRegister(int num) const { return false; }
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const { return false; }
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char* getRegisterName(int num);
+ void jumpto();
+
+ uint32_t getSP() const { return fRegisters.__esp; }
+ void setSP(uint32_t value) { fRegisters.__esp = value; }
+ uint32_t getIP() const { return fRegisters.__eip; }
+ void setIP(uint32_t value) { fRegisters.__eip = value; }
+ uint32_t getEBP() const { return fRegisters.__ebp; }
+ void setEBP(uint32_t value) { fRegisters.__ebp = value; }
+ uint32_t getEBX() const { return fRegisters.__ebx; }
+ void setEBX(uint32_t value) { fRegisters.__ebx = value; }
+ uint32_t getECX() const { return fRegisters.__ecx; }
+ void setECX(uint32_t value) { fRegisters.__ecx = value; }
+ uint32_t getEDX() const { return fRegisters.__edx; }
+ void setEDX(uint32_t value) { fRegisters.__edx = value; }
+ uint32_t getESI() const { return fRegisters.__esi; }
+ void setESI(uint32_t value) { fRegisters.__esi = value; }
+ uint32_t getEDI() const { return fRegisters.__edi; }
+ void setEDI(uint32_t value) { fRegisters.__edi = value; }
+
+private:
+ i386_thread_state_t fRegisters;
+};
+
+inline Registers_x86::Registers_x86(const void* registers)
+{
+ COMPILE_TIME_ASSERT( sizeof(Registers_x86) < sizeof(unw_context_t) );
+ fRegisters = *((i386_thread_state_t*)registers);
+}
+
+inline Registers_x86::Registers_x86()
+{
+ bzero(&fRegisters, sizeof(fRegisters));
+}
+
+
+inline bool Registers_x86::validRegister(int regNum) const
+{
+ if ( regNum == UNW_REG_IP )
+ return true;
+ if ( regNum == UNW_REG_SP )
+ return true;
+ if ( regNum < 0 )
+ return false;
+ if ( regNum > 7 )
+ return false;
+ return true;
+}
+
+inline uint32_t Registers_x86::getRegister(int regNum) const
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return fRegisters.__eip;
+ case UNW_REG_SP:
+ return fRegisters.__esp;
+ case UNW_X86_EAX:
+ return fRegisters.__eax;
+ case UNW_X86_ECX:
+ return fRegisters.__ecx;
+ case UNW_X86_EDX:
+ return fRegisters.__edx;
+ case UNW_X86_EBX:
+ return fRegisters.__ebx;
+ case UNW_X86_EBP:
+ return fRegisters.__ebp;
+ case UNW_X86_ESP:
+ return fRegisters.__esp;
+ case UNW_X86_ESI:
+ return fRegisters.__esi;
+ case UNW_X86_EDI:
+ return fRegisters.__edi;
+ }
+ ABORT("unsupported x86 register");
+}
+
+inline void Registers_x86::setRegister(int regNum, uint32_t value)
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ fRegisters.__eip = value;
+ return;
+ case UNW_REG_SP:
+ fRegisters.__esp = value;
+ return;
+ case UNW_X86_EAX:
+ fRegisters.__eax = value;
+ return;
+ case UNW_X86_ECX:
+ fRegisters.__ecx = value;
+ return;
+ case UNW_X86_EDX:
+ fRegisters.__edx = value;
+ return;
+ case UNW_X86_EBX:
+ fRegisters.__ebx = value;
+ return;
+ case UNW_X86_EBP:
+ fRegisters.__ebp = value;
+ return;
+ case UNW_X86_ESP:
+ fRegisters.__esp = value;
+ return;
+ case UNW_X86_ESI:
+ fRegisters.__esi = value;
+ return;
+ case UNW_X86_EDI:
+ fRegisters.__edi = value;
+ return;
+ }
+ ABORT("unsupported x86 register");
+}
+
+inline const char* Registers_x86::getRegisterName(int regNum)
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return "ip";
+ case UNW_REG_SP:
+ return "esp";
+ case UNW_X86_EAX:
+ return "eax";
+ case UNW_X86_ECX:
+ return "ecx";
+ case UNW_X86_EDX:
+ return "edx";
+ case UNW_X86_EBX:
+ return "ebx";
+ case UNW_X86_EBP:
+ return "ebp";
+ case UNW_X86_ESP:
+ return "esp";
+ case UNW_X86_ESI:
+ return "esi";
+ case UNW_X86_EDI:
+ return "edi";
+ default:
+ return "unknown register";
+ }
+}
+
+inline double Registers_x86::getFloatRegister(int num) const
+{
+ ABORT("no x86 float registers");
+}
+
+inline void Registers_x86::setFloatRegister(int num, double value)
+{
+ ABORT("no x86 float registers");
+}
+
+inline v128 Registers_x86::getVectorRegister(int num) const
+{
+ ABORT("no x86 vector registers");
+}
+
+inline void Registers_x86::setVectorRegister(int num, v128 value)
+{
+ ABORT("no x86 vector registers");
+}
+
+
+
+
+///
+/// Registers_x86_64 holds the register state of a thread in a 64-bit intel process.
+///
+class Registers_x86_64
+{
+public:
+ Registers_x86_64();
+ Registers_x86_64(const void* registers);
+
+ bool validRegister(int num) const;
+ uint64_t getRegister(int num) const;
+ void setRegister(int num, uint64_t value);
+ bool validFloatRegister(int num) const{ return false; }
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const { return false; }
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char* getRegisterName(int num);
+ void jumpto();
+ uint64_t getSP() const { return fRegisters.__rsp; }
+ void setSP(uint64_t value) { fRegisters.__rsp = value; }
+ uint64_t getIP() const { return fRegisters.__rip; }
+ void setIP(uint64_t value) { fRegisters.__rip = value; }
+ uint64_t getRBP() const { return fRegisters.__rbp; }
+ void setRBP(uint64_t value) { fRegisters.__rbp = value; }
+ uint64_t getRBX() const { return fRegisters.__rbx; }
+ void setRBX(uint64_t value) { fRegisters.__rbx = value; }
+ uint64_t getR12() const { return fRegisters.__r12; }
+ void setR12(uint64_t value) { fRegisters.__r12 = value; }
+ uint64_t getR13() const { return fRegisters.__r13; }
+ void setR13(uint64_t value) { fRegisters.__r13 = value; }
+ uint64_t getR14() const { return fRegisters.__r14; }
+ void setR14(uint64_t value) { fRegisters.__r14 = value; }
+ uint64_t getR15() const { return fRegisters.__r15; }
+ void setR15(uint64_t value) { fRegisters.__r15 = value; }
+private:
+ x86_thread_state64_t fRegisters;
+};
+
+inline Registers_x86_64::Registers_x86_64(const void* registers)
+{
+ COMPILE_TIME_ASSERT( sizeof(Registers_x86_64) < sizeof(unw_context_t) );
+ fRegisters = *((x86_thread_state64_t*)registers);
+}
+
+inline Registers_x86_64::Registers_x86_64()
+{
+ bzero(&fRegisters, sizeof(fRegisters));
+}
+
+
+inline bool Registers_x86_64::validRegister(int regNum) const
+{
+ if ( regNum == UNW_REG_IP )
+ return true;
+ if ( regNum == UNW_REG_SP )
+ return true;
+ if ( regNum < 0 )
+ return false;
+ if ( regNum > 15 )
+ return false;
+ return true;
+}
+
+inline uint64_t Registers_x86_64::getRegister(int regNum) const
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return fRegisters.__rip;
+ case UNW_REG_SP:
+ return fRegisters.__rsp;
+ case UNW_X86_64_RAX:
+ return fRegisters.__rax;
+ case UNW_X86_64_RDX:
+ return fRegisters.__rdx;
+ case UNW_X86_64_RCX:
+ return fRegisters.__rcx;
+ case UNW_X86_64_RBX:
+ return fRegisters.__rbx;
+ case UNW_X86_64_RSI:
+ return fRegisters.__rsi;
+ case UNW_X86_64_RDI:
+ return fRegisters.__rdi;
+ case UNW_X86_64_RBP:
+ return fRegisters.__rbp;
+ case UNW_X86_64_RSP:
+ return fRegisters.__rsp;
+ case UNW_X86_64_R8:
+ return fRegisters.__r8;
+ case UNW_X86_64_R9:
+ return fRegisters.__r9;
+ case UNW_X86_64_R10:
+ return fRegisters.__r10;
+ case UNW_X86_64_R11:
+ return fRegisters.__r11;
+ case UNW_X86_64_R12:
+ return fRegisters.__r12;
+ case UNW_X86_64_R13:
+ return fRegisters.__r13;
+ case UNW_X86_64_R14:
+ return fRegisters.__r14;
+ case UNW_X86_64_R15:
+ return fRegisters.__r15;
+ }
+ ABORT("unsupported x86_64 register");
+}
+
+inline void Registers_x86_64::setRegister(int regNum, uint64_t value)
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ fRegisters.__rip = value;
+ return;
+ case UNW_REG_SP:
+ fRegisters.__rsp = value;
+ return;
+ case UNW_X86_64_RAX:
+ fRegisters.__rax = value;
+ return;
+ case UNW_X86_64_RDX:
+ fRegisters.__rdx = value;
+ return;
+ case UNW_X86_64_RCX:
+ fRegisters.__rcx = value;
+ return;
+ case UNW_X86_64_RBX:
+ fRegisters.__rbx = value;
+ return;
+ case UNW_X86_64_RSI:
+ fRegisters.__rsi = value;
+ return;
+ case UNW_X86_64_RDI:
+ fRegisters.__rdi = value;
+ return;
+ case UNW_X86_64_RBP:
+ fRegisters.__rbp = value;
+ return;
+ case UNW_X86_64_RSP:
+ fRegisters.__rsp = value;
+ return;
+ case UNW_X86_64_R8:
+ fRegisters.__r8 = value;
+ return;
+ case UNW_X86_64_R9:
+ fRegisters.__r9 = value;
+ return;
+ case UNW_X86_64_R10:
+ fRegisters.__r10 = value;
+ return;
+ case UNW_X86_64_R11:
+ fRegisters.__r11 = value;
+ return;
+ case UNW_X86_64_R12:
+ fRegisters.__r12 = value;
+ return;
+ case UNW_X86_64_R13:
+ fRegisters.__r13 = value;
+ return;
+ case UNW_X86_64_R14:
+ fRegisters.__r14 = value;
+ return;
+ case UNW_X86_64_R15:
+ fRegisters.__r15 = value;
+ return;
+ }
+ ABORT("unsupported x86_64 register");
+}
+
+inline const char* Registers_x86_64::getRegisterName(int regNum)
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return "rip";
+ case UNW_REG_SP:
+ return "rsp";
+ case UNW_X86_64_RAX:
+ return "rax";
+ case UNW_X86_64_RDX:
+ return "rdx";
+ case UNW_X86_64_RCX:
+ return "rcx";
+ case UNW_X86_64_RBX:
+ return "rbx";
+ case UNW_X86_64_RSI:
+ return "rsi";
+ case UNW_X86_64_RDI:
+ return "rdi";
+ case UNW_X86_64_RBP:
+ return "rbp";
+ case UNW_X86_64_RSP:
+ return "rsp";
+ case UNW_X86_64_R8:
+ return "r8";
+ case UNW_X86_64_R9:
+ return "r9";
+ case UNW_X86_64_R10:
+ return "r10";
+ case UNW_X86_64_R11:
+ return "r11";
+ case UNW_X86_64_R12:
+ return "r12";
+ case UNW_X86_64_R13:
+ return "r13";
+ case UNW_X86_64_R14:
+ return "r14";
+ case UNW_X86_64_R15:
+ return "r15";
+ default:
+ return "unknown register";
+ }
+}
+
+double Registers_x86_64::getFloatRegister(int num) const
+{
+ ABORT("no x86_64 float registers");
+}
+
+void Registers_x86_64::setFloatRegister(int num, double value)
+{
+ ABORT("no x86_64 float registers");
+}
+
+inline v128 Registers_x86_64::getVectorRegister(int num) const
+{
+ ABORT("no x86_64 vector registers");
+}
+
+inline void Registers_x86_64::setVectorRegister(int num, v128 value)
+{
+ ABORT("no x86_64 vector registers");
+}
+
+
+///
+/// Registers_ppc holds the register state of a thread in a 32-bit PowerPC process.
+///
+class Registers_ppc
+{
+public:
+ Registers_ppc();
+ Registers_ppc(const void* registers);
+
+ bool validRegister(int num) const;
+ uint32_t getRegister(int num) const;
+ void setRegister(int num, uint32_t value);
+ bool validFloatRegister(int num) const;
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ void jumpto();
+ const char* getRegisterName(int num);
+ uint64_t getSP() const { return fRegisters.__r1; }
+ void setSP(uint64_t value) { fRegisters.__r1 = value; }
+ uint64_t getIP() const { return fRegisters.__srr0; }
+ void setIP(uint64_t value) { fRegisters.__srr0 = value; }
+private:
+ struct ppc_thread_state_t
+ {
+ unsigned int __srr0; /* Instruction address register (PC) */
+ unsigned int __srr1; /* Machine state register (supervisor) */
+ unsigned int __r0;
+ unsigned int __r1;
+ unsigned int __r2;
+ unsigned int __r3;
+ unsigned int __r4;
+ unsigned int __r5;
+ unsigned int __r6;
+ unsigned int __r7;
+ unsigned int __r8;
+ unsigned int __r9;
+ unsigned int __r10;
+ unsigned int __r11;
+ unsigned int __r12;
+ unsigned int __r13;
+ unsigned int __r14;
+ unsigned int __r15;
+ unsigned int __r16;
+ unsigned int __r17;
+ unsigned int __r18;
+ unsigned int __r19;
+ unsigned int __r20;
+ unsigned int __r21;
+ unsigned int __r22;
+ unsigned int __r23;
+ unsigned int __r24;
+ unsigned int __r25;
+ unsigned int __r26;
+ unsigned int __r27;
+ unsigned int __r28;
+ unsigned int __r29;
+ unsigned int __r30;
+ unsigned int __r31;
+ unsigned int __cr; /* Condition register */
+ unsigned int __xer; /* User's integer exception register */
+ unsigned int __lr; /* Link register */
+ unsigned int __ctr; /* Count register */
+ unsigned int __mq; /* MQ register (601 only) */
+ unsigned int __vrsave; /* Vector Save Register */
+ };
+
+ struct ppc_float_state_t
+ {
+ double __fpregs[32];
+
+ unsigned int __fpscr_pad; /* fpscr is 64 bits, 32 bits of rubbish */
+ unsigned int __fpscr; /* floating point status register */
+ };
+
+ ppc_thread_state_t fRegisters;
+ ppc_float_state_t fFloatRegisters;
+ v128 fVectorRegisters[32]; // offset 424
+};
+
+
+
+inline Registers_ppc::Registers_ppc(const void* registers)
+{
+ COMPILE_TIME_ASSERT( sizeof(Registers_ppc) < sizeof(unw_context_t) );
+ fRegisters = *((ppc_thread_state_t*)registers);
+ fFloatRegisters = *((ppc_float_state_t*)((char*)registers+160));
+ memcpy(fVectorRegisters, ((char*)registers+424), sizeof(fVectorRegisters));
+}
+
+inline Registers_ppc::Registers_ppc()
+{
+ bzero(&fRegisters, sizeof(fRegisters));
+ bzero(&fFloatRegisters, sizeof(fFloatRegisters));
+ bzero(&fVectorRegisters, sizeof(fVectorRegisters));
+}
+
+
+inline bool Registers_ppc::validRegister(int regNum) const
+{
+ if ( regNum == UNW_REG_IP )
+ return true;
+ if ( regNum == UNW_REG_SP )
+ return true;
+ if ( regNum == UNW_PPC_VRSAVE )
+ return true;
+ if ( regNum < 0 )
+ return false;
+ if ( regNum <= UNW_PPC_R31 )
+ return true;
+ if ( regNum == UNW_PPC_MQ )
+ return true;
+ if ( regNum == UNW_PPC_LR )
+ return true;
+ if ( regNum == UNW_PPC_CTR )
+ return true;
+ if ( (UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7) )
+ return true;
+ return false;
+}
+
+
+inline uint32_t Registers_ppc::getRegister(int regNum) const
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return fRegisters.__srr0;
+ case UNW_REG_SP:
+ return fRegisters.__r1;
+ case UNW_PPC_R0:
+ return fRegisters.__r0;
+ case UNW_PPC_R1:
+ return fRegisters.__r1;
+ case UNW_PPC_R2:
+ return fRegisters.__r2;
+ case UNW_PPC_R3:
+ return fRegisters.__r3;
+ case UNW_PPC_R4:
+ return fRegisters.__r4;
+ case UNW_PPC_R5:
+ return fRegisters.__r5;
+ case UNW_PPC_R6:
+ return fRegisters.__r6;
+ case UNW_PPC_R7:
+ return fRegisters.__r7;
+ case UNW_PPC_R8:
+ return fRegisters.__r8;
+ case UNW_PPC_R9:
+ return fRegisters.__r9;
+ case UNW_PPC_R10:
+ return fRegisters.__r10;
+ case UNW_PPC_R11:
+ return fRegisters.__r11;
+ case UNW_PPC_R12:
+ return fRegisters.__r12;
+ case UNW_PPC_R13:
+ return fRegisters.__r13;
+ case UNW_PPC_R14:
+ return fRegisters.__r14;
+ case UNW_PPC_R15:
+ return fRegisters.__r15;
+ case UNW_PPC_R16:
+ return fRegisters.__r16;
+ case UNW_PPC_R17:
+ return fRegisters.__r17;
+ case UNW_PPC_R18:
+ return fRegisters.__r18;
+ case UNW_PPC_R19:
+ return fRegisters.__r19;
+ case UNW_PPC_R20:
+ return fRegisters.__r20;
+ case UNW_PPC_R21:
+ return fRegisters.__r21;
+ case UNW_PPC_R22:
+ return fRegisters.__r22;
+ case UNW_PPC_R23:
+ return fRegisters.__r23;
+ case UNW_PPC_R24:
+ return fRegisters.__r24;
+ case UNW_PPC_R25:
+ return fRegisters.__r25;
+ case UNW_PPC_R26:
+ return fRegisters.__r26;
+ case UNW_PPC_R27:
+ return fRegisters.__r27;
+ case UNW_PPC_R28:
+ return fRegisters.__r28;
+ case UNW_PPC_R29:
+ return fRegisters.__r29;
+ case UNW_PPC_R30:
+ return fRegisters.__r30;
+ case UNW_PPC_R31:
+ return fRegisters.__r31;
+ case UNW_PPC_LR:
+ return fRegisters.__lr;
+ case UNW_PPC_CR0:
+ return (fRegisters.__cr & 0xF0000000);
+ case UNW_PPC_CR1:
+ return (fRegisters.__cr & 0x0F000000);
+ case UNW_PPC_CR2:
+ return (fRegisters.__cr & 0x00F00000);
+ case UNW_PPC_CR3:
+ return (fRegisters.__cr & 0x000F0000);
+ case UNW_PPC_CR4:
+ return (fRegisters.__cr & 0x0000F000);
+ case UNW_PPC_CR5:
+ return (fRegisters.__cr & 0x00000F00);
+ case UNW_PPC_CR6:
+ return (fRegisters.__cr & 0x000000F0);
+ case UNW_PPC_CR7:
+ return (fRegisters.__cr & 0x0000000F);
+ case UNW_PPC_VRSAVE:
+ return fRegisters.__vrsave;
+ }
+ ABORT("unsupported ppc register");
+}
+
+
+inline void Registers_ppc::setRegister(int regNum, uint32_t value)
+{
+ //fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value);
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ fRegisters.__srr0 = value;
+ return;
+ case UNW_REG_SP:
+ fRegisters.__r1 = value;
+ return;
+ case UNW_PPC_R0:
+ fRegisters.__r0 = value;
+ return;
+ case UNW_PPC_R1:
+ fRegisters.__r1 = value;
+ return;
+ case UNW_PPC_R2:
+ fRegisters.__r2 = value;
+ return;
+ case UNW_PPC_R3:
+ fRegisters.__r3 = value;
+ return;
+ case UNW_PPC_R4:
+ fRegisters.__r4 = value;
+ return;
+ case UNW_PPC_R5:
+ fRegisters.__r5 = value;
+ return;
+ case UNW_PPC_R6:
+ fRegisters.__r6 = value;
+ return;
+ case UNW_PPC_R7:
+ fRegisters.__r7 = value;
+ return;
+ case UNW_PPC_R8:
+ fRegisters.__r8 = value;
+ return;
+ case UNW_PPC_R9:
+ fRegisters.__r9 = value;
+ return;
+ case UNW_PPC_R10:
+ fRegisters.__r10 = value;
+ return;
+ case UNW_PPC_R11:
+ fRegisters.__r11 = value;
+ return;
+ case UNW_PPC_R12:
+ fRegisters.__r12 = value;
+ return;
+ case UNW_PPC_R13:
+ fRegisters.__r13 = value;
+ return;
+ case UNW_PPC_R14:
+ fRegisters.__r14 = value;
+ return;
+ case UNW_PPC_R15:
+ fRegisters.__r15 = value;
+ return;
+ case UNW_PPC_R16:
+ fRegisters.__r16 = value;
+ return;
+ case UNW_PPC_R17:
+ fRegisters.__r17 = value;
+ return;
+ case UNW_PPC_R18:
+ fRegisters.__r18 = value;
+ return;
+ case UNW_PPC_R19:
+ fRegisters.__r19 = value;
+ return;
+ case UNW_PPC_R20:
+ fRegisters.__r20 = value;
+ return;
+ case UNW_PPC_R21:
+ fRegisters.__r21 = value;
+ return;
+ case UNW_PPC_R22:
+ fRegisters.__r22 = value;
+ return;
+ case UNW_PPC_R23:
+ fRegisters.__r23 = value;
+ return;
+ case UNW_PPC_R24:
+ fRegisters.__r24 = value;
+ return;
+ case UNW_PPC_R25:
+ fRegisters.__r25 = value;
+ return;
+ case UNW_PPC_R26:
+ fRegisters.__r26 = value;
+ return;
+ case UNW_PPC_R27:
+ fRegisters.__r27 = value;
+ return;
+ case UNW_PPC_R28:
+ fRegisters.__r28 = value;
+ return;
+ case UNW_PPC_R29:
+ fRegisters.__r29 = value;
+ return;
+ case UNW_PPC_R30:
+ fRegisters.__r30 = value;
+ return;
+ case UNW_PPC_R31:
+ fRegisters.__r31 = value;
+ return;
+ case UNW_PPC_MQ:
+ fRegisters.__mq = value;
+ return;
+ case UNW_PPC_LR:
+ fRegisters.__lr = value;
+ return;
+ case UNW_PPC_CTR:
+ fRegisters.__ctr = value;
+ return;
+ case UNW_PPC_CR0:
+ fRegisters.__cr &= 0x0FFFFFFF;
+ fRegisters.__cr |= (value & 0xF0000000);
+ return;
+ case UNW_PPC_CR1:
+ fRegisters.__cr &= 0xF0FFFFFF;
+ fRegisters.__cr |= (value & 0x0F000000);
+ return;
+ case UNW_PPC_CR2:
+ fRegisters.__cr &= 0xFF0FFFFF;
+ fRegisters.__cr |= (value & 0x00F00000);
+ return;
+ case UNW_PPC_CR3:
+ fRegisters.__cr &= 0xFFF0FFFF;
+ fRegisters.__cr |= (value & 0x000F0000);
+ return;
+ case UNW_PPC_CR4:
+ fRegisters.__cr &= 0xFFFF0FFF;
+ fRegisters.__cr |= (value & 0x0000F000);
+ return;
+ case UNW_PPC_CR5:
+ fRegisters.__cr &= 0xFFFFF0FF;
+ fRegisters.__cr |= (value & 0x00000F00);
+ return;
+ case UNW_PPC_CR6:
+ fRegisters.__cr &= 0xFFFFFF0F;
+ fRegisters.__cr |= (value & 0x000000F0);
+ return;
+ case UNW_PPC_CR7:
+ fRegisters.__cr &= 0xFFFFFFF0;
+ fRegisters.__cr |= (value & 0x0000000F);
+ return;
+ case UNW_PPC_VRSAVE:
+ fRegisters.__vrsave = value;
+ return;
+ // not saved
+ return;
+ case UNW_PPC_XER:
+ fRegisters.__xer = value;
+ return;
+ case UNW_PPC_AP:
+ case UNW_PPC_VSCR:
+ case UNW_PPC_SPEFSCR:
+ // not saved
+ return;
+ }
+ ABORT("unsupported ppc register");
+}
+
+inline bool Registers_ppc::validFloatRegister(int regNum) const
+{
+ if ( regNum < UNW_PPC_F0 )
+ return false;
+ if ( regNum > UNW_PPC_F31 )
+ return false;
+ return true;
+}
+
+inline double Registers_ppc::getFloatRegister(int regNum) const
+{
+ assert(validFloatRegister(regNum));
+ return fFloatRegisters.__fpregs[regNum-UNW_PPC_F0];
+}
+
+inline void Registers_ppc::setFloatRegister(int regNum, double value)
+{
+ //fprintf(stderr, "Registers_ppc::setFloatRegister(%d, %g))\n", regNum, value);
+ assert(validFloatRegister(regNum));
+ fFloatRegisters.__fpregs[regNum-UNW_PPC_F0] = value;
+}
+
+
+inline bool Registers_ppc::validVectorRegister(int regNum) const
+{
+ if ( regNum < UNW_PPC_V0 )
+ return false;
+ if ( regNum > UNW_PPC_V31 )
+ return false;
+ return true;
+}
+
+v128 Registers_ppc::getVectorRegister(int regNum) const
+{
+ assert(validVectorRegister(regNum));
+ v128 result = fVectorRegisters[regNum-UNW_PPC_V0];
+ //fprintf(stderr, "Registers_ppc::getVectorRegister(this=%p, %d) => <0x%08X, 0x%08X, 0x%08X, 0x%08X> \n",
+ // this, regNum, result.vec[0], result.vec[1], result.vec[2], result.vec[3]);
+ return result;
+}
+
+void Registers_ppc::setVectorRegister(int regNum, v128 value)
+{
+ assert(validVectorRegister(regNum));
+ //fprintf(stderr, "Registers_ppc::setVectorRegister(this=%p, %d) <0x%08X, 0x%08X, 0x%08X, 0x%08X> => <0x%08X, 0x%08X, 0x%08X, 0x%08X> \n",
+ // this, regNum, fVectorRegisters[regNum-UNW_PPC_V0].vec[0], fVectorRegisters[regNum-UNW_PPC_V0].vec[1], fVectorRegisters[regNum-UNW_PPC_V0].vec[2],
+ // fVectorRegisters[regNum-UNW_PPC_V0].vec[3], value.vec[0], value.vec[1], value.vec[2], value.vec[3]);
+ fVectorRegisters[regNum-UNW_PPC_V0] = value;
+}
+
+
+inline const char* Registers_ppc::getRegisterName(int regNum)
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return "ip";
+ case UNW_REG_SP:
+ return "sp";
+ case UNW_PPC_R0:
+ return "r0";
+ case UNW_PPC_R1:
+ return "r1";
+ case UNW_PPC_R2:
+ return "r2";
+ case UNW_PPC_R3:
+ return "r3";
+ case UNW_PPC_R4:
+ return "r4";
+ case UNW_PPC_R5:
+ return "r5";
+ case UNW_PPC_R6:
+ return "r6";
+ case UNW_PPC_R7:
+ return "r7";
+ case UNW_PPC_R8:
+ return "r8";
+ case UNW_PPC_R9:
+ return "r9";
+ case UNW_PPC_R10:
+ return "r10";
+ case UNW_PPC_R11:
+ return "r11";
+ case UNW_PPC_R12:
+ return "r12";
+ case UNW_PPC_R13:
+ return "r13";
+ case UNW_PPC_R14:
+ return "r14";
+ case UNW_PPC_R15:
+ return "r15";
+ case UNW_PPC_R16:
+ return "r16";
+ case UNW_PPC_R17:
+ return "r17";
+ case UNW_PPC_R18:
+ return "r18";
+ case UNW_PPC_R19:
+ return "r19";
+ case UNW_PPC_R20:
+ return "r20";
+ case UNW_PPC_R21:
+ return "r21";
+ case UNW_PPC_R22:
+ return "r22";
+ case UNW_PPC_R23:
+ return "r23";
+ case UNW_PPC_R24:
+ return "r24";
+ case UNW_PPC_R25:
+ return "r25";
+ case UNW_PPC_R26:
+ return "r26";
+ case UNW_PPC_R27:
+ return "r27";
+ case UNW_PPC_R28:
+ return "r28";
+ case UNW_PPC_R29:
+ return "r29";
+ case UNW_PPC_R30:
+ return "r30";
+ case UNW_PPC_R31:
+ return "r31";
+ case UNW_PPC_F0:
+ return "fp0";
+ case UNW_PPC_F1:
+ return "fp1";
+ case UNW_PPC_F2:
+ return "fp2";
+ case UNW_PPC_F3:
+ return "fp3";
+ case UNW_PPC_F4:
+ return "fp4";
+ case UNW_PPC_F5:
+ return "fp5";
+ case UNW_PPC_F6:
+ return "fp6";
+ case UNW_PPC_F7:
+ return "fp7";
+ case UNW_PPC_F8:
+ return "fp8";
+ case UNW_PPC_F9:
+ return "fp9";
+ case UNW_PPC_F10:
+ return "fp10";
+ case UNW_PPC_F11:
+ return "fp11";
+ case UNW_PPC_F12:
+ return "fp12";
+ case UNW_PPC_F13:
+ return "fp13";
+ case UNW_PPC_F14:
+ return "fp14";
+ case UNW_PPC_F15:
+ return "fp15";
+ case UNW_PPC_F16:
+ return "fp16";
+ case UNW_PPC_F17:
+ return "fp17";
+ case UNW_PPC_F18:
+ return "fp18";
+ case UNW_PPC_F19:
+ return "fp19";
+ case UNW_PPC_F20:
+ return "fp20";
+ case UNW_PPC_F21:
+ return "fp21";
+ case UNW_PPC_F22:
+ return "fp22";
+ case UNW_PPC_F23:
+ return "fp23";
+ case UNW_PPC_F24:
+ return "fp24";
+ case UNW_PPC_F25:
+ return "fp25";
+ case UNW_PPC_F26:
+ return "fp26";
+ case UNW_PPC_F27:
+ return "fp27";
+ case UNW_PPC_F28:
+ return "fp28";
+ case UNW_PPC_F29:
+ return "fp29";
+ case UNW_PPC_F30:
+ return "fp30";
+ case UNW_PPC_F31:
+ return "fp31";
+ case UNW_PPC_LR:
+ return "lr";
+ default:
+ return "unknown register";
+ }
+
+
+}
+
+
+} // namespace libunwind
+
+
+
+#endif // __REGISTERS_HPP__
+
+
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __LTO_READER_H__
+#define __LTO_READER_H__
+
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <mach-o/dyld.h>
+#include <vector>
+#include <ext/hash_set>
+#include <ext/hash_map>
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+#include "ld.hpp"
+#include "macho_relocatable_file.h"
+#include "lto_file.h"
+
+// #defines are a work around for <rdar://problem/8760268>
+#define __STDC_LIMIT_MACROS 1
+#define __STDC_CONSTANT_MACROS 1
+#include "llvm-c/lto.h"
+
+
+namespace lto {
+
+
+//
+// ld64 only tracks non-internal symbols from an llvm bitcode file.
+// We model this by having an InternalAtom which represent all internal functions and data.
+// All non-interal symbols from a bitcode file are represented by an Atom
+// and each Atom has a reference to the InternalAtom. The InternalAtom
+// also has references to each symbol external to the bitcode file.
+//
+class InternalAtom : public ld::Atom
+{
+public:
+ InternalAtom(class File& f);
+ // overrides of ld::Atom
+ virtual ld::File* file() const { return &_file; }
+ virtual const char* name() const { return "import-atom"; }
+ virtual uint64_t size() const { return 0; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_undefs[0]; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &_undefs[_undefs.size()]; }
+
+ // for adding references to symbols outside bitcode file
+ void addReference(const char* nm)
+ { _undefs.push_back(ld::Fixup(0, ld::Fixup::k1of1,
+ ld::Fixup::kindNone, false, nm)); }
+private:
+
+ ld::File& _file;
+ mutable std::vector<ld::Fixup> _undefs;
+};
+
+
+//
+// LLVM bitcode file
+//
+class File : public ld::relocatable::File
+{
+public:
+ File(const char* path, time_t mTime, ld::File::Ordinal ordinal,
+ const uint8_t* content, uint32_t contentLength, cpu_type_t arch);
+ virtual ~File();
+
+ // overrides of ld::File
+ virtual bool forEachAtom(ld::File::AtomHandler&) const;
+ virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const
+ { return false; }
+ virtual uint32_t cpuSubType() const { return _cpuSubType; }
+
+ // overrides of ld::relocatable::File
+ virtual DebugInfoKind debugInfo() const { return _debugInfo; }
+ virtual const char* debugInfoPath() const { return _debugInfoPath; }
+ virtual time_t debugInfoModificationTime() const
+ { return _debugInfoModTime; }
+ virtual const std::vector<ld::relocatable::File::Stab>* stabs() const { return NULL; }
+ virtual bool canScatterAtoms() const { return true; }
+
+ lto_module_t module() { return _module; }
+ class InternalAtom& internalAtom() { return _internalAtom; }
+ void setDebugInfo(ld::relocatable::File::DebugInfoKind k,
+ const char* pth, time_t modTime, uint32_t subtype)
+ { _debugInfo = k;
+ _debugInfoPath = pth;
+ _debugInfoModTime = modTime;
+ _cpuSubType = subtype;}
+
+private:
+ friend class Atom;
+ friend class InternalAtom;
+ friend class Parser;
+
+ cpu_type_t _architecture;
+ class InternalAtom _internalAtom;
+ class Atom* _atomArray;
+ uint32_t _atomArrayCount;
+ lto_module_t _module;
+ const char* _debugInfoPath;
+ time_t _debugInfoModTime;
+ ld::Section _section;
+ ld::Fixup _fixupToInternal;
+ ld::relocatable::File::DebugInfoKind _debugInfo;
+ uint32_t _cpuSubType;
+};
+
+//
+// Atom acts as a proxy Atom for the symbols that are exported by LLVM bitcode file. Initially,
+// Reader creates Atoms to allow linker proceed with usual symbol resolution phase. After
+// optimization is performed, real Atoms are created for these symobls. However these real Atoms
+// are not inserted into global symbol table. Atom holds real Atom and forwards appropriate
+// methods to real atom.
+//
+class Atom : public ld::Atom
+{
+public:
+ Atom(File& f, const char* name, ld::Atom::Scope s,
+ ld::Atom::Definition d, ld::Atom::Combine c, ld::Atom::Alignment a, bool ah);
+
+ // overrides of ld::Atom
+ virtual ld::File* file() const { return &_file; }
+ virtual const char* translationUnitSource() const
+ { return (_compiledAtom ? _compiledAtom->translationUnitSource() : NULL); }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return (_compiledAtom ? _compiledAtom->size() : 0); }
+ virtual uint64_t objectAddress() const { return (_compiledAtom ? _compiledAtom->objectAddress() : 0); }
+ virtual void copyRawContent(uint8_t buffer[]) const
+ { if (_compiledAtom) _compiledAtom->copyRawContent(buffer); }
+ virtual const uint8_t* rawContentPointer() const
+ { return (_compiledAtom ? _compiledAtom->rawContentPointer() : NULL); }
+ virtual unsigned long contentHash(const class ld::IndirectBindingTable& ibt) const
+ { return (_compiledAtom ? _compiledAtom->contentHash(ibt) : 0); }
+ virtual bool canCoalesceWith(const ld::Atom& rhs, const class ld::IndirectBindingTable& ibt) const
+ { return (_compiledAtom ? _compiledAtom->canCoalesceWith(rhs,ibt) : false); }
+ virtual ld::Fixup::iterator fixupsBegin() const
+ { return (_compiledAtom ? _compiledAtom->fixupsBegin() : (ld::Fixup*)&_file._fixupToInternal); }
+ virtual ld::Fixup::iterator fixupsEnd() const
+ { return (_compiledAtom ? _compiledAtom->fixupsEnd() : &((ld::Fixup*)&_file._fixupToInternal)[1]); }
+ virtual ld::Atom::UnwindInfo::iterator beginUnwind() const
+ { return (_compiledAtom ? _compiledAtom->beginUnwind() : NULL); }
+ virtual ld::Atom::UnwindInfo::iterator endUnwind() const
+ { return (_compiledAtom ? _compiledAtom->endUnwind() : NULL); }
+ virtual ld::Atom::LineInfo::iterator beginLineInfo() const
+ { return (_compiledAtom ? _compiledAtom->beginLineInfo() : NULL); }
+ virtual ld::Atom::LineInfo::iterator endLineInfo() const
+ { return (_compiledAtom ? _compiledAtom->endLineInfo() : NULL); }
+
+ const ld::Atom* compiledAtom() { return _compiledAtom; }
+ void setCompiledAtom(const ld::Atom& atom);
+
+private:
+
+ File& _file;
+ const char* _name;
+ const ld::Atom* _compiledAtom;
+};
+
+
+
+
+
+
+
+class Parser
+{
+public:
+ static bool validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch);
+ static const char* fileKind(const uint8_t* fileContent, uint64_t fileLength);
+ static File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
+ time_t modTime, ld::File::Ordinal ordinal, cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles);
+ static bool libLTOisLoaded() { return (::lto_get_version() != NULL); }
+ static bool optimize( const std::vector<const ld::Atom*>& allAtoms,
+ ld::Internal& state,
+ const OptimizeOptions& options,
+ ld::File::AtomHandler& handler,
+ std::vector<const ld::Atom*>& newAtoms,
+ std::vector<const char*>& additionalUndefines);
+
+ static const char* ltoVersion() { return ::lto_get_version(); }
+
+private:
+ static const char* tripletPrefixForArch(cpu_type_t arch);
+ static ld::relocatable::File* parseMachOFile(const uint8_t* p, size_t len, const OptimizeOptions& options);
+
+ class CStringEquals
+ {
+ public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+ };
+ typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> CStringSet;
+ typedef __gnu_cxx::hash_map<const char*, Atom*, __gnu_cxx::hash<const char*>, CStringEquals> CStringToAtom;
+
+ class AtomSyncer : public ld::File::AtomHandler {
+ public:
+ AtomSyncer(std::vector<const char*>& a, std::vector<const ld::Atom*>&na,
+ CStringToAtom la, CStringToAtom dla, const OptimizeOptions& options) :
+ _options(options), _additionalUndefines(a), _newAtoms(na), _llvmAtoms(la), _deadllvmAtoms(dla) { }
+ virtual void doAtom(const class ld::Atom&);
+ virtual void doFile(const class ld::File&) { }
+
+ const OptimizeOptions& _options;
+ std::vector<const char*>& _additionalUndefines;
+ std::vector<const ld::Atom*>& _newAtoms;
+ CStringToAtom _llvmAtoms;
+ CStringToAtom _deadllvmAtoms;
+ };
+
+ static std::vector<File*> _s_files;
+};
+
+std::vector<File*> Parser::_s_files;
+
+
+bool Parser::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch)
+{
+ for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+ if ( (architecture == t->cpuType) && (!(t->isSubType) || (subarch == t->cpuSubType)) ) {
+ bool result = ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, t->llvmTriplePrefix);
+ if ( !result ) {
+ // <rdar://problem/8434487> LTO only supports thumbv7 not armv7
+ if ( t->llvmTriplePrefixAlt[0] != '\0' ) {
+ result = ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, t->llvmTriplePrefixAlt);
+ }
+ }
+ return result;
+ }
+ }
+ return false;
+}
+
+const char* Parser::fileKind(const uint8_t* p, uint64_t fileLength)
+{
+ if ( (p[0] == 0xDE) && (p[1] == 0xC0) && (p[2] == 0x17) && (p[3] == 0x0B) ) {
+ cpu_type_t arch = LittleEndian::get32(*((uint32_t*)(&p[16])));
+ for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+ if ( arch == t->cpuType ) {
+ if ( t->isSubType ) {
+ if ( ::lto_module_is_object_file_in_memory_for_target(p, fileLength, t->llvmTriplePrefix) )
+ return t->archName;
+ }
+ else {
+ return t->archName;
+ }
+ }
+ }
+ return "unknown bitcode architecture";
+ }
+ return NULL;
+}
+
+File* Parser::parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, ld::File::Ordinal ordinal,
+ cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles)
+{
+ File* f = new File(path, modTime, ordinal, fileContent, fileLength, architecture);
+ _s_files.push_back(f);
+ if ( logAllFiles )
+ printf("%s\n", path);
+ return f;
+}
+
+
+ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, const OptimizeOptions& options)
+{
+ mach_o::relocatable::ParserOptions objOpts;
+ objOpts.architecture = options.arch;
+ objOpts.objSubtypeMustMatch = false;
+ objOpts.logAllFiles = false;
+ objOpts.convertUnwindInfo = true;
+ objOpts.subType = 0;
+
+ // mach-o parsing is done in-memory, but need path for debug notes
+ const char* path = "/tmp/lto.o";
+ time_t modTime = 0;
+ if ( options.tmpObjectFilePath != NULL ) {
+ path = options.tmpObjectFilePath;
+ struct stat statBuffer;
+ if ( stat(options.tmpObjectFilePath, &statBuffer) == 0 )
+ modTime = statBuffer.st_mtime;
+ }
+
+ ld::relocatable::File* result = mach_o::relocatable::parse(p, len, path, modTime, ld::File::Ordinal::LTOOrdinal(), objOpts);
+ if ( result != NULL )
+ return result;
+ throw "LLVM LTO, file is not of required architecture";
+}
+
+
+
+File::File(const char* pth, time_t mTime, ld::File::Ordinal ordinal, const uint8_t* content, uint32_t contentLength, cpu_type_t arch)
+ : ld::relocatable::File(pth,mTime,ordinal), _architecture(arch), _internalAtom(*this),
+ _atomArray(NULL), _atomArrayCount(0), _module(NULL), _debugInfoPath(pth),
+ _section("__TEXT_", "__tmp_lto", ld::Section::typeTempLTO),
+ _fixupToInternal(0, ld::Fixup::k1of1, ld::Fixup::kindNone, &_internalAtom),
+ _debugInfo(ld::relocatable::File::kDebugInfoNone), _cpuSubType(0)
+{
+ const bool log = false;
+
+ // create llvm module
+ _module = ::lto_module_create_from_memory(content, contentLength);
+ if ( _module == NULL )
+ throwf("could not parse object file %s: %s", pth, lto_get_error_message());
+
+ if ( log ) fprintf(stderr, "bitcode file: %s\n", pth);
+
+ // create atom for each global symbol in module
+ uint32_t count = ::lto_module_get_num_symbols(_module);
+ _atomArray = (Atom*)malloc(sizeof(Atom)*count);
+ for (uint32_t i=0; i < count; ++i) {
+ const char* name = ::lto_module_get_symbol_name(_module, i);
+ lto_symbol_attributes attr = lto_module_get_symbol_attribute(_module, i);
+
+ // <rdar://problem/6378110> LTO doesn't like dtrace symbols
+ // ignore dtrace static probes for now
+ // later when codegen is done and a mach-o file is produces the probes will be processed
+ if ( (strncmp(name, "___dtrace_probe$", 16) == 0) || (strncmp(name, "___dtrace_isenabled$", 20) == 0) )
+ continue;
+
+ ld::Atom::Definition def;
+ ld::Atom::Combine combine = ld::Atom::combineNever;
+ switch ( attr & LTO_SYMBOL_DEFINITION_MASK ) {
+ case LTO_SYMBOL_DEFINITION_REGULAR:
+ def = ld::Atom::definitionRegular;
+ break;
+ case LTO_SYMBOL_DEFINITION_TENTATIVE:
+ def = ld::Atom::definitionTentative;
+ break;
+ case LTO_SYMBOL_DEFINITION_WEAK:
+ def = ld::Atom::definitionRegular;
+ combine = ld::Atom::combineByName;
+ break;
+ case LTO_SYMBOL_DEFINITION_UNDEFINED:
+ case LTO_SYMBOL_DEFINITION_WEAKUNDEF:
+ def = ld::Atom::definitionProxy;
+ break;
+ default:
+ throwf("unknown definition kind for symbol %s in bitcode file %s", name, pth);
+ }
+
+ // make LLVM atoms for definitions and a reference for undefines
+ if ( def != ld::Atom::definitionProxy ) {
+ ld::Atom::Scope scope;
+ bool autohide = false;
+ switch ( attr & LTO_SYMBOL_SCOPE_MASK) {
+ case LTO_SYMBOL_SCOPE_INTERNAL:
+ scope = ld::Atom::scopeTranslationUnit;
+ break;
+ case LTO_SYMBOL_SCOPE_HIDDEN:
+ scope = ld::Atom::scopeLinkageUnit;
+ break;
+ case LTO_SYMBOL_SCOPE_DEFAULT:
+ scope = ld::Atom::scopeGlobal;
+ break;
+#if LTO_API_VERSION >= 4
+ case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN:
+ scope = ld::Atom::scopeGlobal;
+ autohide = true;
+ break;
+#endif
+ default:
+ throwf("unknown scope for symbol %s in bitcode file %s", name, pth);
+ }
+ // only make atoms for non-internal symbols
+ if ( scope == ld::Atom::scopeTranslationUnit )
+ continue;
+ uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK);
+ // make Atom using placement new operator
+ new (&_atomArray[_atomArrayCount++]) Atom(*this, name, scope, def, combine, alignment, autohide);
+ if ( scope != ld::Atom::scopeTranslationUnit )
+ _internalAtom.addReference(name);
+ if ( log ) fprintf(stderr, "\t0x%08X %s\n", attr, name);
+ }
+ else {
+ // add to list of external references
+ _internalAtom.addReference(name);
+ if ( log ) fprintf(stderr, "\t%s (undefined)\n", name);
+ }
+ }
+}
+
+File::~File()
+{
+ if ( _module != NULL )
+ ::lto_module_dispose(_module);
+}
+
+bool File::forEachAtom(ld::File::AtomHandler& handler) const
+{
+ handler.doAtom(_internalAtom);
+ for(uint32_t i=0; i < _atomArrayCount; ++i) {
+ handler.doAtom(_atomArray[i]);
+ }
+ return true;
+}
+
+InternalAtom::InternalAtom(File& f)
+ : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit,
+ ld::Atom::typeLTOtemporary, ld::Atom::symbolTableNotIn, true, false, false, ld::Atom::Alignment(0)),
+ _file(f)
+{
+}
+
+Atom::Atom(File& f, const char* nm, ld::Atom::Scope s, ld::Atom::Definition d, ld::Atom::Combine c,
+ ld::Atom::Alignment a, bool ah)
+ : ld::Atom(f._section, d, c, s, ld::Atom::typeLTOtemporary,
+ ld::Atom::symbolTableIn, false, false, false, a),
+ _file(f), _name(nm), _compiledAtom(NULL)
+{
+ if ( ah )
+ this->setAutoHide();
+}
+
+void Atom::setCompiledAtom(const ld::Atom& atom)
+{
+ // set delegate so virtual methods go to it
+ _compiledAtom = &atom;
+
+ //fprintf(stderr, "setting lto atom %p to delegate to mach-o atom %p (%s)\n", this, &atom, atom.name());
+
+ // update fields in ld::Atom to match newly constructed mach-o atom
+ (const_cast<Atom*>(this))->setAttributesFromAtom(atom);
+}
+
+
+
+bool Parser::optimize( const std::vector<const ld::Atom*>& allAtoms,
+ ld::Internal& state,
+ const OptimizeOptions& options,
+ ld::File::AtomHandler& handler,
+ std::vector<const ld::Atom*>& newAtoms,
+ std::vector<const char*>& additionalUndefines)
+{
+ const bool logMustPreserve = false;
+ const bool logExtraOptions = false;
+ const bool logBitcodeFiles = false;
+ const bool logAtomsBeforeSync = false;
+
+ // exit quickly if nothing to do
+ if ( _s_files.size() == 0 )
+ return false;
+
+ // print out LTO version string if -v was used
+ if ( options.verbose )
+ fprintf(stderr, "%s\n", lto_get_version());
+
+ // create optimizer and add each Reader
+ lto_code_gen_t generator = ::lto_codegen_create();
+ for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
+ if ( logBitcodeFiles ) fprintf(stderr, "lto_codegen_add_module(%s)\n", (*it)->path());
+ if ( ::lto_codegen_add_module(generator, (*it)->module()) )
+ throwf("lto: could not merge in %s because %s", (*it)->path(), ::lto_get_error_message());
+ }
+
+ // add any -mllvm command line options
+ for (std::vector<const char*>::const_iterator it=options.llvmOptions->begin(); it != options.llvmOptions->end(); ++it) {
+ if ( logExtraOptions ) fprintf(stderr, "passing option to llvm: %s\n", *it);
+ ::lto_codegen_debug_options(generator, *it);
+ }
+
+ // The atom graph uses directed edges (references). Collect all references where
+ // originating atom is not part of any LTO Reader. This allows optimizer to optimize an
+ // external (i.e. not originated from same .o file) reference if all originating atoms are also
+ // defined in llvm bitcode file.
+ CStringSet nonLLVMRefs;
+ CStringToAtom llvmAtoms;
+ bool hasNonllvmAtoms = false;
+ for (std::vector<const ld::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) {
+ const ld::Atom* atom = *it;
+ // only look at references that come from an atom that is not an llvm atom
+ if ( atom->contentType() != ld::Atom::typeLTOtemporary ) {
+ if ( (atom->section().type() != ld::Section::typeMachHeader) && (atom->definition() != ld::Atom::definitionProxy) ) {
+ hasNonllvmAtoms = true;
+ }
+ const ld::Atom* target;
+ for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingDirectlyBound:
+ // that reference an llvm atom
+ if ( fit->u.target->contentType() == ld::Atom::typeLTOtemporary )
+ nonLLVMRefs.insert(fit->u.target->name());
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ target = state.indirectBindingTable[fit->u.bindingIndex];
+ if ( target == NULL )
+ throwf("'%s' in %s contains undefined reference", atom->name(), atom->file()->path());
+ assert(target != NULL);
+ if ( target->contentType() == ld::Atom::typeLTOtemporary )
+ nonLLVMRefs.insert(target->name());
+ default:
+ break;
+ }
+ }
+ }
+ else {
+ llvmAtoms[atom->name()] = (Atom*)atom;
+ }
+ }
+ // if entry point is in a llvm bitcode file, it must be preserved by LTO
+ if ( state.entryPoint!= NULL ) {
+ if ( state.entryPoint->contentType() == ld::Atom::typeLTOtemporary )
+ nonLLVMRefs.insert(state.entryPoint->name());
+ }
+
+ // deadAtoms are the atoms that the linker coalesced. For instance weak or tentative definitions
+ // overriden by another atom. If any of these deadAtoms are llvm atoms and they were replaced
+ // with a mach-o atom, we need to tell the lto engine to preserve (not optimize away) its dead
+ // atom so that the linker can replace it with the mach-o one later.
+ CStringToAtom deadllvmAtoms;
+ for (std::vector<const ld::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) {
+ const ld::Atom* atom = *it;
+ if ( atom->coalescedAway() && (atom->contentType() == ld::Atom::typeLTOtemporary) ) {
+ const char* name = atom->name();
+ if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name);
+ ::lto_codegen_add_must_preserve_symbol(generator, name);
+ deadllvmAtoms[name] = (Atom*)atom;
+ }
+ }
+ for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
+ File* file = *it;
+ for(uint32_t i=0; i < file->_atomArrayCount; ++i) {
+ Atom* llvmAtom = &file->_atomArray[i];
+ if ( llvmAtom->coalescedAway() ) {
+ const char* name = llvmAtom->name();
+ if ( deadllvmAtoms.find(name) == deadllvmAtoms.end() ) {
+ if ( logMustPreserve )
+ fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name);
+ ::lto_codegen_add_must_preserve_symbol(generator, name);
+ deadllvmAtoms[name] = (Atom*)llvmAtom;
+ }
+ }
+ else if ( options.linkerDeadStripping && !llvmAtom->live() ) {
+ const char* name = llvmAtom->name();
+ deadllvmAtoms[name] = (Atom*)llvmAtom;
+ }
+ }
+ }
+
+ // tell code generator about symbols that must be preserved
+ for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) {
+ const char* name = it->first;
+ Atom* atom = it->second;
+ // Include llvm Symbol in export list if it meets one of following two conditions
+ // 1 - atom scope is global (and not linkage unit).
+ // 2 - included in nonLLVMRefs set.
+ // If a symbol is not listed in exportList then LTO is free to optimize it away.
+ if ( (atom->scope() == ld::Atom::scopeGlobal) && options.preserveAllGlobals ) {
+ if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because global symbol\n", name);
+ ::lto_codegen_add_must_preserve_symbol(generator, name);
+ }
+ else if ( nonLLVMRefs.find(name) != nonLLVMRefs.end() ) {
+ if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because referenced by a mach-o atom\n", name);
+ ::lto_codegen_add_must_preserve_symbol(generator, name);
+ }
+ }
+
+ // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o)
+ if ( options.relocatable && !hasNonllvmAtoms ) {
+ if ( ! ::lto_codegen_write_merged_modules(generator, options.outputFilePath) ) {
+ // HACK, no good way to tell linker we are all done, so just quit
+ exit(0);
+ }
+ warning("could not produce merged bitcode file");
+ }
+
+ // set code-gen model
+ lto_codegen_model model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+ if ( options.mainExecutable ) {
+ if ( options.staticExecutable ) {
+ // darwin x86_64 "static" code model is really dynamic code model
+ if ( options.arch == CPU_TYPE_X86_64 )
+ model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+ else
+ model = LTO_CODEGEN_PIC_MODEL_STATIC;
+ }
+ else {
+ if ( options.pie )
+ model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+ else
+ model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
+ }
+ }
+ else {
+ if ( options.allowTextRelocs )
+ model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
+ else
+ model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+ }
+ if ( ::lto_codegen_set_pic_model(generator, model) )
+ throwf("could not create set codegen model: %s", lto_get_error_message());
+
+ // if requested, save off merged bitcode file
+ if ( options.saveTemps ) {
+ char tempBitcodePath[MAXPATHLEN];
+ strcpy(tempBitcodePath, options.outputFilePath);
+ strcat(tempBitcodePath, ".lto.bc");
+ ::lto_codegen_write_merged_modules(generator, tempBitcodePath);
+ }
+
+#if LTO_API_VERSION >= 3
+ // find assembler next to linker
+ char path[PATH_MAX];
+ uint32_t bufSize = PATH_MAX;
+ if ( _NSGetExecutablePath(path, &bufSize) != -1 ) {
+ char* lastSlash = strrchr(path, '/');
+ if ( lastSlash != NULL ) {
+ strcpy(lastSlash+1, "as");
+ struct stat statInfo;
+ if ( stat(path, &statInfo) == 0 )
+ ::lto_codegen_set_assembler_path(generator, path);
+ }
+ }
+#endif
+ // run code generator
+ size_t machOFileLen;
+ const uint8_t* machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen);
+ if ( machOFile == NULL )
+ throwf("could not do LTO codegen: %s", ::lto_get_error_message());
+
+ // if requested, save off temp mach-o file
+ if ( options.saveTemps ) {
+ char tempMachoPath[MAXPATHLEN];
+ strcpy(tempMachoPath, options.outputFilePath);
+ strcat(tempMachoPath, ".lto.o");
+ int fd = ::open(tempMachoPath, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+ if ( fd != -1) {
+ ::write(fd, machOFile, machOFileLen);
+ ::close(fd);
+ }
+ // save off merged bitcode file
+ char tempOptBitcodePath[MAXPATHLEN];
+ strcpy(tempOptBitcodePath, options.outputFilePath);
+ strcat(tempOptBitcodePath, ".lto.opt.bc");
+ ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath);
+ }
+
+ // if needed, save temp mach-o file to specific location
+ if ( options.tmpObjectFilePath != NULL ) {
+ int fd = ::open(options.tmpObjectFilePath, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+ if ( fd != -1) {
+ ::write(fd, machOFile, machOFileLen);
+ ::close(fd);
+ }
+ else {
+ warning("could not write LTO temp file '%s', errno=%d", options.tmpObjectFilePath, errno);
+ }
+ }
+
+ // parse generated mach-o file into a MachOReader
+ ld::relocatable::File* machoFile = parseMachOFile(machOFile, machOFileLen, options);
+
+ // sync generated mach-o atoms with existing atoms ld knows about
+ if ( logAtomsBeforeSync ) {
+ fprintf(stderr, "llvmAtoms:\n");
+ for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) {
+ const char* name = it->first;
+ //Atom* atom = it->second;
+ fprintf(stderr, "\t%s\n", name);
+ }
+ fprintf(stderr, "deadllvmAtoms:\n");
+ for (CStringToAtom::iterator it = deadllvmAtoms.begin(); it != deadllvmAtoms.end(); ++it) {
+ const char* name = it->first;
+ //Atom* atom = it->second;
+ fprintf(stderr, "\t%s\n", name);
+ }
+ }
+ AtomSyncer syncer(additionalUndefines, newAtoms, llvmAtoms, deadllvmAtoms, options);
+ machoFile->forEachAtom(syncer);
+
+ // Remove InternalAtoms from ld
+ for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
+ (*it)->internalAtom().setCoalescedAway();
+ }
+ // Remove Atoms from ld if code generator optimized them away
+ for (CStringToAtom::iterator li = llvmAtoms.begin(), le = llvmAtoms.end(); li != le; ++li) {
+ // check if setRealAtom() called on this Atom
+ if ( li->second->compiledAtom() == NULL ) {
+ //fprintf(stderr, "llvm optimized away %p %s\n", li->second, li->second->name());
+ li->second->setCoalescedAway();
+ }
+ }
+
+ // notify about file level attributes
+ handler.doFile(*machoFile);
+
+ // if final mach-o file has debug info, update original bitcode files to match
+ for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
+ (*it)->setDebugInfo(machoFile->debugInfo(), machoFile->path(),
+ machoFile->modificationTime(), machoFile->cpuSubType());
+ }
+
+ return true;
+}
+
+
+void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
+{
+ // update proxy atoms to point to real atoms and find new atoms
+ const char* name = machoAtom.name();
+ if ( machoAtom.scope() >= ld::Atom::scopeLinkageUnit ) {
+ CStringToAtom::iterator pos = _llvmAtoms.find(name);
+ if ( pos != _llvmAtoms.end() ) {
+ // turn Atom into a proxy for this mach-o atom
+ pos->second->setCompiledAtom(machoAtom);
+ }
+ else {
+ // an atom of this name was not in the allAtoms list the linker gave us
+ if ( _deadllvmAtoms.find(name) != _deadllvmAtoms.end() ) {
+ // this corresponding to an atom that the linker coalesced away or marked not-live
+ if ( _options.linkerDeadStripping ) {
+ // llvm seems to want this atom and -dead_strip is enabled, so it will be deleted if not needed, so add back
+ Atom* llvmAtom = _deadllvmAtoms[name];
+ llvmAtom->setCompiledAtom(machoAtom);
+ _newAtoms.push_back(&machoAtom);
+ }
+ else {
+ // Don't pass it back as a new atom
+ }
+ }
+ else
+ {
+ // this is something new that lto conjured up, tell ld its new
+ _newAtoms.push_back(&machoAtom);
+ }
+ }
+ }
+ else {
+ // ld only knew about non-static atoms, so this one must be new
+ _newAtoms.push_back(&machoAtom);
+ }
+
+ // adjust fixups to go through proxy atoms
+ //fprintf(stderr, "adjusting fixups in atom: %s\n", machoAtom.name());
+ for (ld::Fixup::iterator fit=machoAtom.fixupsBegin(); fit != machoAtom.fixupsEnd(); ++fit) {
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingNone:
+ break;
+ case ld::Fixup::bindingByNameUnbound:
+ // don't know if this target has been seen by linker before or if it is new
+ // be conservative and tell linker it is new
+ _additionalUndefines.push_back(fit->u.name);
+ //fprintf(stderr, " by name ref to: %s\n", fit->u.name);
+ break;
+ case ld::Fixup::bindingDirectlyBound:
+ // If mach-o atom is referencing another mach-o atom then
+ // reference is not going through Atom proxy. Fix it here to ensure that all
+ // llvm symbol references always go through Atom proxy.
+ if ( fit->u.target->scope() != ld::Atom::scopeTranslationUnit ) {
+ const char* targetName = fit->u.target->name();
+ CStringToAtom::iterator pos = _llvmAtoms.find(targetName);
+ if ( pos != _llvmAtoms.end() ) {
+ fit->u.target = pos->second;
+ }
+ else {
+ if ( _deadllvmAtoms.find(targetName) != _deadllvmAtoms.end() ) {
+ // target was coalesed away and replace by mach-o atom from a non llvm .o file
+ fit->binding = ld::Fixup::bindingByNameUnbound;
+ fit->u.name = targetName;
+ }
+ }
+ }
+ //fprintf(stderr, " direct ref to: %s (scope=%d)\n", fit->u.target->name(), fit->u.target->scope());
+ break;
+ case ld::Fixup::bindingByContentBound:
+ //fprintf(stderr, " direct by content to: %s\n", fit->u.target->name());
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ assert(0 && "indirect binding found in initial mach-o file?");
+ //fprintf(stderr, " indirect by content to: %u\n", fit->u.bindingIndex);
+ break;
+ }
+ }
+
+}
+
+class Mutex {
+ static pthread_mutex_t lto_lock;
+public:
+ Mutex() { pthread_mutex_lock(<o_lock); }
+ ~Mutex() { pthread_mutex_unlock(<o_lock); }
+};
+pthread_mutex_t Mutex::lto_lock = PTHREAD_MUTEX_INITIALIZER;
+
+//
+// Used by archive reader to see if member is an llvm bitcode file
+//
+bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch)
+{
+ Mutex lock;
+ return Parser::validFile(fileContent, fileLength, architecture, subarch);
+}
+
+
+//
+// main function used by linker to instantiate ld::Files
+//
+ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength,
+ const char* path, time_t modTime, ld::File::Ordinal ordinal,
+ cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles)
+{
+ Mutex lock;
+ if ( Parser::validFile(fileContent, fileLength, architecture, subarch) )
+ return Parser::parse(fileContent, fileLength, path, modTime, ordinal, architecture, subarch, logAllFiles);
+ else
+ return NULL;
+}
+
+//
+// used by "ld -v" to report version of libLTO.dylib being used
+//
+const char* version()
+{
+ Mutex lock;
+ return ::lto_get_version();
+}
+
+
+//
+// used by ld for error reporting
+//
+bool libLTOisLoaded()
+{
+ Mutex lock;
+ return (::lto_get_version() != NULL);
+}
+
+//
+// used by ld for error reporting
+//
+const char* archName(const uint8_t* fileContent, uint64_t fileLength)
+{
+ Mutex lock;
+ return Parser::fileKind(fileContent, fileLength);
+}
+
+//
+// used by ld for doing link time optimization
+//
+bool optimize( const std::vector<const ld::Atom*>& allAtoms,
+ ld::Internal& state,
+ const OptimizeOptions& options,
+ ld::File::AtomHandler& handler,
+ std::vector<const ld::Atom*>& newAtoms,
+ std::vector<const char*>& additionalUndefines)
+{
+ Mutex lock;
+ return Parser::optimize(allAtoms, state, options, handler, newAtoms, additionalUndefines);
+}
+
+
+
+}; // namespace lto
+
+
+#endif
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __LTO_FILE_H__
+#define __LTO_FILE_H__
+
+#include "ld.hpp"
+
+namespace lto {
+
+extern const char* version();
+
+extern bool libLTOisLoaded();
+
+extern const char* archName(const uint8_t* fileContent, uint64_t fileLength);
+
+extern bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch);
+
+extern ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength,
+ const char* path, time_t modTime, ld::File::Ordinal ordinal,
+ cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles);
+
+struct OptimizeOptions {
+ const char* outputFilePath;
+ const char* tmpObjectFilePath;
+ bool preserveAllGlobals;
+ bool verbose;
+ bool saveTemps;
+ bool pie;
+ bool mainExecutable;
+ bool staticExecutable;
+ bool relocatable;
+ bool allowTextRelocs;
+ bool linkerDeadStripping;
+ cpu_type_t arch;
+ const std::vector<const char*>* llvmOptions;
+};
+
+extern bool optimize( const std::vector<const ld::Atom*>& allAtoms,
+ ld::Internal& state,
+ const OptimizeOptions& options,
+ ld::File::AtomHandler& handler,
+ std::vector<const ld::Atom*>& newAtoms,
+ std::vector<const char*>& additionalUndefines);
+
+} // namespace lto
+
+
+#endif // __LTO_FILE_H__
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+
+
+#include <vector>
+#include <set>
+#include <algorithm>
+#include <ext/hash_map>
+#include <ext/hash_set>
+
+#include "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+#include "MachOTrie.hpp"
+#include "macho_dylib_file.h"
+#include "../code-sign-blobs/superblob.h"
+
+namespace mach_o {
+namespace dylib {
+
+
+// forward reference
+template <typename A> class File;
+
+
+//
+// An ExportAtom has no content. It exists so that the linker can track which imported
+// symbols came from which dynamic libraries.
+//
+template <typename A>
+class ExportAtom : public ld::Atom
+{
+public:
+ ExportAtom(const File<A>& f, const char* nm, bool weakDef,
+ bool tlv, typename A::P::uint_t address)
+ : ld::Atom(f._importProxySection, ld::Atom::definitionProxy,
+ (weakDef? ld::Atom::combineByName : ld::Atom::combineNever),
+ ld::Atom::scopeLinkageUnit,
+ (tlv ? ld::Atom::typeTLV : ld::Atom::typeUnclassified),
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
+ _file(f), _name(nm), _address(address) {}
+ // overrides of ld::Atom
+ virtual const ld::File* file() const { return &_file; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 0; }
+ virtual uint64_t objectAddress() const { return _address; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+
+protected:
+ typedef typename A::P P;
+ typedef typename A::P::uint_t pint_t;
+
+ virtual ~ExportAtom() {}
+
+ const File<A>& _file;
+ const char* _name;
+ pint_t _address;
+};
+
+
+
+//
+// An ImportAtom has no content. It exists so that when linking a main executable flat-namespace
+// the imports of all flat dylibs are checked
+//
+template <typename A>
+class ImportAtom : public ld::Atom
+{
+public:
+ ImportAtom(File<A>& f, std::vector<const char*>& imports);
+
+ // overrides of ld::Atom
+ virtual ld::File* file() const { return &_file; }
+ virtual const char* name() const { return "import-atom"; }
+ virtual uint64_t size() const { return 0; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_undefs[0]; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &_undefs[_undefs.size()]; }
+
+protected:
+ typedef typename A::P P;
+
+ virtual ~ImportAtom() {}
+
+
+ File<A>& _file;
+ mutable std::vector<ld::Fixup> _undefs;
+};
+
+template <typename A>
+ImportAtom<A>::ImportAtom(File<A>& f, std::vector<const char*>& imports)
+: ld::Atom(f._flatDummySection, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit,
+ ld::Atom::typeUnclassified, symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)), _file(f)
+{
+ for(std::vector<const char*>::iterator it=imports.begin(); it != imports.end(); ++it) {
+ _undefs.push_back(ld::Fixup(0, ld::Fixup::k1of1, ld::Fixup::kindNone, false, strdup(*it)));
+ }
+}
+
+
+
+//
+// The reader for a dylib extracts all exported symbols names from the memory-mapped
+// dylib, builds a hash table, then unmaps the file. This is an important memory
+// savings for large dylibs.
+//
+template <typename A>
+class File : public ld::dylib::File
+{
+public:
+ static bool validFile(const uint8_t* fileContent, bool executableOrDylib);
+ File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
+ time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace,
+ bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
+ ld::MacVersionMin macMin, ld::IOSVersionMin iPhoneMin, bool addVers,
+ bool logAllFiles, const char* installPath, bool indirectDylib);
+ virtual ~File() {}
+
+ // overrides of ld::File
+ virtual bool forEachAtom(ld::File::AtomHandler&) const;
+ virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const;
+ virtual ld::File::ObjcConstraint objCConstraint() const { return _objcContraint; }
+
+ // overrides of ld::dylib::File
+ virtual void processIndirectLibraries(ld::dylib::File::DylibHandler*, bool);
+ virtual bool providedExportAtom() const { return _providedAtom; }
+ virtual const char* parentUmbrella() const { return _parentUmbrella; }
+ virtual const std::vector<const char*>* allowableClients() const { return _allowableClients.size() != 0 ? &_allowableClients : NULL; }
+ virtual bool hasWeakExternals() const { return _hasWeakExports; }
+ virtual bool deadStrippable() const { return _deadStrippable; }
+ virtual bool hasPublicInstallName() const{ return _hasPublicInstallName; }
+ virtual bool hasWeakDefinition(const char* name) const;
+ virtual bool allSymbolsAreWeakImported() const;
+ virtual const void* codeSignatureDR() const { return _codeSignatureDR; }
+
+
+protected:
+
+ struct ReExportChain { ReExportChain* prev; File<A>* file; };
+
+ void assertNoReExportCycles(ReExportChain*);
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ friend class ExportAtom<A>;
+ friend class ImportAtom<A>;
+
+ class CStringEquals
+ {
+ public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+ };
+ struct AtomAndWeak { ld::Atom* atom; bool weakDef; bool tlv; pint_t address; };
+ typedef __gnu_cxx::hash_map<const char*, AtomAndWeak, __gnu_cxx::hash<const char*>, CStringEquals> NameToAtomMap;
+ typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> NameSet;
+
+ struct Dependent { const char* path; File<A>* dylib; bool reExport; };
+
+ bool containsOrReExports(const char* name, bool* weakDef, bool* tlv, pint_t* defAddress) const;
+ bool isPublicLocation(const char* pth);
+ void addSymbol(const char* name, bool weak, bool tlv, pint_t address);
+ void addDyldFastStub();
+ void buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo,
+ const uint8_t* fileContent);
+ void buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo,
+ const macho_nlist<P>* symbolTable, const char* strings,
+ const uint8_t* fileContent);
+ static const char* objCInfoSegmentName();
+ static const char* objCInfoSectionName();
+
+ const ld::MacVersionMin _macVersionMin;
+ const ld::IOSVersionMin _iOSVersionMin;
+ const bool _addVersionLoadCommand;
+ bool _linkingFlat;
+ bool _implicitlyLinkPublicDylibs;
+ ld::File::ObjcConstraint _objcContraint;
+ ld::Section _importProxySection;
+ ld::Section _flatDummySection;
+ std::vector<Dependent> _dependentDylibs;
+ std::vector<const char*> _allowableClients;
+ mutable NameToAtomMap _atoms;
+ NameSet _ignoreExports;
+ const char* _parentUmbrella;
+ ImportAtom<A>* _importAtom;
+ const void* _codeSignatureDR;
+ bool _noRexports;
+ bool _hasWeakExports;
+ bool _deadStrippable;
+ bool _hasPublicInstallName;
+ mutable bool _providedAtom;
+ bool _explictReExportFound;
+
+ static bool _s_logHashtable;
+};
+
+template <typename A>
+bool File<A>::_s_logHashtable = false;
+
+template <> const char* File<x86_64>::objCInfoSegmentName() { return "__DATA"; }
+template <> const char* File<arm>::objCInfoSegmentName() { return "__DATA"; }
+template <typename A> const char* File<A>::objCInfoSegmentName() { return "__OBJC"; }
+
+template <> const char* File<x86_64>::objCInfoSectionName() { return "__objc_imageinfo"; }
+template <> const char* File<arm>::objCInfoSectionName() { return "__objc_imageinfo"; }
+template <typename A> const char* File<A>::objCInfoSectionName() { return "__image_info"; }
+
+template <typename A>
+File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth, time_t mTime, ld::File::Ordinal ord,
+ bool linkingFlatNamespace, bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
+ ld::MacVersionMin macMin, ld::IOSVersionMin iOSMin, bool addVers,
+ bool logAllFiles, const char* targetInstallPath, bool indirectDylib)
+ : ld::dylib::File(strdup(pth), mTime, ord),
+ _macVersionMin(macMin), _iOSVersionMin(iOSMin), _addVersionLoadCommand(addVers),
+ _linkingFlat(linkingFlatNamespace), _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs),
+ _objcContraint(ld::File::objcConstraintNone),
+ _importProxySection("__TEXT", "__import", ld::Section::typeImportProxies, true),
+ _flatDummySection("__LINKEDIT", "__flat_dummy", ld::Section::typeLinkEdit, true),
+ _parentUmbrella(NULL), _importAtom(NULL), _codeSignatureDR(NULL),
+ _noRexports(false), _hasWeakExports(false),
+ _deadStrippable(false), _hasPublicInstallName(false),
+ _providedAtom(false), _explictReExportFound(false)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ const uint32_t cmd_count = header->ncmds();
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
+ const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
+
+ // write out path for -t option
+ if ( logAllFiles )
+ printf("%s\n", pth);
+
+ // a "blank" stub has zero load commands
+ if ( (header->filetype() == MH_DYLIB_STUB) && (cmd_count == 0) ) {
+ // no further processing needed
+ munmap((caddr_t)fileContent, fileLength);
+ return;
+ }
+
+
+ // optimize the case where we know there is no reason to look at indirect dylibs
+ _noRexports = (header->flags() & MH_NO_REEXPORTED_DYLIBS)
+ || (header->filetype() == MH_BUNDLE)
+ || (header->filetype() == MH_EXECUTE); // bundles and exectuables can be used via -bundle_loader
+ _hasWeakExports = (header->flags() & MH_WEAK_DEFINES);
+ _deadStrippable = (header->flags() & MH_DEAD_STRIPPABLE_DYLIB);
+
+ // pass 1: get pointers, and see if this dylib uses compressed LINKEDIT format
+ const macho_dysymtab_command<P>* dynamicInfo = NULL;
+ const macho_dyld_info_command<P>* dyldInfo = NULL;
+ const macho_linkedit_data_command<P>* codeSignature = NULL;
+ const macho_nlist<P>* symbolTable = NULL;
+ const char* strings = NULL;
+ bool compressedLinkEdit = false;
+ uint32_t dependentLibCount = 0;
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ macho_dylib_command<P>* dylibID;
+ const macho_symtab_command<P>* symtab;
+ switch (cmd->cmd()) {
+ case LC_SYMTAB:
+ symtab = (macho_symtab_command<P>*)cmd;
+ symbolTable = (const macho_nlist<P>*)((char*)header + symtab->symoff());
+ strings = (char*)header + symtab->stroff();
+ if ( (symtab->stroff() + symtab->strsize()) > fileLength )
+ throwf("mach-o string pool extends beyond end of file in %s", pth);
+ break;
+ case LC_DYSYMTAB:
+ dynamicInfo = (macho_dysymtab_command<P>*)cmd;
+ break;
+ case LC_DYLD_INFO:
+ case LC_DYLD_INFO_ONLY:
+ dyldInfo = (macho_dyld_info_command<P>*)cmd;
+ compressedLinkEdit = true;
+ break;
+ case LC_ID_DYLIB:
+ dylibID = (macho_dylib_command<P>*)cmd;
+ _dylibInstallPath = strdup(dylibID->name());
+ _dylibTimeStamp = dylibID->timestamp();
+ _dylibCurrentVersion = dylibID->current_version();
+ _dylibCompatibilityVersion = dylibID->compatibility_version();
+ _hasPublicInstallName = isPublicLocation(_dylibInstallPath);
+ break;
+ case LC_LOAD_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ ++dependentLibCount;
+ break;
+ case LC_REEXPORT_DYLIB:
+ _explictReExportFound = true;
+ ++dependentLibCount;
+ break;
+ case LC_SUB_FRAMEWORK:
+ _parentUmbrella = strdup(((macho_sub_framework_command<P>*)cmd)->umbrella());
+ break;
+ case LC_SUB_CLIENT:
+ _allowableClients.push_back(strdup(((macho_sub_client_command<P>*)cmd)->client()));
+ break;
+ case LC_VERSION_MIN_MACOSX:
+ if ( _addVersionLoadCommand && !indirectDylib && (_iOSVersionMin != ld::iOSVersionUnset) )
+ warning("building for iOS, but linking against dylib built for MacOSX: %s", pth);
+ break;
+ case LC_VERSION_MIN_IPHONEOS:
+ if ( _addVersionLoadCommand && !indirectDylib && (_macVersionMin != ld::macVersionUnset) )
+ warning("building for MacOSX, but linking against dylib built for iOS: %s", pth);
+ break;
+ case LC_CODE_SIGNATURE:
+ codeSignature = (macho_linkedit_data_command<P>* )cmd;
+ break;
+ case macho_segment_command<P>::CMD:
+ // check for Objective-C info
+ if ( strcmp(((macho_segment_command<P>*)cmd)->segname(), objCInfoSegmentName()) == 0 ) {
+ const macho_segment_command<P>* segment = (macho_segment_command<P>*)cmd;
+ const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
+ const macho_section<P>* const sectionsEnd = §ionsStart[segment->nsects()];
+ for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+ if ( strncmp(sect->sectname(), objCInfoSectionName(), strlen(objCInfoSectionName())) == 0 ) {
+ // struct objc_image_info {
+ // uint32_t version; // initially 0
+ // uint32_t flags;
+ // };
+ // #define OBJC_IMAGE_SUPPORTS_GC 2
+ // #define OBJC_IMAGE_GC_ONLY 4
+ //
+ const uint32_t* contents = (uint32_t*)(&fileContent[sect->offset()]);
+ if ( (sect->size() >= 8) && (contents[0] == 0) ) {
+ uint32_t flags = E::get32(contents[1]);
+ if ( (flags & 4) == 4 )
+ _objcContraint = ld::File::objcConstraintGC;
+ else if ( (flags & 2) == 2 )
+ _objcContraint = ld::File::objcConstraintRetainReleaseOrGC;
+ else
+ _objcContraint = ld::File::objcConstraintRetainRelease;
+ }
+ else if ( sect->size() > 0 ) {
+ warning("can't parse %s/%s section in %s", objCInfoSegmentName(), objCInfoSectionName(), this->path());
+ }
+ }
+ }
+ }
+ }
+ cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+ if ( cmd > cmdsEnd )
+ throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, pth);
+ }
+
+ // figure out if we need to examine dependent dylibs
+ // with compressed LINKEDIT format, MH_NO_REEXPORTED_DYLIBS can be trusted
+ bool processDependentLibraries = true;
+ if ( compressedLinkEdit && _noRexports && !linkingFlatNamespace)
+ processDependentLibraries = false;
+
+ if ( processDependentLibraries ) {
+ // pass 2 builds list of all dependent libraries
+ _dependentDylibs.reserve(dependentLibCount);
+ cmd = cmds;
+ unsigned int reExportDylibCount = 0;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch (cmd->cmd()) {
+ case LC_LOAD_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ // with new linkedit format only care about LC_REEXPORT_DYLIB
+ if ( compressedLinkEdit && !linkingFlatNamespace )
+ break;
+ case LC_REEXPORT_DYLIB:
+ ++reExportDylibCount;
+ Dependent entry;
+ entry.path = strdup(((macho_dylib_command<P>*)cmd)->name());
+ entry.dylib = NULL;
+ entry.reExport = (cmd->cmd() == LC_REEXPORT_DYLIB);
+ if ( (targetInstallPath == NULL) || (strcmp(targetInstallPath, entry.path) != 0) )
+ _dependentDylibs.push_back(entry);
+ break;
+ }
+ cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+ }
+ // verify MH_NO_REEXPORTED_DYLIBS bit was correct
+ if ( compressedLinkEdit && !linkingFlatNamespace ) {
+ assert(reExportDylibCount != 0);
+ }
+ // pass 3 add re-export info
+ cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ const char* frameworkLeafName;
+ const char* dylibBaseName;
+ switch (cmd->cmd()) {
+ case LC_SUB_UMBRELLA:
+ frameworkLeafName = ((macho_sub_umbrella_command<P>*)cmd)->sub_umbrella();
+ for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
+ const char* dylibName = it->path;
+ const char* lastSlash = strrchr(dylibName, '/');
+ if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
+ it->reExport = true;
+ }
+ break;
+ case LC_SUB_LIBRARY:
+ dylibBaseName = ((macho_sub_library_command<P>*)cmd)->sub_library();
+ for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
+ const char* dylibName = it->path;
+ const char* lastSlash = strrchr(dylibName, '/');
+ const char* leafStart = &lastSlash[1];
+ if ( lastSlash == NULL )
+ leafStart = dylibName;
+ const char* firstDot = strchr(leafStart, '.');
+ int len = strlen(leafStart);
+ if ( firstDot != NULL )
+ len = firstDot - leafStart;
+ if ( strncmp(leafStart, dylibBaseName, len) == 0 )
+ it->reExport = true;
+ }
+ break;
+ }
+ cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+ }
+ }
+
+ // validate minimal load commands
+ if ( (_dylibInstallPath == NULL) && ((header->filetype() == MH_DYLIB) || (header->filetype() == MH_DYLIB_STUB)) )
+ throwf("dylib %s missing LC_ID_DYLIB load command", pth);
+ if ( dyldInfo == NULL ) {
+ if ( symbolTable == NULL )
+ throw "binary missing LC_SYMTAB load command";
+ if ( dynamicInfo == NULL )
+ throw "binary missing LC_DYSYMTAB load command";
+ }
+
+ // if linking flat and this is a flat dylib, create one atom that references all imported symbols
+ if ( linkingFlatNamespace && linkingMainExecutable && ((header->flags() & MH_TWOLEVEL) == 0) ) {
+ std::vector<const char*> importNames;
+ importNames.reserve(dynamicInfo->nundefsym());
+ const macho_nlist<P>* start = &symbolTable[dynamicInfo->iundefsym()];
+ const macho_nlist<P>* end = &start[dynamicInfo->nundefsym()];
+ for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
+ importNames.push_back(&strings[sym->n_strx()]);
+ }
+ _importAtom = new ImportAtom<A>(*this, importNames);
+ }
+
+ // if the dylib is code signed, look for its Designated Requirement
+ if ( codeSignature != NULL ) {
+ const Security::BlobCore* overallSignature = (Security::BlobCore*)((char*)header + codeSignature->dataoff());
+ typedef Security::SuperBlob<Security::kSecCodeMagicEmbeddedSignature> EmbeddedSignatureBlob;
+ typedef Security::SuperBlob<Security::kSecCodeMagicRequirementSet> InternalRequirementsBlob;
+ const EmbeddedSignatureBlob* signature = EmbeddedSignatureBlob::specific(overallSignature);
+ if ( signature->validateBlob(codeSignature->datasize()) ) {
+ const InternalRequirementsBlob* ireq = signature->find<InternalRequirementsBlob>(Security::cdRequirementsSlot);
+ if ( (ireq != NULL) && ireq->validateBlob() ) {
+ const Security::BlobCore* dr = ireq->find(Security::kSecDesignatedRequirementType);
+ if ( (dr != NULL) && dr->validateBlob(Security::kSecCodeMagicRequirement) ) {
+ // <rdar://problem/10968461> make copy because mapped file is about to be unmapped
+ _codeSignatureDR = ::malloc(dr->length());
+ ::memcpy((void*)_codeSignatureDR, dr, dr->length());
+ }
+ }
+ }
+ }
+
+ // build hash table
+ if ( dyldInfo != NULL )
+ buildExportHashTableFromExportInfo(dyldInfo, fileContent);
+ else
+ buildExportHashTableFromSymbolTable(dynamicInfo, symbolTable, strings, fileContent);
+
+ // unmap file
+ munmap((caddr_t)fileContent, fileLength);
+}
+
+
+template <typename A>
+void File<A>::buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo,
+ const macho_nlist<P>* symbolTable, const char* strings,
+ const uint8_t* fileContent)
+{
+ if ( dynamicInfo->tocoff() == 0 ) {
+ if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable of %u toc entries for %s\n", dynamicInfo->nextdefsym(), this->path());
+ const macho_nlist<P>* start = &symbolTable[dynamicInfo->iextdefsym()];
+ const macho_nlist<P>* end = &start[dynamicInfo->nextdefsym()];
+ _atoms.resize(dynamicInfo->nextdefsym()); // set initial bucket count
+ for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
+ this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, false, sym->n_value());
+ }
+ }
+ else {
+ int32_t count = dynamicInfo->ntoc();
+ _atoms.resize(count); // set initial bucket count
+ if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable of %u entries for %s\n", count, this->path());
+ const struct dylib_table_of_contents* toc = (dylib_table_of_contents*)(fileContent + dynamicInfo->tocoff());
+ for (int32_t i = 0; i < count; ++i) {
+ const uint32_t index = E::get32(toc[i].symbol_index);
+ const macho_nlist<P>* sym = &symbolTable[index];
+ this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, false, sym->n_value());
+ }
+ }
+
+ // special case old libSystem
+ if ( (_dylibInstallPath != NULL) && (strcmp(_dylibInstallPath, "/usr/lib/libSystem.B.dylib") == 0) )
+ addDyldFastStub();
+}
+
+
+template <typename A>
+void File<A>::buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo,
+ const uint8_t* fileContent)
+{
+ if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable from export info in %s\n", this->path());
+ if ( dyldInfo->export_size() > 0 ) {
+ const uint8_t* start = fileContent + dyldInfo->export_off();
+ const uint8_t* end = &start[dyldInfo->export_size()];
+ std::vector<mach_o::trie::Entry> list;
+ parseTrie(start, end, list);
+ for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it)
+ this->addSymbol(it->name,
+ it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION,
+ (it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL,
+ it->address);
+ }
+}
+
+
+template <>
+void File<x86_64>::addDyldFastStub()
+{
+ addSymbol("dyld_stub_binder", false, false, 0);
+}
+
+template <>
+void File<x86>::addDyldFastStub()
+{
+ addSymbol("dyld_stub_binder", false, false, 0);
+}
+
+template <typename A>
+void File<A>::addDyldFastStub()
+{
+ // do nothing
+}
+
+template <typename A>
+void File<A>::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address)
+{
+ if ( weakDef ) {
+ assert(_hasWeakExports);
+ }
+ //fprintf(stderr, "addSymbol() %s\n", name);
+ // symbols that start with $ld$ are meta-data to the static linker
+ // <rdar://problem/5182537> need way for ld and dyld to see different exported symbols in a dylib
+ if ( strncmp(name, "$ld$", 4) == 0 ) {
+ // $ld$ <action> $ <condition> $ <symbol-name>
+ const char* symAction = &name[4];
+ const char* symCond = strchr(symAction, '$');
+ if ( symCond != NULL ) {
+ char curOSVers[16];
+ if ( _macVersionMin != ld::macVersionUnset ) {
+ sprintf(curOSVers, "$os%d.%d$", (_macVersionMin >> 16), ((_macVersionMin >> 8) & 0xFF));
+ }
+ else if ( _iOSVersionMin != ld::iOSVersionUnset ) {
+ sprintf(curOSVers, "$os%d.%d$", (_iOSVersionMin >> 16), ((_iOSVersionMin >> 8) & 0xFF));
+ }
+ else {
+ assert(0 && "targeting neither macosx nor iphoneos");
+ }
+ if ( strncmp(symCond, curOSVers, strlen(curOSVers)) == 0 ) {
+ const char* symName = strchr(&symCond[1], '$');
+ if ( symName != NULL ) {
+ ++symName;
+ if ( strncmp(symAction, "hide$", 5) == 0 ) {
+ if ( _s_logHashtable ) fprintf(stderr, " adding %s to ignore set for %s\n", symName, this->path());
+ _ignoreExports.insert(strdup(symName));
+ return;
+ }
+ else if ( strncmp(symAction, "add$", 4) == 0 ) {
+ this->addSymbol(symName, weakDef, false, 0);
+ return;
+ }
+ else if ( strncmp(symAction, "install_name$", 13) == 0 ) {
+ _dylibInstallPath = symName;
+ return;
+ }
+ else {
+ warning("bad symbol action: %s in dylib %s", name, this->path());
+ }
+ }
+ }
+ }
+ else {
+ warning("bad symbol condition: %s in dylib %s", name, this->path());
+ }
+ }
+
+ // add symbol as possible export if we are not supposed to ignore it
+ if ( _ignoreExports.count(name) == 0 ) {
+ AtomAndWeak bucket;
+ bucket.atom = NULL;
+ bucket.weakDef = weakDef;
+ bucket.tlv = tlv;
+ bucket.address = address;
+ if ( _s_logHashtable ) fprintf(stderr, " adding %s to hash table for %s\n", name, this->path());
+ _atoms[strdup(name)] = bucket;
+ }
+}
+
+
+template <typename A>
+bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
+{
+ handler.doFile(*this);
+ // if doing flatnamespace and need all this dylib's imports resolve
+ // add atom which references alls undefines in this dylib
+ if ( _importAtom != NULL ) {
+ handler.doAtom(*_importAtom);
+ return true;
+ }
+ return false;
+}
+
+template <typename A>
+bool File<A>::hasWeakDefinition(const char* name) const
+{
+ // if supposed to ignore this export, then pretend I don't have it
+ if ( _ignoreExports.count(name) != 0 )
+ return false;
+
+ typename NameToAtomMap::const_iterator pos = _atoms.find(name);
+ if ( pos != _atoms.end() ) {
+ return pos->second.weakDef;
+ }
+ else {
+ // look in children that I re-export
+ for (typename std::vector<Dependent>::const_iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
+ if ( it->reExport ) {
+ //fprintf(stderr, "getJustInTimeAtomsFor: %s NOT found in %s, looking in child %s\n", name, this->path(), (*it)->getInstallPath());
+ typename NameToAtomMap::iterator cpos = it->dylib->_atoms.find(name);
+ if ( cpos != it->dylib->_atoms.end() )
+ return cpos->second.weakDef;
+ }
+ }
+ }
+ return false;
+}
+
+
+// <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
+template <typename A>
+bool File<A>::allSymbolsAreWeakImported() const
+{
+ bool foundNonWeakImport = false;
+ bool foundWeakImport = false;
+ //fprintf(stderr, "%s:\n", this->path());
+ for (typename NameToAtomMap::const_iterator it = _atoms.begin(); it != _atoms.end(); ++it) {
+ const ld::Atom* atom = it->second.atom;
+ if ( atom != NULL ) {
+ if ( atom->weakImported() )
+ foundWeakImport = true;
+ else
+ foundNonWeakImport = true;
+ //fprintf(stderr, " weak_import=%d, name=%s\n", atom->weakImported(), it->first);
+ }
+ }
+
+ // don't automatically weak link dylib with no imports
+ // so at least one weak import symbol and no non-weak-imported symbols must be found
+ return foundWeakImport && !foundNonWeakImport;
+}
+
+
+template <typename A>
+bool File<A>::containsOrReExports(const char* name, bool* weakDef, bool* tlv, pint_t* defAddress) const
+{
+ if ( _ignoreExports.count(name) != 0 )
+ return false;
+
+// check myself
+ typename NameToAtomMap::iterator pos = _atoms.find(name);
+ if ( pos != _atoms.end() ) {
+ *weakDef = pos->second.weakDef;
+ *tlv = pos->second.tlv;
+ *defAddress = pos->second.address;
+ return true;
+ }
+
+ // check dylibs I re-export
+ for (typename std::vector<Dependent>::const_iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
+ if ( it->reExport && !it->dylib->implicitlyLinked() ) {
+ if ( it->dylib->containsOrReExports(name, weakDef, tlv, defAddress) )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+template <typename A>
+bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& handler) const
+{
+ // if supposed to ignore this export, then pretend I don't have it
+ if ( _ignoreExports.count(name) != 0 )
+ return false;
+
+
+ AtomAndWeak bucket;
+ if ( this->containsOrReExports(name, &bucket.weakDef, &bucket.tlv, &bucket.address) ) {
+ bucket.atom = new ExportAtom<A>(*this, name, bucket.weakDef, bucket.tlv, bucket.address);
+ _atoms[name] = bucket;
+ _providedAtom = true;
+ if ( _s_logHashtable ) fprintf(stderr, "getJustInTimeAtomsFor: %s found in %s\n", name, this->path());
+ // call handler with new export atom
+ handler.doAtom(*bucket.atom);
+ return true;
+ }
+
+ return false;
+}
+
+
+
+template <typename A>
+bool File<A>::isPublicLocation(const char* pth)
+{
+ // -no_implicit_dylibs disables this optimization
+ if ( ! _implicitlyLinkPublicDylibs )
+ return false;
+
+ // /usr/lib is a public location
+ if ( (strncmp(pth, "/usr/lib/", 9) == 0) && (strchr(&pth[9], '/') == NULL) )
+ return true;
+
+ // /System/Library/Frameworks/ is a public location
+ if ( strncmp(pth, "/System/Library/Frameworks/", 27) == 0 ) {
+ const char* frameworkDot = strchr(&pth[27], '.');
+ // but only top level framework
+ // /System/Library/Frameworks/Foo.framework/Versions/A/Foo ==> true
+ // /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib ==> false
+ // /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar ==> false
+ // /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo ==> false
+ if ( frameworkDot != NULL ) {
+ int frameworkNameLen = frameworkDot - &pth[27];
+ if ( strncmp(&pth[strlen(pth)-frameworkNameLen-1], &pth[26], frameworkNameLen+1) == 0 )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+template <typename A>
+void File<A>::processIndirectLibraries(ld::dylib::File::DylibHandler* handler, bool addImplicitDylibs)
+{
+ const static bool log = false;
+ if ( log ) fprintf(stderr, "processIndirectLibraries(%s)\n", this->installPath());
+ if ( _linkingFlat ) {
+ for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) {
+ it->dylib = (File<A>*)handler->findDylib(it->path, this->path());
+ }
+ }
+ else if ( _noRexports ) {
+ // MH_NO_REEXPORTED_DYLIBS bit set, then nothing to do
+ }
+ else {
+ // two-level, might have re-exports
+ for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) {
+ if ( it->reExport ) {
+ if ( log ) fprintf(stderr, "processIndirectLibraries() parent=%s, child=%s\n", this->installPath(), it->path);
+ // a LC_REEXPORT_DYLIB, LC_SUB_UMBRELLA or LC_SUB_LIBRARY says we re-export this child
+ it->dylib = (File<A>*)handler->findDylib(it->path, this->path());
+ if ( it->dylib->hasPublicInstallName() ) {
+ // promote this child to be automatically added as a direct dependent if this already is
+ if ( (this->explicitlyLinked() || this->implicitlyLinked()) && (strcmp(it->path,it->dylib->installPath()) == 0) ) {
+ if ( log ) fprintf(stderr, "processIndirectLibraries() implicitly linking %s\n", it->dylib->installPath());
+ it->dylib->setImplicitlyLinked();
+ }
+ else if ( it->dylib->explicitlyLinked() || it->dylib->implicitlyLinked() ) {
+ if ( log ) fprintf(stderr, "processIndirectLibraries() parent is not directly linked, but child is, so no need to re-export child\n");
+ }
+ else {
+ if ( log ) fprintf(stderr, "processIndirectLibraries() parent is not directly linked, so parent=%s will re-export child=%s\n", this->installPath(), it->path);
+ }
+ }
+ else {
+ // add all child's symbols to me
+ if ( log ) fprintf(stderr, "processIndirectLibraries() child is not public, so parent=%s will re-export child=%s\n", this->installPath(), it->path);
+ }
+ }
+ else if ( !_explictReExportFound ) {
+ // see if child contains LC_SUB_FRAMEWORK with my name
+ it->dylib = (File<A>*)handler->findDylib(it->path, this->path());
+ const char* parentUmbrellaName = it->dylib->parentUmbrella();
+ if ( parentUmbrellaName != NULL ) {
+ const char* parentName = this->path();
+ const char* lastSlash = strrchr(parentName, '/');
+ if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], parentUmbrellaName) == 0) ) {
+ // add all child's symbols to me
+ it->reExport = true;
+ if ( log ) fprintf(stderr, "processIndirectLibraries() umbrella=%s will re-export child=%s\n", this->installPath(), it->path);
+ }
+ }
+ }
+ }
+ }
+
+ // check for re-export cycles
+ ReExportChain chain;
+ chain.prev = NULL;
+ chain.file = this;
+ this->assertNoReExportCycles(&chain);
+}
+
+template <typename A>
+void File<A>::assertNoReExportCycles(ReExportChain* prev)
+{
+ // recursively check my re-exported dylibs
+ ReExportChain chain;
+ chain.prev = prev;
+ chain.file = this;
+ for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) {
+ if ( it->reExport ) {
+ ld::File* child = it->dylib;
+ // check child is not already in chain
+ for (ReExportChain* p = prev; p != NULL; p = p->prev) {
+ if ( p->file == child ) {
+ throwf("cycle in dylib re-exports with %s and %s", child->path(), this->path());
+ }
+ }
+ if ( it->dylib != NULL )
+ it->dylib->assertNoReExportCycles(&chain);
+ }
+ }
+}
+
+
+template <typename A>
+class Parser
+{
+public:
+ typedef typename A::P P;
+
+ static bool validFile(const uint8_t* fileContent, bool executableOrDyliborBundle);
+ static ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength,
+ const char* path, time_t mTime,
+ ld::File::Ordinal ordinal, const Options& opts, bool indirectDylib) {
+ return new File<A>(fileContent, fileLength, path, mTime,
+ ordinal, opts.flatNamespace(),
+ opts.linkingMainExecutable(),
+ opts.implicitlyLinkIndirectPublicDylibs(),
+ opts.macosxVersionMin(),
+ opts.iOSVersionMin(),
+ opts.addVersionLoadCommand(),
+ opts.logAllFiles(),
+ opts.installPath(),
+ indirectDylib);
+ }
+
+};
+
+
+
+template <>
+bool Parser<x86>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_I386 )
+ return false;
+ switch ( header->filetype() ) {
+ case MH_DYLIB:
+ case MH_DYLIB_STUB:
+ return true;
+ case MH_BUNDLE:
+ if ( executableOrDyliborBundle )
+ return true;
+ else
+ throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
+ case MH_EXECUTE:
+ if ( executableOrDyliborBundle )
+ return true;
+ else
+ throw "can't link with a main executable";
+ default:
+ return false;
+ }
+}
+
+template <>
+bool Parser<x86_64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_X86_64 )
+ return false;
+ switch ( header->filetype() ) {
+ case MH_DYLIB:
+ case MH_DYLIB_STUB:
+ return true;
+ case MH_BUNDLE:
+ if ( executableOrDyliborBundle )
+ return true;
+ else
+ throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
+ case MH_EXECUTE:
+ if ( executableOrDyliborBundle )
+ return true;
+ else
+ throw "can't link with a main executable";
+ default:
+ return false;
+ }
+}
+
+template <>
+bool Parser<arm>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_ARM )
+ return false;
+ switch ( header->filetype() ) {
+ case MH_DYLIB:
+ case MH_DYLIB_STUB:
+ return true;
+ case MH_BUNDLE:
+ if ( executableOrDyliborBundle )
+ return true;
+ else
+ throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
+ case MH_EXECUTE:
+ if ( executableOrDyliborBundle )
+ return true;
+ else
+ throw "can't link with a main executable";
+ default:
+ return false;
+ }
+}
+
+
+
+//
+// main function used by linker to instantiate ld::Files
+//
+ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength,
+ const char* path, time_t modTime, const Options& opts, ld::File::Ordinal ordinal,
+ bool bundleLoader, bool indirectDylib)
+{
+ switch ( opts.architecture() ) {
+#if SUPPORT_ARCH_x86_64
+ case CPU_TYPE_X86_64:
+ if ( Parser<x86_64>::validFile(fileContent, bundleLoader) )
+ return Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
+ break;
+#endif
+#if SUPPORT_ARCH_i386
+ case CPU_TYPE_I386:
+ if ( Parser<x86>::validFile(fileContent, bundleLoader) )
+ return Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
+ break;
+#endif
+#if SUPPORT_ARCH_arm_any
+ case CPU_TYPE_ARM:
+ if ( Parser<arm>::validFile(fileContent, bundleLoader) )
+ return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
+ break;
+#endif
+ }
+ return NULL;
+}
+
+
+}; // namespace dylib
+}; // namespace mach_o
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __MACHO_DYLIB_FILE_H__
+#define __MACHO_DYLIB_FILE_H__
+
+#include "ld.hpp"
+#include "Options.h"
+
+namespace mach_o {
+namespace dylib {
+
+extern ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
+ time_t modTime, const Options& opts, ld::File::Ordinal ordinal,
+ bool bundleLoader, bool indirectDylib);
+
+} // namespace dylib
+} // namespace mach_o
+
+
+#endif // __MACHO_DYLIB_FILE_H__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <math.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "MachOFileAbstraction.hpp"
+
+#include "libunwind/DwarfInstructions.hpp"
+#include "libunwind/AddressSpace.hpp"
+#include "libunwind/Registers.hpp"
+
+#include <vector>
+#include <set>
+#include <map>
+#include <algorithm>
+
+#include "dwarf2.h"
+#include "debugline.h"
+
+#include "Architectures.hpp"
+#include "ld.hpp"
+#include "macho_relocatable_file.h"
+
+
+
+extern void throwf(const char* format, ...) __attribute__ ((noreturn,format(printf, 1, 2)));
+extern void warning(const char* format, ...) __attribute__((format(printf, 1, 2)));
+
+namespace mach_o {
+namespace relocatable {
+
+
+// forward reference
+template <typename A> class Parser;
+template <typename A> class Atom;
+template <typename A> class Section;
+template <typename A> class CFISection;
+template <typename A> class CUSection;
+
+template <typename A>
+class File : public ld::relocatable::File
+{
+public:
+ File(const char* p, time_t mTime, const uint8_t* content, ld::File::Ordinal ord) :
+ ld::relocatable::File(p,mTime,ord), _fileContent(content),
+ _sectionsArray(NULL), _atomsArray(NULL),
+ _sectionsArrayCount(0), _atomsArrayCount(0),
+ _debugInfoKind(ld::relocatable::File::kDebugInfoNone),
+ _dwarfTranslationUnitPath(NULL),
+ _dwarfDebugInfoSect(NULL), _dwarfDebugAbbrevSect(NULL),
+ _dwarfDebugLineSect(NULL), _dwarfDebugStringSect(NULL),
+ _objConstraint(ld::File::objcConstraintNone),
+ _cpuSubType(0),
+ _canScatterAtoms(false) {}
+ virtual ~File();
+
+ // overrides of ld::File
+ virtual bool forEachAtom(ld::File::AtomHandler&) const;
+ virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const
+ { return false; }
+
+ // overrides of ld::relocatable::File
+ virtual ObjcConstraint objCConstraint() const { return _objConstraint; }
+ virtual uint32_t cpuSubType() const { return _cpuSubType; }
+ virtual DebugInfoKind debugInfo() const { return _debugInfoKind; }
+ virtual const std::vector<ld::relocatable::File::Stab>* stabs() const { return &_stabs; }
+ virtual bool canScatterAtoms() const { return _canScatterAtoms; }
+ virtual const char* translationUnitSource() const;
+
+ const uint8_t* fileContent() { return _fileContent; }
+private:
+ friend class Atom<A>;
+ friend class Section<A>;
+ friend class Parser<A>;
+ friend class CFISection<A>::OAS;
+
+ typedef typename A::P P;
+
+ const uint8_t* _fileContent;
+ Section<A>** _sectionsArray;
+ uint8_t* _atomsArray;
+ uint32_t _sectionsArrayCount;
+ uint32_t _atomsArrayCount;
+ std::vector<ld::Fixup> _fixups;
+ std::vector<ld::Atom::UnwindInfo> _unwindInfos;
+ std::vector<ld::Atom::LineInfo> _lineInfos;
+ std::vector<ld::relocatable::File::Stab>_stabs;
+ ld::relocatable::File::DebugInfoKind _debugInfoKind;
+ const char* _dwarfTranslationUnitPath;
+ const macho_section<P>* _dwarfDebugInfoSect;
+ const macho_section<P>* _dwarfDebugAbbrevSect;
+ const macho_section<P>* _dwarfDebugLineSect;
+ const macho_section<P>* _dwarfDebugStringSect;
+ ld::File::ObjcConstraint _objConstraint;
+ uint32_t _cpuSubType;
+ bool _canScatterAtoms;
+};
+
+
+template <typename A>
+class Section : public ld::Section
+{
+public:
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+
+ virtual ~Section() { }
+ class File<A>& file() const { return _file; }
+ const macho_section<P>* machoSection() const { return _machOSection; }
+ uint32_t sectionNum(class Parser<A>&) const;
+ virtual ld::Atom::Alignment alignmentForAddress(pint_t addr);
+ virtual ld::Atom::ContentType contentType() { return ld::Atom::typeUnclassified; }
+ virtual bool dontDeadStrip() { return (this->_machOSection->flags() & S_ATTR_NO_DEAD_STRIP); }
+ virtual Atom<A>* findAtomByAddress(pint_t addr) { return this->findContentAtomByAddress(addr, this->_beginAtoms, this->_endAtoms); }
+ virtual bool addFollowOnFixups() const { return ! _file.canScatterAtoms(); }
+ virtual uint32_t appendAtoms(class Parser<A>& parser, uint8_t* buffer,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&) = 0;
+ virtual uint32_t computeAtomCount(class Parser<A>& parser,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&) = 0;
+ virtual void makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&);
+ virtual bool addRelocFixup(class Parser<A>& parser, const macho_relocation_info<P>*);
+ virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const { return 0; }
+ virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const { return false; }
+ static const char* makeSectionName(const macho_section<typename A::P>* s);
+
+protected:
+ Section(File<A>& f, const macho_section<typename A::P>* s)
+ : ld::Section(makeSegmentName(s), makeSectionName(s), sectionType(s)),
+ _file(f), _machOSection(s), _beginAtoms(NULL), _endAtoms(NULL), _hasAliases(false) { }
+ Section(File<A>& f, const char* segName, const char* sectName, ld::Section::Type t, bool hidden=false)
+ : ld::Section(segName, sectName, t, hidden), _file(f), _machOSection(NULL),
+ _beginAtoms(NULL), _endAtoms(NULL), _hasAliases(false) { }
+
+
+ Atom<A>* findContentAtomByAddress(pint_t addr, class Atom<A>* start, class Atom<A>* end);
+ uint32_t x86_64PcRelOffset(uint8_t r_type);
+ static const char* makeSegmentName(const macho_section<typename A::P>* s);
+ static bool readable(const macho_section<typename A::P>* s);
+ static bool writable(const macho_section<typename A::P>* s);
+ static bool exectuable(const macho_section<typename A::P>* s);
+ static ld::Section::Type sectionType(const macho_section<typename A::P>* s);
+
+ File<A>& _file;
+ const macho_section<P>* _machOSection;
+ class Atom<A>* _beginAtoms;
+ class Atom<A>* _endAtoms;
+ bool _hasAliases;
+};
+
+
+template <typename A>
+class CFISection : public Section<A>
+{
+public:
+ CFISection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : Section<A>(f, s) { }
+ uint32_t cfiCount();
+
+ virtual ld::Atom::ContentType contentType() { return ld::Atom::typeCFI; }
+ virtual uint32_t computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFI_CU_InfoArrays&);
+ virtual uint32_t appendAtoms(class Parser<A>& parser, uint8_t* buffer, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFI_CU_InfoArrays&);
+ virtual void makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&);
+ virtual bool addFollowOnFixups() const { return false; }
+
+
+ ///
+ /// ObjectFileAddressSpace is used as a template parameter to UnwindCursor for parsing
+ /// dwarf CFI information in an object file.
+ ///
+ class OAS
+ {
+ public:
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t sint_t;
+
+ OAS(CFISection<A>& ehFrameSection, const uint8_t* ehFrameBuffer) :
+ _ehFrameSection(ehFrameSection),
+ _ehFrameContent(ehFrameBuffer),
+ _ehFrameStartAddr(ehFrameSection.machoSection()->addr()),
+ _ehFrameEndAddr(ehFrameSection.machoSection()->addr()+ehFrameSection.machoSection()->size()) {}
+
+ uint8_t get8(pint_t addr) { return *((uint8_t*)mappedAddress(addr)); }
+ uint16_t get16(pint_t addr) { return E::get16(*((uint16_t*)mappedAddress(addr))); }
+ uint32_t get32(pint_t addr) { return E::get32(*((uint32_t*)mappedAddress(addr))); }
+ uint64_t get64(pint_t addr) { return E::get64(*((uint64_t*)mappedAddress(addr))); }
+ pint_t getP(pint_t addr) { return P::getP(*((pint_t*)mappedAddress(addr))); }
+ uint64_t getULEB128(pint_t& addr, pint_t end);
+ int64_t getSLEB128(pint_t& addr, pint_t end);
+ pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
+ private:
+ const void* mappedAddress(pint_t addr);
+
+ CFISection<A>& _ehFrameSection;
+ const uint8_t* _ehFrameContent;
+ pint_t _ehFrameStartAddr;
+ pint_t _ehFrameEndAddr;
+ };
+
+
+ typedef typename A::P::uint_t pint_t;
+ typedef libunwind::CFI_Atom_Info<OAS> CFI_Atom_Info;
+
+ void cfiParse(class Parser<A>& parser, uint8_t* buffer, CFI_Atom_Info cfiArray[], uint32_t cfiCount);
+ bool needsRelocating();
+
+ static bool bigEndian();
+private:
+ void addCiePersonalityFixups(class Parser<A>& parser, const CFI_Atom_Info* cieInfo);
+ static void warnFunc(void* ref, uint64_t funcAddr, const char* msg);
+};
+
+
+template <typename A>
+class CUSection : public Section<A>
+{
+public:
+ CUSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : Section<A>(f, s) { }
+
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+
+ virtual uint32_t computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFI_CU_InfoArrays&) { return 0; }
+ virtual uint32_t appendAtoms(class Parser<A>& parser, uint8_t* buffer, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFI_CU_InfoArrays&) { return 0; }
+ virtual void makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&);
+ virtual bool addFollowOnFixups() const { return false; }
+
+ struct Info {
+ pint_t functionStartAddress;
+ uint32_t functionSymbolIndex;
+ uint32_t rangeLength;
+ uint32_t compactUnwindInfo;
+ const char* personality;
+ pint_t lsdaAddress;
+ Atom<A>* function;
+ Atom<A>* lsda;
+ };
+
+ uint32_t count();
+ void parse(class Parser<A>& parser, uint32_t cnt, Info array[]);
+
+
+private:
+
+ const char* personalityName(class Parser<A>& parser, const macho_relocation_info<P>* reloc);
+
+ static int infoSorter(const void* l, const void* r);
+
+};
+
+
+template <typename A>
+class TentativeDefinitionSection : public Section<A>
+{
+public:
+ TentativeDefinitionSection(Parser<A>& parser, File<A>& f)
+ : Section<A>(f, "__DATA", "__comm/tent", ld::Section::typeTentativeDefs) {}
+
+ virtual ld::Atom::ContentType contentType() { return ld::Atom::typeZeroFill; }
+ virtual bool addFollowOnFixups() const { return false; }
+ virtual Atom<A>* findAtomByAddress(typename A::P::uint_t addr) { throw "TentativeDefinitionSection::findAtomByAddress() should never be called"; }
+ virtual uint32_t computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&);
+ virtual uint32_t appendAtoms(class Parser<A>& parser, uint8_t* buffer,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&);
+ virtual void makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&) {}
+private:
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+};
+
+
+template <typename A>
+class AbsoluteSymbolSection : public Section<A>
+{
+public:
+ AbsoluteSymbolSection(Parser<A>& parser, File<A>& f)
+ : Section<A>(f, "__DATA", "__abs", ld::Section::typeAbsoluteSymbols, true) {}
+
+ virtual ld::Atom::ContentType contentType() { return ld::Atom::typeUnclassified; }
+ virtual bool dontDeadStrip() { return false; }
+ virtual ld::Atom::Alignment alignmentForAddress(typename A::P::uint_t addr) { return ld::Atom::Alignment(0); }
+ virtual bool addFollowOnFixups() const { return false; }
+ virtual Atom<A>* findAtomByAddress(typename A::P::uint_t addr) { throw "AbsoluteSymbolSection::findAtomByAddress() should never be called"; }
+ virtual uint32_t computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&);
+ virtual uint32_t appendAtoms(class Parser<A>& parser, uint8_t* buffer,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&);
+ virtual void makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&) {}
+ virtual Atom<A>* findAbsAtomForValue(typename A::P::uint_t);
+
+private:
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+};
+
+
+template <typename A>
+class SymboledSection : public Section<A>
+{
+public:
+ SymboledSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s);
+ virtual ld::Atom::ContentType contentType() { return _type; }
+ virtual bool dontDeadStrip();
+ virtual uint32_t computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&);
+ virtual uint32_t appendAtoms(class Parser<A>& parser, uint8_t* buffer,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&);
+protected:
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+
+ ld::Atom::ContentType _type;
+};
+
+
+template <typename A>
+class TLVDefsSection : public SymboledSection<A>
+{
+public:
+ TLVDefsSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s) :
+ SymboledSection<A>(parser, f, s) { }
+
+private:
+
+};
+
+
+template <typename A>
+class ImplicitSizeSection : public Section<A>
+{
+public:
+ ImplicitSizeSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : Section<A>(f, s) { }
+ virtual uint32_t computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFI_CU_InfoArrays&);
+ virtual uint32_t appendAtoms(class Parser<A>& parser, uint8_t* buffer, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFI_CU_InfoArrays&);
+protected:
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+
+ virtual bool addFollowOnFixups() const { return false; }
+ virtual const char* unlabeledAtomName(Parser<A>& parser, pint_t addr) = 0;
+ virtual ld::Atom::SymbolTableInclusion symbolTableInclusion() { return ld::Atom::symbolTableNotIn; }
+ virtual pint_t elementSizeAtAddress(pint_t addr) = 0;
+ virtual ld::Atom::Scope scopeAtAddress(Parser<A>& parser, pint_t addr) { return ld::Atom::scopeLinkageUnit; }
+ virtual bool useElementAt(Parser<A>& parser,
+ struct Parser<A>::LabelAndCFIBreakIterator& it, pint_t addr) = 0;
+ virtual ld::Atom::Definition definition() { return ld::Atom::definitionRegular; }
+ virtual ld::Atom::Combine combine(Parser<A>& parser, pint_t addr) = 0;
+ virtual bool ignoreLabel(const char* label) { return (label[0] == 'L'); }
+};
+
+template <typename A>
+class FixedSizeSection : public ImplicitSizeSection<A>
+{
+public:
+ FixedSizeSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : ImplicitSizeSection<A>(parser, f, s) { }
+protected:
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+
+ virtual bool useElementAt(Parser<A>& parser,
+ struct Parser<A>::LabelAndCFIBreakIterator& it, pint_t addr)
+ { return true; }
+};
+
+
+template <typename A>
+class Literal4Section : public FixedSizeSection<A>
+{
+public:
+ Literal4Section(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : FixedSizeSection<A>(parser, f, s) {}
+protected:
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+
+ virtual ld::Atom::Alignment alignmentForAddress(pint_t addr) { return ld::Atom::Alignment(2); }
+ virtual const char* unlabeledAtomName(Parser<A>&, pint_t) { return "4-byte-literal"; }
+ virtual pint_t elementSizeAtAddress(pint_t addr) { return 4; }
+ virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineByNameAndContent; }
+ virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+ virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const;
+};
+
+template <typename A>
+class Literal8Section : public FixedSizeSection<A>
+{
+public:
+ Literal8Section(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : FixedSizeSection<A>(parser, f, s) {}
+protected:
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+
+ virtual ld::Atom::Alignment alignmentForAddress(pint_t addr) { return ld::Atom::Alignment(3); }
+ virtual const char* unlabeledAtomName(Parser<A>&, pint_t) { return "8-byte-literal"; }
+ virtual pint_t elementSizeAtAddress(pint_t addr) { return 8; }
+ virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineByNameAndContent; }
+ virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+ virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const;
+};
+
+template <typename A>
+class Literal16Section : public FixedSizeSection<A>
+{
+public:
+ Literal16Section(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : FixedSizeSection<A>(parser, f, s) {}
+protected:
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+
+ virtual ld::Atom::Alignment alignmentForAddress(pint_t addr) { return ld::Atom::Alignment(4); }
+ virtual const char* unlabeledAtomName(Parser<A>&, pint_t) { return "16-byte-literal"; }
+ virtual pint_t elementSizeAtAddress(pint_t addr) { return 16; }
+ virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineByNameAndContent; }
+ virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+ virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const;
+};
+
+
+template <typename A>
+class NonLazyPointerSection : public FixedSizeSection<A>
+{
+public:
+ NonLazyPointerSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : FixedSizeSection<A>(parser, f, s) {}
+protected:
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+
+ virtual void makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&);
+ virtual ld::Atom::ContentType contentType() { return ld::Atom::typeNonLazyPointer; }
+ virtual ld::Atom::Alignment alignmentForAddress(pint_t addr) { return ld::Atom::Alignment(log2(sizeof(pint_t))); }
+ virtual const char* unlabeledAtomName(Parser<A>&, pint_t) { return "non_lazy_ptr"; }
+ virtual pint_t elementSizeAtAddress(pint_t addr) { return sizeof(pint_t); }
+ virtual ld::Atom::Scope scopeAtAddress(Parser<A>& parser, pint_t addr);
+ virtual ld::Atom::Combine combine(Parser<A>&, pint_t);
+ virtual bool ignoreLabel(const char* label) { return true; }
+ virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+ virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const;
+
+private:
+ static const char* targetName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind);
+ static ld::Fixup::Kind fixupKind();
+};
+
+
+template <typename A>
+class CFStringSection : public FixedSizeSection<A>
+{
+public:
+ CFStringSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : FixedSizeSection<A>(parser, f, s) {}
+protected:
+ typedef typename A::P::uint_t pint_t;
+
+ virtual ld::Atom::Alignment alignmentForAddress(pint_t addr) { return ld::Atom::Alignment(log2(sizeof(pint_t))); }
+ virtual const char* unlabeledAtomName(Parser<A>&, pint_t) { return "CFString"; }
+ virtual pint_t elementSizeAtAddress(pint_t addr) { return 4*sizeof(pint_t); }
+ virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineByNameAndReferences; }
+ virtual bool ignoreLabel(const char* label) { return true; }
+ virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+ virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const;
+private:
+ enum ContentType { contentUTF8, contentUTF16, contentUnknown };
+ static const uint8_t* targetContent(const class Atom<A>* atom, const ld::IndirectBindingTable& ind,
+ ContentType* ct, unsigned int* count);
+};
+
+
+template <typename A>
+class ObjC1ClassSection : public FixedSizeSection<A>
+{
+public:
+ ObjC1ClassSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : FixedSizeSection<A>(parser, f, s) {}
+protected:
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+
+ virtual ld::Atom::Scope scopeAtAddress(Parser<A>& , pint_t ) { return ld::Atom::scopeGlobal; }
+ virtual ld::Atom::Alignment alignmentForAddress(pint_t addr) { return ld::Atom::Alignment(2); }
+ virtual const char* unlabeledAtomName(Parser<A>&, pint_t);
+ virtual ld::Atom::SymbolTableInclusion symbolTableInclusion() { return ld::Atom::symbolTableIn; }
+ virtual pint_t elementSizeAtAddress(pint_t addr);
+ virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineNever; }
+ virtual bool ignoreLabel(const char* label) { return true; }
+ virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+ { return 0; }
+ virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const { return false; }
+ virtual bool addRelocFixup(class Parser<A>& parser, const macho_relocation_info<P>*);
+};
+
+
+template <typename A>
+class ObjC2ClassRefsSection : public FixedSizeSection<A>
+{
+public:
+ ObjC2ClassRefsSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : FixedSizeSection<A>(parser, f, s) {}
+protected:
+ typedef typename A::P::uint_t pint_t;
+
+ virtual ld::Atom::Alignment alignmentForAddress(pint_t addr) { return ld::Atom::Alignment(log2(sizeof(pint_t))); }
+ virtual const char* unlabeledAtomName(Parser<A>&, pint_t) { return "objc-class-ref"; }
+ virtual pint_t elementSizeAtAddress(pint_t addr) { return sizeof(pint_t); }
+ virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineByNameAndReferences; }
+ virtual bool ignoreLabel(const char* label) { return true; }
+ virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+ virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const;
+private:
+ const char* targetClassName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+};
+
+
+template <typename A>
+class ObjC2CategoryListSection : public FixedSizeSection<A>
+{
+public:
+ ObjC2CategoryListSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : FixedSizeSection<A>(parser, f, s) {}
+protected:
+ typedef typename A::P::uint_t pint_t;
+
+ virtual ld::Atom::Alignment alignmentForAddress(pint_t addr) { return ld::Atom::Alignment(log2(sizeof(pint_t))); }
+ virtual ld::Atom::Scope scopeAtAddress(Parser<A>& parser, pint_t addr) { return ld::Atom::scopeTranslationUnit; }
+ virtual const char* unlabeledAtomName(Parser<A>&, pint_t) { return "objc-cat-list"; }
+ virtual pint_t elementSizeAtAddress(pint_t addr) { return sizeof(pint_t); }
+ virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineNever; }
+ virtual bool ignoreLabel(const char* label) { return true; }
+private:
+ const char* targetClassName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+};
+
+
+template <typename A>
+class PointerToCStringSection : public FixedSizeSection<A>
+{
+public:
+ PointerToCStringSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : FixedSizeSection<A>(parser, f, s) {}
+protected:
+ typedef typename A::P::uint_t pint_t;
+
+ virtual ld::Atom::Alignment alignmentForAddress(pint_t addr) { return ld::Atom::Alignment(log2(sizeof(pint_t))); }
+ virtual const char* unlabeledAtomName(Parser<A>&, pint_t) { return "pointer-to-literal-cstring"; }
+ virtual pint_t elementSizeAtAddress(pint_t addr) { return sizeof(pint_t); }
+ virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineByNameAndReferences; }
+ virtual bool ignoreLabel(const char* label) { return true; }
+ virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+ virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const;
+ virtual const char* targetCString(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+};
+
+
+template <typename A>
+class Objc1ClassReferences : public PointerToCStringSection<A>
+{
+public:
+ Objc1ClassReferences(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : PointerToCStringSection<A>(parser, f, s) {}
+
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+
+ virtual const char* unlabeledAtomName(Parser<A>&, pint_t) { return "pointer-to-literal-objc-class-name"; }
+ virtual bool addRelocFixup(class Parser<A>& parser, const macho_relocation_info<P>*);
+ virtual const char* targetCString(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+};
+
+
+template <typename A>
+class CStringSection : public ImplicitSizeSection<A>
+{
+public:
+ CStringSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : ImplicitSizeSection<A>(parser, f, s) {}
+protected:
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+
+ virtual ld::Atom::ContentType contentType() { return ld::Atom::typeCString; }
+ virtual Atom<A>* findAtomByAddress(pint_t addr);
+ virtual const char* unlabeledAtomName(Parser<A>&, pint_t) { return "cstring"; }
+ virtual pint_t elementSizeAtAddress(pint_t addr);
+ virtual bool ignoreLabel(const char* label);
+ virtual bool useElementAt(Parser<A>& parser,
+ struct Parser<A>::LabelAndCFIBreakIterator& it, pint_t addr);
+ virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineByNameAndContent; }
+ virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+ virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const;
+
+};
+
+
+template <typename A>
+class UTF16StringSection : public SymboledSection<A>
+{
+public:
+ UTF16StringSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : SymboledSection<A>(parser, f, s) {}
+protected:
+ typedef typename A::P::uint_t pint_t;
+ typedef typename A::P P;
+
+ virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineByNameAndContent; }
+ virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+ virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const;
+};
+
+
+//
+// Atoms in mach-o files
+//
+template <typename A>
+class Atom : public ld::Atom
+{
+public:
+ // overrides of ld::Atom
+ virtual ld::File* file() const { return §().file(); }
+ virtual const char* translationUnitSource() const
+ { return sect().file().translationUnitSource(); }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return _size; }
+ virtual uint64_t objectAddress() const { return _objAddress; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+ virtual const uint8_t* rawContentPointer() const { return contentPointer(); }
+ virtual unsigned long contentHash(const ld::IndirectBindingTable& ind) const
+ { if ( _hash == 0 ) _hash = sect().contentHash(this, ind); return _hash; }
+ virtual bool canCoalesceWith(const ld::Atom& rhs, const ld::IndirectBindingTable& ind) const
+ { return sect().canCoalesceWith(this, rhs, ind); }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &machofile()._fixups[_fixupsStartIndex]; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &machofile()._fixups[_fixupsStartIndex+_fixupsCount]; }
+ virtual ld::Atom::UnwindInfo::iterator beginUnwind() const { return &machofile()._unwindInfos[_unwindInfoStartIndex]; }
+ virtual ld::Atom::UnwindInfo::iterator endUnwind() const { return &machofile()._unwindInfos[_unwindInfoStartIndex+_unwindInfoCount]; }
+ virtual ld::Atom::LineInfo::iterator beginLineInfo() const{ return &machofile()._lineInfos[_lineInfoStartIndex]; }
+ virtual ld::Atom::LineInfo::iterator endLineInfo() const { return &machofile()._lineInfos[_lineInfoStartIndex+_lineInfoCount]; }
+
+private:
+
+ enum { kFixupStartIndexBits = 32,
+ kLineInfoStartIndexBits = 32,
+ kUnwindInfoStartIndexBits = 24,
+ kFixupCountBits = 24,
+ kLineInfoCountBits = 12,
+ kUnwindInfoCountBits = 4
+ }; // must sum to 128
+
+public:
+ // methods for all atoms from mach-o object file
+ Section<A>& sect() const { return (Section<A>&)section(); }
+ File<A>& machofile() const { return ((Section<A>*)(this->_section))->file(); }
+ void setFixupsRange(uint32_t s, uint32_t c);
+ void setUnwindInfoRange(uint32_t s, uint32_t c);
+ void extendUnwindInfoRange();
+ void setLineInfoRange(uint32_t s, uint32_t c);
+ bool roomForMoreLineInfoCount() { return (_lineInfoCount < ((1<<kLineInfoCountBits)-1)); }
+ void incrementLineInfoCount() { assert(roomForMoreLineInfoCount()); ++_lineInfoCount; }
+ void incrementFixupCount() { if (_fixupsCount == ((1 << kFixupCountBits)-1))
+ throwf("too may fixups in %s", name()); ++_fixupsCount; }
+ const uint8_t* contentPointer() const;
+ uint32_t fixupCount() const { return _fixupsCount; }
+ void verifyAlignment() const;
+
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+ // constuct via all attributes
+ Atom(Section<A>& sct, const char* nm, pint_t addr, uint64_t sz,
+ ld::Atom::Definition d, ld::Atom::Combine c, ld::Atom::Scope s,
+ ld::Atom::ContentType ct, ld::Atom::SymbolTableInclusion i,
+ bool dds, bool thumb, bool al, ld::Atom::Alignment a)
+ : ld::Atom((ld::Section&)sct, d, c, s, ct, i, dds, thumb, al, a),
+ _size(sz), _objAddress(addr), _name(nm), _hash(0),
+ _fixupsStartIndex(0), _lineInfoStartIndex(0),
+ _unwindInfoStartIndex(0), _fixupsCount(0),
+ _lineInfoCount(0), _unwindInfoCount(0) { }
+ // construct via symbol table entry
+ Atom(Section<A>& sct, Parser<A>& parser, const macho_nlist<P>& sym,
+ uint64_t sz, bool alias=false)
+ : ld::Atom((ld::Section&)sct, parser.definitionFromSymbol(sym),
+ parser.combineFromSymbol(sym), parser.scopeFromSymbol(sym),
+ parser.resolverFromSymbol(sym) ? ld::Atom::typeResolver : sct.contentType(),
+ parser.inclusionFromSymbol(sym),
+ parser.dontDeadStripFromSymbol(sym) || sct.dontDeadStrip(),
+ parser.isThumbFromSymbol(sym), alias,
+ sct.alignmentForAddress(sym.n_value())),
+ _size(sz), _objAddress(sym.n_value()),
+ _name(parser.nameFromSymbol(sym)), _hash(0),
+ _fixupsStartIndex(0), _lineInfoStartIndex(0),
+ _unwindInfoStartIndex(0), _fixupsCount(0),
+ _lineInfoCount(0), _unwindInfoCount(0) {
+ // <rdar://problem/6783167> support auto-hidden weak symbols
+ if ( _scope == ld::Atom::scopeGlobal &&
+ (sym.n_desc() & (N_WEAK_DEF|N_WEAK_REF)) == (N_WEAK_DEF|N_WEAK_REF) )
+ this->setAutoHide();
+ this->verifyAlignment();
+ }
+
+private:
+ friend class Parser<A>;
+ friend class Section<A>;
+ friend class CStringSection<A>;
+ friend class AbsoluteSymbolSection<A>;
+
+ pint_t _size;
+ pint_t _objAddress;
+ const char* _name;
+ mutable unsigned long _hash;
+
+ uint64_t _fixupsStartIndex : kFixupStartIndexBits,
+ _lineInfoStartIndex : kLineInfoStartIndexBits,
+ _unwindInfoStartIndex : kUnwindInfoStartIndexBits,
+ _fixupsCount : kFixupCountBits,
+ _lineInfoCount : kLineInfoCountBits,
+ _unwindInfoCount : kUnwindInfoCountBits;
+
+};
+
+
+
+template <typename A>
+void Atom<A>::setFixupsRange(uint32_t startIndex, uint32_t count)
+{
+ if ( count >= (1 << kFixupCountBits) )
+ throwf("too many fixups in function %s", this->name());
+ if ( startIndex >= (1 << kFixupStartIndexBits) )
+ throwf("too many fixups in file");
+ assert(((startIndex+count) <= sect().file()._fixups.size()) && "fixup index out of range");
+ _fixupsStartIndex = startIndex;
+ _fixupsCount = count;
+}
+
+template <typename A>
+void Atom<A>::setUnwindInfoRange(uint32_t startIndex, uint32_t count)
+{
+ if ( count >= (1 << kUnwindInfoCountBits) )
+ throwf("too many compact unwind infos in function %s", this->name());
+ if ( startIndex >= (1 << kUnwindInfoStartIndexBits) )
+ throwf("too many compact unwind infos (%d) in file", startIndex);
+ assert((startIndex+count) <= sect().file()._unwindInfos.size() && "unwindinfo index out of range");
+ _unwindInfoStartIndex = startIndex;
+ _unwindInfoCount = count;
+}
+
+template <typename A>
+void Atom<A>::extendUnwindInfoRange()
+{
+ if ( _unwindInfoCount+1 >= (1 << kUnwindInfoCountBits) )
+ throwf("too many compact unwind infos in function %s", this->name());
+ _unwindInfoCount += 1;
+}
+
+template <typename A>
+void Atom<A>::setLineInfoRange(uint32_t startIndex, uint32_t count)
+{
+ assert((count < (1 << kLineInfoCountBits)) && "too many line infos");
+ assert((startIndex+count) < sect().file()._lineInfos.size() && "line info index out of range");
+ _lineInfoStartIndex = startIndex;
+ _lineInfoCount = count;
+}
+
+template <typename A>
+const uint8_t* Atom<A>::contentPointer() const
+{
+ const macho_section<P>* sct = this->sect().machoSection();
+ uint32_t fileOffset = sct->offset() - sct->addr() + this->_objAddress;
+ return this->sect().file().fileContent()+fileOffset;
+}
+
+
+template <typename A>
+void Atom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ // copy base bytes
+ if ( this->contentType() == ld::Atom::typeZeroFill ) {
+ bzero(buffer, _size);
+ }
+ else if ( _size != 0 ) {
+ memcpy(buffer, this->contentPointer(), _size);
+ }
+}
+
+template <>
+void Atom<arm>::verifyAlignment() const
+{
+ if ( (this->section().type() == ld::Section::typeCode) && ! isThumb() ) {
+ if ( ((_objAddress % 4) != 0) || (this->alignment().powerOf2 < 2) )
+ warning("ARM function not 4-byte aligned: %s from %s", this->name(), this->file()->path());
+ }
+}
+
+template <typename A>
+void Atom<A>::verifyAlignment() const
+{
+}
+
+
+template <typename A>
+class Parser
+{
+public:
+ static bool validFile(const uint8_t* fileContent, bool subtypeMustMatch=false,
+ cpu_subtype_t subtype=0);
+ static const char* fileKind(const uint8_t* fileContent);
+ static bool hasObjC2Categories(const uint8_t* fileContent);
+ static bool hasObjC1Categories(const uint8_t* fileContent);
+ static ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength,
+ const char* path, time_t modTime, ld::File::Ordinal ordinal,
+ const ParserOptions& opts) {
+ Parser p(fileContent, fileLength, path, modTime,
+ ordinal, opts.convertUnwindInfo);
+ return p.parse(opts);
+ }
+
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ struct SourceLocation {
+ SourceLocation() {}
+ SourceLocation(Atom<A>* a, uint32_t o) : atom(a), offsetInAtom(o) {}
+ Atom<A>* atom;
+ uint32_t offsetInAtom;
+ };
+
+ struct TargetDesc {
+ Atom<A>* atom;
+ const char* name; // only used if targetAtom is NULL
+ int64_t addend;
+ bool weakImport; // only used if targetAtom is NULL
+ };
+
+ struct FixupInAtom {
+ FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, Atom<A>* target) :
+ fixup(src.offsetInAtom, c, k, target), atom(src.atom) { src.atom->incrementFixupCount(); }
+
+ FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, ld::Fixup::TargetBinding b, Atom<A>* target) :
+ fixup(src.offsetInAtom, c, k, b, target), atom(src.atom) { src.atom->incrementFixupCount(); }
+
+ FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, bool wi, const char* name) :
+ fixup(src.offsetInAtom, c, k, wi, name), atom(src.atom) { src.atom->incrementFixupCount(); }
+
+ FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, ld::Fixup::TargetBinding b, const char* name) :
+ fixup(src.offsetInAtom, c, k, b, name), atom(src.atom) { src.atom->incrementFixupCount(); }
+
+ FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, uint64_t addend) :
+ fixup(src.offsetInAtom, c, k, addend), atom(src.atom) { src.atom->incrementFixupCount(); }
+
+ FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k) :
+ fixup(src.offsetInAtom, c, k, (uint64_t)0), atom(src.atom) { src.atom->incrementFixupCount(); }
+
+ ld::Fixup fixup;
+ Atom<A>* atom;
+ };
+
+ void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, Atom<A>* target) {
+ _allFixups.push_back(FixupInAtom(src, c, k, target));
+ }
+
+ void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, ld::Fixup::TargetBinding b, Atom<A>* target) {
+ _allFixups.push_back(FixupInAtom(src, c, k, b, target));
+ }
+
+ void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, bool wi, const char* name) {
+ _allFixups.push_back(FixupInAtom(src, c, k, wi, name));
+ }
+
+ void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, ld::Fixup::TargetBinding b, const char* name) {
+ _allFixups.push_back(FixupInAtom(src, c, k, b, name));
+ }
+
+ void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, uint64_t addend) {
+ _allFixups.push_back(FixupInAtom(src, c, k, addend));
+ }
+
+ void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k) {
+ _allFixups.push_back(FixupInAtom(src, c, k));
+ }
+
+
+ uint32_t symbolCount() { return _symbolCount; }
+ uint32_t indirectSymbol(uint32_t indirectIndex);
+ const macho_nlist<P>& symbolFromIndex(uint32_t index);
+ const char* nameFromSymbol(const macho_nlist<P>& sym);
+ ld::Atom::Scope scopeFromSymbol(const macho_nlist<P>& sym);
+ static ld::Atom::Definition definitionFromSymbol(const macho_nlist<P>& sym);
+ static ld::Atom::Combine combineFromSymbol(const macho_nlist<P>& sym);
+ ld::Atom::SymbolTableInclusion inclusionFromSymbol(const macho_nlist<P>& sym);
+ static bool dontDeadStripFromSymbol(const macho_nlist<P>& sym);
+ static bool isThumbFromSymbol(const macho_nlist<P>& sym);
+ static bool weakImportFromSymbol(const macho_nlist<P>& sym);
+ static bool resolverFromSymbol(const macho_nlist<P>& sym);
+ uint32_t symbolIndexFromIndirectSectionAddress(pint_t,const macho_section<P>*);
+ const macho_section<P>* firstMachOSection() { return _sectionsStart; }
+ const macho_section<P>* machOSectionFromSectionIndex(uint32_t index);
+ uint32_t machOSectionCount() { return _machOSectionsCount; }
+ uint32_t undefinedStartIndex() { return _undefinedStartIndex; }
+ uint32_t undefinedEndIndex() { return _undefinedEndIndex; }
+ void addFixup(FixupInAtom f) { _allFixups.push_back(f); }
+ Section<A>* sectionForNum(unsigned int sectNum);
+ Section<A>* sectionForAddress(pint_t addr);
+ Atom<A>* findAtomByAddress(pint_t addr);
+ Atom<A>* findAtomByAddressOrNullIfStub(pint_t addr);
+ Atom<A>* findAtomByAddressOrLocalTargetOfStub(pint_t addr, uint32_t* offsetInAtom);
+ Atom<A>* findAtomByName(const char* name); // slow!
+ void findTargetFromAddress(pint_t addr, TargetDesc& target);
+ void findTargetFromAddress(pint_t baseAddr, pint_t addr, TargetDesc& target);
+ void findTargetFromAddressAndSectionNum(pint_t addr, unsigned int sectNum,
+ TargetDesc& target);
+ uint32_t tentativeDefinitionCount() { return _tentativeDefinitionCount; }
+ uint32_t absoluteSymbolCount() { return _absoluteSymbolCount; }
+
+ bool hasStubsSection() { return (_stubsSectionNum != 0); }
+ unsigned int stubsSectionNum() { return _stubsSectionNum; }
+ void addDtraceExtraInfos(const SourceLocation& src, const char* provider);
+ const char* scanSymbolTableForAddress(uint64_t addr);
+ bool convertUnwindInfo() { return _convertUnwindInfo; }
+ bool hasDataInCodeLabels() { return _hasDataInCodeLabels; }
+
+ macho_data_in_code_entry<P>* dataInCodeStart() { return _dataInCodeStart; }
+ macho_data_in_code_entry<P>* dataInCodeEnd() { return _dataInCodeEnd; }
+
+ void addFixups(const SourceLocation& src, ld::Fixup::Kind kind, const TargetDesc& target);
+ void addFixups(const SourceLocation& src, ld::Fixup::Kind kind, const TargetDesc& target, const TargetDesc& picBase);
+
+
+
+ struct LabelAndCFIBreakIterator {
+ typedef typename CFISection<A>::CFI_Atom_Info CFI_Atom_Info;
+ LabelAndCFIBreakIterator(const uint32_t* ssa, uint32_t ssc, const pint_t* cfisa,
+ uint32_t cfisc, bool ols)
+ : sortedSymbolIndexes(ssa), sortedSymbolCount(ssc), cfiStartsArray(cfisa),
+ cfiStartsCount(cfisc), fileHasOverlappingSymbols(ols),
+ newSection(false), cfiIndex(0), symIndex(0) {}
+ bool next(Parser<A>& parser, uint32_t sectNum, pint_t startAddr, pint_t endAddr,
+ pint_t* addr, pint_t* size, const macho_nlist<P>** sym);
+ pint_t peek(Parser<A>& parser, pint_t startAddr, pint_t endAddr);
+ void beginSection() { newSection = true; symIndex = 0; }
+
+ const uint32_t* const sortedSymbolIndexes;
+ const uint32_t sortedSymbolCount;
+ const pint_t* cfiStartsArray;
+ const uint32_t cfiStartsCount;
+ const bool fileHasOverlappingSymbols;
+ bool newSection;
+ uint32_t cfiIndex;
+ uint32_t symIndex;
+ };
+
+ struct CFI_CU_InfoArrays {
+ typedef typename CFISection<A>::CFI_Atom_Info CFI_Atom_Info;
+ typedef typename CUSection<A>::Info CU_Info;
+ CFI_CU_InfoArrays(const CFI_Atom_Info* cfiAr, uint32_t cfiC, CU_Info* cuAr, uint32_t cuC)
+ : cfiArray(cfiAr), cuArray(cuAr), cfiCount(cfiC), cuCount(cuC) {}
+ const CFI_Atom_Info* const cfiArray;
+ CU_Info* const cuArray;
+ const uint32_t cfiCount;
+ const uint32_t cuCount;
+ };
+
+
+
+private:
+ friend class Section<A>;
+
+ enum SectionType { sectionTypeIgnore, sectionTypeLiteral4, sectionTypeLiteral8, sectionTypeLiteral16,
+ sectionTypeNonLazy, sectionTypeCFI, sectionTypeCString, sectionTypeCStringPointer,
+ sectionTypeUTF16Strings, sectionTypeCFString, sectionTypeObjC2ClassRefs, typeObjC2CategoryList,
+ sectionTypeObjC1Classes, sectionTypeSymboled, sectionTypeObjC1ClassRefs,
+ sectionTypeTentativeDefinitions, sectionTypeAbsoluteSymbols, sectionTypeTLVDefs,
+ sectionTypeCompactUnwind };
+
+ template <typename P>
+ struct MachOSectionAndSectionClass
+ {
+ const macho_section<P>* sect;
+ SectionType type;
+
+ static int sorter(const void* l, const void* r) {
+ const MachOSectionAndSectionClass<P>* left = (MachOSectionAndSectionClass<P>*)l;
+ const MachOSectionAndSectionClass<P>* right = (MachOSectionAndSectionClass<P>*)r;
+ int64_t diff = left->sect->addr() - right->sect->addr();
+ if ( diff == 0 )
+ return 0;
+ if ( diff < 0 )
+ return -1;
+ else
+ return 1;
+ }
+ };
+
+ struct ParserAndSectionsArray { Parser* parser; const uint32_t* sortedSectionsArray; };
+
+
+ Parser(const uint8_t* fileContent, uint64_t fileLength,
+ const char* path, time_t modTime,
+ ld::File::Ordinal ordinal, bool convertUnwindInfo);
+ ld::relocatable::File* parse(const ParserOptions& opts);
+ uint8_t loadCommandSizeMask();
+ bool parseLoadCommands();
+ void makeSections();
+ void prescanSymbolTable();
+ void makeSortedSymbolsArray(uint32_t symArray[], const uint32_t sectionArray[]);
+ void makeSortedSectionsArray(uint32_t array[]);
+ static int pointerSorter(const void* l, const void* r);
+ static int symbolIndexSorter(void* extra, const void* l, const void* r);
+ static int sectionIndexSorter(void* extra, const void* l, const void* r);
+
+ void parseDebugInfo();
+ void parseStabs();
+ static bool isConstFunStabs(const char *stabStr);
+ bool read_comp_unit(const char ** name, const char ** comp_dir,
+ uint64_t *stmt_list);
+ const char* getDwarfString(uint64_t form, const uint8_t* p);
+ bool skip_form(const uint8_t ** offset, const uint8_t * end,
+ uint64_t form, uint8_t addr_size, bool dwarf64);
+
+
+ // filled in by constructor
+ const uint8_t* _fileContent;
+ uint32_t _fileLength;
+ const char* _path;
+ time_t _modTime;
+ ld::File::Ordinal _ordinal;
+
+ // filled in by parseLoadCommands()
+ File<A>* _file;
+ const macho_nlist<P>* _symbols;
+ uint32_t _symbolCount;
+ const char* _strings;
+ uint32_t _stringsSize;
+ const uint32_t* _indirectTable;
+ uint32_t _indirectTableCount;
+ uint32_t _undefinedStartIndex;
+ uint32_t _undefinedEndIndex;
+ const macho_section<P>* _sectionsStart;
+ uint32_t _machOSectionsCount;
+ bool _hasUUID;
+ macho_data_in_code_entry<P>* _dataInCodeStart;
+ macho_data_in_code_entry<P>* _dataInCodeEnd;
+
+ // filled in by parse()
+ CFISection<A>* _EHFrameSection;
+ CUSection<A>* _compactUnwindSection;
+ AbsoluteSymbolSection<A>* _absoluteSection;
+ uint32_t _tentativeDefinitionCount;
+ uint32_t _absoluteSymbolCount;
+ uint32_t _symbolsInSections;
+ bool _hasLongBranchStubs;
+ bool _AppleObjc; // FSF has objc that uses different data layout
+ bool _overlappingSymbols;
+ bool _convertUnwindInfo;
+ bool _hasDataInCodeLabels;
+ unsigned int _stubsSectionNum;
+ const macho_section<P>* _stubsMachOSection;
+ std::vector<const char*> _dtraceProviderInfo;
+ std::vector<FixupInAtom> _allFixups;
+};
+
+
+
+template <typename A>
+Parser<A>::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime,
+ ld::File::Ordinal ordinal, bool convertDUI)
+ : _fileContent(fileContent), _fileLength(fileLength), _path(path), _modTime(modTime),
+ _ordinal(ordinal), _file(NULL),
+ _symbols(NULL), _symbolCount(0), _strings(NULL), _stringsSize(0),
+ _indirectTable(NULL), _indirectTableCount(0),
+ _undefinedStartIndex(0), _undefinedEndIndex(0),
+ _sectionsStart(NULL), _machOSectionsCount(0), _hasUUID(false),
+ _dataInCodeStart(NULL), _dataInCodeEnd(NULL),
+ _EHFrameSection(NULL), _compactUnwindSection(NULL), _absoluteSection(NULL),
+ _tentativeDefinitionCount(0), _absoluteSymbolCount(0),
+ _symbolsInSections(0), _hasLongBranchStubs(false), _AppleObjc(false),
+ _overlappingSymbols(false), _convertUnwindInfo(convertDUI), _hasDataInCodeLabels(false),
+ _stubsSectionNum(0), _stubsMachOSection(NULL)
+{
+}
+
+
+template <>
+bool Parser<x86>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_I386 )
+ return false;
+ if ( header->filetype() != MH_OBJECT )
+ return false;
+ return true;
+}
+
+template <>
+bool Parser<x86_64>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_X86_64 )
+ return false;
+ if ( header->filetype() != MH_OBJECT )
+ return false;
+ return true;
+}
+
+template <>
+bool Parser<arm>::validFile(const uint8_t* fileContent, bool subtypeMustMatch, cpu_subtype_t subtype)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_ARM )
+ return false;
+ if ( header->filetype() != MH_OBJECT )
+ return false;
+ if ( subtypeMustMatch ) {
+ if ( (cpu_subtype_t)header->cpusubtype() == subtype )
+ return true;
+ // hack until libcc_kext.a is made fat
+ if ( header->cpusubtype() == CPU_SUBTYPE_ARM_ALL )
+ return true;
+ return false;
+ }
+ return true;
+}
+
+
+
+template <>
+const char* Parser<x86>::fileKind(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return NULL;
+ if ( header->cputype() != CPU_TYPE_I386 )
+ return NULL;
+ return "i386";
+}
+
+template <>
+const char* Parser<x86_64>::fileKind(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return NULL;
+ if ( header->cputype() != CPU_TYPE_X86_64 )
+ return NULL;
+ return "x86_64";
+}
+
+template <>
+const char* Parser<arm>::fileKind(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return NULL;
+ if ( header->cputype() != CPU_TYPE_ARM )
+ return NULL;
+ for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+ if ( (t->cpuType == CPU_TYPE_ARM) && ((cpu_subtype_t)header->cpusubtype() == t->cpuSubType) ) {
+ return t->archName;
+ }
+ }
+ return "arm???";
+}
+
+
+template <typename A>
+bool Parser<A>::hasObjC2Categories(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ const uint32_t cmd_count = header->ncmds();
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
+ const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* segment = (macho_segment_command<P>*)cmd;
+ const macho_section<P>* sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
+ for (uint32_t si=0; si < segment->nsects(); ++si) {
+ const macho_section<P>* sect = §ionsStart[si];
+ if ( (sect->size() > 0)
+ && (strcmp(sect->sectname(), "__objc_catlist") == 0)
+ && (strcmp(sect->segname(), "__DATA") == 0) ) {
+ return true;
+ }
+ }
+ }
+ cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+ if ( cmd > cmdsEnd )
+ throwf("malformed mach-o file, load command #%d is outside size of load commands", i);
+ }
+ return false;
+}
+
+
+template <typename A>
+bool Parser<A>::hasObjC1Categories(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ const uint32_t cmd_count = header->ncmds();
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
+ const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* segment = (macho_segment_command<P>*)cmd;
+ const macho_section<P>* sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
+ for (uint32_t si=0; si < segment->nsects(); ++si) {
+ const macho_section<P>* sect = §ionsStart[si];
+ if ( (sect->size() > 0)
+ && (strcmp(sect->sectname(), "__category") == 0)
+ && (strcmp(sect->segname(), "__OBJC") == 0) ) {
+ return true;
+ }
+ }
+ }
+ cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+ if ( cmd > cmdsEnd )
+ throwf("malformed mach-o file, load command #%d is outside size of load commands", i);
+ }
+ return false;
+}
+
+template <typename A>
+int Parser<A>::pointerSorter(const void* l, const void* r)
+{
+ // sort references by address
+ const pint_t* left = (pint_t*)l;
+ const pint_t* right = (pint_t*)r;
+ return (*left - *right);
+}
+
+template <typename A>
+typename A::P::uint_t Parser<A>::LabelAndCFIBreakIterator::peek(Parser<A>& parser, pint_t startAddr, pint_t endAddr)
+{
+ pint_t symbolAddr;
+ if ( symIndex < sortedSymbolCount )
+ symbolAddr = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]).n_value();
+ else
+ symbolAddr = endAddr;
+ pint_t cfiAddr;
+ if ( cfiIndex < cfiStartsCount )
+ cfiAddr = cfiStartsArray[cfiIndex];
+ else
+ cfiAddr = endAddr;
+ if ( (cfiAddr < symbolAddr) && (cfiAddr >= startAddr) ) {
+ if ( cfiAddr < endAddr )
+ return cfiAddr;
+ else
+ return endAddr;
+ }
+ else {
+ if ( symbolAddr < endAddr )
+ return symbolAddr;
+ else
+ return endAddr;
+ }
+}
+
+//
+// Parses up a section into chunks based on labels and CFI information.
+// Each call returns the next chunk address and size, and (if the break
+// was becuase of a label, the symbol). Returns false when no more chunks.
+//
+template <typename A>
+bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, uint32_t sectNum, pint_t startAddr, pint_t endAddr,
+ pint_t* addr, pint_t* size, const macho_nlist<P>** symbol)
+{
+ // may not be a label on start of section, but need atom demarcation there
+ if ( newSection ) {
+ newSection = false;
+ // advance symIndex until we get to the first label at or past the start of this section
+ while ( symIndex < sortedSymbolCount ) {
+ const macho_nlist<P>& sym = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]);
+ pint_t nextSymbolAddr = sym.n_value();
+ //fprintf(stderr, "sectNum=%d, nextSymbolAddr=0x%08llX, name=%s\n", sectNum, (uint64_t)nextSymbolAddr, parser.nameFromSymbol(sym));
+ if ( (nextSymbolAddr > startAddr) || ((nextSymbolAddr == startAddr) && (sym.n_sect() == sectNum)) )
+ break;
+ ++symIndex;
+ }
+ if ( symIndex < sortedSymbolCount ) {
+ const macho_nlist<P>& sym = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]);
+ pint_t nextSymbolAddr = sym.n_value();
+ // if next symbol found is not in this section
+ if ( sym.n_sect() != sectNum ) {
+ // check for CFI break instead of symbol break
+ if ( cfiIndex < cfiStartsCount ) {
+ pint_t nextCfiAddr = cfiStartsArray[cfiIndex];
+ if ( nextCfiAddr < endAddr ) {
+ // use cfi
+ ++cfiIndex;
+ *addr = nextCfiAddr;
+ *size = peek(parser, startAddr, endAddr) - nextCfiAddr;
+ *symbol = NULL;
+ return true;
+ }
+ }
+ *addr = startAddr;
+ *size = endAddr - startAddr;
+ *symbol = NULL;
+ if ( startAddr == endAddr )
+ return false; // zero size section
+ else
+ return true; // whole section is one atom with no label
+ }
+ // if also CFI break here, eat it
+ if ( cfiIndex < cfiStartsCount ) {
+ if ( cfiStartsArray[cfiIndex] == nextSymbolAddr )
+ ++cfiIndex;
+ }
+ if ( nextSymbolAddr == startAddr ) {
+ // label at start of section, return it as chunk
+ ++symIndex;
+ *addr = startAddr;
+ *size = peek(parser, startAddr, endAddr) - startAddr;
+ *symbol = &sym;
+ return true;
+ }
+ // return chunk before first symbol
+ *addr = startAddr;
+ *size = nextSymbolAddr - startAddr;
+ *symbol = NULL;
+ return true;
+ }
+ // no symbols left in whole file, so entire section is one chunk
+ *addr = startAddr;
+ *size = endAddr - startAddr;
+ *symbol = NULL;
+ if ( startAddr == endAddr )
+ return false; // zero size section
+ else
+ return true; // whole section is one atom with no label
+ }
+
+ while ( (symIndex < sortedSymbolCount) && (cfiIndex < cfiStartsCount) ) {
+ const macho_nlist<P>& sym = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]);
+ pint_t nextSymbolAddr = sym.n_value();
+ pint_t nextCfiAddr = cfiStartsArray[cfiIndex];
+ if ( nextSymbolAddr < nextCfiAddr ) {
+ if ( nextSymbolAddr >= endAddr )
+ return false;
+ ++symIndex;
+ if ( nextSymbolAddr < startAddr )
+ continue;
+ *addr = nextSymbolAddr;
+ *size = peek(parser, startAddr, endAddr) - nextSymbolAddr;
+ *symbol = &sym;
+ return true;
+ }
+ else if ( nextCfiAddr < nextSymbolAddr ) {
+ if ( nextCfiAddr >= endAddr )
+ return false;
+ ++cfiIndex;
+ if ( nextCfiAddr < startAddr )
+ continue;
+ *addr = nextCfiAddr;
+ *size = peek(parser, startAddr, endAddr) - nextCfiAddr;
+ *symbol = NULL;
+ return true;
+ }
+ else {
+ if ( nextCfiAddr >= endAddr )
+ return false;
+ ++symIndex;
+ ++cfiIndex;
+ if ( nextCfiAddr < startAddr )
+ continue;
+ *addr = nextCfiAddr;
+ *size = peek(parser, startAddr, endAddr) - nextCfiAddr;
+ *symbol = &sym;
+ return true;
+ }
+ }
+ while ( symIndex < sortedSymbolCount ) {
+ const macho_nlist<P>& sym = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]);
+ pint_t nextSymbolAddr = sym.n_value();
+ // if next symbol found is not in this section, then done with iteration
+ if ( sym.n_sect() != sectNum )
+ return false;
+ ++symIndex;
+ if ( nextSymbolAddr < startAddr )
+ continue;
+ *addr = nextSymbolAddr;
+ *size = peek(parser, startAddr, endAddr) - nextSymbolAddr;
+ *symbol = &sym;
+ return true;
+ }
+ while ( cfiIndex < cfiStartsCount ) {
+ pint_t nextCfiAddr = cfiStartsArray[cfiIndex];
+ if ( nextCfiAddr >= endAddr )
+ return false;
+ ++cfiIndex;
+ if ( nextCfiAddr < startAddr )
+ continue;
+ *addr = nextCfiAddr;
+ *size = peek(parser, startAddr, endAddr) - nextCfiAddr;
+ *symbol = NULL;
+ return true;
+ }
+ return false;
+}
+
+
+
+template <typename A>
+ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
+{
+ // create file object
+ _file = new File<A>(_path, _modTime, _fileContent, _ordinal);
+
+ // respond to -t option
+ if ( opts.logAllFiles )
+ printf("%s\n", _path);
+
+ // parse start of mach-o file
+ if ( ! parseLoadCommands() )
+ return _file;
+
+ // make array of
+ uint32_t sortedSectionIndexes[_machOSectionsCount];
+ this->makeSortedSectionsArray(sortedSectionIndexes);
+
+ // make symbol table sorted by address
+ this->prescanSymbolTable();
+ uint32_t sortedSymbolIndexes[_symbolsInSections];
+ this->makeSortedSymbolsArray(sortedSymbolIndexes, sortedSectionIndexes);
+
+ // allocate Section<A> object for each mach-o section
+ makeSections();
+
+ // if it exists, do special early parsing of __compact_unwind section
+ uint32_t countOfCUs = 0;
+ if ( _compactUnwindSection != NULL )
+ countOfCUs = _compactUnwindSection->count();
+ uint8_t cuInfoBuffer[sizeof(typename CUSection<A>::Info) * countOfCUs];
+ typename CUSection<A>::Info* cuInfoArray = (typename CUSection<A>::Info*)cuInfoBuffer;
+ if ( countOfCUs != 0 )
+ _compactUnwindSection->parse(*this, countOfCUs, cuInfoArray);
+
+ // if it exists, do special early parsing of __eh_frame section
+ // stack allocate array of CFI_Atom_Info
+ uint32_t countOfCFIs = 0;
+ if ( _EHFrameSection != NULL )
+ countOfCFIs = _EHFrameSection->cfiCount();
+ typename CFISection<A>::CFI_Atom_Info cfiArray[countOfCFIs];
+ // stack allocate (if not too large) a copy of __eh_frame to apply relocations to
+ uint8_t* ehBuffer = NULL;
+ uint32_t stackAllocSize = 0;
+ if ( (countOfCFIs != 0) && _EHFrameSection->needsRelocating() ) {
+ uint32_t sectSize = _EHFrameSection->machoSection()->size();
+ if ( sectSize > 50*1024 )
+ ehBuffer = (uint8_t*)malloc(sectSize);
+ else
+ stackAllocSize = sectSize;
+ }
+ uint32_t ehStackBuffer[1+stackAllocSize/4]; // make 4-byte aligned stack bufffer
+ if ( ehBuffer == NULL )
+ ehBuffer = (uint8_t*)&ehStackBuffer;
+ uint32_t cfiStartsCount = 0;
+ if ( countOfCFIs != 0 ) {
+ _EHFrameSection->cfiParse(*this, ehBuffer, cfiArray, countOfCFIs);
+ // count functions and lsdas
+ for(uint32_t i=0; i < countOfCFIs; ++i) {
+ if ( cfiArray[i].isCIE )
+ continue;
+ //fprintf(stderr, "cfiArray[i].func = 0x%08llX, cfiArray[i].lsda = 0x%08llX, encoding=0x%08X\n",
+ // (uint64_t)cfiArray[i].u.fdeInfo.function.targetAddress,
+ // (uint64_t)cfiArray[i].u.fdeInfo.lsda.targetAddress,
+ // cfiArray[i].u.fdeInfo.compactUnwindInfo);
+ if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS )
+ ++cfiStartsCount;
+ if ( cfiArray[i].u.fdeInfo.lsda.targetAddress != CFI_INVALID_ADDRESS )
+ ++cfiStartsCount;
+ }
+ }
+ CFI_CU_InfoArrays cfis(cfiArray, countOfCFIs, cuInfoArray, countOfCUs);
+
+ // create sorted array of function starts and lsda starts
+ pint_t cfiStartsArray[cfiStartsCount];
+ uint32_t countOfFDEs = 0;
+ if ( countOfCFIs != 0 ) {
+ int index = 0;
+ for(uint32_t i=0; i < countOfCFIs; ++i) {
+ if ( cfiArray[i].isCIE )
+ continue;
+ if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS )
+ cfiStartsArray[index++] = cfiArray[i].u.fdeInfo.function.targetAddress;
+ if ( cfiArray[i].u.fdeInfo.lsda.targetAddress != CFI_INVALID_ADDRESS )
+ cfiStartsArray[index++] = cfiArray[i].u.fdeInfo.lsda.targetAddress;
+ ++countOfFDEs;
+ }
+ ::qsort(cfiStartsArray, cfiStartsCount, sizeof(pint_t), pointerSorter);
+ #ifndef NDEBUG
+ // scan for FDEs claming the same function
+ for(int i=1; i < index; ++i) {
+ assert( cfiStartsArray[i] != cfiStartsArray[i-1] );
+ }
+ #endif
+ }
+
+ Section<A>** sections = _file->_sectionsArray;
+ uint32_t sectionsCount = _file->_sectionsArrayCount;
+
+ // figure out how many atoms will be allocated and allocate
+ LabelAndCFIBreakIterator breakIterator(sortedSymbolIndexes, _symbolsInSections, cfiStartsArray,
+ cfiStartsCount, _overlappingSymbols);
+ uint32_t computedAtomCount = 0;
+ for (uint32_t i=0; i < sectionsCount; ++i ) {
+ breakIterator.beginSection();
+ uint32_t count = sections[i]->computeAtomCount(*this, breakIterator, cfis);
+ //const macho_section<P>* sect = sections[i]->machoSection();
+ //fprintf(stderr, "computed count=%u for section %s size=%llu\n", count, sect->sectname(), (sect != NULL) ? sect->size() : 0);
+ computedAtomCount += count;
+ }
+ //fprintf(stderr, "allocating %d atoms * sizeof(Atom<A>)=%ld, sizeof(ld::Atom)=%ld\n", computedAtomCount, sizeof(Atom<A>), sizeof(ld::Atom));
+ _file->_atomsArray = new uint8_t[computedAtomCount*sizeof(Atom<A>)];
+ _file->_atomsArrayCount = 0;
+
+ // have each section append atoms to _atomsArray
+ LabelAndCFIBreakIterator breakIterator2(sortedSymbolIndexes, _symbolsInSections, cfiStartsArray,
+ cfiStartsCount, _overlappingSymbols);
+ for (uint32_t i=0; i < sectionsCount; ++i ) {
+ uint8_t* atoms = _file->_atomsArray + _file->_atomsArrayCount*sizeof(Atom<A>);
+ breakIterator2.beginSection();
+ uint32_t count = sections[i]->appendAtoms(*this, atoms, breakIterator2, cfis);
+ //fprintf(stderr, "append count=%u for section %s/%s\n", count, sections[i]->machoSection()->segname(), sections[i]->machoSection()->sectname());
+ _file->_atomsArrayCount += count;
+ }
+ assert( _file->_atomsArrayCount == computedAtomCount && "more atoms allocated than expected");
+
+
+ // have each section add all fix-ups for its atoms
+ _allFixups.reserve(computedAtomCount*5);
+ for (uint32_t i=0; i < sectionsCount; ++i )
+ sections[i]->makeFixups(*this, cfis);
+
+ // assign fixups start offset for each atom
+ uint8_t* p = _file->_atomsArray;
+ uint32_t fixupOffset = 0;
+ for(int i=_file->_atomsArrayCount; i > 0; --i) {
+ Atom<A>* atom = (Atom<A>*)p;
+ atom->_fixupsStartIndex = fixupOffset;
+ fixupOffset += atom->_fixupsCount;
+ atom->_fixupsCount = 0;
+ p += sizeof(Atom<A>);
+ }
+ assert(fixupOffset == _allFixups.size());
+ _file->_fixups.reserve(fixupOffset);
+
+ // copy each fixup for each atom
+ for(typename std::vector<FixupInAtom>::iterator it=_allFixups.begin(); it != _allFixups.end(); ++it) {
+ uint32_t slot = it->atom->_fixupsStartIndex + it->atom->_fixupsCount;
+ _file->_fixups[slot] = it->fixup;
+ it->atom->_fixupsCount++;
+ }
+
+ // done with temp vector
+ _allFixups.clear();
+
+ // add unwind info
+ _file->_unwindInfos.reserve(countOfFDEs+countOfCUs);
+ for(uint32_t i=0; i < countOfCFIs; ++i) {
+ if ( cfiArray[i].isCIE )
+ continue;
+ if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS ) {
+ ld::Atom::UnwindInfo info;
+ info.startOffset = 0;
+ info.unwindInfo = cfiArray[i].u.fdeInfo.compactUnwindInfo;
+ _file->_unwindInfos.push_back(info);
+ Atom<A>* func = findAtomByAddress(cfiArray[i].u.fdeInfo.function.targetAddress);
+ func->setUnwindInfoRange(_file->_unwindInfos.size()-1, 1);
+ }
+ }
+ // apply compact infos in __LD,__compact_unwind section to each function
+ // if function also has dwarf unwind, CU will override it
+ Atom<A>* lastFunc = NULL;
+ uint32_t lastEnd = 0;
+ for(uint32_t i=0; i < countOfCUs; ++i) {
+ typename CUSection<A>::Info* info = &cuInfoArray[i];
+ assert(info->function != NULL);
+ ld::Atom::UnwindInfo ui;
+ ui.startOffset = info->functionStartAddress - info->function->objectAddress();
+ ui.unwindInfo = info->compactUnwindInfo;
+ _file->_unwindInfos.push_back(ui);
+ // if previous is for same function, extend range
+ if ( info->function == lastFunc ) {
+ if ( lastEnd != ui.startOffset ) {
+ if ( lastEnd < ui.startOffset )
+ warning("__LD,__compact_unwind entries for %s have a gap at offset 0x%0X", info->function->name(), lastEnd);
+ else
+ warning("__LD,__compact_unwind entries for %s overlap at offset 0x%0X", info->function->name(), lastEnd);
+ }
+ lastFunc->extendUnwindInfoRange();
+ }
+ else
+ info->function->setUnwindInfoRange(_file->_unwindInfos.size()-1, 1);
+ lastFunc = info->function;
+ lastEnd = ui.startOffset + info->rangeLength;
+ }
+
+ // parse dwarf debug info to get line info
+ this->parseDebugInfo();
+
+ return _file;
+}
+
+
+
+template <> uint8_t Parser<x86>::loadCommandSizeMask() { return 0x03; }
+template <> uint8_t Parser<x86_64>::loadCommandSizeMask() { return 0x07; }
+template <> uint8_t Parser<arm>::loadCommandSizeMask() { return 0x03; }
+
+template <typename A>
+bool Parser<A>::parseLoadCommands()
+{
+ const macho_header<P>* header = (const macho_header<P>*)_fileContent;
+
+ // set File attributes
+ _file->_canScatterAtoms = (header->flags() & MH_SUBSECTIONS_VIA_SYMBOLS);
+ _file->_cpuSubType = header->cpusubtype();
+
+ const macho_segment_command<P>* segment = NULL;
+ const uint8_t* const endOfFile = _fileContent + _fileLength;
+ const uint32_t cmd_count = header->ncmds();
+ // <rdar://problem/5394172> an empty .o file with zero load commands will crash linker
+ if ( cmd_count == 0 )
+ return false;
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
+ const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ uint32_t size = cmd->cmdsize();
+ if ( (size & this->loadCommandSizeMask()) != 0 )
+ throwf("load command #%d has a unaligned size", i);
+ const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
+ if ( endOfCmd > (uint8_t*)cmdsEnd )
+ throwf("load command #%d extends beyond the end of the load commands", i);
+ if ( endOfCmd > endOfFile )
+ throwf("load command #%d extends beyond the end of the file", i);
+ switch (cmd->cmd()) {
+ case LC_SYMTAB:
+ {
+ const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
+ _symbolCount = symtab->nsyms();
+ _symbols = (const macho_nlist<P>*)(_fileContent + symtab->symoff());
+ _strings = (char*)_fileContent + symtab->stroff();
+ _stringsSize = symtab->strsize();
+ if ( (symtab->symoff() + _symbolCount*sizeof(macho_nlist<P>)) > _fileLength )
+ throw "mach-o symbol table extends beyond end of file";
+ if ( (_strings + _stringsSize) > (char*)endOfFile )
+ throw "mach-o string pool extends beyond end of file";
+ if ( _indirectTable == NULL ) {
+ if ( _undefinedEndIndex == 0 ) {
+ _undefinedStartIndex = 0;
+ _undefinedEndIndex = symtab->nsyms();
+ }
+ }
+ }
+ break;
+ case LC_DYSYMTAB:
+ {
+ const macho_dysymtab_command<P>* dsymtab = (macho_dysymtab_command<P>*)cmd;
+ _indirectTable = (uint32_t*)(_fileContent + dsymtab->indirectsymoff());
+ _indirectTableCount = dsymtab->nindirectsyms();
+ if ( &_indirectTable[_indirectTableCount] > (uint32_t*)endOfFile )
+ throw "indirect symbol table extends beyond end of file";
+ _undefinedStartIndex = dsymtab->iundefsym();
+ _undefinedEndIndex = _undefinedStartIndex + dsymtab->nundefsym();
+ }
+ break;
+ case LC_UUID:
+ _hasUUID = true;
+ break;
+ case LC_DATA_IN_CODE:
+ {
+ const macho_linkedit_data_command<P>* dc = (macho_linkedit_data_command<P>*)cmd;
+ _dataInCodeStart = (macho_data_in_code_entry<P>*)(_fileContent + dc->dataoff());
+ _dataInCodeEnd = (macho_data_in_code_entry<P>*)(_fileContent + dc->dataoff() + dc->datasize());
+ if ( _dataInCodeEnd > (macho_data_in_code_entry<P>*)endOfFile )
+ throw "LC_DATA_IN_CODE table extends beyond end of file";
+ }
+ default:
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ if ( segment != NULL )
+ throw "more than one LC_SEGMENT found in object file";
+ segment = (macho_segment_command<P>*)cmd;
+ }
+ break;
+ }
+ cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+ if ( cmd > cmdsEnd )
+ throwf("malformed mach-o file, load command #%d is outside size of load commands", i);
+ }
+
+ // record range of sections
+ if ( segment == NULL )
+ throw "missing LC_SEGMENT";
+ _sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
+ _machOSectionsCount = segment->nsects();
+
+ return true;
+}
+
+
+template <typename A>
+void Parser<A>::prescanSymbolTable()
+{
+ _tentativeDefinitionCount = 0;
+ _absoluteSymbolCount = 0;
+ _symbolsInSections = 0;
+ _hasDataInCodeLabels = false;
+ for (uint32_t i=0; i < this->_symbolCount; ++i) {
+ const macho_nlist<P>& sym = symbolFromIndex(i);
+ // ignore stabs
+ if ( (sym.n_type() & N_STAB) != 0 )
+ continue;
+
+ // look at undefines
+ const char* symbolName = this->nameFromSymbol(sym);
+ if ( (sym.n_type() & N_TYPE) == N_UNDF ) {
+ if ( sym.n_value() != 0 ) {
+ // count tentative definitions
+ ++_tentativeDefinitionCount;
+ }
+ else if ( strncmp(symbolName, "___dtrace_", 10) == 0 ) {
+ // any undefined starting with __dtrace_*$ that is not ___dtrace_probe$* or ___dtrace_isenabled$*
+ // is extra provider info
+ if ( (strncmp(&symbolName[10], "probe$", 6) != 0) && (strncmp(&symbolName[10], "isenabled$", 10) != 0) ) {
+ _dtraceProviderInfo.push_back(symbolName);
+ }
+ }
+ continue;
+ }
+
+ // count absolute symbols
+ if ( (sym.n_type() & N_TYPE) == N_ABS ) {
+ const char* absName = this->nameFromSymbol(sym);
+ // ignore .objc_class_name_* symbols
+ if ( strncmp(absName, ".objc_class_name_", 17) == 0 ) {
+ _AppleObjc = true;
+ continue;
+ }
+ // ignore .objc_class_name_* symbols
+ if ( strncmp(absName, ".objc_category_name_", 20) == 0 )
+ continue;
+ // ignore empty *.eh symbols
+ if ( strcmp(&absName[strlen(absName)-3], ".eh") == 0 )
+ continue;
+ ++_absoluteSymbolCount;
+ }
+
+ // only look at definitions
+ if ( (sym.n_type() & N_TYPE) != N_SECT )
+ continue;
+
+ // 'L' labels do not denote atom breaks
+ if ( symbolName[0] == 'L' ) {
+ // <rdar://problem/9218847> Formalize data in code with L$start$ labels
+ if ( strncmp(symbolName, "L$start$", 8) == 0 )
+ _hasDataInCodeLabels = true;
+ continue;
+ }
+ // how many def syms in each section
+ if ( sym.n_sect() > _machOSectionsCount )
+ throw "bad n_sect in symbol table";
+
+ _symbolsInSections++;
+ }
+}
+
+template <typename A>
+int Parser<A>::sectionIndexSorter(void* extra, const void* l, const void* r)
+{
+ Parser<A>* parser = (Parser<A>*)extra;
+ const uint32_t* left = (uint32_t*)l;
+ const uint32_t* right = (uint32_t*)r;
+ const macho_section<P>* leftSect = parser->machOSectionFromSectionIndex(*left);
+ const macho_section<P>* rightSect = parser->machOSectionFromSectionIndex(*right);
+
+ // can't just return difference because 64-bit diff does not fit in 32-bit return type
+ int64_t result = leftSect->addr() - rightSect->addr();
+ if ( result == 0 ) {
+ // two sections with same start address
+ // one with zero size goes first
+ bool leftEmpty = ( leftSect->size() == 0 );
+ bool rightEmpty = ( rightSect->size() == 0 );
+ if ( leftEmpty != rightEmpty ) {
+ return ( rightEmpty ? 1 : -1 );
+ }
+ if ( !leftEmpty && !rightEmpty )
+ throwf("overlapping sections");
+ // both empty, so chose file order
+ return ( rightSect - leftSect );
+ }
+ else if ( result < 0 )
+ return -1;
+ else
+ return 1;
+}
+
+template <typename A>
+void Parser<A>::makeSortedSectionsArray(uint32_t array[])
+{
+ const bool log = false;
+
+ if ( log ) {
+ fprintf(stderr, "unsorted sections:\n");
+ for(unsigned int i=0; i < _machOSectionsCount; ++i )
+ fprintf(stderr, "0x%08llX %s %s\n", _sectionsStart[i].addr(), _sectionsStart[i].segname(), _sectionsStart[i].sectname());
+ }
+
+ // sort by symbol table address
+ for (uint32_t i=0; i < _machOSectionsCount; ++i)
+ array[i] = i;
+ ::qsort_r(array, _machOSectionsCount, sizeof(uint32_t), this, §ionIndexSorter);
+
+ if ( log ) {
+ fprintf(stderr, "sorted sections:\n");
+ for(unsigned int i=0; i < _machOSectionsCount; ++i )
+ fprintf(stderr, "0x%08llX %s %s\n", _sectionsStart[array[i]].addr(), _sectionsStart[array[i]].segname(), _sectionsStart[array[i]].sectname());
+ }
+}
+
+
+
+template <typename A>
+int Parser<A>::symbolIndexSorter(void* extra, const void* l, const void* r)
+{
+ ParserAndSectionsArray* extraInfo = (ParserAndSectionsArray*)extra;
+ Parser<A>* parser = extraInfo->parser;
+ const uint32_t* sortedSectionsArray = extraInfo->sortedSectionsArray;
+ const uint32_t* left = (uint32_t*)l;
+ const uint32_t* right = (uint32_t*)r;
+ const macho_nlist<P>& leftSym = parser->symbolFromIndex(*left);
+ const macho_nlist<P>& rightSym = parser->symbolFromIndex(*right);
+ // can't just return difference because 64-bit diff does not fit in 32-bit return type
+ int64_t result = leftSym.n_value() - rightSym.n_value();
+ if ( result == 0 ) {
+ // two symbols with same address
+ // if in different sections, sort earlier section first
+ if ( leftSym.n_sect() != rightSym.n_sect() ) {
+ for (uint32_t i=0; i < parser->machOSectionCount(); ++i) {
+ if ( sortedSectionsArray[i]+1 == leftSym.n_sect() )
+ return -1;
+ if ( sortedSectionsArray[i]+1 == rightSym.n_sect() )
+ return 1;
+ }
+ }
+ // two symbols in same section, means one is an alias
+ // if only one is global, make the other an alias (sort first)
+ if ( (leftSym.n_type() & N_EXT) != (rightSym.n_type() & N_EXT) ) {
+ if ( (rightSym.n_type() & N_EXT) != 0 )
+ return -1;
+ else
+ return 1;
+ }
+ // if both are global, make alphabetically last one be the alias
+ return ( strcmp(parser->nameFromSymbol(rightSym), parser->nameFromSymbol(leftSym)) );
+ }
+ else if ( result < 0 )
+ return -1;
+ else
+ return 1;
+}
+
+
+template <typename A>
+void Parser<A>::makeSortedSymbolsArray(uint32_t array[], const uint32_t sectionArray[])
+{
+ const bool log = false;
+
+ uint32_t* p = array;
+ for (uint32_t i=0; i < this->_symbolCount; ++i) {
+ const macho_nlist<P>& sym = symbolFromIndex(i);
+ // ignore stabs
+ if ( (sym.n_type() & N_STAB) != 0 )
+ continue;
+
+ // only look at definitions
+ if ( (sym.n_type() & N_TYPE) != N_SECT )
+ continue;
+
+ // 'L' labels do not denote atom breaks
+ const char* symbolName = this->nameFromSymbol(sym);
+ if ( symbolName[0] == 'L' )
+ continue;
+
+ // how many def syms in each section
+ if ( sym.n_sect() > _machOSectionsCount )
+ throw "bad n_sect in symbol table";
+
+ // append to array
+ *p++ = i;
+ }
+ assert(p == &array[_symbolsInSections] && "second pass over symbol table yield a different number of symbols");
+
+ // sort by symbol table address
+ ParserAndSectionsArray extra = { this, sectionArray };
+ ::qsort_r(array, _symbolsInSections, sizeof(uint32_t), &extra, &symbolIndexSorter);
+
+ // look for two symbols at same address
+ _overlappingSymbols = false;
+ for (unsigned int i=1; i < _symbolsInSections; ++i) {
+ if ( symbolFromIndex(array[i-1]).n_value() == symbolFromIndex(array[i]).n_value() ) {
+ //fprintf(stderr, "overlapping symbols at 0x%08llX\n", symbolFromIndex(array[i-1]).n_value());
+ _overlappingSymbols = true;
+ }
+ }
+
+ if ( log ) {
+ fprintf(stderr, "sorted symbols:\n");
+ for(unsigned int i=0; i < _symbolsInSections; ++i )
+ fprintf(stderr, "0x%09llX symIndex=%d sectNum=%2d, %s\n", symbolFromIndex(array[i]).n_value(), array[i], symbolFromIndex(array[i]).n_sect(), nameFromSymbol(symbolFromIndex(array[i])) );
+ }
+}
+
+
+template <typename A>
+void Parser<A>::makeSections()
+{
+ // classify each section by type
+ // compute how many Section objects will be needed and total size for all
+ unsigned int totalSectionsSize = 0;
+ uint8_t machOSectsStorage[sizeof(MachOSectionAndSectionClass<P>)*(_machOSectionsCount+2)]; // also room for tentative-defs and absolute symbols
+ // allocate raw storage for all section objects on stack
+ MachOSectionAndSectionClass<P>* machOSects = (MachOSectionAndSectionClass<P>*)machOSectsStorage;
+ unsigned int count = 0;
+ for (uint32_t i=0; i < _machOSectionsCount; ++i) {
+ const macho_section<P>* sect = &_sectionsStart[i];
+ if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
+ if ( strcmp(sect->segname(), "__DWARF") == 0 ) {
+ // note that .o file has dwarf
+ _file->_debugInfoKind = ld::relocatable::File::kDebugInfoDwarf;
+ // save off iteresting dwarf sections
+ if ( strcmp(sect->sectname(), "__debug_info") == 0 )
+ _file->_dwarfDebugInfoSect = sect;
+ else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 )
+ _file->_dwarfDebugAbbrevSect = sect;
+ else if ( strcmp(sect->sectname(), "__debug_line") == 0 )
+ _file->_dwarfDebugLineSect = sect;
+ else if ( strcmp(sect->sectname(), "__debug_str") == 0 )
+ _file->_dwarfDebugStringSect = sect;
+ // linker does not propagate dwarf sections to output file
+ continue;
+ }
+ else if ( strcmp(sect->segname(), "__LD") == 0 ) {
+ if ( strncmp(sect->sectname(), "__compact_unwind", 16) == 0 ) {
+ machOSects[count].sect = sect;
+ totalSectionsSize += sizeof(CUSection<A>);
+ machOSects[count++].type = sectionTypeCompactUnwind;
+ continue;
+ }
+ }
+ }
+ // ignore empty __OBJC sections
+ if ( (sect->size() == 0) && (strcmp(sect->segname(), "__OBJC") == 0) )
+ continue;
+ // objc image info section is really attributes and not content
+ if ( ((strcmp(sect->sectname(), "__image_info") == 0) && (strcmp(sect->segname(), "__OBJC") == 0))
+ || ((strncmp(sect->sectname(), "__objc_imageinfo", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0)) ) {
+ // struct objc_image_info {
+ // uint32_t version; // initially 0
+ // uint32_t flags;
+ // };
+ // #define OBJC_IMAGE_SUPPORTS_GC 2
+ // #define OBJC_IMAGE_GC_ONLY 4
+ //
+ const uint32_t* contents = (uint32_t*)(_file->fileContent()+sect->offset());
+ if ( (sect->size() >= 8) && (contents[0] == 0) ) {
+ uint32_t flags = E::get32(contents[1]);
+ if ( (flags & 4) == 4 )
+ _file->_objConstraint = ld::File::objcConstraintGC;
+ else if ( (flags & 2) == 2 )
+ _file->_objConstraint = ld::File::objcConstraintRetainReleaseOrGC;
+ else
+ _file->_objConstraint = ld::File::objcConstraintRetainRelease;
+ if ( sect->size() > 8 ) {
+ warning("section %s/%s has unexpectedly large size %llu in %s",
+ sect->segname(), Section<A>::makeSectionName(sect), sect->size(), _file->path());
+ }
+ }
+ else {
+ warning("can't parse %s/%s section in %s", sect->segname(), Section<A>::makeSectionName(sect), _file->path());
+ }
+ continue;
+ }
+ machOSects[count].sect = sect;
+ switch ( sect->flags() & SECTION_TYPE ) {
+ case S_SYMBOL_STUBS:
+ if ( _stubsSectionNum == 0 ) {
+ _stubsSectionNum = i+1;
+ _stubsMachOSection = sect;
+ }
+ else
+ assert(1 && "multiple S_SYMBOL_STUBS sections");
+ case S_LAZY_SYMBOL_POINTERS:
+ break;
+ case S_4BYTE_LITERALS:
+ totalSectionsSize += sizeof(Literal4Section<A>);
+ machOSects[count++].type = sectionTypeLiteral4;
+ break;
+ case S_8BYTE_LITERALS:
+ totalSectionsSize += sizeof(Literal8Section<A>);
+ machOSects[count++].type = sectionTypeLiteral8;
+ break;
+ case S_16BYTE_LITERALS:
+ totalSectionsSize += sizeof(Literal16Section<A>);
+ machOSects[count++].type = sectionTypeLiteral16;
+ break;
+ case S_NON_LAZY_SYMBOL_POINTERS:
+ totalSectionsSize += sizeof(NonLazyPointerSection<A>);
+ machOSects[count++].type = sectionTypeNonLazy;
+ break;
+ case S_LITERAL_POINTERS:
+ if ( (strcmp(sect->segname(), "__OBJC") == 0) && (strcmp(sect->sectname(), "__cls_refs") == 0) ) {
+ totalSectionsSize += sizeof(Objc1ClassReferences<A>);
+ machOSects[count++].type = sectionTypeObjC1ClassRefs;
+ }
+ else {
+ totalSectionsSize += sizeof(PointerToCStringSection<A>);
+ machOSects[count++].type = sectionTypeCStringPointer;
+ }
+ break;
+ case S_CSTRING_LITERALS:
+ totalSectionsSize += sizeof(CStringSection<A>);
+ machOSects[count++].type = sectionTypeCString;
+ break;
+ case S_MOD_INIT_FUNC_POINTERS:
+ case S_MOD_TERM_FUNC_POINTERS:
+ case S_THREAD_LOCAL_INIT_FUNCTION_POINTERS:
+ case S_INTERPOSING:
+ case S_ZEROFILL:
+ case S_REGULAR:
+ case S_COALESCED:
+ case S_THREAD_LOCAL_REGULAR:
+ case S_THREAD_LOCAL_ZEROFILL:
+ if ( (strcmp(sect->segname(), "__TEXT") == 0) && (strcmp(sect->sectname(), "__eh_frame") == 0) ) {
+ totalSectionsSize += sizeof(CFISection<A>);
+ machOSects[count++].type = sectionTypeCFI;
+ }
+ else if ( (strcmp(sect->segname(), "__DATA") == 0) && (strcmp(sect->sectname(), "__cfstring") == 0) ) {
+ totalSectionsSize += sizeof(CFStringSection<A>);
+ machOSects[count++].type = sectionTypeCFString;
+ }
+ else if ( (strcmp(sect->segname(), "__TEXT") == 0) && (strcmp(sect->sectname(), "__ustring") == 0) ) {
+ totalSectionsSize += sizeof(UTF16StringSection<A>);
+ machOSects[count++].type = sectionTypeUTF16Strings;
+ }
+ else if ( (strcmp(sect->segname(), "__DATA") == 0) && (strncmp(sect->sectname(), "__objc_classrefs", 16) == 0) ) {
+ totalSectionsSize += sizeof(ObjC2ClassRefsSection<A>);
+ machOSects[count++].type = sectionTypeObjC2ClassRefs;
+ }
+ else if ( (strcmp(sect->segname(), "__DATA") == 0) && (strcmp(sect->sectname(), "__objc_catlist") == 0) ) {
+ totalSectionsSize += sizeof(ObjC2CategoryListSection<A>);
+ machOSects[count++].type = typeObjC2CategoryList;
+ }
+ else if ( _AppleObjc && (strcmp(sect->segname(), "__OBJC") == 0) && (strcmp(sect->sectname(), "__class") == 0) ) {
+ totalSectionsSize += sizeof(ObjC1ClassSection<A>);
+ machOSects[count++].type = sectionTypeObjC1Classes;
+ }
+ else {
+ totalSectionsSize += sizeof(SymboledSection<A>);
+ machOSects[count++].type = sectionTypeSymboled;
+ }
+ break;
+ case S_THREAD_LOCAL_VARIABLES:
+ totalSectionsSize += sizeof(TLVDefsSection<A>);
+ machOSects[count++].type = sectionTypeTLVDefs;
+ break;
+ case S_THREAD_LOCAL_VARIABLE_POINTERS:
+ default:
+ throwf("unknown section type %d", sect->flags() & SECTION_TYPE);
+ }
+ }
+
+ // sort by address (mach-o object files don't aways have sections sorted)
+ ::qsort(machOSects, count, sizeof(MachOSectionAndSectionClass<P>), MachOSectionAndSectionClass<P>::sorter);
+
+ // we will synthesize a dummy Section<A> object for tentative definitions
+ if ( _tentativeDefinitionCount > 0 ) {
+ totalSectionsSize += sizeof(TentativeDefinitionSection<A>);
+ machOSects[count++].type = sectionTypeTentativeDefinitions;
+ }
+
+ // we will synthesize a dummy Section<A> object for Absolute symbols
+ if ( _absoluteSymbolCount > 0 ) {
+ totalSectionsSize += sizeof(AbsoluteSymbolSection<A>);
+ machOSects[count++].type = sectionTypeAbsoluteSymbols;
+ }
+
+ // allocate one block for all Section objects as well as pointers to each
+ uint8_t* space = new uint8_t[totalSectionsSize+count*sizeof(Section<A>*)];
+ _file->_sectionsArray = (Section<A>**)space;
+ _file->_sectionsArrayCount = count;
+ Section<A>** objects = _file->_sectionsArray;
+ space += count*sizeof(Section<A>*);
+ for (uint32_t i=0; i < count; ++i) {
+ switch ( machOSects[i].type ) {
+ case sectionTypeIgnore:
+ break;
+ case sectionTypeLiteral4:
+ *objects++ = new (space) Literal4Section<A>(*this, *_file, machOSects[i].sect);
+ space += sizeof(Literal4Section<A>);
+ break;
+ case sectionTypeLiteral8:
+ *objects++ = new (space) Literal8Section<A>(*this, *_file, machOSects[i].sect);
+ space += sizeof(Literal8Section<A>);
+ break;
+ case sectionTypeLiteral16:
+ *objects++ = new (space) Literal16Section<A>(*this, *_file, machOSects[i].sect);
+ space += sizeof(Literal16Section<A>);
+ break;
+ case sectionTypeNonLazy:
+ *objects++ = new (space) NonLazyPointerSection<A>(*this, *_file, machOSects[i].sect);
+ space += sizeof(NonLazyPointerSection<A>);
+ break;
+ case sectionTypeCFI:
+ _EHFrameSection = new (space) CFISection<A>(*this, *_file, machOSects[i].sect);
+ *objects++ = _EHFrameSection;
+ space += sizeof(CFISection<A>);
+ break;
+ case sectionTypeCString:
+ *objects++ = new (space) CStringSection<A>(*this, *_file, machOSects[i].sect);
+ space += sizeof(CStringSection<A>);
+ break;
+ case sectionTypeCStringPointer:
+ *objects++ = new (space) PointerToCStringSection<A>(*this, *_file, machOSects[i].sect);
+ space += sizeof(PointerToCStringSection<A>);
+ break;
+ case sectionTypeObjC1ClassRefs:
+ *objects++ = new (space) Objc1ClassReferences<A>(*this, *_file, machOSects[i].sect);
+ space += sizeof(Objc1ClassReferences<A>);
+ break;
+ case sectionTypeUTF16Strings:
+ *objects++ = new (space) UTF16StringSection<A>(*this, *_file, machOSects[i].sect);
+ space += sizeof(UTF16StringSection<A>);
+ break;
+ case sectionTypeCFString:
+ *objects++ = new (space) CFStringSection<A>(*this, *_file, machOSects[i].sect);
+ space += sizeof(CFStringSection<A>);
+ break;
+ case sectionTypeObjC2ClassRefs:
+ *objects++ = new (space) ObjC2ClassRefsSection<A>(*this, *_file, machOSects[i].sect);
+ space += sizeof(ObjC2ClassRefsSection<A>);
+ break;
+ case typeObjC2CategoryList:
+ *objects++ = new (space) ObjC2CategoryListSection<A>(*this, *_file, machOSects[i].sect);
+ space += sizeof(ObjC2CategoryListSection<A>);
+ break;
+ case sectionTypeObjC1Classes:
+ *objects++ = new (space) ObjC1ClassSection<A>(*this, *_file, machOSects[i].sect);
+ space += sizeof(ObjC1ClassSection<A>);
+ break;
+ case sectionTypeSymboled:
+ *objects++ = new (space) SymboledSection<A>(*this, *_file, machOSects[i].sect);
+ space += sizeof(SymboledSection<A>);
+ break;
+ case sectionTypeTLVDefs:
+ *objects++ = new (space) TLVDefsSection<A>(*this, *_file, machOSects[i].sect);
+ space += sizeof(TLVDefsSection<A>);
+ break;
+ case sectionTypeCompactUnwind:
+ _compactUnwindSection = new (space) CUSection<A>(*this, *_file, machOSects[i].sect);
+ *objects++ = _compactUnwindSection;
+ space += sizeof(CUSection<A>);
+ break;
+ case sectionTypeTentativeDefinitions:
+ *objects++ = new (space) TentativeDefinitionSection<A>(*this, *_file);
+ space += sizeof(TentativeDefinitionSection<A>);
+ break;
+ case sectionTypeAbsoluteSymbols:
+ _absoluteSection = new (space) AbsoluteSymbolSection<A>(*this, *_file);
+ *objects++ = _absoluteSection;
+ space += sizeof(AbsoluteSymbolSection<A>);
+ break;
+ default:
+ throw "internal error uknown SectionType";
+ }
+ }
+}
+
+
+template <typename A>
+Section<A>* Parser<A>::sectionForAddress(typename A::P::uint_t addr)
+{
+ for (uint32_t i=0; i < _file->_sectionsArrayCount; ++i ) {
+ const macho_section<typename A::P>* sect = _file->_sectionsArray[i]->machoSection();
+ // TentativeDefinitionSection and AbsoluteSymbolSection have no mach-o section
+ if ( sect != NULL ) {
+ if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) ) {
+ return _file->_sectionsArray[i];
+ }
+ }
+ }
+ // not strictly in any section
+ // may be in a zero length section
+ for (uint32_t i=0; i < _file->_sectionsArrayCount; ++i ) {
+ const macho_section<typename A::P>* sect = _file->_sectionsArray[i]->machoSection();
+ // TentativeDefinitionSection and AbsoluteSymbolSection have no mach-o section
+ if ( sect != NULL ) {
+ if ( (sect->addr() == addr) && (sect->size() == 0) ) {
+ return _file->_sectionsArray[i];
+ }
+ }
+ }
+
+ throwf("sectionForAddress(0x%llX) address not in any section", (uint64_t)addr);
+}
+
+template <typename A>
+Section<A>* Parser<A>::sectionForNum(unsigned int num)
+{
+ for (uint32_t i=0; i < _file->_sectionsArrayCount; ++i ) {
+ const macho_section<typename A::P>* sect = _file->_sectionsArray[i]->machoSection();
+ // TentativeDefinitionSection and AbsoluteSymbolSection have no mach-o section
+ if ( sect != NULL ) {
+ if ( num == (unsigned int)((sect - _sectionsStart)+1) )
+ return _file->_sectionsArray[i];
+ }
+ }
+ throwf("sectionForNum(%u) section number not for any section", num);
+}
+
+template <typename A>
+Atom<A>* Parser<A>::findAtomByAddress(pint_t addr)
+{
+ Section<A>* section = this->sectionForAddress(addr);
+ return section->findAtomByAddress(addr);
+}
+
+template <typename A>
+Atom<A>* Parser<A>::findAtomByAddressOrNullIfStub(pint_t addr)
+{
+ if ( hasStubsSection() && (_stubsMachOSection->addr() <= addr) && (addr < (_stubsMachOSection->addr()+_stubsMachOSection->size())) )
+ return NULL;
+ return findAtomByAddress(addr);
+}
+
+template <typename A>
+Atom<A>* Parser<A>::findAtomByAddressOrLocalTargetOfStub(pint_t addr, uint32_t* offsetInAtom)
+{
+ if ( hasStubsSection() && (_stubsMachOSection->addr() <= addr) && (addr < (_stubsMachOSection->addr()+_stubsMachOSection->size())) ) {
+ // target is a stub, remove indirection
+ uint32_t symbolIndex = this->symbolIndexFromIndirectSectionAddress(addr, _stubsMachOSection);
+ assert(symbolIndex != INDIRECT_SYMBOL_LOCAL);
+ const macho_nlist<P>& sym = this->symbolFromIndex(symbolIndex);
+ // can't be to external weak symbol
+ assert( (this->combineFromSymbol(sym) != ld::Atom::combineByName) || (this->scopeFromSymbol(sym) != ld::Atom::scopeGlobal) );
+ *offsetInAtom = 0;
+ return this->findAtomByName(this->nameFromSymbol(sym));
+ }
+ Atom<A>* target = this->findAtomByAddress(addr);
+ *offsetInAtom = addr - target->_objAddress;
+ return target;
+}
+
+template <typename A>
+Atom<A>* Parser<A>::findAtomByName(const char* name)
+{
+ uint8_t* p = _file->_atomsArray;
+ for(int i=_file->_atomsArrayCount; i > 0; --i) {
+ Atom<A>* atom = (Atom<A>*)p;
+ if ( strcmp(name, atom->name()) == 0 )
+ return atom;
+ p += sizeof(Atom<A>);
+ }
+ return NULL;
+}
+
+template <typename A>
+void Parser<A>::findTargetFromAddress(pint_t addr, TargetDesc& target)
+{
+ if ( hasStubsSection() && (_stubsMachOSection->addr() <= addr) && (addr < (_stubsMachOSection->addr()+_stubsMachOSection->size())) ) {
+ // target is a stub, remove indirection
+ uint32_t symbolIndex = this->symbolIndexFromIndirectSectionAddress(addr, _stubsMachOSection);
+ assert(symbolIndex != INDIRECT_SYMBOL_LOCAL);
+ const macho_nlist<P>& sym = this->symbolFromIndex(symbolIndex);
+ target.atom = NULL;
+ target.name = this->nameFromSymbol(sym);
+ target.weakImport = this->weakImportFromSymbol(sym);
+ target.addend = 0;
+ return;
+ }
+ Section<A>* section = this->sectionForAddress(addr);
+ target.atom = section->findAtomByAddress(addr);
+ target.addend = addr - target.atom->_objAddress;
+ target.weakImport = false;
+ target.name = NULL;
+}
+
+template <typename A>
+void Parser<A>::findTargetFromAddress(pint_t baseAddr, pint_t addr, TargetDesc& target)
+{
+ findTargetFromAddress(baseAddr, target);
+ target.addend = addr - target.atom->_objAddress;
+}
+
+template <typename A>
+void Parser<A>::findTargetFromAddressAndSectionNum(pint_t addr, unsigned int sectNum, TargetDesc& target)
+{
+ if ( sectNum == R_ABS ) {
+ // target is absolute symbol that corresponds to addr
+ if ( _absoluteSection != NULL ) {
+ target.atom = _absoluteSection->findAbsAtomForValue(addr);
+ if ( target.atom != NULL ) {
+ target.name = NULL;
+ target.weakImport = false;
+ target.addend = 0;
+ return;
+ }
+ }
+ throwf("R_ABS reloc but no absolute symbol at target address");
+ }
+
+ if ( hasStubsSection() && (stubsSectionNum() == sectNum) ) {
+ // target is a stub, remove indirection
+ uint32_t symbolIndex = this->symbolIndexFromIndirectSectionAddress(addr, _stubsMachOSection);
+ assert(symbolIndex != INDIRECT_SYMBOL_LOCAL);
+ const macho_nlist<P>& sym = this->symbolFromIndex(symbolIndex);
+ // use direct reference when stub is to a static function
+ if ( ((sym.n_type() & N_TYPE) == N_SECT) && (((sym.n_type() & N_EXT) == 0) || (this->nameFromSymbol(sym)[0] == 'L')) ) {
+ this->findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target);
+ }
+ else {
+ target.atom = NULL;
+ target.name = this->nameFromSymbol(sym);
+ target.weakImport = this->weakImportFromSymbol(sym);
+ target.addend = 0;
+ }
+ return;
+ }
+ Section<A>* section = this->sectionForNum(sectNum);
+ target.atom = section->findAtomByAddress(addr);
+ if ( target.atom == NULL ) {
+ typedef typename A::P::sint_t sint_t;
+ sint_t a = (sint_t)addr;
+ sint_t sectStart = (sint_t)(section->machoSection()->addr());
+ sint_t sectEnd = sectStart + section->machoSection()->size();
+ if ( a < sectStart ) {
+ // target address is before start of section, so must be negative addend
+ target.atom = section->findAtomByAddress(sectStart);
+ target.addend = a - sectStart;
+ target.weakImport = false;
+ target.name = NULL;
+ return;
+ }
+ else if ( a >= sectEnd ) {
+ target.atom = section->findAtomByAddress(sectEnd-1);
+ target.addend = a - sectEnd;
+ target.weakImport = false;
+ target.name = NULL;
+ return;
+ }
+ }
+ assert(target.atom != NULL);
+ target.addend = addr - target.atom->_objAddress;
+ target.weakImport = false;
+ target.name = NULL;
+}
+
+template <typename A>
+void Parser<A>::addDtraceExtraInfos(const SourceLocation& src, const char* providerName)
+{
+ // for every ___dtrace_stability$* and ___dtrace_typedefs$* undefine with
+ // a matching provider name, add a by-name kDtraceTypeReference at probe site
+ const char* dollar = strchr(providerName, '$');
+ if ( dollar != NULL ) {
+ int providerNameLen = dollar-providerName+1;
+ for ( std::vector<const char*>::iterator it = _dtraceProviderInfo.begin(); it != _dtraceProviderInfo.end(); ++it) {
+ const char* typeDollar = strchr(*it, '$');
+ if ( typeDollar != NULL ) {
+ if ( strncmp(typeDollar+1, providerName, providerNameLen) == 0 ) {
+ addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindDtraceExtra,false, *it);
+ }
+ }
+ }
+ }
+}
+
+template <typename A>
+const char* Parser<A>::scanSymbolTableForAddress(uint64_t addr)
+{
+ uint64_t closestSymAddr = 0;
+ const char* closestSymName = NULL;
+ for (uint32_t i=0; i < this->_symbolCount; ++i) {
+ const macho_nlist<P>& sym = symbolFromIndex(i);
+ // ignore stabs
+ if ( (sym.n_type() & N_STAB) != 0 )
+ continue;
+
+ // only look at definitions
+ if ( (sym.n_type() & N_TYPE) != N_SECT )
+ continue;
+
+ // return with exact match
+ if ( sym.n_value() == addr )
+ return nameFromSymbol(sym);
+
+ // record closest seen so far
+ if ( (sym.n_value() < addr) && ((sym.n_value() > closestSymAddr) || (closestSymName == NULL)) )
+ closestSymName = nameFromSymbol(sym);
+ }
+
+ return (closestSymName != NULL) ? closestSymName : "unknown";
+}
+
+
+template <typename A>
+void Parser<A>::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, const TargetDesc& target)
+{
+ // some fixup pairs can be combined
+ ld::Fixup::Cluster cl = ld::Fixup::k1of3;
+ ld::Fixup::Kind firstKind = ld::Fixup::kindSetTargetAddress;
+ bool combined = false;
+ if ( target.addend == 0 ) {
+ cl = ld::Fixup::k1of1;
+ combined = true;
+ switch ( setKind ) {
+ case ld::Fixup::kindStoreLittleEndian32:
+ firstKind = ld::Fixup::kindStoreTargetAddressLittleEndian32;
+ break;
+ case ld::Fixup::kindStoreLittleEndian64:
+ firstKind = ld::Fixup::kindStoreTargetAddressLittleEndian64;
+ break;
+ case ld::Fixup::kindStoreBigEndian32:
+ firstKind = ld::Fixup::kindStoreTargetAddressBigEndian32;
+ break;
+ case ld::Fixup::kindStoreBigEndian64:
+ firstKind = ld::Fixup::kindStoreTargetAddressBigEndian64;
+ break;
+ case ld::Fixup::kindStoreX86BranchPCRel32:
+ firstKind = ld::Fixup::kindStoreTargetAddressX86BranchPCRel32;
+ break;
+ case ld::Fixup::kindStoreX86PCRel32:
+ firstKind = ld::Fixup::kindStoreTargetAddressX86PCRel32;
+ break;
+ case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+ firstKind = ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad;
+ break;
+ case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+ firstKind = ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad;
+ break;
+ case ld::Fixup::kindStoreX86Abs32TLVLoad:
+ firstKind = ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad;
+ break;
+ case ld::Fixup::kindStoreARMBranch24:
+ firstKind = ld::Fixup::kindStoreTargetAddressARMBranch24;
+ break;
+ case ld::Fixup::kindStoreThumbBranch22:
+ firstKind = ld::Fixup::kindStoreTargetAddressThumbBranch22;
+ break;
+ default:
+ combined = false;
+ cl = ld::Fixup::k1of2;
+ break;
+ }
+ }
+
+ if ( target.atom != NULL ) {
+ if ( target.atom->scope() == ld::Atom::scopeTranslationUnit ) {
+ addFixup(src, cl, firstKind, target.atom);
+ }
+ else if ( (target.atom->combine() == ld::Atom::combineByNameAndContent) || (target.atom->combine() == ld::Atom::combineByNameAndReferences) ) {
+ addFixup(src, cl, firstKind, ld::Fixup::bindingByContentBound, target.atom);
+ }
+ else if ( (src.atom->section().type() == ld::Section::typeCFString) && (src.offsetInAtom != 0) ) {
+ // backing string in CFStrings should always be direct
+ addFixup(src, cl, firstKind, target.atom);
+ }
+ else {
+ // change direct fixup to by-name fixup
+ addFixup(src, cl, firstKind, false, target.atom->name());
+ }
+ }
+ else {
+ addFixup(src, cl, firstKind, target.weakImport, target.name);
+ }
+ if ( target.addend == 0 ) {
+ if ( ! combined )
+ addFixup(src, ld::Fixup::k2of2, setKind);
+ }
+ else {
+ addFixup(src, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, target.addend);
+ addFixup(src, ld::Fixup::k3of3, setKind);
+ }
+}
+
+template <typename A>
+void Parser<A>::addFixups(const SourceLocation& src, ld::Fixup::Kind kind, const TargetDesc& target, const TargetDesc& picBase)
+{
+ ld::Fixup::Cluster cl = (target.addend == 0) ? ld::Fixup::k1of4 : ld::Fixup::k1of5;
+ if ( target.atom != NULL ) {
+ if ( target.atom->scope() == ld::Atom::scopeTranslationUnit ) {
+ addFixup(src, cl, ld::Fixup::kindSetTargetAddress, target.atom);
+ }
+ else if ( (target.atom->combine() == ld::Atom::combineByNameAndContent) || (target.atom->combine() == ld::Atom::combineByNameAndReferences) ) {
+ addFixup(src, cl, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, target.atom);
+ }
+ else {
+ addFixup(src, cl, ld::Fixup::kindSetTargetAddress, false, target.atom->name());
+ }
+ }
+ else {
+ addFixup(src, cl, ld::Fixup::kindSetTargetAddress, target.weakImport, target.name);
+ }
+ if ( target.addend == 0 ) {
+ assert(picBase.atom != NULL);
+ addFixup(src, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, picBase.atom);
+ addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, picBase.addend);
+ addFixup(src, ld::Fixup::k4of4, kind);
+ }
+ else {
+ addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, target.addend);
+ addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, picBase.atom);
+ addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, picBase.addend);
+ addFixup(src, ld::Fixup::k5of5, kind);
+ }
+}
+
+
+
+template <typename A>
+uint32_t TentativeDefinitionSection<A>::computeAtomCount(class Parser<A>& parser,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&)
+{
+ return parser.tentativeDefinitionCount();
+}
+
+template <typename A>
+uint32_t TentativeDefinitionSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&)
+{
+ this->_beginAtoms = (Atom<A>*)p;
+ uint32_t count = 0;
+ for (uint32_t i=parser.undefinedStartIndex(); i < parser.undefinedEndIndex(); ++i) {
+ const macho_nlist<P>& sym = parser.symbolFromIndex(i);
+ if ( ((sym.n_type() & N_TYPE) == N_UNDF) && (sym.n_value() != 0) ) {
+ uint64_t size = sym.n_value();
+ uint8_t alignP2 = GET_COMM_ALIGN(sym.n_desc());
+ if ( alignP2 == 0 ) {
+ // common symbols align to their size
+ // that is, a 4-byte common aligns to 4-bytes
+ // if this size is not a power of two,
+ // then round up to the next power of two
+ alignP2 = 63 - (uint8_t)__builtin_clzll(size);
+ if ( size != (1ULL << alignP2) )
+ ++alignP2;
+ }
+ // limit alignment of extremely large commons to 2^15 bytes (8-page)
+ if ( alignP2 > 15 )
+ alignP2 = 15;
+ Atom<A>* allocatedSpace = (Atom<A>*)p;
+ new (allocatedSpace) Atom<A>(*this, parser.nameFromSymbol(sym), (pint_t)ULLONG_MAX, size,
+ ld::Atom::definitionTentative, ld::Atom::combineByName,
+ parser.scopeFromSymbol(sym), ld::Atom::typeZeroFill, ld::Atom::symbolTableIn,
+ parser.dontDeadStripFromSymbol(sym), false, false, ld::Atom::Alignment(alignP2) );
+ p += sizeof(Atom<A>);
+ ++count;
+ }
+ }
+ this->_endAtoms = (Atom<A>*)p;
+ return count;
+}
+
+
+template <typename A>
+uint32_t AbsoluteSymbolSection<A>::computeAtomCount(class Parser<A>& parser,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&)
+{
+ return parser.absoluteSymbolCount();
+}
+
+template <typename A>
+uint32_t AbsoluteSymbolSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&)
+{
+ this->_beginAtoms = (Atom<A>*)p;
+ uint32_t count = 0;
+ for (uint32_t i=0; i < parser.symbolCount(); ++i) {
+ const macho_nlist<P>& sym = parser.symbolFromIndex(i);
+ if ( (sym.n_type() & N_TYPE) != N_ABS )
+ continue;
+ const char* absName = parser.nameFromSymbol(sym);
+ // ignore .objc_class_name_* symbols
+ if ( strncmp(absName, ".objc_class_name_", 17) == 0 )
+ continue;
+ // ignore .objc_class_name_* symbols
+ if ( strncmp(absName, ".objc_category_name_", 20) == 0 )
+ continue;
+ // ignore empty *.eh symbols
+ if ( strcmp(&absName[strlen(absName)-3], ".eh") == 0 )
+ continue;
+
+ Atom<A>* allocatedSpace = (Atom<A>*)p;
+ new (allocatedSpace) Atom<A>(*this, parser, sym, 0);
+ p += sizeof(Atom<A>);
+ ++count;
+ }
+ this->_endAtoms = (Atom<A>*)p;
+ return count;
+}
+
+template <typename A>
+Atom<A>* AbsoluteSymbolSection<A>::findAbsAtomForValue(typename A::P::uint_t value)
+{
+ Atom<A>* end = this->_endAtoms;
+ for(Atom<A>* p = this->_beginAtoms; p < end; ++p) {
+ if ( p->_objAddress == value )
+ return p;
+ }
+ return NULL;
+}
+
+
+template <typename A>
+uint32_t Parser<A>::indirectSymbol(uint32_t indirectIndex)
+{
+ if ( indirectIndex >= _indirectTableCount )
+ throw "indirect symbol index out of range";
+ return E::get32(_indirectTable[indirectIndex]);
+}
+
+template <typename A>
+const macho_nlist<typename A::P>& Parser<A>::symbolFromIndex(uint32_t index)
+{
+ if ( index > _symbolCount )
+ throw "symbol index out of range";
+ return _symbols[index];
+}
+
+template <typename A>
+const macho_section<typename A::P>* Parser<A>::machOSectionFromSectionIndex(uint32_t index)
+{
+ if ( index >= _machOSectionsCount )
+ throw "section index out of range";
+ return &_sectionsStart[index];
+}
+
+template <typename A>
+uint32_t Parser<A>::symbolIndexFromIndirectSectionAddress(pint_t addr, const macho_section<P>* sect)
+{
+ uint32_t elementSize = 0;
+ switch ( sect->flags() & SECTION_TYPE ) {
+ case S_SYMBOL_STUBS:
+ elementSize = sect->reserved2();
+ break;
+ case S_LAZY_SYMBOL_POINTERS:
+ case S_NON_LAZY_SYMBOL_POINTERS:
+ elementSize = sizeof(pint_t);
+ break;
+ default:
+ throw "section does not use inirect symbol table";
+ }
+ uint32_t indexInSection = (addr - sect->addr()) / elementSize;
+ uint32_t indexIntoIndirectTable = sect->reserved1() + indexInSection;
+ return this->indirectSymbol(indexIntoIndirectTable);
+}
+
+
+
+template <typename A>
+const char* Parser<A>::nameFromSymbol(const macho_nlist<P>& sym)
+{
+ return &_strings[sym.n_strx()];
+}
+
+template <typename A>
+ld::Atom::Scope Parser<A>::scopeFromSymbol(const macho_nlist<P>& sym)
+{
+ if ( (sym.n_type() & N_EXT) == 0 )
+ return ld::Atom::scopeTranslationUnit;
+ else if ( (sym.n_type() & N_PEXT) != 0 )
+ return ld::Atom::scopeLinkageUnit;
+ else if ( this->nameFromSymbol(sym)[0] == 'l' ) // since all 'l' symbols will be remove, don't make them global
+ return ld::Atom::scopeLinkageUnit;
+ else
+ return ld::Atom::scopeGlobal;
+}
+
+template <typename A>
+ld::Atom::Definition Parser<A>::definitionFromSymbol(const macho_nlist<P>& sym)
+{
+ switch ( sym.n_type() & N_TYPE ) {
+ case N_ABS:
+ return ld::Atom::definitionAbsolute;
+ case N_SECT:
+ return ld::Atom::definitionRegular;
+ case N_UNDF:
+ if ( sym.n_value() != 0 )
+ return ld::Atom::definitionTentative;
+ }
+ throw "definitionFromSymbol() bad symbol";
+}
+
+template <typename A>
+ld::Atom::Combine Parser<A>::combineFromSymbol(const macho_nlist<P>& sym)
+{
+ if ( sym.n_desc() & N_WEAK_DEF )
+ return ld::Atom::combineByName;
+ else
+ return ld::Atom::combineNever;
+}
+
+
+template <typename A>
+ld::Atom::SymbolTableInclusion Parser<A>::inclusionFromSymbol(const macho_nlist<P>& sym)
+{
+ const char* symbolName = nameFromSymbol(sym);
+ // labels beginning with 'l' (lowercase ell) are automatically removed in final linked images <rdar://problem/4571042>
+ // labels beginning with 'L' should have been stripped by the assembler, so are stripped now
+ if ( sym.n_desc() & REFERENCED_DYNAMICALLY )
+ return ld::Atom::symbolTableInAndNeverStrip;
+ else if ( symbolName[0] == 'l' )
+ return ld::Atom::symbolTableNotInFinalLinkedImages;
+ else if ( symbolName[0] == 'L' )
+ return ld::Atom::symbolTableNotIn;
+ else
+ return ld::Atom::symbolTableIn;
+}
+
+template <typename A>
+bool Parser<A>::dontDeadStripFromSymbol(const macho_nlist<P>& sym)
+{
+ return ( (sym.n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0 );
+}
+
+template <typename A>
+bool Parser<A>::isThumbFromSymbol(const macho_nlist<P>& sym)
+{
+ return ( sym.n_desc() & N_ARM_THUMB_DEF );
+}
+
+template <typename A>
+bool Parser<A>::weakImportFromSymbol(const macho_nlist<P>& sym)
+{
+ return ( ((sym.n_type() & N_TYPE) == N_UNDF) && ((sym.n_desc() & N_WEAK_REF) != 0) );
+}
+
+template <typename A>
+bool Parser<A>::resolverFromSymbol(const macho_nlist<P>& sym)
+{
+ return ( sym.n_desc() & N_SYMBOL_RESOLVER );
+}
+
+
+/* Skip over a LEB128 value (signed or unsigned). */
+static void
+skip_leb128 (const uint8_t ** offset, const uint8_t * end)
+{
+ while (*offset != end && **offset >= 0x80)
+ (*offset)++;
+ if (*offset != end)
+ (*offset)++;
+}
+
+/* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow
+ or error. On overflow, skip past the rest of the uleb128. */
+static uint64_t
+read_uleb128 (const uint8_t ** offset, const uint8_t * end)
+{
+ uint64_t result = 0;
+ int bit = 0;
+
+ do {
+ uint64_t b;
+
+ if (*offset == end)
+ return (uint64_t) -1;
+
+ b = **offset & 0x7f;
+
+ if (bit >= 64 || b << bit >> bit != b)
+ result = (uint64_t) -1;
+ else
+ result |= b << bit, bit += 7;
+ } while (*(*offset)++ >= 0x80);
+ return result;
+}
+
+
+/* Skip over a DWARF attribute of form FORM. */
+template <typename A>
+bool Parser<A>::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form,
+ uint8_t addr_size, bool dwarf64)
+{
+ int64_t sz=0;
+
+ switch (form)
+ {
+ case DW_FORM_addr:
+ sz = addr_size;
+ break;
+
+ case DW_FORM_block2:
+ if (end - *offset < 2)
+ return false;
+ sz = 2 + A::P::E::get16(*(uint16_t*)offset);
+ break;
+
+ case DW_FORM_block4:
+ if (end - *offset < 4)
+ return false;
+ sz = 2 + A::P::E::get32(*(uint32_t*)offset);
+ break;
+
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ sz = 2;
+ break;
+
+ case DW_FORM_data4:
+ case DW_FORM_ref4:
+ sz = 4;
+ break;
+
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ sz = 8;
+ break;
+
+ case DW_FORM_string:
+ while (*offset != end && **offset)
+ ++*offset;
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ case DW_FORM_ref1:
+ sz = 1;
+ break;
+
+ case DW_FORM_block:
+ sz = read_uleb128 (offset, end);
+ break;
+
+ case DW_FORM_block1:
+ if (*offset == end)
+ return false;
+ sz = 1 + **offset;
+ break;
+
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_ref_udata:
+ skip_leb128 (offset, end);
+ return true;
+
+ case DW_FORM_strp:
+ case DW_FORM_ref_addr:
+ sz = 4;
+ break;
+
+ default:
+ return false;
+ }
+ if (end - *offset < sz)
+ return false;
+ *offset += sz;
+ return true;
+}
+
+
+template <typename A>
+const char* Parser<A>::getDwarfString(uint64_t form, const uint8_t* p)
+{
+ if ( form == DW_FORM_string )
+ return (const char*)p;
+ else if ( form == DW_FORM_strp ) {
+ uint32_t offset = E::get32(*((uint32_t*)p));
+ const char* dwarfStrings = (char*)_file->fileContent() + _file->_dwarfDebugStringSect->offset();
+ if ( offset > _file->_dwarfDebugStringSect->size() ) {
+ warning("unknown dwarf DW_FORM_strp (offset=0x%08X) is too big in %s\n", offset, this->_path);
+ return NULL;
+ }
+ return &dwarfStrings[offset];
+ }
+ warning("unknown dwarf string encoding (form=%lld) in %s\n", form, this->_path);
+ return NULL;
+}
+
+
+template <typename A>
+struct AtomAndLineInfo {
+ Atom<A>* atom;
+ ld::Atom::LineInfo info;
+};
+
+
+// <rdar://problem/5591394> Add support to ld64 for N_FUN stabs when used for symbolic constants
+// Returns whether a stabStr belonging to an N_FUN stab represents a
+// symbolic constant rather than a function
+template <typename A>
+bool Parser<A>::isConstFunStabs(const char *stabStr)
+{
+ const char* colon;
+ // N_FUN can be used for both constants and for functions. In case it's a constant,
+ // the format of the stabs string is "symname:c=<value>;"
+ // ':' cannot appear in the symbol name, except if it's an Objective-C method
+ // (in which case the symbol name starts with + or -, and then it's definitely
+ // not a constant)
+ return (stabStr != NULL) && (stabStr[0] != '+') && (stabStr[0] != '-')
+ && ((colon = strchr(stabStr, ':')) != NULL)
+ && (colon[1] == 'c') && (colon[2] == '=');
+}
+
+
+template <typename A>
+void Parser<A>::parseDebugInfo()
+{
+ // check for dwarf __debug_info section
+ if ( _file->_dwarfDebugInfoSect == NULL ) {
+ // if no DWARF debug info, look for stabs
+ this->parseStabs();
+ return;
+ }
+ if ( _file->_dwarfDebugInfoSect->size() == 0 )
+ return;
+
+ uint64_t stmtList;
+ const char* tuDir;
+ const char* tuName;
+ if ( !read_comp_unit(&tuName, &tuDir, &stmtList) ) {
+ // if can't parse dwarf, warn and give up
+ _file->_dwarfTranslationUnitPath = NULL;
+ warning("can't parse dwarf compilation unit info in %s", _path);
+ _file->_debugInfoKind = ld::relocatable::File::kDebugInfoNone;
+ return;
+ }
+ if ( (tuName != NULL) && (tuName[1] == '/') ) {
+ _file->_dwarfTranslationUnitPath = tuName;
+ }
+ else if ( (tuDir != NULL) && (tuName != NULL) ) {
+ asprintf((char**)&(_file->_dwarfTranslationUnitPath), "%s/%s", tuDir, tuName);
+ }
+ else if ( tuDir == NULL ) {
+ _file->_dwarfTranslationUnitPath = tuName;
+ }
+ else {
+ _file->_dwarfTranslationUnitPath = NULL;
+ }
+
+ // add line number info to atoms from dwarf
+ std::vector<AtomAndLineInfo<A> > entries;
+ entries.reserve(64);
+ if ( _file->_debugInfoKind == ld::relocatable::File::kDebugInfoDwarf ) {
+ // file with just data will have no __debug_line info
+ if ( (_file->_dwarfDebugLineSect != NULL) && (_file->_dwarfDebugLineSect->size() != 0) ) {
+ // validate stmt_list
+ if ( (stmtList != (uint64_t)-1) && (stmtList < _file->_dwarfDebugLineSect->size()) ) {
+ const uint8_t* debug_line = (uint8_t*)_file->fileContent() + _file->_dwarfDebugLineSect->offset();
+ struct line_reader_data* lines = line_open(&debug_line[stmtList],
+ _file->_dwarfDebugLineSect->size() - stmtList, E::little_endian);
+ struct line_info result;
+ Atom<A>* curAtom = NULL;
+ uint32_t curAtomOffset = 0;
+ uint32_t curAtomAddress = 0;
+ uint32_t curAtomSize = 0;
+ std::map<uint32_t,const char*> dwarfIndexToFile;
+ if ( lines != NULL ) {
+ while ( line_next(lines, &result, line_stop_pc) ) {
+ //fprintf(stderr, "curAtom=%p, result.pc=0x%llX, result.line=%llu, result.end_of_sequence=%d,"
+ // " curAtomAddress=0x%X, curAtomSize=0x%X\n",
+ // curAtom, result.pc, result.line, result.end_of_sequence, curAtomAddress, curAtomSize);
+ // work around weird debug line table compiler generates if no functions in __text section
+ if ( (curAtom == NULL) && (result.pc == 0) && result.end_of_sequence && (result.file == 1))
+ continue;
+ // for performance, see if in next pc is in current atom
+ if ( (curAtom != NULL) && (curAtomAddress <= result.pc) && (result.pc < (curAtomAddress+curAtomSize)) ) {
+ curAtomOffset = result.pc - curAtomAddress;
+ }
+ // or pc at end of current atom
+ else if ( result.end_of_sequence && (curAtom != NULL) && (result.pc == (curAtomAddress+curAtomSize)) ) {
+ curAtomOffset = result.pc - curAtomAddress;
+ }
+ // or only one function that is a one line function
+ else if ( result.end_of_sequence && (curAtom == NULL) && (this->findAtomByAddress(0) != NULL) && (result.pc == this->findAtomByAddress(0)->size()) ) {
+ curAtom = this->findAtomByAddress(0);
+ curAtomOffset = result.pc - curAtom->objectAddress();
+ curAtomAddress = curAtom->objectAddress();
+ curAtomSize = curAtom->size();
+ }
+ else {
+ // do slow look up of atom by address
+ try {
+ curAtom = this->findAtomByAddress(result.pc);
+ }
+ catch (...) {
+ // in case of bug in debug info, don't abort link, just limp on
+ curAtom = NULL;
+ }
+ if ( curAtom == NULL )
+ break; // file has line info but no functions
+ if ( result.end_of_sequence && (curAtomAddress+curAtomSize < result.pc) ) {
+ // a one line function can be returned by line_next() as one entry with pc at end of blob
+ // look for alt atom starting at end of previous atom
+ uint32_t previousEnd = curAtomAddress+curAtomSize;
+ Atom<A>* alt = this->findAtomByAddressOrNullIfStub(previousEnd);
+ if ( alt == NULL )
+ continue; // ignore spurious debug info for stubs
+ if ( result.pc <= alt->objectAddress() + alt->size() ) {
+ curAtom = alt;
+ curAtomOffset = result.pc - alt->objectAddress();
+ curAtomAddress = alt->objectAddress();
+ curAtomSize = alt->size();
+ }
+ else {
+ curAtomOffset = result.pc - curAtom->objectAddress();
+ curAtomAddress = curAtom->objectAddress();
+ curAtomSize = curAtom->size();
+ }
+ }
+ else {
+ curAtomOffset = result.pc - curAtom->objectAddress();
+ curAtomAddress = curAtom->objectAddress();
+ curAtomSize = curAtom->size();
+ }
+ }
+ const char* filename;
+ std::map<uint32_t,const char*>::iterator pos = dwarfIndexToFile.find(result.file);
+ if ( pos == dwarfIndexToFile.end() ) {
+ filename = line_file(lines, result.file);
+ dwarfIndexToFile[result.file] = filename;
+ }
+ else {
+ filename = pos->second;
+ }
+ // only record for ~8000 line info records per function
+ if ( curAtom->roomForMoreLineInfoCount() ) {
+ AtomAndLineInfo<A> entry;
+ entry.atom = curAtom;
+ entry.info.atomOffset = curAtomOffset;
+ entry.info.fileName = filename;
+ entry.info.lineNumber = result.line;
+ //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s, atom=%s, atom.size=0x%X, end=%d\n",
+ // result.pc, result.line, filename, curAtom->name(), curAtomSize, result.end_of_sequence);
+ entries.push_back(entry);
+ curAtom->incrementLineInfoCount();
+ }
+ if ( result.end_of_sequence ) {
+ curAtom = NULL;
+ }
+ }
+ line_free(lines);
+ }
+ }
+ }
+ }
+
+ // assign line info start offset for each atom
+ uint8_t* p = _file->_atomsArray;
+ uint32_t liOffset = 0;
+ for(int i=_file->_atomsArrayCount; i > 0; --i) {
+ Atom<A>* atom = (Atom<A>*)p;
+ atom->_lineInfoStartIndex = liOffset;
+ liOffset += atom->_lineInfoCount;
+ atom->_lineInfoCount = 0;
+ p += sizeof(Atom<A>);
+ }
+ assert(liOffset == entries.size());
+ _file->_lineInfos.reserve(liOffset);
+
+ // copy each line info for each atom
+ for (typename std::vector<AtomAndLineInfo<A> >::iterator it = entries.begin(); it != entries.end(); ++it) {
+ uint32_t slot = it->atom->_lineInfoStartIndex + it->atom->_lineInfoCount;
+ _file->_lineInfos[slot] = it->info;
+ it->atom->_lineInfoCount++;
+ }
+
+ // done with temp vector
+ entries.clear();
+}
+
+template <typename A>
+void Parser<A>::parseStabs()
+{
+ // scan symbol table for stabs entries
+ Atom<A>* currentAtom = NULL;
+ pint_t currentAtomAddress = 0;
+ enum { start, inBeginEnd, inFun } state = start;
+ for (uint32_t symbolIndex = 0; symbolIndex < _symbolCount; ++symbolIndex ) {
+ const macho_nlist<P>& sym = this->symbolFromIndex(symbolIndex);
+ bool useStab = true;
+ uint8_t type = sym.n_type();
+ const char* symString = (sym.n_strx() != 0) ? this->nameFromSymbol(sym) : NULL;
+ if ( (type & N_STAB) != 0 ) {
+ _file->_debugInfoKind = (_hasUUID ? ld::relocatable::File::kDebugInfoStabsUUID : ld::relocatable::File::kDebugInfoStabs);
+ ld::relocatable::File::Stab stab;
+ stab.atom = NULL;
+ stab.type = type;
+ stab.other = sym.n_sect();
+ stab.desc = sym.n_desc();
+ stab.value = sym.n_value();
+ stab.string = NULL;
+ switch (state) {
+ case start:
+ switch (type) {
+ case N_BNSYM:
+ // beginning of function block
+ state = inBeginEnd;
+ // fall into case to lookup atom by addresss
+ case N_LCSYM:
+ case N_STSYM:
+ currentAtomAddress = sym.n_value();
+ currentAtom = this->findAtomByAddress(currentAtomAddress);
+ if ( currentAtom != NULL ) {
+ stab.atom = currentAtom;
+ stab.string = symString;
+ }
+ else {
+ fprintf(stderr, "can't find atom for stabs BNSYM at %08llX in %s",
+ (uint64_t)sym.n_value(), _path);
+ }
+ break;
+ case N_SO:
+ case N_OSO:
+ case N_OPT:
+ case N_LSYM:
+ case N_RSYM:
+ case N_PSYM:
+ // not associated with an atom, just copy
+ stab.string = symString;
+ break;
+ case N_GSYM:
+ {
+ // n_value field is NOT atom address ;-(
+ // need to find atom by name match
+ const char* colon = strchr(symString, ':');
+ if ( colon != NULL ) {
+ // build underscore leading name
+ int nameLen = colon - symString;
+ char symName[nameLen+2];
+ strlcpy(&symName[1], symString, nameLen+1);
+ symName[0] = '_';
+ symName[nameLen+1] = '\0';
+ currentAtom = this->findAtomByName(symName);
+ if ( currentAtom != NULL ) {
+ stab.atom = currentAtom;
+ stab.string = symString;
+ }
+ }
+ else {
+ // might be a debug-note without trailing :G()
+ currentAtom = this->findAtomByName(symString);
+ if ( currentAtom != NULL ) {
+ stab.atom = currentAtom;
+ stab.string = symString;
+ }
+ }
+ if ( stab.atom == NULL ) {
+ // ld_classic added bogus GSYM stabs for old style dtrace probes
+ if ( (strncmp(symString, "__dtrace_probe$", 15) != 0) )
+ warning("can't find atom for N_GSYM stabs %s in %s", symString, _path);
+ useStab = false;
+ }
+ break;
+ }
+ case N_FUN:
+ if ( isConstFunStabs(symString) ) {
+ // constant not associated with a function
+ stab.string = symString;
+ }
+ else {
+ // old style stabs without BNSYM
+ state = inFun;
+ currentAtomAddress = sym.n_value();
+ currentAtom = this->findAtomByAddress(currentAtomAddress);
+ if ( currentAtom != NULL ) {
+ stab.atom = currentAtom;
+ stab.string = symString;
+ }
+ else {
+ warning("can't find atom for stabs FUN at %08llX in %s",
+ (uint64_t)currentAtomAddress, _path);
+ }
+ }
+ break;
+ case N_SOL:
+ case N_SLINE:
+ stab.string = symString;
+ // old stabs
+ break;
+ case N_BINCL:
+ case N_EINCL:
+ case N_EXCL:
+ stab.string = symString;
+ // -gfull built .o file
+ break;
+ default:
+ warning("unknown stabs type 0x%X in %s", type, _path);
+ }
+ break;
+ case inBeginEnd:
+ stab.atom = currentAtom;
+ switch (type) {
+ case N_ENSYM:
+ state = start;
+ currentAtom = NULL;
+ break;
+ case N_LCSYM:
+ case N_STSYM:
+ {
+ Atom<A>* nestedAtom = this->findAtomByAddress(sym.n_value());
+ if ( nestedAtom != NULL ) {
+ stab.atom = nestedAtom;
+ stab.string = symString;
+ }
+ else {
+ warning("can't find atom for stabs 0x%X at %08llX in %s",
+ type, (uint64_t)sym.n_value(), _path);
+ }
+ break;
+ }
+ case N_LBRAC:
+ case N_RBRAC:
+ case N_SLINE:
+ // adjust value to be offset in atom
+ stab.value -= currentAtomAddress;
+ default:
+ stab.string = symString;
+ break;
+ }
+ break;
+ case inFun:
+ switch (type) {
+ case N_FUN:
+ if ( isConstFunStabs(symString) ) {
+ stab.atom = currentAtom;
+ stab.string = symString;
+ }
+ else {
+ if ( sym.n_sect() != 0 ) {
+ // found another start stab, must be really old stabs...
+ currentAtomAddress = sym.n_value();
+ currentAtom = this->findAtomByAddress(currentAtomAddress);
+ if ( currentAtom != NULL ) {
+ stab.atom = currentAtom;
+ stab.string = symString;
+ }
+ else {
+ warning("can't find atom for stabs FUN at %08llX in %s",
+ (uint64_t)currentAtomAddress, _path);
+ }
+ }
+ else {
+ // found ending stab, switch back to start state
+ stab.string = symString;
+ stab.atom = currentAtom;
+ state = start;
+ currentAtom = NULL;
+ }
+ }
+ break;
+ case N_LBRAC:
+ case N_RBRAC:
+ case N_SLINE:
+ // adjust value to be offset in atom
+ stab.value -= currentAtomAddress;
+ stab.atom = currentAtom;
+ break;
+ case N_SO:
+ stab.string = symString;
+ state = start;
+ break;
+ default:
+ stab.atom = currentAtom;
+ stab.string = symString;
+ break;
+ }
+ break;
+ }
+ // add to list of stabs for this .o file
+ if ( useStab )
+ _file->_stabs.push_back(stab);
+ }
+ }
+}
+
+
+
+// Look at the compilation unit DIE and determine
+// its NAME, compilation directory (in COMP_DIR) and its
+// line number information offset (in STMT_LIST). NAME and COMP_DIR
+// may be NULL (especially COMP_DIR) if they are not in the .o file;
+// STMT_LIST will be (uint64_t) -1.
+//
+// At present this assumes that there's only one compilation unit DIE.
+//
+template <typename A>
+bool Parser<A>::read_comp_unit(const char ** name, const char ** comp_dir,
+ uint64_t *stmt_list)
+{
+ const uint8_t * debug_info;
+ const uint8_t * debug_abbrev;
+ const uint8_t * di;
+ const uint8_t * da;
+ const uint8_t * end;
+ const uint8_t * enda;
+ uint64_t sz;
+ uint16_t vers;
+ uint64_t abbrev_base;
+ uint64_t abbrev;
+ uint8_t address_size;
+ bool dwarf64;
+
+ *name = NULL;
+ *comp_dir = NULL;
+ *stmt_list = (uint64_t) -1;
+
+ if ( (_file->_dwarfDebugInfoSect == NULL) || (_file->_dwarfDebugAbbrevSect == NULL) )
+ return false;
+
+ debug_info = (uint8_t*)_file->fileContent() + _file->_dwarfDebugInfoSect->offset();
+ debug_abbrev = (uint8_t*)_file->fileContent() + _file->_dwarfDebugAbbrevSect->offset();
+ di = debug_info;
+
+ if (_file->_dwarfDebugInfoSect->size() < 12)
+ /* Too small to be a real debug_info section. */
+ return false;
+ sz = A::P::E::get32(*(uint32_t*)di);
+ di += 4;
+ dwarf64 = sz == 0xffffffff;
+ if (dwarf64)
+ sz = A::P::E::get64(*(uint64_t*)di), di += 8;
+ else if (sz > 0xffffff00)
+ /* Unknown dwarf format. */
+ return false;
+
+ /* Verify claimed size. */
+ if (sz + (di - debug_info) > _file->_dwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11))
+ return false;
+
+ vers = A::P::E::get16(*(uint16_t*)di);
+ if (vers < 2 || vers > 3)
+ /* DWARF version wrong for this code.
+ Chances are we could continue anyway, but we don't know for sure. */
+ return false;
+ di += 2;
+
+ /* Find the debug_abbrev section. */
+ abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di);
+ di += dwarf64 ? 8 : 4;
+
+ if (abbrev_base > _file->_dwarfDebugAbbrevSect->size())
+ return false;
+ da = debug_abbrev + abbrev_base;
+ enda = debug_abbrev + _file->_dwarfDebugAbbrevSect->size();
+
+ address_size = *di++;
+
+ /* Find the abbrev number we're looking for. */
+ end = di + sz;
+ abbrev = read_uleb128 (&di, end);
+ if (abbrev == (uint64_t) -1)
+ return false;
+
+ /* Skip through the debug_abbrev section looking for that abbrev. */
+ for (;;)
+ {
+ uint64_t this_abbrev = read_uleb128 (&da, enda);
+ uint64_t attr;
+
+ if (this_abbrev == abbrev)
+ /* This is almost always taken. */
+ break;
+ skip_leb128 (&da, enda); /* Skip the tag. */
+ if (da == enda)
+ return false;
+ da++; /* Skip the DW_CHILDREN_* value. */
+
+ do {
+ attr = read_uleb128 (&da, enda);
+ skip_leb128 (&da, enda);
+ } while (attr != 0 && attr != (uint64_t) -1);
+ if (attr != 0)
+ return false;
+ }
+
+ /* Check that the abbrev is one for a DW_TAG_compile_unit. */
+ if (read_uleb128 (&da, enda) != DW_TAG_compile_unit)
+ return false;
+ if (da == enda)
+ return false;
+ da++; /* Skip the DW_CHILDREN_* value. */
+
+ /* Now, go through the DIE looking for DW_AT_name,
+ DW_AT_comp_dir, and DW_AT_stmt_list. */
+ for (;;)
+ {
+ uint64_t attr = read_uleb128 (&da, enda);
+ uint64_t form = read_uleb128 (&da, enda);
+
+ if (attr == (uint64_t) -1)
+ return false;
+ else if (attr == 0)
+ return true;
+
+ if (form == DW_FORM_indirect)
+ form = read_uleb128 (&di, end);
+
+ if (attr == DW_AT_name)
+ *name = getDwarfString(form, di);
+ else if (attr == DW_AT_comp_dir)
+ *comp_dir = getDwarfString(form, di);
+ else if (attr == DW_AT_stmt_list && form == DW_FORM_data4)
+ *stmt_list = A::P::E::get32(*(uint32_t*)di);
+ else if (attr == DW_AT_stmt_list && form == DW_FORM_data8)
+ *stmt_list = A::P::E::get64(*(uint64_t*)di);
+ if (! skip_form (&di, end, form, address_size, dwarf64))
+ return false;
+ }
+}
+
+
+
+template <typename A>
+File<A>::~File()
+{
+ free(_sectionsArray);
+ free(_atomsArray);
+}
+
+template <typename A>
+const char* File<A>::translationUnitSource() const
+{
+ return _dwarfTranslationUnitPath;
+}
+
+
+
+template <typename A>
+bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
+{
+ handler.doFile(*this);
+ uint8_t* p = _atomsArray;
+ for(int i=_atomsArrayCount; i > 0; --i) {
+ handler.doAtom(*((Atom<A>*)p));
+ p += sizeof(Atom<A>);
+ }
+ return (_atomsArrayCount != 0);
+}
+
+template <typename A>
+const char* Section<A>::makeSegmentName(const macho_section<typename A::P>* sect)
+{
+ // mach-o section record only has room for 16-byte seg/sect names
+ // so a 16-byte name has no trailing zero
+ const char* name = sect->segname();
+ if ( strlen(name) < 16 )
+ return name;
+ char* tmp = new char[17];
+ strlcpy(tmp, name, 17);
+ return tmp;
+}
+
+template <typename A>
+const char* Section<A>::makeSectionName(const macho_section<typename A::P>* sect)
+{
+ const char* name = sect->sectname();
+ if ( strlen(name) < 16 )
+ return name;
+
+ // special case common long section names so we don't have to malloc
+ if ( strncmp(sect->sectname(), "__objc_classrefs", 16) == 0 )
+ return "__objc_classrefs";
+ if ( strncmp(sect->sectname(), "__objc_classlist", 16) == 0 )
+ return "__objc_classlist";
+ if ( strncmp(sect->sectname(), "__objc_nlclslist", 16) == 0 )
+ return "__objc_nlclslist";
+ if ( strncmp(sect->sectname(), "__objc_nlcatlist", 16) == 0 )
+ return "__objc_nlcatlist";
+ if ( strncmp(sect->sectname(), "__objc_protolist", 16) == 0 )
+ return "__objc_protolist";
+ if ( strncmp(sect->sectname(), "__objc_protorefs", 16) == 0 )
+ return "__objc_protorefs";
+ if ( strncmp(sect->sectname(), "__objc_superrefs", 16) == 0 )
+ return "__objc_superrefs";
+ if ( strncmp(sect->sectname(), "__objc_imageinfo", 16) == 0 )
+ return "__objc_imageinfo";
+ if ( strncmp(sect->sectname(), "__objc_stringobj", 16) == 0 )
+ return "__objc_stringobj";
+ if ( strncmp(sect->sectname(), "__gcc_except_tab", 16) == 0 )
+ return "__gcc_except_tab";
+
+ char* tmp = new char[17];
+ strlcpy(tmp, name, 17);
+ return tmp;
+}
+
+template <typename A>
+bool Section<A>::readable(const macho_section<typename A::P>* sect)
+{
+ return true;
+}
+
+template <typename A>
+bool Section<A>::writable(const macho_section<typename A::P>* sect)
+{
+ // mach-o .o files do not contain segment permissions
+ // we just know TEXT is special
+ return ( strcmp(sect->segname(), "__TEXT") != 0 );
+}
+
+template <typename A>
+bool Section<A>::exectuable(const macho_section<typename A::P>* sect)
+{
+ // mach-o .o files do not contain segment permissions
+ // we just know TEXT is special
+ return ( strcmp(sect->segname(), "__TEXT") == 0 );
+}
+
+
+template <typename A>
+ld::Section::Type Section<A>::sectionType(const macho_section<typename A::P>* sect)
+{
+ switch ( sect->flags() & SECTION_TYPE ) {
+ case S_ZEROFILL:
+ return ld::Section::typeZeroFill;
+ case S_CSTRING_LITERALS:
+ if ( (strcmp(sect->sectname(), "__cstring") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) )
+ return ld::Section::typeCString;
+ else
+ return ld::Section::typeNonStdCString;
+ case S_4BYTE_LITERALS:
+ return ld::Section::typeLiteral4;
+ case S_8BYTE_LITERALS:
+ return ld::Section::typeLiteral8;
+ case S_LITERAL_POINTERS:
+ return ld::Section::typeCStringPointer;
+ case S_NON_LAZY_SYMBOL_POINTERS:
+ return ld::Section::typeNonLazyPointer;
+ case S_LAZY_SYMBOL_POINTERS:
+ return ld::Section::typeLazyPointer;
+ case S_SYMBOL_STUBS:
+ return ld::Section::typeStub;
+ case S_MOD_INIT_FUNC_POINTERS:
+ return ld::Section::typeInitializerPointers;
+ case S_MOD_TERM_FUNC_POINTERS:
+ return ld::Section::typeTerminatorPointers;
+ case S_INTERPOSING:
+ return ld::Section::typeUnclassified;
+ case S_16BYTE_LITERALS:
+ return ld::Section::typeLiteral16;
+ case S_REGULAR:
+ case S_COALESCED:
+ if ( sect->flags() & S_ATTR_PURE_INSTRUCTIONS ) {
+ return ld::Section::typeCode;
+ }
+ else if ( strcmp(sect->segname(), "__TEXT") == 0 ) {
+ if ( strcmp(sect->sectname(), "__eh_frame") == 0 )
+ return ld::Section::typeCFI;
+ else if ( strcmp(sect->sectname(), "__ustring") == 0 )
+ return ld::Section::typeUTF16Strings;
+ else if ( strcmp(sect->sectname(), "__textcoal_nt") == 0 )
+ return ld::Section::typeCode;
+ else if ( strcmp(sect->sectname(), "__StaticInit") == 0 )
+ return ld::Section::typeCode;
+ else if ( strcmp(sect->sectname(), "__constructor") == 0 )
+ return ld::Section::typeInitializerPointers;
+ }
+ else if ( strcmp(sect->segname(), "__DATA") == 0 ) {
+ if ( strcmp(sect->sectname(), "__cfstring") == 0 )
+ return ld::Section::typeCFString;
+ else if ( strcmp(sect->sectname(), "__dyld") == 0 )
+ return ld::Section::typeDyldInfo;
+ else if ( strcmp(sect->sectname(), "__program_vars") == 0 )
+ return ld::Section::typeDyldInfo;
+ else if ( strncmp(sect->sectname(), "__objc_classrefs", 16) == 0 )
+ return ld::Section::typeObjCClassRefs;
+ else if ( strcmp(sect->sectname(), "__objc_catlist") == 0 )
+ return ld::Section::typeObjC2CategoryList;
+ }
+ else if ( strcmp(sect->segname(), "__OBJC") == 0 ) {
+ if ( strcmp(sect->sectname(), "__class") == 0 )
+ return ld::Section::typeObjC1Classes;
+ }
+ break;
+ case S_THREAD_LOCAL_REGULAR:
+ return ld::Section::typeTLVInitialValues;
+ case S_THREAD_LOCAL_ZEROFILL:
+ return ld::Section::typeTLVZeroFill;
+ case S_THREAD_LOCAL_VARIABLES:
+ return ld::Section::typeTLVDefs;
+ case S_THREAD_LOCAL_INIT_FUNCTION_POINTERS:
+ return ld::Section::typeTLVInitializerPointers;
+ }
+ return ld::Section::typeUnclassified;
+}
+
+
+template <typename A>
+Atom<A>* Section<A>::findContentAtomByAddress(pint_t addr, class Atom<A>* start, class Atom<A>* end)
+{
+ // do a binary search of atom array
+ uint32_t atomCount = end - start;
+ Atom<A>* base = start;
+ for (uint32_t n = atomCount; n > 0; n /= 2) {
+ Atom<A>* pivot = &base[n/2];
+ pint_t atomStartAddr = pivot->_objAddress;
+ pint_t atomEndAddr = atomStartAddr + pivot->_size;
+ if ( atomStartAddr <= addr ) {
+ // address in normal atom
+ if (addr < atomEndAddr)
+ return pivot;
+ // address in "end" label (but not in alias)
+ if ( (pivot->_size == 0) && (addr == atomEndAddr) && !pivot->isAlias() )
+ return pivot;
+ }
+ if ( addr >= atomEndAddr ) {
+ // key > pivot
+ // move base to atom after pivot
+ base = &pivot[1];
+ --n;
+ }
+ else {
+ // key < pivot
+ // keep same base
+ }
+ }
+ return NULL;
+}
+
+template <typename A>
+ld::Atom::Alignment Section<A>::alignmentForAddress(pint_t addr)
+{
+ const uint32_t sectionAlignment = this->_machOSection->align();
+ return ld::Atom::Alignment(sectionAlignment, (addr % (1 << sectionAlignment)));
+}
+
+template <typename A>
+uint32_t Section<A>::sectionNum(class Parser<A>& parser) const
+{
+ if ( _machOSection == NULL )
+ return 0;
+ else
+ return 1 + (this->_machOSection - parser.firstMachOSection());
+}
+
+// arm does not have zero cost exceptions
+template <> uint32_t CFISection<arm>::cfiCount() { return 0; }
+
+template <typename A>
+uint32_t CFISection<A>::cfiCount()
+{
+ // create ObjectAddressSpace object for use by libunwind
+ OAS oas(*this, (uint8_t*)this->file().fileContent()+this->_machOSection->offset());
+ return libunwind::CFI_Parser<OAS>::getCFICount(oas,
+ this->_machOSection->addr(), this->_machOSection->size());
+}
+
+template <typename A>
+void CFISection<A>::warnFunc(void* ref, uint64_t funcAddr, const char* msg)
+{
+ Parser<A>* parser = (Parser<A>*)ref;
+ if ( ! parser->convertUnwindInfo() )
+ return;
+ if ( funcAddr != CFI_INVALID_ADDRESS ) {
+ // atoms are not constructed yet, so scan symbol table for labels
+ const char* name = parser->scanSymbolTableForAddress(funcAddr);
+ warning("could not create compact unwind for %s: %s", name, msg);
+ }
+ else {
+ warning("could not create compact unwind: %s", msg);
+ }
+}
+
+template <>
+bool CFISection<x86_64>::needsRelocating()
+{
+ return true;
+}
+
+template <typename A>
+bool CFISection<A>::needsRelocating()
+{
+ return false;
+}
+
+template <>
+void CFISection<x86_64>::cfiParse(class Parser<x86_64>& parser, uint8_t* buffer,
+ libunwind::CFI_Atom_Info<CFISection<x86_64>::OAS>::CFI_Atom_Info cfiArray[],
+ uint32_t count)
+{
+ // copy __eh_frame data to buffer
+ memcpy(buffer, file().fileContent() + this->_machOSection->offset(), this->_machOSection->size());
+
+ // and apply relocations
+ const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(file().fileContent() + this->_machOSection->reloff());
+ const macho_relocation_info<P>* relocsEnd = &relocs[this->_machOSection->nreloc()];
+ for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
+ uint64_t value = 0;
+ switch ( reloc->r_type() ) {
+ case X86_64_RELOC_SUBTRACTOR:
+ value = 0 - parser.symbolFromIndex(reloc->r_symbolnum()).n_value();
+ ++reloc;
+ if ( reloc->r_extern() )
+ value += parser.symbolFromIndex(reloc->r_symbolnum()).n_value();
+ break;
+ case X86_64_RELOC_UNSIGNED:
+ value = parser.symbolFromIndex(reloc->r_symbolnum()).n_value();
+ break;
+ case X86_64_RELOC_GOT:
+ // this is used for the reference to the personality function in CIEs
+ // store the symbol number of the personality function for later use as a Fixup
+ value = reloc->r_symbolnum();
+ break;
+ default:
+ fprintf(stderr, "CFISection::cfiParse() unexpected relocation type at r_address=0x%08X\n", reloc->r_address());
+ break;
+ }
+ uint64_t* p64;
+ uint32_t* p32;
+ switch ( reloc->r_length() ) {
+ case 3:
+ p64 = (uint64_t*)&buffer[reloc->r_address()];
+ E::set64(*p64, value + E::get64(*p64));
+ break;
+ case 2:
+ p32 = (uint32_t*)&buffer[reloc->r_address()];
+ E::set32(*p32, value + E::get32(*p32));
+ break;
+ default:
+ fprintf(stderr, "CFISection::cfiParse() unexpected relocation size at r_address=0x%08X\n", reloc->r_address());
+ break;
+ }
+ }
+
+
+ // create ObjectAddressSpace object for use by libunwind
+ OAS oas(*this, buffer);
+
+ // use libuwind to parse __eh_frame data into array of CFI_Atom_Info
+ const char* msg;
+ msg = libunwind::DwarfInstructions<OAS, libunwind::Registers_x86_64>::parseCFIs(
+ oas, this->_machOSection->addr(), this->_machOSection->size(),
+ cfiArray, count, (void*)&parser, warnFunc);
+ if ( msg != NULL )
+ throwf("malformed __eh_frame section: %s", msg);
+}
+
+template <>
+void CFISection<x86>::cfiParse(class Parser<x86>& parser, uint8_t* buffer,
+ libunwind::CFI_Atom_Info<CFISection<x86>::OAS>::CFI_Atom_Info cfiArray[],
+ uint32_t count)
+{
+ // create ObjectAddressSpace object for use by libunwind
+ OAS oas(*this, (uint8_t*)this->file().fileContent()+this->_machOSection->offset());
+
+ // use libuwind to parse __eh_frame data into array of CFI_Atom_Info
+ const char* msg;
+ msg = libunwind::DwarfInstructions<OAS, libunwind::Registers_x86>::parseCFIs(
+ oas, this->_machOSection->addr(), this->_machOSection->size(),
+ cfiArray, count, (void*)&parser, warnFunc);
+ if ( msg != NULL )
+ throwf("malformed __eh_frame section: %s", msg);
+}
+
+
+
+
+template <>
+void CFISection<arm>::cfiParse(class Parser<arm>& parser, uint8_t* buffer,
+ libunwind::CFI_Atom_Info<CFISection<arm>::OAS>::CFI_Atom_Info cfiArray[],
+ uint32_t count)
+{
+ // arm does not use zero cost exceptions
+ assert(count == 0);
+}
+
+
+
+template <typename A>
+uint32_t CFISection<A>::computeAtomCount(class Parser<A>& parser,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays& cfis)
+{
+ return cfis.cfiCount;
+}
+
+
+
+template <typename A>
+uint32_t CFISection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays& cfis)
+{
+ this->_beginAtoms = (Atom<A>*)p;
+ // walk CFI_Atom_Info array and create atom for each entry
+ const CFI_Atom_Info* start = &cfis.cfiArray[0];
+ const CFI_Atom_Info* end = &cfis.cfiArray[cfis.cfiCount];
+ for(const CFI_Atom_Info* a=start; a < end; ++a) {
+ Atom<A>* space = (Atom<A>*)p;
+ new (space) Atom<A>(*this, (a->isCIE ? "CIE" : "FDE"), a->address, a->size,
+ ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit,
+ ld::Atom::typeCFI, ld::Atom::symbolTableNotInFinalLinkedImages,
+ false, false, false, ld::Atom::Alignment(0));
+ p += sizeof(Atom<A>);
+ }
+ this->_endAtoms = (Atom<A>*)p;
+ return cfis.cfiCount;
+}
+
+
+template <> bool CFISection<x86_64>::bigEndian() { return false; }
+template <> bool CFISection<x86>::bigEndian() { return false; }
+template <> bool CFISection<arm>::bigEndian() { return false; }
+
+
+template <>
+void CFISection<x86_64>::addCiePersonalityFixups(class Parser<x86_64>& parser, const CFI_Atom_Info* cieInfo)
+{
+ uint8_t personalityEncoding = cieInfo->u.cieInfo.personality.encodingOfTargetAddress;
+ if ( personalityEncoding == 0x9B ) {
+ // compiler always produces X86_64_RELOC_GOT with addend of 4 to personality function
+ // CFISection<x86_64>::cfiParse() set targetAddress to be symbolIndex + 4 + addressInCIE
+ uint32_t symbolIndex = cieInfo->u.cieInfo.personality.targetAddress - 4
+ - cieInfo->address - cieInfo->u.cieInfo.personality.offsetInCFI;
+ const macho_nlist<P>& sym = parser.symbolFromIndex(symbolIndex);
+ const char* personalityName = parser.nameFromSymbol(sym);
+
+ Atom<x86_64>* cieAtom = this->findAtomByAddress(cieInfo->address);
+ Parser<x86_64>::SourceLocation src(cieAtom, cieInfo->u.cieInfo.personality.offsetInCFI);
+ parser.addFixup(src, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, false, personalityName);
+ parser.addFixup(src, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, 4);
+ parser.addFixup(src, ld::Fixup::k3of3, ld::Fixup::kindStoreX86PCRel32GOT);
+ }
+ else if ( personalityEncoding != 0 ) {
+ throwf("unsupported address encoding (%02X) of personality function in CIE",
+ personalityEncoding);
+ }
+}
+
+template <>
+void CFISection<x86>::addCiePersonalityFixups(class Parser<x86>& parser, const CFI_Atom_Info* cieInfo)
+{
+ uint8_t personalityEncoding = cieInfo->u.cieInfo.personality.encodingOfTargetAddress;
+ if ( (personalityEncoding == 0x9B) || (personalityEncoding == 0x90) ) {
+ uint32_t offsetInCFI = cieInfo->u.cieInfo.personality.offsetInCFI;
+ uint32_t nlpAddr = cieInfo->u.cieInfo.personality.targetAddress;
+ Atom<x86>* cieAtom = this->findAtomByAddress(cieInfo->address);
+ Atom<x86>* nlpAtom = parser.findAtomByAddress(nlpAddr);
+ assert(nlpAtom->contentType() == ld::Atom::typeNonLazyPointer);
+ Parser<x86>::SourceLocation src(cieAtom, cieInfo->u.cieInfo.personality.offsetInCFI);
+
+ parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, nlpAtom);
+ parser.addFixup(src, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, cieAtom);
+ parser.addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, offsetInCFI);
+ parser.addFixup(src, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32);
+ }
+ else if ( personalityEncoding != 0 ) {
+ throwf("unsupported address encoding (%02X) of personality function in CIE", personalityEncoding);
+ }
+}
+
+
+template <typename A>
+void CFISection<A>::addCiePersonalityFixups(class Parser<A>& parser, const CFI_Atom_Info* cieInfo)
+{
+ // FIX ME
+ assert(0);
+}
+
+template <typename A>
+void CFISection<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays& cfis)
+{
+ ld::Fixup::Kind store32 = bigEndian() ? ld::Fixup::kindStoreBigEndian32 : ld::Fixup::kindStoreLittleEndian32;
+ ld::Fixup::Kind store64 = bigEndian() ? ld::Fixup::kindStoreBigEndian64 : ld::Fixup::kindStoreLittleEndian64;
+
+ // add all references for FDEs, including implicit group references
+ const CFI_Atom_Info* end = &cfis.cfiArray[cfis.cfiCount];
+ for(const CFI_Atom_Info* p = &cfis.cfiArray[0]; p < end; ++p) {
+ if ( p->isCIE ) {
+ // add reference to personality function if used
+ if ( p->u.cieInfo.personality.targetAddress != CFI_INVALID_ADDRESS ) {
+ this->addCiePersonalityFixups(parser, p);
+ }
+ }
+ else {
+ // find FDE Atom
+ Atom<A>* fdeAtom = this->findAtomByAddress(p->address);
+ // find function Atom
+ Atom<A>* functionAtom = parser.findAtomByAddress(p->u.fdeInfo.function.targetAddress);
+ // find CIE Atom
+ Atom<A>* cieAtom = this->findAtomByAddress(p->u.fdeInfo.cie.targetAddress);
+ // find LSDA Atom
+ Atom<A>* lsdaAtom = NULL;
+ if ( p->u.fdeInfo.lsda.targetAddress != CFI_INVALID_ADDRESS ) {
+ lsdaAtom = parser.findAtomByAddress(p->u.fdeInfo.lsda.targetAddress);
+ }
+ // add reference from FDE to CIE (always 32-bit pc-rel)
+ typename Parser<A>::SourceLocation fdeToCieSrc(fdeAtom, p->u.fdeInfo.cie.offsetInCFI);
+ parser.addFixup(fdeToCieSrc, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, fdeAtom);
+ parser.addFixup(fdeToCieSrc, ld::Fixup::k2of4, ld::Fixup::kindAddAddend, p->u.fdeInfo.cie.offsetInCFI);
+ parser.addFixup(fdeToCieSrc, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, cieAtom);
+ parser.addFixup(fdeToCieSrc, ld::Fixup::k4of4, store32, cieAtom);
+
+ // add reference from FDE to function
+ typename Parser<A>::SourceLocation fdeToFuncSrc(fdeAtom, p->u.fdeInfo.function.offsetInCFI);
+ switch (p->u.fdeInfo.function.encodingOfTargetAddress) {
+ case DW_EH_PE_pcrel|DW_EH_PE_ptr:
+ if ( sizeof(typename A::P::uint_t) == 8 ) {
+ parser.addFixup(fdeToFuncSrc, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, functionAtom);
+ parser.addFixup(fdeToFuncSrc, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, fdeAtom);
+ parser.addFixup(fdeToFuncSrc, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, p->u.fdeInfo.function.offsetInCFI);
+ parser.addFixup(fdeToFuncSrc, ld::Fixup::k4of4, store64);
+ break;
+ }
+ // else fall into 32-bit case
+ case DW_EH_PE_pcrel|DW_EH_PE_sdata4:
+ parser.addFixup(fdeToFuncSrc, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, functionAtom);
+ parser.addFixup(fdeToFuncSrc, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, fdeAtom);
+ parser.addFixup(fdeToFuncSrc, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, p->u.fdeInfo.function.offsetInCFI);
+ parser.addFixup(fdeToFuncSrc, ld::Fixup::k4of4, store32);
+ break;
+ default:
+ throw "unsupported encoding in FDE of pointer to function";
+ }
+
+ // add reference from FDE to LSDA
+ typename Parser<A>::SourceLocation fdeToLsdaSrc(fdeAtom, p->u.fdeInfo.lsda.offsetInCFI);
+ if ( lsdaAtom != NULL ) {
+ switch (p->u.fdeInfo.lsda.encodingOfTargetAddress) {
+ case DW_EH_PE_pcrel|DW_EH_PE_ptr:
+ if ( sizeof(typename A::P::uint_t) == 8 ) {
+ parser.addFixup(fdeToLsdaSrc, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, lsdaAtom);
+ parser.addFixup(fdeToLsdaSrc, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, fdeAtom);
+ parser.addFixup(fdeToLsdaSrc, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, p->u.fdeInfo.lsda.offsetInCFI);
+ parser.addFixup(fdeToLsdaSrc, ld::Fixup::k4of4, store64);
+ break;
+ }
+ // else fall into 32-bit case
+ case DW_EH_PE_pcrel|DW_EH_PE_sdata4:
+ parser.addFixup(fdeToLsdaSrc, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, lsdaAtom);
+ parser.addFixup(fdeToLsdaSrc, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, fdeAtom);
+ parser.addFixup(fdeToLsdaSrc, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, p->u.fdeInfo.lsda.offsetInCFI);
+ parser.addFixup(fdeToLsdaSrc, ld::Fixup::k4of4, store32);
+ break;
+ default:
+ throw "unsupported encoding in FDE of pointer to LSDA";
+ }
+ }
+
+ // FDE is in group lead by function atom
+ typename Parser<A>::SourceLocation fdeSrc(functionAtom,0);
+ parser.addFixup(fdeSrc, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinateFDE, fdeAtom);
+
+ // LSDA is in group lead by function atom
+ if ( lsdaAtom != NULL ) {
+ parser.addFixup(fdeSrc, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinateLSDA, lsdaAtom);
+ }
+ }
+ }
+}
+
+
+
+
+template <typename A>
+const void* CFISection<A>::OAS::mappedAddress(pint_t addr)
+{
+ if ( (_ehFrameStartAddr <= addr) && (addr < _ehFrameEndAddr) )
+ return &_ehFrameContent[addr-_ehFrameStartAddr];
+ else {
+ // requested bytes are not in __eh_frame section
+ // this can occur when examining the instruction bytes in the __text
+ File<A>& file = _ehFrameSection.file();
+ for (uint32_t i=0; i < file._sectionsArrayCount; ++i ) {
+ const macho_section<typename A::P>* sect = file._sectionsArray[i]->machoSection();
+ // TentativeDefinitionSection and AbsoluteSymbolSection have no mach-o section
+ if ( sect != NULL ) {
+ if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) ) {
+ return file.fileContent() + sect->offset() + addr - sect->addr();
+ }
+ }
+ }
+ throwf("__eh_frame parsing problem. Can't find target of reference to address 0x%08llX", (uint64_t)addr);
+ }
+}
+
+
+template <typename A>
+uint64_t CFISection<A>::OAS::getULEB128(pint_t& logicalAddr, pint_t end)
+{
+ uintptr_t size = (end - logicalAddr);
+ libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr);
+ libunwind::LocalAddressSpace::pint_t sladdr = laddr;
+ uint64_t result = libunwind::LocalAddressSpace::getULEB128(laddr, laddr+size);
+ logicalAddr += (laddr-sladdr);
+ return result;
+}
+
+template <typename A>
+int64_t CFISection<A>::OAS::getSLEB128(pint_t& logicalAddr, pint_t end)
+{
+ uintptr_t size = (end - logicalAddr);
+ libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr);
+ libunwind::LocalAddressSpace::pint_t sladdr = laddr;
+ int64_t result = libunwind::LocalAddressSpace::getSLEB128(laddr, laddr+size);
+ logicalAddr += (laddr-sladdr);
+ return result;
+}
+
+template <typename A>
+typename A::P::uint_t CFISection<A>::OAS::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
+{
+ pint_t startAddr = addr;
+ pint_t p = addr;
+ pint_t result;
+
+ // first get value
+ switch (encoding & 0x0F) {
+ case DW_EH_PE_ptr:
+ result = getP(addr);
+ p += sizeof(pint_t);
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_uleb128:
+ result = getULEB128(addr, end);
+ break;
+ case DW_EH_PE_udata2:
+ result = get16(addr);
+ p += 2;
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_udata4:
+ result = get32(addr);
+ p += 4;
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_udata8:
+ result = get64(addr);
+ p += 8;
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_sleb128:
+ result = getSLEB128(addr, end);
+ break;
+ case DW_EH_PE_sdata2:
+ result = (int16_t)get16(addr);
+ p += 2;
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_sdata4:
+ result = (int32_t)get32(addr);
+ p += 4;
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_sdata8:
+ result = get64(addr);
+ p += 8;
+ addr = (pint_t)p;
+ break;
+ default:
+ throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding);
+ }
+
+ // then add relative offset
+ switch ( encoding & 0x70 ) {
+ case DW_EH_PE_absptr:
+ // do nothing
+ break;
+ case DW_EH_PE_pcrel:
+ result += startAddr;
+ break;
+ case DW_EH_PE_textrel:
+ throw "DW_EH_PE_textrel pointer encoding not supported";
+ break;
+ case DW_EH_PE_datarel:
+ throw "DW_EH_PE_datarel pointer encoding not supported";
+ break;
+ case DW_EH_PE_funcrel:
+ throw "DW_EH_PE_funcrel pointer encoding not supported";
+ break;
+ case DW_EH_PE_aligned:
+ throw "DW_EH_PE_aligned pointer encoding not supported";
+ break;
+ default:
+ throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding);
+ break;
+ }
+
+// Note: DW_EH_PE_indirect is only used in CIEs to refernce the personality pointer
+// When parsing .o files that pointer contains zero, so we don't to return that.
+// Instead we skip the dereference and return the address of the pointer.
+// if ( encoding & DW_EH_PE_indirect )
+// result = getP(result);
+
+ return result;
+}
+
+template <>
+const char* CUSection<x86_64>::personalityName(class Parser<x86_64>& parser, const macho_relocation_info<x86_64::P>* reloc)
+{
+ assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+ assert((reloc->r_type() == X86_64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
+ const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+ return parser.nameFromSymbol(sym);
+}
+
+template <>
+const char* CUSection<x86>::personalityName(class Parser<x86>& parser, const macho_relocation_info<x86::P>* reloc)
+{
+ assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+ assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section");
+ const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+ return parser.nameFromSymbol(sym);
+}
+
+template <typename A>
+const char* CUSection<A>::personalityName(class Parser<A>& parser, const macho_relocation_info<P>* reloc)
+{
+ return NULL;
+}
+
+
+template <typename A>
+int CUSection<A>::infoSorter(const void* l, const void* r)
+{
+ // sort references by symbol index, then address
+ const Info* left = (Info*)l;
+ const Info* right = (Info*)r;
+ if ( left->functionSymbolIndex == right->functionSymbolIndex )
+ return (left->functionStartAddress - right->functionStartAddress);
+ else
+ return (left->functionSymbolIndex - right->functionSymbolIndex);
+}
+
+template <typename A>
+void CUSection<A>::parse(class Parser<A>& parser, uint32_t cnt, Info array[])
+{
+ // walk section content and copy to Info array
+ const macho_compact_unwind_entry<P>* const entries = (macho_compact_unwind_entry<P>*)(this->file().fileContent() + this->_machOSection->offset());
+ for (uint32_t i=0; i < cnt; ++i) {
+ Info* info = &array[i];
+ const macho_compact_unwind_entry<P>* entry = &entries[i];
+ info->functionStartAddress = entry->codeStart();
+ info->functionSymbolIndex = 0xFFFFFFFF;
+ info->rangeLength = entry->codeLen();
+ info->compactUnwindInfo = entry->compactUnwindInfo();
+ info->personality = NULL;
+ info->lsdaAddress = entry->lsda();
+ info->function = NULL;
+ info->lsda = NULL;
+ if ( (info->compactUnwindInfo & UNWIND_PERSONALITY_MASK) != 0 )
+ warning("no bits should be set in UNWIND_PERSONALITY_MASK of compact unwind encoding in __LD,__compact_unwind section");
+ if ( info->lsdaAddress != 0 ) {
+ info->compactUnwindInfo |= UNWIND_HAS_LSDA;
+ }
+ }
+
+ // scan relocs, local relocs are useless - ignore them
+ // extern relocs are needed for personality references (possibly for function/lsda refs??)
+ const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(this->file().fileContent() + this->_machOSection->reloff());
+ const macho_relocation_info<P>* relocsEnd = &relocs[this->_machOSection->nreloc()];
+ for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
+ if ( reloc->r_extern() ) {
+ // only expect external relocs on some colummns
+ if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry<P>)) == macho_compact_unwind_entry<P>::personalityFieldOffset() ) {
+ uint32_t entryIndex = reloc->r_address() / sizeof(macho_compact_unwind_entry<P>);
+ array[entryIndex].personality = this->personalityName(parser, reloc);
+ }
+ else if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry<P>)) == macho_compact_unwind_entry<P>::lsdaFieldOffset() ) {
+ uint32_t entryIndex = reloc->r_address() / sizeof(macho_compact_unwind_entry<P>);
+ const macho_nlist<P>& lsdaSym = parser.symbolFromIndex(reloc->r_symbolnum());
+ if ( (lsdaSym.n_type() & N_TYPE) == N_SECT )
+ array[entryIndex].lsdaAddress = lsdaSym.n_value();
+ else
+ warning("unexpected extern relocation to lsda in __compact_unwind section");
+ }
+ else if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry<P>)) == macho_compact_unwind_entry<P>::codeStartFieldOffset() ) {
+ uint32_t entryIndex = reloc->r_address() / sizeof(macho_compact_unwind_entry<P>);
+ array[entryIndex].functionSymbolIndex = reloc->r_symbolnum();
+ }
+ else {
+ warning("unexpected extern relocation in __compact_unwind section");
+ }
+ }
+ }
+
+ // sort array by function start address so unwind infos will be contiguous for a given function
+ ::qsort(array, cnt, sizeof(Info), infoSorter);
+}
+
+template <typename A>
+uint32_t CUSection<A>::count()
+{
+ const macho_section<P>* machoSect = this->machoSection();
+ if ( (machoSect->size() % sizeof(macho_compact_unwind_entry<P>)) != 0 )
+ throw "malformed __LD,__compact_unwind section, bad length";
+
+ return machoSect->size() / sizeof(macho_compact_unwind_entry<P>);
+}
+
+template <typename A>
+void CUSection<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays& cus)
+{
+ Info* const arrayStart = cus.cuArray;
+ Info* const arrayEnd = &cus.cuArray[cus.cuCount];
+ for (Info* info=arrayStart; info < arrayEnd; ++info) {
+ // if external reloc was used, real address is symbol n_value + addend
+ if ( info->functionSymbolIndex != 0xFFFFFFFF )
+ info->functionStartAddress += parser.symbolFromIndex(info->functionSymbolIndex).n_value();
+ // find function atom from address
+ info->function = parser.findAtomByAddress(info->functionStartAddress);
+ // find lsda atom from address
+ if ( info->lsdaAddress != 0 ) {
+ info->lsda = parser.findAtomByAddress(info->lsdaAddress);
+ // add lsda subordinate
+ typename Parser<A>::SourceLocation src(info->function, info->functionStartAddress - info->function->objectAddress());
+ parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinateLSDA, info->lsda);
+ }
+ if ( info->personality != NULL ) {
+ // add personality subordinate
+ typename Parser<A>::SourceLocation src(info->function, info->functionStartAddress - info->function->objectAddress());
+ parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinatePersonality, false, info->personality);
+ }
+ }
+
+}
+
+template <typename A>
+SymboledSection<A>::SymboledSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+ : Section<A>(f, s), _type(ld::Atom::typeUnclassified)
+{
+ switch ( s->flags() & SECTION_TYPE ) {
+ case S_ZEROFILL:
+ _type = ld::Atom::typeZeroFill;
+ break;
+ case S_MOD_INIT_FUNC_POINTERS:
+ _type = ld::Atom::typeInitializerPointers;
+ break;
+ case S_MOD_TERM_FUNC_POINTERS:
+ _type = ld::Atom::typeTerminatorPointers;
+ break;
+ case S_THREAD_LOCAL_VARIABLES:
+ _type = ld::Atom::typeTLV;
+ break;
+ case S_THREAD_LOCAL_ZEROFILL:
+ _type = ld::Atom::typeTLVZeroFill;
+ break;
+ case S_THREAD_LOCAL_REGULAR:
+ _type = ld::Atom::typeTLVInitialValue;
+ break;
+ case S_THREAD_LOCAL_INIT_FUNCTION_POINTERS:
+ _type = ld::Atom::typeTLVInitializerPointers;
+ break;
+ case S_REGULAR:
+ if ( strncmp(s->sectname(), "__gcc_except_tab", 16) == 0 )
+ _type = ld::Atom::typeLSDA;
+ else if ( this->type() == ld::Section::typeInitializerPointers )
+ _type = ld::Atom::typeInitializerPointers;
+ break;
+ }
+}
+
+
+template <typename A>
+bool SymboledSection<A>::dontDeadStrip()
+{
+ switch ( _type ) {
+ case ld::Atom::typeInitializerPointers:
+ case ld::Atom::typeTerminatorPointers:
+ return true;
+ default:
+ // model an object file without MH_SUBSECTIONS_VIA_SYMBOLS as one in which nothing can be dead stripped
+ if ( ! this->_file.canScatterAtoms() )
+ return true;
+ // call inherited
+ return Section<A>::dontDeadStrip();
+ }
+ return false;
+}
+
+
+template <typename A>
+uint32_t SymboledSection<A>::computeAtomCount(class Parser<A>& parser,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&)
+{
+ const pint_t startAddr = this->_machOSection->addr();
+ const pint_t endAddr = startAddr + this->_machOSection->size();
+ const uint32_t sectNum = this->sectionNum(parser);
+
+ uint32_t count = 0;
+ pint_t addr;
+ pint_t size;
+ const macho_nlist<P>* sym;
+ while ( it.next(parser, sectNum, startAddr, endAddr, &addr, &size, &sym) ) {
+ ++count;
+ }
+ //fprintf(stderr, "computeAtomCount(%s,%s) => %d\n", this->segmentName(), this->sectionName(), count);
+ return count;
+}
+
+template <typename A>
+uint32_t SymboledSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&)
+{
+ this->_beginAtoms = (Atom<A>*)p;
+
+ //fprintf(stderr, "SymboledSection::appendAtoms() in section %s\n", this->_machOSection->sectname());
+ const pint_t startAddr = this->_machOSection->addr();
+ const pint_t endAddr = startAddr + this->_machOSection->size();
+ const uint32_t sectNum = this->sectionNum(parser);
+
+ uint32_t count = 0;
+ pint_t addr;
+ pint_t size;
+ const macho_nlist<P>* label;
+ while ( it.next(parser, sectNum, startAddr, endAddr, &addr, &size, &label) ) {
+ Atom<A>* allocatedSpace = (Atom<A>*)p;
+ // is break because of label or CFI?
+ if ( label != NULL ) {
+ // The size is computed based on the address of the next label (or the end of the section for the last label)
+ // If there are two labels at the same address, we want them one to be an alias of the other.
+ // If the label is at the end of a section, it is has zero size, but is not an alias
+ const bool isAlias = ( (size == 0) && (addr < endAddr) );
+ new (allocatedSpace) Atom<A>(*this, parser, *label, size, isAlias);
+ if ( isAlias )
+ this->_hasAliases = true;
+ }
+ else {
+ ld::Atom::SymbolTableInclusion inclusion = ld::Atom::symbolTableNotIn;
+ ld::Atom::ContentType ctype = this->contentType();
+ if ( ctype == ld::Atom::typeLSDA )
+ inclusion = ld::Atom::symbolTableInWithRandomAutoStripLabel;
+ new (allocatedSpace) Atom<A>(*this, "anon", addr, size, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeTranslationUnit, ctype, inclusion,
+ this->dontDeadStrip(), false, false, this->alignmentForAddress(addr));
+ }
+ p += sizeof(Atom<A>);
+ ++count;
+ }
+
+ this->_endAtoms = (Atom<A>*)p;
+ return count;
+}
+
+
+template <typename A>
+uint32_t ImplicitSizeSection<A>::computeAtomCount(class Parser<A>& parser,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&)
+{
+ uint32_t count = 0;
+ const macho_section<P>* sect = this->machoSection();
+ const pint_t startAddr = sect->addr();
+ const pint_t endAddr = startAddr + sect->size();
+ for (pint_t addr = startAddr; addr < endAddr; addr += elementSizeAtAddress(addr) ) {
+ if ( useElementAt(parser, it, addr) )
+ ++count;
+ }
+ if ( it.fileHasOverlappingSymbols && (sect->size() != 0) && (this->combine(parser, startAddr) == ld::Atom::combineByNameAndContent) ) {
+ // if there are multiple labels in this section for the same address, then clone them into multi atoms
+ pint_t prevSymbolAddr = (pint_t)(-1);
+ uint8_t prevSymbolSectNum = 0;
+ for(uint32_t i=0; i < it.sortedSymbolCount; ++i) {
+ const macho_nlist<P>& sym = parser.symbolFromIndex(it.sortedSymbolIndexes[i]);
+ const pint_t symbolAddr = sym.n_value();
+ const pint_t symbolSectNum = sym.n_sect();
+ if ( (symbolAddr == prevSymbolAddr) && (prevSymbolSectNum == symbolSectNum) && (symbolSectNum == this->sectionNum(parser)) ) {
+ ++count;
+ }
+ prevSymbolAddr = symbolAddr;
+ prevSymbolSectNum = symbolSectNum;
+ }
+ }
+ return count;
+}
+
+template <typename A>
+uint32_t ImplicitSizeSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
+ const struct Parser<A>::CFI_CU_InfoArrays&)
+{
+ this->_beginAtoms = (Atom<A>*)p;
+
+ const macho_section<P>* sect = this->machoSection();
+ const pint_t startAddr = sect->addr();
+ const pint_t endAddr = startAddr + sect->size();
+ const uint32_t sectNum = this->sectionNum(parser);
+ //fprintf(stderr, "ImplicitSizeSection::appendAtoms() in section %s\n", sect->sectname());
+ uint32_t count = 0;
+ pint_t foundAddr;
+ pint_t size;
+ const macho_nlist<P>* foundLabel;
+ Atom<A>* allocatedSpace;
+ while ( it.next(parser, sectNum, startAddr, endAddr, &foundAddr, &size, &foundLabel) ) {
+ if ( foundLabel != NULL ) {
+ pint_t labeledAtomSize = this->elementSizeAtAddress(foundAddr);
+ allocatedSpace = (Atom<A>*)p;
+ if ( this->ignoreLabel(parser.nameFromSymbol(*foundLabel)) ) {
+ //fprintf(stderr, " 0x%08llX make annon\n", (uint64_t)foundAddr);
+ new (allocatedSpace) Atom<A>(*this, this->unlabeledAtomName(parser, foundAddr), foundAddr,
+ this->elementSizeAtAddress(foundAddr), this->definition(),
+ this->combine(parser, foundAddr), this->scopeAtAddress(parser, foundAddr),
+ this->contentType(), this->symbolTableInclusion(),
+ this->dontDeadStrip(), false, false, this->alignmentForAddress(foundAddr));
+ }
+ else {
+ // make named atom for label
+ //fprintf(stderr, " 0x%08llX make labeled\n", (uint64_t)foundAddr);
+ new (allocatedSpace) Atom<A>(*this, parser, *foundLabel, labeledAtomSize);
+ }
+ ++count;
+ p += sizeof(Atom<A>);
+ foundAddr += labeledAtomSize;
+ size -= labeledAtomSize;
+ }
+ // some number of anonymous atoms
+ for (pint_t addr = foundAddr; addr < (foundAddr+size); addr += elementSizeAtAddress(addr) ) {
+ // make anon atoms for area before label
+ if ( this->useElementAt(parser, it, addr) ) {
+ //fprintf(stderr, " 0x%08llX make annon\n", (uint64_t)addr);
+ allocatedSpace = (Atom<A>*)p;
+ new (allocatedSpace) Atom<A>(*this, this->unlabeledAtomName(parser, addr), addr, this->elementSizeAtAddress(addr),
+ this->definition(), this->combine(parser, addr), this->scopeAtAddress(parser, addr),
+ this->contentType(), this->symbolTableInclusion(),
+ this->dontDeadStrip(), false, false, this->alignmentForAddress(addr));
+ ++count;
+ p += sizeof(Atom<A>);
+ }
+ }
+ }
+
+ this->_endAtoms = (Atom<A>*)p;
+
+ return count;
+}
+
+
+template <typename A>
+unsigned long Literal4Section<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+ const uint32_t* literalContent = (uint32_t*)atom->contentPointer();
+ return *literalContent;
+}
+
+template <typename A>
+bool Literal4Section<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const
+{
+ assert(this->type() == rhs.section().type());
+ const uint32_t* literalContent = (uint32_t*)atom->contentPointer();
+
+ const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+ assert(rhsAtom != NULL);
+ if ( rhsAtom != NULL ) {
+ const uint32_t* rhsLiteralContent = (uint32_t*)rhsAtom->contentPointer();
+ return (*literalContent == *rhsLiteralContent);
+ }
+ return false;
+}
+
+
+template <typename A>
+unsigned long Literal8Section<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+#if __LP64__
+ const uint64_t* literalContent = (uint64_t*)atom->contentPointer();
+ return *literalContent;
+#else
+ unsigned long hash = 5381;
+ const uint8_t* byteContent = atom->contentPointer();
+ for (int i=0; i < 8; ++i) {
+ hash = hash * 33 + byteContent[i];
+ }
+ return hash;
+#endif
+}
+
+template <typename A>
+bool Literal8Section<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const
+{
+ if ( rhs.section().type() != ld::Section::typeLiteral8 )
+ return false;
+ assert(this->type() == rhs.section().type());
+ const uint64_t* literalContent = (uint64_t*)atom->contentPointer();
+
+ const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+ assert(rhsAtom != NULL);
+ if ( rhsAtom != NULL ) {
+ const uint64_t* rhsLiteralContent = (uint64_t*)rhsAtom->contentPointer();
+ return (*literalContent == *rhsLiteralContent);
+ }
+ return false;
+}
+
+
+template <typename A>
+unsigned long Literal16Section<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+ unsigned long hash = 5381;
+ const uint8_t* byteContent = atom->contentPointer();
+ for (int i=0; i < 16; ++i) {
+ hash = hash * 33 + byteContent[i];
+ }
+ return hash;
+}
+
+template <typename A>
+bool Literal16Section<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const
+{
+ if ( rhs.section().type() != ld::Section::typeLiteral16 )
+ return false;
+ assert(this->type() == rhs.section().type());
+ const uint64_t* literalContent = (uint64_t*)atom->contentPointer();
+
+ const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+ assert(rhsAtom != NULL);
+ if ( rhsAtom != NULL ) {
+ const uint64_t* rhsLiteralContent = (uint64_t*)rhsAtom->contentPointer();
+ return ((literalContent[0] == rhsLiteralContent[0]) && (literalContent[1] == rhsLiteralContent[1]));
+ }
+ return false;
+}
+
+
+
+template <typename A>
+typename A::P::uint_t CStringSection<A>::elementSizeAtAddress(pint_t addr)
+{
+ const macho_section<P>* sect = this->machoSection();
+ const char* stringContent = (char*)(this->file().fileContent() + sect->offset() + addr - sect->addr());
+ return strlen(stringContent) + 1;
+}
+
+template <typename A>
+bool CStringSection<A>::useElementAt(Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, pint_t addr)
+{
+ return true;
+}
+
+template <typename A>
+bool CStringSection<A>::ignoreLabel(const char* label)
+{
+ return (label[0] == 'L') || (label[0] == 'l');
+}
+
+template <typename A>
+Atom<A>* CStringSection<A>::findAtomByAddress(pint_t addr)
+{
+ Atom<A>* result = this->findContentAtomByAddress(addr, this->_beginAtoms, this->_endAtoms);
+ return result;
+}
+
+template <typename A>
+unsigned long CStringSection<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+ unsigned long hash = 5381;
+ const char* stringContent = (char*)atom->contentPointer();
+ for (const char* s = stringContent; *s != '\0'; ++s) {
+ hash = hash * 33 + *s;
+ }
+ return hash;
+}
+
+
+template <typename A>
+bool CStringSection<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const
+{
+ if ( rhs.section().type() != ld::Section::typeCString )
+ return false;
+ assert(this->type() == rhs.section().type());
+ assert(strcmp(this->sectionName(), rhs.section().sectionName())== 0);
+ assert(strcmp(this->segmentName(), rhs.section().segmentName())== 0);
+ const char* stringContent = (char*)atom->contentPointer();
+
+ const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+ assert(rhsAtom != NULL);
+ if ( rhsAtom != NULL ) {
+ if ( atom->_size != rhsAtom->_size )
+ return false;
+ const char* rhsStringContent = (char*)rhsAtom->contentPointer();
+ return (strcmp(stringContent, rhsStringContent) == 0);
+ }
+ return false;
+}
+
+
+template <>
+ld::Fixup::Kind NonLazyPointerSection<x86>::fixupKind()
+{
+ return ld::Fixup::kindStoreLittleEndian32;
+}
+
+template <>
+ld::Fixup::Kind NonLazyPointerSection<arm>::fixupKind()
+{
+ return ld::Fixup::kindStoreLittleEndian32;
+}
+
+
+template <>
+void NonLazyPointerSection<x86_64>::makeFixups(class Parser<x86_64>& parser, const struct Parser<x86_64>::CFI_CU_InfoArrays&)
+{
+ assert(0 && "x86_64 should not have non-lazy-pointer sections in .o files");
+}
+
+template <typename A>
+void NonLazyPointerSection<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&)
+{
+ // add references for each NLP atom based on indirect symbol table
+ const macho_section<P>* sect = this->machoSection();
+ const pint_t endAddr = sect->addr() + sect->size();
+ for( pint_t addr = sect->addr(); addr < endAddr; addr += sizeof(pint_t)) {
+ typename Parser<A>::SourceLocation src;
+ typename Parser<A>::TargetDesc target;
+ src.atom = this->findAtomByAddress(addr);
+ src.offsetInAtom = 0;
+ uint32_t symIndex = parser.symbolIndexFromIndirectSectionAddress(addr, sect);
+ target.atom = NULL;
+ target.name = NULL;
+ target.weakImport = false;
+ target.addend = 0;
+ if ( symIndex == INDIRECT_SYMBOL_LOCAL ) {
+ // use direct reference for local symbols
+ const pint_t* nlpContent = (pint_t*)(this->file().fileContent() + sect->offset() + addr - sect->addr());
+ pint_t targetAddr = P::getP(*nlpContent);
+ target.atom = parser.findAtomByAddress(targetAddr);
+ target.weakImport = false;
+ target.addend = (targetAddr - target.atom->objectAddress());
+ // <rdar://problem/8385011> if pointer to thumb function, mask of thumb bit (not an addend of +1)
+ if ( target.atom->isThumb() )
+ target.addend &= (-2);
+ assert(src.atom->combine() == ld::Atom::combineNever);
+ }
+ else {
+ const macho_nlist<P>& sym = parser.symbolFromIndex(symIndex);
+ // use direct reference for local symbols
+ if ( ((sym.n_type() & N_TYPE) == N_SECT) && ((sym.n_type() & N_EXT) == 0) ) {
+ parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target);
+ assert(src.atom->combine() == ld::Atom::combineNever);
+ }
+ else {
+ target.name = parser.nameFromSymbol(sym);
+ target.weakImport = parser.weakImportFromSymbol(sym);
+ assert(src.atom->combine() == ld::Atom::combineByNameAndReferences);
+ }
+ }
+ parser.addFixups(src, this->fixupKind(), target);
+ }
+}
+
+template <typename A>
+ld::Atom::Combine NonLazyPointerSection<A>::combine(Parser<A>& parser, pint_t addr)
+{
+ const macho_section<P>* sect = this->machoSection();
+ uint32_t symIndex = parser.symbolIndexFromIndirectSectionAddress(addr, sect);
+ if ( symIndex == INDIRECT_SYMBOL_LOCAL)
+ return ld::Atom::combineNever;
+
+ // don't coalesce non-lazy-pointers to local symbols
+ const macho_nlist<P>& sym = parser.symbolFromIndex(symIndex);
+ if ( ((sym.n_type() & N_TYPE) == N_SECT) && ((sym.n_type() & N_EXT) == 0) )
+ return ld::Atom::combineNever;
+
+ return ld::Atom::combineByNameAndReferences;
+}
+
+template <typename A>
+const char* NonLazyPointerSection<A>::targetName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind)
+{
+ assert(atom->combine() == ld::Atom::combineByNameAndReferences);
+ assert(atom->fixupCount() == 1);
+ ld::Fixup::iterator fit = atom->fixupsBegin();
+ const char* name = NULL;
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingByNameUnbound:
+ name = fit->u.name;
+ break;
+ case ld::Fixup::bindingByContentBound:
+ name = fit->u.target->name();
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ name = ind.indirectName(fit->u.bindingIndex);
+ break;
+ default:
+ assert(0);
+ }
+ assert(name != NULL);
+ return name;
+}
+
+template <typename A>
+unsigned long NonLazyPointerSection<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+ assert(atom->combine() == ld::Atom::combineByNameAndReferences);
+ unsigned long hash = 9508;
+ for (const char* s = this->targetName(atom, ind); *s != '\0'; ++s) {
+ hash = hash * 33 + *s;
+ }
+ return hash;
+}
+
+template <typename A>
+bool NonLazyPointerSection<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& indirectBindingTable) const
+{
+ if ( rhs.section().type() != ld::Section::typeNonLazyPointer )
+ return false;
+ assert(this->type() == rhs.section().type());
+ // there can be many non-lazy pointer in different section names
+ // we only want to coalesce in same section name
+ if ( *this != rhs.section() )
+ return false;
+ const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+ assert(rhsAtom != NULL);
+ const char* thisName = this->targetName(atom, indirectBindingTable);
+ const char* rhsName = this->targetName(rhsAtom, indirectBindingTable);
+ return (strcmp(thisName, rhsName) == 0);
+}
+
+template <typename A>
+ld::Atom::Scope NonLazyPointerSection<A>::scopeAtAddress(Parser<A>& parser, pint_t addr)
+{
+ const macho_section<P>* sect = this->machoSection();
+ uint32_t symIndex = parser.symbolIndexFromIndirectSectionAddress(addr, sect);
+ if ( symIndex == INDIRECT_SYMBOL_LOCAL)
+ return ld::Atom::scopeTranslationUnit;
+ else
+ return ld::Atom::scopeLinkageUnit;
+}
+
+
+template <typename A>
+const uint8_t* CFStringSection<A>::targetContent(const class Atom<A>* atom, const ld::IndirectBindingTable& ind,
+ ContentType* ct, unsigned int* count)
+{
+ *ct = contentUnknown;
+ for (ld::Fixup::iterator fit=atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ const ld::Atom* targetAtom = NULL;
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingByNameUnbound:
+ // ignore reference to ___CFConstantStringClassReference
+ // we are just looking for reference to backing string data
+ assert(fit->offsetInAtom == 0);
+ assert(strcmp(fit->u.name, "___CFConstantStringClassReference") == 0);
+ break;
+ case ld::Fixup::bindingDirectlyBound:
+ case ld::Fixup::bindingByContentBound:
+ targetAtom = fit->u.target;
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ targetAtom = ind.indirectAtom(fit->u.bindingIndex);
+ break;
+ default:
+ assert(0 && "bad binding type");
+ }
+ assert(targetAtom != NULL);
+ const Atom<A>* target = dynamic_cast<const Atom<A>*>(targetAtom);
+ if ( targetAtom->section().type() == ld::Section::typeCString ) {
+ *ct = contentUTF8;
+ *count = targetAtom->size();
+ }
+ else if ( targetAtom->section().type() == ld::Section::typeUTF16Strings ) {
+ *ct = contentUTF16;
+ *count = (targetAtom->size()+1)/2; // round up incase of buggy compiler that has only one trailing zero byte
+ }
+ assert(target != NULL);
+ return target->contentPointer();
+ }
+ assert(0);
+ return NULL;
+}
+
+template <typename A>
+unsigned long CFStringSection<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+ // base hash of CFString on hash of cstring it wraps
+ ContentType cType;
+ unsigned long hash;
+ unsigned int charCount;
+ const uint8_t* content = this->targetContent(atom, ind, &cType, &charCount);
+ switch ( cType ) {
+ case contentUTF8:
+ hash = 9408;
+ for (const char* s = (char*)content; *s != '\0'; ++s) {
+ hash = hash * 33 + *s;
+ }
+ return hash;
+ case contentUTF16:
+ hash = 407955;
+ --charCount; // don't add last 0x0000 to hash because some buggy compilers only have trailing single byte
+ for (const uint16_t* s = (uint16_t*)content; charCount > 0; ++s, --charCount) {
+ hash = hash * 1025 + *s;
+ }
+ return hash;
+ case contentUnknown:
+ return 0;
+ }
+ return 0;
+}
+
+
+template <typename A>
+bool CFStringSection<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& indirectBindingTable) const
+{
+ if ( atom == &rhs )
+ return true;
+ if ( rhs.section().type() != ld::Section::typeCFString)
+ return false;
+ assert(this->type() == rhs.section().type());
+ assert(strcmp(this->sectionName(), "__cfstring") == 0);
+
+ ContentType thisType;
+ unsigned int charCount;
+ const uint8_t* cstringContent = this->targetContent(atom, indirectBindingTable, &thisType, &charCount);
+ ContentType rhsType;
+ const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+ assert(rhsAtom != NULL);
+ unsigned int rhsCharCount;
+ const uint8_t* rhsStringContent = this->targetContent(rhsAtom, indirectBindingTable, &rhsType, &rhsCharCount);
+
+ if ( thisType != rhsType )
+ return false;
+
+ // no need to compare content of pointers are already the same
+ if ( cstringContent == rhsStringContent )
+ return true;
+
+ // no need to compare content if size is different
+ if ( charCount != rhsCharCount )
+ return false;
+
+ switch ( thisType ) {
+ case contentUTF8:
+ return (strcmp((char*)cstringContent, (char*)rhsStringContent) == 0);
+ case contentUTF16:
+ {
+ const uint16_t* cstringContent16 = (uint16_t*)cstringContent;
+ const uint16_t* rhsStringContent16 = (uint16_t*)rhsStringContent;
+ for (unsigned int i = 0; i < charCount; ++i) {
+ if ( cstringContent16[i] != rhsStringContent16[i] )
+ return false;
+ }
+ return true;
+ }
+ case contentUnknown:
+ return false;
+ }
+ return false;
+}
+
+
+template <typename A>
+typename A::P::uint_t ObjC1ClassSection<A>::elementSizeAtAddress(pint_t addr)
+{
+ // nominal size for each class is 48 bytes, but sometimes the compiler
+ // over aligns and there is padding after class data
+ const macho_section<P>* sct = this->machoSection();
+ uint32_t align = 1 << sct->align();
+ uint32_t size = ((12 * sizeof(pint_t)) + align-1) & (-align);
+ return size;
+}
+
+template <typename A>
+const char* ObjC1ClassSection<A>::unlabeledAtomName(Parser<A>& parser, pint_t addr)
+{
+ // 8-bytes into class object is pointer to class name
+ const macho_section<P>* sct = this->machoSection();
+ uint32_t classObjcFileOffset = sct->offset() - sct->addr() + addr;
+ const uint8_t* mappedFileContent = this->file().fileContent();
+ pint_t nameAddr = P::getP(*((pint_t*)(mappedFileContent+classObjcFileOffset+2*sizeof(pint_t))));
+
+ // find section containing string address to get string bytes
+ const macho_section<P>* const sections = parser.firstMachOSection();
+ const uint32_t sectionCount = parser.machOSectionCount();
+ for (uint32_t i=0; i < sectionCount; ++i) {
+ const macho_section<P>* aSect = §ions[i];
+ if ( (aSect->addr() <= nameAddr) && (nameAddr < (aSect->addr()+aSect->size())) ) {
+ assert((aSect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS);
+ uint32_t nameFileOffset = aSect->offset() - aSect->addr() + nameAddr;
+ const char* name = (char*)mappedFileContent + nameFileOffset;
+ // spin through symbol table to find absolute symbol corresponding to this class
+ for (uint32_t s=0; s < parser.symbolCount(); ++s) {
+ const macho_nlist<P>& sym = parser.symbolFromIndex(s);
+ if ( (sym.n_type() & N_TYPE) != N_ABS )
+ continue;
+ const char* absName = parser.nameFromSymbol(sym);
+ if ( strncmp(absName, ".objc_class_name_", 17) == 0 ) {
+ if ( strcmp(&absName[17], name) == 0 )
+ return absName;
+ }
+ }
+ assert(0 && "obj class name not found in symbol table");
+ }
+ }
+ assert(0 && "obj class name not found");
+ return "unknown objc class";
+}
+
+
+template <typename A>
+const char* ObjC2ClassRefsSection<A>::targetClassName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+ assert(atom->fixupCount() == 1);
+ ld::Fixup::iterator fit = atom->fixupsBegin();
+ const char* className = NULL;
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingByNameUnbound:
+ className = fit->u.name;
+ break;
+ case ld::Fixup::bindingDirectlyBound:
+ case ld::Fixup::bindingByContentBound:
+ className = fit->u.target->name();
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ className = ind.indirectName(fit->u.bindingIndex);
+ break;
+ default:
+ assert(0 && "unsupported binding in objc2 class ref section");
+ }
+ assert(className != NULL);
+ return className;
+}
+
+
+template <typename A>
+unsigned long ObjC2ClassRefsSection<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+ unsigned long hash = 978;
+ for (const char* s = targetClassName(atom, ind); *s != '\0'; ++s) {
+ hash = hash * 33 + *s;
+ }
+ return hash;
+}
+
+template <typename A>
+bool ObjC2ClassRefsSection<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& indirectBindingTable) const
+{
+ assert(this->type() == rhs.section().type());
+ const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+ assert(rhsAtom != NULL);
+ const char* thisClassName = targetClassName(atom, indirectBindingTable);
+ const char* rhsClassName = targetClassName(rhsAtom, indirectBindingTable);
+ return (strcmp(thisClassName, rhsClassName) == 0);
+}
+
+
+template <typename A>
+const char* Objc1ClassReferences<A>::targetCString(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+ assert(atom->fixupCount() == 2);
+ ld::Fixup::iterator fit = atom->fixupsBegin();
+ if ( fit->kind == ld::Fixup::kindSetTargetAddress )
+ ++fit;
+ const ld::Atom* targetAtom = NULL;
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingByContentBound:
+ targetAtom = fit->u.target;
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ targetAtom = ind.indirectAtom(fit->u.bindingIndex);
+ if ( targetAtom == NULL ) {
+ fprintf(stderr, "missing target named %s\n", ind.indirectName(fit->u.bindingIndex));
+ }
+ break;
+ default:
+ assert(0);
+ }
+ assert(targetAtom != NULL);
+ const Atom<A>* target = dynamic_cast<const Atom<A>*>(targetAtom);
+ assert(target != NULL);
+ return (char*)target->contentPointer();
+}
+
+
+template <typename A>
+const char* PointerToCStringSection<A>::targetCString(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+ assert(atom->fixupCount() == 1);
+ ld::Fixup::iterator fit = atom->fixupsBegin();
+ const ld::Atom* targetAtom = NULL;
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingByContentBound:
+ targetAtom = fit->u.target;
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ targetAtom = ind.indirectAtom(fit->u.bindingIndex);
+ break;
+ default:
+ assert(0);
+ }
+ assert(targetAtom != NULL);
+ const Atom<A>* target = dynamic_cast<const Atom<A>*>(targetAtom);
+ assert(target != NULL);
+ return (char*)target->contentPointer();
+}
+
+template <typename A>
+unsigned long PointerToCStringSection<A>::contentHash(const class Atom<A>* atom,
+ const ld::IndirectBindingTable& indirectBindingTable) const
+{
+ // make hash from section name and target cstring name
+ unsigned long hash = 123;
+ for (const char* s = this->sectionName(); *s != '\0'; ++s) {
+ hash = hash * 33 + *s;
+ }
+ for (const char* s = this->targetCString(atom, indirectBindingTable); *s != '\0'; ++s) {
+ hash = hash * 33 + *s;
+ }
+ return hash;
+}
+
+template <typename A>
+bool PointerToCStringSection<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& indirectBindingTable) const
+{
+ assert(this->type() == rhs.section().type());
+ // there can be pointers-to-cstrings in different section names
+ // we only want to coalesce in same section name
+ if ( *this != rhs.section() )
+ return false;
+
+ // get string content for this
+ const char* cstringContent = this->targetCString(atom, indirectBindingTable);
+ const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+ assert(rhsAtom != NULL);
+ const char* rhsCstringContent = this->targetCString(rhsAtom, indirectBindingTable);
+
+ assert(cstringContent != NULL);
+ assert(rhsCstringContent != NULL);
+ return (strcmp(cstringContent, rhsCstringContent) == 0);
+}
+
+
+
+template <typename A>
+unsigned long UTF16StringSection<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+ unsigned long hash = 5381;
+ const uint16_t* stringContent = (uint16_t*)atom->contentPointer();
+ // some buggy compilers end utf16 data with single byte, so don't use last word in hash computation
+ unsigned int count = (atom->size()/2) - 1;
+ for (const uint16_t* s = stringContent; count > 0; ++s, --count) {
+ hash = hash * 33 + *s;
+ }
+ return hash;
+}
+
+template <typename A>
+bool UTF16StringSection<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+ const ld::IndirectBindingTable& ind) const
+{
+ if ( rhs.section().type() != ld::Section::typeUTF16Strings )
+ return false;
+ assert(0);
+ return false;
+}
+
+
+
+
+
+
+
+template <>
+uint32_t Section<x86_64>::x86_64PcRelOffset(uint8_t r_type)
+{
+ switch ( r_type ) {
+ case X86_64_RELOC_SIGNED:
+ return 4;
+ case X86_64_RELOC_SIGNED_1:
+ return 5;
+ case X86_64_RELOC_SIGNED_2:
+ return 6;
+ case X86_64_RELOC_SIGNED_4:
+ return 8;
+ }
+ return 0;
+}
+
+
+template <>
+bool Section<x86_64>::addRelocFixup(class Parser<x86_64>& parser, const macho_relocation_info<P>* reloc)
+{
+ const macho_section<P>* sect = this->machoSection();
+ uint64_t srcAddr = sect->addr() + reloc->r_address();
+ Parser<x86_64>::SourceLocation src;
+ Parser<x86_64>::TargetDesc target;
+ Parser<x86_64>::TargetDesc toTarget;
+ src.atom = this->findAtomByAddress(srcAddr);
+ src.offsetInAtom = srcAddr - src.atom->_objAddress;
+ const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address();
+ uint64_t contentValue = 0;
+ const macho_relocation_info<x86_64::P>* nextReloc = &reloc[1];
+ bool result = false;
+ bool useDirectBinding;
+ switch ( reloc->r_length() ) {
+ case 0:
+ contentValue = *fixUpPtr;
+ break;
+ case 1:
+ contentValue = (int64_t)(int16_t)E::get16(*((uint16_t*)fixUpPtr));
+ break;
+ case 2:
+ contentValue = (int64_t)(int32_t)E::get32(*((uint32_t*)fixUpPtr));
+ break;
+ case 3:
+ contentValue = E::get64(*((uint64_t*)fixUpPtr));
+ break;
+ }
+ target.atom = NULL;
+ target.name = NULL;
+ target.weakImport = false;
+ target.addend = 0;
+ if ( reloc->r_extern() ) {
+ const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+ // use direct reference for local symbols
+ if ( ((sym.n_type() & N_TYPE) == N_SECT) && (((sym.n_type() & N_EXT) == 0) || (parser.nameFromSymbol(sym)[0] == 'L')) ) {
+ parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target);
+ target.addend += contentValue;
+ }
+ else {
+ target.name = parser.nameFromSymbol(sym);
+ target.weakImport = parser.weakImportFromSymbol(sym);
+ target.addend = contentValue;
+ }
+ // cfstrings should always use direct reference to backing store
+ if ( (this->type() == ld::Section::typeCFString) && (src.offsetInAtom != 0) ) {
+ parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target);
+ target.addend = contentValue;
+ }
+ }
+ else {
+ if ( reloc->r_pcrel() )
+ contentValue += srcAddr + x86_64PcRelOffset(reloc->r_type());
+ parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), target);
+ }
+ switch ( reloc->r_type() ) {
+ case X86_64_RELOC_UNSIGNED:
+ if ( reloc->r_pcrel() )
+ throw "pcrel and X86_64_RELOC_UNSIGNED not supported";
+ switch ( reloc->r_length() ) {
+ case 0:
+ case 1:
+ throw "length < 2 and X86_64_RELOC_UNSIGNED not supported";
+ case 2:
+ parser.addFixups(src, ld::Fixup::kindStoreLittleEndian32, target);
+ break;
+ case 3:
+ parser.addFixups(src, ld::Fixup::kindStoreLittleEndian64, target);
+ break;
+ }
+ break;
+ case X86_64_RELOC_SIGNED:
+ case X86_64_RELOC_SIGNED_1:
+ case X86_64_RELOC_SIGNED_2:
+ case X86_64_RELOC_SIGNED_4:
+ if ( ! reloc->r_pcrel() )
+ throw "not pcrel and X86_64_RELOC_SIGNED* not supported";
+ if ( reloc->r_length() != 2 )
+ throw "length != 2 and X86_64_RELOC_SIGNED* not supported";
+ switch ( reloc->r_type() ) {
+ case X86_64_RELOC_SIGNED:
+ parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32, target);
+ break;
+ case X86_64_RELOC_SIGNED_1:
+ if ( reloc->r_extern() )
+ target.addend += 1;
+ parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32_1, target);
+ break;
+ case X86_64_RELOC_SIGNED_2:
+ if ( reloc->r_extern() )
+ target.addend += 2;
+ parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32_2, target);
+ break;
+ case X86_64_RELOC_SIGNED_4:
+ if ( reloc->r_extern() )
+ target.addend += 4;
+ parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32_4, target);
+ break;
+ }
+ break;
+ case X86_64_RELOC_BRANCH:
+ if ( ! reloc->r_pcrel() )
+ throw "not pcrel and X86_64_RELOC_BRANCH not supported";
+ switch ( reloc->r_length() ) {
+ case 2:
+ if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_probe$", 16) == 0) ) {
+ parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindStoreX86DtraceCallSiteNop, false, target.name);
+ parser.addDtraceExtraInfos(src, &target.name[16]);
+ }
+ else if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_isenabled$", 20) == 0) ) {
+ parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindStoreX86DtraceIsEnableSiteClear, false, target.name);
+ parser.addDtraceExtraInfos(src, &target.name[20]);
+ }
+ else {
+ parser.addFixups(src, ld::Fixup::kindStoreX86BranchPCRel32, target);
+ }
+ break;
+ case 0:
+ parser.addFixups(src, ld::Fixup::kindStoreX86BranchPCRel8, target);
+ break;
+ default:
+ throwf("length=%d and X86_64_RELOC_BRANCH not supported", reloc->r_length());
+ }
+ break;
+ case X86_64_RELOC_GOT:
+ if ( ! reloc->r_extern() )
+ throw "not extern and X86_64_RELOC_GOT not supported";
+ if ( ! reloc->r_pcrel() )
+ throw "not pcrel and X86_64_RELOC_GOT not supported";
+ if ( reloc->r_length() != 2 )
+ throw "length != 2 and X86_64_RELOC_GOT not supported";
+ parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32GOT, target);
+ break;
+ case X86_64_RELOC_GOT_LOAD:
+ if ( ! reloc->r_extern() )
+ throw "not extern and X86_64_RELOC_GOT_LOAD not supported";
+ if ( ! reloc->r_pcrel() )
+ throw "not pcrel and X86_64_RELOC_GOT_LOAD not supported";
+ if ( reloc->r_length() != 2 )
+ throw "length != 2 and X86_64_RELOC_GOT_LOAD not supported";
+ parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32GOTLoad, target);
+ break;
+ case X86_64_RELOC_SUBTRACTOR:
+ if ( reloc->r_pcrel() )
+ throw "X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
+ if ( reloc->r_length() < 2 )
+ throw "X86_64_RELOC_SUBTRACTOR must have r_length of 2 or 3";
+ if ( !reloc->r_extern() )
+ throw "X86_64_RELOC_SUBTRACTOR must have r_extern=1";
+ if ( nextReloc->r_type() != X86_64_RELOC_UNSIGNED )
+ throw "X86_64_RELOC_SUBTRACTOR must be followed by X86_64_RELOC_UNSIGNED";
+ result = true;
+ if ( nextReloc->r_pcrel() )
+ throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
+ if ( nextReloc->r_length() != reloc->r_length() )
+ throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR must have same r_length";
+ if ( nextReloc->r_extern() ) {
+ const macho_nlist<P>& sym = parser.symbolFromIndex(nextReloc->r_symbolnum());
+ // use direct reference for local symbols
+ if ( ((sym.n_type() & N_TYPE) == N_SECT) && (((sym.n_type() & N_EXT) == 0) || (parser.nameFromSymbol(sym)[0] == 'L')) ) {
+ parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), toTarget);
+ toTarget.addend = contentValue;
+ useDirectBinding = true;
+ }
+ else {
+ toTarget.name = parser.nameFromSymbol(sym);
+ toTarget.weakImport = parser.weakImportFromSymbol(sym);
+ toTarget.addend = contentValue;
+ useDirectBinding = false;
+ }
+ }
+ else {
+ parser.findTargetFromAddressAndSectionNum(contentValue, nextReloc->r_symbolnum(), toTarget);
+ useDirectBinding = (toTarget.atom->scope() == ld::Atom::scopeTranslationUnit);
+ }
+ if ( useDirectBinding )
+ parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, toTarget.atom);
+ else
+ parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, toTarget.weakImport, toTarget.name);
+ parser.addFixup(src, ld::Fixup::k2of4, ld::Fixup::kindAddAddend, toTarget.addend);
+ if ( target.atom == NULL )
+ parser.addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, false, target.name);
+ else
+ parser.addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, target.atom);
+ if ( reloc->r_length() == 2 )
+ parser.addFixup(src, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32);
+ else
+ parser.addFixup(src, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian64);
+ break;
+ case X86_64_RELOC_TLV:
+ if ( ! reloc->r_extern() )
+ throw "not extern and X86_64_RELOC_TLV not supported";
+ if ( ! reloc->r_pcrel() )
+ throw "not pcrel and X86_64_RELOC_TLV not supported";
+ if ( reloc->r_length() != 2 )
+ throw "length != 2 and X86_64_RELOC_TLV not supported";
+ parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32TLVLoad, target);
+ break;
+ default:
+ throwf("unknown relocation type %d", reloc->r_type());
+ }
+ return result;
+}
+
+
+
+template <>
+bool Section<x86>::addRelocFixup(class Parser<x86>& parser, const macho_relocation_info<P>* reloc)
+{
+ const macho_section<P>* sect = this->machoSection();
+ uint32_t srcAddr;
+ const uint8_t* fixUpPtr;
+ uint32_t contentValue = 0;
+ ld::Fixup::Kind kind = ld::Fixup::kindNone;
+ Parser<x86>::SourceLocation src;
+ Parser<x86>::TargetDesc target;
+
+ if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+ srcAddr = sect->addr() + reloc->r_address();
+ src.atom = this->findAtomByAddress(srcAddr);
+ src.offsetInAtom = srcAddr - src.atom->_objAddress;
+ fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address();
+ switch ( reloc->r_type() ) {
+ case GENERIC_RELOC_VANILLA:
+ switch ( reloc->r_length() ) {
+ case 0:
+ contentValue = (int32_t)(int8_t)*fixUpPtr;
+ if ( reloc->r_pcrel() ) {
+ kind = ld::Fixup::kindStoreX86BranchPCRel8;
+ contentValue += srcAddr + sizeof(uint8_t);
+ }
+ else
+ throw "r_length=0 and r_pcrel=0 not supported";
+ break;
+ case 1:
+ contentValue = (int32_t)(int16_t)E::get16(*((uint16_t*)fixUpPtr));
+ if ( reloc->r_pcrel() ) {
+ kind = ld::Fixup::kindStoreX86PCRel16;
+ contentValue += srcAddr + sizeof(uint16_t);
+ }
+ else
+ kind = ld::Fixup::kindStoreLittleEndian16;
+ break;
+ case 2:
+ contentValue = E::get32(*((uint32_t*)fixUpPtr));
+ if ( reloc->r_pcrel() ) {
+ kind = ld::Fixup::kindStoreX86BranchPCRel32;
+ contentValue += srcAddr + sizeof(uint32_t);
+ }
+ else
+ kind = ld::Fixup::kindStoreLittleEndian32;
+ break;
+ case 3:
+ throw "r_length=3 not supported";
+ }
+ if ( reloc->r_extern() ) {
+ target.atom = NULL;
+ const macho_nlist<P>& targetSymbol = parser.symbolFromIndex(reloc->r_symbolnum());
+ target.name = parser.nameFromSymbol(targetSymbol);
+ target.weakImport = parser.weakImportFromSymbol(targetSymbol);
+ target.addend = (int32_t)contentValue;
+ }
+ else {
+ parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), target);
+ }
+ if ( (kind == ld::Fixup::kindStoreX86BranchPCRel32) && (target.name != NULL) ) {
+ if ( strncmp(target.name, "___dtrace_probe$", 16) == 0 ) {
+ parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindStoreX86DtraceCallSiteNop, false, target.name);
+ parser.addDtraceExtraInfos(src, &target.name[16]);
+ return false;
+ }
+ else if ( strncmp(target.name, "___dtrace_isenabled$", 20) == 0 ) {
+ parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindStoreX86DtraceIsEnableSiteClear, false, target.name);
+ parser.addDtraceExtraInfos(src, &target.name[20]);
+ return false;
+ }
+ }
+ parser.addFixups(src, kind, target);
+ return false;
+ break;
+ case GENERIC_RLEOC_TLV:
+ {
+ if ( !reloc->r_extern() )
+ throw "r_extern=0 and r_type=GENERIC_RLEOC_TLV not supported";
+ if ( reloc->r_length() != 2 )
+ throw "r_length!=2 and r_type=GENERIC_RLEOC_TLV not supported";
+ const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+ // use direct reference for local symbols
+ if ( ((sym.n_type() & N_TYPE) == N_SECT) && ((sym.n_type() & N_EXT) == 0) ) {
+ parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target);
+ }
+ else {
+ target.atom = NULL;
+ target.name = parser.nameFromSymbol(sym);
+ target.weakImport = parser.weakImportFromSymbol(sym);
+ }
+ target.addend = (int64_t)(int32_t)E::get32(*((uint32_t*)fixUpPtr));
+ if ( reloc->r_pcrel() ) {
+ parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32TLVLoad, target);
+ }
+ else {
+ parser.addFixups(src, ld::Fixup::kindStoreX86Abs32TLVLoad, target);
+ }
+ return false;
+ }
+ break;
+ default:
+ throwf("unsupported i386 relocation type (%d)", reloc->r_type());
+ }
+ }
+ else {
+ // scattered relocation
+ const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
+ srcAddr = sect->addr() + sreloc->r_address();
+ src.atom = this->findAtomByAddress(srcAddr);
+ assert(src.atom != NULL);
+ src.offsetInAtom = srcAddr - src.atom->_objAddress;
+ fixUpPtr = file().fileContent() + sect->offset() + sreloc->r_address();
+ uint32_t relocValue = sreloc->r_value();
+ bool result = false;
+ // file format allows pair to be scattered or not
+ const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
+ const macho_relocation_info<P>* nextReloc = &reloc[1];
+ bool nextRelocIsPair = false;
+ uint32_t nextRelocAddress = 0;
+ uint32_t nextRelocValue = 0;
+ if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
+ if ( nextReloc->r_type() == GENERIC_RELOC_PAIR ) {
+ nextRelocIsPair = true;
+ nextRelocAddress = nextReloc->r_address();
+ result = true; // iterator should skip next reloc, since we've consumed it here
+ }
+ }
+ else {
+ if ( nextSReloc->r_type() == GENERIC_RELOC_PAIR ) {
+ nextRelocIsPair = true;
+ nextRelocAddress = nextSReloc->r_address();
+ nextRelocValue = nextSReloc->r_value();
+ }
+ }
+ switch (sreloc->r_type()) {
+ case GENERIC_RELOC_VANILLA:
+ // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
+ target.atom = parser.findAtomByAddress(relocValue);
+ if ( sreloc->r_pcrel() ) {
+ switch ( sreloc->r_length() ) {
+ case 0:
+ contentValue = srcAddr + 1 + *fixUpPtr;
+ target.addend = (int32_t)contentValue - (int32_t)relocValue;
+ parser.addFixups(src, ld::Fixup::kindStoreX86PCRel8, target);
+ break;
+ case 1:
+ contentValue = srcAddr + 2 + LittleEndian::get16(*((uint16_t*)fixUpPtr));
+ target.addend = (int32_t)contentValue - (int32_t)relocValue;
+ parser.addFixups(src, ld::Fixup::kindStoreX86PCRel16, target);
+ break;
+ case 2:
+ contentValue = srcAddr + 4 + LittleEndian::get32(*((uint32_t*)fixUpPtr));
+ target.addend = (int32_t)contentValue - (int32_t)relocValue;
+ parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32, target);
+ break;
+ case 3:
+ throw "unsupported r_length=3 for scattered pc-rel vanilla reloc";
+ break;
+ }
+ }
+ else {
+ if ( sreloc->r_length() != 2 )
+ throwf("unsupported r_length=%d for scattered vanilla reloc", sreloc->r_length());
+ contentValue = LittleEndian::get32(*((uint32_t*)fixUpPtr));
+ target.addend = (int32_t)contentValue - (int32_t)(target.atom->objectAddress());
+ parser.addFixups(src, ld::Fixup::kindStoreLittleEndian32, target);
+ }
+ break;
+ case GENERIC_RELOC_SECTDIFF:
+ case GENERIC_RELOC_LOCAL_SECTDIFF:
+ {
+ if ( !nextRelocIsPair )
+ throw "GENERIC_RELOC_SECTDIFF missing following pair";
+ switch ( sreloc->r_length() ) {
+ case 0:
+ case 3:
+ throw "bad length for GENERIC_RELOC_SECTDIFF";
+ case 1:
+ contentValue = (int32_t)(int16_t)LittleEndian::get16(*((uint16_t*)fixUpPtr));
+ kind = ld::Fixup::kindStoreLittleEndian16;
+ break;
+ case 2:
+ contentValue = LittleEndian::get32(*((uint32_t*)fixUpPtr));
+ kind = ld::Fixup::kindStoreLittleEndian32;
+ break;
+ }
+ Atom<x86>* fromAtom = parser.findAtomByAddress(nextRelocValue);
+ uint32_t offsetInFrom = nextRelocValue - fromAtom->_objAddress;
+ parser.findTargetFromAddress(sreloc->r_value(), target);
+ // check for addend encoded in the section content
+ int64_t addend = (int32_t)contentValue - (int32_t)(sreloc->r_value() - nextRelocValue);
+ if ( addend < 0 ) {
+ // switch binding base on coalescing
+ if ( target.atom == NULL ) {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, target.name);
+ }
+ else if ( target.atom->scope() == ld::Atom::scopeTranslationUnit ) {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, target.atom);
+ }
+ else if ( (target.atom->combine() == ld::Atom::combineByNameAndContent) || (target.atom->combine() == ld::Atom::combineByNameAndReferences) ) {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, target.atom);
+ }
+ else {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, target.atom->name());
+ }
+ parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, target.addend);
+ parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom);
+ parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom-addend);
+ parser.addFixup(src, ld::Fixup::k5of5, kind);
+ }
+ else {
+ // switch binding base on coalescing
+ if ( target.atom == NULL ) {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, target.name);
+ }
+ else if ( target.atom->scope() == ld::Atom::scopeTranslationUnit ) {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, target.atom);
+ }
+ else if ( (target.atom->combine() == ld::Atom::combineByNameAndContent) || (target.atom->combine() == ld::Atom::combineByNameAndReferences) ) {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, target.atom);
+ }
+ else {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, target.atom->name());
+ }
+ parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, target.addend+addend);
+ parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom);
+ parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom);
+ parser.addFixup(src, ld::Fixup::k5of5, kind);
+ }
+ }
+ break;
+ }
+ return result;
+ }
+}
+
+
+
+
+
+#if SUPPORT_ARCH_arm_any
+template <>
+bool Section<arm>::addRelocFixup(class Parser<arm>& parser, const macho_relocation_info<P>* reloc)
+{
+ const macho_section<P>* sect = this->machoSection();
+ bool result = false;
+ uint32_t srcAddr;
+ uint32_t dstAddr;
+ uint32_t* fixUpPtr;
+ int32_t displacement = 0;
+ uint32_t instruction = 0;
+ pint_t contentValue = 0;
+ Parser<arm>::SourceLocation src;
+ Parser<arm>::TargetDesc target;
+ const macho_relocation_info<P>* nextReloc;
+
+ if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+ bool externSymbolIsThumbDef = false;
+ srcAddr = sect->addr() + reloc->r_address();
+ src.atom = this->findAtomByAddress(srcAddr);
+ src.offsetInAtom = srcAddr - src.atom->_objAddress;
+ fixUpPtr = (uint32_t*)(file().fileContent() + sect->offset() + reloc->r_address());
+ if ( reloc->r_type() != ARM_RELOC_PAIR )
+ instruction = LittleEndian::get32(*fixUpPtr);
+ if ( reloc->r_extern() ) {
+ const macho_nlist<P>& targetSymbol = parser.symbolFromIndex(reloc->r_symbolnum());
+ // use direct reference for local symbols
+ if ( ((targetSymbol.n_type() & N_TYPE) == N_SECT) && (((targetSymbol.n_type() & N_EXT) == 0) || (parser.nameFromSymbol(targetSymbol)[0] == 'L')) ) {
+ parser.findTargetFromAddressAndSectionNum(targetSymbol.n_value(), targetSymbol.n_sect(), target);
+ }
+ else {
+ target.atom = NULL;
+ target.name = parser.nameFromSymbol(targetSymbol);
+ target.weakImport = parser.weakImportFromSymbol(targetSymbol);
+ if ( ((targetSymbol.n_type() & N_TYPE) == N_SECT) && (targetSymbol.n_desc() & N_ARM_THUMB_DEF) )
+ externSymbolIsThumbDef = true;
+ }
+ }
+ switch ( reloc->r_type() ) {
+ case ARM_RELOC_BR24:
+ // Sign-extend displacement
+ displacement = (instruction & 0x00FFFFFF) << 2;
+ if ( (displacement & 0x02000000) != 0 )
+ displacement |= 0xFC000000;
+ // The pc added will be +8 from the pc
+ displacement += 8;
+ // If this is BLX add H << 1
+ if ((instruction & 0xFE000000) == 0xFA000000)
+ displacement += ((instruction & 0x01000000) >> 23);
+ if ( reloc->r_extern() ) {
+ target.addend = srcAddr + displacement;
+ if ( externSymbolIsThumbDef )
+ target.addend &= -2; // remove thumb bit
+ }
+ else {
+ dstAddr = srcAddr + displacement;
+ parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target);
+ }
+ // special case "calls" for dtrace
+ if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_probe$", 16) == 0) ) {
+ parser.addFixup(src, ld::Fixup::k1of1,
+ ld::Fixup::kindStoreARMDtraceCallSiteNop, false, target.name);
+ parser.addDtraceExtraInfos(src, &target.name[16]);
+ }
+ else if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_isenabled$", 20) == 0) ) {
+ parser.addFixup(src, ld::Fixup::k1of1,
+ ld::Fixup::kindStoreARMDtraceIsEnableSiteClear, false, target.name);
+ parser.addDtraceExtraInfos(src, &target.name[20]);
+ }
+ else {
+ parser.addFixups(src, ld::Fixup::kindStoreARMBranch24, target);
+ }
+ break;
+ case ARM_THUMB_RELOC_BR22:
+ // thumb2 added two more bits to displacement, complicating the displacement decoding
+ {
+ uint32_t s = (instruction >> 10) & 0x1;
+ uint32_t j1 = (instruction >> 29) & 0x1;
+ uint32_t j2 = (instruction >> 27) & 0x1;
+ uint32_t imm10 = instruction & 0x3FF;
+ uint32_t imm11 = (instruction >> 16) & 0x7FF;
+ uint32_t i1 = (j1 == s);
+ uint32_t i2 = (j2 == s);
+ uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
+ int32_t sdis = dis;
+ if ( s )
+ sdis |= 0xFE000000;
+ displacement = sdis;
+ }
+ // The pc added will be +4 from the pc
+ displacement += 4;
+ // If the instruction was blx, force the low 2 bits to be clear
+ dstAddr = srcAddr + displacement;
+ if ((instruction & 0xF8000000) == 0xE8000000)
+ dstAddr &= 0xFFFFFFFC;
+
+ if ( reloc->r_extern() ) {
+ target.addend = dstAddr;
+ }
+ else {
+ parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target);
+ }
+ // special case "calls" for dtrace
+ if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_probe$", 16) == 0) ) {
+ parser.addFixup(src, ld::Fixup::k1of1,
+ ld::Fixup::kindStoreThumbDtraceCallSiteNop, false, target.name);
+ parser.addDtraceExtraInfos(src, &target.name[16]);
+ }
+ else if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_isenabled$", 20) == 0) ) {
+ parser.addFixup(src, ld::Fixup::k1of1,
+ ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear, false, target.name);
+ parser.addDtraceExtraInfos(src, &target.name[20]);
+ }
+ else {
+ parser.addFixups(src, ld::Fixup::kindStoreThumbBranch22, target);
+ }
+ break;
+ case ARM_RELOC_VANILLA:
+ if ( reloc->r_length() != 2 )
+ throw "bad length for ARM_RELOC_VANILLA";
+ contentValue = LittleEndian::get32(*fixUpPtr);
+ if ( reloc->r_extern() ) {
+ target.addend = (int32_t)contentValue;
+ if ( externSymbolIsThumbDef )
+ target.addend &= -2; // remove thumb bit
+ }
+ else {
+ parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), target);
+ // possible non-extern relocation turned into by-name ref because target is a weak-def
+ if ( target.atom != NULL ) {
+ if ( target.atom->isThumb() )
+ target.addend &= -2; // remove thumb bit
+ // if reference to LSDA, add group subordinate fixup
+ if ( target.atom->contentType() == ld::Atom::typeLSDA ) {
+ Parser<arm>::SourceLocation src2;
+ src2.atom = src.atom;
+ src2.offsetInAtom = 0;
+ parser.addFixup(src2, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinateLSDA, target.atom);
+ }
+ }
+ }
+ parser.addFixups(src, ld::Fixup::kindStoreLittleEndian32, target);
+ break;
+ case ARM_THUMB_32BIT_BRANCH:
+ // silently ignore old unnecessary reloc
+ break;
+ case ARM_RELOC_HALF:
+ nextReloc = &reloc[1];
+ if ( nextReloc->r_type() == ARM_RELOC_PAIR ) {
+ uint32_t instruction16;
+ uint32_t other16 = (nextReloc->r_address() & 0xFFFF);
+ bool isThumb;
+ if ( reloc->r_length() & 2 ) {
+ isThumb = true;
+ uint32_t i = ((instruction & 0x00000400) >> 10);
+ uint32_t imm4 = (instruction & 0x0000000F);
+ uint32_t imm3 = ((instruction & 0x70000000) >> 28);
+ uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
+ instruction16 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
+ }
+ else {
+ isThumb = false;
+ uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
+ uint32_t imm12 = (instruction & 0x00000FFF);
+ instruction16 = (imm4 << 12) | imm12;
+ }
+ if ( reloc->r_length() & 1 ) {
+ // high 16
+ dstAddr = ((instruction16 << 16) | other16);
+ if ( reloc->r_extern() ) {
+ target.addend = dstAddr;
+ if ( externSymbolIsThumbDef )
+ target.addend &= -2; // remove thumb bit
+ }
+ else {
+ parser.findTargetFromAddress(dstAddr, target);
+ if ( target.atom->isThumb() )
+ target.addend &= (-2); // remove thumb bit
+ }
+ parser.addFixups(src, (isThumb ? ld::Fixup::kindStoreThumbHigh16 : ld::Fixup::kindStoreARMHigh16), target);
+ }
+ else {
+ // low 16
+ dstAddr = (other16 << 16) | instruction16;
+ if ( reloc->r_extern() ) {
+ target.addend = dstAddr;
+ if ( externSymbolIsThumbDef )
+ target.addend &= -2; // remove thumb bit
+ }
+ else {
+ parser.findTargetFromAddress(dstAddr, target);
+ if ( target.atom->isThumb() )
+ target.addend &= (-2); // remove thumb bit
+ }
+ parser.addFixups(src, (isThumb ? ld::Fixup::kindStoreThumbLow16 : ld::Fixup::kindStoreARMLow16), target);
+ }
+ result = true;
+ }
+ else
+ throw "for ARM_RELOC_HALF, next reloc is not ARM_RELOC_PAIR";
+ break;
+ default:
+ throwf("unknown relocation type %d", reloc->r_type());
+ break;
+ }
+ }
+ else {
+ const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
+ // file format allows pair to be scattered or not
+ const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
+ nextReloc = &reloc[1];
+ srcAddr = sect->addr() + sreloc->r_address();
+ dstAddr = sreloc->r_value();
+ fixUpPtr = (uint32_t*)(file().fileContent() + sect->offset() + sreloc->r_address());
+ instruction = LittleEndian::get32(*fixUpPtr);
+ src.atom = this->findAtomByAddress(srcAddr);
+ src.offsetInAtom = srcAddr - src.atom->_objAddress;
+ bool nextRelocIsPair = false;
+ uint32_t nextRelocAddress = 0;
+ uint32_t nextRelocValue = 0;
+ if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
+ if ( nextReloc->r_type() == ARM_RELOC_PAIR ) {
+ nextRelocIsPair = true;
+ nextRelocAddress = nextReloc->r_address();
+ result = true;
+ }
+ }
+ else {
+ if ( nextSReloc->r_type() == ARM_RELOC_PAIR ) {
+ nextRelocIsPair = true;
+ nextRelocAddress = nextSReloc->r_address();
+ nextRelocValue = nextSReloc->r_value();
+ result = true;
+ }
+ }
+ switch ( sreloc->r_type() ) {
+ case ARM_RELOC_VANILLA:
+ // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
+ if ( sreloc->r_length() != 2 )
+ throw "bad length for ARM_RELOC_VANILLA";
+ target.atom = parser.findAtomByAddress(sreloc->r_value());
+ contentValue = LittleEndian::get32(*fixUpPtr);
+ target.addend = contentValue - target.atom->_objAddress;
+ if ( target.atom->isThumb() )
+ target.addend &= -2; // remove thumb bit
+ parser.addFixups(src, ld::Fixup::kindStoreLittleEndian32, target);
+ break;
+ case ARM_RELOC_BR24:
+ // Sign-extend displacement
+ displacement = (instruction & 0x00FFFFFF) << 2;
+ if ( (displacement & 0x02000000) != 0 )
+ displacement |= 0xFC000000;
+ // The pc added will be +8 from the pc
+ displacement += 8;
+ // If this is BLX add H << 1
+ if ((instruction & 0xFE000000) == 0xFA000000)
+ displacement += ((instruction & 0x01000000) >> 23);
+ target.atom = parser.findAtomByAddress(sreloc->r_value());
+ target.addend = (int64_t)(srcAddr + displacement) - (int64_t)(target.atom->_objAddress);
+ parser.addFixups(src, ld::Fixup::kindStoreARMBranch24, target);
+ break;
+ case ARM_THUMB_RELOC_BR22:
+ // thumb2 added two more bits to displacement, complicating the displacement decoding
+ {
+ uint32_t s = (instruction >> 10) & 0x1;
+ uint32_t j1 = (instruction >> 29) & 0x1;
+ uint32_t j2 = (instruction >> 27) & 0x1;
+ uint32_t imm10 = instruction & 0x3FF;
+ uint32_t imm11 = (instruction >> 16) & 0x7FF;
+ uint32_t i1 = (j1 == s);
+ uint32_t i2 = (j2 == s);
+ uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
+ int32_t sdis = dis;
+ if ( s )
+ sdis |= 0xFE000000;
+ displacement = sdis;
+ }
+ // The pc added will be +4 from the pc
+ displacement += 4;
+ dstAddr = srcAddr+displacement;
+ // If the instruction was blx, force the low 2 bits to be clear
+ if ((instruction & 0xF8000000) == 0xE8000000)
+ dstAddr &= 0xFFFFFFFC;
+ target.atom = parser.findAtomByAddress(sreloc->r_value());
+ target.addend = dstAddr - target.atom->_objAddress;
+ parser.addFixups(src, ld::Fixup::kindStoreThumbBranch22, target);
+ break;
+ case ARM_RELOC_SECTDIFF:
+ case ARM_RELOC_LOCAL_SECTDIFF:
+ {
+ if ( ! nextRelocIsPair )
+ throw "ARM_RELOC_SECTDIFF missing following pair";
+ if ( sreloc->r_length() != 2 )
+ throw "bad length for ARM_RELOC_SECTDIFF";
+ contentValue = LittleEndian::get32(*fixUpPtr);
+ Atom<arm>* fromAtom = parser.findAtomByAddress(nextRelocValue);
+ uint32_t offsetInFrom = nextRelocValue - fromAtom->_objAddress;
+ uint32_t offsetInTarget;
+ Atom<arm>* targetAtom = parser.findAtomByAddressOrLocalTargetOfStub(sreloc->r_value(), &offsetInTarget);
+ // check for addend encoded in the section content
+ int64_t addend = (int32_t)contentValue - (int32_t)(sreloc->r_value() - nextRelocValue);
+ if ( targetAtom->isThumb() )
+ addend &= -2; // remove thumb bit
+ // if reference to LSDA, add group subordinate fixup
+ if ( targetAtom->contentType() == ld::Atom::typeLSDA ) {
+ Parser<arm>::SourceLocation src2;
+ src2.atom = src.atom;
+ src2.offsetInAtom = 0;
+ parser.addFixup(src2, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinateLSDA, targetAtom);
+ }
+ if ( addend < 0 ) {
+ // switch binding base on coalescing
+ if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom);
+ }
+ else if ( (targetAtom->combine() == ld::Atom::combineByNameAndContent) || (targetAtom->combine() == ld::Atom::combineByNameAndReferences) ) {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, targetAtom);
+ }
+ else {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, targetAtom->name());
+ }
+ parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, offsetInTarget);
+ parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom);
+ parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom-addend);
+ parser.addFixup(src, ld::Fixup::k5of5, ld::Fixup::kindStoreLittleEndian32);
+ }
+ else {
+ if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom);
+ }
+ else if ( (targetAtom->combine() == ld::Atom::combineByNameAndContent) || (targetAtom->combine() == ld::Atom::combineByNameAndReferences) ) {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, targetAtom);
+ }
+ else {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, targetAtom->name());
+ }
+ parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, (uint32_t)(offsetInTarget+addend));
+ parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom);
+ parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom);
+ parser.addFixup(src, ld::Fixup::k5of5, ld::Fixup::kindStoreLittleEndian32);
+ }
+ }
+ break;
+ case ARM_RELOC_HALF_SECTDIFF:
+ if ( nextRelocIsPair ) {
+ instruction = LittleEndian::get32(*fixUpPtr);
+ Atom<arm>* fromAtom = parser.findAtomByAddress(nextRelocValue);
+ uint32_t offsetInFrom = nextRelocValue - fromAtom->_objAddress;
+ Atom<arm>* targetAtom = parser.findAtomByAddress(sreloc->r_value());
+ uint32_t offsetInTarget = sreloc->r_value() - targetAtom->_objAddress;
+ uint32_t instruction16;
+ uint32_t other16 = (nextRelocAddress & 0xFFFF);
+ bool isThumb;
+ if ( sreloc->r_length() & 2 ) {
+ isThumb = true;
+ uint32_t i = ((instruction & 0x00000400) >> 10);
+ uint32_t imm4 = (instruction & 0x0000000F);
+ uint32_t imm3 = ((instruction & 0x70000000) >> 28);
+ uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
+ instruction16 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
+ }
+ else {
+ isThumb = false;
+ uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
+ uint32_t imm12 = (instruction & 0x00000FFF);
+ instruction16 = (imm4 << 12) | imm12;
+ }
+ if ( sreloc->r_length() & 1 )
+ dstAddr = ((instruction16 << 16) | other16);
+ else
+ dstAddr = (other16 << 16) | instruction16;
+ if ( targetAtom->isThumb() )
+ dstAddr &= (-2); // remove thumb bit
+ int32_t addend = dstAddr - (sreloc->r_value() - nextRelocValue);
+ if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom);
+ }
+ else if ( (targetAtom->combine() == ld::Atom::combineByNameAndContent) || (targetAtom->combine() == ld::Atom::combineByNameAndReferences) ) {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, targetAtom);
+ }
+ else {
+ parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, targetAtom->name());
+ }
+ parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, (uint32_t)offsetInTarget+addend);
+ parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom);
+ parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom);
+ if ( sreloc->r_length() & 1 ) {
+ // high 16
+ parser.addFixup(src, ld::Fixup::k5of5, (isThumb ? ld::Fixup::kindStoreThumbHigh16 : ld::Fixup::kindStoreARMHigh16));
+ }
+ else {
+ // low 16
+ parser.addFixup(src, ld::Fixup::k5of5, (isThumb ? ld::Fixup::kindStoreThumbLow16 : ld::Fixup::kindStoreARMLow16));
+ }
+ result = true;
+ }
+ else
+ throw "ARM_RELOC_HALF_SECTDIFF reloc missing following pair";
+ break;
+ case ARM_RELOC_HALF:
+ if ( nextRelocIsPair ) {
+ instruction = LittleEndian::get32(*fixUpPtr);
+ Atom<arm>* targetAtom = parser.findAtomByAddress(sreloc->r_value());
+ uint32_t instruction16;
+ uint32_t other16 = (nextRelocAddress & 0xFFFF);
+ bool isThumb;
+ if ( sreloc->r_length() & 2 ) {
+ isThumb = true;
+ uint32_t i = ((instruction & 0x00000400) >> 10);
+ uint32_t imm4 = (instruction & 0x0000000F);
+ uint32_t imm3 = ((instruction & 0x70000000) >> 28);
+ uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
+ instruction16 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
+ }
+ else {
+ isThumb = false;
+ uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
+ uint32_t imm12 = (instruction & 0x00000FFF);
+ instruction16 = (imm4 << 12) | imm12;
+ }
+ if ( sreloc->r_length() & 1 )
+ dstAddr = ((instruction16 << 16) | other16);
+ else
+ dstAddr = (other16 << 16) | instruction16;
+ if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) {
+ parser.addFixup(src, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, targetAtom);
+ }
+ else if ( (targetAtom->combine() == ld::Atom::combineByNameAndContent) || (targetAtom->combine() == ld::Atom::combineByNameAndReferences) ) {
+ parser.addFixup(src, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, targetAtom);
+ }
+ else {
+ parser.addFixup(src, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, false, targetAtom->name());
+ }
+ parser.addFixup(src, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, dstAddr - targetAtom->_objAddress);
+ if ( sreloc->r_length() & 1 ) {
+ // high 16
+ parser.addFixup(src, ld::Fixup::k3of3, (isThumb ? ld::Fixup::kindStoreThumbHigh16 : ld::Fixup::kindStoreARMHigh16));
+ }
+ else {
+ // low 16
+ parser.addFixup(src, ld::Fixup::k3of3, (isThumb ? ld::Fixup::kindStoreThumbLow16 : ld::Fixup::kindStoreARMLow16));
+ }
+ result = true;
+ }
+ else
+ throw "scattered ARM_RELOC_HALF reloc missing following pair";
+ break;
+ default:
+ throwf("unknown ARM scattered relocation type %d", sreloc->r_type());
+ }
+ }
+ return result;
+}
+#endif
+
+
+
+
+
+template <typename A>
+bool ObjC1ClassSection<A>::addRelocFixup(class Parser<A>& parser, const macho_relocation_info<P>* reloc)
+{
+ // inherited
+ FixedSizeSection<A>::addRelocFixup(parser, reloc);
+
+ assert(0 && "needs template specialization");
+ return false;
+}
+
+template <>
+bool ObjC1ClassSection<x86>::addRelocFixup(class Parser<x86>& parser, const macho_relocation_info<x86::P>* reloc)
+{
+ // if this is the reloc for the super class name string, add implicit reference to super class
+ if ( ((reloc->r_address() & R_SCATTERED) == 0) && (reloc->r_type() == GENERIC_RELOC_VANILLA) ) {
+ assert( reloc->r_length() == 2 );
+ assert( ! reloc->r_pcrel() );
+
+ const macho_section<P>* sect = this->machoSection();
+ Parser<x86>::SourceLocation src;
+ uint32_t srcAddr = sect->addr() + reloc->r_address();
+ src.atom = this->findAtomByAddress(srcAddr);
+ src.offsetInAtom = srcAddr - src.atom->objectAddress();
+ if ( src.offsetInAtom == 4 ) {
+ Parser<x86>::TargetDesc stringTarget;
+ const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address();
+ uint32_t contentValue = LittleEndian::get32(*((uint32_t*)fixUpPtr));
+ parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), stringTarget);
+
+ assert(stringTarget.atom != NULL);
+ assert(stringTarget.atom->contentType() == ld::Atom::typeCString);
+ const char* superClassBaseName = (char*)stringTarget.atom->rawContentPointer();
+ char* superClassName = new char[strlen(superClassBaseName) + 20];
+ strcpy(superClassName, ".objc_class_name_");
+ strcat(superClassName, superClassBaseName);
+
+ parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindSetTargetAddress, false, superClassName);
+ }
+ }
+ // inherited
+ return FixedSizeSection<x86>::addRelocFixup(parser, reloc);
+}
+
+
+
+template <typename A>
+bool Objc1ClassReferences<A>::addRelocFixup(class Parser<A>& parser, const macho_relocation_info<P>* reloc)
+{
+ // inherited
+ PointerToCStringSection<A>::addRelocFixup(parser, reloc);
+
+ assert(0 && "needs template specialization");
+ return false;
+}
+
+
+
+template <>
+bool Objc1ClassReferences<x86>::addRelocFixup(class Parser<x86>& parser, const macho_relocation_info<x86::P>* reloc)
+{
+ // add implict class refs, fixups not usable yet, so look at relocations
+ assert( (reloc->r_address() & R_SCATTERED) == 0 );
+ assert( reloc->r_type() == GENERIC_RELOC_VANILLA );
+ assert( reloc->r_length() == 2 );
+ assert( ! reloc->r_pcrel() );
+
+ const macho_section<P>* sect = this->machoSection();
+ Parser<x86>::SourceLocation src;
+ uint32_t srcAddr = sect->addr() + reloc->r_address();
+ src.atom = this->findAtomByAddress(srcAddr);
+ src.offsetInAtom = srcAddr - src.atom->objectAddress();
+ Parser<x86>::TargetDesc stringTarget;
+ const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address();
+ uint32_t contentValue = LittleEndian::get32(*((uint32_t*)fixUpPtr));
+ parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), stringTarget);
+
+ assert(stringTarget.atom != NULL);
+ assert(stringTarget.atom->contentType() == ld::Atom::typeCString);
+ const char* baseClassName = (char*)stringTarget.atom->rawContentPointer();
+ char* objcClassName = new char[strlen(baseClassName) + 20];
+ strcpy(objcClassName, ".objc_class_name_");
+ strcat(objcClassName, baseClassName);
+
+ parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindSetTargetAddress, false, objcClassName);
+
+ // inherited
+ return PointerToCStringSection<x86>::addRelocFixup(parser, reloc);
+}
+
+
+template <typename A>
+void Section<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&)
+{
+ const macho_section<P>* sect = this->machoSection();
+ const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(file().fileContent() + sect->reloff());
+ const uint32_t relocCount = sect->nreloc();
+ for (uint32_t r = 0; r < relocCount; ++r) {
+ try {
+ if ( this->addRelocFixup(parser, &relocs[r]) )
+ ++r; // skip next
+ }
+ catch (const char* msg) {
+ throwf("in section %s,%s reloc %u: %s", sect->segname(), Section<A>::makeSectionName(sect), r, msg);
+ }
+ }
+
+ // add follow-on fixups if .o file is missing .subsections_via_symbols
+ if ( this->addFollowOnFixups() ) {
+ Atom<A>* end = &_endAtoms[-1];
+ for(Atom<A>* p = _beginAtoms; p < end; ++p) {
+ typename Parser<A>::SourceLocation src(p, 0);
+ Atom<A>* nextAtom = &p[1];
+ parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, nextAtom);
+ }
+ }
+ else if ( this->type() == ld::Section::typeCode ) {
+ // if FDE broke text not at a symbol, use followOn to keep code together
+ Atom<A>* end = &_endAtoms[-1];
+ for(Atom<A>* p = _beginAtoms; p < end; ++p) {
+ typename Parser<A>::SourceLocation src(p, 0);
+ Atom<A>* nextAtom = &p[1];
+ if ( (p->symbolTableInclusion() == ld::Atom::symbolTableIn) && (nextAtom->symbolTableInclusion() == ld::Atom::symbolTableNotIn) ) {
+ parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, nextAtom);
+ }
+ }
+ }
+
+ // <rdar://problem/9218847> track data-in-code
+ if ( parser.hasDataInCodeLabels() && (this->type() == ld::Section::typeCode) ) {
+ for (uint32_t i=0; i < parser.symbolCount(); ++i) {
+ const macho_nlist<P>& sym = parser.symbolFromIndex(i);
+ // ignore stabs
+ if ( (sym.n_type() & N_STAB) != 0 )
+ continue;
+ // ignore non-definitions
+ if ( (sym.n_type() & N_TYPE) != N_SECT )
+ continue;
+
+ // 'L' labels do not denote atom breaks
+ const char* symbolName = parser.nameFromSymbol(sym);
+ if ( symbolName[0] == 'L' ) {
+ if ( strncmp(symbolName, "L$start$", 8) == 0 ) {
+ ld::Fixup::Kind kind = ld::Fixup::kindNone;
+ if ( strncmp(&symbolName[8], "data$", 5) == 0 )
+ kind = ld::Fixup::kindDataInCodeStartData;
+ else if ( strncmp(&symbolName[8], "code$", 5) == 0 )
+ kind = ld::Fixup::kindDataInCodeEnd;
+ else if ( strncmp(&symbolName[8], "jt8$", 4) == 0 )
+ kind = ld::Fixup::kindDataInCodeStartJT8;
+ else if ( strncmp(&symbolName[8], "jt16$", 4) == 0 )
+ kind = ld::Fixup::kindDataInCodeStartJT16;
+ else if ( strncmp(&symbolName[8], "jt32$", 4) == 0 )
+ kind = ld::Fixup::kindDataInCodeStartJT32;
+ else if ( strncmp(&symbolName[8], "jta32$", 4) == 0 )
+ kind = ld::Fixup::kindDataInCodeStartJTA32;
+ else
+ warning("unknown L$start$ label %s in file %s", symbolName, this->file().path());
+ if ( kind != ld::Fixup::kindNone ) {
+ Atom<A>* inAtom = parser.findAtomByAddress(sym.n_value());
+ typename Parser<A>::SourceLocation src(inAtom, sym.n_value() - inAtom->objectAddress());
+ parser.addFixup(src, ld::Fixup::k1of1, kind);
+ }
+ }
+ }
+ }
+ }
+
+ // <rdar://problem/11150575> Handle LC_DATA_IN_CODE in object files
+ if ( this->type() == ld::Section::typeCode ) {
+ const pint_t startAddr = this->_machOSection->addr();
+ const pint_t endAddr = startAddr + this->_machOSection->size();
+ for ( const macho_data_in_code_entry<P>* p = parser.dataInCodeStart(); p != parser.dataInCodeEnd(); ++p ) {
+ if ( (p->offset() >= startAddr) && (p->offset() < endAddr) ) {
+ ld::Fixup::Kind kind = ld::Fixup::kindNone;
+ switch ( p->kind() ) {
+ case DICE_KIND_DATA:
+ kind = ld::Fixup::kindDataInCodeStartData;
+ break;
+ case DICE_KIND_JUMP_TABLE8:
+ kind = ld::Fixup::kindDataInCodeStartJT8;
+ break;
+ case DICE_KIND_JUMP_TABLE16:
+ kind = ld::Fixup::kindDataInCodeStartJT16;
+ break;
+ case DICE_KIND_JUMP_TABLE32:
+ kind = ld::Fixup::kindDataInCodeStartJT32;
+ break;
+ case DICE_KIND_ABS_JUMP_TABLE32:
+ kind = ld::Fixup::kindDataInCodeStartJTA32;
+ break;
+ default:
+ kind = ld::Fixup::kindDataInCodeStartData;
+ warning("uknown LC_DATA_IN_CODE kind (%d) at offset 0x%08X", p->kind(), p->offset());
+ break;
+ }
+ Atom<A>* inAtom = parser.findAtomByAddress(p->offset());
+ typename Parser<A>::SourceLocation srcStart(inAtom, p->offset() - inAtom->objectAddress());
+ parser.addFixup(srcStart, ld::Fixup::k1of1, kind);
+ typename Parser<A>::SourceLocation srcEnd(inAtom, p->offset() + p->length() - inAtom->objectAddress());
+ parser.addFixup(srcEnd, ld::Fixup::k1of1, ld::Fixup::kindDataInCodeEnd);
+ }
+ }
+ }
+
+
+ // add follow-on fixups for aliases
+ if ( _hasAliases ) {
+ for(Atom<A>* p = _beginAtoms; p < _endAtoms; ++p) {
+ if ( p->isAlias() && ! this->addFollowOnFixups() ) {
+ Atom<A>* targetOfAlias = &p[1];
+ assert(p < &_endAtoms[-1]);
+ assert(p->_objAddress == targetOfAlias->_objAddress);
+ typename Parser<A>::SourceLocation src(p, 0);
+ parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, targetOfAlias);
+ }
+ }
+ }
+}
+
+
+
+//
+// main function used by linker to instantiate ld::Files
+//
+ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength,
+ const char* path, time_t modTime, ld::File::Ordinal ordinal, const ParserOptions& opts)
+{
+ switch ( opts.architecture ) {
+#if SUPPORT_ARCH_x86_64
+ case CPU_TYPE_X86_64:
+ if ( mach_o::relocatable::Parser<x86_64>::validFile(fileContent) )
+ return mach_o::relocatable::Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+ break;
+#endif
+#if SUPPORT_ARCH_i386
+ case CPU_TYPE_I386:
+ if ( mach_o::relocatable::Parser<x86>::validFile(fileContent) )
+ return mach_o::relocatable::Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+ break;
+#endif
+#if SUPPORT_ARCH_arm_any
+ case CPU_TYPE_ARM:
+ if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) )
+ return mach_o::relocatable::Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+ break;
+#endif
+ }
+ return NULL;
+}
+
+//
+// used by archive reader to validate member object file
+//
+bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, const ParserOptions& opts)
+{
+ switch ( opts.architecture ) {
+ case CPU_TYPE_X86_64:
+ return ( mach_o::relocatable::Parser<x86_64>::validFile(fileContent) );
+ case CPU_TYPE_I386:
+ return ( mach_o::relocatable::Parser<x86>::validFile(fileContent) );
+ case CPU_TYPE_ARM:
+ return ( mach_o::relocatable::Parser<arm>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) );
+ }
+ return false;
+}
+
+//
+// used by linker to infer architecture when no -arch is on command line
+//
+bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult)
+{
+ if ( mach_o::relocatable::Parser<x86_64>::validFile(fileContent) ) {
+ *result = CPU_TYPE_X86_64;
+ *subResult = CPU_SUBTYPE_X86_64_ALL;
+ return true;
+ }
+ if ( mach_o::relocatable::Parser<x86>::validFile(fileContent) ) {
+ *result = CPU_TYPE_I386;
+ *subResult = CPU_SUBTYPE_X86_ALL;
+ return true;
+ }
+ if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, false, 0) ) {
+ *result = CPU_TYPE_ARM;
+ const macho_header<Pointer32<LittleEndian> >* header = (const macho_header<Pointer32<LittleEndian> >*)fileContent;
+ *subResult = header->cpusubtype();
+ return true;
+ }
+ return false;
+}
+
+//
+// used by linker is error messages to describe bad .o file
+//
+const char* archName(const uint8_t* fileContent)
+{
+ if ( mach_o::relocatable::Parser<x86_64>::validFile(fileContent) ) {
+ return mach_o::relocatable::Parser<x86_64>::fileKind(fileContent);
+ }
+ if ( mach_o::relocatable::Parser<x86>::validFile(fileContent) ) {
+ return mach_o::relocatable::Parser<x86>::fileKind(fileContent);
+ }
+ if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, false, 0) ) {
+ return mach_o::relocatable::Parser<arm>::fileKind(fileContent);
+ }
+ return NULL;
+}
+
+//
+// Used by archive reader when -ObjC option is specified
+//
+bool hasObjC2Categories(const uint8_t* fileContent)
+{
+ if ( mach_o::relocatable::Parser<x86_64>::validFile(fileContent) ) {
+ return mach_o::relocatable::Parser<x86_64>::hasObjC2Categories(fileContent);
+ }
+ else if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, false, 0) ) {
+ return mach_o::relocatable::Parser<arm>::hasObjC2Categories(fileContent);
+ }
+ else if ( mach_o::relocatable::Parser<x86>::validFile(fileContent, false, 0) ) {
+ return mach_o::relocatable::Parser<x86>::hasObjC2Categories(fileContent);
+ }
+ return false;
+}
+
+//
+// Used by archive reader when -ObjC option is specified
+//
+bool hasObjC1Categories(const uint8_t* fileContent)
+{
+ if ( mach_o::relocatable::Parser<x86>::validFile(fileContent, false, 0) ) {
+ return mach_o::relocatable::Parser<x86>::hasObjC1Categories(fileContent);
+ }
+ return false;
+}
+
+
+
+} // namespace relocatable
+} // namespace mach_o
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __MACHO_RELOCATABLE_FILE_H__
+#define __MACHO_RELOCATABLE_FILE_H__
+
+#include "ld.hpp"
+#include "Options.h"
+
+namespace mach_o {
+namespace relocatable {
+
+struct ParserOptions {
+ uint32_t architecture;
+ bool objSubtypeMustMatch;
+ bool logAllFiles;
+ bool convertUnwindInfo;
+ uint32_t subType;
+};
+
+extern ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength,
+ const char* path, time_t modTime, ld::File::Ordinal ordinal,
+ const ParserOptions& opts);
+
+extern bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, const ParserOptions& opts);
+
+extern bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult);
+
+extern bool hasObjC2Categories(const uint8_t* fileContent);
+
+extern bool hasObjC1Categories(const uint8_t* fileContent);
+
+extern const char* archName(const uint8_t* fileContent);
+
+} // namespace relocatable
+} // namespace mach_o
+
+
+#endif // __MACHO_RELOCATABLE_FILE_H__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <vector>
+
+#include "ld.hpp"
+#include "opaque_section_file.h"
+
+
+namespace opaque_section {
+
+
+
+class Atom : public ld::Atom {
+public:
+ virtual ld::File* file() const { return (ld::File*)&_file; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return _size; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const
+ { memcpy(buffer, _content, _size); }
+ virtual void setScope(Scope) { }
+
+protected:
+ friend class File;
+ Atom(class File& f, const char* n, const uint8_t* content, uint64_t sz);
+ virtual ~Atom() {}
+
+ class File& _file;
+ const char* _name;
+ const uint8_t* _content;
+ uint64_t _size;
+};
+
+
+class File : public ld::File
+{
+public:
+ File(const char* segmentName, const char* sectionName, const char* pth,
+ const uint8_t fileContent[], uint64_t fileLength,
+ const char* symbolName="sect_create")
+ : ld::File(pth, 0, ld::File::Ordinal::NullOrdinal(), Other),
+ _atom(*this, symbolName, fileContent, fileLength),
+ _section(segmentName, sectionName, ld::Section::typeUnclassified) { }
+ virtual ~File() { }
+
+ virtual bool forEachAtom(ld::File::AtomHandler& h) const { h.doAtom(_atom); return true; }
+ virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const { return false; }
+
+ ld::Atom* atom() { return &_atom; }
+private:
+ friend class Atom;
+
+ Atom _atom;
+ ld::Section _section;
+};
+
+Atom::Atom(File& f, const char* n, const uint8_t* content, uint64_t sz)
+ : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
+ symbolTableNotIn, true, false, false, ld::Atom::Alignment(0)),
+ _file(f), _name(n), _content(content), _size(sz) {}
+
+
+//
+// main function used by linker for -sectcreate
+//
+ld::File* parse(const char* segmentName, const char* sectionName, const char* path,
+ const uint8_t fileContent[], uint64_t fileLength,
+ const char* symbolName)
+{
+ return new File(segmentName, sectionName, path, fileContent, fileLength, symbolName);
+}
+
+
+} // namespace opaque_section
+
+
+
+
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __SECTION_FILE_H__
+#define __SECTION_FILE_H__
+
+
+
+#include "ld.hpp"
+
+namespace opaque_section {
+
+extern ld::File* parse(const char* segmentName, const char* sectionName, const char* path,
+ const uint8_t fileContent[], uint64_t fileLength,
+ const char* symbolName="opaque_section");
+
+
+} // namespace opaque_section
+
+
+
+#endif // __SECTION_FILE_H__
+
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <libkern/OSByteOrder.h>
+
+#include <vector>
+#include <map>
+
+#include "MachOFileAbstraction.hpp"
+#include "ld.hpp"
+#include "branch_island.h"
+
+namespace ld {
+namespace passes {
+namespace branch_island {
+
+
+
+
+struct TargetAndOffset { const ld::Atom* atom; uint32_t offset; };
+class TargetAndOffsetComparor
+{
+public:
+ bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
+ {
+ if ( left.atom != right.atom )
+ return ( left.atom < right.atom );
+ return ( left.offset < right.offset );
+ }
+};
+
+
+static bool _s_log = false;
+static ld::Section _s_text_section("__TEXT", "__text", ld::Section::typeCode);
+
+
+
+class ARMtoARMBranchIslandAtom : public ld::Atom {
+public:
+ ARMtoARMBranchIslandAtom(const char* nm, const ld::Atom* target, TargetAndOffset finalTarget)
+ : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland,
+ ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)),
+ _name(nm),
+ _target(target),
+ _finalTarget(finalTarget) { }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 4; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ int64_t displacement = _target->finalAddress() - this->finalAddress() - 8;
+ if ( _target->contentType() == ld::Atom::typeBranchIsland ) {
+ // an ARM branch can branch farther than a thumb branch. The branch
+ // island generation was conservative and put islands every thumb
+ // branch distance apart. Check to see if this is a an island
+ // hopping branch that could be optimized to go directly to target.
+ int64_t skipToFinalDisplacement = _finalTarget.atom->finalAddress() + _finalTarget.offset - this->finalAddress() - 8;
+ if ( (skipToFinalDisplacement < 33554428LL) && (skipToFinalDisplacement > (-33554432LL)) ) {
+ // can skip branch island and jump straight to target
+ if (_s_log) fprintf(stderr, "%s: optimized jump to final target at 0x%08llX, thisAddr=0x%08llX\n",
+ _target->name(), _finalTarget.atom->finalAddress(), this->finalAddress());
+ displacement = skipToFinalDisplacement;
+ }
+ else {
+ // ultimate target is too far, jump to island
+ if (_s_log) fprintf(stderr, "%s: jump to branch island at 0x%08llX\n",
+ _target->name(), _finalTarget.atom->finalAddress());
+ }
+ }
+ uint32_t imm24 = (displacement >> 2) & 0x00FFFFFF;
+ int32_t branchInstruction = 0xEA000000 | imm24;
+ OSWriteLittleInt32(buffer, 0, branchInstruction);
+ }
+ virtual void setScope(Scope) { }
+
+private:
+ const char* _name;
+ const ld::Atom* _target;
+ TargetAndOffset _finalTarget;
+};
+
+
+
+class ARMtoThumb1BranchIslandAtom : public ld::Atom {
+public:
+ ARMtoThumb1BranchIslandAtom(const char* nm, const ld::Atom* target, TargetAndOffset finalTarget)
+ : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland,
+ ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)),
+ _name(nm),
+ _target(target),
+ _finalTarget(finalTarget) { }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 16; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ // There is no large displacement thumb1 branch instruction.
+ // Instead use ARM instructions that can jump to thumb.
+ // we use a 32-bit displacement, so we can directly jump to target which means no island hopping
+ int64_t displacement = _finalTarget.atom->finalAddress() + _finalTarget.offset - (this->finalAddress() + 12);
+ if ( _finalTarget.atom->isThumb() )
+ displacement |= 1;
+ if (_s_log) fprintf(stderr, "%s: 4 ARM instruction jump to final target at 0x%08llX\n",
+ _target->name(), _finalTarget.atom->finalAddress());
+ OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 4
+ OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip
+ OSWriteLittleInt32(&buffer[ 8], 0, 0xe12fff1c); // bx ip
+ OSWriteLittleInt32(&buffer[12], 0, displacement); // .long target-this
+ }
+ virtual void setScope(Scope) { }
+
+private:
+ const char* _name;
+ const ld::Atom* _target;
+ TargetAndOffset _finalTarget;
+};
+
+
+
+class Thumb2toThumbBranchIslandAtom : public ld::Atom {
+public:
+ Thumb2toThumbBranchIslandAtom(const char* nm, const ld::Atom* target, TargetAndOffset finalTarget)
+ : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland,
+ ld::Atom::symbolTableIn, false, true, false, ld::Atom::Alignment(1)),
+ _name(nm),
+ _target(target),
+ _finalTarget(finalTarget) { }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 4; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ int64_t displacement = _target->finalAddress() - this->finalAddress() - 4;
+ if ( _target->contentType() == ld::Atom::typeBranchIsland ) {
+ // an ARM branch can branch farther than a thumb branch. The branch
+ // island generation was conservative and put islands every thumb
+ // branch distance apart. Check to see if this is a an island
+ // hopping branch that could be optimized to go directly to target.
+ int64_t skipToFinalDisplacement = _finalTarget.atom->finalAddress() + _finalTarget.offset - this->finalAddress() - 4;
+ if ( (skipToFinalDisplacement < 16777214) && (skipToFinalDisplacement > (-16777216LL)) ) {
+ // can skip branch island and jump straight to target
+ if (_s_log) fprintf(stderr, "%s: optimized jump to final target at 0x%08llX, thisAddr=0x%08llX\n",
+ _target->name(), _finalTarget.atom->finalAddress(), this->finalAddress());
+ displacement = skipToFinalDisplacement;
+ }
+ else {
+ // ultimate target is too far for thumb2 branch, jump to island
+ if (_s_log) fprintf(stderr, "%s: jump to branch island at 0x%08llX\n",
+ _target->name(), _finalTarget.atom->finalAddress());
+ }
+ }
+ // The instruction is really two instructions:
+ // The lower 16 bits are the first instruction, which contains the high
+ // 11 bits of the displacement.
+ // The upper 16 bits are the second instruction, which contains the low
+ // 11 bits of the displacement, as well as differentiating bl and blx.
+ uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
+ uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
+ uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
+ uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
+ uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
+ uint32_t j1 = (i1 == s);
+ uint32_t j2 = (i2 == s);
+ uint32_t opcode = 0x9000F000;
+ uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
+ uint32_t firstDisp = (s << 10) | imm10;
+ uint32_t newInstruction = opcode | (nextDisp << 16) | firstDisp;
+ //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
+ // s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
+ OSWriteLittleInt32(buffer, 0, newInstruction);
+ }
+ virtual void setScope(Scope) { }
+
+private:
+ const char* _name;
+ const ld::Atom* _target;
+ TargetAndOffset _finalTarget;
+};
+
+
+class NoPicARMtoThumbMBranchIslandAtom : public ld::Atom {
+public:
+ NoPicARMtoThumbMBranchIslandAtom(const char* nm, const ld::Atom* target, TargetAndOffset finalTarget)
+ : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland,
+ ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)),
+ _name(nm),
+ _target(target),
+ _finalTarget(finalTarget) { }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 8; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ // There is no large displacement thumb1 branch instruction.
+ // Instead use ARM instructions that can jump to thumb.
+ // we use a 32-bit displacement, so we can directly jump to final target which means no island hopping
+ uint32_t targetAddr = _finalTarget.atom->finalAddress();
+ if ( _finalTarget.atom->isThumb() )
+ targetAddr |= 1;
+ if (_s_log) fprintf(stderr, "%s: 2 ARM instruction jump to final target at 0x%08llX\n",
+ _target->name(), _finalTarget.atom->finalAddress());
+ OSWriteLittleInt32(&buffer[0], 0, 0xe51ff004); // ldr pc, [pc, #-4]
+ OSWriteLittleInt32(&buffer[4], 0, targetAddr); // .long target-this
+ }
+ virtual void setScope(Scope) { }
+
+private:
+ const char* _name;
+ const ld::Atom* _target;
+ TargetAndOffset _finalTarget;
+};
+
+
+static ld::Atom* makeBranchIsland(const Options& opts, ld::Fixup::Kind kind, int islandRegion, const ld::Atom* nextTarget, TargetAndOffset finalTarget)
+{
+ char* name;
+ if ( finalTarget.offset == 0 ) {
+ if ( islandRegion == 0 )
+ asprintf(&name, "%s.island", finalTarget.atom->name());
+ else
+ asprintf(&name, "%s.island.%d", finalTarget.atom->name(), islandRegion+1);
+ }
+ else {
+ asprintf(&name, "%s_plus_%d.island.%d", finalTarget.atom->name(), finalTarget.offset, islandRegion);
+ }
+
+ switch ( kind ) {
+ case ld::Fixup::kindStoreARMBranch24:
+ case ld::Fixup::kindStoreThumbBranch22:
+ case ld::Fixup::kindStoreTargetAddressARMBranch24:
+ case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+ if ( finalTarget.atom->isThumb() ) {
+ if ( opts.preferSubArchitecture() && opts.archSupportsThumb2() ) {
+ return new Thumb2toThumbBranchIslandAtom(name, nextTarget, finalTarget);
+ }
+ else if ( opts.outputSlidable() ) {
+ return new ARMtoThumb1BranchIslandAtom(name, nextTarget, finalTarget);
+ }
+ else {
+ return new NoPicARMtoThumbMBranchIslandAtom(name, nextTarget, finalTarget);
+ }
+ }
+ else {
+ return new ARMtoARMBranchIslandAtom(name, nextTarget, finalTarget);
+ }
+ break;
+ default:
+ assert(0 && "unexpected branch kind");
+ break;
+ }
+ return NULL;
+}
+
+
+static uint64_t textSizeWhenMightNeedBranchIslands(const Options& opts, bool seenThumbBranch)
+{
+ switch ( opts.architecture() ) {
+ case CPU_TYPE_ARM:
+ if ( ! seenThumbBranch )
+ return 32000000; // ARM can branch +/- 32MB
+ else if ( opts.preferSubArchitecture() && opts.archSupportsThumb2() )
+ return 16000000; // thumb2 can branch +/- 16MB
+ else
+ return 4000000; // thumb1 can branch +/- 4MB
+ break;
+ }
+ assert(0 && "unexpected architecture");
+ return 0x100000000LL;
+}
+
+
+static uint64_t maxDistanceBetweenIslands(const Options& opts, bool seenThumbBranch)
+{
+ switch ( opts.architecture() ) {
+ case CPU_TYPE_ARM:
+ if ( ! seenThumbBranch )
+ return 30*1024*1024; // 2MB of branch islands per 32MB
+ else if ( opts.preferSubArchitecture() && opts.archSupportsThumb2() )
+ return 14*1024*1024; // 2MB of branch islands per 16MB
+ else
+ return 3500000; // 0.5MB of branch islands per 4MB
+ break;
+ }
+ assert(0 && "unexpected architecture");
+ return 0x100000000LL;
+}
+
+
+//
+// PowerPC can do PC relative branches as far as +/-16MB.
+// If a branch target is >16MB then we insert one or more
+// "branch islands" between the branch and its target that
+// allows island hopping to the target.
+//
+// Branch Island Algorithm
+//
+// If the __TEXT segment < 16MB, then no branch islands needed
+// Otherwise, every 14MB into the __TEXT segment a region is
+// added which can contain branch islands. Every out-of-range
+// bl instruction is checked. If it crosses a region, an island
+// is added to that region with the same target and the bl is
+// adjusted to target the island instead.
+//
+// In theory, if too many islands are added to one region, it
+// could grow the __TEXT enough that other previously in-range
+// bl branches could be pushed out of range. We reduce the
+// probability this could happen by placing the ranges every
+// 14MB which means the region would have to be 2MB (512,000 islands)
+// before any branches could be pushed out of range.
+//
+
+void doPass(const Options& opts, ld::Internal& state)
+{
+ // only make branch islands in final linked images
+ if ( opts.outputKind() == Options::kObjectFile )
+ return;
+
+ // only ARM needs branch islands
+ switch ( opts.architecture() ) {
+ case CPU_TYPE_ARM:
+ break;
+ default:
+ return;
+ }
+
+ // scan to find __text section
+ ld::Internal::FinalSection* textSection = NULL;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( strcmp(sect->sectionName(), "__text") == 0 )
+ textSection = sect;
+ }
+ if ( textSection == NULL )
+ return;
+
+ // assign section offsets to each atom in __text section, watch for thumb branches, and find total size
+ const bool isARM = (opts.architecture() == CPU_TYPE_ARM);
+ bool hasThumbBranches = false;
+ uint64_t offset = 0;
+ for (std::vector<const ld::Atom*>::iterator ait=textSection->atoms.begin(); ait != textSection->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ // check for thumb branches
+ if ( isARM && ~hasThumbBranches ) {
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ switch ( fit->kind ) {
+ case ld::Fixup::kindStoreThumbBranch22:
+ case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+ hasThumbBranches = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ // align atom
+ ld::Atom::Alignment atomAlign = atom->alignment();
+ uint64_t atomAlignP2 = (1 << atomAlign.powerOf2);
+ uint64_t currentModulus = (offset % atomAlignP2);
+ if ( currentModulus != atomAlign.modulus ) {
+ if ( atomAlign.modulus > currentModulus )
+ offset += atomAlign.modulus-currentModulus;
+ else
+ offset += atomAlign.modulus+atomAlignP2-currentModulus;
+ }
+ (const_cast<ld::Atom*>(atom))->setSectionOffset(offset);
+ offset += atom->size();
+ }
+ uint64_t totalTextSize = offset;
+ if ( totalTextSize < textSizeWhenMightNeedBranchIslands(opts, hasThumbBranches) )
+ return;
+ if (_s_log) fprintf(stderr, "ld: __text section size=%llu, might need branch islands\n", totalTextSize);
+
+ // Figure out how many regions of branch islands will be needed, and their locations.
+ // Construct a vector containing the atoms after which branch islands will be inserted,
+ // taking into account follow on fixups. No atom run without an island can exceed kBetweenRegions.
+ const uint64_t kBetweenRegions = maxDistanceBetweenIslands(opts, hasThumbBranches); // place regions of islands every 14MB in __text section
+ std::vector<const ld::Atom*> branchIslandInsertionPoints; // atoms in the atom list after which branch islands will be inserted
+ uint64_t previousIslandEndAddr = 0;
+ const ld::Atom *insertionPoint;
+ branchIslandInsertionPoints.reserve(totalTextSize/kBetweenRegions*2);
+ for (std::vector<const ld::Atom*>::iterator it=textSection->atoms.begin(); it != textSection->atoms.end(); it++) {
+ const ld::Atom* atom = *it;
+ // if we move past the next atom, will the run length exceed kBetweenRegions?
+ if ( atom->sectionOffset() + atom->size() - previousIslandEndAddr > kBetweenRegions ) {
+ // yes. Add the last known good location (atom) for inserting a branch island.
+ if ( insertionPoint == NULL )
+ throwf("Unable to insert branch island. No insertion point available.");
+ branchIslandInsertionPoints.push_back(insertionPoint);
+ previousIslandEndAddr = insertionPoint->sectionOffset()+insertionPoint->size();
+ insertionPoint = NULL;
+ }
+ // Can we insert an island after this atom? If so then keep track of it.
+ if ( !atom->hasFixupsOfKind(ld::Fixup::kindNoneFollowOn) )
+ insertionPoint = atom;
+ }
+ // add one more island after the last atom
+ if (insertionPoint != NULL)
+ branchIslandInsertionPoints.push_back(insertionPoint);
+ const int kIslandRegionsCount = branchIslandInsertionPoints.size();
+ if (_s_log) {
+ fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount);
+ for (std::vector<const ld::Atom*>::iterator it = branchIslandInsertionPoints.begin(); it != branchIslandInsertionPoints.end(); ++it) {
+ const ld::Atom* atom = *it;
+ const ld::File *file = atom->file();
+ fprintf(stderr, "ld: branch island will be inserted at 0x%llx after %s", atom->sectionOffset()+atom->size(), atom->name());
+ if (file) fprintf(stderr, " (%s)", atom->file()->path());
+ fprintf(stderr, "\n");
+ }
+ }
+
+
+ typedef std::map<TargetAndOffset,const ld::Atom*, TargetAndOffsetComparor> AtomToIsland;
+ AtomToIsland* regionsMap[kIslandRegionsCount];
+ std::vector<const ld::Atom*>* regionsIslands[kIslandRegionsCount];
+ for(int i=0; i < kIslandRegionsCount; ++i) {
+ regionsMap[i] = new AtomToIsland();
+ regionsIslands[i] = new std::vector<const ld::Atom*>();
+ }
+ unsigned int islandCount = 0;
+
+ // create islands for branches in __text that are out of range
+ for (std::vector<const ld::Atom*>::iterator ait=textSection->atoms.begin(); ait != textSection->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ const ld::Atom* target = NULL;
+ uint64_t addend = 0;
+ ld::Fixup* fixupWithTarget = NULL;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ if ( fit->firstInCluster() ) {
+ target = NULL;
+ fixupWithTarget = NULL;
+ addend = 0;
+ }
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingNone:
+ case ld::Fixup::bindingByNameUnbound:
+ break;
+ case ld::Fixup::bindingByContentBound:
+ case ld::Fixup::bindingDirectlyBound:
+ target = fit->u.target;
+ fixupWithTarget = fit;
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ target = state.indirectBindingTable[fit->u.bindingIndex];
+ fixupWithTarget = fit;
+ break;
+ }
+ bool haveBranch = false;
+ switch (fit->kind) {
+ case ld::Fixup::kindAddAddend:
+ addend = fit->u.addend;
+ break;
+ case ld::Fixup::kindStoreARMBranch24:
+ case ld::Fixup::kindStoreThumbBranch22:
+ case ld::Fixup::kindStoreTargetAddressARMBranch24:
+ case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+ haveBranch = true;
+ break;
+ default:
+ break;
+ }
+ if ( haveBranch ) {
+ int64_t srcAddr = atom->sectionOffset() + fit->offsetInAtom;
+ int64_t dstAddr = target->sectionOffset() + addend;
+ if ( target->section().type() == ld::Section::typeStub )
+ dstAddr = totalTextSize;
+ int64_t displacement = dstAddr - srcAddr;
+ TargetAndOffset finalTargetAndOffset = { target, addend };
+ const int64_t kBranchLimit = kBetweenRegions;
+ if ( displacement > kBranchLimit ) {
+ // create forward branch chain
+ const ld::Atom* nextTarget = target;
+ for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
+ AtomToIsland* region = regionsMap[i];
+ int64_t islandRegionAddr = kBetweenRegions * (i+1);
+ if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) {
+ AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
+ if ( pos == region->end() ) {
+ ld::Atom* island = makeBranchIsland(opts, fit->kind, i, nextTarget, finalTargetAndOffset);
+ (*region)[finalTargetAndOffset] = island;
+ if (_s_log) fprintf(stderr, "added island %s to region %d for %s\n", island->name(), i, atom->name());
+ regionsIslands[i]->push_back(island);
+ ++islandCount;
+ nextTarget = island;
+ }
+ else {
+ nextTarget = pos->second;
+ }
+ }
+ }
+ if (_s_log) fprintf(stderr, "using island %s for branch to %s from %s\n", nextTarget->name(), target->name(), atom->name());
+ fixupWithTarget->u.target = nextTarget;
+ fixupWithTarget->binding = ld::Fixup::bindingDirectlyBound;
+ }
+ else if ( displacement < (-kBranchLimit) ) {
+ // create back branching chain
+ const ld::Atom* prevTarget = target;
+ for (int i=0; i < kIslandRegionsCount ; ++i) {
+ AtomToIsland* region = regionsMap[i];
+ int64_t islandRegionAddr = kBetweenRegions * (i+1);
+ if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) {
+ AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
+ if ( pos == region->end() ) {
+ ld::Atom* island = makeBranchIsland(opts, fit->kind, i, prevTarget, finalTargetAndOffset);
+ (*region)[finalTargetAndOffset] = island;
+ if (_s_log) fprintf(stderr, "added back island %s to region %d for %s\n", island->name(), i, atom->name());
+ regionsIslands[i]->push_back(island);
+ ++islandCount;
+ prevTarget = island;
+ }
+ else {
+ prevTarget = pos->second;
+ }
+ }
+ }
+ if (_s_log) fprintf(stderr, "using back island %s for %s\n", prevTarget->name(), atom->name());
+ fixupWithTarget->u.target = prevTarget;
+ fixupWithTarget->binding = ld::Fixup::bindingDirectlyBound;
+ }
+ }
+ }
+ }
+
+
+ // insert islands into __text section and adjust section offsets
+ if ( islandCount > 0 ) {
+ if ( _s_log ) fprintf(stderr, "ld: %u branch islands required in %u regions\n", islandCount, kIslandRegionsCount);
+ std::vector<const ld::Atom*> newAtomList;
+ newAtomList.reserve(textSection->atoms.size()+islandCount);
+
+ uint64_t regionIndex = 0;
+ for (std::vector<const ld::Atom*>::iterator ait=textSection->atoms.begin(); ait != textSection->atoms.end(); ait++) {
+ newAtomList.push_back(*ait);
+ // copy over atoms until we find an island insertion point
+ // Note that the last insertion point is the last atom, so this loop never moves the iterator to atoms.end().
+ while (*ait != branchIslandInsertionPoints[regionIndex]) {
+ ait++;
+ newAtomList.push_back(*ait);
+ }
+
+ // insert the branch island atoms after the insertion point atom
+ std::vector<const ld::Atom*>* regionIslands = regionsIslands[regionIndex];
+ for (std::vector<const ld::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
+ const ld::Atom* islandAtom = *rit;
+ newAtomList.push_back(islandAtom);
+ if ( _s_log ) fprintf(stderr, "inserting island %s into __text section\n", islandAtom->name());
+ }
+ regionIndex++;
+ }
+ // swap in new list of atoms for __text section
+ textSection->atoms.clear();
+ textSection->atoms = newAtomList;
+ }
+
+}
+
+
+} // namespace branch_island
+} // namespace passes
+} // namespace ld
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __BRANCH_ISLAND_H__
+#define __BRANCH_ISLAND_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace branch_island {
+
+// called by linker to branch islands if there are out of range branches
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace branch_island
+} // namespace passes
+} // namespace ld
+
+#endif // __BRANCH_ISLAND_H__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <vector>
+#include <map>
+
+#include "MachOFileAbstraction.hpp"
+#include "ld.hpp"
+#include "branch_shim.h"
+
+namespace ld {
+namespace passes {
+namespace branch_shim {
+
+
+
+static bool _s_log = false;
+
+
+class Thumb2ToArmShimAtom : public ld::Atom {
+public:
+ Thumb2ToArmShimAtom(const ld::Atom* target, const ld::Section& inSect)
+ : ld::Atom(inSect, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
+ ld::Atom::symbolTableIn, false, true, false, ld::Atom::Alignment(2)),
+ _name(NULL),
+ _target(target),
+ _fixup1(8, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, target),
+ _fixup2(8, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+ _fixup3(8, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 8),
+ _fixup4(8, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32)
+ { asprintf((char**)&_name, "%s$shim", target->name()); }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 12; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ // Use ARM instructions that can jump to thumb.
+ assert( ! _target->isThumb() );
+ if (_s_log) fprintf(stderr, "3 Thumb2 instruction shim to jump to %s\n", _target->name());
+ OSWriteLittleInt32(&buffer[0], 0, 0xc004f8df); // ldr ip, pc + 4
+ OSWriteLittleInt16(&buffer[4], 0, 0x44fc); // add ip, pc, ip
+ OSWriteLittleInt16(&buffer[6], 0, 0x4760); // bx ip
+ OSWriteLittleInt32(&buffer[8], 0, 0x00000000); // .long target-this
+ }
+
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup4)[1]; }
+
+private:
+ const char* _name;
+ const ld::Atom* _target;
+ ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+ ld::Fixup _fixup4;
+};
+
+
+class NoPICThumb2ToArmShimAtom : public ld::Atom {
+public:
+ NoPICThumb2ToArmShimAtom(const ld::Atom* target, const ld::Section& inSect)
+ : ld::Atom(inSect, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
+ ld::Atom::symbolTableIn, false, true, false, ld::Atom::Alignment(2)),
+ _name(NULL),
+ _target(target),
+ _fixup1(8, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, target)
+ { asprintf((char**)&_name, "%s$shim", target->name()); }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 12; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ // Use ARM instructions that can jump to thumb.
+ assert( ! _target->isThumb() );
+ if (_s_log) fprintf(stderr, "3 Thumb2 instruction shim to jump to %s\n", _target->name());
+ OSWriteLittleInt32(&buffer[0], 0, 0xc004f8df); // ldr ip, pc + 4
+ OSWriteLittleInt16(&buffer[4], 0, 0x4760); // bx ip
+ OSWriteLittleInt16(&buffer[6], 0, 0x46C0); // nop
+ OSWriteLittleInt32(&buffer[8], 0, 0x00000000); // .long target
+ }
+
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup1)[1]; }
+
+private:
+ const char* _name;
+ const ld::Atom* _target;
+ ld::Fixup _fixup1;
+};
+
+
+class Thumb1ToArmShimAtom : public ld::Atom {
+public:
+ Thumb1ToArmShimAtom(const ld::Atom* target, const ld::Section& inSect)
+ : ld::Atom(inSect, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
+ ld::Atom::symbolTableIn, false, true, false, ld::Atom::Alignment(2)),
+ _name(NULL),
+ _target(target),
+ _fixup1(12, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, target),
+ _fixup2(12, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+ _fixup3(12, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 8),
+ _fixup4(12, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32)
+ { asprintf((char**)&_name, "%s$shim", target->name()); }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 16; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ // Use ARM instructions that can jump to thumb.
+ assert( ! _target->isThumb() );
+ if (_s_log) fprintf(stderr, "6 Thumb1 instruction shim to jump to %s\n", _target->name());
+ OSWriteLittleInt16(&buffer[ 0], 0, 0xb402); // push {r1}
+ OSWriteLittleInt16(&buffer[ 2], 0, 0x4902); // ldr r1, [pc, #8]
+ OSWriteLittleInt16(&buffer[ 4], 0, 0x4479); // add r1, pc
+ OSWriteLittleInt16(&buffer[ 6], 0, 0x468c); // mov ip, r1
+ OSWriteLittleInt16(&buffer[ 8], 0, 0xbc02); // pop {r1}
+ OSWriteLittleInt16(&buffer[10], 0, 0x4760); // bx ip
+ OSWriteLittleInt32(&buffer[12], 0, 0x00000000); // .long target-this
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup4)[1]; }
+
+private:
+ const char* _name;
+ const ld::Atom* _target;
+ ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+ ld::Fixup _fixup4;
+};
+
+
+
+
+class ARMtoThumbShimAtom : public ld::Atom {
+public:
+ ARMtoThumbShimAtom(const ld::Atom* target, const ld::Section& inSect)
+ : ld::Atom(inSect, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
+ ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)),
+ _name(NULL),
+ _target(target),
+ _fixup1(12, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, target),
+ _fixup2(12, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+ _fixup3(12, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 12),
+ _fixup4(12, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32)
+ { asprintf((char**)&_name, "%s$shim", target->name()); }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 16; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ // Use ARM instructions that can jump to thumb.
+ assert( _target->isThumb() );
+ if (_s_log) fprintf(stderr, "4 ARM instruction shim to jump to %s\n", _target->name());
+ OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 4
+ OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip
+ OSWriteLittleInt32(&buffer[ 8], 0, 0xe12fff1c); // bx ip
+ OSWriteLittleInt32(&buffer[12], 0, 0); // .long target-this
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup4)[1]; }
+
+private:
+ const char* _name;
+ const ld::Atom* _target;
+ ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+ ld::Fixup _fixup4;
+};
+
+
+class NoPICARMtoThumbShimAtom : public ld::Atom {
+public:
+ NoPICARMtoThumbShimAtom(const ld::Atom* target, const ld::Section& inSect)
+ : ld::Atom(inSect, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
+ ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)),
+ _name(NULL),
+ _target(target),
+ _fixup1(8, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, target)
+ { asprintf((char**)&_name, "%s$shim", target->name()); }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 12; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ // Use ARM instructions that can jump to thumb.
+ if (_s_log) fprintf(stderr, "3 ARM instruction shim to jump to %s\n", _target->name());
+ OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); // ldr ip, pc + 4
+ OSWriteLittleInt32(&buffer[ 4], 0, 0xe12fff1c); // bx ip
+ OSWriteLittleInt32(&buffer[ 8], 0, 0); // .long target
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup1)[1]; }
+
+private:
+ const char* _name;
+ const ld::Atom* _target;
+ ld::Fixup _fixup1;
+};
+
+
+
+
+
+
+static void extractTarget(ld::Fixup::iterator fixup, ld::Internal& state, const ld::Atom** target)
+{
+ switch ( fixup->binding ) {
+ case ld::Fixup::bindingNone:
+ throw "unexpected bindingNone";
+ case ld::Fixup::bindingByNameUnbound:
+ throw "unexpected bindingByNameUnbound";
+ case ld::Fixup::bindingByContentBound:
+ case ld::Fixup::bindingDirectlyBound:
+ *target = fixup->u.target;
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ *target = state.indirectBindingTable[fixup->u.bindingIndex];
+ break;
+ }
+}
+
+
+
+//
+// The tail-call optimzation may result in a function ending in a jump (b)
+// to another functions. At compile time the compiler does not know
+// if the target of the jump will be in the same mode (arm vs thumb).
+// The arm/thumb instruction set has a way to change modes in a bl(x)
+// insruction, but no instruction to change mode in a jump (b) instruction.
+// In those rare cases, the linker needs to insert a shim of code to
+// make the mode switch.
+//
+void doPass(const Options& opts, ld::Internal& state)
+{
+ // only make branch shims in final linked images
+ if ( opts.outputKind() == Options::kObjectFile )
+ return;
+
+ // only ARM need branch islands
+ if ( opts.architecture() != CPU_TYPE_ARM )
+ return;
+
+ const bool makingKextBundle = (opts.outputKind() == Options::kKextBundle);
+
+ // scan all sections
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ std::map<const Atom*, const Atom*> atomToThumbMap;
+ std::map<const Atom*, const Atom*> thumbToAtomMap;
+ std::vector<const Atom*> shims;
+ // scan section for branch instructions that need to switch mode
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ const ld::Atom* target = NULL;
+ bool targetIsProxy;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ switch ( fit->kind ) {
+ case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+ extractTarget(fit, state, &target);
+ targetIsProxy = (target->definition() == ld::Atom::definitionProxy);
+ if ( ! target->isThumb() ) {
+ const uint8_t* fixUpLocation = atom->rawContentPointer();
+ // <rdar://problem/9544194> don't try to scan atom for branches if atom unwilling to supply raw content
+ if ( fixUpLocation == NULL )
+ break;
+ fixUpLocation += fit->offsetInAtom;
+ uint32_t instruction = *((uint32_t*)fixUpLocation);
+ bool is_b = ((instruction & 0xD000F800) == 0x9000F000);
+ // need shim for branch from thumb to arm, or for call to function outside kext
+ if ( is_b || (targetIsProxy && makingKextBundle) ) {
+ if ( _s_log ) fprintf(stderr, "need to add thumb->arm instr=0x%08X shim to %s for %s\n", instruction, target->name(), atom->name());
+ const Atom* shim = NULL;
+ std::map<const Atom*, const Atom*>::iterator pos = thumbToAtomMap.find(target);
+ if ( pos == thumbToAtomMap.end() ) {
+ if ( opts.archSupportsThumb2() ) {
+ // <rdar://problem/9116044> make long-branch style shims for arm kexts
+ if ( makingKextBundle && opts.allowTextRelocs() )
+ shim = new NoPICThumb2ToArmShimAtom(target, *sect);
+ else
+ shim = new Thumb2ToArmShimAtom(target, *sect);
+ }
+ else {
+ shim = new Thumb1ToArmShimAtom(target, *sect);
+ }
+ shims.push_back(shim);
+ thumbToAtomMap[target] = shim;
+ }
+ else {
+ shim = pos->second;
+ }
+ fit->binding = ld::Fixup::bindingDirectlyBound;
+ fit->u.target = shim;
+ }
+ }
+ break;
+ case ld::Fixup::kindStoreTargetAddressARMBranch24:
+ extractTarget(fit, state, &target);
+ targetIsProxy = (target->definition() == ld::Atom::definitionProxy);
+ if ( target->isThumb() || (targetIsProxy && makingKextBundle) ) {
+ const uint8_t* fixUpLocation = atom->rawContentPointer();
+ // <rdar://problem/9544194> don't try to scan atom for branches if atom unwilling to supply raw content
+ if ( fixUpLocation == NULL )
+ break;
+ fixUpLocation += fit->offsetInAtom;
+ uint32_t instruction = *((uint32_t*)fixUpLocation);
+ bool is_b = ((instruction & 0x0F000000) == 0x0A000000) && ((instruction & 0xF0000000) != 0xF0000000);
+ // need shim for branch from arm to thumb, or for call to function outside kext
+ if ( is_b || (targetIsProxy && makingKextBundle) ) {
+ if ( _s_log ) fprintf(stderr, "need to add arm->thumb instr=0x%08X shim to %s for %s\n", instruction, target->name(), atom->name());
+ const Atom* shim = NULL;
+ std::map<const Atom*, const Atom*>::iterator pos = atomToThumbMap.find(target);
+ if ( pos == atomToThumbMap.end() ) {
+ // <rdar://problem/9116044> make long-branch style shims for arm kexts
+ if ( makingKextBundle && opts.allowTextRelocs() )
+ shim = new NoPICARMtoThumbShimAtom(target, *sect);
+ else
+ shim = new ARMtoThumbShimAtom(target, *sect);
+ shims.push_back(shim);
+ atomToThumbMap[target] = shim;
+ }
+ else {
+ shim = pos->second;
+ }
+ fit->binding = ld::Fixup::bindingDirectlyBound;
+ fit->u.target = shim;
+ }
+ }
+ break;
+
+ //case ld::Fixup::kindStoreARMBranch24:
+ //case ld::Fixup::kindStoreThumbBranch22:
+ // Note: these fixups will only be seen if the the b/bl is to a symbol plus addend
+ // for now we don't handle making shims. If a shim is needed there will
+ // be an error later.
+ // break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // append all new shims to end of __text
+ sect->atoms.insert(sect->atoms.end(), shims.begin(), shims.end());
+ }
+}
+
+
+} // namespace branch_shim
+} // namespace passes
+} // namespace ld
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __BRANCH_SHIM_H__
+#define __BRANCH_SHIM_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace branch_shim {
+
+// called by linker to branch shims to support branch (but not bl) that switches mode
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace branch_shim
+} // namespace passes
+} // namespace ld
+
+#endif // __BRANCH_SHIM_H__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <mach/machine.h>
+#include <mach-o/compact_unwind_encoding.h>
+
+#include <vector>
+#include <map>
+
+#include "ld.hpp"
+#include "compact_unwind.h"
+#include "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace compact_unwind {
+
+
+struct UnwindEntry {
+ UnwindEntry(const ld::Atom* f, uint64_t a, uint32_t o, const ld::Atom* d,
+ const ld::Atom* l, const ld::Atom* p, uint32_t en)
+ : func(f), fde(d), lsda(l), personalityPointer(p), funcTentAddress(a),
+ functionOffset(o), encoding(en) { }
+ const ld::Atom* func;
+ const ld::Atom* fde;
+ const ld::Atom* lsda;
+ const ld::Atom* personalityPointer;
+ uint64_t funcTentAddress;
+ uint32_t functionOffset;
+ compact_unwind_encoding_t encoding;
+};
+
+struct LSDAEntry {
+ const ld::Atom* func;
+ const ld::Atom* lsda;
+};
+
+
+template <typename A>
+class UnwindInfoAtom : public ld::Atom {
+public:
+ UnwindInfoAtom(const std::vector<UnwindEntry>& entries,uint64_t ehFrameSize);
+ ~UnwindInfoAtom();
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "compact unwind info"; }
+ virtual uint64_t size() const { return _headerSize+_pagesSize; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixups[0]; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return (ld::Fixup*)&_fixups[_fixups.size()]; }
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ typedef macho_unwind_info_compressed_second_level_page_header<P> CSLP;
+
+ bool encodingMeansUseDwarf(compact_unwind_encoding_t enc);
+ void compressDuplicates(const std::vector<UnwindEntry>& entries,
+ std::vector<UnwindEntry>& uniqueEntries);
+ void makePersonalityIndexes(std::vector<UnwindEntry>& entries,
+ std::map<const ld::Atom*, uint32_t>& personalityIndexMap);
+ void findCommonEncoding(const std::vector<UnwindEntry>& entries,
+ std::map<compact_unwind_encoding_t, unsigned int>& commonEncodings);
+ void makeLsdaIndex(const std::vector<UnwindEntry>& entries, std::vector<LSDAEntry>& lsdaIndex,
+ std::map<const ld::Atom*, uint32_t>& lsdaIndexOffsetMap);
+ unsigned int makeCompressedSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos,
+ const std::map<compact_unwind_encoding_t,unsigned int> commonEncodings,
+ uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd);
+ unsigned int makeRegularSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos, uint32_t pageSize,
+ unsigned int endIndex, uint8_t*& pageEnd);
+ void addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc);
+ void addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde);
+ void addRegularAddressFixup(uint32_t offset, const ld::Atom* func);
+ void addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde);
+ void addImageOffsetFixup(uint32_t offset, const ld::Atom* targ);
+ void addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend);
+
+ uint8_t* _pagesForDelete;
+ uint8_t* _pages;
+ uint64_t _pagesSize;
+ uint8_t* _header;
+ uint64_t _headerSize;
+ std::vector<ld::Fixup> _fixups;
+
+ static bool _s_log;
+ static ld::Section _s_section;
+};
+
+template <typename A>
+bool UnwindInfoAtom<A>::_s_log = false;
+
+template <typename A>
+ld::Section UnwindInfoAtom<A>::_s_section("__TEXT", "__unwind_info", ld::Section::typeUnwindInfo);
+
+
+template <typename A>
+UnwindInfoAtom<A>::UnwindInfoAtom(const std::vector<UnwindEntry>& entries, uint64_t ehFrameSize)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
+ _pagesForDelete(NULL), _pages(NULL), _pagesSize(0), _header(NULL), _headerSize(0)
+{
+ // build new compressed list by removing entries where next function has same encoding
+ std::vector<UnwindEntry> uniqueEntries;
+ compressDuplicates(entries, uniqueEntries);
+
+ // reserve room so _fixups vector is not reallocated a bunch of times
+ _fixups.reserve(uniqueEntries.size()*3);
+
+ // build personality index, update encodings with personality index
+ std::map<const ld::Atom*, uint32_t> personalityIndexMap;
+ makePersonalityIndexes(uniqueEntries, personalityIndexMap);
+ if ( personalityIndexMap.size() > 3 ) {
+ warning("too many personality routines for compact unwind to encode");
+ return;
+ }
+
+ // put the most common encodings into the common table, but at most 127 of them
+ std::map<compact_unwind_encoding_t, unsigned int> commonEncodings;
+ findCommonEncoding(uniqueEntries, commonEncodings);
+
+ // build lsda index
+ std::map<const ld::Atom*, uint32_t> lsdaIndexOffsetMap;
+ std::vector<LSDAEntry> lsdaIndex;
+ makeLsdaIndex(uniqueEntries, lsdaIndex, lsdaIndexOffsetMap);
+
+
+ // calculate worst case size for all unwind info pages when allocating buffer
+ const unsigned int entriesPerRegularPage = (4096-sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
+ assert(uniqueEntries.size() > 0);
+ const unsigned int pageCount = ((uniqueEntries.size() - 1)/entriesPerRegularPage) + 1;
+ _pagesForDelete = (uint8_t*)calloc(pageCount,4096);
+ if ( _pagesForDelete == NULL ) {
+ warning("could not allocate space for compact unwind info");
+ return;
+ }
+
+ // make last second level page smaller so that all other second level pages can be page aligned
+ uint32_t maxLastPageSize = 4096 - (ehFrameSize % 4096);
+ uint32_t tailPad = 0;
+ if ( maxLastPageSize < 128 ) {
+ tailPad = maxLastPageSize;
+ maxLastPageSize = 4096;
+ }
+
+ // fill in pages in reverse order
+ const ld::Atom* secondLevelFirstFuncs[pageCount*3];
+ uint8_t* secondLevelPagesStarts[pageCount*3];
+ unsigned int endIndex = uniqueEntries.size();
+ unsigned int secondLevelPageCount = 0;
+ uint8_t* pageEnd = &_pagesForDelete[pageCount*4096];
+ uint32_t pageSize = maxLastPageSize;
+ while ( endIndex > 0 ) {
+ endIndex = makeCompressedSecondLevelPage(uniqueEntries, commonEncodings, pageSize, endIndex, pageEnd);
+ secondLevelPagesStarts[secondLevelPageCount] = pageEnd;
+ secondLevelFirstFuncs[secondLevelPageCount] = uniqueEntries[endIndex].func;
+ ++secondLevelPageCount;
+ pageSize = 4096; // last page can be odd size, make rest up to 4096 bytes in size
+ }
+ _pages = pageEnd;
+ _pagesSize = &_pagesForDelete[pageCount*4096] - pageEnd;
+
+
+ // calculate section layout
+ const uint32_t commonEncodingsArraySectionOffset = sizeof(macho_unwind_info_section_header<P>);
+ const uint32_t commonEncodingsArrayCount = commonEncodings.size();
+ const uint32_t commonEncodingsArraySize = commonEncodingsArrayCount * sizeof(compact_unwind_encoding_t);
+ const uint32_t personalityArraySectionOffset = commonEncodingsArraySectionOffset + commonEncodingsArraySize;
+ const uint32_t personalityArrayCount = personalityIndexMap.size();
+ const uint32_t personalityArraySize = personalityArrayCount * sizeof(uint32_t);
+ const uint32_t indexSectionOffset = personalityArraySectionOffset + personalityArraySize;
+ const uint32_t indexCount = secondLevelPageCount+1;
+ const uint32_t indexSize = indexCount * sizeof(macho_unwind_info_section_header_index_entry<P>);
+ const uint32_t lsdaIndexArraySectionOffset = indexSectionOffset + indexSize;
+ const uint32_t lsdaIndexArrayCount = lsdaIndex.size();
+ const uint32_t lsdaIndexArraySize = lsdaIndexArrayCount * sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
+ const uint32_t headerEndSectionOffset = lsdaIndexArraySectionOffset + lsdaIndexArraySize;
+
+ // now that we know the size of the header, slide all existing fixups on the pages
+ const int32_t fixupSlide = headerEndSectionOffset + (_pagesForDelete - _pages);
+ for(std::vector<ld::Fixup>::iterator it = _fixups.begin(); it != _fixups.end(); ++it) {
+ it->offsetInAtom += fixupSlide;
+ }
+
+ // allocate and fill in section header
+ _headerSize = headerEndSectionOffset;
+ _header = new uint8_t[_headerSize];
+ bzero(_header, _headerSize);
+ macho_unwind_info_section_header<P>* sectionHeader = (macho_unwind_info_section_header<P>*)_header;
+ sectionHeader->set_version(UNWIND_SECTION_VERSION);
+ sectionHeader->set_commonEncodingsArraySectionOffset(commonEncodingsArraySectionOffset);
+ sectionHeader->set_commonEncodingsArrayCount(commonEncodingsArrayCount);
+ sectionHeader->set_personalityArraySectionOffset(personalityArraySectionOffset);
+ sectionHeader->set_personalityArrayCount(personalityArrayCount);
+ sectionHeader->set_indexSectionOffset(indexSectionOffset);
+ sectionHeader->set_indexCount(indexCount);
+
+ // copy common encodings
+ uint32_t* commonEncodingsTable = (uint32_t*)&_header[commonEncodingsArraySectionOffset];
+ for (std::map<uint32_t, unsigned int>::iterator it=commonEncodings.begin(); it != commonEncodings.end(); ++it)
+ E::set32(commonEncodingsTable[it->second], it->first);
+
+ // make references for personality entries
+ uint32_t* personalityArray = (uint32_t*)&_header[sectionHeader->personalityArraySectionOffset()];
+ for (std::map<const ld::Atom*, unsigned int>::iterator it=personalityIndexMap.begin(); it != personalityIndexMap.end(); ++it) {
+ uint32_t offset = (uint8_t*)&personalityArray[it->second-1] - _header;
+ this->addImageOffsetFixup(offset, it->first);
+ }
+
+ // build first level index and references
+ macho_unwind_info_section_header_index_entry<P>* indexTable = (macho_unwind_info_section_header_index_entry<P>*)&_header[indexSectionOffset];
+ uint32_t refOffset;
+ for (unsigned int i=0; i < secondLevelPageCount; ++i) {
+ unsigned int reverseIndex = secondLevelPageCount - 1 - i;
+ indexTable[i].set_functionOffset(0);
+ indexTable[i].set_secondLevelPagesSectionOffset(secondLevelPagesStarts[reverseIndex]-_pages+headerEndSectionOffset);
+ indexTable[i].set_lsdaIndexArraySectionOffset(lsdaIndexOffsetMap[secondLevelFirstFuncs[reverseIndex]]+lsdaIndexArraySectionOffset);
+ refOffset = (uint8_t*)&indexTable[i] - _header;
+ this->addImageOffsetFixup(refOffset, secondLevelFirstFuncs[reverseIndex]);
+ }
+ indexTable[secondLevelPageCount].set_functionOffset(0);
+ indexTable[secondLevelPageCount].set_secondLevelPagesSectionOffset(0);
+ indexTable[secondLevelPageCount].set_lsdaIndexArraySectionOffset(lsdaIndexArraySectionOffset+lsdaIndexArraySize);
+ refOffset = (uint8_t*)&indexTable[secondLevelPageCount] - _header;
+ this->addImageOffsetFixupPlusAddend(refOffset, entries.back().func, entries.back().func->size()+1);
+
+ // build lsda references
+ uint32_t lsdaEntrySectionOffset = lsdaIndexArraySectionOffset;
+ for (std::vector<LSDAEntry>::iterator it = lsdaIndex.begin(); it != lsdaIndex.end(); ++it) {
+ this->addImageOffsetFixup(lsdaEntrySectionOffset, it->func);
+ this->addImageOffsetFixup(lsdaEntrySectionOffset+4, it->lsda);
+ lsdaEntrySectionOffset += sizeof(unwind_info_section_header_lsda_index_entry);
+ }
+
+}
+
+template <typename A>
+UnwindInfoAtom<A>::~UnwindInfoAtom()
+{
+ free(_pagesForDelete);
+ free(_header);
+}
+
+template <typename A>
+void UnwindInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ // content is in two parts
+ memcpy(buffer, _header, _headerSize);
+ memcpy(&buffer[_headerSize], _pages, _pagesSize);
+}
+
+
+template <>
+bool UnwindInfoAtom<x86>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
+{
+ return ((enc & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF);
+}
+
+template <>
+bool UnwindInfoAtom<x86_64>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
+{
+ return ((enc & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF);
+}
+
+template <typename A>
+void UnwindInfoAtom<A>::compressDuplicates(const std::vector<UnwindEntry>& entries, std::vector<UnwindEntry>& uniqueEntries)
+{
+ // build new list removing entries where next function has same encoding
+ uniqueEntries.reserve(entries.size());
+ UnwindEntry last(NULL, 0, 0, NULL, NULL, NULL, 0xFFFFFFFF);
+ for(std::vector<UnwindEntry>::const_iterator it=entries.begin(); it != entries.end(); ++it) {
+ const UnwindEntry& next = *it;
+ bool newNeedsDwarf = encodingMeansUseDwarf(next.encoding);
+ // remove entries which have same encoding and personalityPointer as last one
+ if ( newNeedsDwarf || (next.encoding != last.encoding) || (next.personalityPointer != last.personalityPointer)
+ || (next.lsda != NULL) || (last.lsda != NULL) ) {
+ uniqueEntries.push_back(next);
+ }
+ last = next;
+ }
+ if (_s_log) fprintf(stderr, "compressDuplicates() entries.size()=%lu, uniqueEntries.size()=%lu\n",
+ entries.size(), uniqueEntries.size());
+}
+
+template <typename A>
+void UnwindInfoAtom<A>::makePersonalityIndexes(std::vector<UnwindEntry>& entries, std::map<const ld::Atom*, uint32_t>& personalityIndexMap)
+{
+ for(std::vector<UnwindEntry>::iterator it=entries.begin(); it != entries.end(); ++it) {
+ if ( it->personalityPointer != NULL ) {
+ std::map<const ld::Atom*, uint32_t>::iterator pos = personalityIndexMap.find(it->personalityPointer);
+ if ( pos == personalityIndexMap.end() ) {
+ const uint32_t nextIndex = personalityIndexMap.size() + 1;
+ personalityIndexMap[it->personalityPointer] = nextIndex;
+ }
+ uint32_t personalityIndex = personalityIndexMap[it->personalityPointer];
+ it->encoding |= (personalityIndex << (__builtin_ctz(UNWIND_PERSONALITY_MASK)) );
+ }
+ }
+ if (_s_log) fprintf(stderr, "makePersonalityIndexes() %lu personality routines used\n", personalityIndexMap.size());
+}
+
+
+template <typename A>
+void UnwindInfoAtom<A>::findCommonEncoding(const std::vector<UnwindEntry>& entries,
+ std::map<compact_unwind_encoding_t, unsigned int>& commonEncodings)
+{
+ // scan infos to get frequency counts for each encoding
+ std::map<compact_unwind_encoding_t, unsigned int> encodingsUsed;
+ unsigned int mostCommonEncodingUsageCount = 0;
+ for(std::vector<UnwindEntry>::const_iterator it=entries.begin(); it != entries.end(); ++it) {
+ // never put dwarf into common table
+ if ( encodingMeansUseDwarf(it->encoding) )
+ continue;
+ std::map<compact_unwind_encoding_t, unsigned int>::iterator pos = encodingsUsed.find(it->encoding);
+ if ( pos == encodingsUsed.end() ) {
+ encodingsUsed[it->encoding] = 1;
+ }
+ else {
+ encodingsUsed[it->encoding] += 1;
+ if ( mostCommonEncodingUsageCount < encodingsUsed[it->encoding] )
+ mostCommonEncodingUsageCount = encodingsUsed[it->encoding];
+ }
+ }
+ // put the most common encodings into the common table, but at most 127 of them
+ for(unsigned int usages=mostCommonEncodingUsageCount; usages > 1; --usages) {
+ for (std::map<compact_unwind_encoding_t, unsigned int>::iterator euit=encodingsUsed.begin(); euit != encodingsUsed.end(); ++euit) {
+ if ( euit->second == usages ) {
+ unsigned int sz = commonEncodings.size();
+ if ( sz < 127 ) {
+ commonEncodings[euit->first] = sz;
+ }
+ }
+ }
+ }
+ if (_s_log) fprintf(stderr, "findCommonEncoding() %lu common encodings found\n", commonEncodings.size());
+}
+
+
+template <typename A>
+void UnwindInfoAtom<A>::makeLsdaIndex(const std::vector<UnwindEntry>& entries, std::vector<LSDAEntry>& lsdaIndex, std::map<const ld::Atom*, uint32_t>& lsdaIndexOffsetMap)
+{
+ for(std::vector<UnwindEntry>::const_iterator it=entries.begin(); it != entries.end(); ++it) {
+ lsdaIndexOffsetMap[it->func] = lsdaIndex.size() * sizeof(unwind_info_section_header_lsda_index_entry);
+ if ( it->lsda != NULL ) {
+ LSDAEntry entry;
+ entry.func = it->func;
+ entry.lsda = it->lsda;
+ lsdaIndex.push_back(entry);
+ }
+ }
+ if (_s_log) fprintf(stderr, "makeLsdaIndex() %lu LSDAs found\n", lsdaIndex.size());
+}
+
+
+template <>
+void UnwindInfoAtom<x86>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
+{
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
+template <>
+void UnwindInfoAtom<x86_64>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
+{
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
+template <>
+void UnwindInfoAtom<x86>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
+{
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
+template <>
+void UnwindInfoAtom<x86_64>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
+{
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
+
+template <>
+void UnwindInfoAtom<x86>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
+{
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
+}
+
+template <>
+void UnwindInfoAtom<x86_64>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
+{
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
+}
+
+template <>
+void UnwindInfoAtom<x86>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
+{
+ _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
+ _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
+template <>
+void UnwindInfoAtom<x86_64>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
+{
+ _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
+ _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
+template <>
+void UnwindInfoAtom<x86>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
+{
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
+}
+
+template <>
+void UnwindInfoAtom<x86_64>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
+{
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
+}
+
+template <>
+void UnwindInfoAtom<x86>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
+{
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
+}
+
+template <>
+void UnwindInfoAtom<x86_64>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
+{
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
+}
+
+
+
+
+
+template <typename A>
+unsigned int UnwindInfoAtom<A>::makeRegularSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos, uint32_t pageSize,
+ unsigned int endIndex, uint8_t*& pageEnd)
+{
+ const unsigned int maxEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
+ const unsigned int entriesToAdd = ((endIndex > maxEntriesPerPage) ? maxEntriesPerPage : endIndex);
+ uint8_t* pageStart = pageEnd
+ - entriesToAdd*sizeof(unwind_info_regular_second_level_entry)
+ - sizeof(unwind_info_regular_second_level_page_header);
+ macho_unwind_info_regular_second_level_page_header<P>* page = (macho_unwind_info_regular_second_level_page_header<P>*)pageStart;
+ page->set_kind(UNWIND_SECOND_LEVEL_REGULAR);
+ page->set_entryPageOffset(sizeof(macho_unwind_info_regular_second_level_page_header<P>));
+ page->set_entryCount(entriesToAdd);
+ macho_unwind_info_regular_second_level_entry<P>* entryTable = (macho_unwind_info_regular_second_level_entry<P>*)(pageStart + page->entryPageOffset());
+ for (unsigned int i=0; i < entriesToAdd; ++i) {
+ const UnwindEntry& info = uniqueInfos[endIndex-entriesToAdd+i];
+ entryTable[i].set_functionOffset(0);
+ entryTable[i].set_encoding(info.encoding);
+ // add fixup for address part of entry
+ uint32_t offset = (uint8_t*)(&entryTable[i]) - _pagesForDelete;
+ this->addRegularAddressFixup(offset, info.func);
+ if ( encodingMeansUseDwarf(info.encoding) ) {
+ // add fixup for dwarf offset part of page specific encoding
+ uint32_t encOffset = (uint8_t*)(&entryTable[i]) - _pagesForDelete;
+ this->addRegularFDEOffsetFixup(encOffset, info.fde);
+ }
+ }
+ if (_s_log) fprintf(stderr, "regular page with %u entries\n", entriesToAdd);
+ pageEnd = pageStart;
+ return endIndex - entriesToAdd;
+}
+
+
+template <typename A>
+unsigned int UnwindInfoAtom<A>::makeCompressedSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos,
+ const std::map<compact_unwind_encoding_t,unsigned int> commonEncodings,
+ uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd)
+{
+ if (_s_log) fprintf(stderr, "makeCompressedSecondLevelPage(pageSize=%u, endIndex=%u)\n", pageSize, endIndex);
+ // first pass calculates how many compressed entries we could fit in this sized page
+ // keep adding entries to page until:
+ // 1) encoding table plus entry table plus header exceed page size
+ // 2) the file offset delta from the first to last function > 24 bits
+ // 3) custom encoding index reachs 255
+ // 4) run out of uniqueInfos to encode
+ std::map<compact_unwind_encoding_t, unsigned int> pageSpecificEncodings;
+ uint32_t space4 = (pageSize - sizeof(unwind_info_compressed_second_level_page_header))/sizeof(uint32_t);
+ std::vector<uint8_t> encodingIndexes;
+ int index = endIndex-1;
+ int entryCount = 0;
+ uint64_t lastEntryAddress = uniqueInfos[index].funcTentAddress;
+ bool canDo = true;
+ while ( canDo && (index >= 0) ) {
+ const UnwindEntry& info = uniqueInfos[index--];
+ // compute encoding index
+ unsigned int encodingIndex;
+ std::map<compact_unwind_encoding_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
+ if ( pos != commonEncodings.end() ) {
+ encodingIndex = pos->second;
+ }
+ else {
+ // no commmon entry, so add one on this page
+ uint32_t encoding = info.encoding;
+ if ( encodingMeansUseDwarf(encoding) ) {
+ // make unique pseudo encoding so this dwarf will gets is own encoding entry slot
+ encoding += (index+1);
+ }
+ std::map<compact_unwind_encoding_t, unsigned int>::iterator ppos = pageSpecificEncodings.find(encoding);
+ if ( ppos != pageSpecificEncodings.end() ) {
+ encodingIndex = pos->second;
+ }
+ else {
+ encodingIndex = commonEncodings.size() + pageSpecificEncodings.size();
+ if ( encodingIndex <= 255 ) {
+ pageSpecificEncodings[encoding] = encodingIndex;
+ }
+ else {
+ canDo = false; // case 3)
+ if (_s_log) fprintf(stderr, "end of compressed page with %u entries, %lu custom encodings because too many custom encodings\n",
+ entryCount, pageSpecificEncodings.size());
+ }
+ }
+ }
+ if ( canDo )
+ encodingIndexes.push_back(encodingIndex);
+ // compute function offset
+ uint32_t funcOffsetWithInPage = lastEntryAddress - info.funcTentAddress;
+ if ( funcOffsetWithInPage > 0x00FFFF00 ) {
+ // don't use 0x00FFFFFF because addresses may vary after atoms are laid out again
+ canDo = false; // case 2)
+ if (_s_log) fprintf(stderr, "can't use compressed page with %u entries because function offset too big\n", entryCount);
+ }
+ else {
+ ++entryCount;
+ }
+ // check room for entry
+ if ( (pageSpecificEncodings.size()+entryCount) >= space4 ) {
+ canDo = false; // case 1)
+ --entryCount;
+ if (_s_log) fprintf(stderr, "end of compressed page with %u entries because full\n", entryCount);
+ }
+ //if (_s_log) fprintf(stderr, "space4=%d, pageSpecificEncodings.size()=%ld, entryCount=%d\n", space4, pageSpecificEncodings.size(), entryCount);
+ }
+
+ // check for cases where it would be better to use a regular (non-compressed) page
+ const unsigned int compressPageUsed = sizeof(unwind_info_compressed_second_level_page_header)
+ + pageSpecificEncodings.size()*sizeof(uint32_t)
+ + entryCount*sizeof(uint32_t);
+ if ( (compressPageUsed < (pageSize-4) && (index >= 0) ) ) {
+ const int regularEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
+ if ( entryCount < regularEntriesPerPage ) {
+ return makeRegularSecondLevelPage(uniqueInfos, pageSize, endIndex, pageEnd);
+ }
+ }
+
+ // check if we need any padding because adding another entry would take 8 bytes but only have room for 4
+ uint32_t pad = 0;
+ if ( compressPageUsed == (pageSize-4) )
+ pad = 4;
+
+ // second pass fills in page
+ uint8_t* pageStart = pageEnd - compressPageUsed - pad;
+ CSLP* page = (CSLP*)pageStart;
+ page->set_kind(UNWIND_SECOND_LEVEL_COMPRESSED);
+ page->set_entryPageOffset(sizeof(CSLP));
+ page->set_entryCount(entryCount);
+ page->set_encodingsPageOffset(page->entryPageOffset()+entryCount*sizeof(uint32_t));
+ page->set_encodingsCount(pageSpecificEncodings.size());
+ uint32_t* const encodingsArray = (uint32_t*)&pageStart[page->encodingsPageOffset()];
+ // fill in entry table
+ uint32_t* const entiresArray = (uint32_t*)&pageStart[page->entryPageOffset()];
+ const ld::Atom* firstFunc = uniqueInfos[endIndex-entryCount].func;
+ for(unsigned int i=endIndex-entryCount; i < endIndex; ++i) {
+ const UnwindEntry& info = uniqueInfos[i];
+ uint8_t encodingIndex;
+ if ( encodingMeansUseDwarf(info.encoding) ) {
+ // dwarf entries are always in page specific encodings
+ encodingIndex = pageSpecificEncodings[info.encoding+i];
+ }
+ else {
+ std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
+ if ( pos != commonEncodings.end() )
+ encodingIndex = pos->second;
+ else
+ encodingIndex = pageSpecificEncodings[info.encoding];
+ }
+ uint32_t entryIndex = i - endIndex + entryCount;
+ E::set32(entiresArray[entryIndex], encodingIndex << 24);
+ // add fixup for address part of entry
+ uint32_t offset = (uint8_t*)(&entiresArray[entryIndex]) - _pagesForDelete;
+ this->addCompressedAddressOffsetFixup(offset, info.func, firstFunc);
+ if ( encodingMeansUseDwarf(info.encoding) ) {
+ // add fixup for dwarf offset part of page specific encoding
+ uint32_t encOffset = (uint8_t*)(&encodingsArray[encodingIndex-commonEncodings.size()]) - _pagesForDelete;
+ this->addCompressedEncodingFixup(encOffset, info.fde);
+ }
+ }
+ // fill in encodings table
+ for(std::map<uint32_t, unsigned int>::const_iterator it = pageSpecificEncodings.begin(); it != pageSpecificEncodings.end(); ++it) {
+ E::set32(encodingsArray[it->second-commonEncodings.size()], it->first);
+ }
+
+ if (_s_log) fprintf(stderr, "compressed page with %u entries, %lu custom encodings\n", entryCount, pageSpecificEncodings.size());
+
+ // update pageEnd;
+ pageEnd = pageStart;
+ return endIndex-entryCount; // endIndex for next page
+}
+
+
+
+
+
+
+static uint64_t calculateEHFrameSize(const ld::Internal& state)
+{
+ uint64_t size = 0;
+ for (std::vector<ld::Internal::FinalSection*>::const_iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() == ld::Section::typeCFI ) {
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ size += (*ait)->size();
+ }
+ }
+ }
+ return size;
+}
+
+static void getAllUnwindInfos(const ld::Internal& state, std::vector<UnwindEntry>& entries)
+{
+ uint64_t address = 0;
+ for (std::vector<ld::Internal::FinalSection*>::const_iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ // adjust address for atom alignment
+ uint64_t alignment = 1 << atom->alignment().powerOf2;
+ uint64_t currentModulus = (address % alignment);
+ uint64_t requiredModulus = atom->alignment().modulus;
+ if ( currentModulus != requiredModulus ) {
+ if ( requiredModulus > currentModulus )
+ address += requiredModulus-currentModulus;
+ else
+ address += requiredModulus+alignment-currentModulus;
+ }
+
+ if ( atom->beginUnwind() == atom->endUnwind() ) {
+ // be sure to mark that we have no unwind info for stuff in the TEXT segment without unwind info
+ if ( atom->section().type() == ld::Section::typeCode ) {
+ entries.push_back(UnwindEntry(atom, address, 0, NULL, NULL, NULL, 0));
+ }
+ }
+ else {
+ // atom has unwind info(s), add entry for each
+ const ld::Atom* fde = NULL;
+ const ld::Atom* lsda = NULL;
+ const ld::Atom* personalityPointer = NULL;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ switch ( fit->kind ) {
+ case ld::Fixup::kindNoneGroupSubordinateFDE:
+ assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+ fde = fit->u.target;
+ break;
+ case ld::Fixup::kindNoneGroupSubordinateLSDA:
+ assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+ lsda = fit->u.target;
+ break;
+ case ld::Fixup::kindNoneGroupSubordinatePersonality:
+ assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+ personalityPointer = fit->u.target;
+ assert(personalityPointer->section().type() == ld::Section::typeNonLazyPointer);
+ break;
+ default:
+ break;
+ }
+ }
+ if ( fde != NULL ) {
+ // find CIE for this FDE
+ const ld::Atom* cie = NULL;
+ for (ld::Fixup::iterator fit = fde->fixupsBegin(), end=fde->fixupsEnd(); fit != end; ++fit) {
+ if ( fit->kind != ld::Fixup::kindSubtractTargetAddress )
+ continue;
+ if ( fit->binding != ld::Fixup::bindingDirectlyBound )
+ continue;
+ cie = fit->u.target;
+ // CIE is only direct subtracted target in FDE
+ assert(cie->section().type() == ld::Section::typeCFI);
+ break;
+ }
+ if ( cie != NULL ) {
+ // if CIE can have just one fixup - to the personality pointer
+ for (ld::Fixup::iterator fit = cie->fixupsBegin(), end=cie->fixupsEnd(); fit != end; ++fit) {
+ if ( fit->kind == ld::Fixup::kindSetTargetAddress ) {
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingsIndirectlyBound:
+ personalityPointer = state.indirectBindingTable[fit->u.bindingIndex];
+ assert(personalityPointer->section().type() == ld::Section::typeNonLazyPointer);
+ break;
+ case ld::Fixup::bindingDirectlyBound:
+ personalityPointer = fit->u.target;
+ assert(personalityPointer->section().type() == ld::Section::typeNonLazyPointer);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+ for ( ld::Atom::UnwindInfo::iterator uit = atom->beginUnwind(); uit != atom->endUnwind(); ++uit ) {
+ entries.push_back(UnwindEntry(atom, address, uit->startOffset, fde, lsda, personalityPointer, uit->unwindInfo));
+ }
+ }
+ address += atom->size();
+ }
+ }
+}
+
+
+static void makeFinalLinkedImageCompactUnwindSection(const Options& opts, ld::Internal& state)
+{
+ // walk every atom and gets its unwind info
+ std::vector<UnwindEntry> entries;
+ entries.reserve(64);
+ getAllUnwindInfos(state, entries);
+
+ // don't generate an __unwind_info section if there is no code in this linkage unit
+ if ( entries.size() == 0 )
+ return;
+
+ // calculate size of __eh_frame section, so __unwind_info can go before it and page align
+ uint64_t ehFrameSize = calculateEHFrameSize(state);
+
+ // create atom that contains the whole compact unwind table
+ switch ( opts.architecture() ) {
+#if SUPPORT_ARCH_x86_64
+ case CPU_TYPE_X86_64:
+ state.addAtom(*new UnwindInfoAtom<x86_64>(entries, ehFrameSize));
+ break;
+#endif
+#if SUPPORT_ARCH_i386
+ case CPU_TYPE_I386:
+ state.addAtom(*new UnwindInfoAtom<x86>(entries, ehFrameSize));
+ break;
+#endif
+ default:
+ assert(0 && "no compact unwind for arch");
+ }
+}
+
+
+
+template <typename A>
+class CompactUnwindAtom : public ld::Atom {
+public:
+ CompactUnwindAtom(ld::Internal& state,const ld::Atom* funcAtom,
+ uint32_t startOffset, uint32_t len, uint32_t cui);
+ ~CompactUnwindAtom() {}
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "compact unwind info"; }
+ virtual uint64_t size() const { return sizeof(macho_compact_unwind_entry<P>); }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const;
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixups[0]; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return (ld::Fixup*)&_fixups[_fixups.size()]; }
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+
+ const ld::Atom* _atom;
+ const uint32_t _startOffset;
+ const uint32_t _len;
+ const uint32_t _compactUnwindInfo;
+ std::vector<ld::Fixup> _fixups;
+
+ static ld::Fixup::Kind _s_pointerKind;
+ static ld::Fixup::Kind _s_pointerStoreKind;
+ static ld::Section _s_section;
+};
+
+
+template <typename A>
+ld::Section CompactUnwindAtom<A>::_s_section("__LD", "__compact_unwind", ld::Section::typeDebug);
+
+template <> ld::Fixup::Kind CompactUnwindAtom<x86>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian32;
+template <> ld::Fixup::Kind CompactUnwindAtom<x86>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian32;
+template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian64;
+template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian64;
+
+template <typename A>
+CompactUnwindAtom<A>::CompactUnwindAtom(ld::Internal& state,const ld::Atom* funcAtom, uint32_t startOffset,
+ uint32_t len, uint32_t cui)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
+ _atom(funcAtom), _startOffset(startOffset), _len(len), _compactUnwindInfo(cui)
+{
+ _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, funcAtom));
+ _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k2of3, ld::Fixup::kindAddAddend, _startOffset));
+ _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k3of3, _s_pointerKind));
+ // see if atom has subordinate personality function or lsda
+ for (ld::Fixup::iterator fit = funcAtom->fixupsBegin(), end=funcAtom->fixupsEnd(); fit != end; ++fit) {
+ switch ( fit->kind ) {
+ case ld::Fixup::kindNoneGroupSubordinatePersonality:
+ assert(fit->binding == ld::Fixup::bindingsIndirectlyBound);
+ _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::personalityFieldOffset(), ld::Fixup::k1of1, _s_pointerStoreKind, state.indirectBindingTable[fit->u.bindingIndex]));
+ break;
+ case ld::Fixup::kindNoneGroupSubordinateLSDA:
+ assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+ _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::lsdaFieldOffset(), ld::Fixup::k1of1, _s_pointerStoreKind, fit->u.target));
+ break;
+ default:
+ break;
+ }
+ }
+
+}
+
+template <typename A>
+void CompactUnwindAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ macho_compact_unwind_entry<P>* buf = (macho_compact_unwind_entry<P>*)buffer;
+ buf->set_codeStart(0);
+ buf->set_codeLen(_len);
+ buf->set_compactUnwindInfo(_compactUnwindInfo);
+ buf->set_personality(0);
+ buf->set_lsda(0);
+}
+
+
+static void makeCompactUnwindAtom(const Options& opts, ld::Internal& state, const ld::Atom* atom,
+ uint32_t startOffset, uint32_t endOffset, uint32_t cui)
+{
+ switch ( opts.architecture() ) {
+#if SUPPORT_ARCH_x86_64
+ case CPU_TYPE_X86_64:
+ state.addAtom(*new CompactUnwindAtom<x86_64>(state, atom, startOffset, endOffset-startOffset, cui));
+ break;
+#endif
+#if SUPPORT_ARCH_i386
+ case CPU_TYPE_I386:
+ state.addAtom(*new CompactUnwindAtom<x86>(state, atom, startOffset, endOffset-startOffset, cui));
+ break;
+#endif
+ }
+}
+
+static void makeRelocateableCompactUnwindSection(const Options& opts, ld::Internal& state)
+{
+ // can't add CompactUnwindAtom atoms will iterating, so pre-scan
+ std::vector<const ld::Atom*> atomsWithUnwind;
+ for (std::vector<ld::Internal::FinalSection*>::const_iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ if ( atom->beginUnwind() != atom->endUnwind() )
+ atomsWithUnwind.push_back(atom);
+ }
+ }
+ // make one CompactUnwindAtom for each compact unwind range in each atom
+ for (std::vector<const ld::Atom*>::iterator it = atomsWithUnwind.begin(); it != atomsWithUnwind.end(); ++it) {
+ const ld::Atom* atom = *it;
+ uint32_t lastOffset = 0;
+ uint32_t lastCUE = 0;
+ bool first = true;
+ for (ld::Atom::UnwindInfo::iterator uit=atom->beginUnwind(); uit != atom->endUnwind(); ++uit) {
+ if ( !first ) {
+ makeCompactUnwindAtom(opts, state, atom, lastOffset, uit->startOffset, lastCUE);
+ }
+ lastOffset = uit->startOffset;
+ lastCUE = uit->unwindInfo;
+ first = false;
+ }
+ makeCompactUnwindAtom(opts, state, atom, lastOffset, (uint32_t)atom->size(), lastCUE);
+ }
+}
+
+
+void doPass(const Options& opts, ld::Internal& state)
+{
+ if ( opts.outputKind() == Options::kObjectFile )
+ makeRelocateableCompactUnwindSection(opts, state);
+
+ else if ( opts.needsUnwindInfoSection() )
+ makeFinalLinkedImageCompactUnwindSection(opts, state);
+}
+
+
+} // namespace compact_unwind
+} // namespace passes
+} // namespace ld
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __COMPACT_UNWIND_H__
+#define __COMPACT_UNWIND_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace compact_unwind {
+
+// called by linker to add __unwind_info section table
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace compact_unwind
+} // namespace passes
+} // namespace ld
+
+#endif // __COMPACT_UNWIND_H__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+
+#include <vector>
+#include <map>
+#include <ext/hash_map>
+
+#include "ld.hpp"
+#include "dtrace_dof.h"
+
+// prototype for entry point in libdtrace.dylib
+typedef uint8_t* (*createdof_func_t)(cpu_type_t, unsigned int, const char*[], unsigned int, const char*[], const char*[], uint64_t offsetsInDOF[], size_t* size);
+
+
+namespace ld {
+namespace passes {
+namespace dtrace {
+
+class File; // forward reference
+
+class Atom : public ld::Atom {
+public:
+ Atom(class File& f, const char* n, const uint8_t* content, uint64_t sz);
+
+ virtual ld::File* file() const { return (ld::File*)&_file; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return _size; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const
+ { memcpy(buffer, _content, _size); }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixups[0]; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &_fixups[_fixups.size()]; }
+
+protected:
+ friend class File;
+ virtual ~Atom() {}
+
+ class File& _file;
+ const char* _name;
+ const uint8_t* _content;
+ uint64_t _size;
+ mutable std::vector<ld::Fixup> _fixups;
+};
+
+
+class File : public ld::File
+{
+public:
+ File(const char* segmentName, const char* sectionName, const char* pth,
+ const uint8_t fileContent[], uint64_t fileLength, Ordinal ord,
+ const char* symbolName="dof")
+ : ld::File(pth, 0, ord, Other),
+ _atom(*this, symbolName, fileContent, fileLength),
+ _section(segmentName, sectionName, ld::Section::typeDtraceDOF) { }
+ virtual ~File() {}
+
+ virtual bool forEachAtom(AtomHandler& h) const { h.doAtom(_atom); return true; }
+ virtual bool justInTimeforEachAtom(const char* name, AtomHandler&) const { return false; }
+
+ void reserveFixups(unsigned int count) { _atom._fixups.reserve(count); }
+ void addSectionFixup(const ld::Fixup& f) { _atom._fixups.push_back(f); }
+ ld::Atom& atom() { return _atom; }
+private:
+ friend class Atom;
+
+ Atom _atom;
+ ld::Section _section;
+};
+
+Atom::Atom(File& f, const char* n, const uint8_t* content, uint64_t sz)
+ : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
+ _file(f), _name(strdup(n)), _content(content), _size(sz) {}
+
+
+
+class CStringEquals
+{
+public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+};
+
+struct DTraceProbeInfo {
+ DTraceProbeInfo(const ld::Atom* a, uint32_t o, const char* n) : atom(a), offset(o), probeName(n) {}
+ const ld::Atom* atom;
+ uint32_t offset;
+ const char* probeName;
+};
+typedef __gnu_cxx::hash_map<const char*, std::vector<DTraceProbeInfo>, __gnu_cxx::hash<const char*>, CStringEquals> ProviderToProbes;
+typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> CStringSet;
+
+
+
+void doPass(const Options& opts, ld::Internal& internal)
+{
+ static bool log = false;
+
+ // only make __dof section in final linked images
+ if ( opts.outputKind() == Options::kObjectFile )
+ return;
+
+ // scan all atoms looking for dtrace probes
+ std::vector<DTraceProbeInfo> probeSites;
+ std::vector<DTraceProbeInfo> isEnabledSites;
+ std::map<const ld::Atom*,CStringSet> atomToDtraceTypes;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=internal.sections.begin(); sit != internal.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() != ld::Section::typeCode )
+ continue;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ switch ( fit->kind ) {
+ case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+ case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+ case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+ probeSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
+ break;
+ case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+ case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+ case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+ isEnabledSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
+ break;
+ case ld::Fixup::kindDtraceExtra:
+ atomToDtraceTypes[atom].insert(fit->u.name);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ // if no probes, we're done
+ if ( (probeSites.size() == 0) && (isEnabledSites.size() == 0) )
+ return;
+
+ ld::Fixup::Kind storeKind = ld::Fixup::kindNone;
+ switch ( opts.architecture() ) {
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64:
+ case CPU_TYPE_ARM:
+ storeKind = ld::Fixup::kindStoreLittleEndian32;
+ break;
+ default:
+ throw "unsupported arch for DOF";
+ }
+
+ // partition probes by provider name
+ // The symbol names looks like:
+ // "___dtrace_probe$" provider-name "$" probe-name [ "$"... ]
+ // "___dtrace_isenabled$" provider-name "$" probe-name [ "$"... ]
+ ProviderToProbes providerToProbes;
+ std::vector<DTraceProbeInfo> emptyList;
+ for(std::vector<DTraceProbeInfo>::iterator it = probeSites.begin(); it != probeSites.end(); ++it) {
+ // ignore probes in functions that were coalesed away rdar://problem/5628149
+ if ( it->atom->coalescedAway() )
+ continue;
+ const char* providerStart = &it->probeName[16];
+ const char* providerEnd = strchr(providerStart, '$');
+ if ( providerEnd != NULL ) {
+ char providerName[providerEnd-providerStart+1];
+ strlcpy(providerName, providerStart, providerEnd-providerStart+1);
+ ProviderToProbes::iterator pos = providerToProbes.find(providerName);
+ if ( pos == providerToProbes.end() ) {
+ const char* dup = strdup(providerName);
+ providerToProbes[dup] = emptyList;
+ }
+ providerToProbes[providerName].push_back(*it);
+ }
+ }
+ for(std::vector<DTraceProbeInfo>::iterator it = isEnabledSites.begin(); it != isEnabledSites.end(); ++it) {
+ // ignore probes in functions that were coalesed away rdar://problem/5628149
+ if ( it->atom->coalescedAway() )
+ continue;
+ const char* providerStart = &it->probeName[20];
+ const char* providerEnd = strchr(providerStart, '$');
+ if ( providerEnd != NULL ) {
+ char providerName[providerEnd-providerStart+1];
+ strlcpy(providerName, providerStart, providerEnd-providerStart+1);
+ ProviderToProbes::iterator pos = providerToProbes.find(providerName);
+ if ( pos == providerToProbes.end() ) {
+ const char* dup = strdup(providerName);
+ providerToProbes[dup] = emptyList;
+ }
+ providerToProbes[providerName].push_back(*it);
+ }
+ }
+
+ // create a DOF section for each provider
+ int dofIndex=1;
+ CStringSet sectionNamesUsed;
+ for(ProviderToProbes::iterator pit = providerToProbes.begin(); pit != providerToProbes.end(); ++pit, ++dofIndex) {
+ const char* providerName = pit->first;
+ const std::vector<DTraceProbeInfo>& probes = pit->second;
+
+ // open library and find dtrace_create_dof()
+ void* handle = dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY);
+ if ( handle == NULL )
+ throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s", dlerror());
+ createdof_func_t pCreateDOF = (createdof_func_t)dlsym(handle, "dtrace_ld_create_dof");
+ if ( pCreateDOF == NULL )
+ throwf("couldn't find \"dtrace_ld_create_dof\" in /usr/lib/libdtrace.dylib: %s", dlerror());
+ // build list of typedefs/stability infos for this provider
+ CStringSet types;
+ for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
+ std::map<const ld::Atom*,CStringSet>::iterator pos = atomToDtraceTypes.find(it->atom);
+ if ( pos != atomToDtraceTypes.end() ) {
+ for(CStringSet::iterator sit = pos->second.begin(); sit != pos->second.end(); ++sit) {
+ const char* providerStart = strchr(*sit, '$')+1;
+ const char* providerEnd = strchr(providerStart, '$');
+ if ( providerEnd != NULL ) {
+ char aProviderName[providerEnd-providerStart+1];
+ strlcpy(aProviderName, providerStart, providerEnd-providerStart+1);
+ if ( strcmp(aProviderName, providerName) == 0 )
+ types.insert(*sit);
+ }
+ }
+ }
+ }
+ int typeCount = types.size();
+ const char* typeNames[typeCount];
+ //fprintf(stderr, "types for %s:\n", providerName);
+ uint32_t index = 0;
+ for(CStringSet::iterator it = types.begin(); it != types.end(); ++it) {
+ typeNames[index] = *it;
+ //fprintf(stderr, "\t%s\n", *it);
+ ++index;
+ }
+
+ // build list of probe/isenabled sites
+ const uint32_t probeCount = probes.size();
+ const char* probeNames[probeCount];
+ const char* funtionNames[probeCount];
+ uint64_t offsetsInDOF[probeCount];
+ index = 0;
+ for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
+ probeNames[index] = it->probeName;
+ funtionNames[index] = it->atom->name();
+ offsetsInDOF[index] = 0;
+ ++index;
+ }
+ if ( log ) {
+ fprintf(stderr, "calling libtrace to create DOF:\n");
+ fprintf(stderr, " types::\n");
+ for(int i=0; i < typeCount; ++i)
+ fprintf(stderr, " [%u]\t %s\n", i, typeNames[i]);
+ fprintf(stderr, " probes::\n");
+ for(uint32_t i=0; i < probeCount; ++i)
+ fprintf(stderr, " [%u]\t %s in %s\n", i, probeNames[i], funtionNames[i]);
+ }
+
+ // call dtrace library to create DOF section
+ size_t dofSectionSize;
+ uint8_t* p = (*pCreateDOF)(opts.architecture(), typeCount, typeNames, probeCount, probeNames, funtionNames, offsetsInDOF, &dofSectionSize);
+ if ( p != NULL ) {
+ char* sectionName = new char[18]; // alloc new string, pass ownership to File()
+ strcpy(sectionName, "__dof_");
+ strlcpy(§ionName[6], providerName, 10);
+ // create unique section name so each DOF is in its own section
+ if ( sectionNamesUsed.count(sectionName) != 0 ) {
+ sectionName[15] = '0';
+ sectionName[16] = '\0';
+ while ( sectionNamesUsed.count(sectionName) != 0 ) {
+ ++sectionName[15];
+ }
+ }
+ sectionNamesUsed.insert(sectionName);
+ char symbolName[strlen(providerName)+64];
+ sprintf(symbolName, "__dtrace_dof_for_provider_%s", providerName);
+ File* f = new File("__TEXT", sectionName, "dtrace", p, dofSectionSize, ld::File::Ordinal::NullOrdinal(), symbolName);
+ if ( log ) {
+ fprintf(stderr, "libdtrace created DOF of size %ld\n", dofSectionSize);
+ }
+ // add references
+ f->reserveFixups(3*probeCount);
+ for (uint32_t i=0; i < probeCount; ++i) {
+ uint64_t offset = offsetsInDOF[i];
+ //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset);
+ if ( offset > dofSectionSize )
+ throwf("offsetsInDOF[%d]=%0llX > dofSectionSize=%0lX\n", i, offset, dofSectionSize);
+ f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, probes[i].atom));
+ f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k2of4, ld::Fixup::kindAddAddend, probes[i].offset));
+ f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, &f->atom()));
+ f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k4of4, storeKind));
+ }
+ // insert new section
+ internal.addAtom(f->atom());
+ }
+ else {
+ throw "error creating dtrace DOF section";
+ }
+ }
+
+
+
+}
+
+
+} // namespace dtrace
+} // namespace passes
+} // namespace ld
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __DTRACE_DOF_H__
+#define __DTRACE_DOF_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace dtrace {
+
+// called by linker to process atoms in Internal and add DOF sections as needed
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace dtrace
+} // namespace passes
+} // namespace ld
+
+#endif // __DTRACE_DOF_H__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <mach/machine.h>
+
+#include <vector>
+
+#include "ld.hpp"
+#include "dylibs.h"
+
+namespace ld {
+namespace passes {
+namespace dylibs {
+
+
+class WillBeUsed
+{
+public:
+ bool operator()(ld::dylib::File* dylib) const {
+ return dylib->willRemoved();
+ }
+};
+
+
+void doPass(const Options& opts, ld::Internal& state)
+{
+// const bool log = false;
+
+ // clear "willRemoved" bit on all dylibs
+ for (std::vector<ld::dylib::File*>::iterator it = state.dylibs.begin(); it != state.dylibs.end(); ++it) {
+ ld::dylib::File* aDylib = *it;
+ aDylib->setWillBeRemoved(false);
+ }
+ for (std::vector<ld::dylib::File*>::iterator it = state.dylibs.begin(); it != state.dylibs.end(); ++it) {
+ ld::dylib::File* aDylib = *it;
+ // set "willRemoved" bit on implicit dylibs that did not provide any exports
+ if ( aDylib->implicitlyLinked() && !aDylib->explicitlyLinked() && !aDylib->providedExportAtom() )
+ aDylib->setWillBeRemoved(true);
+ // set "willRemoved" bit on dead strippable explicit dylibs that did not provide any exports
+ if ( aDylib->explicitlyLinked() && aDylib->deadStrippable() && !aDylib->providedExportAtom() )
+ aDylib->setWillBeRemoved(true);
+ // set "willRemoved" bit on any unused explicit when -dead_strip_dylibs is used
+ if ( opts.deadStripDylibs() && !aDylib->providedExportAtom() )
+ aDylib->setWillBeRemoved(true);
+ }
+ // remove unused dylibs
+ state.dylibs.erase(std::remove_if(state.dylibs.begin(), state.dylibs.end(), WillBeUsed()), state.dylibs.end());
+
+
+ // <rdar://problem/9441273> automatically weak-import dylibs when all symbols from it are weak-imported
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ const ld::Atom* target = NULL;
+ bool targetIsWeakImport = false;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ if ( fit->firstInCluster() )
+ target = NULL;
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingsIndirectlyBound:
+ target = state.indirectBindingTable[fit->u.bindingIndex];
+ targetIsWeakImport = fit->weakImport;
+ break;
+ case ld::Fixup::bindingDirectlyBound:
+ target = fit->u.target;
+ targetIsWeakImport = fit->weakImport;
+ break;
+ default:
+ break;
+ }
+ if ( (target != NULL) && (target->definition() == ld::Atom::definitionProxy) ) {
+ ld::Atom::WeakImportState curWI = target->weakImportState();
+ if ( curWI == ld::Atom::weakImportUnset ) {
+ // first use of this proxy, set weak-import based on this usage
+ (const_cast<ld::Atom*>(target))->setWeakImportState(targetIsWeakImport);
+ }
+ else {
+ // proxy already has weak-importness set, check for weakness mismatch
+ bool curIsWeakImport = (curWI == ld::Atom::weakImportTrue);
+ if ( curIsWeakImport != targetIsWeakImport ) {
+ // found mismatch
+ switch ( opts.weakReferenceMismatchTreatment() ) {
+ case Options::kWeakReferenceMismatchError:
+ throwf("mismatching weak references for symbol: %s", target->name());
+ case Options::kWeakReferenceMismatchWeak:
+ (const_cast<ld::Atom*>(target))->setWeakImportState(true);
+ break;
+ case Options::kWeakReferenceMismatchNonWeak:
+ (const_cast<ld::Atom*>(target))->setWeakImportState(false);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+}
+
+
+} // namespace dylibs
+} // namespace passes
+} // namespace ld
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __DYLIBS_H__
+#define __DYLIBS_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace dylibs {
+
+// called by linker to optimize use of dylibs
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace dylibs
+} // namespace passes
+} // namespace ld
+
+#endif // __DYLIBS_H__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+
+#include <vector>
+#include <map>
+#include <ext/hash_map>
+
+#include "ld.hpp"
+#include "got.h"
+
+namespace ld {
+namespace passes {
+namespace got {
+
+class File; // forward reference
+
+class GOTEntryAtom : public ld::Atom {
+public:
+ GOTEntryAtom(ld::Internal& internal, const ld::Atom* target, bool weakImport)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
+ _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, target),
+ _target(target)
+ { _fixup.weakImport = weakImport; internal.addAtom(*this); }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return _target->name(); }
+ virtual uint64_t size() const { return 8; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+ mutable ld::Fixup _fixup;
+ const ld::Atom* _target;
+
+ static ld::Section _s_section;
+};
+
+ld::Section GOTEntryAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
+
+
+static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom* targetOfGOT, const ld::Fixup* fixup, bool* optimizable)
+{
+ switch (fixup->kind) {
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+ // start by assuming this can be optimized
+ *optimizable = true;
+ // cannot do LEA optimization if target is in another dylib
+ if ( targetOfGOT->definition() == ld::Atom::definitionProxy )
+ *optimizable = false;
+ // cannot do LEA optimization if target in __huge section
+ if ( internal.usingHugeSections && (targetOfGOT->size() > 1024*1024)
+ && ( (targetOfGOT->section().type() == ld::Section::typeZeroFill)
+ || (targetOfGOT->section().type() == ld::Section::typeTentativeDefs)) ) {
+ *optimizable = false;
+ }
+ if ( targetOfGOT->scope() == ld::Atom::scopeGlobal ) {
+ // cannot do LEA optimization if target is weak exported symbol
+ if ( (targetOfGOT->definition() == ld::Atom::definitionRegular) && (targetOfGOT->combine() == ld::Atom::combineByName) ) {
+ switch ( opts.outputKind() ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kKextBundle:
+ *optimizable = false;
+ break;
+ case Options::kStaticExecutable:
+ case Options::kDyld:
+ case Options::kPreload:
+ case Options::kObjectFile:
+ break;
+ }
+ }
+ // cannot do LEA optimization if target is interposable
+ if ( opts.interposable(targetOfGOT->name()) )
+ *optimizable = false;
+ // cannot do LEA optimization if target is resolver function
+ if ( targetOfGOT->contentType() == ld::Atom::typeResolver )
+ *optimizable = false;
+ // cannot do LEA optimization for flat-namespace
+ if ( opts.nameSpace() != Options::kTwoLevelNameSpace )
+ *optimizable = false;
+ }
+ return true;
+ case ld::Fixup::kindStoreX86PCRel32GOT:
+ *optimizable = false;
+ return true;
+ case ld::Fixup::kindNoneGroupSubordinatePersonality:
+ *optimizable = false;
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+struct AtomByNameSorter
+{
+ bool operator()(const ld::Atom* left, const ld::Atom* right)
+ {
+ return (strcmp(left->name(), right->name()) < 0);
+ }
+};
+
+void doPass(const Options& opts, ld::Internal& internal)
+{
+ const bool log = false;
+
+ // only make got section in final linked images
+ if ( opts.outputKind() == Options::kObjectFile )
+ return;
+
+ // walk all atoms and fixups looking for GOT-able references
+ // don't create GOT atoms during this loop because that could invalidate the sections iterator
+ std::vector<const ld::Atom*> atomsReferencingGOT;
+ std::map<const ld::Atom*,ld::Atom*> gotMap;
+ std::map<const ld::Atom*,bool> weakImportMap;
+ atomsReferencingGOT.reserve(128);
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=internal.sections.begin(); sit != internal.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ bool atomUsesGOT = false;
+ const ld::Atom* targetOfGOT = NULL;
+ bool targetIsWeakImport = false;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ if ( fit->firstInCluster() )
+ targetOfGOT = NULL;
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingsIndirectlyBound:
+ targetOfGOT = internal.indirectBindingTable[fit->u.bindingIndex];
+ targetIsWeakImport = fit->weakImport;
+ break;
+ case ld::Fixup::bindingDirectlyBound:
+ targetOfGOT = fit->u.target;
+ targetIsWeakImport = fit->weakImport;
+ break;
+ default:
+ break;
+ }
+ bool optimizable;
+ if ( !gotFixup(opts, internal, targetOfGOT, fit, &optimizable) )
+ continue;
+ if ( optimizable ) {
+ // change from load of GOT entry to lea of target
+ if ( log ) fprintf(stderr, "optimized GOT usage in %s to %s\n", atom->name(), targetOfGOT->name());
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingsIndirectlyBound:
+ case ld::Fixup::bindingDirectlyBound:
+ fit->binding = ld::Fixup::bindingDirectlyBound;
+ fit->u.target = targetOfGOT;
+ fit->kind = ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA;
+ break;
+ default:
+ assert(0 && "unsupported GOT reference");
+ break;
+ }
+ }
+ else {
+ // remember that we need to use GOT in this function
+ if ( log ) fprintf(stderr, "found GOT use in %s to %s\n", atom->name(), targetOfGOT->name());
+ if ( !atomUsesGOT ) {
+ atomsReferencingGOT.push_back(atom);
+ atomUsesGOT = true;
+ }
+ gotMap[targetOfGOT] = NULL;
+ // record weak_import attribute
+ std::map<const ld::Atom*,bool>::iterator pos = weakImportMap.find(targetOfGOT);
+ if ( pos == weakImportMap.end() ) {
+ // target not in weakImportMap, so add
+ if ( log ) fprintf(stderr, "weakImportMap[%s] = %d\n", targetOfGOT->name(), targetIsWeakImport);
+ weakImportMap[targetOfGOT] = targetIsWeakImport;
+ }
+ else {
+ // target in weakImportMap, check for weakness mismatch
+ if ( pos->second != targetIsWeakImport ) {
+ // found mismatch
+ switch ( opts.weakReferenceMismatchTreatment() ) {
+ case Options::kWeakReferenceMismatchError:
+ throwf("mismatching weak references for symbol: %s", targetOfGOT->name());
+ case Options::kWeakReferenceMismatchWeak:
+ pos->second = true;
+ break;
+ case Options::kWeakReferenceMismatchNonWeak:
+ pos->second = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // make GOT entries
+ for (std::map<const ld::Atom*,ld::Atom*>::iterator it = gotMap.begin(); it != gotMap.end(); ++it) {
+ it->second = new GOTEntryAtom(internal, it->first, weakImportMap[it->first]);
+ }
+
+ // update atoms to use GOT entries
+ for (std::vector<const ld::Atom*>::iterator it=atomsReferencingGOT.begin(); it != atomsReferencingGOT.end(); ++it) {
+ const ld::Atom* atom = *it;
+ const ld::Atom* targetOfGOT = NULL;
+ ld::Fixup::iterator fitThatSetTarget = NULL;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ if ( fit->firstInCluster() ) {
+ targetOfGOT = NULL;
+ fitThatSetTarget = NULL;
+ }
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingsIndirectlyBound:
+ targetOfGOT = internal.indirectBindingTable[fit->u.bindingIndex];
+ fitThatSetTarget = fit;
+ break;
+ case ld::Fixup::bindingDirectlyBound:
+ targetOfGOT = fit->u.target;
+ fitThatSetTarget = fit;
+ break;
+ default:
+ break;
+ }
+ bool optimizable;
+ if ( (targetOfGOT == NULL) || !gotFixup(opts, internal, targetOfGOT, fit, &optimizable) )
+ continue;
+ if ( !optimizable ) {
+ // GOT use not optimized away, update to bind to GOT entry
+ assert(fitThatSetTarget != NULL);
+ switch ( fitThatSetTarget->binding ) {
+ case ld::Fixup::bindingsIndirectlyBound:
+ case ld::Fixup::bindingDirectlyBound:
+ fitThatSetTarget->binding = ld::Fixup::bindingDirectlyBound;
+ fitThatSetTarget->u.target = gotMap[targetOfGOT];
+ break;
+ default:
+ assert(0 && "unsupported GOT reference");
+ break;
+ }
+ }
+ }
+ }
+
+ // sort new atoms so links are consistent
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=internal.sections.begin(); sit != internal.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() == ld::Section::typeNonLazyPointer ) {
+ std::sort(sect->atoms.begin(), sect->atoms.end(), AtomByNameSorter());
+ }
+ }
+}
+
+
+} // namespace got
+} // namespace passes
+} // namespace ld
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __GOT_H__
+#define __GOT_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace got {
+
+// called by linker to create GOT entries and optimize GOT loads into LEAs instead
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace got
+} // namespace passes
+} // namespace ld
+
+#endif // __GOT_H__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <mach/machine.h>
+
+#include <vector>
+
+#include "ld.hpp"
+#include "huge.h"
+
+namespace ld {
+namespace passes {
+namespace huge {
+
+class NullAtom
+{
+public:
+ bool operator()(const ld::Atom* atom) const {
+ return (atom == NULL);
+ }
+};
+
+void doPass(const Options& opts, ld::Internal& state)
+{
+ const bool log = false;
+
+ // only make make __huge section in final linked images
+ if ( opts.outputKind() == Options::kObjectFile )
+ return;
+
+ // only make make __huge section for x86_64
+ if ( opts.architecture() != CPU_TYPE_X86_64 )
+ return;
+
+ // only needed if some (non-linkedit) atoms have an addresss >2GB from base address
+ state.usingHugeSections = false;
+ uint64_t address = 0;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() == ld::Section::typePageZero )
+ continue;
+ if ( sect->type() == ld::Section::typeStack )
+ continue;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ if ( (address > 0x7FFFFFFFLL) && !sect->isSectionHidden() ) {
+ state.usingHugeSections = true;
+ if (log) fprintf(stderr, "atom: %s is >2GB (0x%09llX), so enabling huge mode\n", atom->name(), address);
+ break;
+ }
+ address += atom->size();
+ }
+ if ( state.usingHugeSections )
+ break;
+ }
+ if ( !state.usingHugeSections )
+ return;
+
+ // move all zero fill atoms that >1MB in size to a new __huge section
+ ld::Internal::FinalSection* hugeSection = state.getFinalSection(ld::Section("__DATA", "__huge", ld::Section::typeZeroFill));
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect == hugeSection )
+ continue;
+ if ( sect->type() == ld::Section::typeZeroFill ) {
+ bool movedSome = false;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ if ( atom->size() > 1024*1024 ) {
+ hugeSection->atoms.push_back(atom);
+ if (log) fprintf(stderr, "moved to __huge: %s, size=%llu\n", atom->name(), atom->size());
+ *ait = NULL; // change atom to NULL for later bulk removal
+ movedSome = true;
+ }
+ }
+ if ( movedSome )
+ sect->atoms.erase(std::remove_if(sect->atoms.begin(), sect->atoms.end(), NullAtom()), sect->atoms.end());
+ }
+ }
+
+
+}
+
+
+} // namespace huge
+} // namespace passes
+} // namespace ld
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __HUGE_H__
+#define __HUGE_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace huge {
+
+// called by linker to move large zero-fill atoms to the __huge section
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace huge
+} // namespace passes
+} // namespace ld
+
+#endif // __HUGE_H__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <mach/machine.h>
+
+#include <vector>
+#include <map>
+#include <set>
+
+#include "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+
+#include "ld.hpp"
+#include "objc.h"
+
+namespace ld {
+namespace passes {
+namespace objc {
+
+
+
+struct objc_image_info {
+ uint32_t version; // initially 0
+ uint32_t flags;
+};
+
+#define OBJC_IMAGE_SUPPORTS_GC (1<<1)
+#define OBJC_IMAGE_REQUIRES_GC (1<<2)
+#define OBJC_IMAGE_OPTIMIZED_BY_DYLD (1<<3)
+#define OBJC_IMAGE_SUPPORTS_COMPACTION (1<<4)
+
+
+
+//
+// This class is the 8 byte section containing ObjC flags
+//
+template <typename A>
+class ObjCImageInfoAtom : public ld::Atom {
+public:
+ ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint,
+ bool compaction, bool abi2);
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "objc image info"; }
+ virtual uint64_t size() const { return sizeof(objc_image_info); }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void setScope(Scope) { }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ memcpy(buffer, &_content, sizeof(objc_image_info));
+ }
+
+private:
+ objc_image_info _content;
+
+ static ld::Section _s_sectionABI1;
+ static ld::Section _s_sectionABI2;
+};
+
+template <typename A> ld::Section ObjCImageInfoAtom<A>::_s_sectionABI1("__OBJC", "__image_info", ld::Section::typeUnclassified);
+template <typename A> ld::Section ObjCImageInfoAtom<A>::_s_sectionABI2("__DATA", "__objc_imageinfo", ld::Section::typeUnclassified);
+
+
+template <typename A>
+ObjCImageInfoAtom<A>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint, bool compaction,
+ bool abi2)
+ : ld::Atom(abi2 ? _s_sectionABI2 : _s_sectionABI1, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2))
+{
+
+ uint32_t value = 0;
+ switch ( objcConstraint ) {
+ case ld::File::objcConstraintNone:
+ case ld::File::objcConstraintRetainRelease:
+ if ( compaction )
+ warning("ignoring -objc_gc_compaction because code not compiled for ObjC garbage collection");
+ break;
+ case ld::File::objcConstraintRetainReleaseOrGC:
+ value |= OBJC_IMAGE_SUPPORTS_GC;
+ if ( compaction )
+ value |= OBJC_IMAGE_SUPPORTS_COMPACTION;
+ break;
+ case ld::File::objcConstraintGC:
+ value |= OBJC_IMAGE_SUPPORTS_GC | OBJC_IMAGE_REQUIRES_GC;
+ if ( compaction )
+ value |= OBJC_IMAGE_SUPPORTS_COMPACTION;
+ break;
+ }
+
+ _content.version = 0;
+ A::P::E::set32(_content.flags, value);
+}
+
+
+
+//
+// This class is for a new Atom which is an ObjC method list created by merging method lists from categories
+//
+template <typename A>
+class MethodListAtom : public ld::Atom {
+public:
+ MethodListAtom(ld::Internal& state, const ld::Atom* baseMethodList, bool meta,
+ const std::vector<const ld::Atom*>* categories,
+ std::set<const ld::Atom*>& deadAtoms);
+
+ virtual const ld::File* file() const { return _file; }
+ virtual const char* name() const { return "objc merged method list"; }
+ virtual uint64_t size() const { return _methodCount*3*sizeof(pint_t) + 8; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void setScope(Scope) { }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ bzero(buffer, size());
+ A::P::E::set32(*((uint32_t*)(&buffer[0])), 3*sizeof(pint_t)); // entry size
+ A::P::E::set32(*((uint32_t*)(&buffer[4])), _methodCount);
+ }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixups[0]; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return (ld::Fixup*)&_fixups[_fixups.size()]; }
+
+private:
+ typedef typename A::P::uint_t pint_t;
+
+ const ld::File* _file;
+ unsigned int _methodCount;
+ std::vector<ld::Fixup> _fixups;
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section MethodListAtom<A>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified);
+
+
+//
+// This class is for a new Atom which is an ObjC protocol list created by merging protocol lists from categories
+//
+template <typename A>
+class ProtocolListAtom : public ld::Atom {
+public:
+ ProtocolListAtom(ld::Internal& state, const ld::Atom* baseProtocolList,
+ const std::vector<const ld::Atom*>* categories,
+ std::set<const ld::Atom*>& deadAtoms);
+
+ virtual const ld::File* file() const { return _file; }
+ virtual const char* name() const { return "objc merged protocol list"; }
+ virtual uint64_t size() const { return (_protocolCount+1)*sizeof(pint_t); }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void setScope(Scope) { }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ bzero(buffer, size());
+ A::P::setP(*((pint_t*)(buffer)), _protocolCount);
+ }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixups[0]; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return (ld::Fixup*)&_fixups[_fixups.size()]; }
+
+private:
+ typedef typename A::P::uint_t pint_t;
+
+ const ld::File* _file;
+ unsigned int _protocolCount;
+ std::vector<ld::Fixup> _fixups;
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section ProtocolListAtom<A>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified);
+
+
+
+//
+// This class is for a new Atom which is an ObjC property list created by merging property lists from categories
+//
+template <typename A>
+class PropertyListAtom : public ld::Atom {
+public:
+ PropertyListAtom(ld::Internal& state, const ld::Atom* baseProtocolList,
+ const std::vector<const ld::Atom*>* categories,
+ std::set<const ld::Atom*>& deadAtoms);
+
+ virtual const ld::File* file() const { return _file; }
+ virtual const char* name() const { return "objc merged property list"; }
+ virtual uint64_t size() const { return _propertyCount*2*sizeof(pint_t) + 8; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void setScope(Scope) { }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ bzero(buffer, size());
+ A::P::E::set32(((uint32_t*)(buffer))[0], 2*sizeof(pint_t)); // sizeof(objc_property)
+ A::P::E::set32(((uint32_t*)(buffer))[1], _propertyCount);
+ }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixups[0]; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return (ld::Fixup*)&_fixups[_fixups.size()]; }
+
+private:
+ typedef typename A::P::uint_t pint_t;
+
+ const ld::File* _file;
+ unsigned int _propertyCount;
+ std::vector<ld::Fixup> _fixups;
+
+ static ld::Section _s_section;
+};
+
+template <typename A>
+ld::Section PropertyListAtom<A>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified);
+
+
+
+
+
+//
+// This class is used to create an Atom that replaces an atom from a .o file that holds a class_ro_t.
+// It is needed because there is no way to add Fixups to an existing atom.
+//
+template <typename A>
+class ClassROOverlayAtom : public ld::Atom {
+public:
+ ClassROOverlayAtom(const ld::Atom* classROAtom);
+
+ // overrides of ld::Atom
+ virtual const ld::File* file() const { return _atom->file(); }
+ virtual const char* name() const { return _atom->name(); }
+ virtual uint64_t size() const { return _atom->size(); }
+ virtual uint64_t objectAddress() const { return _atom->objectAddress(); }
+ virtual void copyRawContent(uint8_t buffer[]) const
+ { _atom->copyRawContent(buffer); }
+ virtual const uint8_t* rawContentPointer() const
+ { return _atom->rawContentPointer(); }
+ virtual unsigned long contentHash(const class ld::IndirectBindingTable& ibt) const
+ { return _atom->contentHash(ibt); }
+ virtual bool canCoalesceWith(const ld::Atom& rhs, const class ld::IndirectBindingTable& ibt) const
+ { return _atom->canCoalesceWith(rhs,ibt); }
+
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixups[0]; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return (ld::Fixup*)&_fixups[_fixups.size()]; }
+
+ void addProtocolListFixup();
+ void addPropertyListFixup();
+ void addMethodListFixup();
+
+private:
+ typedef typename A::P::uint_t pint_t;
+
+ const ld::Atom* _atom;
+ std::vector<ld::Fixup> _fixups;
+};
+
+template <typename A>
+ClassROOverlayAtom<A>::ClassROOverlayAtom(const ld::Atom* classROAtom)
+ : ld::Atom(classROAtom->section(), ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
+ classROAtom->symbolTableInclusion(), false, false, false, classROAtom->alignment()),
+ _atom(classROAtom)
+{
+ // ensure all attributes are same as original
+ this->setAttributesFromAtom(*classROAtom);
+
+ // copy fixups from orginal atom
+ for (ld::Fixup::iterator fit=classROAtom->fixupsBegin(); fit != classROAtom->fixupsEnd(); ++fit) {
+ ld::Fixup fixup = *fit;
+ _fixups.push_back(fixup);
+ }
+}
+
+
+//
+// Base class for reading and updating existing ObjC atoms from .o files
+//
+template <typename A>
+class ObjCData {
+public:
+ static const ld::Atom* getPointerInContent(ld::Internal& state, const ld::Atom* contentAtom, unsigned int offset, bool* hasAddend=NULL);
+ static void setPointerInContent(ld::Internal& state, const ld::Atom* contentAtom,
+ unsigned int offset, const ld::Atom* newAtom);
+ typedef typename A::P::uint_t pint_t;
+};
+
+template <typename A>
+const ld::Atom* ObjCData<A>::getPointerInContent(ld::Internal& state, const ld::Atom* contentAtom, unsigned int offset, bool* hasAddend)
+{
+ const ld::Atom* target = NULL;
+ if ( hasAddend != NULL )
+ *hasAddend = false;
+ for (ld::Fixup::iterator fit=contentAtom->fixupsBegin(); fit != contentAtom->fixupsEnd(); ++fit) {
+ if ( fit->offsetInAtom == offset ) {
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingsIndirectlyBound:
+ target = state.indirectBindingTable[fit->u.bindingIndex];
+ break;
+ case ld::Fixup::bindingDirectlyBound:
+ target = fit->u.target;
+ break;
+ case ld::Fixup::bindingNone:
+ if ( fit->kind == ld::Fixup::kindAddAddend ) {
+ if ( hasAddend != NULL )
+ *hasAddend = true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return target;
+}
+
+template <typename A>
+void ObjCData<A>::setPointerInContent(ld::Internal& state, const ld::Atom* contentAtom,
+ unsigned int offset, const ld::Atom* newAtom)
+{
+ for (ld::Fixup::iterator fit=contentAtom->fixupsBegin(); fit != contentAtom->fixupsEnd(); ++fit) {
+ if ( fit->offsetInAtom == offset ) {
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingsIndirectlyBound:
+ state.indirectBindingTable[fit->u.bindingIndex] = newAtom;
+ return;
+ case ld::Fixup::bindingDirectlyBound:
+ fit->u.target = newAtom;
+ return;
+ default:
+ break;
+ }
+ }
+ }
+ assert(0 && "could not update method list");
+}
+
+
+
+//
+// Helper class for reading and updating existing ObjC category atoms from .o files
+//
+template <typename A>
+class Category : public ObjCData<A> {
+public:
+ static const ld::Atom* getClass(ld::Internal& state, const ld::Atom* contentAtom);
+ static const ld::Atom* getInstanceMethods(ld::Internal& state, const ld::Atom* contentAtom);
+ static const ld::Atom* getClassMethods(ld::Internal& state, const ld::Atom* contentAtom);
+ static const ld::Atom* getProtocols(ld::Internal& state, const ld::Atom* contentAtom);
+ static const ld::Atom* getProperties(ld::Internal& state, const ld::Atom* contentAtom);
+ static uint32_t size() { return 6*sizeof(pint_t); }
+private:
+ typedef typename A::P::uint_t pint_t;
+};
+
+
+template <typename A>
+const ld::Atom* Category<A>::getClass(ld::Internal& state, const ld::Atom* contentAtom)
+{
+ return ObjCData<A>::getPointerInContent(state, contentAtom, sizeof(pint_t)); // category_t.cls
+}
+
+template <typename A>
+const ld::Atom* Category<A>::getInstanceMethods(ld::Internal& state, const ld::Atom* contentAtom)
+{
+ return ObjCData<A>::getPointerInContent(state, contentAtom, 2*sizeof(pint_t)); // category_t.instanceMethods
+}
+
+template <typename A>
+const ld::Atom* Category<A>::getClassMethods(ld::Internal& state, const ld::Atom* contentAtom)
+{
+ return ObjCData<A>::getPointerInContent(state, contentAtom, 3*sizeof(pint_t)); // category_t.classMethods
+}
+
+template <typename A>
+const ld::Atom* Category<A>::getProtocols(ld::Internal& state, const ld::Atom* contentAtom)
+{
+ return ObjCData<A>::getPointerInContent(state, contentAtom, 4*sizeof(pint_t)); // category_t.protocols
+}
+
+template <typename A>
+const ld::Atom* Category<A>::getProperties(ld::Internal& state, const ld::Atom* contentAtom)
+{
+ return ObjCData<A>::getPointerInContent(state, contentAtom, 5*sizeof(pint_t)); // category_t.instanceProperties
+}
+
+
+template <typename A>
+class MethodList : public ObjCData<A> {
+public:
+ static uint32_t count(ld::Internal& state, const ld::Atom* methodListAtom) {
+ const uint32_t* methodListData = (uint32_t*)(methodListAtom->rawContentPointer());
+ return A::P::E::get32(methodListData[1]); // method_list_t.count
+ }
+};
+
+template <typename A>
+class ProtocolList : public ObjCData<A> {
+public:
+ static uint32_t count(ld::Internal& state, const ld::Atom* protocolListAtom) {
+ pint_t* protocolListData = (pint_t*)(protocolListAtom->rawContentPointer());
+ return A::P::getP(*protocolListData); // protocol_list_t.count
+ }
+private:
+ typedef typename A::P::uint_t pint_t;
+};
+
+template <typename A>
+class PropertyList : public ObjCData<A> {
+public:
+ static uint32_t count(ld::Internal& state, const ld::Atom* protocolListAtom) {
+ uint32_t* protocolListData = (uint32_t*)(protocolListAtom->rawContentPointer());
+ return A::P::E::get32(protocolListData[1]); // property_list_t.count
+ }
+private:
+ typedef typename A::P::uint_t pint_t;
+};
+
+
+
+//
+// Helper class for reading and updating existing ObjC class atoms from .o files
+//
+template <typename A>
+class Class : public ObjCData<A> {
+public:
+ static const ld::Atom* getInstanceMethodList(ld::Internal& state, const ld::Atom* classAtom);
+ static const ld::Atom* getInstanceProtocolList(ld::Internal& state, const ld::Atom* classAtom);
+ static const ld::Atom* getInstancePropertyList(ld::Internal& state, const ld::Atom* classAtom);
+ static const ld::Atom* getClassMethodList(ld::Internal& state, const ld::Atom* classAtom);
+ static const ld::Atom* setInstanceMethodList(ld::Internal& state, const ld::Atom* classAtom,
+ const ld::Atom* methodListAtom, std::set<const ld::Atom*>& deadAtoms);
+ static const ld::Atom* setInstanceProtocolList(ld::Internal& state, const ld::Atom* classAtom,
+ const ld::Atom* protocolListAtom, std::set<const ld::Atom*>& deadAtoms);
+ static const ld::Atom* setInstancePropertyList(ld::Internal& state, const ld::Atom* classAtom,
+ const ld::Atom* propertyListAtom, std::set<const ld::Atom*>& deadAtoms);
+ static const ld::Atom* setClassMethodList(ld::Internal& state, const ld::Atom* classAtom,
+ const ld::Atom* methodListAtom, std::set<const ld::Atom*>& deadAtoms);
+ static const ld::Atom* setClassProtocolList(ld::Internal& state, const ld::Atom* classAtom,
+ const ld::Atom* protocolListAtom, std::set<const ld::Atom*>& deadAtoms);
+ static uint32_t size() { return 5*sizeof(pint_t); }
+ static unsigned int class_ro_header_size();
+private:
+ typedef typename A::P::uint_t pint_t;
+ static const ld::Atom* getROData(ld::Internal& state, const ld::Atom* classAtom);
+};
+
+template <> unsigned int Class<x86_64>::class_ro_header_size() { return 16; }
+template <> unsigned int Class<arm>::class_ro_header_size() { return 12;}
+template <> unsigned int Class<x86>::class_ro_header_size() { return 12; }
+
+
+template <typename A>
+const ld::Atom* Class<A>::getROData(ld::Internal& state, const ld::Atom* classAtom)
+{
+ return ObjCData<A>::getPointerInContent(state, classAtom, 4*sizeof(pint_t)); // class_t.data
+
+}
+
+template <typename A>
+const ld::Atom* Class<A>::getInstanceMethodList(ld::Internal& state, const ld::Atom* classAtom)
+{
+ const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
+ assert(classROAtom != NULL);
+ return ObjCData<A>::getPointerInContent(state, classROAtom, class_ro_header_size() + 2*sizeof(pint_t)); // class_ro_t.baseMethods
+}
+
+template <typename A>
+const ld::Atom* Class<A>::getInstanceProtocolList(ld::Internal& state, const ld::Atom* classAtom)
+{
+ const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
+ assert(classROAtom != NULL);
+ return ObjCData<A>::getPointerInContent(state, classROAtom, class_ro_header_size() + 3*sizeof(pint_t)); // class_ro_t.baseProtocols
+}
+
+template <typename A>
+const ld::Atom* Class<A>::getInstancePropertyList(ld::Internal& state, const ld::Atom* classAtom)
+{
+ const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
+ assert(classROAtom != NULL);
+ return ObjCData<A>::getPointerInContent(state, classROAtom, class_ro_header_size() + 6*sizeof(pint_t)); // class_ro_t.baseProperties
+}
+
+template <typename A>
+const ld::Atom* Class<A>::getClassMethodList(ld::Internal& state, const ld::Atom* classAtom)
+{
+ const ld::Atom* metaClassAtom = ObjCData<A>::getPointerInContent(state, classAtom, 0); // class_t.isa
+ assert(metaClassAtom != NULL);
+ return Class<A>::getInstanceMethodList(state, metaClassAtom);
+}
+
+template <typename A>
+const ld::Atom* Class<A>::setInstanceMethodList(ld::Internal& state, const ld::Atom* classAtom,
+ const ld::Atom* methodListAtom, std::set<const ld::Atom*>& deadAtoms)
+{
+ const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
+ assert(classROAtom != NULL);
+ // if the base class does not already have a method list, we need to create an overlay
+ if ( getInstanceMethodList(state, classAtom) == NULL ) {
+ ClassROOverlayAtom<A>* overlay = new ClassROOverlayAtom<A>(classROAtom);
+ //fprintf(stderr, "replace class RO atom %p with %p for method list in class atom %s\n", classROAtom, overlay, classAtom->name());
+ overlay->addMethodListFixup();
+ ObjCData<A>::setPointerInContent(state, classAtom, 4*sizeof(pint_t), overlay); // class_t.data
+ deadAtoms.insert(classROAtom);
+ ObjCData<A>::setPointerInContent(state, overlay, class_ro_header_size() + 2*sizeof(pint_t), methodListAtom); // class_ro_t.baseMethods
+ return overlay;
+ }
+ ObjCData<A>::setPointerInContent(state, classROAtom, class_ro_header_size() + 2*sizeof(pint_t), methodListAtom); // class_ro_t.baseMethods
+ return NULL; // means classRO atom was not replaced
+}
+
+template <typename A>
+const ld::Atom* Class<A>::setInstanceProtocolList(ld::Internal& state, const ld::Atom* classAtom,
+ const ld::Atom* protocolListAtom, std::set<const ld::Atom*>& deadAtoms)
+{
+ const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
+ assert(classROAtom != NULL);
+ // if the base class does not already have a protocol list, we need to create an overlay
+ if ( getInstanceProtocolList(state, classAtom) == NULL ) {
+ ClassROOverlayAtom<A>* overlay = new ClassROOverlayAtom<A>(classROAtom);
+ //fprintf(stderr, "replace class RO atom %p with %p for protocol list in class atom %s\n", classROAtom, overlay, classAtom->name());
+ overlay->addProtocolListFixup();
+ ObjCData<A>::setPointerInContent(state, classAtom, 4*sizeof(pint_t), overlay); // class_t.data
+ deadAtoms.insert(classROAtom);
+ ObjCData<A>::setPointerInContent(state, overlay, class_ro_header_size() + 3*sizeof(pint_t), protocolListAtom); // class_ro_t.baseProtocols
+ return overlay;
+ }
+ //fprintf(stderr, "set class RO atom %p protocol list in class atom %s\n", classROAtom, classAtom->name());
+ ObjCData<A>::setPointerInContent(state, classROAtom, class_ro_header_size() + 3*sizeof(pint_t), protocolListAtom); // class_ro_t.baseProtocols
+ return NULL; // means classRO atom was not replaced
+}
+
+template <typename A>
+const ld::Atom* Class<A>::setClassProtocolList(ld::Internal& state, const ld::Atom* classAtom,
+ const ld::Atom* protocolListAtom, std::set<const ld::Atom*>& deadAtoms)
+{
+ // meta class also points to same protocol list as class
+ const ld::Atom* metaClassAtom = ObjCData<A>::getPointerInContent(state, classAtom, 0); // class_t.isa
+ //fprintf(stderr, "setClassProtocolList(), classAtom=%p %s, metaClass=%p %s\n", classAtom, classAtom->name(), metaClassAtom, metaClassAtom->name());
+ assert(metaClassAtom != NULL);
+ return setInstanceProtocolList(state, metaClassAtom, protocolListAtom, deadAtoms);
+}
+
+
+
+template <typename A>
+const ld::Atom* Class<A>::setInstancePropertyList(ld::Internal& state, const ld::Atom* classAtom,
+ const ld::Atom* propertyListAtom, std::set<const ld::Atom*>& deadAtoms)
+{
+ const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
+ assert(classROAtom != NULL);
+ // if the base class does not already have a property list, we need to create an overlay
+ if ( getInstancePropertyList(state, classAtom) == NULL ) {
+ ClassROOverlayAtom<A>* overlay = new ClassROOverlayAtom<A>(classROAtom);
+ //fprintf(stderr, "replace class RO atom %p with %p for property list in class atom %s\n", classROAtom, overlay, classAtom->name());
+ overlay->addPropertyListFixup();
+ ObjCData<A>::setPointerInContent(state, classAtom, 4*sizeof(pint_t), overlay); // class_t.data
+ deadAtoms.insert(classROAtom);
+ ObjCData<A>::setPointerInContent(state, overlay, class_ro_header_size() + 6*sizeof(pint_t), propertyListAtom); // class_ro_t.baseProperties
+ return overlay;
+ }
+ ObjCData<A>::setPointerInContent(state, classROAtom, class_ro_header_size() + 6*sizeof(pint_t), propertyListAtom); // class_ro_t.baseProperties
+ return NULL; // means classRO atom was not replaced
+}
+
+template <typename A>
+const ld::Atom* Class<A>::setClassMethodList(ld::Internal& state, const ld::Atom* classAtom,
+ const ld::Atom* methodListAtom, std::set<const ld::Atom*>& deadAtoms)
+{
+ // class methods is just instance methods of metaClass
+ const ld::Atom* metaClassAtom = ObjCData<A>::getPointerInContent(state, classAtom, 0); // class_t.isa
+ assert(metaClassAtom != NULL);
+ return setInstanceMethodList(state, metaClassAtom, methodListAtom, deadAtoms);
+}
+
+
+
+template <>
+void ClassROOverlayAtom<x86_64>::addMethodListFixup()
+{
+ const ld::Atom* targetAtom = this; // temporary
+ uint32_t offset = Class<x86_64>::class_ro_header_size() + 2*8; // class_ro_t.baseMethods
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, targetAtom));
+}
+
+template <>
+void ClassROOverlayAtom<arm>::addMethodListFixup()
+{
+ const ld::Atom* targetAtom = this; // temporary
+ uint32_t offset = Class<arm>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
+}
+
+template <>
+void ClassROOverlayAtom<x86>::addMethodListFixup()
+{
+ const ld::Atom* targetAtom = this; // temporary
+ uint32_t offset = Class<x86>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
+}
+
+
+
+template <>
+void ClassROOverlayAtom<x86_64>::addProtocolListFixup()
+{
+ const ld::Atom* targetAtom = this; // temporary
+ uint32_t offset = Class<x86_64>::class_ro_header_size() + 3*8; // class_ro_t.baseProtocols
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, targetAtom));
+}
+
+template <>
+void ClassROOverlayAtom<arm>::addProtocolListFixup()
+{
+ const ld::Atom* targetAtom = this; // temporary
+ uint32_t offset = Class<arm>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
+}
+
+template <>
+void ClassROOverlayAtom<x86>::addProtocolListFixup()
+{
+ const ld::Atom* targetAtom = this; // temporary
+ uint32_t offset = Class<x86>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
+}
+
+
+template <>
+void ClassROOverlayAtom<x86_64>::addPropertyListFixup()
+{
+ const ld::Atom* targetAtom = this; // temporary
+ uint32_t offset = Class<x86_64>::class_ro_header_size() + 6*8; // class_ro_t.baseProperties
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, targetAtom));
+}
+
+template <>
+void ClassROOverlayAtom<arm>::addPropertyListFixup()
+{
+ const ld::Atom* targetAtom = this; // temporary
+ uint32_t offset = Class<arm>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
+}
+
+template <>
+void ClassROOverlayAtom<x86>::addPropertyListFixup()
+{
+ const ld::Atom* targetAtom = this; // temporary
+ uint32_t offset = Class<x86>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
+}
+
+
+
+
+//
+// Encapsulates merging of ObjC categories
+//
+template <typename A>
+class OptimizeCategories {
+public:
+ static void doit(const Options& opts, ld::Internal& state);
+ static bool hasInstanceMethods(ld::Internal& state, const std::vector<const ld::Atom*>* categories);
+ static bool hasClassMethods(ld::Internal& state, const std::vector<const ld::Atom*>* categories);
+ static bool hasProtocols(ld::Internal& state, const std::vector<const ld::Atom*>* categories);
+ static bool hasProperties(ld::Internal& state, const std::vector<const ld::Atom*>* categories);
+
+
+ static unsigned int class_ro_baseMethods_offset();
+private:
+ typedef typename A::P::uint_t pint_t;
+
+};
+
+
+template <typename A>
+bool OptimizeCategories<A>::hasInstanceMethods(ld::Internal& state, const std::vector<const ld::Atom*>* categories)
+{
+ for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
+ const ld::Atom* categoryAtom = *it;
+ const ld::Atom* methodList = Category<A>::getInstanceMethods(state, categoryAtom);
+ if ( methodList != NULL ) {
+ if ( MethodList<A>::count(state, methodList) > 0 )
+ return true;
+ }
+ }
+ return false;
+}
+
+
+template <typename A>
+bool OptimizeCategories<A>::hasClassMethods(ld::Internal& state, const std::vector<const ld::Atom*>* categories)
+{
+ for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
+ const ld::Atom* categoryAtom = *it;
+ const ld::Atom* methodList = Category<A>::getClassMethods(state, categoryAtom);
+ if ( methodList != NULL ) {
+ if ( MethodList<A>::count(state, methodList) > 0 )
+ return true;
+ }
+ }
+ return false;
+}
+
+template <typename A>
+bool OptimizeCategories<A>::hasProtocols(ld::Internal& state, const std::vector<const ld::Atom*>* categories)
+{
+ for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
+ const ld::Atom* categoryAtom = *it;
+ const ld::Atom* protocolListAtom = Category<A>::getProtocols(state, categoryAtom);
+ if ( protocolListAtom != NULL ) {
+ if ( ProtocolList<A>::count(state, protocolListAtom) > 0 ) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+template <typename A>
+bool OptimizeCategories<A>::hasProperties(ld::Internal& state, const std::vector<const ld::Atom*>* categories)
+{
+ for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
+ const ld::Atom* categoryAtom = *it;
+ const ld::Atom* propertyListAtom = Category<A>::getProperties(state, categoryAtom);
+ if ( propertyListAtom != NULL ) {
+ if ( PropertyList<A>::count(state, propertyListAtom) > 0 )
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+//
+// Helper for std::remove_if
+//
+class OptimizedAway {
+public:
+ OptimizedAway(const std::set<const ld::Atom*>& oa) : _dead(oa) {}
+ bool operator()(const ld::Atom* atom) const {
+ return ( _dead.count(atom) != 0 );
+ }
+private:
+ const std::set<const ld::Atom*>& _dead;
+};
+
+ struct AtomSorter
+ {
+ bool operator()(const Atom* left, const Atom* right)
+ {
+ // sort by file ordinal, then object address, then zero size, then symbol name
+ // only file based atoms are supported (file() != NULL)
+ if (left==right) return false;
+ const File *leftf = left->file();
+ const File *rightf = right->file();
+
+ if (leftf == rightf) {
+ if (left->objectAddress() != right->objectAddress()) {
+ return left->objectAddress() < right->objectAddress();
+ } else {
+ // for atoms in the same file with the same address, zero sized
+ // atoms must sort before nonzero sized atoms
+ if ((left->size() == 0 && right->size() > 0) || (left->size() > 0 && right->size() == 0))
+ return left->size() < right->size();
+ return strcmp(left->name(), right->name());
+ }
+ }
+ return (leftf->ordinal() < rightf->ordinal());
+ }
+ };
+
+ static void sortAtomVector(std::vector<const Atom*> &atoms) {
+ std::sort(atoms.begin(), atoms.end(), AtomSorter());
+ }
+
+template <typename A>
+void OptimizeCategories<A>::doit(const Options& opts, ld::Internal& state)
+{
+ // first find all categories referenced by __objc_nlcatlist section
+ std::set<const ld::Atom*> nlcatListAtoms;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( (strcmp(sect->sectionName(), "__objc_nlcatlist") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) ) {
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* categoryListElementAtom = *ait;
+ for (unsigned int offset=0; offset < categoryListElementAtom->size(); offset += sizeof(pint_t)) {
+ const ld::Atom* categoryAtom = ObjCData<A>::getPointerInContent(state, categoryListElementAtom, offset);
+ //fprintf(stderr, "offset=%d, cat=%p %s\n", offset, categoryAtom, categoryAtom->name());
+ assert(categoryAtom != NULL);
+ nlcatListAtoms.insert(categoryAtom);
+ }
+ }
+ }
+ }
+
+ // build map of all classes in this image that have categories on them
+ typedef std::map<const ld::Atom*, std::vector<const ld::Atom*>*> CatMap;
+ CatMap classToCategories;
+ std::vector<const ld::Atom*> classOrder;
+ std::set<const ld::Atom*> deadAtoms;
+ ld::Internal::FinalSection* methodListSection = NULL;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() == ld::Section::typeObjC2CategoryList ) {
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* categoryListElementAtom = *ait;
+ bool hasAddend;
+ const ld::Atom* categoryAtom = ObjCData<A>::getPointerInContent(state, categoryListElementAtom, 0, &hasAddend);
+ if ( hasAddend || (categoryAtom->symbolTableInclusion() == ld::Atom::symbolTableNotIn)) {
+ //<rdar://problem/8309530> gcc-4.0 uses 'L' labels on categories which disables this optimization
+ //warning("__objc_catlist element does not point to start of category");
+ continue;
+ }
+ assert(categoryAtom != NULL);
+ assert(categoryAtom->size() >= Category<A>::size());
+ // ignore categories also in __objc_nlcatlist
+ if ( nlcatListAtoms.count(categoryAtom) != 0 )
+ continue;
+ const ld::Atom* categoryOnClassAtom = Category<A>::getClass(state, categoryAtom);
+ assert(categoryOnClassAtom != NULL);
+ if ( categoryOnClassAtom->definition() != ld::Atom::definitionProxy ) {
+ // only look at classes defined in this image
+ CatMap::iterator pos = classToCategories.find(categoryOnClassAtom);
+ if ( pos == classToCategories.end() ) {
+ classToCategories[categoryOnClassAtom] = new std::vector<const ld::Atom*>();
+ classOrder.push_back(categoryOnClassAtom);
+ }
+ classToCategories[categoryOnClassAtom]->push_back(categoryAtom);
+ // mark category atom and catlist atom as dead
+ deadAtoms.insert(categoryAtom);
+ deadAtoms.insert(categoryListElementAtom);
+ }
+ }
+ }
+ // record method list section
+ if ( (strcmp(sect->sectionName(), "__objc_const") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+ methodListSection = sect;
+ }
+
+ // if found some categories
+ if ( classToCategories.size() != 0 ) {
+ assert(methodListSection != NULL);
+ sortAtomVector(classOrder);
+ // alter each class definition to have new method list which includes all category methods
+ for (std::vector<const ld::Atom*>::iterator it = classOrder.begin(); it != classOrder.end(); it++) {
+ const ld::Atom* classAtom = *it;
+ const std::vector<const ld::Atom*>* categories = classToCategories[classAtom];
+ assert(categories->size() != 0);
+ // if any category adds instance methods, generate new merged method list, and replace
+ if ( OptimizeCategories<A>::hasInstanceMethods(state, categories) ) {
+ const ld::Atom* baseInstanceMethodListAtom = Class<A>::getInstanceMethodList(state, classAtom);
+ const ld::Atom* newInstanceMethodListAtom = new MethodListAtom<A>(state, baseInstanceMethodListAtom, false, categories, deadAtoms);
+ const ld::Atom* newClassRO = Class<A>::setInstanceMethodList(state, classAtom, newInstanceMethodListAtom, deadAtoms);
+ // add new method list to final sections
+ methodListSection->atoms.push_back(newInstanceMethodListAtom);
+ if ( newClassRO != NULL ) {
+ assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
+ methodListSection->atoms.push_back(newClassRO);
+ }
+ }
+ // if any category adds class methods, generate new merged method list, and replace
+ if ( OptimizeCategories<A>::hasClassMethods(state, categories) ) {
+ const ld::Atom* baseClassMethodListAtom = Class<A>::getClassMethodList(state, classAtom);
+ const ld::Atom* newClassMethodListAtom = new MethodListAtom<A>(state, baseClassMethodListAtom, true, categories, deadAtoms);
+ const ld::Atom* newClassRO = Class<A>::setClassMethodList(state, classAtom, newClassMethodListAtom, deadAtoms);
+ // add new method list to final sections
+ methodListSection->atoms.push_back(newClassMethodListAtom);
+ if ( newClassRO != NULL ) {
+ assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
+ methodListSection->atoms.push_back(newClassRO);
+ }
+ }
+ // if any category adds protocols, generate new merged protocol list, and replace
+ if ( OptimizeCategories<A>::hasProtocols(state, categories) ) {
+ const ld::Atom* baseProtocolListAtom = Class<A>::getInstanceProtocolList(state, classAtom);
+ const ld::Atom* newProtocolListAtom = new ProtocolListAtom<A>(state, baseProtocolListAtom, categories, deadAtoms);
+ const ld::Atom* newClassRO = Class<A>::setInstanceProtocolList(state, classAtom, newProtocolListAtom, deadAtoms);
+ const ld::Atom* newMetaClassRO = Class<A>::setClassProtocolList(state, classAtom, newProtocolListAtom, deadAtoms);
+ // add new protocol list to final sections
+ methodListSection->atoms.push_back(newProtocolListAtom);
+ if ( newClassRO != NULL ) {
+ assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
+ methodListSection->atoms.push_back(newClassRO);
+ }
+ if ( newMetaClassRO != NULL ) {
+ assert(strcmp(newMetaClassRO->section().sectionName(), "__objc_const") == 0);
+ methodListSection->atoms.push_back(newMetaClassRO);
+ }
+ }
+ // if any category adds properties, generate new merged property list, and replace
+ if ( OptimizeCategories<A>::hasProperties(state, categories) ) {
+ const ld::Atom* basePropertyListAtom = Class<A>::getInstancePropertyList(state, classAtom);
+ const ld::Atom* newPropertyListAtom = new PropertyListAtom<A>(state, basePropertyListAtom, categories, deadAtoms);
+ const ld::Atom* newClassRO = Class<A>::setInstancePropertyList(state, classAtom, newPropertyListAtom, deadAtoms);
+ // add new property list to final sections
+ methodListSection->atoms.push_back(newPropertyListAtom);
+ if ( newClassRO != NULL ) {
+ assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
+ methodListSection->atoms.push_back(newClassRO);
+ }
+ }
+
+ }
+
+ // remove dead atoms
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ sect->atoms.erase(std::remove_if(sect->atoms.begin(), sect->atoms.end(), OptimizedAway(deadAtoms)), sect->atoms.end());
+ }
+ }
+}
+
+
+template <typename A>
+MethodListAtom<A>::MethodListAtom(ld::Internal& state, const ld::Atom* baseMethodList, bool meta,
+ const std::vector<const ld::Atom*>* categories, std::set<const ld::Atom*>& deadAtoms)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), _file(NULL), _methodCount(0)
+{
+ unsigned int fixupCount = 0;
+ std::set<const ld::Atom*> baseMethodListMethodNameAtoms;
+ // if base class has method list, then associate new method list with file defining class
+ if ( baseMethodList != NULL ) {
+ _file = baseMethodList->file();
+ // calculate total size of merge method lists
+ _methodCount = MethodList<A>::count(state, baseMethodList);
+ deadAtoms.insert(baseMethodList);
+ fixupCount = baseMethodList->fixupsEnd() - baseMethodList->fixupsBegin();
+ for (ld::Fixup::iterator fit=baseMethodList->fixupsBegin(); fit != baseMethodList->fixupsEnd(); ++fit) {
+ if ( (fit->offsetInAtom - 8) % (3*sizeof(pint_t)) == 0 ) {
+ assert(fit->binding == ld::Fixup::bindingsIndirectlyBound && "malformed method list");
+ const ld::Atom* target = state.indirectBindingTable[fit->u.bindingIndex];
+ assert(target->contentType() == ld::Atom::typeCString && "malformed method list");
+ baseMethodListMethodNameAtoms.insert(target);
+ }
+ }
+ }
+ for (std::vector<const ld::Atom*>::const_iterator ait=categories->begin(); ait != categories->end(); ++ait) {
+ const ld::Atom* categoryMethodListAtom;
+ if ( meta )
+ categoryMethodListAtom = Category<A>::getClassMethods(state, *ait);
+ else
+ categoryMethodListAtom = Category<A>::getInstanceMethods(state, *ait);
+ if ( categoryMethodListAtom != NULL ) {
+ _methodCount += MethodList<A>::count(state, categoryMethodListAtom);
+ fixupCount += (categoryMethodListAtom->fixupsEnd() - categoryMethodListAtom->fixupsBegin());
+ deadAtoms.insert(categoryMethodListAtom);
+ // if base class did not have method list, associate new method list with file the defined category
+ if ( _file == NULL )
+ _file = categoryMethodListAtom->file();
+ }
+ }
+ //if ( baseMethodList != NULL )
+ // fprintf(stderr, "total merged method count=%u for baseMethodList=%s\n", _methodCount, baseMethodList->name());
+ //else
+ // fprintf(stderr, "total merged method count=%u\n", _methodCount);
+ //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
+
+ // copy fixups and adjust offsets (in reverse order to simulator objc runtime)
+ _fixups.reserve(fixupCount);
+ uint32_t slide = 0;
+ std::set<const ld::Atom*> categoryMethodNameAtoms;
+ for (std::vector<const ld::Atom*>::const_reverse_iterator rit=categories->rbegin(); rit != categories->rend(); ++rit) {
+ const ld::Atom* categoryMethodListAtom;
+ if ( meta )
+ categoryMethodListAtom = Category<A>::getClassMethods(state, *rit);
+ else
+ categoryMethodListAtom = Category<A>::getInstanceMethods(state, *rit);
+ if ( categoryMethodListAtom != NULL ) {
+ for (ld::Fixup::iterator fit=categoryMethodListAtom->fixupsBegin(); fit != categoryMethodListAtom->fixupsEnd(); ++fit) {
+ ld::Fixup fixup = *fit;
+ fixup.offsetInAtom += slide;
+ _fixups.push_back(fixup);
+ if ( (fixup.offsetInAtom - 8) % (3*sizeof(pint_t)) == 0 ) {
+ // <rdar://problem/8642343> warning when a method is overridden in a category in the same link unit
+ assert(fixup.binding == ld::Fixup::bindingsIndirectlyBound && "malformed category method list");
+ const ld::Atom* target = state.indirectBindingTable[fixup.u.bindingIndex];
+ assert(target->contentType() == ld::Atom::typeCString && "malformed method list");
+ // this objc pass happens after cstrings are coalesced, so we can just compare the atom addres instead of its content
+ if ( baseMethodListMethodNameAtoms.count(target) != 0 ) {
+ warning("%s method '%s' in category from %s overrides method from class in %s",
+ (meta ? "meta" : "instance"), target->rawContentPointer(),
+ categoryMethodListAtom->file()->path(), baseMethodList->file()->path() );
+ }
+ if ( categoryMethodNameAtoms.count(target) != 0 ) {
+ warning("%s method '%s' in category from %s conflicts with same method from another category",
+ (meta ? "meta" : "instance"), target->rawContentPointer(),
+ categoryMethodListAtom->file()->path());
+ }
+ categoryMethodNameAtoms.insert(target);
+ }
+ }
+ slide += 3*sizeof(pint_t) * MethodList<A>::count(state, categoryMethodListAtom);
+ }
+ }
+ // add method list from base class last
+ if ( baseMethodList != NULL ) {
+ for (ld::Fixup::iterator fit=baseMethodList->fixupsBegin(); fit != baseMethodList->fixupsEnd(); ++fit) {
+ ld::Fixup fixup = *fit;
+ fixup.offsetInAtom += slide;
+ _fixups.push_back(fixup);
+ }
+ }
+}
+
+
+template <typename A>
+ProtocolListAtom<A>::ProtocolListAtom(ld::Internal& state, const ld::Atom* baseProtocolList,
+ const std::vector<const ld::Atom*>* categories, std::set<const ld::Atom*>& deadAtoms)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), _file(NULL), _protocolCount(0)
+{
+ unsigned int fixupCount = 0;
+ if ( baseProtocolList != NULL ) {
+ // if base class has protocol list, then associate new protocol list with file defining class
+ _file = baseProtocolList->file();
+ // calculate total size of merged protocol list
+ _protocolCount = ProtocolList<A>::count(state, baseProtocolList);
+ deadAtoms.insert(baseProtocolList);
+ fixupCount = baseProtocolList->fixupsEnd() - baseProtocolList->fixupsBegin();
+ }
+ for (std::vector<const ld::Atom*>::const_iterator ait=categories->begin(); ait != categories->end(); ++ait) {
+ const ld::Atom* categoryProtocolListAtom = Category<A>::getProtocols(state, *ait);
+ if ( categoryProtocolListAtom != NULL ) {
+ _protocolCount += ProtocolList<A>::count(state, categoryProtocolListAtom);
+ fixupCount += (categoryProtocolListAtom->fixupsEnd() - categoryProtocolListAtom->fixupsBegin());
+ deadAtoms.insert(categoryProtocolListAtom);
+ // if base class did not have protocol list, associate new protocol list with file the defined category
+ if ( _file == NULL )
+ _file = categoryProtocolListAtom->file();
+ }
+ }
+ //fprintf(stderr, "total merged protocol count=%u\n", _protocolCount);
+ //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
+
+ // copy fixups and adjust offsets
+ _fixups.reserve(fixupCount);
+ uint32_t slide = 0;
+ for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
+ const ld::Atom* categoryProtocolListAtom = Category<A>::getProtocols(state, *it);
+ if ( categoryProtocolListAtom != NULL ) {
+ for (ld::Fixup::iterator fit=categoryProtocolListAtom->fixupsBegin(); fit != categoryProtocolListAtom->fixupsEnd(); ++fit) {
+ ld::Fixup fixup = *fit;
+ fixup.offsetInAtom += slide;
+ _fixups.push_back(fixup);
+ //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
+ // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
+ }
+ slide += sizeof(pint_t) * ProtocolList<A>::count(state, categoryProtocolListAtom);
+ }
+ }
+ // add method list from base class last
+ if ( baseProtocolList != NULL ) {
+ for (ld::Fixup::iterator fit=baseProtocolList->fixupsBegin(); fit != baseProtocolList->fixupsEnd(); ++fit) {
+ ld::Fixup fixup = *fit;
+ fixup.offsetInAtom += slide;
+ _fixups.push_back(fixup);
+ }
+ }
+}
+
+
+template <typename A>
+PropertyListAtom<A>::PropertyListAtom(ld::Internal& state, const ld::Atom* basePropertyList,
+ const std::vector<const ld::Atom*>* categories, std::set<const ld::Atom*>& deadAtoms)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), _file(NULL), _propertyCount(0)
+{
+ unsigned int fixupCount = 0;
+ if ( basePropertyList != NULL ) {
+ // if base class has property list, then associate new property list with file defining class
+ _file = basePropertyList->file();
+ // calculate total size of merged property list
+ _propertyCount = PropertyList<A>::count(state, basePropertyList);
+ deadAtoms.insert(basePropertyList);
+ fixupCount = basePropertyList->fixupsEnd() - basePropertyList->fixupsBegin();
+ }
+ for (std::vector<const ld::Atom*>::const_iterator ait=categories->begin(); ait != categories->end(); ++ait) {
+ const ld::Atom* categoryPropertyListAtom = Category<A>::getProperties(state, *ait);
+ if ( categoryPropertyListAtom != NULL ) {
+ _propertyCount += PropertyList<A>::count(state, categoryPropertyListAtom);
+ fixupCount += (categoryPropertyListAtom->fixupsEnd() - categoryPropertyListAtom->fixupsBegin());
+ deadAtoms.insert(categoryPropertyListAtom);
+ // if base class did not have property list, associate new property list with file the defined category
+ if ( _file == NULL )
+ _file = categoryPropertyListAtom->file();
+ }
+ }
+ //fprintf(stderr, "total merged property count=%u\n", _propertyCount);
+ //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
+
+ // copy fixups and adjust offsets
+ _fixups.reserve(fixupCount);
+ uint32_t slide = 0;
+ for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
+ const ld::Atom* categoryPropertyListAtom = Category<A>::getProperties(state, *it);
+ if ( categoryPropertyListAtom != NULL ) {
+ for (ld::Fixup::iterator fit=categoryPropertyListAtom->fixupsBegin(); fit != categoryPropertyListAtom->fixupsEnd(); ++fit) {
+ ld::Fixup fixup = *fit;
+ fixup.offsetInAtom += slide;
+ _fixups.push_back(fixup);
+ //fprintf(stderr, "offset=0x%08X, binding=%d\n", fixup.offsetInAtom, fixup.binding);
+ //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
+ // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
+ //else if ( fixup.binding == ld::Fixup::bindingsIndirectlyBound )
+ // fprintf(stderr, "offset=0x%08X, indirect index=%u, name=%s\n", fixup.offsetInAtom, fixup.u.bindingIndex,
+ // (char*)(state.indirectBindingTable[fixup.u.bindingIndex]->rawContentPointer()));
+ }
+ slide += 2*sizeof(pint_t) * PropertyList<A>::count(state, categoryPropertyListAtom);
+ }
+ }
+ // add method list from base class last
+ if ( basePropertyList != NULL ) {
+ for (ld::Fixup::iterator fit=basePropertyList->fixupsBegin(); fit != basePropertyList->fixupsEnd(); ++fit) {
+ ld::Fixup fixup = *fit;
+ fixup.offsetInAtom += slide;
+ _fixups.push_back(fixup);
+ }
+ }
+}
+
+
+
+
+void doPass(const Options& opts, ld::Internal& state)
+{
+ // only make image info section if objc was used
+ if ( state.objcObjectConstraint != ld::File::objcConstraintNone ) {
+
+ // verify dylibs are GC compatible with object files
+ if ( state.objcObjectConstraint != state.objcDylibConstraint ) {
+ if ( (state.objcDylibConstraint == ld::File::objcConstraintRetainRelease)
+ && (state.objcObjectConstraint == ld::File::objcConstraintGC) ) {
+ throw "Linked dylibs built for retain/release but object files built for GC-only";
+ }
+ else if ( (state.objcDylibConstraint == ld::File::objcConstraintGC)
+ && (state.objcObjectConstraint == ld::File::objcConstraintRetainRelease) ) {
+ throw "Linked dylibs built for GC-only but object files built for retain/release";
+ }
+ }
+
+ const bool compaction = opts.objcGcCompaction();
+
+ // add image info atom
+ switch ( opts.architecture() ) {
+#if SUPPORT_ARCH_x86_64
+ case CPU_TYPE_X86_64:
+ state.addAtom(*new ObjCImageInfoAtom<x86_64>(state.objcObjectConstraint, compaction,
+ true));
+ break;
+#endif
+#if SUPPORT_ARCH_i386
+ case CPU_TYPE_I386:
+ state.addAtom(*new ObjCImageInfoAtom<x86>(state.objcObjectConstraint, compaction,
+ opts.objCABIVersion2POverride() ? true : false));
+ break;
+#endif
+ case CPU_TYPE_ARM:
+ state.addAtom(*new ObjCImageInfoAtom<arm>(state.objcObjectConstraint, compaction,
+ true));
+ break;
+ default:
+ assert(0 && "unknown objc arch");
+ }
+ }
+
+ if ( opts.objcCategoryMerging() ) {
+ // optimize classes defined in this linkage unit by merging in categories also in this linkage unit
+ switch ( opts.architecture() ) {
+#if SUPPORT_ARCH_x86_64
+ case CPU_TYPE_X86_64:
+ OptimizeCategories<x86_64>::doit(opts, state);
+ break;
+#endif
+#if SUPPORT_ARCH_i386
+ case CPU_TYPE_I386:
+ // disable optimization until fully tested
+ if ( opts.objCABIVersion2POverride() )
+ OptimizeCategories<x86>::doit(opts, state);
+ break;
+#endif
+#if SUPPORT_ARCH_arm_any
+ case CPU_TYPE_ARM:
+ // disable optimization until fully tested
+ OptimizeCategories<arm>::doit(opts, state);
+ break;
+#endif
+ default:
+ assert(0 && "unknown objc arch");
+ }
+ }
+}
+
+
+} // namespace objc
+} // namespace passes
+} // namespace ld
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __OBJC_H__
+#define __OBJC_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace objc {
+
+// called by linker to optimize ObjC data structures
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace objc
+} // namespace passes
+} // namespace ld
+
+#endif // __OBJC_H__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <mach/machine.h>
+
+#include <vector>
+#include <map>
+
+#include "ld.hpp"
+#include "order.h"
+
+namespace ld {
+namespace passes {
+namespace order {
+
+//
+// The purpose of this pass is to take the graph of all Atoms and produce an ordered
+// sequence of atoms. The constraints are that: 1) all Atoms of the same Segment must
+// be contiguous, 2) all Atoms of the same Section must be contigous, 3) Atoms specified
+// in an order are sequenced as in the order file and before Atoms not specified,
+// 4) Atoms in the same section from the same .o file should be contiguous and sequenced
+// in the same order they were in the .o file, 5) Atoms in the same Section but which came
+// from different .o files should be sequenced in the same order that the .o files
+// were passed to the linker (i.e. command line order).
+//
+// The way this is implemented is that the linker passes a "base ordinal" to each File
+// as it is constructed. Add each atom has an objectAddress() method. Then
+// sorting is just sorting by section, then by file ordinal, then by object address.
+//
+// If an -order_file is specified, it gets more complicated. First, an override-ordinal map
+// is created. It causes the sort routine to ignore the value returned by ordinal() and objectAddress()
+// and use the override value instead. Next some Atoms must be laid out consecutively
+// (e.g. hand written assembly that does not end with return, but rather falls into
+// the next label). This is modeled in via a kindNoneFollowOn fixup. The use of
+// kindNoneFollowOn fixups produces "clusters" of atoms that must stay together.
+// If an order_file tries to move one atom, it may need to move a whole cluster. The
+// algorithm to do this models clusters using two maps. The "starts" maps maps any
+// atom in a cluster to the first Atom in the cluster. The "nexts" maps an Atom in a
+// cluster to the next Atom in the cluster. With this in place, while processing an
+// order_file, if any entry is in a cluster (in "starts" map), then the entire cluster is
+// given ordinal overrides.
+//
+
+class Layout
+{
+public:
+ Layout(const Options& opts, ld::Internal& state);
+ void doPass();
+private:
+
+ class Comparer {
+ public:
+ Comparer(const Layout& l) : _layout(l) {}
+ bool operator()(const ld::Atom* left, const ld::Atom* right);
+ private:
+ const Layout& _layout;
+ };
+
+ class CStringEquals {
+ public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+ };
+ typedef __gnu_cxx::hash_map<const char*, const ld::Atom*, __gnu_cxx::hash<const char*>, CStringEquals> NameToAtom;
+
+ typedef std::map<const ld::Atom*, const ld::Atom*> AtomToAtom;
+
+ typedef std::map<const ld::Atom*, uint32_t> AtomToOrdinal;
+
+ const ld::Atom* findAtom(const Options::OrderedSymbol& orderedSymbol);
+ void buildNameTable();
+ void buildFollowOnTables();
+ void buildOrdinalOverrideMap();
+ const ld::Atom* follower(const ld::Atom* atom);
+ static bool matchesObjectFile(const ld::Atom* atom, const char* objectFileLeafName);
+ bool possibleToOrder(const ld::Internal::FinalSection*);
+
+ const Options& _options;
+ ld::Internal& _state;
+ AtomToAtom _followOnStarts;
+ AtomToAtom _followOnNexts;
+ NameToAtom _nameTable;
+ std::vector<const ld::Atom*> _nameCollisionAtoms;
+ AtomToOrdinal _ordinalOverrideMap;
+ Comparer _comparer;
+ bool _haveOrderFile;
+
+ static bool _s_log;
+};
+
+bool Layout::_s_log = false;
+
+Layout::Layout(const Options& opts, ld::Internal& state)
+ : _options(opts), _state(state), _comparer(*this), _haveOrderFile(opts.orderedSymbolsCount() != 0)
+{
+}
+
+
+bool Layout::Comparer::operator()(const ld::Atom* left, const ld::Atom* right)
+{
+ if ( left == right )
+ return false;
+
+ // magic section$start symbol always sorts to the start of its section
+ if ( left->contentType() == ld::Atom::typeSectionStart )
+ return true;
+ if ( right->contentType() == ld::Atom::typeSectionStart )
+ return false;
+
+ // if an -order_file is specified, then sorting is altered to sort those symbols first
+ if ( _layout._haveOrderFile ) {
+ AtomToOrdinal::const_iterator leftPos = _layout._ordinalOverrideMap.find(left);
+ AtomToOrdinal::const_iterator rightPos = _layout._ordinalOverrideMap.find(right);
+ AtomToOrdinal::const_iterator end = _layout._ordinalOverrideMap.end();
+ if ( leftPos != end ) {
+ if ( rightPos != end ) {
+ // both left and right are overridden, so compare overridden ordinals
+ return leftPos->second < rightPos->second;
+ }
+ else {
+ // left is overridden and right is not, so left < right
+ return true;
+ }
+ }
+ else {
+ if ( rightPos != end ) {
+ // right is overridden and left is not, so right < left
+ return false;
+ }
+ else {
+ // neither are overridden,
+ // fall into default sorting below
+ }
+ }
+ }
+
+ // magic section$end symbol always sorts to the end of its section
+ if ( left->contentType() == ld::Atom::typeSectionEnd )
+ return false;
+ if ( right->contentType() == ld::Atom::typeSectionEnd )
+ return true;
+
+ // the __common section can have real or tentative definitions
+ // we want the real ones to sort before tentative ones
+ bool leftIsTent = (left->definition() == ld::Atom::definitionTentative);
+ bool rightIsTent = (right->definition() == ld::Atom::definitionTentative);
+ if ( leftIsTent != rightIsTent )
+ return rightIsTent;
+
+#if 0
+ // initializers are auto sorted to start of section
+ if ( !fInitializerSet.empty() ) {
+ bool leftFirst = (fInitializerSet.count(left) != 0);
+ bool rightFirst = (fInitializerSet.count(right) != 0);
+ if ( leftFirst != rightFirst )
+ return leftFirst;
+ }
+
+ // terminators are auto sorted to end of section
+ if ( !fTerminatorSet.empty() ) {
+ bool leftLast = (fTerminatorSet.count(left) != 0);
+ bool rightLast = (fTerminatorSet.count(right) != 0);
+ if ( leftLast != rightLast )
+ return rightLast;
+ }
+#endif
+
+ // sort by .o order
+ const ld::File* leftFile = left->file();
+ const ld::File* rightFile = right->file();
+ // <rdar://problem/10830126> properly sort if on file is NULL and the other is not
+ ld::File::Ordinal leftFileOrdinal = (leftFile != NULL) ? leftFile->ordinal() : ld::File::Ordinal::NullOrdinal();
+ ld::File::Ordinal rightFileOrdinal = (rightFile != NULL) ? rightFile->ordinal() : ld::File::Ordinal::NullOrdinal();
+ if ( leftFileOrdinal != rightFileOrdinal )
+ return leftFileOrdinal< rightFileOrdinal;
+
+ // tentative defintions have no address in .o file, they are traditionally laid out by name
+ if ( leftIsTent && rightIsTent )
+ return (strcmp(left->name(), right->name()) < 0);
+
+ // lastly sort by atom address
+ int64_t addrDiff = left->objectAddress() - right->objectAddress();
+ if ( addrDiff == 0 ) {
+ // have same address so one might be an alias, and aliases need to sort before target
+ bool leftIsAlias = left->isAlias();
+ bool rightIsAlias = right->isAlias();
+ if ( leftIsAlias != rightIsAlias )
+ return leftIsAlias;
+
+ // both at same address, sort by name
+ return (strcmp(left->name(), right->name()) < 0);
+ }
+ return (addrDiff < 0);
+}
+
+bool Layout::matchesObjectFile(const ld::Atom* atom, const char* objectFileLeafName)
+{
+ if ( objectFileLeafName == NULL )
+ return true;
+ const char* atomFullPath = atom->file()->path();
+ const char* lastSlash = strrchr(atomFullPath, '/');
+ if ( lastSlash != NULL ) {
+ if ( strcmp(&lastSlash[1], objectFileLeafName) == 0 )
+ return true;
+ }
+ else {
+ if ( strcmp(atomFullPath, objectFileLeafName) == 0 )
+ return true;
+ }
+ return false;
+}
+
+
+bool Layout::possibleToOrder(const ld::Internal::FinalSection* sect)
+{
+ // atoms in only some sections can have order_file applied
+ switch ( sect->type() ) {
+ case ld::Section::typeUnclassified:
+ case ld::Section::typeCode:
+ case ld::Section::typeZeroFill:
+ return true;
+ case ld::Section::typeImportProxies:
+ return false;
+ default:
+ // if section has command line aliases, then we must apply ordering so aliases layout before targets
+ if ( _options.haveCmdLineAliases() ) {
+ for (std::vector<const ld::Atom*>::const_iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ if ( atom->isAlias() )
+ return true;
+ }
+ }
+ break;
+ }
+ return false;
+}
+
+void Layout::buildNameTable()
+{
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ // some sections are not worth scanning for names
+ if ( ! possibleToOrder(sect) )
+ continue;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ if ( atom->symbolTableInclusion() == ld::Atom::symbolTableIn ) {
+ const char* name = atom->name();
+ if ( name != NULL) {
+ // static function or data
+ NameToAtom::iterator pos = _nameTable.find(name);
+ if ( pos == _nameTable.end() )
+ _nameTable[name] = atom;
+ else {
+ const ld::Atom* existing = _nameTable[name];
+ if ( existing != NULL ) {
+ _nameCollisionAtoms.push_back(existing);
+ _nameTable[name] = NULL; // collision, denote with NULL
+ }
+ _nameCollisionAtoms.push_back(atom);
+ }
+ }
+ }
+ }
+ }
+ if ( _s_log ) {
+ fprintf(stderr, "buildNameTable() _nameTable:\n");
+ for(NameToAtom::iterator it=_nameTable.begin(); it != _nameTable.end(); ++it)
+ fprintf(stderr, " %p <- %s\n", it->second, it->first);
+ fprintf(stderr, "buildNameTable() _nameCollisionAtoms:\n");
+ for(std::vector<const ld::Atom*>::iterator it=_nameCollisionAtoms.begin(); it != _nameCollisionAtoms.end(); ++it)
+ fprintf(stderr, " %p, %s\n", *it, (*it)->name());
+ }
+}
+
+
+const ld::Atom* Layout::findAtom(const Options::OrderedSymbol& orderedSymbol)
+{
+ // look for name in _nameTable
+ NameToAtom::iterator pos = _nameTable.find(orderedSymbol.symbolName);
+ if ( pos != _nameTable.end() ) {
+ if ( (pos->second != NULL) && matchesObjectFile(pos->second, orderedSymbol.objectFileName) ) {
+ //fprintf(stderr, "found %s in hash table\n", orderedSymbol.symbolName);
+ return pos->second;
+ }
+ if ( pos->second == NULL ) {
+ // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way
+ if ( ( orderedSymbol.objectFileName == NULL) && _options.printOrderFileStatistics() ) {
+ warning("%s specified in order_file but it exists in multiple .o files. "
+ "Prefix symbol with .o filename in order_file to disambiguate", orderedSymbol.symbolName);
+ }
+ for (std::vector<const ld::Atom*>::iterator it=_nameCollisionAtoms.begin(); it != _nameCollisionAtoms.end(); it++) {
+ const ld::Atom* atom = *it;
+ if ( strcmp(atom->name(), orderedSymbol.symbolName) == 0 ) {
+ if ( matchesObjectFile(atom, orderedSymbol.objectFileName) ) {
+ return atom;
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+const ld::Atom* Layout::follower(const ld::Atom* atom)
+{
+ for (const ld::Atom* a = _followOnStarts[atom]; a != NULL; a = _followOnNexts[a]) {
+ assert(a != NULL);
+ if ( _followOnNexts[a] == atom ) {
+ return a;
+ }
+ }
+ // no follower, first in chain
+ return NULL;
+}
+
+void Layout::buildFollowOnTables()
+{
+ // if no -order_file, then skip building follow on table
+ if ( ! _haveOrderFile )
+ return;
+
+ // first make a pass to find all follow-on references and build start/next maps
+ // which are a way to represent clusters of atoms that must layout together
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( !possibleToOrder(sect) )
+ continue;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+ assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+ const ld::Atom* followOnAtom = fit->u.target;
+ if ( _s_log ) fprintf(stderr, "ref %p %s -> %p %s\n", atom, atom->name(), followOnAtom, followOnAtom->name());
+ assert(_followOnNexts.count(atom) == 0);
+ _followOnNexts[atom] = followOnAtom;
+ if ( _followOnStarts.count(atom) == 0 ) {
+ // first time atom has been seen, make it start of chain
+ _followOnStarts[atom] = atom;
+ if ( _s_log ) fprintf(stderr, " start %s -> %s\n", atom->name(), atom->name());
+ }
+ if ( _followOnStarts.count(followOnAtom) == 0 ) {
+ // first time followOnAtom has been seen, make atom start of chain
+ _followOnStarts[followOnAtom] = _followOnStarts[atom];
+ if ( _s_log ) fprintf(stderr, " start %s -> %s\n", followOnAtom->name(), _followOnStarts[atom]->name());
+ }
+ else {
+ if ( _followOnStarts[followOnAtom] == followOnAtom ) {
+ // followOnAtom atom already start of another chain, hook together
+ // and change all to use atom as start
+ const ld::Atom* a = followOnAtom;
+ while ( true ) {
+ assert(_followOnStarts[a] == followOnAtom);
+ _followOnStarts[a] = _followOnStarts[atom];
+ if ( _s_log ) fprintf(stderr, " adjust start for %s -> %s\n", a->name(), _followOnStarts[atom]->name());
+ AtomToAtom::iterator pos = _followOnNexts.find(a);
+ if ( pos != _followOnNexts.end() )
+ a = pos->second;
+ else
+ break;
+ }
+ }
+ else {
+ // attempt to insert atom into existing followOn chain
+ const ld::Atom* curPrevToFollowOnAtom = this->follower(followOnAtom);
+ assert(curPrevToFollowOnAtom != NULL);
+ assert((atom->size() == 0) || (curPrevToFollowOnAtom->size() == 0));
+ if ( atom->size() == 0 ) {
+ // insert alias into existing chain right before followOnAtom
+ _followOnNexts[curPrevToFollowOnAtom] = atom;
+ _followOnNexts[atom] = followOnAtom;
+ _followOnStarts[atom] = _followOnStarts[followOnAtom];
+ }
+ else {
+ // insert real atom into existing chain right before alias of followOnAtom
+ const ld::Atom* curPrevPrevToFollowOn = this->follower(curPrevToFollowOnAtom);
+ if ( curPrevPrevToFollowOn == NULL ) {
+ // nothing previous, so make this a start of a new chain
+ _followOnNexts[atom] = curPrevToFollowOnAtom;
+ for (const ld::Atom* a = atom; a != NULL; a = _followOnNexts[a]) {
+ if ( _s_log ) fprintf(stderr, " adjust start for %s -> %s\n", a->name(), atom->name());
+ _followOnStarts[a] = atom;
+ }
+ }
+ else {
+ // is previous, insert into existing chain before previous
+ _followOnNexts[curPrevPrevToFollowOn] = atom;
+ _followOnNexts[atom] = curPrevToFollowOnAtom;
+ _followOnStarts[atom] = _followOnStarts[curPrevToFollowOnAtom];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( _s_log ) {
+ for(AtomToAtom::iterator it = _followOnStarts.begin(); it != _followOnStarts.end(); ++it)
+ fprintf(stderr, "start %s -> %s\n", it->first->name(), it->second->name());
+
+ for(AtomToAtom::iterator it = _followOnNexts.begin(); it != _followOnNexts.end(); ++it)
+ fprintf(stderr, "next %s -> %s\n", it->first->name(), (it->second != NULL) ? it->second->name() : "null");
+ }
+}
+
+
+class InSet
+{
+public:
+ InSet(const std::set<const ld::Atom*>& theSet) : _set(theSet) {}
+
+ bool operator()(const ld::Atom* atom) const {
+ return ( _set.count(atom) != 0 );
+ }
+private:
+ const std::set<const ld::Atom*>& _set;
+};
+
+
+void Layout::buildOrdinalOverrideMap()
+{
+ // if no -order_file, then skip building override map
+ if ( ! _haveOrderFile )
+ return;
+
+ // build fast name->atom table
+ this->buildNameTable();
+
+ // handle .o files that cannot have their atoms rearranged
+ // with the start/next maps of follow-on atoms we can process the order file and produce override ordinals
+ uint32_t index = 0;
+ uint32_t matchCount = 0;
+ std::set<const ld::Atom*> moveToData;
+ for(Options::OrderedSymbolsIterator it = _options.orderedSymbolsBegin(); it != _options.orderedSymbolsEnd(); ++it) {
+ const ld::Atom* atom = this->findAtom(*it);
+ if ( atom != NULL ) {
+ // <rdar://problem/8612550> When order file used on data, turn ordered zero fill symbols into zero data
+ switch ( atom->section().type() ) {
+ case ld::Section::typeZeroFill:
+ case ld::Section::typeTentativeDefs:
+ if ( atom->size() <= 512 )
+ moveToData.insert(atom);
+ break;
+ default:
+ break;
+ }
+
+ AtomToAtom::iterator start = _followOnStarts.find(atom);
+ if ( start != _followOnStarts.end() ) {
+ // this symbol for the order file corresponds to an atom that is in a cluster that must lay out together
+ for(const ld::Atom* nextAtom = start->second; nextAtom != NULL; nextAtom = _followOnNexts[nextAtom]) {
+ AtomToOrdinal::iterator pos = _ordinalOverrideMap.find(nextAtom);
+ if ( pos == _ordinalOverrideMap.end() ) {
+ _ordinalOverrideMap[nextAtom] = index++;
+ if (_s_log ) fprintf(stderr, "override ordinal %u assigned to %s in cluster from %s\n", index, nextAtom->name(), nextAtom->file()->path());
+ }
+ else {
+ if (_s_log ) fprintf(stderr, "could not order %s as %u because it was already laid out earlier by %s as %u\n",
+ atom->name(), index, _followOnStarts[atom]->name(), _ordinalOverrideMap[atom] );
+ }
+ }
+ }
+ else {
+ _ordinalOverrideMap[atom] = index;
+ if (_s_log ) fprintf(stderr, "override ordinal %u assigned to %s from %s\n", index, atom->name(), atom->file()->path());
+ }
+ ++matchCount;
+ }
+ else {
+ if ( _options.printOrderFileStatistics() ) {
+ if ( it->objectFileName == NULL )
+ warning("can't find match for order_file entry: %s", it->symbolName);
+ else
+ warning("can't find match for order_file entry: %s/%s", it->objectFileName, it->symbolName);
+ }
+ }
+ ++index;
+ }
+ if ( _options.printOrderFileStatistics() && (_options.orderedSymbolsCount() != matchCount) ) {
+ warning("only %u out of %lu order_file symbols were applicable", matchCount, _options.orderedSymbolsCount() );
+ }
+
+
+ // <rdar://problem/8612550> When order file used on data, turn ordered zero fill symbols into zeroed data
+ if ( ! moveToData.empty() ) {
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ switch ( sect->type() ) {
+ case ld::Section::typeZeroFill:
+ case ld::Section::typeTentativeDefs:
+ sect->atoms.erase(std::remove_if(sect->atoms.begin(), sect->atoms.end(), InSet(moveToData)), sect->atoms.end());
+ break;
+ case ld::Section::typeUnclassified:
+ if ( (strcmp(sect->sectionName(), "__data") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+ sect->atoms.insert(sect->atoms.end(), moveToData.begin(), moveToData.end());
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+}
+
+void Layout::doPass()
+{
+ // handle .o files that cannot have their atoms rearranged
+ this->buildFollowOnTables();
+
+ // assign new ordinal value to all ordered atoms
+ this->buildOrdinalOverrideMap();
+
+ // sort atoms in each section
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ std::sort(sect->atoms.begin(), sect->atoms.end(), _comparer);
+ }
+
+ //fprintf(stderr, "Sorted atoms:\n");
+ //for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
+ // ld::Internal::FinalSection* sect = *sit;
+ // for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ // const ld::Atom* atom = *ait;
+ // fprintf(stderr, "\t%s\t%s\n", sect->sectionName(), atom->name());
+ // }
+ //}
+
+}
+
+
+void doPass(const Options& opts, ld::Internal& state)
+{
+ Layout layout(opts, state);
+ layout.doPass();
+}
+
+
+} // namespace order_file
+} // namespace passes
+} // namespace ld
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __ORDER_H__
+#define __ORDER_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace order {
+
+// called by linker to re-arrange atoms to improve locality and performance
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace order
+} // namespace passes
+} // namespace ld
+
+#endif // __ORDER_H__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include "Options.h"
+#include "ld.hpp"
+
+namespace ld {
+namespace passes {
+namespace stubs {
+
+// called by linker to process atoms in Internal and add stubs as needed
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+} // namespace stubs
+} // namespace passes
+} // namespace ld
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+// already in ld::passes::stubs namespace
+namespace arm {
+
+
+class FastBindingPointerAtom : public ld::Atom {
+public:
+ FastBindingPointerAtom(ld::passes::stubs::Pass& pass)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, pass.internal()->compressedFastBinderProxy)
+ { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "fast binder pointer"; }
+ virtual uint64_t size() const { return 4; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+ ld::Fixup _fixup;
+
+ static ld::Section _s_section;
+};
+
+ld::Section FastBindingPointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+
+
+class ImageCachePointerAtom : public ld::Atom {
+public:
+ ImageCachePointerAtom(ld::passes::stubs::Pass& pass)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)) { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "non-lazy pointer"; }
+ virtual uint64_t size() const { return 4; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+
+private:
+
+ static ld::Section _s_section;
+};
+
+ld::Section ImageCachePointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+
+
+
+class StubHelperHelperAtom : public ld::Atom {
+public:
+ StubHelperHelperAtom(ld::passes::stubs::Pass& pass)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
+ ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)),
+ _fixup1(28, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, compressedImageCache(pass)),
+ _fixup2(28, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+ _fixup3(28, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 16),
+ _fixup4(28, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32),
+ _fixup5(32, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, compressedFastBinder(pass)),
+ _fixup6(32, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+ _fixup7(32, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 28),
+ _fixup8(32, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32)
+ { pass.addAtom(*this); }
+
+ virtual ld::File* file() const { return NULL; }
+ virtual const char* name() const { return " stub helpers"; }
+ virtual uint64_t size() const { return 36; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ // push lazy-info-offset
+ OSWriteLittleInt32(&buffer[ 0], 0, 0xe52dc004); // str ip, [sp, #-4]!
+ // push address of dyld_mageLoaderCache
+ OSWriteLittleInt32(&buffer[ 4], 0, 0xe59fc010); // ldr ip, L1
+ OSWriteLittleInt32(&buffer[ 8], 0, 0xe08fc00c); // add ip, pc, ip
+ OSWriteLittleInt32(&buffer[12], 0, 0xe52dc004); // str ip, [sp, #-4]!
+ // jump through _fast_lazy_bind
+ OSWriteLittleInt32(&buffer[16], 0, 0xe59fc008); // ldr ip, L2
+ OSWriteLittleInt32(&buffer[20], 0, 0xe08fc00c); // add ip, pc, ip
+ OSWriteLittleInt32(&buffer[24], 0, 0xe59cf000); // ldr pc, [ip]
+ OSWriteLittleInt32(&buffer[28], 0, 0x00000000); // L1: .long fFastStubGOTAtom - (helperhelper+16)
+ OSWriteLittleInt32(&buffer[32], 0, 0x00000000); // L2: .long _fast_lazy_bind - (helperhelper+28)
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup8)[1]; }
+
+private:
+ static ld::Atom* compressedImageCache(ld::passes::stubs::Pass& pass) {
+ if ( pass.compressedImageCache == NULL )
+ pass.compressedImageCache = new ImageCachePointerAtom(pass);
+ return pass.compressedImageCache;
+ }
+ static ld::Atom* compressedFastBinder(ld::passes::stubs::Pass& pass) {
+ if ( pass.compressedFastBinderPointer == NULL )
+ pass.compressedFastBinderPointer = new FastBindingPointerAtom(pass);
+ return pass.compressedFastBinderPointer;
+ }
+
+ ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+ ld::Fixup _fixup4;
+ ld::Fixup _fixup5;
+ ld::Fixup _fixup6;
+ ld::Fixup _fixup7;
+ ld::Fixup _fixup8;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubHelperHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+class StubHelperAtom : public ld::Atom {
+public:
+ StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ const ld::Atom* lazyPointer)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _stubTo(stubTo),
+ _fixup1(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARMBranch24, helperHelper(pass)),
+ _fixup2(8, ld::Fixup::k1of2, ld::Fixup::kindSetLazyOffset, lazyPointer),
+ _fixup3(8, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32) { }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 12; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ OSWriteLittleInt32(&buffer[0], 0, 0xe59fc000); // ldr ip, [pc, #0]
+ OSWriteLittleInt32(&buffer[4], 0, 0xea000000); // b _helperhelper
+ OSWriteLittleInt32(&buffer[8], 0, 0); // .long lazy-info-offset
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
+
+private:
+ static ld::Atom* helperHelper(ld::passes::stubs::Pass& pass) {
+ if ( pass.compressedHelperHelper == NULL )
+ pass.compressedHelperHelper = new StubHelperHelperAtom(pass);
+ return pass.compressedHelperHelper;
+ }
+ const ld::Atom& _stubTo;
+ ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+class ResolverHelperAtom : public ld::Atom {
+public:
+ ResolverHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ const ld::Atom* lazyPointer)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
+ ld::Atom::symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _stubTo(stubTo),
+ _fixup1( 4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARMBranch24, &stubTo),
+ _fixup2(32, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, lazyPointer),
+ _fixup3(32, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+ _fixup4(32, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 20),
+ _fixup5(32, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32) { }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 36; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ OSWriteLittleInt32(&buffer[ 0], 0, 0xe92d400f); // push {r0, r1, r2, r3, lr}
+ OSWriteLittleInt32(&buffer[ 4], 0, 0xebfffffd); // bl _foo
+ OSWriteLittleInt32(&buffer[ 8], 0, 0xe59fc010); // ldr ip, [pc, #16]
+ OSWriteLittleInt32(&buffer[12], 0, 0xe08fc00c); // add ip, pc, ip
+ OSWriteLittleInt32(&buffer[16], 0, 0xe58c0000); // str r0, [ip]
+ OSWriteLittleInt32(&buffer[20], 0, 0xe1a0c000); // mov ip, r0
+ OSWriteLittleInt32(&buffer[24], 0, 0xe8bd400f); // pop {r0, r1, r2, r3, lr}
+ OSWriteLittleInt32(&buffer[28], 0, 0xe12fff1c); // bx ip
+ OSWriteLittleInt32(&buffer[32], 0, 0x00000000); // .long foo$lazyptr - helper + 20
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup5)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+ ld::Fixup _fixup4;
+ ld::Fixup _fixup5;
+
+ static ld::Section _s_section;
+};
+
+ld::Section ResolverHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+class LazyPointerAtom : public ld::Atom {
+public:
+ LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool stubToGlobalWeakDef, bool stubToResolver,
+ bool weakImport, bool close)
+ : ld::Atom(close ? _s_sectionClose : _s_section, ld::Atom::definitionRegular,
+ ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _stubTo(stubTo),
+ _helper(pass, stubTo, this),
+ _resolverHelper(pass, stubTo, this),
+ _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32,
+ stubToResolver ? &_resolverHelper : (stubToGlobalWeakDef ? &stubTo : &_helper)),
+ _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo) {
+ _fixup2.weakImport = weakImport; pass.addAtom(*this);
+ if ( stubToResolver )
+ pass.addAtom(_resolverHelper);
+ else if ( !stubToGlobalWeakDef )
+ pass.addAtom(_helper);
+ }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 4; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ StubHelperAtom _helper;
+ ResolverHelperAtom _resolverHelper;
+ ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+
+ static ld::Section _s_section;
+ static ld::Section _s_sectionClose;
+};
+
+ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
+ld::Section LazyPointerAtom::_s_sectionClose("__DATA", "__lazy_symbol", ld::Section::typeLazyPointerClose);
+
+
+class NonLazyPointerAtom : public ld::Atom {
+public:
+ NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular,
+ ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _stubTo(stubTo),
+ _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &stubTo) {
+ pass.addAtom(*this);
+ }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 4; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup1)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ ld::Fixup _fixup1;
+
+ static ld::Section _s_section;
+ static ld::Section _s_sectionClose;
+};
+
+ld::Section NonLazyPointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+
+
+class StubPICKextAtom : public ld::Atom {
+public:
+ StubPICKextAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
+ symbolTableIn, false, true, false, ld::Atom::Alignment(2)),
+ _stubTo(stubTo),
+ _nonLazyPointer(pass, stubTo),
+ _fixup1(0, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_nonLazyPointer),
+ _fixup2(0, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+ _fixup3(0, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 12),
+ _fixup4(0, ld::Fixup::k4of4, ld::Fixup::kindStoreThumbLow16),
+ _fixup5(4, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_nonLazyPointer),
+ _fixup6(4, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+ _fixup7(4, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 12),
+ _fixup8(4, ld::Fixup::k4of4, ld::Fixup::kindStoreThumbHigh16) {
+ pass.addAtom(*this);
+ asprintf((char**)&_name, "%s.stub", _stubTo.name());
+ }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 16; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ OSWriteLittleInt32(&buffer[ 0], 0, 0x0c00f240); // movw ip, #lo(nlp - L1)
+ OSWriteLittleInt32(&buffer[ 4], 0, 0x0c00f2c0); // movt ip, #hi(nlp - L1)
+ OSWriteLittleInt16(&buffer[ 8], 0, 0x44fc); // add ip, pc
+ OSWriteLittleInt32(&buffer[10], 0, 0xc000f8dc); // ldr.w ip, [ip]
+ OSWriteLittleInt16(&buffer[14], 0, 0x4760); // bx ip
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup8)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ const char* _name;
+ NonLazyPointerAtom _nonLazyPointer;
+ ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+ ld::Fixup _fixup4;
+ ld::Fixup _fixup5;
+ ld::Fixup _fixup6;
+ ld::Fixup _fixup7;
+ ld::Fixup _fixup8;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubPICKextAtom::_s_section("__TEXT", "__stub", ld::Section::typeCode);
+
+
+
+class StubPICAtom : public ld::Atom {
+public:
+ StubPICAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _stubTo(stubTo),
+ _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, false),
+ _fixup1(12, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_lazyPointer),
+ _fixup2(12, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+ _fixup3(12, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 12),
+ _fixup4(12, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32)
+ { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 16; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 12
+ OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip
+ OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); // ldr pc, [ip]
+ OSWriteLittleInt32(&buffer[12], 0, 0x00000000); // .long L_foo$lazy_ptr - (L1$scv + 8)
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup4)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ LazyPointerAtom _lazyPointer;
+ ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+ ld::Fixup _fixup4;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubPICAtom::_s_section("__TEXT", "__picsymbolstub4", ld::Section::typeStub);
+
+
+
+class StubNoPICAtom : public ld::Atom {
+public:
+ StubNoPICAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _stubTo(stubTo),
+ _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, false),
+ _fixup(8, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &_lazyPointer)
+ { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 12; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); // ldr ip, [pc, #0]
+ OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); // ldr pc, [ip]
+ OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); // .long L_foo$lazy_ptr
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ LazyPointerAtom _lazyPointer;
+ ld::Fixup _fixup;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubNoPICAtom::_s_section("__TEXT", "__symbol_stub4", ld::Section::typeStub);
+
+
+
+
+class StubCloseAtom : public ld::Atom {
+public:
+ StubCloseAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _stubTo(stubTo),
+ _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, true),
+ _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARMLoad12, &_lazyPointer)
+ { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 4; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ OSWriteLittleInt32(&buffer[ 0], 0, 0xE59FF000); // ldr pc, [pc, #foo$lazy_ptr]
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ LazyPointerAtom _lazyPointer;
+ ld::Fixup _fixup;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubCloseAtom::_s_section("__TEXT", "__symbolstub1", ld::Section::typeStubClose);
+
+
+
+
+} // namespace arm
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+// already in ld::passes::stubs namespace
+namespace arm {
+namespace classic {
+
+
+class LazyPointerAtom : public ld::Atom {
+public:
+ LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool forLazyDylib, bool weakImport)
+ : ld::Atom(forLazyDylib ? _s_sectionLazy : _s_section, ld::Atom::definitionRegular,
+ ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _stubTo(stubTo),
+ _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32,
+ forLazyDylib ? pass.internal()->lazyBindingHelper : pass.internal()->classicBindingHelper),
+ _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo)
+ { _fixup2.weakImport = weakImport; pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 4; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+
+ static ld::Section _s_section;
+ static ld::Section _s_sectionLazy;
+};
+
+ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
+ld::Section LazyPointerAtom::_s_sectionLazy("__DATA", "__ld_symbol_ptr", ld::Section::typeLazyDylibPointer);
+
+
+class StubPICAtom : public ld::Atom {
+public:
+ StubPICAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool forLazyDylib, bool weakImport)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _stubTo(stubTo),
+ _lazyPointer(pass, stubTo, forLazyDylib, weakImport),
+ _fixup1(12, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_lazyPointer),
+ _fixup2(12, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+ _fixup3(12, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 12),
+ _fixup4(12, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32)
+ { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 16; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 12
+ OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip
+ OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); // ldr pc, [ip]
+ OSWriteLittleInt32(&buffer[12], 0, 0x00000000); // .long L_foo$lazy_ptr - (L1$scv + 8)
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup4)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ LazyPointerAtom _lazyPointer;
+ ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+ ld::Fixup _fixup4;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubPICAtom::_s_section("__TEXT", "__picsymbolstub4", ld::Section::typeStub);
+
+
+
+class StubNoPICAtom : public ld::Atom {
+public:
+ StubNoPICAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool forLazyDylib, bool weakImport)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _stubTo(stubTo),
+ _lazyPointer(pass, stubTo, forLazyDylib, weakImport),
+ _fixup(8, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &_lazyPointer)
+ { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 12; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); // ldr ip, [pc, #0]
+ OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); // ldr pc, [ip]
+ OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); // .long L_foo$lazy_ptr
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ LazyPointerAtom _lazyPointer;
+ ld::Fixup _fixup;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubNoPICAtom::_s_section("__TEXT", "__symbol_stub4", ld::Section::typeStub);
+
+
+
+
+} // namespace classic
+} // namespace arm
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+// already in ld::passes::stubs namespace
+namespace x86 {
+
+
+
+class FastBindingPointerAtom : public ld::Atom {
+public:
+ FastBindingPointerAtom(ld::passes::stubs::Pass& pass)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32,
+ pass.internal()->compressedFastBinderProxy)
+ { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "fast binder pointer"; }
+ virtual uint64_t size() const { return 4; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+ mutable ld::Fixup _fixup;
+
+ static ld::Section _s_section;
+};
+
+ld::Section FastBindingPointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+
+
+class ImageCachePointerAtom : public ld::Atom {
+public:
+ ImageCachePointerAtom(ld::passes::stubs::Pass& pass)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)) { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "image cache pointer"; }
+ virtual uint64_t size() const { return 4; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+
+private:
+
+ static ld::Section _s_section;
+};
+
+ld::Section ImageCachePointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+
+
+
+
+
+//
+// The stub-helper-helper is the common code factored out of each helper function.
+// It is in the same section as the stub-helpers.
+// Similar to the PLT0 entry in ELF.
+//
+class StubHelperHelperAtom : public ld::Atom {
+public:
+ StubHelperHelperAtom(ld::passes::stubs::Pass& pass)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _fixup1(1, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, compressedImageCache(pass)),
+ _fixup2(7, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, compressedFastBinder(pass))
+ { pass.addAtom(*this); }
+
+ virtual ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "helper helper"; }
+ virtual uint64_t size() const { return 12; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ buffer[0] = 0x68; // pushl $dyld_ImageLoaderCache
+ buffer[1] = 0x00;
+ buffer[2] = 0x00;
+ buffer[3] = 0x00;
+ buffer[4] = 0x00;
+ buffer[5] = 0xFF; // jmp *_fast_lazy_bind
+ buffer[6] = 0x25;
+ buffer[7] = 0x00;
+ buffer[8] = 0x00;
+ buffer[9] = 0x00;
+ buffer[10] = 0x00;
+ buffer[11] = 0x90; // nop
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+ static ld::Atom* compressedImageCache(ld::passes::stubs::Pass& pass) {
+ if ( pass.compressedImageCache == NULL )
+ pass.compressedImageCache = new ImageCachePointerAtom(pass);
+ return pass.compressedImageCache;
+ }
+ static ld::Atom* compressedFastBinder(ld::passes::stubs::Pass& pass) {
+ if ( pass.compressedFastBinderPointer == NULL )
+ pass.compressedFastBinderPointer = new FastBindingPointerAtom(pass);
+ return pass.compressedFastBinderPointer;
+ }
+
+ mutable ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubHelperHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class StubHelperAtom : public ld::Atom {
+public:
+ StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
+ const ld::Atom& stubTo)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
+ _stubTo(stubTo),
+ _fixup1(1, ld::Fixup::k1of2, ld::Fixup::kindSetLazyOffset, lazyPointer),
+ _fixup2(1, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32),
+ _fixup3(6, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32, helperHelper(pass)) { }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 10; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ buffer[0] = 0x68; // pushl $lazy-info-offset
+ buffer[1] = 0x00;
+ buffer[2] = 0x00;
+ buffer[3] = 0x00;
+ buffer[4] = 0x00;
+ buffer[5] = 0xE9; // jmp helperhelper
+ buffer[6] = 0x00;
+ buffer[7] = 0x00;
+ buffer[8] = 0x00;
+ buffer[9] = 0x00;
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
+
+private:
+ static ld::Atom* helperHelper(ld::passes::stubs::Pass& pass) {
+ if ( pass.compressedHelperHelper == NULL )
+ pass.compressedHelperHelper = new StubHelperHelperAtom(pass);
+ return pass.compressedHelperHelper;
+ }
+
+ const ld::Atom& _stubTo;
+ mutable ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+class ResolverHelperAtom : public ld::Atom {
+public:
+ ResolverHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
+ const ld::Atom& stubTo)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
+ _stubTo(stubTo),
+ _fixup1(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32, &stubTo),
+ _fixup2(9, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, lazyPointer),
+ _fixup3(18, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, lazyPointer) { }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 22; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ buffer[ 0] = 0x50; // push %eax
+ buffer[ 1] = 0x51; // push %ecx
+ buffer[ 2] = 0x52; // push %edx
+ buffer[ 3] = 0xE8; // call foo
+ buffer[ 4] = 0x00;
+ buffer[ 5] = 0x00;
+ buffer[ 6] = 0x00;
+ buffer[ 7] = 0x00;
+ buffer[ 8] = 0xA3; // movl %eax,foo$lazy_ptr
+ buffer[ 9] = 0x00;
+ buffer[10] = 0x00;
+ buffer[11] = 0x00;
+ buffer[12] = 0x00;
+ buffer[13] = 0x5A; // pop %edx
+ buffer[14] = 0x59; // pop %ecx
+ buffer[15] = 0x58; // pop %eax
+ buffer[16] = 0xFF; // jmp *foo$lazy_ptr
+ buffer[17] = 0x25;
+ buffer[18] = 0x00;
+ buffer[19] = 0x00;
+ buffer[20] = 0x00;
+ buffer[21] = 0x00;
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
+
+private:
+
+ const ld::Atom& _stubTo;
+ mutable ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+
+ static ld::Section _s_section;
+};
+
+ld::Section ResolverHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class LazyPointerAtom : public ld::Atom {
+public:
+ LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeTranslationUnit, ld::Atom::typeLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _stubTo(stubTo),
+ _helper(pass, this, stubTo),
+ _resolverHelper(pass, this, stubTo),
+ _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32,
+ stubToResolver ? &_resolverHelper : (stubToGlobalWeakDef ? &stubTo : &_helper)),
+ _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo) {
+ _fixup2.weakImport = weakImport; pass.addAtom(*this);
+ if ( stubToResolver )
+ pass.addAtom(_resolverHelper);
+ else if ( !stubToGlobalWeakDef )
+ pass.addAtom(_helper);
+ }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 4; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ StubHelperAtom _helper;
+ ResolverHelperAtom _resolverHelper;
+ mutable ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+
+ static ld::Section _s_section;
+};
+
+ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
+
+
+class StubAtom : public ld::Atom {
+public:
+ StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
+ _stubTo(stubTo),
+ _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport),
+ _fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &_lazyPointer) { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 6; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ buffer[0] = 0xFF; // jmp *foo$lazy_pointer
+ buffer[1] = 0x25;
+ buffer[2] = 0x00;
+ buffer[3] = 0x00;
+ buffer[4] = 0x00;
+ buffer[5] = 0x00;
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ LazyPointerAtom _lazyPointer;
+ mutable ld::Fixup _fixup;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubAtom::_s_section("__TEXT", "__symbol_stub", ld::Section::typeStub);
+
+
+
+} // namespace x86
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+// already in ld::passes::stubs namespace
+namespace x86_64 {
+
+
+
+class FastBindingPointerAtom : public ld::Atom {
+public:
+ FastBindingPointerAtom(ld::passes::stubs::Pass& pass)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
+ _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64,
+ pass.internal()->compressedFastBinderProxy)
+ { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "fast binder pointer"; }
+ virtual uint64_t size() const { return 8; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+ mutable ld::Fixup _fixup;
+
+ static ld::Section _s_section;
+};
+
+ld::Section FastBindingPointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+
+
+class ImageCachePointerAtom : public ld::Atom {
+public:
+ ImageCachePointerAtom(ld::passes::stubs::Pass& pass)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)) { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "image cache pointer"; }
+ virtual uint64_t size() const { return 8; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+
+private:
+
+ static ld::Section _s_section;
+};
+
+ld::Section ImageCachePointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+
+
+
+
+
+//
+// The stub-helper-helper is the common code factored out of each helper function.
+// It is in the same section as the stub-helpers.
+// Similar to the PLT0 entry in ELF.
+//
+class StubHelperHelperAtom : public ld::Atom {
+public:
+ StubHelperHelperAtom(ld::passes::stubs::Pass& pass)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _fixup1(3, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, compressedImageCache(pass)),
+ _fixup2(11, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, compressedFastBinder(pass))
+ { pass.addAtom(*this); }
+
+ virtual ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "helper helper"; }
+ virtual uint64_t size() const { return 16; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ buffer[0] = 0x4C; // leaq dyld_mageLoaderCache(%rip),%r11
+ buffer[1] = 0x8D;
+ buffer[2] = 0x1D;
+ buffer[3] = 0x00;
+ buffer[4] = 0x00;
+ buffer[5] = 0x00;
+ buffer[6] = 0x00;
+ buffer[7] = 0x41; // pushq %r11
+ buffer[8] = 0x53;
+ buffer[9] = 0xFF; // jmp *_fast_lazy_bind(%rip)
+ buffer[10] = 0x25;
+ buffer[11] = 0x00;
+ buffer[12] = 0x00;
+ buffer[13] = 0x00;
+ buffer[14] = 0x00;
+ buffer[15] = 0x90; // nop
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+ static ld::Atom* compressedImageCache(ld::passes::stubs::Pass& pass) {
+ if ( pass.compressedImageCache == NULL )
+ pass.compressedImageCache = new ImageCachePointerAtom(pass);
+ return pass.compressedImageCache;
+ }
+ static ld::Atom* compressedFastBinder(ld::passes::stubs::Pass& pass) {
+ if ( pass.compressedFastBinderPointer == NULL )
+ pass.compressedFastBinderPointer = new FastBindingPointerAtom(pass);
+ return pass.compressedFastBinderPointer;
+ }
+
+ mutable ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubHelperHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class StubHelperAtom : public ld::Atom {
+public:
+ StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
+ const ld::Atom& stubTo)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
+ _stubTo(stubTo),
+ _fixup1(1, ld::Fixup::k1of2, ld::Fixup::kindSetLazyOffset, lazyPointer),
+ _fixup2(1, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32),
+ _fixup3(6, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32, helperHelper(pass)) { }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 10; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ buffer[0] = 0x68; // pushq $lazy-info-offset
+ buffer[1] = 0x00;
+ buffer[2] = 0x00;
+ buffer[3] = 0x00;
+ buffer[4] = 0x00;
+ buffer[5] = 0xE9; // jmp helperhelper
+ buffer[6] = 0x00;
+ buffer[7] = 0x00;
+ buffer[8] = 0x00;
+ buffer[9] = 0x00;
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
+
+private:
+ static ld::Atom* helperHelper(ld::passes::stubs::Pass& pass) {
+ if ( pass.compressedHelperHelper == NULL )
+ pass.compressedHelperHelper = new StubHelperHelperAtom(pass);
+ return pass.compressedHelperHelper;
+ }
+
+ const ld::Atom& _stubTo;
+ mutable ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+class ResolverHelperAtom : public ld::Atom {
+public:
+ ResolverHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
+ const ld::Atom& stubTo)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
+ _stubTo(stubTo),
+ _fixup1(10, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32, &stubTo),
+ _fixup2(17, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, lazyPointer),
+ _fixup3(32, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, lazyPointer) { }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 36; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ buffer[ 0] = 0x50; // push %rax
+ buffer[ 1] = 0x57; // push %rdi
+ buffer[ 2] = 0x56; // push %rsi
+ buffer[ 3] = 0x52; // push %rdx
+ buffer[ 4] = 0x51; // push %rcx
+ buffer[ 5] = 0x41; // push %r8
+ buffer[ 6] = 0x50;
+ buffer[ 7] = 0x41; // push %r9
+ buffer[ 8] = 0x51;
+ buffer[ 9] = 0xE8; // call foo
+ buffer[10] = 0x00;
+ buffer[11] = 0x00;
+ buffer[12] = 0x00;
+ buffer[13] = 0x00;
+ buffer[14] = 0x48; // movq %rax,foo$lazy_pointer(%rip)
+ buffer[15] = 0x89;
+ buffer[16] = 0x05;
+ buffer[17] = 0x00;
+ buffer[18] = 0x00;
+ buffer[19] = 0x00;
+ buffer[20] = 0x00;
+ buffer[21] = 0x41; // pop %r9
+ buffer[22] = 0x59;
+ buffer[23] = 0x41; // pop %r8
+ buffer[24] = 0x58;
+ buffer[25] = 0x59; // pop %rcx
+ buffer[26] = 0x5A; // pop %rdx
+ buffer[27] = 0x5E; // pop %rsi
+ buffer[28] = 0x5F; // pop %rdi
+ buffer[29] = 0x58; // pop %rax
+ buffer[30] = 0xFF; // jmp *foo$lazy_ptr(%rip)
+ buffer[31] = 0x25;
+ buffer[32] = 0x00;
+ buffer[33] = 0x00;
+ buffer[34] = 0x00;
+ buffer[35] = 0x00;
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
+
+private:
+
+ const ld::Atom& _stubTo;
+ mutable ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+
+ static ld::Section _s_section;
+};
+
+ld::Section ResolverHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class LazyPointerAtom : public ld::Atom {
+public:
+ LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeTranslationUnit, ld::Atom::typeLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
+ _stubTo(stubTo),
+ _helper(pass, this, stubTo),
+ _resolverHelper(pass, this, stubTo),
+ _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64,
+ stubToResolver ? &_resolverHelper :
+ (stubToGlobalWeakDef ? &stubTo : &_helper)),
+ _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo) {
+ _fixup2.weakImport = weakImport; pass.addAtom(*this);
+ if ( stubToResolver )
+ pass.addAtom(_resolverHelper);
+ else if ( !stubToGlobalWeakDef )
+ pass.addAtom(_helper);
+ }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 8; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ StubHelperAtom _helper;
+ ResolverHelperAtom _resolverHelper;
+ mutable ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+
+ static ld::Section _s_section;
+};
+
+ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
+
+
+class StubAtom : public ld::Atom {
+public:
+ StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
+ _stubTo(stubTo),
+ _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport),
+ _fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &_lazyPointer) { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 6; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip)
+ buffer[1] = 0x25;
+ buffer[2] = 0x00;
+ buffer[3] = 0x00;
+ buffer[4] = 0x00;
+ buffer[5] = 0x00;
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ LazyPointerAtom _lazyPointer;
+ mutable ld::Fixup _fixup;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
+
+
+
+
+class NonLazyPointerAtom : public ld::Atom {
+public:
+ NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular,
+ ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
+ _stubTo(stubTo),
+ _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, &stubTo) {
+ pass.addAtom(*this);
+ }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 8; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup1)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ ld::Fixup _fixup1;
+
+ static ld::Section _s_section;
+};
+
+ld::Section NonLazyPointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
+
+
+
+class KextStubAtom : public ld::Atom {
+public:
+ KextStubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
+ _stubTo(stubTo),
+ _nonLazyPointer(pass, stubTo),
+ _fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &_nonLazyPointer) { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 6; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ buffer[0] = 0xFF; // jmp *foo$non_lazy_pointer(%rip)
+ buffer[1] = 0x25;
+ buffer[2] = 0x00;
+ buffer[3] = 0x00;
+ buffer[4] = 0x00;
+ buffer[5] = 0x00;
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ NonLazyPointerAtom _nonLazyPointer;
+ mutable ld::Fixup _fixup;
+
+ static ld::Section _s_section;
+};
+
+ld::Section KextStubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
+
+
+} // namespace x86_64
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+// already in ld::passes::stubs namespace
+namespace x86_64 {
+namespace classic {
+
+
+
+
+class StubHelperAtom : public ld::Atom {
+public:
+ StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ const ld::Atom& lazyPointer, bool forLazyDylib)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _stubTo(stubTo),
+ _fixup1(3, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &lazyPointer),
+ _fixup2(8, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32,
+ forLazyDylib ? pass.internal()->lazyBindingHelper : pass.internal()->classicBindingHelper)
+ { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 12; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ buffer[0] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
+ buffer[1] = 0x8D;
+ buffer[2] = 0x1D;
+ buffer[3] = 0x00;
+ buffer[4] = 0x00;
+ buffer[5] = 0x00;
+ buffer[6] = 0x00;
+ buffer[7] = 0xE9; // jmp dyld_stub_binding_helper
+ buffer[8] = 0x00;
+ buffer[9] = 0x00;
+ buffer[10] = 0x00;
+ buffer[11] = 0x00;
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ mutable ld::Fixup _fixup1;
+ mutable ld::Fixup _fixup2;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class LazyPointerAtom : public ld::Atom {
+public:
+ LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool forLazyDylib, bool weakImport)
+ : ld::Atom( forLazyDylib ? _s_sectionLazy : _s_section,
+ ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeTranslationUnit,
+ forLazyDylib ? ld::Atom::typeLazyDylibPointer : ld::Atom::typeLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
+ _stubTo(stubTo),
+ _helper(pass, stubTo, *this, forLazyDylib),
+ _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, &_helper),
+ _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo)
+ { _fixup2.weakImport = weakImport; pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 8; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ StubHelperAtom _helper;
+ mutable ld::Fixup _fixup1;
+ mutable ld::Fixup _fixup2;
+
+ static ld::Section _s_section;
+ static ld::Section _s_sectionLazy;
+};
+
+ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
+ld::Section LazyPointerAtom::_s_sectionLazy("__DATA", "__ld_symbol_ptr", ld::Section::typeLazyDylibPointer);
+
+
+
+class StubAtom : public ld::Atom {
+public:
+ StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool forLazyDylib, bool weakImport)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
+ _stubTo(stubTo),
+ _lazyPointer(pass, stubTo, forLazyDylib, weakImport),
+ _fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &_lazyPointer) { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 6; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip)
+ buffer[1] = 0x25;
+ buffer[2] = 0x00;
+ buffer[3] = 0x00;
+ buffer[4] = 0x00;
+ buffer[5] = 0x00;
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ LazyPointerAtom _lazyPointer;
+ mutable ld::Fixup _fixup;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
+
+
+} // namespace classic
+} // namespace x86_64
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+// already in ld::passes::stubs namespace
+namespace x86 {
+namespace classic {
+
+
+
+
+class StubHelperAtom : public ld::Atom {
+public:
+ StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ const ld::Atom& lazyPointer, bool forLazyDylib)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _stubTo(stubTo),
+ _fixup1(1, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &lazyPointer),
+ _fixup2(6, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32,
+ forLazyDylib ? pass.internal()->lazyBindingHelper : pass.internal()->classicBindingHelper)
+ { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 10; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ buffer[0] = 0x68; // pushl $foo$lazy_ptr
+ buffer[1] = 0x00;
+ buffer[2] = 0x00;
+ buffer[3] = 0x00;
+ buffer[4] = 0x00;
+ buffer[5] = 0xE9; // jmp dyld_stub_binding_helper
+ buffer[6] = 0x00;
+ buffer[7] = 0x00;
+ buffer[8] = 0x00;
+ buffer[9] = 0x00;
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ mutable ld::Fixup _fixup1;
+ mutable ld::Fixup _fixup2;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class LazyPointerAtom : public ld::Atom {
+public:
+ LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool forLazyDylib, bool weakImport)
+ : ld::Atom( forLazyDylib ? _s_sectionLazy : _s_section,
+ ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeTranslationUnit,
+ forLazyDylib ? ld::Atom::typeLazyDylibPointer : ld::Atom::typeLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _stubTo(stubTo),
+ _helper(pass, stubTo, *this, forLazyDylib),
+ _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &_helper),
+ _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo)
+ { _fixup2.weakImport = weakImport; pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 4; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ StubHelperAtom _helper;
+ mutable ld::Fixup _fixup1;
+ mutable ld::Fixup _fixup2;
+
+ static ld::Section _s_section;
+ static ld::Section _s_sectionLazy;
+};
+
+ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
+ld::Section LazyPointerAtom::_s_sectionLazy("__DATA", "__ld_symbol_ptr", ld::Section::typeLazyDylibPointer);
+
+
+
+class StubAtom : public ld::Atom {
+public:
+ StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool forLazyDylib, bool weakImport)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
+ _stubTo(stubTo),
+ _lazyPointer(pass, stubTo, forLazyDylib, weakImport),
+ _fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &_lazyPointer) { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 6; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip)
+ buffer[1] = 0x25;
+ buffer[2] = 0x00;
+ buffer[3] = 0x00;
+ buffer[4] = 0x00;
+ buffer[5] = 0x00;
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ LazyPointerAtom _lazyPointer;
+ mutable ld::Fixup _fixup;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubAtom::_s_section("__TEXT", "__symbol_stub", ld::Section::typeStub);
+
+
+} // namespace classic
+} // namespace x86
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <assert.h>
+#include <libkern/OSByteOrder.h>
+
+#include <vector>
+#include <set>
+#include <map>
+
+#include "Options.h"
+#include "ld.hpp"
+#include "MachOFileAbstraction.hpp"
+
+#include "make_stubs.h"
+
+
+namespace ld {
+namespace passes {
+namespace stubs {
+
+class Pass {
+public:
+ Pass(const Options& opts);
+ void process(ld::Internal& internal);
+ void addAtom(const ld::Atom& atom) { _internal->addAtom(atom); }
+ bool usingCompressedLINKEDIT() const { return _compressedLINKEDIT; }
+ ld::Internal* internal() { return _internal; }
+
+ Atom* compressedHelperHelper;
+ Atom* compressedImageCache;
+ Atom* compressedFastBinderPointer;
+
+private:
+
+ struct AtomByNameSorter
+ {
+ bool operator()(const ld::Atom* left, const ld::Atom* right)
+ {
+ return (strcmp(left->name(), right->name()) < 0);
+ }
+ };
+
+ const ld::Atom* stubableFixup(const ld::Fixup* fixup, ld::Internal&);
+ ld::Atom* makeStub(const ld::Atom& target, bool weakImport);
+ void verifyNoResolverFunctions(ld::Internal& state);
+
+ const Options& _options;
+ const cpu_type_t _architecture;
+ const bool _lazyDylibsInUuse;
+ const bool _compressedLINKEDIT;
+ const bool _prebind;
+ const bool _mightBeInSharedRegion;
+ const bool _pic;
+ const bool _flatNamespace;
+ ld::Internal* _internal;
+ uint32_t _stubCount;
+ bool _largeText;
+};
+
+#include "stub_x86_64.hpp"
+#include "stub_x86_64_classic.hpp"
+#include "stub_x86.hpp"
+#include "stub_x86_classic.hpp"
+#include "stub_arm.hpp"
+#include "stub_arm_classic.hpp"
+
+
+
+Pass::Pass(const Options& opts)
+ : compressedHelperHelper(NULL),
+ compressedImageCache(NULL),
+ compressedFastBinderPointer(NULL),
+ _options(opts),
+ _architecture(opts.architecture()),
+ _lazyDylibsInUuse(opts.usingLazyDylibLinking()),
+ _compressedLINKEDIT(opts.makeCompressedDyldInfo()),
+ _prebind(opts.prebind()),
+ _mightBeInSharedRegion(opts.sharedRegionEligible()),
+ _pic(opts.outputSlidable()),
+ _flatNamespace(opts.nameSpace() != Options::kTwoLevelNameSpace),
+ _internal(NULL), _stubCount(0), _largeText(false)
+{
+
+}
+
+
+const ld::Atom* Pass::stubableFixup(const ld::Fixup* fixup, ld::Internal& state)
+{
+ if ( fixup->binding == ld::Fixup::bindingsIndirectlyBound ) {
+ const ld::Atom* target = state.indirectBindingTable[fixup->u.bindingIndex];
+ switch ( fixup->kind ) {
+ case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+ case ld::Fixup::kindStoreTargetAddressARMBranch24:
+ case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+ assert(target != NULL);
+ // create stub if target is in a dylib
+ if ( target->definition() == ld::Atom::definitionProxy )
+ return target;
+ // use stub if target is a resolver function in same linkage unit
+ if ( target->contentType() == ld::Atom::typeResolver )
+ return target;
+ if ( target->scope() == ld::Atom::scopeGlobal ) {
+ // create stub if target is global weak definition in symbol table
+ if ( (target->definition() == ld::Atom::definitionRegular)
+ && (target->combine() == ld::Atom::combineByName)
+ && ((target->symbolTableInclusion() == ld::Atom::symbolTableIn)
+ || (target->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)) )
+ return target;
+ // create stub if target is interposable
+ if ( _options.interposable(target->name()) )
+ return target;
+ if ( _flatNamespace ) {
+ // flat namespace does not indirect calls within main exectuables
+ if ( _options.outputKind() == Options::kDynamicExecutable )
+ return NULL;
+ // create stub if target is global and building -flat dylib or bundle
+ return target;
+ }
+ }
+ break;
+ default:
+ if ( target->contentType() == ld::Atom::typeResolver ) {
+ // any pointer to a resolver needs to change to pointer to stub
+ return target;
+ }
+ break;
+ }
+ }
+ return NULL;
+}
+
+
+
+ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport)
+{
+ //fprintf(stderr, "makeStub(target=%p %s in sect %s)\n", &target, target.name(), target.section().sectionName());
+ bool stubToGlobalWeakDef = ( (target.scope() == ld::Atom::scopeGlobal)
+ && (target.definition() == ld::Atom::definitionRegular)
+ && (target.combine() == ld::Atom::combineByName) );
+
+ bool forLazyDylib = false;
+ const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target.file());
+ if ( (dylib != NULL) && dylib->willBeLazyLoadedDylib() )
+ forLazyDylib = true;
+ bool stubToResolver = (target.contentType() == ld::Atom::typeResolver);
+
+ if ( usingCompressedLINKEDIT() && !forLazyDylib ) {
+ if ( _internal->compressedFastBinderProxy == NULL )
+ throwf("symbol dyld_stub_binder not found (normally in libSystem.dylib). Needed to perform lazy binding to function %s", target.name());
+ }
+
+ switch ( _architecture ) {
+#if SUPPORT_ARCH_i386
+ case CPU_TYPE_I386:
+ if ( usingCompressedLINKEDIT() && !forLazyDylib )
+ return new ld::passes::stubs::x86::StubAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
+ else
+ return new ld::passes::stubs::x86::classic::StubAtom(*this, target, forLazyDylib, weakImport);
+ break;
+#endif
+#if SUPPORT_ARCH_x86_64
+ case CPU_TYPE_X86_64:
+ if ( (_options.outputKind() == Options::kKextBundle) && _options.kextsUseStubs() )
+ return new ld::passes::stubs::x86_64::KextStubAtom(*this, target);
+ else if ( usingCompressedLINKEDIT() && !forLazyDylib )
+ return new ld::passes::stubs::x86_64::StubAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
+ else
+ return new ld::passes::stubs::x86_64::classic::StubAtom(*this, target, forLazyDylib, weakImport);
+ break;
+#endif
+#if SUPPORT_ARCH_arm_any
+ case CPU_TYPE_ARM:
+ if ( (_options.outputKind() == Options::kKextBundle) && _options.kextsUseStubs() ) {
+ // if text relocs are not allows in kext bundles, then linker must create a stub
+ return new ld::passes::stubs::arm::StubPICKextAtom(*this, target);
+ }
+ else if ( usingCompressedLINKEDIT() && !forLazyDylib ) {
+ if ( (_stubCount < 900) && !_mightBeInSharedRegion && !_largeText )
+ return new ld::passes::stubs::arm::StubCloseAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
+ else if ( _pic )
+ return new ld::passes::stubs::arm::StubPICAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
+ else
+ return new ld::passes::stubs::arm::StubNoPICAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
+ }
+ else {
+ if ( _pic )
+ return new ld::passes::stubs::arm::classic::StubPICAtom(*this, target, forLazyDylib, weakImport);
+ else
+ return new ld::passes::stubs::arm::classic::StubNoPICAtom(*this, target, forLazyDylib, weakImport);
+ }
+ break;
+#endif
+ }
+ throw "unsupported arch for stub";
+}
+
+
+void Pass::verifyNoResolverFunctions(ld::Internal& state)
+{
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ if ( atom->contentType() == ld::Atom::typeResolver )
+ throwf("resolver function '%s' not supported in type of output", atom->name());
+ }
+ }
+}
+
+void Pass::process(ld::Internal& state)
+{
+ switch ( _options.outputKind() ) {
+ case Options::kObjectFile:
+ // these kinds don't use stubs and can have resolver functions
+ return;
+ case Options::kStaticExecutable:
+ case Options::kPreload:
+ case Options::kDyld:
+ // these kinds don't use stubs and cannot have resolver functions
+ verifyNoResolverFunctions(state);
+ return;
+ case Options::kDynamicLibrary:
+ // uses stubs and can have resolver functions
+ break;
+ case Options::kKextBundle:
+ verifyNoResolverFunctions(state);
+ // if kext don't use stubs, don't do this pass
+ if ( !_options.kextsUseStubs() )
+ return;
+ break;
+ case Options::kDynamicExecutable:
+ case Options::kDynamicBundle:
+ // these kinds do use stubs and cannot have resolver functions
+ verifyNoResolverFunctions(state);
+ break;
+ }
+
+ // walk all atoms and fixups looking for stubable references
+ // don't create stubs inline because that could invalidate the sections iterator
+ std::vector<const ld::Atom*> atomsCallingStubs;
+ std::map<const ld::Atom*,ld::Atom*> stubFor;
+ std::map<const ld::Atom*,bool> weakImportMap;
+ atomsCallingStubs.reserve(128);
+ uint64_t codeSize = 0;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ codeSize += atom->size();
+ bool atomNeedsStub = false;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ const ld::Atom* stubableTargetOfFixup = stubableFixup(fit, state);
+ if ( stubableTargetOfFixup != NULL ) {
+ if ( !atomNeedsStub ) {
+ atomsCallingStubs.push_back(atom);
+ atomNeedsStub = true;
+ }
+ stubFor[stubableTargetOfFixup] = NULL;
+ // record weak_import attribute
+ std::map<const ld::Atom*,bool>::iterator pos = weakImportMap.find(stubableTargetOfFixup);
+ if ( pos == weakImportMap.end() ) {
+ // target not in weakImportMap, so add
+ weakImportMap[stubableTargetOfFixup] = fit->weakImport;
+ }
+ else {
+ // target in weakImportMap, check for weakness mismatch
+ if ( pos->second != fit->weakImport ) {
+ // found mismatch
+ switch ( _options.weakReferenceMismatchTreatment() ) {
+ case Options::kWeakReferenceMismatchError:
+ throwf("mismatching weak references for symbol: %s", stubableTargetOfFixup->name());
+ case Options::kWeakReferenceMismatchWeak:
+ pos->second = true;
+ break;
+ case Options::kWeakReferenceMismatchNonWeak:
+ pos->second = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ // all resolver functions must have a corresponding stub
+ if ( atom->contentType() == ld::Atom::typeResolver ) {
+ if ( _options.outputKind() != Options::kDynamicLibrary )
+ throwf("resolver functions (%s) can only be used in dylibs", atom->name());
+ if ( !_options.makeCompressedDyldInfo() ) {
+ if ( _options.architecture() == CPU_TYPE_ARM )
+ throwf("resolver functions (%s) can only be used when targeting iOS 4.2 or later", atom->name());
+ else
+ throwf("resolver functions (%s) can only be used when targeting Mac OS X 10.6 or later", atom->name());
+ }
+ stubFor[atom] = NULL;
+ }
+ }
+ }
+
+ const bool needStubForMain = _options.needsEntryPointLoadCommand()
+ && (state.entryPoint != NULL)
+ && (state.entryPoint->definition() == ld::Atom::definitionProxy);
+ if ( needStubForMain ) {
+ // _main not found in any .o files. Currently have proxy to dylib
+ // Add to map, so that a stub will be made
+ stubFor[state.entryPoint] = NULL;
+ }
+
+ // short circuit if no stubs needed
+ _internal = &state;
+ _stubCount = stubFor.size();
+ if ( _stubCount == 0 )
+ return;
+
+ // <rdar://problem/8553283> lazily check for helper
+ if ( !_options.makeCompressedDyldInfo() && (state.classicBindingHelper == NULL) && (_options.outputKind() != Options::kKextBundle) )
+ throw "symbol dyld_stub_binding_helper not found, normally in crt1.o/dylib1.o/bundle1.o";
+
+ // disable arm close stubs in some cases
+ if ( _architecture == CPU_TYPE_ARM ) {
+ if ( codeSize > 4*1024*1024 )
+ _largeText = true;
+ else {
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() == ld::Section::typeMachHeader )
+ continue;
+ if ( strcmp(sect->segmentName(), "__TEXT") == 0) {
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ if ( atom->alignment().powerOf2 > 10 ) {
+ // overaligned section means might not be able to keep closestubs sect pushed to end of __TEXT
+ //warning("alignment 1<<%d in atom %s in section %s disables close stubs optimization",
+ // atom->alignment().powerOf2, atom->name(), sect->segmentName());
+ _largeText = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // make stub atoms
+ for (std::map<const ld::Atom*,ld::Atom*>::iterator it = stubFor.begin(); it != stubFor.end(); ++it) {
+ it->second = makeStub(*it->first, weakImportMap[it->first]);
+ }
+
+ // updated atoms to use stubs
+ for (std::vector<const ld::Atom*>::iterator it=atomsCallingStubs.begin(); it != atomsCallingStubs.end(); ++it) {
+ const ld::Atom* atom = *it;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ const ld::Atom* stubableTargetOfFixup = stubableFixup(fit, state);
+ if ( stubableTargetOfFixup != NULL ) {
+ ld::Atom* stub = stubFor[stubableTargetOfFixup];
+ assert(stub != NULL && "stub not created");
+ fit->binding = ld::Fixup::bindingDirectlyBound;
+ fit->u.target = stub;
+ }
+ }
+ }
+
+ // switch entry point from proxy to stub
+ if ( needStubForMain ) {
+ const ld::Atom* mainStub = stubFor[state.entryPoint];
+ assert(mainStub != NULL);
+ state.entryPoint = mainStub;
+ }
+
+ // sort new atoms so links are consistent
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ switch ( sect->type() ) {
+ case ld::Section::typeStubHelper:
+ case ld::Section::typeStub:
+ case ld::Section::typeStubClose:
+ case ld::Section::typeLazyPointer:
+ case ld::Section::typeLazyPointerClose:
+ std::sort(sect->atoms.begin(), sect->atoms.end(), AtomByNameSorter());
+ break;
+ default:
+ break;
+ }
+ }
+
+}
+
+
+void doPass(const Options& opts, ld::Internal& internal)
+{
+ Pass pass(opts);
+ pass.process(internal);
+}
+
+
+
+} // namespace stubs
+} // namespace passes
+} // namespace ld
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+
+#include <vector>
+#include <map>
+#include <ext/hash_map>
+
+#include "ld.hpp"
+#include "tlvp.h"
+
+namespace ld {
+namespace passes {
+namespace tlvp {
+
+class File; // forward reference
+
+class TLVEntryAtom : public ld::Atom {
+public:
+ TLVEntryAtom(ld::Internal& internal, const ld::Atom* target, bool weakImport)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
+ _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, target),
+ _target(target)
+ { _fixup.weakImport = weakImport; internal.addAtom(*this); }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return _target->name(); }
+ virtual uint64_t size() const { return 8; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+ mutable ld::Fixup _fixup;
+ const ld::Atom* _target;
+
+ static ld::Section _s_section;
+};
+
+ld::Section TLVEntryAtom::_s_section("__DATA", "__thread_ptrs", ld::Section::typeTLVPointers);
+
+
+static bool optimizable(const Options& opts, const ld::Atom* targetOfTLV)
+{
+ // cannot do LEA optimization if target is in another dylib
+ if ( targetOfTLV->definition() == ld::Atom::definitionProxy )
+ return false;
+ if ( targetOfTLV->scope() == ld::Atom::scopeGlobal ) {
+ // cannot do LEA optimization if target is weak exported symbol
+ if ( (targetOfTLV->definition() == ld::Atom::definitionRegular) && (targetOfTLV->combine() == ld::Atom::combineByName) )
+ return false;
+ // cannot do LEA optimization if target is interposable
+ if ( opts.interposable(targetOfTLV->name()) )
+ return false;
+ // cannot do LEA optimization for flat-namespace
+ if ( opts.nameSpace() != Options::kTwoLevelNameSpace )
+ return false;
+ }
+ return true;
+}
+
+struct AtomByNameSorter
+{
+ bool operator()(const ld::Atom* left, const ld::Atom* right)
+ {
+ return (strcmp(left->name(), right->name()) < 0);
+ }
+};
+
+struct TlVReferenceCluster
+{
+ const ld::Atom* targetOfTLV;
+ ld::Fixup* fixupWithTarget;
+ ld::Fixup* fixupWithTLVStore;
+ bool optimizable;
+};
+
+void doPass(const Options& opts, ld::Internal& internal)
+{
+ const bool log = false;
+
+ // only make tlv section in final linked images
+ if ( opts.outputKind() == Options::kObjectFile )
+ return;
+
+ // walk all atoms and fixups looking for TLV references and add them to list
+ std::vector<TlVReferenceCluster> references;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=internal.sections.begin(); sit != internal.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ TlVReferenceCluster ref;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ if ( fit->firstInCluster() ) {
+ ref.targetOfTLV = NULL;
+ ref.fixupWithTarget = NULL;
+ ref.fixupWithTLVStore = NULL;
+ }
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingsIndirectlyBound:
+ ref.targetOfTLV = internal.indirectBindingTable[fit->u.bindingIndex];
+ ref.fixupWithTarget = fit;
+ break;
+ case ld::Fixup::bindingDirectlyBound:
+ ref.targetOfTLV = fit->u.target;
+ ref.fixupWithTarget = fit;
+ break;
+ default:
+ break;
+ }
+ switch ( fit->kind ) {
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+ case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreX86Abs32TLVLoad:
+ ref.fixupWithTLVStore = fit;
+ break;
+ default:
+ break;
+ }
+ if ( fit->lastInCluster() && (ref.fixupWithTLVStore != NULL) ) {
+ ref.optimizable = optimizable(opts, ref.targetOfTLV);
+ if (log) fprintf(stderr, "found reference to TLV at %s+0x%X to %s\n",
+ atom->name(), ref.fixupWithTLVStore->offsetInAtom, ref.targetOfTLV->name());
+ if ( ! opts.canUseThreadLocalVariables() ) {
+ throwf("targeted OS version does not support use of thread local variables in %s", atom->name());
+ }
+ references.push_back(ref);
+ }
+ }
+ }
+ }
+
+ // compute which TLV references will be weak_imports
+ std::map<const ld::Atom*,bool> weakImportMap;
+ for(std::vector<TlVReferenceCluster>::iterator it=references.begin(); it != references.end(); ++it) {
+ if ( !it->optimizable ) {
+ // record weak_import attribute
+ std::map<const ld::Atom*,bool>::iterator pos = weakImportMap.find(it->targetOfTLV);
+ if ( pos == weakImportMap.end() ) {
+ // target not in weakImportMap, so add
+ weakImportMap[it->targetOfTLV] = it->fixupWithTarget->weakImport;
+ }
+ else {
+ // target in weakImportMap, check for weakness mismatch
+ if ( pos->second != it->fixupWithTarget->weakImport ) {
+ // found mismatch
+ switch ( opts.weakReferenceMismatchTreatment() ) {
+ case Options::kWeakReferenceMismatchError:
+ throwf("mismatching weak references for symbol: %s", it->targetOfTLV->name());
+ case Options::kWeakReferenceMismatchWeak:
+ pos->second = true;
+ break;
+ case Options::kWeakReferenceMismatchNonWeak:
+ pos->second = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // create TLV pointers for TLV references that cannot be optimized
+ std::map<const ld::Atom*,ld::Atom*> variableToPointerMap;
+ for(std::map<const ld::Atom*,bool>::iterator it=weakImportMap.begin(); it != weakImportMap.end(); ++it) {
+ std::map<const ld::Atom*,ld::Atom*>::iterator pos = variableToPointerMap.find(it->first);
+ if ( pos == variableToPointerMap.end() ) {
+ if (log) fprintf(stderr, "make TLV pointer for %s\n", it->first->name());
+ if ( it->first->contentType() != ld::Atom::typeTLV )
+ throwf("illegal thread local variable reference to regular symbol %s", it->first->name());
+ TLVEntryAtom* tlvp = new TLVEntryAtom(internal, it->first, it->second);
+ variableToPointerMap[it->first] = tlvp;
+ }
+ }
+
+ // sort new tvlp atoms so links are consistent
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=internal.sections.begin(); sit != internal.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() == ld::Section::typeTLVPointers ) {
+ std::sort(sect->atoms.begin(), sect->atoms.end(), AtomByNameSorter());
+ }
+ }
+
+ // update references to use TLV pointers or TLV object directly
+ for(std::vector<TlVReferenceCluster>::iterator it=references.begin(); it != references.end(); ++it) {
+ if ( it->optimizable ) {
+ // change store to be LEA instead load (mov)
+ if (log) fprintf(stderr, "optimizing load of TLV to %s into an LEA\n", it->targetOfTLV->name());
+ it->fixupWithTLVStore->binding = ld::Fixup::bindingDirectlyBound;
+ it->fixupWithTLVStore->u.target = it->targetOfTLV;
+ switch ( it->fixupWithTLVStore->kind ) {
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+ it->fixupWithTLVStore->kind = ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA;
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+ it->fixupWithTLVStore->kind = ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA;
+ break;
+ case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+ it->fixupWithTLVStore->kind = ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA;
+ break;
+ case ld::Fixup::kindStoreX86Abs32TLVLoad:
+ it->fixupWithTLVStore->kind = ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA;
+ break;
+ default:
+ assert(0 && "bad store kind for TLV optimization");
+ }
+ }
+ else {
+ // change target to be new TLV pointer atom
+ if (log) fprintf(stderr, "updating load of TLV to %s to load from TLV pointer\n", it->targetOfTLV->name());
+ const ld::Atom* tlvpAtom = variableToPointerMap[it->targetOfTLV];
+ assert(tlvpAtom != NULL);
+ it->fixupWithTarget->binding = ld::Fixup::bindingDirectlyBound;
+ it->fixupWithTarget->u.target = tlvpAtom;
+ }
+ }
+
+
+
+ // alter tlv definitions to have an offset as third field
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=internal.sections.begin(); sit != internal.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() != ld::Section::typeTLVDefs )
+ continue;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ if ( fit->offsetInAtom != 0 ) {
+ assert(fit->binding == ld::Fixup::bindingDirectlyBound && "thread variable def contains pointer to global");
+ switch( fit->u.target->contentType() ) {
+ case ld::Atom::typeTLVZeroFill:
+ case ld::Atom::typeTLVInitialValue:
+ switch ( fit->kind ) {
+ case ld::Fixup::kindSetTargetAddress:
+ fit->kind = ld::Fixup::kindSetTargetTLVTemplateOffset;
+ break;
+ case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ fit->kind = ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32;
+ break;
+ case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+ fit->kind = ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64;
+ break;
+ default:
+ assert(0 && "bad kind for target in tlv defs");
+ break;
+ }
+ break;
+ default:
+ assert(0 && "wrong content type for target in tlv defs");
+ break;
+ }
+ }
+ }
+ }
+ }
+
+}
+
+
+
+} // namespace tlvp
+} // namespace passes
+} // namespace ld
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __TLVP_H__
+#define __TLVP_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace tlvp {
+
+// called by linker to create TLVP entries and optimize TLV loads into LEAs instead
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace tlvp
+} // namespace passes
+} // namespace ld
+
+#endif // __TLVP_H__
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <mach-o/nlist.h>
+#include <mach-o/stab.h>
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+
+#include "MachOFileAbstraction.hpp"
+#include "parsers/macho_relocatable_file.h"
+#include "parsers/lto_file.h"
+
+static bool sDumpContent= true;
+static bool sDumpStabs = false;
+static bool sSort = true;
+static bool sNMmode = false;
+static bool sShowSection = true;
+static bool sShowDefinitionKind = true;
+static bool sShowCombineKind = true;
+static bool sShowLineInfo = true;
+
+static cpu_type_t sPreferredArch = 0xFFFFFFFF;
+static cpu_subtype_t sPreferredSubArch = 0xFFFFFFFF;
+static const char* sMatchName = NULL;
+static int sPrintRestrict;
+static int sPrintAlign;
+static int sPrintName;
+
+ __attribute__((noreturn))
+void throwf(const char* format, ...)
+{
+ va_list list;
+ char* p;
+ va_start(list, format);
+ vasprintf(&p, format, list);
+ va_end(list);
+
+ const char* t = p;
+ throw t;
+}
+
+void warning(const char* format, ...)
+{
+ va_list list;
+ fprintf(stderr, "warning: ");
+ va_start(list, format);
+ vfprintf(stderr, format, list);
+ va_end(list);
+ fprintf(stderr, "\n");
+}
+
+static void dumpStabs(const std::vector<ld::relocatable::File::Stab>* stabs)
+{
+ // debug info
+ printf("stabs: (%lu)\n", stabs->size());
+ for (std::vector<ld::relocatable::File::Stab>::const_iterator it = stabs->begin(); it != stabs->end(); ++it ) {
+ const ld::relocatable::File::Stab& stab = *it;
+ const char* code = "?????";
+ switch (stab.type) {
+ case N_GSYM:
+ code = " GSYM";
+ break;
+ case N_FNAME:
+ code = "FNAME";
+ break;
+ case N_FUN:
+ code = " FUN";
+ break;
+ case N_STSYM:
+ code = "STSYM";
+ break;
+ case N_LCSYM:
+ code = "LCSYM";
+ break;
+ case N_BNSYM:
+ code = "BNSYM";
+ break;
+ case N_OPT:
+ code = " OPT";
+ break;
+ case N_RSYM:
+ code = " RSYM";
+ break;
+ case N_SLINE:
+ code = "SLINE";
+ break;
+ case N_ENSYM:
+ code = "ENSYM";
+ break;
+ case N_SSYM:
+ code = " SSYM";
+ break;
+ case N_SO:
+ code = " SO";
+ break;
+ case N_OSO:
+ code = " OSO";
+ break;
+ case N_LSYM:
+ code = " LSYM";
+ break;
+ case N_BINCL:
+ code = "BINCL";
+ break;
+ case N_SOL:
+ code = " SOL";
+ break;
+ case N_PARAMS:
+ code = "PARMS";
+ break;
+ case N_VERSION:
+ code = " VERS";
+ break;
+ case N_OLEVEL:
+ code = "OLEVL";
+ break;
+ case N_PSYM:
+ code = " PSYM";
+ break;
+ case N_EINCL:
+ code = "EINCL";
+ break;
+ case N_ENTRY:
+ code = "ENTRY";
+ break;
+ case N_LBRAC:
+ code = "LBRAC";
+ break;
+ case N_EXCL:
+ code = " EXCL";
+ break;
+ case N_RBRAC:
+ code = "RBRAC";
+ break;
+ case N_BCOMM:
+ code = "BCOMM";
+ break;
+ case N_ECOMM:
+ code = "ECOMM";
+ break;
+ case N_LENG:
+ code = "LENG";
+ break;
+ }
+ printf(" [atom=%20s] %02X %04X %s %s\n", ((stab.atom != NULL) ? stab.atom->name() : ""), stab.other, stab.desc, code, stab.string);
+ }
+}
+
+#if 0
+static void dumpAtomLikeNM(ld::Atom* atom)
+{
+ uint32_t size = atom->size();
+
+ const char* visibility;
+ switch ( atom->scope() ) {
+ case ld::Atom::scopeTranslationUnit:
+ visibility = "internal";
+ break;
+ case ld::Atom::scopeLinkageUnit:
+ visibility = "hidden ";
+ break;
+ case ld::Atom::scopeGlobal:
+ visibility = "global ";
+ break;
+ default:
+ visibility = " ";
+ break;
+ }
+
+ const char* kind;
+ switch ( atom->definitionKind() ) {
+ case ld::Atom::kRegularDefinition:
+ kind = "regular ";
+ break;
+ case ld::Atom::kTentativeDefinition:
+ kind = "tentative";
+ break;
+ case ld::Atom::kWeakDefinition:
+ kind = "weak ";
+ break;
+ case ld::Atom::kAbsoluteSymbol:
+ kind = "absolute ";
+ break;
+ default:
+ kind = " ";
+ break;
+ }
+
+ printf("0x%08X %s %s %s\n", size, visibility, kind, atom->name());
+}
+
+
+static void dumpAtom(ld::Atom* atom)
+{
+ if(sMatchName && strcmp(sMatchName, atom->name()))
+ return;
+
+ //printf("atom: %p\n", atom);
+
+ // name
+ if(!sPrintRestrict || sPrintName)
+ printf("name: %s\n", atom->name());
+
+ // scope
+ if(!sPrintRestrict)
+ switch ( atom->scope() ) {
+ case ld::Atom::scopeTranslationUnit:
+ printf("scope: translation unit\n");
+ break;
+ case ld::Atom::scopeLinkageUnit:
+ printf("scope: linkage unit\n");
+ break;
+ case ld::Atom::scopeGlobal:
+ printf("scope: global\n");
+ break;
+ default:
+ printf("scope: unknown\n");
+ }
+
+ // kind
+ if(!sPrintRestrict)
+ switch ( atom->definitionKind() ) {
+ case ld::Atom::kRegularDefinition:
+ printf("kind: regular\n");
+ break;
+ case ld::Atom::kWeakDefinition:
+ printf("kind: weak\n");
+ break;
+ case ld::Atom::kTentativeDefinition:
+ printf("kind: tentative\n");
+ break;
+ case ld::Atom::kExternalDefinition:
+ printf("kind: import\n");
+ break;
+ case ld::Atom::kExternalWeakDefinition:
+ printf("kind: weak import\n");
+ break;
+ case ld::Atom::kAbsoluteSymbol:
+ printf("kind: absolute symbol\n");
+ break;
+ default:
+ printf("kind: unknown\n");
+ }
+
+ // segment and section
+ if(!sPrintRestrict && (atom->section().sectionName() != NULL) )
+ printf("section: %s,%s\n", atom->section().segmentName(), atom->section().sectionName());
+
+ // attributes
+ if(!sPrintRestrict) {
+ printf("attrs: ");
+ if ( atom->dontDeadStrip() )
+ printf("dont-dead-strip ");
+ if ( atom->isThumb() )
+ printf("thumb ");
+ printf("\n");
+ }
+
+ // size
+ if(!sPrintRestrict)
+ printf("size: 0x%012llX\n", atom->size());
+
+ // alignment
+ if(!sPrintRestrict || sPrintAlign)
+ printf("align: %u mod %u\n", atom->alignment().modulus, (1 << atom->alignment().powerOf2) );
+
+ // content
+ if (!sPrintRestrict && sDumpContent ) {
+ uint64_t size = atom->size();
+ if ( size < 4096 ) {
+ uint8_t content[size];
+ atom->copyRawContent(content);
+ printf("content: ");
+ if ( atom->contentType() == ld::Atom::typeCString ) {
+ printf("\"");
+ for (unsigned int i=0; i < size; ++i) {
+ if(content[i]<'!' || content[i]>=127)
+ printf("\\%o", content[i]);
+ else
+ printf("%c", content[i]);
+ }
+ printf("\"");
+ }
+ else {
+ for (unsigned int i=0; i < size; ++i)
+ printf("%02X ", content[i]);
+ }
+ }
+ printf("\n");
+ }
+
+ // unwind info
+ if(!sPrintRestrict) {
+ if ( atom->beginUnwind() != atom->endUnwind() ) {
+ printf("unwind encodings:\n");
+ for (ld::Atom::UnwindInfo::iterator it = atom->beginUnwind(); it != atom->endUnwind(); ++it) {
+ printf("\t 0x%04X 0x%08X\n", it->startOffset, it->unwindInfo);
+ }
+ }
+ }
+#if 0
+ // references
+ if(!sPrintRestrict) {
+ std::vector<ObjectFile::Reference*>& references = atom->getReferences();
+ const int refCount = references.size();
+ printf("references: (%u)\n", refCount);
+ for (int i=0; i < refCount; ++i) {
+ ObjectFile::Reference* ref = references[i];
+ printf(" %s\n", ref->getDescription());
+ }
+ }
+#endif
+ // line info
+ if(!sPrintRestrict) {
+ if ( atom->beginLineInfo() != atom->endLineInfo() ) {
+ printf("line info:\n");
+ for (ld::Atom::LineInfo::iterator it = atom->beginLineInfo(); it != atom->endLineInfo(); ++it) {
+ printf(" offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName);
+ }
+ }
+ }
+
+ if(!sPrintRestrict)
+ printf("\n");
+}
+#endif
+struct AtomSorter
+{
+ bool operator()(const ld::Atom* left, const ld::Atom* right)
+ {
+ if ( left == right )
+ return false;
+ // first sort by segment name
+ int diff = strcmp(left->section().segmentName(), right->section().segmentName());
+ if ( diff != 0 )
+ return (diff > 0);
+
+ // then sort by section name
+ diff = strcmp(left->section().sectionName(), right->section().sectionName());
+ if ( diff != 0 )
+ return (diff < 0);
+
+ // then sort by atom name
+ diff = strcmp(left->name(), right->name());
+ if ( diff != 0 )
+ return (diff < 0);
+
+ // if cstring, sort by content
+ if ( left->contentType() == ld::Atom::typeCString ) {
+ diff = strcmp((char*)left->rawContentPointer(), (char*)right->rawContentPointer());
+ if ( diff != 0 )
+ return (diff < 0);
+ }
+ else if ( left->section().type() == ld::Section::typeCStringPointer ) {
+ // if pointer to c-string sort by name
+ const char* leftString = NULL;
+ assert(left->fixupsBegin() != left->fixupsEnd());
+ for (ld::Fixup::iterator fit = left->fixupsBegin(); fit != left->fixupsEnd(); ++fit) {
+ if ( fit->binding == ld::Fixup::bindingByContentBound ) {
+ const ld::Atom* cstringAtom = fit->u.target;
+ assert(cstringAtom->contentType() == ld::Atom::typeCString);
+ leftString = (char*)cstringAtom->rawContentPointer();
+ }
+ }
+ const char* rightString = NULL;
+ assert(right->fixupsBegin() != right->fixupsEnd());
+ for (ld::Fixup::iterator fit = right->fixupsBegin(); fit != right->fixupsEnd(); ++fit) {
+ if ( fit->binding == ld::Fixup::bindingByContentBound ) {
+ const ld::Atom* cstringAtom = fit->u.target;
+ assert(cstringAtom->contentType() == ld::Atom::typeCString);
+ rightString = (char*)cstringAtom->rawContentPointer();
+ }
+ }
+ assert(leftString != NULL);
+ assert(rightString != NULL);
+ diff = strcmp(leftString, rightString);
+ if ( diff != 0 )
+ return (diff < 0);
+ }
+ else if ( left->section().type() == ld::Section::typeLiteral4 ) {
+ // if literal sort by content
+ uint32_t leftValue = *(uint32_t*)left->rawContentPointer();
+ uint32_t rightValue = *(uint32_t*)right->rawContentPointer();
+ diff = (leftValue - rightValue);
+ if ( diff != 0 )
+ return (diff < 0);
+ }
+ else if ( left->section().type() == ld::Section::typeCFI ) {
+ // if __he_frame sort by address
+ diff = (left->objectAddress() - right->objectAddress());
+ if ( diff != 0 )
+ return (diff < 0);
+ }
+ else if ( left->section().type() == ld::Section::typeNonLazyPointer ) {
+ // if non-lazy-pointer sort by name
+ const char* leftString = NULL;
+ assert(left->fixupsBegin() != left->fixupsEnd());
+ for (ld::Fixup::iterator fit = left->fixupsBegin(); fit != left->fixupsEnd(); ++fit) {
+ if ( fit->binding == ld::Fixup::bindingByNameUnbound ) {
+ leftString = fit->u.name;
+ }
+ else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+ leftString = fit->u.target->name();
+ }
+ }
+ const char* rightString = NULL;
+ assert(right->fixupsBegin() != right->fixupsEnd());
+ for (ld::Fixup::iterator fit = right->fixupsBegin(); fit != right->fixupsEnd(); ++fit) {
+ if ( fit->binding == ld::Fixup::bindingByNameUnbound ) {
+ rightString = fit->u.name;
+ }
+ else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+ rightString = fit->u.target->name();
+ }
+ }
+ assert(leftString != NULL);
+ assert(rightString != NULL);
+ diff = strcmp(leftString, rightString);
+ if ( diff != 0 )
+ return (diff < 0);
+ }
+
+ // else sort by size
+ return (left->size() < right->size());
+ }
+};
+
+
+class dumper : public ld::File::AtomHandler
+{
+public:
+ void dump();
+ virtual void doAtom(const ld::Atom&);
+ virtual void doFile(const ld::File&) {}
+private:
+ void dumpAtom(const ld::Atom& atom);
+ const char* scopeString(const ld::Atom&);
+ const char* definitionString(const ld::Atom&);
+ const char* combineString(const ld::Atom&);
+ const char* inclusionString(const ld::Atom&);
+ const char* attributeString(const ld::Atom&);
+ const char* makeName(const ld::Atom& atom);
+ const char* referenceTargetAtomName(const ld::Fixup* ref);
+ void dumpFixup(const ld::Fixup* ref);
+
+ uint64_t addressOfFirstAtomInSection(const ld::Section&);
+
+ std::vector<const ld::Atom*> _atoms;
+};
+
+const char* dumper::scopeString(const ld::Atom& atom)
+{
+ switch ( (ld::Atom::Scope)atom.scope() ) {
+ case ld::Atom::scopeTranslationUnit:
+ return "translation-unit";
+ case ld::Atom::scopeLinkageUnit:
+ return "hidden";
+ case ld::Atom::scopeGlobal:
+ if ( atom.autoHide() )
+ return "global but automatically hidden";
+ else
+ return "global";
+ }
+ return "UNKNOWN";
+}
+
+const char* dumper::definitionString(const ld::Atom& atom)
+{
+ switch ( (ld::Atom::Definition)atom.definition() ) {
+ case ld::Atom::definitionRegular:
+ return "regular";
+ case ld::Atom::definitionTentative:
+ return "tentative";
+ case ld::Atom::definitionAbsolute:
+ return "absolute";
+ case ld::Atom::definitionProxy:
+ return "proxy";
+ }
+ return "UNKNOWN";
+}
+
+const char* dumper::combineString(const ld::Atom& atom)
+{
+ switch ( (ld::Atom::Combine)atom.combine() ) {
+ case ld::Atom::combineNever:
+ return "never";
+ case ld::Atom::combineByName:
+ return "by-name";
+ case ld::Atom::combineByNameAndContent:
+ return "by-name-and-content";
+ case ld::Atom::combineByNameAndReferences:
+ return "by-name-and-references";
+ }
+ return "UNKNOWN";
+}
+
+const char* dumper::inclusionString(const ld::Atom& atom)
+{
+ switch ( (ld::Atom::SymbolTableInclusion)atom.symbolTableInclusion() ) {
+ case ld::Atom::symbolTableNotIn:
+ return "not in";
+ case ld::Atom::symbolTableNotInFinalLinkedImages:
+ return "not in final linked images";
+ case ld::Atom::symbolTableIn:
+ return "in";
+ case ld::Atom::symbolTableInAndNeverStrip:
+ return "in and never strip";
+ case ld::Atom::symbolTableInAsAbsolute:
+ return "in as absolute";
+ case ld::Atom::symbolTableInWithRandomAutoStripLabel:
+ return "in as random auto-strip label";
+ }
+ return "UNKNOWN";
+}
+
+
+
+const char* dumper::attributeString(const ld::Atom& atom)
+{
+ static char buffer[256];
+ buffer[0] = '\0';
+
+ if ( atom.dontDeadStrip() )
+ strcat(buffer, "dont-dead-strip ");
+
+ if ( atom.isThumb() )
+ strcat(buffer, "thumb ");
+
+ if ( atom.isAlias() )
+ strcat(buffer, "alias ");
+
+ if ( atom.contentType() == ld::Atom::typeResolver )
+ strcat(buffer, "resolver ");
+
+ return buffer;
+}
+
+const char* dumper::makeName(const ld::Atom& atom)
+{
+ static char buffer[4096];
+ strcpy(buffer, "???");
+ switch ( atom.symbolTableInclusion() ) {
+ case ld::Atom::symbolTableNotIn:
+ if ( atom.contentType() == ld::Atom::typeCString ) {
+ strcpy(buffer, "cstring=");
+ strlcat(buffer, (char*)atom.rawContentPointer(), 4096);
+ }
+ else if ( atom.section().type() == ld::Section::typeLiteral4 ) {
+ char temp[16];
+ strcpy(buffer, "literal4=");
+ uint32_t value = *(uint32_t*)atom.rawContentPointer();
+ sprintf(temp, "0x%08X", value);
+ strcat(buffer, temp);
+ }
+ else if ( atom.section().type() == ld::Section::typeLiteral8 ) {
+ char temp[32];
+ strcpy(buffer, "literal8=");
+ uint32_t value1 = *(uint32_t*)atom.rawContentPointer();
+ uint32_t value2 = ((uint32_t*)atom.rawContentPointer())[1];
+ sprintf(temp, "0x%08X%08X", value1, value2);
+ strcat(buffer, temp);
+ }
+ else if ( atom.section().type() == ld::Section::typeLiteral16 ) {
+ char temp[64];
+ strcpy(buffer, "literal16=");
+ uint32_t value1 = *(uint32_t*)atom.rawContentPointer();
+ uint32_t value2 = ((uint32_t*)atom.rawContentPointer())[1];
+ uint32_t value3 = ((uint32_t*)atom.rawContentPointer())[2];
+ uint32_t value4 = ((uint32_t*)atom.rawContentPointer())[3];
+ sprintf(temp, "0x%08X%08X%08X%08X", value1, value2, value3, value4);
+ strcat(buffer, temp);
+ }
+ else if ( atom.section().type() == ld::Section::typeCStringPointer ) {
+ assert(atom.fixupsBegin() != atom.fixupsEnd());
+ for (ld::Fixup::iterator fit = atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
+ if ( fit->binding == ld::Fixup::bindingByContentBound ) {
+ const ld::Atom* cstringAtom = fit->u.target;
+ if ( (cstringAtom != NULL) && (cstringAtom->contentType() == ld::Atom::typeCString) ) {
+ strlcpy(buffer, atom.name(), 4096);
+ strlcat(buffer, "=", 4096);
+ strlcat(buffer, (char*)cstringAtom->rawContentPointer(), 4096);
+ }
+ }
+ }
+ }
+ else if ( atom.section().type() == ld::Section::typeNonLazyPointer ) {
+ assert(atom.fixupsBegin() != atom.fixupsEnd());
+ for (ld::Fixup::iterator fit = atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
+ if ( fit->binding == ld::Fixup::bindingByNameUnbound ) {
+ strcpy(buffer, "non-lazy-pointer-to:");
+ strlcat(buffer, fit->u.name, 4096);
+ return buffer;
+ }
+ else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+ strcpy(buffer, "non-lazy-pointer-to-local:");
+ strlcat(buffer, fit->u.target->name(), 4096);
+ return buffer;
+ }
+ }
+ strlcpy(buffer, atom.name(), 4096);
+ }
+ else {
+ uint64_t sectAddr = addressOfFirstAtomInSection(atom.section());
+ sprintf(buffer, "%s@%s+0x%08llX", atom.name(), atom.section().sectionName(), atom.objectAddress()-sectAddr);
+ }
+ break;
+ case ld::Atom::symbolTableNotInFinalLinkedImages:
+ case ld::Atom::symbolTableIn:
+ case ld::Atom::symbolTableInAndNeverStrip:
+ case ld::Atom::symbolTableInAsAbsolute:
+ case ld::Atom::symbolTableInWithRandomAutoStripLabel:
+ strlcpy(buffer, atom.name(), 4096);
+ break;
+ }
+ return buffer;
+}
+
+const char* dumper::referenceTargetAtomName(const ld::Fixup* ref)
+{
+ static char buffer[4096];
+ switch ( ref->binding ) {
+ case ld::Fixup::bindingNone:
+ return "NO BINDING";
+ case ld::Fixup::bindingByNameUnbound:
+ strcpy(buffer, "by-name(");
+ strlcat(buffer, ref->u.name, 4096);
+ strlcat(buffer, ")", 4096);
+ return buffer;
+ //return ref->u.name;
+ case ld::Fixup::bindingByContentBound:
+ strcpy(buffer, "by-content(");
+ strlcat(buffer, makeName(*ref->u.target), 4096);
+ strlcat(buffer, ")", 4096);
+ return buffer;
+ case ld::Fixup::bindingDirectlyBound:
+ strcpy(buffer, "direct(");
+ strlcat(buffer, makeName(*ref->u.target), 4096);
+ strlcat(buffer, ")", 4096);
+ return buffer;
+ case ld::Fixup::bindingsIndirectlyBound:
+ return "BOUND INDIRECTLY";
+ }
+ return "BAD BINDING";
+}
+
+
+void dumper::dumpFixup(const ld::Fixup* ref)
+{
+ if ( ref->weakImport ) {
+ printf("weak_import ");
+ }
+ switch ( (ld::Fixup::Kind)(ref->kind) ) {
+ case ld::Fixup::kindNone:
+ printf("none");
+ break;
+ case ld::Fixup::kindNoneFollowOn:
+ printf("followed by %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindNoneGroupSubordinate:
+ printf("group subordinate %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindNoneGroupSubordinateFDE:
+ printf("group subordinate FDE %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindNoneGroupSubordinateLSDA:
+ printf("group subordinate LSDA %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindNoneGroupSubordinatePersonality:
+ printf("group subordinate personality %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindSetTargetAddress:
+ printf("%s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindSubtractTargetAddress:
+ printf(" - %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindAddAddend:
+ printf(" + 0x%llX", ref->u.addend);
+ break;
+ case ld::Fixup::kindSubtractAddend:
+ printf(" - 0x%llX", ref->u.addend);
+ break;
+ case ld::Fixup::kindSetTargetImageOffset:
+ printf("imageOffset(%s)", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindSetTargetSectionOffset:
+ printf("sectionOffset(%s)", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStore8:
+ printf(", then store byte");
+ break;
+ case ld::Fixup::kindStoreLittleEndian16:
+ printf(", then store 16-bit little endian");
+ break;
+ case ld::Fixup::kindStoreLittleEndianLow24of32:
+ printf(", then store low 24-bit little endian");
+ break;
+ case ld::Fixup::kindStoreLittleEndian32:
+ printf(", then store 32-bit little endian");
+ break;
+ case ld::Fixup::kindStoreLittleEndian64:
+ printf(", then store 64-bit little endian");
+ break;
+ case ld::Fixup::kindStoreBigEndian16:
+ printf(", then store 16-bit big endian");
+ break;
+ case ld::Fixup::kindStoreBigEndianLow24of32:
+ printf(", then store low 24-bit big endian");
+ break;
+ case ld::Fixup::kindStoreBigEndian32:
+ printf(", then store 32-bit big endian");
+ break;
+ case ld::Fixup::kindStoreBigEndian64:
+ printf(", then store 64-bit big endian");
+ break;
+ case ld::Fixup::kindStoreX86BranchPCRel8:
+ printf(", then store as x86 8-bit pcrel branch");
+ break;
+ case ld::Fixup::kindStoreX86BranchPCRel32:
+ printf(", then store as x86 32-bit pcrel branch");
+ break;
+ case ld::Fixup::kindStoreX86PCRel8:
+ printf(", then store as x86 8-bit pcrel");
+ break;
+ case ld::Fixup::kindStoreX86PCRel16:
+ printf(", then store as x86 16-bit pcrel");
+ break;
+ case ld::Fixup::kindStoreX86PCRel32:
+ printf(", then store as x86 32-bit pcrel");
+ break;
+ case ld::Fixup::kindStoreX86PCRel32_1:
+ printf(", then store as x86 32-bit pcrel from +1");
+ break;
+ case ld::Fixup::kindStoreX86PCRel32_2:
+ printf(", then store as x86 32-bit pcrel from +2");
+ break;
+ case ld::Fixup::kindStoreX86PCRel32_4:
+ printf(", then store as x86 32-bit pcrel from +4");
+ break;
+ case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+ printf(", then store as x86 32-bit pcrel GOT load");
+ break;
+ case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
+ printf(", then store as x86 32-bit pcrel GOT load -> LEA");
+ break;
+ case ld::Fixup::kindStoreX86PCRel32GOT:
+ printf(", then store as x86 32-bit pcrel GOT access");
+ break;
+ case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+ printf(", then store as x86 32-bit pcrel TLV load");
+ break;
+ case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
+ printf(", then store as x86 32-bit pcrel TLV load");
+ break;
+ case ld::Fixup::kindStoreX86Abs32TLVLoad:
+ printf(", then store as x86 32-bit absolute TLV load");
+ break;
+ case ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA:
+ printf(", then store as x86 32-bit absolute TLV load -> LEA");
+ break;
+ case ld::Fixup::kindStoreARMBranch24:
+ printf(", then store as ARM 24-bit pcrel branch");
+ break;
+ case ld::Fixup::kindStoreThumbBranch22:
+ printf(", then store as Thumb 22-bit pcrel branch");
+ break;
+ case ld::Fixup::kindStoreARMLoad12:
+ printf(", then store as ARM 12-bit pcrel load");
+ break;
+ case ld::Fixup::kindStoreARMLow16:
+ printf(", then store low-16 in ARM movw");
+ break;
+ case ld::Fixup::kindStoreARMHigh16:
+ printf(", then store high-16 in ARM movt");
+ break;
+ case ld::Fixup::kindStoreThumbLow16:
+ printf(", then store low-16 in Thumb movw");
+ break;
+ case ld::Fixup::kindStoreThumbHigh16:
+ printf(", then store high-16 in Thumb movt");
+ break;
+ case ld::Fixup::kindDtraceExtra:
+ printf("dtrace static probe extra info");
+ break;
+ case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+ printf("x86 dtrace static probe site");
+ break;
+ case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+ printf("x86 dtrace static is-enabled site");
+ break;
+ case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+ printf("ARM dtrace static probe site");
+ break;
+ case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+ printf("ARM dtrace static is-enabled site");
+ break;
+ case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+ printf("Thumb dtrace static probe site");
+ break;
+ case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+ printf("Thumb dtrace static is-enabled site");
+ break;
+ case ld::Fixup::kindLazyTarget:
+ printf("lazy reference to external symbol %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindSetLazyOffset:
+ printf("offset of lazy binding info for %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindDataInCodeStartData:
+ printf("start of data in code");
+ break;
+ case ld::Fixup::kindDataInCodeStartJT8:
+ printf("start of jump table 8 data in code");
+ break;
+ case ld::Fixup::kindDataInCodeStartJT16:
+ printf("start of jump table 16 data in code");
+ break;
+ case ld::Fixup::kindDataInCodeStartJT32:
+ printf("start of jump table 32 data in code");
+ break;
+ case ld::Fixup::kindDataInCodeStartJTA32:
+ printf("start of jump table absolute 32 data in code");
+ break;
+ case ld::Fixup::kindDataInCodeEnd:
+ printf("end of data in code");
+ break;
+ case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ printf("store 32-bit little endian address of %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+ printf("store 64-bit little endian address of %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressBigEndian32:
+ printf("store 32-bit big endian address of %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressBigEndian64:
+ printf("store 64-bit big endian address of %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+ printf("x86 store 32-bit pc-rel address of %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+ printf("x86 store 32-bit pc-rel branch to %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+ printf("x86 store 32-bit pc-rel GOT load of %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+ printf("x86 store 32-bit pc-rel lea of %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+ printf("x86 store 32-bit pc-rel TLV load of %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
+ printf("x86 store 32-bit pc-rel TLV lea of %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+ printf("x86 store 32-bit absolute TLV load of %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA:
+ printf("x86 store 32-bit absolute TLV lea of %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressARMBranch24:
+ printf("ARM store 24-bit pc-rel branch to %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+ printf("Thumb store 22-bit pc-rel branch to %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressARMLoad12:
+ printf("ARM store 12-bit pc-rel branch to %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindSetTargetTLVTemplateOffset:
+ case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32:
+ case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64:
+ printf("tlv template offset of %s", referenceTargetAtomName(ref));
+ //default:
+ // printf("unknown fixup");
+ // break;
+ }
+}
+
+uint64_t dumper::addressOfFirstAtomInSection(const ld::Section& sect)
+{
+ uint64_t lowestAddr = (uint64_t)(-1);
+ for (std::vector<const ld::Atom*>::iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ const ld::Atom* atom = *it;
+ if ( &atom->section() == § ) {
+ if ( atom->objectAddress() < lowestAddr )
+ lowestAddr = atom->objectAddress();
+ }
+ }
+ return lowestAddr;
+}
+
+void dumper::doAtom(const ld::Atom& atom)
+{
+ if ( (sMatchName != NULL) && (strcmp(sMatchName, atom.name()) != 0) )
+ return;
+ _atoms.push_back(&atom);
+}
+
+void dumper::dump()
+{
+ if ( sSort )
+ std::sort(_atoms.begin(), _atoms.end(), AtomSorter());
+
+ for (std::vector<const ld::Atom*>::iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ this->dumpAtom(**it);
+ }
+}
+
+void dumper::dumpAtom(const ld::Atom& atom)
+{
+ printf("name: %s\n", makeName(atom));
+ printf("size: 0x%0llX\n", atom.size());
+ printf("align: %u mod %u\n", atom.alignment().modulus, (1 << atom.alignment().powerOf2) );
+ printf("scope: %s\n", scopeString(atom));
+ if ( sShowDefinitionKind )
+ printf("def: %s\n", definitionString(atom));
+ if ( sShowCombineKind )
+ printf("combine: %s\n", combineString(atom));
+ printf("symbol: %s\n", inclusionString(atom));
+ printf("attrs: %s\n", attributeString(atom));
+ if ( sShowSection )
+ printf("section: %s,%s\n", atom.section().segmentName(), atom.section().sectionName());
+ if ( atom.beginUnwind() != atom.endUnwind() ) {
+ uint32_t lastOffset = 0;
+ uint32_t lastCUE = 0;
+ bool first = true;
+ const char* label = "unwind:";
+ for (ld::Atom::UnwindInfo::iterator it=atom.beginUnwind(); it != atom.endUnwind(); ++it) {
+ if ( !first ) {
+ printf("%s 0x%08X -> 0x%08X: 0x%08X\n", label, lastOffset, it->startOffset, lastCUE);
+ label = " ";
+ }
+ lastOffset = it->startOffset;
+ lastCUE = it->unwindInfo;
+ first = false;
+ }
+ printf("%s 0x%08X -> 0x%08X: 0x%08X\n", label, lastOffset, (uint32_t)atom.size(), lastCUE);
+ }
+ if ( atom.contentType() == ld::Atom::typeCString ) {
+ uint8_t buffer[atom.size()+2];
+ atom.copyRawContent(buffer);
+ buffer[atom.size()] = '\0';
+ printf("content: \"%s\"\n", buffer);
+ }
+ if ( atom.fixupsBegin() != atom.fixupsEnd() ) {
+ printf("fixups:\n");
+ for (unsigned int off=0; off < atom.size()+1; ++off) {
+ for (ld::Fixup::iterator it = atom.fixupsBegin(); it != atom.fixupsEnd(); ++it) {
+ if ( it->offsetInAtom == off ) {
+ switch ( it->clusterSize ) {
+ case ld::Fixup::k1of1:
+ printf(" 0x%04X ", it->offsetInAtom);
+ dumpFixup(it);
+ break;
+ case ld::Fixup::k1of2:
+ printf(" 0x%04X ", it->offsetInAtom);
+ dumpFixup(it);
+ ++it;
+ dumpFixup(it);
+ break;
+ case ld::Fixup::k1of3:
+ printf(" 0x%04X ", it->offsetInAtom);
+ dumpFixup(it);
+ ++it;
+ dumpFixup(it);
+ ++it;
+ dumpFixup(it);
+ break;
+ case ld::Fixup::k1of4:
+ printf(" 0x%04X ", it->offsetInAtom);
+ dumpFixup(it);
+ ++it;
+ dumpFixup(it);
+ ++it;
+ dumpFixup(it);
+ ++it;
+ dumpFixup(it);
+ break;
+ case ld::Fixup::k1of5:
+ printf(" 0x%04X ", it->offsetInAtom);
+ dumpFixup(it);
+ ++it;
+ dumpFixup(it);
+ ++it;
+ dumpFixup(it);
+ ++it;
+ dumpFixup(it);
+ ++it;
+ dumpFixup(it);
+ break;
+ default:
+ printf(" BAD CLUSTER SIZE: cluster=%d\n", it->clusterSize);
+ }
+ printf("\n");
+ }
+ }
+ }
+ }
+ if ( sShowLineInfo ) {
+ if ( atom.beginLineInfo() != atom.endLineInfo() ) {
+ printf("line info:\n");
+ for (ld::Atom::LineInfo::iterator it = atom.beginLineInfo(); it != atom.endLineInfo(); ++it) {
+ printf(" offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName);
+ }
+ }
+ }
+
+ printf("\n");
+}
+
+static void dumpFile(ld::relocatable::File* file)
+{
+ // stabs debug info
+ if ( sDumpStabs && (file->debugInfo() == ld::relocatable::File::kDebugInfoStabs) ) {
+ const std::vector<ld::relocatable::File::Stab>* stabs = file->stabs();
+ if ( stabs != NULL )
+ dumpStabs(stabs);
+ }
+ // dump atoms
+ dumper d;
+ file->forEachAtom(d);
+ d.dump();
+
+#if 0
+ // get all atoms
+ std::vector<ObjectFile::Atom*> atoms = reader->getAtoms();
+
+ // make copy of vector and sort (so output is canonical)
+ std::vector<ObjectFile::Atom*> sortedAtoms(atoms);
+ if ( sSort )
+ std::sort(sortedAtoms.begin(), sortedAtoms.end(), AtomSorter());
+
+ for(std::vector<ObjectFile::Atom*>::iterator it=sortedAtoms.begin(); it != sortedAtoms.end(); ++it) {
+ if ( sNMmode )
+ dumpAtomLikeNM(*it);
+ else
+ dumpAtom(*it);
+ }
+#endif
+}
+
+
+static ld::relocatable::File* createReader(const char* path)
+{
+ struct stat stat_buf;
+
+ int fd = ::open(path, O_RDONLY, 0);
+ if ( fd == -1 )
+ throwf("cannot open file: %s", path);
+ ::fstat(fd, &stat_buf);
+ uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+ ::close(fd);
+ if ( p == (uint8_t*)(-1) )
+ throwf("cannot mmap file: %s", path);
+ const mach_header* mh = (mach_header*)p;
+ uint64_t fileLen = stat_buf.st_size;
+ bool foundFatSlice = false;
+ if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+ const struct fat_header* fh = (struct fat_header*)p;
+ const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
+ if ( (uint32_t)sPreferredArch == 0xFFFFFFFF ) {
+ // just dump first slice of fat .o file
+ if ( OSSwapBigToHostInt32(fh->nfat_arch) > 0 ) {
+ p = p + OSSwapBigToHostInt32(archs[0].offset);
+ mh = (struct mach_header*)p;
+ fileLen = OSSwapBigToHostInt32(archs[0].size);
+ sPreferredArch = OSSwapBigToHostInt32(archs[0].cputype);
+ sPreferredSubArch = OSSwapBigToHostInt32(archs[0].cpusubtype);
+ foundFatSlice = true;
+ }
+ }
+ else {
+ for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
+ if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) {
+ if ( ((uint32_t)sPreferredSubArch == 0xFFFFFFFF) || ((uint32_t)sPreferredSubArch == OSSwapBigToHostInt32(archs[i].cpusubtype)) ) {
+ p = p + OSSwapBigToHostInt32(archs[i].offset);
+ mh = (struct mach_header*)p;
+ fileLen = OSSwapBigToHostInt32(archs[i].size);
+ foundFatSlice = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ mach_o::relocatable::ParserOptions objOpts;
+ objOpts.architecture = sPreferredArch;
+ objOpts.objSubtypeMustMatch = false;
+ objOpts.logAllFiles = false;
+ objOpts.convertUnwindInfo = true;
+ objOpts.subType = sPreferredSubArch;
+#if 1
+ if ( ! foundFatSlice ) {
+ cpu_type_t archOfObj;
+ cpu_subtype_t subArchOfObj;
+ if ( mach_o::relocatable::isObjectFile(p, &archOfObj, &subArchOfObj) ) {
+ objOpts.architecture = archOfObj;
+ objOpts.subType = subArchOfObj;
+ }
+ }
+
+ ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, ld::File::Ordinal::NullOrdinal(), objOpts);
+ if ( objResult != NULL )
+ return objResult;
+
+ // see if it is an llvm object file
+ objResult = lto::parse(p, fileLen, path, stat_buf.st_mtime, ld::File::Ordinal::NullOrdinal(), sPreferredArch, sPreferredSubArch, false);
+ if ( objResult != NULL )
+ return objResult;
+
+ throwf("not a mach-o object file: %s", path);
+#else
+ // for peformance testing
+ for (int i=0; i < 500; ++i ) {
+ ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, 0, objOpts);
+ delete objResult;
+ }
+ exit(0);
+#endif
+}
+
+static
+void
+usage()
+{
+ fprintf(stderr, "ObjectDump options:\n"
+ "\t-no_content\tdon't dump contents\n"
+ "\t-no_section\tdon't dump section name\n"
+ "\t-no_defintion\tdon't dump definition kind\n"
+ "\t-no_combine\tdon't dump combine mode\n"
+ "\t-stabs\t\tdump stabs\n"
+ "\t-arch aaa\tonly dump info about arch aaa\n"
+ "\t-only sym\tonly dump info about sym\n"
+ "\t-align\t\tonly print alignment info\n"
+ "\t-name\t\tonly print symbol names\n"
+ );
+}
+
+int main(int argc, const char* argv[])
+{
+ if(argc<2) {
+ usage();
+ return 0;
+ }
+
+ try {
+ for(int i=1; i < argc; ++i) {
+ const char* arg = argv[i];
+ if ( arg[0] == '-' ) {
+ if ( strcmp(arg, "-no_content") == 0 ) {
+ sDumpContent = false;
+ }
+ else if ( strcmp(arg, "-nm") == 0 ) {
+ sNMmode = true;
+ }
+ else if ( strcmp(arg, "-stabs") == 0 ) {
+ sDumpStabs = true;
+ }
+ else if ( strcmp(arg, "-no_sort") == 0 ) {
+ sSort = false;
+ }
+ else if ( strcmp(arg, "-no_section") == 0 ) {
+ sShowSection = false;
+ }
+ else if ( strcmp(arg, "-no_definition") == 0 ) {
+ sShowDefinitionKind = false;
+ }
+ else if ( strcmp(arg, "-no_combine") == 0 ) {
+ sShowCombineKind = false;
+ }
+ else if ( strcmp(arg, "-no_line_info") == 0 ) {
+ sShowLineInfo = false;
+ }
+ else if ( strcmp(arg, "-arch") == 0 ) {
+ const char* archName = argv[++i];
+ if ( archName == NULL )
+ throw "-arch missing architecture name";
+ bool found = false;
+ for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+ if ( strcmp(t->archName,archName) == 0 ) {
+ sPreferredArch = t->cpuType;
+ if ( t->isSubType )
+ sPreferredSubArch = t->cpuSubType;
+ found = true;
+ }
+ }
+ if ( !found )
+ throwf("unknown architecture %s", archName);
+ }
+ else if ( strcmp(arg, "-only") == 0 ) {
+ sMatchName = ++i<argc? argv[i]: NULL;
+ }
+ else if ( strcmp(arg, "-align") == 0 ) {
+ sPrintRestrict = true;
+ sPrintAlign = true;
+ }
+ else if ( strcmp(arg, "-name") == 0 ) {
+ sPrintRestrict = true;
+ sPrintName = true;
+ }
+ else {
+ usage();
+ throwf("unknown option: %s\n", arg);
+ }
+ }
+ else {
+ ld::relocatable::File* reader = createReader(arg);
+ dumpFile(reader);
+ }
+ }
+ }
+ catch (const char* msg) {
+ fprintf(stderr, "ObjDump failed: %s\n", msg);
+ return 1;
+ }
+
+ return 0;
+}
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <vector>
+
+#include "MachOFileAbstraction.hpp"
+#include "MachOTrie.hpp"
+#include "prune_trie.h"
+
+
+
+
+/*
+ * prune_trie() is a C vended function that is used by strip(1) to prune out
+ * defined exported symbols from the export trie. It is passed a pointer to
+ * the start of bytes of the the trie and the size. The prune() funciton
+ * passed is called with each symbol name in the trie to determine if it is
+ * to be pruned (retuning 1) or not (returning 0). It writes the new trie
+ * back into the trie buffer and returns the new size in trie_new_size.
+ * If the pruning succeeds, NULL is returned. If there was an error processing
+ * the trie (e.f. it is malformed), then an error message string is returned.
+ * The error string can be freed.
+ */
+const char*
+prune_trie(
+ uint8_t* trie_start,
+ uint32_t trie_start_size,
+ int (*prune)(const char *name),
+ uint32_t* trie_new_size)
+{
+ // convert trie to vector of entries
+ std::vector<mach_o::trie::Entry> originalExports;
+ try {
+ parseTrie(trie_start, trie_start+trie_start_size, originalExports);
+ }
+ catch (const char* msg) {
+ return strdup(msg);
+ }
+ catch (...) {
+ return strdup("unexpected exception processing trie");
+ }
+
+ // prune entries into new vector of entries
+ std::vector<mach_o::trie::Entry> newExports;
+ newExports.reserve(originalExports.size());
+ for(std::vector<mach_o::trie::Entry>::iterator it = originalExports.begin(); it != originalExports.end(); ++it) {
+ if ( prune(it->name) == 0 )
+ newExports.push_back(*it);
+ }
+
+ // create new export trie
+ std::vector<uint8_t> newExportTrieBytes;
+ newExportTrieBytes.reserve(trie_start_size);
+ mach_o::trie::makeTrie(newExports, newExportTrieBytes);
+ // Need to align trie to 8 or 4 bytes. We don't know the arch, but if the incoming trie
+ // was not 8-byte aligned, then it can't be a 64-bit arch, so use 4-byte alignement.
+ if ( (trie_start_size % 8) != 0 ) {
+ // 4-byte align
+ while ( (newExportTrieBytes.size() % 4 ) != 0)
+ newExportTrieBytes.push_back(0);
+ }
+ else {
+ // 8-byte align
+ while ( (newExportTrieBytes.size() % 8 ) != 0)
+ newExportTrieBytes.push_back(0);
+ }
+
+ // copy into place, zero pad
+ *trie_new_size = newExportTrieBytes.size();
+ if ( *trie_new_size > trie_start_size ) {
+ char* msg;
+ asprintf(&msg, "new trie is larger (%d) than original (%d)", *trie_new_size, trie_start_size);
+ return msg;
+ }
+ memcpy(trie_start, &newExportTrieBytes[0], *trie_new_size);
+ bzero(trie_start+*trie_new_size, trie_start_size - *trie_new_size);
+
+ // success
+ return NULL;
+}
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <vector>
+#include <set>
+#include <ext/hash_set>
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+#include "MachOTrie.hpp"
+#include "../ld/code-sign-blobs/superblob.h"
+
+static bool printRebase = false;
+static bool printBind = false;
+static bool printWeakBind = false;
+static bool printLazyBind = false;
+static bool printOpcodes = false;
+static bool printExport = false;
+static bool printExportGraph = false;
+static bool printExportNodes = false;
+static bool printSharedRegion = false;
+static bool printFunctionStarts = false;
+static bool printDylibs = false;
+static bool printDRs = false;
+static bool printDataCode = false;
+static cpu_type_t sPreferredArch = 0;
+static cpu_type_t sPreferredSubArch = 0;
+
+
+__attribute__((noreturn))
+static void throwf(const char* format, ...)
+{
+ va_list list;
+ char* p;
+ va_start(list, format);
+ vasprintf(&p, format, list);
+ va_end(list);
+
+ const char* t = p;
+ throw t;
+}
+
+
+template <typename A>
+class DyldInfoPrinter
+{
+public:
+ static bool validFile(const uint8_t* fileContent);
+ static DyldInfoPrinter<A>* make(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch)
+ { return new DyldInfoPrinter<A>(fileContent, fileLength, path, printArch); }
+ virtual ~DyldInfoPrinter() {}
+
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ class CStringEquals
+ {
+ public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+ };
+
+ typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> StringSet;
+
+ DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch);
+ void printRebaseInfo();
+ void printRebaseInfoOpcodes();
+ void printBindingInfo();
+ void printWeakBindingInfo();
+ void printLazyBindingInfo();
+ void printBindingInfoOpcodes(bool weakBinding);
+ void printWeakBindingInfoOpcodes();
+ void printLazyBindingOpcodes();
+ void printExportInfo();
+ void printExportInfoGraph();
+ void printExportInfoNodes();
+ void printRelocRebaseInfo();
+ void printSymbolTableExportInfo();
+ void printClassicLazyBindingInfo();
+ void printClassicBindingInfo();
+ void printSharedRegionInfo();
+ void printFunctionStartsInfo();
+ void printDylibsInfo();
+ void printDRInfo();
+ void printDataInCode();
+ void printFunctionStartLine(uint64_t addr);
+ const uint8_t* printSharedRegionInfoForEachULEB128Address(const uint8_t* p, uint8_t kind);
+ pint_t relocBase();
+ const char* relocTypeName(uint8_t r_type);
+ uint8_t segmentIndexForAddress(pint_t addr);
+ void processExportGraphNode(const uint8_t* const start, const uint8_t* const end,
+ const uint8_t* parent, const uint8_t* p,
+ char* cummulativeString, int curStrOffset);
+ void gatherNodeStarts(const uint8_t* const start, const uint8_t* const end,
+ const uint8_t* parent, const uint8_t* p,
+ std::vector<uint32_t>& nodeStarts);
+ const char* rebaseTypeName(uint8_t type);
+ const char* bindTypeName(uint8_t type);
+ pint_t segStartAddress(uint8_t segIndex);
+ const char* segmentName(uint8_t segIndex);
+ const char* sectionName(uint8_t segIndex, pint_t address);
+ const char* getSegAndSectName(uint8_t segIndex, pint_t address);
+ const char* ordinalName(int libraryOrdinal);
+ const char* classicOrdinalName(int libraryOrdinal);
+ pint_t* mappedAddressForVMAddress(pint_t vmaddress);
+ const char* symbolNameForAddress(uint64_t);
+
+
+ const char* fPath;
+ const macho_header<P>* fHeader;
+ uint64_t fLength;
+ const char* fStrings;
+ const char* fStringsEnd;
+ const macho_nlist<P>* fSymbols;
+ uint32_t fSymbolCount;
+ const macho_dyld_info_command<P>* fInfo;
+ const macho_linkedit_data_command<P>* fSharedRegionInfo;
+ const macho_linkedit_data_command<P>* fFunctionStartsInfo;
+ const macho_linkedit_data_command<P>* fDataInCode;
+ const macho_linkedit_data_command<P>* fDRInfo;
+ uint64_t fBaseAddress;
+ const macho_dysymtab_command<P>* fDynamicSymbolTable;
+ const macho_segment_command<P>* fFirstSegment;
+ const macho_segment_command<P>* fFirstWritableSegment;
+ bool fWriteableSegmentWithAddrOver4G;
+ std::vector<const macho_segment_command<P>*>fSegments;
+ std::vector<const char*> fDylibs;
+ std::vector<const macho_dylib_command<P>*> fDylibLoadCommands;
+};
+
+
+
+template <>
+bool DyldInfoPrinter<ppc>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_POWERPC )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_DYLIB_STUB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ return true;
+ }
+ return false;
+}
+
+template <>
+bool DyldInfoPrinter<ppc64>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_POWERPC64 )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_DYLIB_STUB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ return true;
+ }
+ return false;
+}
+
+template <>
+bool DyldInfoPrinter<x86>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_I386 )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_DYLIB_STUB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ return true;
+ }
+ return false;
+}
+
+template <>
+bool DyldInfoPrinter<x86_64>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_X86_64 )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_DYLIB_STUB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ return true;
+ }
+ return false;
+}
+
+#if SUPPORT_ARCH_arm_any
+template <>
+bool DyldInfoPrinter<arm>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_ARM )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_DYLIB_STUB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ return true;
+ }
+ return false;
+}
+#endif
+
+template <typename A>
+DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch)
+ : fHeader(NULL), fLength(fileLength),
+ fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fInfo(NULL),
+ fSharedRegionInfo(NULL), fFunctionStartsInfo(NULL), fDataInCode(NULL), fDRInfo(NULL),
+ fBaseAddress(0), fDynamicSymbolTable(NULL), fFirstSegment(NULL), fFirstWritableSegment(NULL),
+ fWriteableSegmentWithAddrOver4G(false)
+{
+ // sanity check
+ if ( ! validFile(fileContent) )
+ throw "not a mach-o file that can be checked";
+
+ fPath = strdup(path);
+ fHeader = (const macho_header<P>*)fileContent;
+
+ // get LC_DYLD_INFO
+ const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
+ const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
+ if ( endOfCmd > endOfLoadCommands )
+ throwf("load command #%d extends beyond the end of the load commands", i);
+ if ( endOfCmd > endOfFile )
+ throwf("load command #%d extends beyond the end of the file", i);
+ switch ( cmd->cmd() ) {
+ case LC_DYLD_INFO:
+ case LC_DYLD_INFO_ONLY:
+ fInfo = (macho_dyld_info_command<P>*)cmd;
+ break;
+ case macho_segment_command<P>::CMD:
+ {
+ const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+ fSegments.push_back(segCmd);
+ if ( (segCmd->fileoff() == 0) && (segCmd->filesize() != 0) )
+ fBaseAddress = segCmd->vmaddr();
+ if ( fFirstSegment == NULL )
+ fFirstSegment = segCmd;
+ if ( (segCmd->initprot() & VM_PROT_WRITE) != 0 ) {
+ if ( fFirstWritableSegment == NULL )
+ fFirstWritableSegment = segCmd;
+ if ( segCmd->vmaddr() > 0x100000000ULL )
+ fWriteableSegmentWithAddrOver4G = true;
+ }
+ }
+ break;
+ case LC_LOAD_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ case LC_REEXPORT_DYLIB:
+ case LC_LOAD_UPWARD_DYLIB:
+ case LC_LAZY_LOAD_DYLIB:
+ {
+ const macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
+ fDylibLoadCommands.push_back(dylib);
+ const char* lastSlash = strrchr(dylib->name(), '/');
+ const char* leafName = (lastSlash != NULL) ? lastSlash+1 : dylib->name();
+ const char* firstDot = strchr(leafName, '.');
+ if ( firstDot != NULL ) {
+ char* t = strdup(leafName);
+ t[firstDot-leafName] = '\0';
+ fDylibs.push_back(t);
+ }
+ else {
+ fDylibs.push_back(leafName);
+ }
+ }
+ break;
+ case LC_DYSYMTAB:
+ fDynamicSymbolTable = (macho_dysymtab_command<P>*)cmd;
+ break;
+ case LC_SYMTAB:
+ {
+ const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
+ fSymbolCount = symtab->nsyms();
+ fSymbols = (const macho_nlist<P>*)((char*)fHeader + symtab->symoff());
+ fStrings = (char*)fHeader + symtab->stroff();
+ fStringsEnd = fStrings + symtab->strsize();
+ }
+ break;
+ case LC_SEGMENT_SPLIT_INFO:
+ fSharedRegionInfo = (macho_linkedit_data_command<P>*)cmd;
+ break;
+ case LC_FUNCTION_STARTS:
+ fFunctionStartsInfo = (macho_linkedit_data_command<P>*)cmd;
+ break;
+ case LC_DATA_IN_CODE:
+ fDataInCode = (macho_linkedit_data_command<P>*)cmd;
+ break;
+ case LC_DYLIB_CODE_SIGN_DRS:
+ fDRInfo = (macho_linkedit_data_command<P>*)cmd;
+ break;
+ }
+ cmd = (const macho_load_command<P>*)endOfCmd;
+ }
+
+ if ( printArch ) {
+ for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+ if ( (cpu_type_t)fHeader->cputype() == t->cpuType ) {
+ if ( t->isSubType && ((cpu_subtype_t)fHeader->cpusubtype() != t->cpuSubType) )
+ continue;
+ printf("for arch %s:\n", t->archName);
+ }
+ }
+ }
+
+ if ( printRebase ) {
+ if ( fInfo != NULL )
+ printRebaseInfo();
+ else
+ printRelocRebaseInfo();
+ }
+ if ( printBind ) {
+ if ( fInfo != NULL )
+ printBindingInfo();
+ else
+ printClassicBindingInfo();
+ }
+ if ( printWeakBind )
+ printWeakBindingInfo();
+ if ( printLazyBind ) {
+ if ( fInfo != NULL )
+ printLazyBindingInfo();
+ else
+ printClassicLazyBindingInfo();
+ }
+ if ( printExport ) {
+ if ( fInfo != NULL )
+ printExportInfo();
+ else
+ printSymbolTableExportInfo();
+ }
+ if ( printOpcodes ) {
+ printRebaseInfoOpcodes();
+ printBindingInfoOpcodes(false);
+ printBindingInfoOpcodes(true);
+ printLazyBindingOpcodes();
+ }
+ if ( printExportGraph )
+ printExportInfoGraph();
+ if ( printExportNodes )
+ printExportInfoNodes();
+ if ( printSharedRegion )
+ printSharedRegionInfo();
+ if ( printFunctionStarts )
+ printFunctionStartsInfo();
+ if ( printDylibs )
+ printDylibsInfo();
+ if ( printDRs )
+ printDRInfo();
+ if ( printDataCode )
+ printDataInCode();
+}
+
+static uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end)
+{
+ uint64_t result = 0;
+ int bit = 0;
+ do {
+ if (p == end)
+ throwf("malformed uleb128");
+
+ uint64_t slice = *p & 0x7f;
+
+ if (bit >= 64 || slice << bit >> bit != slice)
+ throwf("uleb128 too big");
+ else {
+ result |= (slice << bit);
+ bit += 7;
+ }
+ }
+ while (*p++ & 0x80);
+ return result;
+}
+
+static int64_t read_sleb128(const uint8_t*& p, const uint8_t* end)
+{
+ int64_t result = 0;
+ int bit = 0;
+ uint8_t byte;
+ do {
+ if (p == end)
+ throwf("malformed sleb128");
+ byte = *p++;
+ result |= (((int64_t)(byte & 0x7f)) << bit);
+ bit += 7;
+ } while (byte & 0x80);
+ // sign extend negative numbers
+ if ( (byte & 0x40) != 0 )
+ result |= (-1LL) << bit;
+ return result;
+}
+
+
+template <typename A>
+const char* DyldInfoPrinter<A>::rebaseTypeName(uint8_t type)
+{
+ switch (type ){
+ case REBASE_TYPE_POINTER:
+ return "pointer";
+ case REBASE_TYPE_TEXT_ABSOLUTE32:
+ return "text abs32";
+ case REBASE_TYPE_TEXT_PCREL32:
+ return "text rel32";
+ }
+ return "!!unknown!!";
+}
+
+
+template <typename A>
+const char* DyldInfoPrinter<A>::bindTypeName(uint8_t type)
+{
+ switch (type ){
+ case BIND_TYPE_POINTER:
+ return "pointer";
+ case BIND_TYPE_TEXT_ABSOLUTE32:
+ return "text abs32";
+ case BIND_TYPE_TEXT_PCREL32:
+ return "text rel32";
+ }
+ return "!!unknown!!";
+}
+
+
+template <typename A>
+typename A::P::uint_t DyldInfoPrinter<A>::segStartAddress(uint8_t segIndex)
+{
+ if ( segIndex > fSegments.size() )
+ throw "segment index out of range";
+ return fSegments[segIndex]->vmaddr();
+}
+
+template <typename A>
+const char* DyldInfoPrinter<A>::segmentName(uint8_t segIndex)
+{
+ if ( segIndex > fSegments.size() )
+ throw "segment index out of range";
+ return fSegments[segIndex]->segname();
+}
+
+template <typename A>
+const char* DyldInfoPrinter<A>::sectionName(uint8_t segIndex, pint_t address)
+{
+ if ( segIndex > fSegments.size() )
+ throw "segment index out of range";
+ const macho_segment_command<P>* segCmd = fSegments[segIndex];
+ macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+ macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()];
+ for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+ if ( (sect->addr() <= address) && (address < (sect->addr()+sect->size())) ) {
+ if ( strlen(sect->sectname()) > 15 ) {
+ static char temp[18];
+ strlcpy(temp, sect->sectname(), 17);
+ return temp;
+ }
+ else {
+ return sect->sectname();
+ }
+ }
+ }
+ return "??";
+}
+
+template <typename A>
+const char* DyldInfoPrinter<A>::getSegAndSectName(uint8_t segIndex, pint_t address)
+{
+ static char buffer[64];
+ strcpy(buffer, segmentName(segIndex));
+ strcat(buffer, "/");
+ const macho_segment_command<P>* segCmd = fSegments[segIndex];
+ macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+ macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()];
+ for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+ if ( (sect->addr() <= address) && (address < (sect->addr()+sect->size())) ) {
+ // section name may not be zero terminated
+ char* end = &buffer[strlen(buffer)];
+ strlcpy(end, sect->sectname(), 16);
+ return buffer;
+ }
+ }
+ return "??";
+}
+
+template <typename A>
+uint8_t DyldInfoPrinter<A>::segmentIndexForAddress(pint_t address)
+{
+ for(unsigned int i=0; i < fSegments.size(); ++i) {
+ if ( (fSegments[i]->vmaddr() <= address) && (address < (fSegments[i]->vmaddr()+fSegments[i]->vmsize())) ) {
+ return i;
+ }
+ }
+ throwf("address 0x%llX is not in any segment", (uint64_t)address);
+}
+
+template <typename A>
+typename A::P::uint_t* DyldInfoPrinter<A>::mappedAddressForVMAddress(pint_t vmaddress)
+{
+ for(unsigned int i=0; i < fSegments.size(); ++i) {
+ if ( (fSegments[i]->vmaddr() <= vmaddress) && (vmaddress < (fSegments[i]->vmaddr()+fSegments[i]->vmsize())) ) {
+ unsigned long offsetInMappedFile = fSegments[i]->fileoff()+vmaddress-fSegments[i]->vmaddr();
+ return (pint_t*)((uint8_t*)fHeader + offsetInMappedFile);
+ }
+ }
+ throwf("address 0x%llX is not in any segment", (uint64_t)vmaddress);
+}
+
+template <typename A>
+const char* DyldInfoPrinter<A>::ordinalName(int libraryOrdinal)
+{
+ switch ( libraryOrdinal) {
+ case BIND_SPECIAL_DYLIB_SELF:
+ return "this-image";
+ case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:
+ return "main-executable";
+ case BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
+ return "flat-namespace";
+ }
+ if ( libraryOrdinal < BIND_SPECIAL_DYLIB_FLAT_LOOKUP )
+ throw "unknown special ordinal";
+ if ( libraryOrdinal > (int)fDylibs.size() )
+ throw "libraryOrdinal out of range";
+ return fDylibs[libraryOrdinal-1];
+}
+
+template <typename A>
+const char* DyldInfoPrinter<A>::classicOrdinalName(int libraryOrdinal)
+{
+ if ( (fHeader->flags() & MH_TWOLEVEL) == 0 )
+ return "flat-namespace";
+ switch ( libraryOrdinal) {
+ case SELF_LIBRARY_ORDINAL:
+ return "this-image";
+ case EXECUTABLE_ORDINAL:
+ return "main-executable";
+ case DYNAMIC_LOOKUP_ORDINAL:
+ return "flat-namespace";
+ }
+ if ( libraryOrdinal > (int)fDylibs.size() )
+ throw "libraryOrdinal out of range";
+ return fDylibs[libraryOrdinal-1];
+}
+
+template <typename A>
+void DyldInfoPrinter<A>::printRebaseInfo()
+{
+ if ( (fInfo == NULL) || (fInfo->rebase_off() == 0) ) {
+ printf("no compressed rebase info\n");
+ }
+ else {
+ printf("rebase information (from compressed dyld info):\n");
+ printf("segment section address type\n");
+
+ const uint8_t* p = (uint8_t*)fHeader + fInfo->rebase_off();
+ const uint8_t* end = &p[fInfo->rebase_size()];
+
+ uint8_t type = 0;
+ uint64_t segOffset = 0;
+ uint32_t count;
+ uint32_t skip;
+ int segIndex;
+ pint_t segStartAddr = 0;
+ const char* segName = "??";
+ const char* typeName = "??";
+ bool done = false;
+ while ( !done && (p < end) ) {
+ uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
+ uint8_t opcode = *p & REBASE_OPCODE_MASK;
+ ++p;
+ switch (opcode) {
+ case REBASE_OPCODE_DONE:
+ done = true;
+ break;
+ case REBASE_OPCODE_SET_TYPE_IMM:
+ type = immediate;
+ typeName = rebaseTypeName(type);
+ break;
+ case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ segIndex = immediate;
+ segStartAddr = segStartAddress(segIndex);
+ segName = segmentName(segIndex);
+ segOffset = read_uleb128(p, end);
+ break;
+ case REBASE_OPCODE_ADD_ADDR_ULEB:
+ segOffset += read_uleb128(p, end);
+ break;
+ case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+ segOffset += immediate*sizeof(pint_t);
+ break;
+ case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+ for (int i=0; i < immediate; ++i) {
+ printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+ segOffset += sizeof(pint_t);
+ }
+ break;
+ case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+ count = read_uleb128(p, end);
+ for (uint32_t i=0; i < count; ++i) {
+ printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+ segOffset += sizeof(pint_t);
+ }
+ break;
+ case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+ printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+ segOffset += read_uleb128(p, end) + sizeof(pint_t);
+ break;
+ case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
+ count = read_uleb128(p, end);
+ skip = read_uleb128(p, end);
+ for (uint32_t i=0; i < count; ++i) {
+ printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+ segOffset += skip + sizeof(pint_t);
+ }
+ break;
+ default:
+ throwf("bad rebase opcode %d", *p);
+ }
+ }
+ }
+
+}
+
+
+
+template <typename A>
+void DyldInfoPrinter<A>::printRebaseInfoOpcodes()
+{
+ if ( (fInfo == NULL) || (fInfo->rebase_off() == 0) ) {
+ printf("no compressed rebase info\n");
+ }
+ else {
+ printf("rebase opcodes:\n");
+ const uint8_t* p = (uint8_t*)fHeader + fInfo->rebase_off();
+ const uint8_t* end = &p[fInfo->rebase_size()];
+
+ uint8_t type = 0;
+ uint64_t address = fBaseAddress;
+ uint32_t count;
+ uint32_t skip;
+ unsigned int segmentIndex;
+ bool done = false;
+ while ( !done && (p < end) ) {
+ uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
+ uint8_t opcode = *p & REBASE_OPCODE_MASK;
+ ++p;
+ switch (opcode) {
+ case REBASE_OPCODE_DONE:
+ done = true;
+ printf("REBASE_OPCODE_DONE()\n");
+ break;
+ case REBASE_OPCODE_SET_TYPE_IMM:
+ type = immediate;
+ printf("REBASE_OPCODE_SET_TYPE_IMM(%d)\n", type);
+ break;
+ case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ segmentIndex = immediate;
+ address = read_uleb128(p, end);
+ printf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", segmentIndex, address);
+ break;
+ case REBASE_OPCODE_ADD_ADDR_ULEB:
+ address = read_uleb128(p, end);
+ printf("REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", address);
+ break;
+ case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+ address = immediate*sizeof(pint_t);
+ printf("REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", address);
+ break;
+ case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+ printf("REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", immediate);
+ break;
+ case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+ count = read_uleb128(p, end);
+ printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", count);
+ break;
+ case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+ skip = read_uleb128(p, end) + sizeof(pint_t);
+ printf("REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", skip);
+ break;
+ case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
+ count = read_uleb128(p, end);
+ skip = read_uleb128(p, end);
+ printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", count, skip);
+ break;
+ default:
+ throwf("bad rebase opcode %d", *p);
+ }
+ }
+ }
+
+}
+
+
+
+
+
+
+template <typename A>
+void DyldInfoPrinter<A>::printBindingInfoOpcodes(bool weakbinding)
+{
+ if ( fInfo == NULL ) {
+ printf("no compressed binding info\n");
+ }
+ else if ( !weakbinding && (fInfo->bind_off() == 0) ) {
+ printf("no compressed binding info\n");
+ }
+ else if ( weakbinding && (fInfo->weak_bind_off() == 0) ) {
+ printf("no compressed weak binding info\n");
+ }
+ else {
+ const uint8_t* start;
+ const uint8_t* end;
+ if ( weakbinding ) {
+ printf("weak binding opcodes:\n");
+ start = (uint8_t*)fHeader + fInfo->weak_bind_off();
+ end = &start[fInfo->weak_bind_size()];
+ }
+ else {
+ printf("binding opcodes:\n");
+ start = (uint8_t*)fHeader + fInfo->bind_off();
+ end = &start[fInfo->bind_size()];
+ }
+ const uint8_t* p = start;
+ uint8_t type = 0;
+ uint8_t flags;
+ uint64_t address = fBaseAddress;
+ const char* symbolName = NULL;
+ int libraryOrdinal = 0;
+ int64_t addend = 0;
+ uint32_t segmentIndex = 0;
+ uint32_t count;
+ uint32_t skip;
+ bool done = false;
+ while ( !done && (p < end) ) {
+ uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+ uint8_t opcode = *p & BIND_OPCODE_MASK;
+ uint32_t opcodeOffset = p-start;
+ ++p;
+ switch (opcode) {
+ case BIND_OPCODE_DONE:
+ done = true;
+ printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset);
+ break;
+ case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+ libraryOrdinal = immediate;
+ printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
+ break;
+ case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+ libraryOrdinal = read_uleb128(p, end);
+ printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset, libraryOrdinal);
+ break;
+ case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+ // the special ordinals are negative numbers
+ if ( immediate == 0 )
+ libraryOrdinal = 0;
+ else {
+ int8_t signExtended = BIND_OPCODE_MASK | immediate;
+ libraryOrdinal = signExtended;
+ }
+ printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
+ break;
+ case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+ flags = immediate;
+ symbolName = (char*)p;
+ while (*p != '\0')
+ ++p;
+ ++p;
+ printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset, flags, symbolName);
+ break;
+ case BIND_OPCODE_SET_TYPE_IMM:
+ type = immediate;
+ printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
+ break;
+ case BIND_OPCODE_SET_ADDEND_SLEB:
+ addend = read_sleb128(p, end);
+ printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset, addend);
+ break;
+ case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ segmentIndex = immediate;
+ address = read_uleb128(p, end);
+ printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
+ break;
+ case BIND_OPCODE_ADD_ADDR_ULEB:
+ skip = read_uleb128(p, end);
+ printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
+ break;
+ case BIND_OPCODE_DO_BIND:
+ printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset);
+ break;
+ case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+ skip = read_uleb128(p, end);
+ printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
+ break;
+ case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+ skip = immediate*sizeof(pint_t) + sizeof(pint_t);
+ printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset, skip);
+ break;
+ case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+ count = read_uleb128(p, end);
+ skip = read_uleb128(p, end);
+ printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
+ break;
+ default:
+ throwf("unknown bind opcode %d", *p);
+ }
+ }
+ }
+
+}
+
+
+
+template <typename A>
+void DyldInfoPrinter<A>::printBindingInfo()
+{
+ if ( (fInfo == NULL) || (fInfo->bind_off() == 0) ) {
+ printf("no compressed binding info\n");
+ }
+ else {
+ printf("bind information:\n");
+ printf("segment section address type addend dylib symbol\n");
+ const uint8_t* p = (uint8_t*)fHeader + fInfo->bind_off();
+ const uint8_t* end = &p[fInfo->bind_size()];
+
+ uint8_t type = 0;
+ uint8_t segIndex = 0;
+ uint64_t segOffset = 0;
+ const char* symbolName = NULL;
+ const char* fromDylib = "??";
+ int libraryOrdinal = 0;
+ int64_t addend = 0;
+ uint32_t count;
+ uint32_t skip;
+ pint_t segStartAddr = 0;
+ const char* segName = "??";
+ const char* typeName = "??";
+ const char* weak_import = "";
+ bool done = false;
+ while ( !done && (p < end) ) {
+ uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+ uint8_t opcode = *p & BIND_OPCODE_MASK;
+ ++p;
+ switch (opcode) {
+ case BIND_OPCODE_DONE:
+ done = true;
+ break;
+ case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+ libraryOrdinal = immediate;
+ fromDylib = ordinalName(libraryOrdinal);
+ break;
+ case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+ libraryOrdinal = read_uleb128(p, end);
+ fromDylib = ordinalName(libraryOrdinal);
+ break;
+ case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+ // the special ordinals are negative numbers
+ if ( immediate == 0 )
+ libraryOrdinal = 0;
+ else {
+ int8_t signExtended = BIND_OPCODE_MASK | immediate;
+ libraryOrdinal = signExtended;
+ }
+ fromDylib = ordinalName(libraryOrdinal);
+ break;
+ case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+ symbolName = (char*)p;
+ while (*p != '\0')
+ ++p;
+ ++p;
+ if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
+ weak_import = " (weak import)";
+ else
+ weak_import = "";
+ break;
+ case BIND_OPCODE_SET_TYPE_IMM:
+ type = immediate;
+ typeName = bindTypeName(type);
+ break;
+ case BIND_OPCODE_SET_ADDEND_SLEB:
+ addend = read_sleb128(p, end);
+ break;
+ case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ segIndex = immediate;
+ segStartAddr = segStartAddress(segIndex);
+ segName = segmentName(segIndex);
+ segOffset = read_uleb128(p, end);
+ break;
+ case BIND_OPCODE_ADD_ADDR_ULEB:
+ segOffset += read_uleb128(p, end);
+ break;
+ case BIND_OPCODE_DO_BIND:
+ printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
+ segOffset += sizeof(pint_t);
+ break;
+ case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+ printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
+ segOffset += read_uleb128(p, end) + sizeof(pint_t);
+ break;
+ case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+ printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
+ segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
+ break;
+ case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+ count = read_uleb128(p, end);
+ skip = read_uleb128(p, end);
+ for (uint32_t i=0; i < count; ++i) {
+ printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
+ segOffset += skip + sizeof(pint_t);
+ }
+ break;
+ default:
+ throwf("bad bind opcode %d", *p);
+ }
+ }
+ }
+
+}
+
+template <typename A>
+void DyldInfoPrinter<A>::printWeakBindingInfo()
+{
+ if ( (fInfo == NULL) || (fInfo->weak_bind_off() == 0) ) {
+ printf("no weak binding\n");
+ }
+ else {
+ printf("weak binding information:\n");
+ printf("segment section address type addend symbol\n");
+ const uint8_t* p = (uint8_t*)fHeader + fInfo->weak_bind_off();
+ const uint8_t* end = &p[fInfo->weak_bind_size()];
+
+ uint8_t type = 0;
+ uint8_t segIndex = 0;
+ uint64_t segOffset = 0;
+ const char* symbolName = NULL;
+ int64_t addend = 0;
+ uint32_t count;
+ uint32_t skip;
+ pint_t segStartAddr = 0;
+ const char* segName = "??";
+ const char* typeName = "??";
+ bool done = false;
+ while ( !done && (p < end) ) {
+ uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+ uint8_t opcode = *p & BIND_OPCODE_MASK;
+ ++p;
+ switch (opcode) {
+ case BIND_OPCODE_DONE:
+ done = true;
+ break;
+ case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+ symbolName = (char*)p;
+ while (*p != '\0')
+ ++p;
+ ++p;
+ if ( (immediate & BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) != 0 )
+ printf(" strong %s\n", symbolName );
+ break;
+ case BIND_OPCODE_SET_TYPE_IMM:
+ type = immediate;
+ typeName = bindTypeName(type);
+ break;
+ case BIND_OPCODE_SET_ADDEND_SLEB:
+ addend = read_sleb128(p, end);
+ break;
+ case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ segIndex = immediate;
+ segStartAddr = segStartAddress(segIndex);
+ segName = segmentName(segIndex);
+ segOffset = read_uleb128(p, end);
+ break;
+ case BIND_OPCODE_ADD_ADDR_ULEB:
+ segOffset += read_uleb128(p, end);
+ break;
+ case BIND_OPCODE_DO_BIND:
+ printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
+ segOffset += sizeof(pint_t);
+ break;
+ case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+ printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
+ segOffset += read_uleb128(p, end) + sizeof(pint_t);
+ break;
+ case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+ printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
+ segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
+ break;
+ case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+ count = read_uleb128(p, end);
+ skip = read_uleb128(p, end);
+ for (uint32_t i=0; i < count; ++i) {
+ printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
+ segOffset += skip + sizeof(pint_t);
+ }
+ break;
+ default:
+ throwf("unknown weak bind opcode %d", *p);
+ }
+ }
+ }
+
+}
+
+
+template <typename A>
+void DyldInfoPrinter<A>::printLazyBindingInfo()
+{
+ if ( fInfo == NULL ) {
+ printf("no compressed dyld info\n");
+ }
+ else if ( fInfo->lazy_bind_off() == 0 ) {
+ printf("no compressed lazy binding info\n");
+ }
+ else {
+ printf("lazy binding information (from lazy_bind part of dyld info):\n");
+ printf("segment section address index dylib symbol\n");
+ const uint8_t* const start = (uint8_t*)fHeader + fInfo->lazy_bind_off();
+ const uint8_t* const end = &start[fInfo->lazy_bind_size()];
+
+ uint8_t type = BIND_TYPE_POINTER;
+ uint8_t segIndex = 0;
+ uint64_t segOffset = 0;
+ const char* symbolName = NULL;
+ const char* fromDylib = "??";
+ int libraryOrdinal = 0;
+ int64_t addend = 0;
+ uint32_t lazy_offset = 0;
+ pint_t segStartAddr = 0;
+ const char* segName = "??";
+ const char* typeName = "??";
+ const char* weak_import = "";
+ for (const uint8_t* p=start; p < end; ) {
+ uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+ uint8_t opcode = *p & BIND_OPCODE_MASK;
+ ++p;
+ switch (opcode) {
+ case BIND_OPCODE_DONE:
+ lazy_offset = p-start;
+ break;
+ case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+ libraryOrdinal = immediate;
+ fromDylib = ordinalName(libraryOrdinal);
+ break;
+ case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+ libraryOrdinal = read_uleb128(p, end);
+ fromDylib = ordinalName(libraryOrdinal);
+ break;
+ case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+ // the special ordinals are negative numbers
+ if ( immediate == 0 )
+ libraryOrdinal = 0;
+ else {
+ int8_t signExtended = BIND_OPCODE_MASK | immediate;
+ libraryOrdinal = signExtended;
+ }
+ fromDylib = ordinalName(libraryOrdinal);
+ break;
+ case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+ symbolName = (char*)p;
+ while (*p != '\0')
+ ++p;
+ ++p;
+ if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
+ weak_import = " (weak import)";
+ else
+ weak_import = "";
+ break;
+ case BIND_OPCODE_SET_TYPE_IMM:
+ type = immediate;
+ typeName = bindTypeName(type);
+ break;
+ case BIND_OPCODE_SET_ADDEND_SLEB:
+ addend = read_sleb128(p, end);
+ break;
+ case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ segIndex = immediate;
+ segStartAddr = segStartAddress(segIndex);
+ segName = segmentName(segIndex);
+ segOffset = read_uleb128(p, end);
+ break;
+ case BIND_OPCODE_ADD_ADDR_ULEB:
+ segOffset += read_uleb128(p, end);
+ break;
+ case BIND_OPCODE_DO_BIND:
+ printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, lazy_offset, fromDylib, symbolName, weak_import);
+ segOffset += sizeof(pint_t);
+ break;
+ default:
+ throwf("bad lazy bind opcode %d", *p);
+ }
+ }
+ }
+
+}
+
+template <typename A>
+void DyldInfoPrinter<A>::printLazyBindingOpcodes()
+{
+ if ( fInfo == NULL ) {
+ printf("no compressed dyld info\n");
+ }
+ else if ( fInfo->lazy_bind_off() == 0 ) {
+ printf("no compressed lazy binding info\n");
+ }
+ else {
+ printf("lazy binding opcodes:\n");
+ const uint8_t* const start = (uint8_t*)fHeader + fInfo->lazy_bind_off();
+ const uint8_t* const end = &start[fInfo->lazy_bind_size()];
+ uint8_t type = BIND_TYPE_POINTER;
+ uint8_t flags;
+ uint64_t address = fBaseAddress;
+ const char* symbolName = NULL;
+ int libraryOrdinal = 0;
+ int64_t addend = 0;
+ uint32_t segmentIndex = 0;
+ uint32_t count;
+ uint32_t skip;
+ for (const uint8_t* p = start; p < end; ) {
+ uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+ uint8_t opcode = *p & BIND_OPCODE_MASK;
+ uint32_t opcodeOffset = p-start;
+ ++p;
+ switch (opcode) {
+ case BIND_OPCODE_DONE:
+ printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset);
+ break;
+ case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+ libraryOrdinal = immediate;
+ printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
+ break;
+ case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+ libraryOrdinal = read_uleb128(p, end);
+ printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset, libraryOrdinal);
+ break;
+ case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+ // the special ordinals are negative numbers
+ if ( immediate == 0 )
+ libraryOrdinal = 0;
+ else {
+ int8_t signExtended = BIND_OPCODE_MASK | immediate;
+ libraryOrdinal = signExtended;
+ }
+ printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
+ break;
+ case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+ flags = immediate;
+ symbolName = (char*)p;
+ while (*p != '\0')
+ ++p;
+ ++p;
+ printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset, flags, symbolName);
+ break;
+ case BIND_OPCODE_SET_TYPE_IMM:
+ type = immediate;
+ printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
+ break;
+ case BIND_OPCODE_SET_ADDEND_SLEB:
+ addend = read_sleb128(p, end);
+ printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset, addend);
+ break;
+ case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ segmentIndex = immediate;
+ address = read_uleb128(p, end);
+ printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
+ break;
+ case BIND_OPCODE_ADD_ADDR_ULEB:
+ skip = read_uleb128(p, end);
+ printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
+ break;
+ case BIND_OPCODE_DO_BIND:
+ printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset);
+ break;
+ case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+ skip = read_uleb128(p, end);
+ printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
+ break;
+ case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+ skip = immediate*sizeof(pint_t) + sizeof(pint_t);
+ printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset, skip);
+ break;
+ case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+ count = read_uleb128(p, end);
+ skip = read_uleb128(p, end);
+ printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
+ break;
+ default:
+ throwf("unknown bind opcode %d", *p);
+ }
+ }
+ }
+
+}
+
+struct SortExportsByAddress
+{
+ bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
+ {
+ return ( left.address < right.address );
+ }
+};
+
+template <typename A>
+void DyldInfoPrinter<A>::printExportInfo()
+{
+ if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
+ printf("no compressed export info\n");
+ }
+ else {
+ printf("export information (from trie):\n");
+ const uint8_t* start = (uint8_t*)fHeader + fInfo->export_off();
+ const uint8_t* end = &start[fInfo->export_size()];
+ std::vector<mach_o::trie::Entry> list;
+ parseTrie(start, end, list);
+ //std::sort(list.begin(), list.end(), SortExportsByAddress());
+ for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it) {
+ if ( it->flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+ if ( it->importName[0] == '\0' )
+ fprintf(stdout, "[re-export] %s from dylib=%llu\n", it->name, it->other);
+ else
+ fprintf(stdout, "[re-export] %s from dylib=%llu named=%s\n", it->name, it->other, it->importName);
+ }
+ else {
+ const char* flags = "";
+ if ( it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION )
+ flags = "[weak_def] ";
+ else if ( (it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL )
+ flags = "[per-thread] ";
+ if ( it->flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
+ flags = "[resolver] ";
+ fprintf(stdout, "0x%08llX %s%s (resolver=0x%08llX)\n", fBaseAddress+it->address, flags, it->name, it->other);
+ }
+ else {
+ fprintf(stdout, "0x%08llX %s%s\n", fBaseAddress+it->address, flags, it->name);
+ }
+ }
+ }
+ }
+}
+
+
+template <typename A>
+void DyldInfoPrinter<A>::processExportGraphNode(const uint8_t* const start, const uint8_t* const end,
+ const uint8_t* parent, const uint8_t* p,
+ char* cummulativeString, int curStrOffset)
+{
+ const uint8_t* const me = p;
+ const uint8_t terminalSize = read_uleb128(p, end);
+ const uint8_t* children = p + terminalSize;
+ if ( terminalSize != 0 ) {
+ uint32_t flags = read_uleb128(p, end);
+ if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+ uint64_t ordinal = read_uleb128(p, end);
+ const char* importName = (const char*)p;
+ while (*p != '\0')
+ ++p;
+ ++p;
+ if ( *importName == '\0' )
+ printf("\tnode%03ld [ label=%s,re-export from dylib=%llu ];\n", (long)(me-start), cummulativeString, ordinal);
+ else
+ printf("\tnode%03ld [ label=%s,re-export %s from dylib=%llu ];\n", (long)(me-start), cummulativeString, importName, ordinal);
+ }
+ else {
+ uint64_t address = read_uleb128(p, end);
+ printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me-start), cummulativeString, address);
+ if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
+ read_uleb128(p, end);
+ }
+ }
+ else {
+ printf("\tnode%03ld;\n", (long)(me-start));
+ }
+ const uint8_t childrenCount = *children++;
+ const uint8_t* s = children;
+ for (uint8_t i=0; i < childrenCount; ++i) {
+ const char* edgeName = (char*)s;
+ int edgeStrLen = 0;
+ while (*s != '\0') {
+ cummulativeString[curStrOffset+edgeStrLen] = *s++;
+ ++edgeStrLen;
+ }
+ cummulativeString[curStrOffset+edgeStrLen] = *s++;
+ uint32_t childNodeOffet = read_uleb128(s, end);
+ printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me-start), childNodeOffet, edgeName);
+ processExportGraphNode(start, end, start, start+childNodeOffet, cummulativeString, curStrOffset+edgeStrLen);
+ }
+}
+
+template <typename A>
+void DyldInfoPrinter<A>::printExportInfoGraph()
+{
+ if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
+ printf("no compressed export info\n");
+ }
+ else {
+ const uint8_t* p = (uint8_t*)fHeader + fInfo->export_off();
+ const uint8_t* end = &p[fInfo->export_size()];
+ char cummulativeString[2000];
+ printf("digraph {\n");
+ processExportGraphNode(p, end, p, p, cummulativeString, 0);
+ printf("}\n");
+ }
+}
+
+template <typename A>
+void DyldInfoPrinter<A>::gatherNodeStarts(const uint8_t* const start, const uint8_t* const end,
+ const uint8_t* parent, const uint8_t* p,
+ std::vector<uint32_t>& nodeStarts)
+{
+ nodeStarts.push_back(p-start);
+ const uint8_t terminalSize = read_uleb128(p, end);
+ const uint8_t* children = p + terminalSize;
+
+ const uint8_t childrenCount = *children++;
+ const uint8_t* s = children;
+ for (uint8_t i=0; i < childrenCount; ++i) {
+ // skip over edge string
+ while (*s != '\0')
+ ++s;
+ ++s;
+ uint32_t childNodeOffet = read_uleb128(s, end);
+ gatherNodeStarts(start, end, start, start+childNodeOffet, nodeStarts);
+ }
+}
+
+
+template <typename A>
+void DyldInfoPrinter<A>::printExportInfoNodes()
+{
+ if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
+ printf("no compressed export info\n");
+ }
+ else {
+ const uint8_t* start = (uint8_t*)fHeader + fInfo->export_off();
+ const uint8_t* end = &start[fInfo->export_size()];
+ std::vector<uint32_t> nodeStarts;
+ gatherNodeStarts(start, end, start, start, nodeStarts);
+ std::sort(nodeStarts.begin(), nodeStarts.end());
+ for (std::vector<uint32_t>::const_iterator it=nodeStarts.begin(); it != nodeStarts.end(); ++it) {
+ printf("0x%04X: ", *it);
+ const uint8_t* p = start + *it;
+ uint64_t exportInfoSize = read_uleb128(p, end);
+ if ( exportInfoSize != 0 ) {
+ // print terminal info
+ uint64_t flags = read_uleb128(p, end);
+ if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+ uint64_t ordinal = read_uleb128(p, end);
+ const char* importName = (const char*)p;
+ while (*p != '\0')
+ ++p;
+ ++p;
+ if ( strlen(importName) == 0 )
+ printf("[flags=REEXPORT ordinal=%llu] ", ordinal);
+ else
+ printf("[flags=REEXPORT ordinal=%llu import=%s] ", ordinal, importName);
+ }
+ else if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
+ uint64_t stub = read_uleb128(p, end);
+ uint64_t resolver = read_uleb128(p, end);
+ printf("[flags=STUB_AND_RESOLVER stub=0x%06llX resolver=0x%06llX] ", stub, resolver);
+ }
+ else {
+ uint64_t address = read_uleb128(p, end);
+ if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR )
+ printf("[addr=0x%06llX] ", address);
+ else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL)
+ printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address);
+ else
+ printf("[flags=0x%llX addr=0x%06llX] ", flags, address);
+ }
+ }
+ // print child edges
+ const uint8_t childrenCount = *p++;
+ for (uint8_t i=0; i < childrenCount; ++i) {
+ const char* edgeName = (const char*)p;
+ while (*p != '\0')
+ ++p;
+ ++p;
+ uint32_t childNodeOffet = read_uleb128(p, end);
+ printf("%s->0x%04X", edgeName, childNodeOffet);
+ if ( i < (childrenCount-1) )
+ printf(", ");
+ }
+ printf("\n");
+ }
+ }
+}
+
+
+
+template <typename A>
+const uint8_t* DyldInfoPrinter<A>::printSharedRegionInfoForEachULEB128Address(const uint8_t* p, uint8_t kind)
+{
+ const char* kindStr = "??";
+ switch (kind) {
+ case 1:
+ kindStr = "32-bit pointer";
+ break;
+ case 2:
+ kindStr = "64-bit pointer";
+ break;
+ case 3:
+ kindStr = "ppc hi16";
+ break;
+ case 4:
+ kindStr = "32-bit offset to IMPORT";
+ break;
+ case 5:
+ kindStr = "thumb2 movw";
+ break;
+ case 6:
+ kindStr = "ARM movw";
+ break;
+ case 0x10:
+ kindStr = "thumb2 movt low high 4 bits=0";
+ break;
+ case 0x11:
+ kindStr = "thumb2 movt low high 4 bits=1";
+ break;
+ case 0x12:
+ kindStr = "thumb2 movt low high 4 bits=2";
+ break;
+ case 0x13:
+ kindStr = "thumb2 movt low high 4 bits=3";
+ break;
+ case 0x14:
+ kindStr = "thumb2 movt low high 4 bits=4";
+ break;
+ case 0x15:
+ kindStr = "thumb2 movt low high 4 bits=5";
+ break;
+ case 0x16:
+ kindStr = "thumb2 movt low high 4 bits=6";
+ break;
+ case 0x17:
+ kindStr = "thumb2 movt low high 4 bits=7";
+ break;
+ case 0x18:
+ kindStr = "thumb2 movt low high 4 bits=8";
+ break;
+ case 0x19:
+ kindStr = "thumb2 movt low high 4 bits=9";
+ break;
+ case 0x1A:
+ kindStr = "thumb2 movt low high 4 bits=0xA";
+ break;
+ case 0x1B:
+ kindStr = "thumb2 movt low high 4 bits=0xB";
+ break;
+ case 0x1C:
+ kindStr = "thumb2 movt low high 4 bits=0xC";
+ break;
+ case 0x1D:
+ kindStr = "thumb2 movt low high 4 bits=0xD";
+ break;
+ case 0x1E:
+ kindStr = "thumb2 movt low high 4 bits=0xE";
+ break;
+ case 0x1F:
+ kindStr = "thumb2 movt low high 4 bits=0xF";
+ break;
+ }
+ uint64_t address = 0;
+ uint64_t delta = 0;
+ uint32_t shift = 0;
+ bool more = true;
+ do {
+ uint8_t byte = *p++;
+ delta |= ((byte & 0x7F) << shift);
+ shift += 7;
+ if ( byte < 0x80 ) {
+ if ( delta != 0 ) {
+ address += delta;
+ printf("0x%0llX %s\n", address+fBaseAddress, kindStr);
+ delta = 0;
+ shift = 0;
+ }
+ else {
+ more = false;
+ }
+ }
+ } while (more);
+ return p;
+}
+
+template <typename A>
+void DyldInfoPrinter<A>::printSharedRegionInfo()
+{
+ if ( (fSharedRegionInfo == NULL) || (fSharedRegionInfo->datasize() == 0) ) {
+ printf("no shared region info\n");
+ }
+ else {
+ const uint8_t* infoStart = (uint8_t*)fHeader + fSharedRegionInfo->dataoff();
+ const uint8_t* infoEnd = &infoStart[fSharedRegionInfo->datasize()];
+ for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd);) {
+ uint8_t kind = *p++;
+ p = this->printSharedRegionInfoForEachULEB128Address(p, kind);
+ }
+
+ }
+}
+
+#if SUPPORT_ARCH_arm_any
+template <>
+void DyldInfoPrinter<arm>::printFunctionStartLine(uint64_t addr)
+{
+ if ( addr & 1 )
+ printf("0x%0llX [thumb] %s\n", (addr & -2), symbolNameForAddress(addr & -2));
+ else
+ printf("0x%0llX %s\n", addr, symbolNameForAddress(addr));
+}
+#endif
+
+template <typename A>
+void DyldInfoPrinter<A>::printFunctionStartLine(uint64_t addr)
+{
+ printf("0x%0llX %s\n", addr, symbolNameForAddress(addr));
+}
+
+
+template <typename A>
+void DyldInfoPrinter<A>::printFunctionStartsInfo()
+{
+ if ( (fFunctionStartsInfo == NULL) || (fFunctionStartsInfo->datasize() == 0) ) {
+ printf("no function starts info\n");
+ }
+ else {
+ const uint8_t* infoStart = (uint8_t*)fHeader + fFunctionStartsInfo->dataoff();
+ const uint8_t* infoEnd = &infoStart[fFunctionStartsInfo->datasize()];
+ uint64_t address = fBaseAddress;
+ for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd); ) {
+ uint64_t delta = 0;
+ uint32_t shift = 0;
+ bool more = true;
+ do {
+ uint8_t byte = *p++;
+ delta |= ((byte & 0x7F) << shift);
+ shift += 7;
+ if ( byte < 0x80 ) {
+ address += delta;
+ printFunctionStartLine(address);
+ more = false;
+ }
+ } while (more);
+ }
+ }
+}
+
+template <typename A>
+void DyldInfoPrinter<A>::printDylibsInfo()
+{
+ printf("attributes dependent dylibs\n");
+ for(typename std::vector<const macho_dylib_command<P>*>::iterator it = fDylibLoadCommands.begin(); it != fDylibLoadCommands.end(); ++it) {
+ const macho_dylib_command<P>* dylib = *it;
+ const char* attribute = "";
+ switch ( dylib->cmd() ) {
+ case LC_LOAD_WEAK_DYLIB:
+ attribute = "weak_import";
+ break;
+ case LC_REEXPORT_DYLIB:
+ attribute = "re-export";
+ break;
+ case LC_LOAD_UPWARD_DYLIB:
+ attribute = "upward";
+ break;
+ case LC_LAZY_LOAD_DYLIB:
+ attribute = "lazy_load";
+ break;
+ case LC_LOAD_DYLIB:
+ default:
+ break;
+ }
+ printf(" %-12s %s\n", attribute, dylib->name());
+ }
+}
+
+template <typename A>
+void DyldInfoPrinter<A>::printDRInfo()
+{
+ if ( fDRInfo == NULL ) {
+ printf("no Designated Requirements info\n");
+ }
+ else {
+ printf("dylibs DRs\n");
+ const uint8_t* start = ((uint8_t*)fHeader + fDRInfo->dataoff());
+ //const uint8_t* end = ((uint8_t*)fHeader + fDRInfo->dataoff() + fDRInfo->datasize());
+ typedef Security::SuperBlob<Security::kSecCodeMagicDRList> DRListSuperBlob;
+ typedef Security::SuperBlob<Security::kSecCodeMagicRequirementSet> InternalRequirementsSetBlob;
+ const DRListSuperBlob* topBlob = (DRListSuperBlob*)start;
+ if ( topBlob->validateBlob(fDRInfo->datasize()) ) {
+ if ( topBlob->count() == fDylibLoadCommands.size() ) {
+ for(unsigned i=0; i < topBlob->count(); ++i) {
+ printf(" %-20s ", fDylibs[i]);
+ const Security::BlobCore* item = topBlob->find(i);
+ if ( item != NULL ) {
+ const uint8_t* itemStart = (uint8_t*)item;
+ const uint8_t* itemEnd = itemStart + item->length();
+ for(const uint8_t* p=itemStart; p < itemEnd; ++p)
+ printf("%02X ", *p);
+ }
+ else {
+ printf("no DR info");
+ }
+ printf("\n");
+ }
+ }
+ else {
+ fprintf(stderr, "superblob of DRs has a different number of elements than dylib load commands\n");
+ }
+ }
+ else {
+ fprintf(stderr, "superblob of DRs invalid\n");
+ }
+ }
+}
+
+
+
+
+
+template <typename A>
+void DyldInfoPrinter<A>::printDataInCode()
+{
+ if ( fDataInCode == NULL ) {
+ printf("no data-in-code info\n");
+ }
+ else {
+ printf("offset length data-kind\n");
+ const macho_data_in_code_entry<P>* start = (macho_data_in_code_entry<P>*)((uint8_t*)fHeader + fDataInCode->dataoff());
+ const macho_data_in_code_entry<P>* end = (macho_data_in_code_entry<P>*)((uint8_t*)fHeader + fDataInCode->dataoff() + fDataInCode->datasize());
+ for (const macho_data_in_code_entry<P>* p=start; p < end; ++p) {
+ const char* kindStr = "???";
+ switch ( p->kind() ) {
+ case 1:
+ kindStr = "data";
+ break;
+ case 2:
+ kindStr = "jumptable8";
+ break;
+ case 3:
+ kindStr = "jumptable16";
+ break;
+ case 4:
+ kindStr = "jumptable32";
+ break;
+ case 5:
+ kindStr = "jumptable32absolute";
+ break;
+ }
+ printf("0x%08X 0x%04X %s\n", p->offset(), p->length(), kindStr);
+ }
+ }
+}
+
+
+
+template <>
+ppc::P::uint_t DyldInfoPrinter<ppc>::relocBase()
+{
+ if ( fHeader->flags() & MH_SPLIT_SEGS )
+ return fFirstWritableSegment->vmaddr();
+ else
+ return fFirstSegment->vmaddr();
+}
+
+template <>
+ppc64::P::uint_t DyldInfoPrinter<ppc64>::relocBase()
+{
+ if ( fWriteableSegmentWithAddrOver4G )
+ return fFirstWritableSegment->vmaddr();
+ else
+ return fFirstSegment->vmaddr();
+}
+
+template <>
+x86::P::uint_t DyldInfoPrinter<x86>::relocBase()
+{
+ if ( fHeader->flags() & MH_SPLIT_SEGS )
+ return fFirstWritableSegment->vmaddr();
+ else
+ return fFirstSegment->vmaddr();
+}
+
+template <>
+x86_64::P::uint_t DyldInfoPrinter<x86_64>::relocBase()
+{
+ // check for split-seg
+ return fFirstWritableSegment->vmaddr();
+}
+
+#if SUPPORT_ARCH_arm_any
+template <>
+arm::P::uint_t DyldInfoPrinter<arm>::relocBase()
+{
+ if ( fHeader->flags() & MH_SPLIT_SEGS )
+ return fFirstWritableSegment->vmaddr();
+ else
+ return fFirstSegment->vmaddr();
+}
+#endif
+
+
+template <>
+const char* DyldInfoPrinter<ppc>::relocTypeName(uint8_t r_type)
+{
+ if ( r_type == GENERIC_RELOC_VANILLA )
+ return "pointer";
+ else
+ return "??";
+}
+
+template <>
+const char* DyldInfoPrinter<ppc64>::relocTypeName(uint8_t r_type)
+{
+ if ( r_type == GENERIC_RELOC_VANILLA )
+ return "pointer";
+ else
+ return "??";
+}
+
+template <>
+const char* DyldInfoPrinter<x86>::relocTypeName(uint8_t r_type)
+{
+ if ( r_type == GENERIC_RELOC_VANILLA )
+ return "pointer";
+ else if ( r_type == GENERIC_RELOC_PB_LA_PTR )
+ return "pb pointer";
+ else
+ return "??";
+}
+
+template <>
+const char* DyldInfoPrinter<x86_64>::relocTypeName(uint8_t r_type)
+{
+ if ( r_type == X86_64_RELOC_UNSIGNED )
+ return "pointer";
+ else
+ return "??";
+}
+
+#if SUPPORT_ARCH_arm_any
+template <>
+const char* DyldInfoPrinter<arm>::relocTypeName(uint8_t r_type)
+{
+ if ( r_type == ARM_RELOC_VANILLA )
+ return "pointer";
+ else if ( r_type == ARM_RELOC_PB_LA_PTR )
+ return "pb pointer";
+ else
+ return "??";
+}
+#endif
+
+template <typename A>
+void DyldInfoPrinter<A>::printRelocRebaseInfo()
+{
+ if ( fDynamicSymbolTable == NULL ) {
+ printf("no classic dynamic symbol table");
+ }
+ else {
+ printf("rebase information (from local relocation records and indirect symbol table):\n");
+ printf("segment section address type\n");
+ // walk all local relocations
+ pint_t rbase = relocBase();
+ const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(((uint8_t*)fHeader) + fDynamicSymbolTable->locreloff());
+ const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nlocrel()];
+ for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
+ if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+ pint_t addr = reloc->r_address() + rbase;
+ uint8_t segIndex = segmentIndexForAddress(addr);
+ const char* typeName = relocTypeName(reloc->r_type());
+ const char* segName = segmentName(segIndex);
+ const char* sectName = sectionName(segIndex, addr);
+ printf("%-8s %-16s 0x%08llX %s\n", segName, sectName, (uint64_t)addr, typeName);
+ }
+ else {
+ const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
+ pint_t addr = sreloc->r_address() + rbase;
+ uint8_t segIndex = segmentIndexForAddress(addr);
+ const char* typeName = relocTypeName(sreloc->r_type());
+ const char* segName = segmentName(segIndex);
+ const char* sectName = sectionName(segIndex, addr);
+ printf("%-8s %-16s 0x%08llX %s\n", segName, sectName, (uint64_t)addr, typeName);
+ }
+ }
+ // look for local non-lazy-pointers
+ const uint32_t* indirectSymbolTable = (uint32_t*)(((uint8_t*)fHeader) + fDynamicSymbolTable->indirectsymoff());
+ uint8_t segIndex = 0;
+ for(typename std::vector<const macho_segment_command<P>*>::iterator segit=fSegments.begin(); segit != fSegments.end(); ++segit, ++segIndex) {
+ const macho_segment_command<P>* segCmd = *segit;
+ macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+ macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()];
+ for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+ uint8_t type = sect->flags() & SECTION_TYPE;
+ if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
+ uint32_t indirectOffset = sect->reserved1();
+ uint32_t count = sect->size() / sizeof(pint_t);
+ for (uint32_t i=0; i < count; ++i) {
+ uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
+ if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) {
+ pint_t addr = sect->addr() + i*sizeof(pint_t);
+ const char* typeName = "pointer";
+ const char* segName = segmentName(segIndex);
+ const char* sectName = sectionName(segIndex, addr);
+ printf("%-8s %-16s 0x%08llX %s\n", segName, sectName, (uint64_t)addr, typeName);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+template <typename A>
+void DyldInfoPrinter<A>::printSymbolTableExportInfo()
+{
+ if ( fDynamicSymbolTable == NULL ) {
+ printf("no classic dynamic symbol table");
+ }
+ else {
+ printf("export information (from symbol table):\n");
+ const macho_nlist<P>* lastExport = &fSymbols[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
+ for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->iextdefsym()]; sym < lastExport; ++sym) {
+ const char* flags = "";
+ if ( sym->n_desc() & N_WEAK_DEF )
+ flags = "[weak_def] ";
+ pint_t thumb = 0;
+ if ( sym->n_desc() & N_ARM_THUMB_DEF )
+ thumb = 1;
+ printf("0x%08llX %s%s\n", sym->n_value()+thumb, flags, &fStrings[sym->n_strx()]);
+ }
+ }
+}
+
+template <typename A>
+const char* DyldInfoPrinter<A>::symbolNameForAddress(uint64_t addr)
+{
+ if ( fDynamicSymbolTable != NULL ) {
+ // find exact match in globals
+ const macho_nlist<P>* lastExport = &fSymbols[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
+ for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->iextdefsym()]; sym < lastExport; ++sym) {
+ if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
+ return &fStrings[sym->n_strx()];
+ }
+ }
+ // find exact match in local symbols
+ const macho_nlist<P>* lastLocal = &fSymbols[fDynamicSymbolTable->ilocalsym()+fDynamicSymbolTable->nlocalsym()];
+ for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->ilocalsym()]; sym < lastLocal; ++sym) {
+ if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
+ return &fStrings[sym->n_strx()];
+ }
+ }
+ }
+ else {
+ // find exact match in all symbols
+ const macho_nlist<P>* lastSym = &fSymbols[fSymbolCount];
+ for (const macho_nlist<P>* sym = &fSymbols[0]; sym < lastSym; ++sym) {
+ if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
+ return &fStrings[sym->n_strx()];
+ }
+ }
+ }
+
+ return "?";
+}
+
+template <typename A>
+void DyldInfoPrinter<A>::printClassicBindingInfo()
+{
+ if ( fDynamicSymbolTable == NULL ) {
+ printf("no classic dynamic symbol table");
+ }
+ else {
+ printf("binding information (from relocations and indirect symbol table):\n");
+ printf("segment section address type weak addend dylib symbol\n");
+ // walk all external relocations
+ pint_t rbase = relocBase();
+ const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(((uint8_t*)fHeader) + fDynamicSymbolTable->extreloff());
+ const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nextrel()];
+ for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
+ pint_t addr = reloc->r_address() + rbase;
+ uint32_t symbolIndex = reloc->r_symbolnum();
+ const macho_nlist<P>* sym = &fSymbols[symbolIndex];
+ const char* symbolName = &fStrings[sym->n_strx()];
+ const char* weak_import = (sym->n_desc() & N_WEAK_REF) ? "weak" : "";
+ const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
+ uint8_t segIndex = segmentIndexForAddress(addr);
+ const char* typeName = relocTypeName(reloc->r_type());
+ const char* segName = segmentName(segIndex);
+ const char* sectName = sectionName(segIndex, addr);
+ const pint_t* addressMapped = mappedAddressForVMAddress(addr);
+ int64_t addend = P::getP(*addressMapped);
+ if ( fHeader->flags() & MH_PREBOUND ) {
+ // In prebound binaries the content is already pointing to the target.
+ // To get the addend requires subtracting out the base address it was prebound to.
+ addend -= sym->n_value();
+ }
+ printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectName, (uint64_t)addr,
+ typeName, weak_import, addend, fromDylib, symbolName);
+ }
+ // look for non-lazy pointers
+ const uint32_t* indirectSymbolTable = (uint32_t*)(((uint8_t*)fHeader) + fDynamicSymbolTable->indirectsymoff());
+ for(typename std::vector<const macho_segment_command<P>*>::iterator segit=fSegments.begin(); segit != fSegments.end(); ++segit) {
+ const macho_segment_command<P>* segCmd = *segit;
+ macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+ macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()];
+ for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+ uint8_t type = sect->flags() & SECTION_TYPE;
+ if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
+ uint32_t indirectOffset = sect->reserved1();
+ uint32_t count = sect->size() / sizeof(pint_t);
+ for (uint32_t i=0; i < count; ++i) {
+ uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
+ if ( symbolIndex != INDIRECT_SYMBOL_LOCAL ) {
+ const macho_nlist<P>* sym = &fSymbols[symbolIndex];
+ const char* symbolName = &fStrings[sym->n_strx()];
+ const char* weak_import = (sym->n_desc() & N_WEAK_REF) ? "weak" : "";
+ const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
+ pint_t addr = sect->addr() + i*sizeof(pint_t);
+ uint8_t segIndex = segmentIndexForAddress(addr);
+ const char* typeName = "pointer";
+ const char* segName = segmentName(segIndex);
+ const char* sectName = sectionName(segIndex, addr);
+ int64_t addend = 0;
+ printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectName, (uint64_t)addr,
+ typeName, weak_import, addend, fromDylib, symbolName);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+template <typename A>
+void DyldInfoPrinter<A>::printClassicLazyBindingInfo()
+{
+ if ( fDynamicSymbolTable == NULL ) {
+ printf("no classic dynamic symbol table");
+ }
+ else {
+ printf("lazy binding information (from section records and indirect symbol table):\n");
+ printf("segment section address index dylib symbol\n");
+ const uint32_t* indirectSymbolTable = (uint32_t*)(((uint8_t*)fHeader) + fDynamicSymbolTable->indirectsymoff());
+ for(typename std::vector<const macho_segment_command<P>*>::iterator segit=fSegments.begin(); segit != fSegments.end(); ++segit) {
+ const macho_segment_command<P>* segCmd = *segit;
+ macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+ macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()];
+ for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+ uint8_t type = sect->flags() & SECTION_TYPE;
+ if ( type == S_LAZY_SYMBOL_POINTERS ) {
+ uint32_t indirectOffset = sect->reserved1();
+ uint32_t count = sect->size() / sizeof(pint_t);
+ for (uint32_t i=0; i < count; ++i) {
+ uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
+ const macho_nlist<P>* sym = &fSymbols[symbolIndex];
+ const char* symbolName = &fStrings[sym->n_strx()];
+ const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
+ pint_t addr = sect->addr() + i*sizeof(pint_t);
+ uint8_t segIndex = segmentIndexForAddress(addr);
+ const char* segName = segmentName(segIndex);
+ const char* sectName = sectionName(segIndex, addr);
+ printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName, sectName, (uint64_t)addr, symbolIndex, fromDylib, symbolName);
+ }
+ }
+ else if ( (type == S_SYMBOL_STUBS) && (((sect->flags() & S_ATTR_SELF_MODIFYING_CODE) != 0)) && (sect->reserved2() == 5) ) {
+ // i386 self-modifying stubs
+ uint32_t indirectOffset = sect->reserved1();
+ uint32_t count = sect->size() / 5;
+ for (uint32_t i=0; i < count; ++i) {
+ uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
+ if ( symbolIndex != INDIRECT_SYMBOL_ABS ) {
+ const macho_nlist<P>* sym = &fSymbols[symbolIndex];
+ const char* symbolName = &fStrings[sym->n_strx()];
+ const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
+ pint_t addr = sect->addr() + i*5;
+ uint8_t segIndex = segmentIndexForAddress(addr);
+ const char* segName = segmentName(segIndex);
+ const char* sectName = sectionName(segIndex, addr);
+ printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName, sectName, (uint64_t)addr, symbolIndex, fromDylib, symbolName);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void dump(const char* path)
+{
+ struct stat stat_buf;
+
+ try {
+ int fd = ::open(path, O_RDONLY, 0);
+ if ( fd == -1 )
+ throw "cannot open file";
+ if ( ::fstat(fd, &stat_buf) != 0 )
+ throwf("fstat(%s) failed, errno=%d\n", path, errno);
+ uint32_t length = stat_buf.st_size;
+ uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+ if ( p == ((uint8_t*)(-1)) )
+ throw "cannot map file";
+ ::close(fd);
+ const mach_header* mh = (mach_header*)p;
+ if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+ const struct fat_header* fh = (struct fat_header*)p;
+ const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
+ for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
+ size_t offset = OSSwapBigToHostInt32(archs[i].offset);
+ size_t size = OSSwapBigToHostInt32(archs[i].size);
+ cpu_type_t cputype = OSSwapBigToHostInt32(archs[i].cputype);
+ cpu_type_t cpusubtype = OSSwapBigToHostInt32(archs[i].cpusubtype);
+ if ( ((cputype == sPreferredArch)
+ && ((sPreferredSubArch==0) || (sPreferredSubArch==cpusubtype)))
+ || (sPreferredArch == 0) ) {
+ switch(cputype) {
+ case CPU_TYPE_POWERPC:
+ if ( DyldInfoPrinter<ppc>::validFile(p + offset) )
+ DyldInfoPrinter<ppc>::make(p + offset, size, path, (sPreferredArch == 0));
+ else
+ throw "in universal file, ppc slice does not contain ppc mach-o";
+ break;
+ case CPU_TYPE_I386:
+ if ( DyldInfoPrinter<x86>::validFile(p + offset) )
+ DyldInfoPrinter<x86>::make(p + offset, size, path, (sPreferredArch == 0));
+ else
+ throw "in universal file, i386 slice does not contain i386 mach-o";
+ break;
+ case CPU_TYPE_POWERPC64:
+ if ( DyldInfoPrinter<ppc64>::validFile(p + offset) )
+ DyldInfoPrinter<ppc64>::make(p + offset, size, path, (sPreferredArch == 0));
+ else
+ throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
+ break;
+ case CPU_TYPE_X86_64:
+ if ( DyldInfoPrinter<x86_64>::validFile(p + offset) )
+ DyldInfoPrinter<x86_64>::make(p + offset, size, path, (sPreferredArch == 0));
+ else
+ throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
+ break;
+#if SUPPORT_ARCH_arm_any
+ case CPU_TYPE_ARM:
+ if ( DyldInfoPrinter<arm>::validFile(p + offset) )
+ DyldInfoPrinter<arm>::make(p + offset, size, path, (sPreferredArch == 0));
+ else
+ throw "in universal file, arm slice does not contain arm mach-o";
+ break;
+#endif
+ default:
+ throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
+ }
+ }
+ }
+ }
+ else if ( DyldInfoPrinter<x86>::validFile(p) ) {
+ DyldInfoPrinter<x86>::make(p, length, path, false);
+ }
+ else if ( DyldInfoPrinter<ppc>::validFile(p) ) {
+ DyldInfoPrinter<ppc>::make(p, length, path, false);
+ }
+ else if ( DyldInfoPrinter<ppc64>::validFile(p) ) {
+ DyldInfoPrinter<ppc64>::make(p, length, path, false);
+ }
+ else if ( DyldInfoPrinter<x86_64>::validFile(p) ) {
+ DyldInfoPrinter<x86_64>::make(p, length, path, false);
+ }
+#if SUPPORT_ARCH_arm_any
+ else if ( DyldInfoPrinter<arm>::validFile(p) ) {
+ DyldInfoPrinter<arm>::make(p, length, path, false);
+ }
+#endif
+ else {
+ throw "not a known file type";
+ }
+ }
+ catch (const char* msg) {
+ throwf("%s in %s", msg, path);
+ }
+}
+
+static void usage()
+{
+ fprintf(stderr, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
+ "\t-dylibs print dependent dylibs\n"
+ "\t-dr print dependent dylibs and show any recorded DR info\n"
+ "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
+ "\t-bind print addresses dyld will set based on symbolic lookups\n"
+ "\t-weak_bind print symbols which dyld must coalesce\n"
+ "\t-lazy_bind print addresses dyld will lazily set on first use\n"
+ "\t-export print addresses of all symbols this file exports\n"
+ "\t-opcodes print opcodes used to generate the rebase and binding information\n"
+ "\t-function_starts print table of function start addresses\n"
+ "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
+ "\t-data_in_code print any data-in-code inforamtion\n"
+ );
+}
+
+
+int main(int argc, const char* argv[])
+{
+ if ( argc == 1 ) {
+ usage();
+ return 0;
+ }
+
+ try {
+ std::vector<const char*> files;
+ for(int i=1; i < argc; ++i) {
+ const char* arg = argv[i];
+ if ( arg[0] == '-' ) {
+ if ( strcmp(arg, "-arch") == 0 ) {
+ const char* arch = ++i<argc? argv[i]: "";
+ if ( strcmp(arch, "ppc64") == 0 )
+ sPreferredArch = CPU_TYPE_POWERPC64;
+ else if ( strcmp(arch, "ppc") == 0 )
+ sPreferredArch = CPU_TYPE_POWERPC;
+ else if ( strcmp(arch, "i386") == 0 )
+ sPreferredArch = CPU_TYPE_I386;
+ else if ( strcmp(arch, "x86_64") == 0 )
+ sPreferredArch = CPU_TYPE_X86_64;
+ else {
+ const char* archName = argv[++i];
+ if ( archName == NULL )
+ throw "-arch missing architecture name";
+ bool found = false;
+ for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+ if ( strcmp(t->archName,archName) == 0 ) {
+ sPreferredArch = t->cpuType;
+ if ( t->isSubType )
+ sPreferredSubArch = t->cpuSubType;
+ }
+ }
+ if ( !found )
+ throwf("unknown architecture %s", archName);
+ }
+ }
+ else if ( strcmp(arg, "-rebase") == 0 ) {
+ printRebase = true;
+ }
+ else if ( strcmp(arg, "-bind") == 0 ) {
+ printBind = true;
+ }
+ else if ( strcmp(arg, "-weak_bind") == 0 ) {
+ printWeakBind = true;
+ }
+ else if ( strcmp(arg, "-lazy_bind") == 0 ) {
+ printLazyBind = true;
+ }
+ else if ( strcmp(arg, "-export") == 0 ) {
+ printExport = true;
+ }
+ else if ( strcmp(arg, "-opcodes") == 0 ) {
+ printOpcodes = true;
+ }
+ else if ( strcmp(arg, "-export_dot") == 0 ) {
+ printExportGraph = true;
+ }
+ else if ( strcmp(arg, "-export_trie_nodes") == 0 ) {
+ printExportNodes = true;
+ }
+ else if ( strcmp(arg, "-shared_region") == 0 ) {
+ printSharedRegion = true;
+ }
+ else if ( strcmp(arg, "-function_starts") == 0 ) {
+ printFunctionStarts = true;
+ }
+ else if ( strcmp(arg, "-dylibs") == 0 ) {
+ printDylibs = true;
+ }
+ else if ( strcmp(arg, "-dr") == 0 ) {
+ printDRs = true;
+ }
+ else if ( strcmp(arg, "-data_in_code") == 0 ) {
+ printDataCode = true;
+ }
+ else {
+ throwf("unknown option: %s\n", arg);
+ }
+ }
+ else {
+ files.push_back(arg);
+ }
+ }
+ if ( files.size() == 0 )
+ usage();
+ if ( files.size() == 1 ) {
+ dump(files[0]);
+ }
+ else {
+ for(std::vector<const char*>::iterator it=files.begin(); it != files.end(); ++it) {
+ printf("\n%s:\n", *it);
+ dump(*it);
+ }
+ }
+ }
+ catch (const char* msg) {
+ fprintf(stderr, "dyldinfo failed: %s\n", msg);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <vector>
+#include <set>
+#include <ext/hash_set>
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+
+
+ __attribute__((noreturn))
+void throwf(const char* format, ...)
+{
+ va_list list;
+ char* p;
+ va_start(list, format);
+ vasprintf(&p, format, list);
+ va_end(list);
+
+ const char* t = p;
+ throw t;
+}
+
+static uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end)
+{
+ uint64_t result = 0;
+ int bit = 0;
+ do {
+ if (p == end)
+ throwf("malformed uleb128");
+
+ uint64_t slice = *p & 0x7f;
+
+ if (bit >= 64 || slice << bit >> bit != slice)
+ throwf("uleb128 too big");
+ else {
+ result |= (slice << bit);
+ bit += 7;
+ }
+ }
+ while (*p++ & 0x80);
+ return result;
+}
+
+
+static int64_t read_sleb128(const uint8_t*& p, const uint8_t* end)
+{
+ int64_t result = 0;
+ int bit = 0;
+ uint8_t byte;
+ do {
+ if (p == end)
+ throwf("malformed sleb128");
+ byte = *p++;
+ result |= ((byte & 0x7f) << bit);
+ bit += 7;
+ } while (byte & 0x80);
+ // sign extend negative numbers
+ if ( (byte & 0x40) != 0 )
+ result |= (-1LL) << bit;
+ return result;
+}
+
+
+template <typename A>
+class MachOChecker
+{
+public:
+ static bool validFile(const uint8_t* fileContent);
+ static MachOChecker<A>* make(const uint8_t* fileContent, uint32_t fileLength, const char* path)
+ { return new MachOChecker<A>(fileContent, fileLength, path); }
+ virtual ~MachOChecker() {}
+
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ class CStringEquals
+ {
+ public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+ };
+
+ typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> StringSet;
+
+ MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path);
+ void checkMachHeader();
+ void checkLoadCommands();
+ void checkSection(const macho_segment_command<P>* segCmd, const macho_section<P>* sect);
+ uint8_t loadCommandSizeMask();
+ void checkSymbolTable();
+ void checkInitTerms();
+ void checkIndirectSymbolTable();
+ void checkRelocations();
+ void checkExternalReloation(const macho_relocation_info<P>* reloc);
+ void checkLocalReloation(const macho_relocation_info<P>* reloc);
+ pint_t relocBase();
+ bool addressInWritableSegment(pint_t address);
+ bool hasTextRelocInRange(pint_t start, pint_t end);
+ pint_t segStartAddress(uint8_t segIndex);
+ bool addressIsRebaseSite(pint_t addr);
+ bool addressIsBindingSite(pint_t addr);
+ pint_t getInitialStackPointer(const macho_thread_command<P>*);
+ pint_t getEntryPoint(const macho_thread_command<P>*);
+
+
+
+ const char* fPath;
+ const macho_header<P>* fHeader;
+ uint32_t fLength;
+ const char* fStrings;
+ const char* fStringsEnd;
+ const macho_nlist<P>* fSymbols;
+ uint32_t fSymbolCount;
+ const macho_dysymtab_command<P>* fDynamicSymbolTable;
+ const uint32_t* fIndirectTable;
+ uint32_t fIndirectTableCount;
+ const macho_relocation_info<P>* fLocalRelocations;
+ uint32_t fLocalRelocationsCount;
+ const macho_relocation_info<P>* fExternalRelocations;
+ uint32_t fExternalRelocationsCount;
+ bool fWriteableSegmentWithAddrOver4G;
+ bool fSlidableImage;
+ const macho_segment_command<P>* fFirstSegment;
+ const macho_segment_command<P>* fFirstWritableSegment;
+ const macho_segment_command<P>* fTEXTSegment;
+ const macho_dyld_info_command<P>* fDyldInfo;
+ uint32_t fSectionCount;
+ std::vector<const macho_segment_command<P>*>fSegments;
+};
+
+
+
+template <>
+bool MachOChecker<ppc>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_POWERPC )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ return true;
+ }
+ return false;
+}
+
+template <>
+bool MachOChecker<ppc64>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_POWERPC64 )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ return true;
+ }
+ return false;
+}
+
+template <>
+bool MachOChecker<x86>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_I386 )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ return true;
+ }
+ return false;
+}
+
+template <>
+bool MachOChecker<x86_64>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_X86_64 )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ return true;
+ }
+ return false;
+}
+
+template <>
+bool MachOChecker<arm>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_ARM )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ return true;
+ }
+ return false;
+}
+
+template <> uint8_t MachOChecker<ppc>::loadCommandSizeMask() { return 0x03; }
+template <> uint8_t MachOChecker<ppc64>::loadCommandSizeMask() { return 0x07; }
+template <> uint8_t MachOChecker<x86>::loadCommandSizeMask() { return 0x03; }
+template <> uint8_t MachOChecker<x86_64>::loadCommandSizeMask() { return 0x07; }
+template <> uint8_t MachOChecker<arm>::loadCommandSizeMask() { return 0x03; }
+
+
+template <>
+ppc::P::uint_t MachOChecker<ppc>::getInitialStackPointer(const macho_thread_command<ppc::P>* threadInfo)
+{
+ return threadInfo->thread_register(3);
+}
+
+template <>
+ppc64::P::uint_t MachOChecker<ppc64>::getInitialStackPointer(const macho_thread_command<ppc64::P>* threadInfo)
+{
+ return threadInfo->thread_register(3);
+}
+
+template <>
+x86::P::uint_t MachOChecker<x86>::getInitialStackPointer(const macho_thread_command<x86::P>* threadInfo)
+{
+ return threadInfo->thread_register(7);
+}
+
+template <>
+x86_64::P::uint_t MachOChecker<x86_64>::getInitialStackPointer(const macho_thread_command<x86_64::P>* threadInfo)
+{
+ return threadInfo->thread_register(7);
+}
+
+template <>
+arm::P::uint_t MachOChecker<arm>::getInitialStackPointer(const macho_thread_command<arm::P>* threadInfo)
+{
+ return threadInfo->thread_register(13);
+}
+
+
+
+
+
+template <>
+ppc::P::uint_t MachOChecker<ppc>::getEntryPoint(const macho_thread_command<ppc::P>* threadInfo)
+{
+ return threadInfo->thread_register(0);
+}
+
+template <>
+ppc64::P::uint_t MachOChecker<ppc64>::getEntryPoint(const macho_thread_command<ppc64::P>* threadInfo)
+{
+ return threadInfo->thread_register(0);
+}
+
+template <>
+x86::P::uint_t MachOChecker<x86>::getEntryPoint(const macho_thread_command<x86::P>* threadInfo)
+{
+ return threadInfo->thread_register(10);
+}
+
+template <>
+x86_64::P::uint_t MachOChecker<x86_64>::getEntryPoint(const macho_thread_command<x86_64::P>* threadInfo)
+{
+ return threadInfo->thread_register(16);
+}
+
+template <>
+arm::P::uint_t MachOChecker<arm>::getEntryPoint(const macho_thread_command<arm::P>* threadInfo)
+{
+ return threadInfo->thread_register(15);
+}
+
+
+template <typename A>
+MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path)
+ : fHeader(NULL), fLength(fileLength), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fDynamicSymbolTable(NULL), fIndirectTableCount(0),
+ fLocalRelocations(NULL), fLocalRelocationsCount(0), fExternalRelocations(NULL), fExternalRelocationsCount(0),
+ fWriteableSegmentWithAddrOver4G(false), fSlidableImage(false), fFirstSegment(NULL), fFirstWritableSegment(NULL),
+ fTEXTSegment(NULL), fDyldInfo(NULL), fSectionCount(0)
+{
+ // sanity check
+ if ( ! validFile(fileContent) )
+ throw "not a mach-o file that can be checked";
+
+ fPath = strdup(path);
+ fHeader = (const macho_header<P>*)fileContent;
+
+ // sanity check header
+ checkMachHeader();
+
+ // check load commands
+ checkLoadCommands();
+
+ checkIndirectSymbolTable();
+
+ checkRelocations();
+
+ checkSymbolTable();
+
+ checkInitTerms();
+}
+
+
+template <typename A>
+void MachOChecker<A>::checkMachHeader()
+{
+ if ( (fHeader->sizeofcmds() + sizeof(macho_header<P>)) > fLength )
+ throw "sizeofcmds in mach_header is larger than file";
+
+ uint32_t flags = fHeader->flags();
+ const uint32_t invalidBits = MH_INCRLINK | MH_LAZY_INIT | 0xFE000000;
+ if ( flags & invalidBits )
+ throw "invalid bits in mach_header flags";
+ if ( (flags & MH_NO_REEXPORTED_DYLIBS) && (fHeader->filetype() != MH_DYLIB) )
+ throw "MH_NO_REEXPORTED_DYLIBS bit of mach_header flags only valid for dylibs";
+
+ switch ( fHeader->filetype() ) {
+ case MH_EXECUTE:
+ fSlidableImage = ( flags & MH_PIE );
+ break;
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ fSlidableImage = true;
+ break;
+ default:
+ throw "not a mach-o file type supported by this tool";
+ }
+}
+
+template <typename A>
+void MachOChecker<A>::checkLoadCommands()
+{
+ // check that all load commands fit within the load command space file
+ const macho_encryption_info_command<P>* encryption_info = NULL;
+ const macho_thread_command<P>* threadInfo = NULL;
+ const macho_entry_point_command<P>* entryPoint = NULL;
+ const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
+ const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ uint32_t size = cmd->cmdsize();
+ if ( (size & this->loadCommandSizeMask()) != 0 )
+ throwf("load command #%d has a unaligned size", i);
+ const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
+ if ( endOfCmd > endOfLoadCommands )
+ throwf("load command #%d extends beyond the end of the load commands", i);
+ if ( endOfCmd > endOfFile )
+ throwf("load command #%d extends beyond the end of the file", i);
+ switch ( cmd->cmd() ) {
+ case macho_segment_command<P>::CMD:
+ case LC_SYMTAB:
+ case LC_DYSYMTAB:
+ case LC_LOAD_DYLIB:
+ case LC_ID_DYLIB:
+ case LC_LOAD_DYLINKER:
+ case LC_ID_DYLINKER:
+ case macho_routines_command<P>::CMD:
+ case LC_SUB_FRAMEWORK:
+ case LC_SUB_CLIENT:
+ case LC_TWOLEVEL_HINTS:
+ case LC_PREBIND_CKSUM:
+ case LC_LOAD_WEAK_DYLIB:
+ case LC_LAZY_LOAD_DYLIB:
+ case LC_UUID:
+ case LC_REEXPORT_DYLIB:
+ case LC_SEGMENT_SPLIT_INFO:
+ case LC_CODE_SIGNATURE:
+ case LC_LOAD_UPWARD_DYLIB:
+ case LC_VERSION_MIN_MACOSX:
+ case LC_VERSION_MIN_IPHONEOS:
+ case LC_RPATH:
+ case LC_FUNCTION_STARTS:
+ case LC_DYLD_ENVIRONMENT:
+ case LC_DATA_IN_CODE:
+ case LC_DYLIB_CODE_SIGN_DRS:
+ case LC_SOURCE_VERSION:
+ break;
+ case LC_DYLD_INFO:
+ case LC_DYLD_INFO_ONLY:
+ fDyldInfo = (macho_dyld_info_command<P>*)cmd;
+ break;
+ case LC_ENCRYPTION_INFO:
+ encryption_info = (macho_encryption_info_command<P>*)cmd;
+ break;
+ case LC_SUB_UMBRELLA:
+ case LC_SUB_LIBRARY:
+ if ( fHeader->flags() & MH_NO_REEXPORTED_DYLIBS )
+ throw "MH_NO_REEXPORTED_DYLIBS bit of mach_header flags should not be set in an image with LC_SUB_LIBRARY or LC_SUB_UMBRELLA";
+ break;
+ case LC_MAIN:
+ if ( fHeader->filetype() != MH_EXECUTE )
+ throw "LC_MAIN can only be used in MH_EXECUTE file types";
+ entryPoint = (macho_entry_point_command<P>*)cmd;
+ break;
+ case LC_UNIXTHREAD:
+ if ( fHeader->filetype() != MH_EXECUTE )
+ throw "LC_UNIXTHREAD can only be used in MH_EXECUTE file types";
+ threadInfo = (macho_thread_command<P>*)cmd;
+ break;
+ default:
+ throwf("load command #%d is an unknown kind 0x%X", i, cmd->cmd());
+ }
+ cmd = (const macho_load_command<P>*)endOfCmd;
+ }
+
+ // check segments
+ cmd = cmds;
+ std::vector<std::pair<pint_t, pint_t> > segmentAddressRanges;
+ std::vector<std::pair<pint_t, pint_t> > segmentFileOffsetRanges;
+ const macho_segment_command<P>* linkEditSegment = NULL;
+ const macho_segment_command<P>* stackSegment = NULL;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+ fSegments.push_back(segCmd);
+ if ( segCmd->cmdsize() != (sizeof(macho_segment_command<P>) + segCmd->nsects() * sizeof(macho_section_content<P>)) )
+ throw "invalid segment load command size";
+
+ // see if this overlaps another segment address range
+ uint64_t startAddr = segCmd->vmaddr();
+ uint64_t endAddr = startAddr + segCmd->vmsize();
+ for (typename std::vector<std::pair<pint_t, pint_t> >::iterator it = segmentAddressRanges.begin(); it != segmentAddressRanges.end(); ++it) {
+ if ( it->first < startAddr ) {
+ if ( it->second > startAddr )
+ throw "overlapping segment vm addresses";
+ }
+ else if ( it->first > startAddr ) {
+ if ( it->first < endAddr )
+ throw "overlapping segment vm addresses";
+ }
+ else {
+ throw "overlapping segment vm addresses";
+ }
+ segmentAddressRanges.push_back(std::make_pair<pint_t, pint_t>(startAddr, endAddr));
+ }
+ // see if this overlaps another segment file offset range
+ uint64_t startOffset = segCmd->fileoff();
+ uint64_t endOffset = startOffset + segCmd->filesize();
+ for (typename std::vector<std::pair<pint_t, pint_t> >::iterator it = segmentFileOffsetRanges.begin(); it != segmentFileOffsetRanges.end(); ++it) {
+ if ( it->first < startOffset ) {
+ if ( it->second > startOffset )
+ throw "overlapping segment file data";
+ }
+ else if ( it->first > startOffset ) {
+ if ( it->first < endOffset )
+ throw "overlapping segment file data";
+ }
+ else {
+ throw "overlapping segment file data";
+ }
+ segmentFileOffsetRanges.push_back(std::make_pair<pint_t, pint_t>(startOffset, endOffset));
+ // check is within file bounds
+ if ( (startOffset > fLength) || (endOffset > fLength) )
+ throw "segment file data is past end of file";
+ }
+ // verify it fits in file
+ if ( startOffset > fLength )
+ throw "segment fileoff does not fit in file";
+ if ( endOffset > fLength )
+ throw "segment fileoff+filesize does not fit in file";
+
+ // record special segments
+ if ( strcmp(segCmd->segname(), "__LINKEDIT") == 0 )
+ linkEditSegment = segCmd;
+ else if ( strcmp(segCmd->segname(), "__UNIXSTACK") == 0 )
+ stackSegment = segCmd;
+
+ // cache interesting segments
+ if ( fFirstSegment == NULL )
+ fFirstSegment = segCmd;
+ if ( (fTEXTSegment == NULL) && (strcmp(segCmd->segname(), "__TEXT") == 0) )
+ fTEXTSegment = segCmd;
+ if ( (segCmd->initprot() & VM_PROT_WRITE) != 0 ) {
+ if ( fFirstWritableSegment == NULL )
+ fFirstWritableSegment = segCmd;
+ if ( segCmd->vmaddr() > 0x100000000ULL )
+ fWriteableSegmentWithAddrOver4G = true;
+ }
+
+ // check section ranges
+ const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+ const macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()];
+ for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+ // check all non-zero sized sections are within segment
+ if ( sect->addr() < startAddr )
+ throwf("section %s vm address not within segment", sect->sectname());
+ if ( (sect->addr()+sect->size()) > endAddr )
+ throwf("section %s vm address not within segment", sect->sectname());
+ if ( ((sect->flags() & SECTION_TYPE) != S_ZEROFILL)
+ && ((sect->flags() & SECTION_TYPE) != S_THREAD_LOCAL_ZEROFILL)
+ && (segCmd->filesize() != 0)
+ && (sect->size() != 0) ) {
+ if ( sect->offset() < startOffset )
+ throwf("section %s file offset not within segment", sect->sectname());
+ if ( (sect->offset()+sect->size()) > endOffset )
+ throwf("section %s file offset not within segment", sect->sectname());
+ }
+ checkSection(segCmd, sect);
+ ++fSectionCount;
+ }
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+
+ // verify there was a LINKEDIT segment
+ if ( linkEditSegment == NULL )
+ throw "no __LINKEDIT segment";
+
+ // verify there was an executable __TEXT segment and load commands are in it
+ if ( fTEXTSegment == NULL )
+ throw "no __TEXT segment";
+ if ( fTEXTSegment->initprot() != (VM_PROT_READ|VM_PROT_EXECUTE) )
+ throw "__TEXT segment does not have r-x init permissions";
+ //if ( fTEXTSegment->maxprot() != (VM_PROT_READ|VM_PROT_EXECUTE|VM_PROT_WRITE) )
+ // throw "__TEXT segment does not have rwx max permissions";
+ if ( fTEXTSegment->fileoff() != 0 )
+ throw "__TEXT segment does not start at mach_header";
+ if ( fTEXTSegment->filesize() < (sizeof(macho_header<P>)+fHeader->sizeofcmds()) )
+ throw "__TEXT segment smaller than load commands";
+
+ // verify if custom stack used, that stack is in __UNIXSTACK segment
+ if ( threadInfo != NULL ) {
+ pint_t initialSP = getInitialStackPointer(threadInfo);
+ if ( initialSP != 0 ) {
+ if ( stackSegment == NULL )
+ throw "LC_UNIXTHREAD specifics custom initial stack pointer, but no __UNIXSTACK segment";
+ if ( (initialSP < stackSegment->vmaddr()) || (initialSP > (stackSegment->vmaddr()+stackSegment->vmsize())) )
+ throw "LC_UNIXTHREAD specifics custom initial stack pointer which does not point into __UNIXSTACK segment";
+ }
+ }
+
+ // verify __UNIXSTACK is zero fill
+ if ( stackSegment != NULL ) {
+ if ( (stackSegment->filesize() != 0) || (stackSegment->fileoff() != 0) )
+ throw "__UNIXSTACK is not a zero-fill segment";
+ if ( stackSegment->vmsize() < 4096 )
+ throw "__UNIXSTACK segment is too small";
+ }
+
+ // verify entry point is in __TEXT segment
+ if ( threadInfo != NULL ) {
+ pint_t initialPC = getEntryPoint(threadInfo);
+ if ( (initialPC < fTEXTSegment->vmaddr()) || (initialPC >= (fTEXTSegment->vmaddr()+fTEXTSegment->vmsize())) )
+ throwf("entry point 0x%0llX is outside __TEXT segment", (long long)initialPC);
+ }
+ else if ( entryPoint != NULL ) {
+ pint_t initialOffset = entryPoint->entryoff();
+ if ( (initialOffset < fTEXTSegment->fileoff()) || (initialOffset >= (fTEXTSegment->fileoff()+fTEXTSegment->filesize())) )
+ throwf("entry point 0x%0llX is outside __TEXT segment", (long long)initialOffset);
+ }
+
+ // checks for executables
+ bool isStaticExecutable = false;
+ if ( fHeader->filetype() == MH_EXECUTE ) {
+ isStaticExecutable = true;
+ cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch ( cmd->cmd() ) {
+ case LC_LOAD_DYLINKER:
+ // the existence of a dyld load command makes a executable dynamic
+ isStaticExecutable = false;
+ break;
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+ if ( isStaticExecutable ) {
+ if ( (fHeader->flags() != MH_NOUNDEFS) && (fHeader->flags() != (MH_NOUNDEFS|MH_PIE)) )
+ throw "invalid bits in mach_header flags for static executable";
+ }
+ }
+
+ // verify encryption info
+ if ( encryption_info != NULL ) {
+ if ( fHeader->filetype() != MH_EXECUTE )
+ throw "LC_ENCRYPTION_INFO load command is only legal in main executables";
+ if ( encryption_info->cryptoff() < (sizeof(macho_header<P>) + fHeader->sizeofcmds()) )
+ throw "LC_ENCRYPTION_INFO load command has cryptoff covers some load commands";
+ if ( (encryption_info->cryptoff() % 4096) != 0 )
+ throw "LC_ENCRYPTION_INFO load command has cryptoff which is not page aligned";
+ if ( (encryption_info->cryptsize() % 4096) != 0 )
+ throw "LC_ENCRYPTION_INFO load command has cryptsize which is not page sized";
+ for (typename std::vector<std::pair<pint_t, pint_t> >::iterator it = segmentFileOffsetRanges.begin();
+ it != segmentFileOffsetRanges.end(); ++it) {
+ if ( (it->first <= encryption_info->cryptoff()) && (encryption_info->cryptoff() < it->second) ) {
+ if ( (encryption_info->cryptoff() + encryption_info->cryptsize()) > it->second )
+ throw "LC_ENCRYPTION_INFO load command is not contained within one segment";
+ }
+ }
+ }
+
+ // check LC_SYMTAB, LC_DYSYMTAB, and LC_SEGMENT_SPLIT_INFO
+ cmd = cmds;
+ bool foundDynamicSymTab = false;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch ( cmd->cmd() ) {
+ case LC_SYMTAB:
+ {
+ const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
+ fSymbolCount = symtab->nsyms();
+ fSymbols = (const macho_nlist<P>*)((char*)fHeader + symtab->symoff());
+ if ( symtab->symoff() < linkEditSegment->fileoff() )
+ throw "symbol table not in __LINKEDIT";
+ if ( (symtab->symoff() + fSymbolCount*sizeof(macho_nlist<P>*)) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+ throw "symbol table end not in __LINKEDIT";
+ if ( (symtab->symoff() % sizeof(pint_t)) != 0 )
+ throw "symbol table start not pointer aligned";
+ fStrings = (char*)fHeader + symtab->stroff();
+ fStringsEnd = fStrings + symtab->strsize();
+ if ( symtab->stroff() < linkEditSegment->fileoff() )
+ throw "string pool not in __LINKEDIT";
+ if ( (symtab->stroff()+symtab->strsize()) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+ throw "string pool extends beyond __LINKEDIT";
+ if ( (symtab->stroff() % 4) != 0 ) // work around until rdar://problem/4737991 is fixed
+ throw "string pool start not pointer aligned";
+ if ( (symtab->strsize() % sizeof(pint_t)) != 0 )
+ throw "string pool size not a multiple of pointer size";
+ }
+ break;
+ case LC_DYSYMTAB:
+ {
+ if ( isStaticExecutable &&! fSlidableImage )
+ throw "LC_DYSYMTAB should not be used in static executable";
+ foundDynamicSymTab = true;
+ fDynamicSymbolTable = (macho_dysymtab_command<P>*)cmd;
+ fIndirectTable = (uint32_t*)((char*)fHeader + fDynamicSymbolTable->indirectsymoff());
+ fIndirectTableCount = fDynamicSymbolTable->nindirectsyms();
+ if ( fIndirectTableCount != 0 ) {
+ if ( fDynamicSymbolTable->indirectsymoff() < linkEditSegment->fileoff() )
+ throw "indirect symbol table not in __LINKEDIT";
+ if ( (fDynamicSymbolTable->indirectsymoff()+fIndirectTableCount*8) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+ throw "indirect symbol table not in __LINKEDIT";
+ if ( (fDynamicSymbolTable->indirectsymoff() % sizeof(pint_t)) != 0 )
+ throw "indirect symbol table not pointer aligned";
+ }
+ fLocalRelocationsCount = fDynamicSymbolTable->nlocrel();
+ if ( fLocalRelocationsCount != 0 ) {
+ fLocalRelocations = (const macho_relocation_info<P>*)((char*)fHeader + fDynamicSymbolTable->locreloff());
+ if ( fDynamicSymbolTable->locreloff() < linkEditSegment->fileoff() )
+ throw "local relocations not in __LINKEDIT";
+ if ( (fDynamicSymbolTable->locreloff()+fLocalRelocationsCount*sizeof(macho_relocation_info<P>)) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+ throw "local relocations not in __LINKEDIT";
+ if ( (fDynamicSymbolTable->locreloff() % sizeof(pint_t)) != 0 )
+ throw "local relocations table not pointer aligned";
+ }
+ fExternalRelocationsCount = fDynamicSymbolTable->nextrel();
+ if ( fExternalRelocationsCount != 0 ) {
+ fExternalRelocations = (const macho_relocation_info<P>*)((char*)fHeader + fDynamicSymbolTable->extreloff());
+ if ( fDynamicSymbolTable->extreloff() < linkEditSegment->fileoff() )
+ throw "external relocations not in __LINKEDIT";
+ if ( (fDynamicSymbolTable->extreloff()+fExternalRelocationsCount*sizeof(macho_relocation_info<P>)) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+ throw "external relocations not in __LINKEDIT";
+ if ( (fDynamicSymbolTable->extreloff() % sizeof(pint_t)) != 0 )
+ throw "external relocations table not pointer aligned";
+ }
+ }
+ break;
+ case LC_SEGMENT_SPLIT_INFO:
+ {
+ if ( isStaticExecutable )
+ throw "LC_SEGMENT_SPLIT_INFO should not be used in static executable";
+ const macho_linkedit_data_command<P>* info = (macho_linkedit_data_command<P>*)cmd;
+ if ( info->dataoff() < linkEditSegment->fileoff() )
+ throw "split seg info not in __LINKEDIT";
+ if ( (info->dataoff()+info->datasize()) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+ throw "split seg info not in __LINKEDIT";
+ if ( (info->dataoff() % sizeof(pint_t)) != 0 )
+ throw "split seg info table not pointer aligned";
+ if ( (info->datasize() % sizeof(pint_t)) != 0 )
+ throw "split seg info size not a multiple of pointer size";
+ }
+ break;
+ case LC_FUNCTION_STARTS:
+ {
+ const macho_linkedit_data_command<P>* info = (macho_linkedit_data_command<P>*)cmd;
+ if ( info->dataoff() < linkEditSegment->fileoff() )
+ throw "function starts data not in __LINKEDIT";
+ if ( (info->dataoff()+info->datasize()) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+ throw "function starts data not in __LINKEDIT";
+ if ( (info->dataoff() % sizeof(pint_t)) != 0 )
+ throw "function starts data table not pointer aligned";
+ if ( (info->datasize() % sizeof(pint_t)) != 0 )
+ throw "function starts data size not a multiple of pointer size";
+ }
+ break;
+ case LC_DATA_IN_CODE:
+ {
+ const macho_linkedit_data_command<P>* info = (macho_linkedit_data_command<P>*)cmd;
+ if ( info->dataoff() < linkEditSegment->fileoff() )
+ throw "data-in-code data not in __LINKEDIT";
+ if ( (info->dataoff()+info->datasize()) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+ throw "data-in-code data not in __LINKEDIT";
+ if ( (info->dataoff() % sizeof(pint_t)) != 0 )
+ throw "data-in-code data table not pointer aligned";
+ if ( (info->datasize() % sizeof(pint_t)) != 0 )
+ throw "data-in-code data size not a multiple of pointer size";
+ }
+ break;
+ case LC_DYLIB_CODE_SIGN_DRS:
+ {
+ const macho_linkedit_data_command<P>* info = (macho_linkedit_data_command<P>*)cmd;
+ if ( info->dataoff() < linkEditSegment->fileoff() )
+ throw "dependent dylib DR data not in __LINKEDIT";
+ if ( (info->dataoff()+info->datasize()) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+ throw "dependent dylib DR data not in __LINKEDIT";
+ if ( (info->dataoff() % sizeof(pint_t)) != 0 )
+ throw "dependent dylib DR data table not pointer aligned";
+ if ( (info->datasize() % sizeof(pint_t)) != 0 )
+ throw "dependent dylib DR data size not a multiple of pointer size";
+ }
+ break;
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+ if ( !isStaticExecutable && !foundDynamicSymTab )
+ throw "missing dynamic symbol table";
+ if ( fStrings == NULL )
+ throw "missing symbol table";
+
+}
+
+template <typename A>
+void MachOChecker<A>::checkSection(const macho_segment_command<P>* segCmd, const macho_section<P>* sect)
+{
+ uint8_t sectionType = (sect->flags() & SECTION_TYPE);
+ if ( sectionType == S_ZEROFILL ) {
+ if ( sect->offset() != 0 )
+ throwf("section offset should be zero for zero-fill section %s", sect->sectname());
+ }
+
+ // check section's segment name matches segment
+// if ( strncmp(sect->segname(), segCmd->segname(), 16) != 0 )
+// throwf("section %s in segment %s has wrong segment name", sect->sectname(), segCmd->segname());
+
+ // more section tests here
+}
+
+
+
+
+template <typename A>
+void MachOChecker<A>::checkIndirectSymbolTable()
+{
+ // static executables don't have indirect symbol table
+ if ( fDynamicSymbolTable == NULL )
+ return;
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+ const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+ const macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()];
+ for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+ // make sure all magic sections that use indirect symbol table fit within it
+ uint32_t start = 0;
+ uint32_t elementSize = 0;
+ switch ( sect->flags() & SECTION_TYPE ) {
+ case S_SYMBOL_STUBS:
+ elementSize = sect->reserved2();
+ start = sect->reserved1();
+ break;
+ case S_LAZY_SYMBOL_POINTERS:
+ case S_NON_LAZY_SYMBOL_POINTERS:
+ elementSize = sizeof(pint_t);
+ start = sect->reserved1();
+ break;
+ }
+ if ( elementSize != 0 ) {
+ uint32_t count = sect->size() / elementSize;
+ if ( (count*elementSize) != sect->size() )
+ throwf("%s section size is not an even multiple of element size", sect->sectname());
+ if ( (start+count) > fIndirectTableCount )
+ throwf("%s section references beyond end of indirect symbol table (%d > %d)", sect->sectname(), start+count, fIndirectTableCount );
+ }
+ }
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+}
+
+
+
+
+template <typename A>
+void MachOChecker<A>::checkSymbolTable()
+{
+ // verify no duplicate external symbol names
+ if ( fDynamicSymbolTable != NULL ) {
+ StringSet externalNames;
+ const macho_nlist<P>* const exportedStart = &fSymbols[fDynamicSymbolTable->iextdefsym()];
+ const macho_nlist<P>* const exportedEnd = &exportedStart[fDynamicSymbolTable->nextdefsym()];
+ int i = fDynamicSymbolTable->iextdefsym();
+ for(const macho_nlist<P>* p = exportedStart; p < exportedEnd; ++p, ++i) {
+ const char* symName = &fStrings[p->n_strx()];
+ if ( symName > fStringsEnd )
+ throw "string index out of range";
+ //fprintf(stderr, "sym[%d] = %s\n", i, symName);
+ if ( externalNames.find(symName) != externalNames.end() )
+ throwf("duplicate external symbol: %s", symName);
+ if ( (p->n_type() & N_EXT) == 0 )
+ throwf("non-external symbol in external symbol range: %s", symName);
+ // don't add N_INDR to externalNames because there is likely an undefine with same name
+ if ( (p->n_type() & N_INDR) == 0 )
+ externalNames.insert(symName);
+ }
+ // verify no undefines with same name as an external symbol
+ const macho_nlist<P>* const undefinesStart = &fSymbols[fDynamicSymbolTable->iundefsym()];
+ const macho_nlist<P>* const undefinesEnd = &undefinesStart[fDynamicSymbolTable->nundefsym()];
+ for(const macho_nlist<P>* p = undefinesStart; p < undefinesEnd; ++p) {
+ const char* symName = &fStrings[p->n_strx()];
+ if ( symName > fStringsEnd )
+ throw "string index out of range";
+ if ( externalNames.find(symName) != externalNames.end() )
+ throwf("undefine with same name as external symbol: %s", symName);
+ }
+ // verify all N_SECT values are valid
+ for(const macho_nlist<P>* p = fSymbols; p < &fSymbols[fSymbolCount]; ++p) {
+ uint8_t type = p->n_type();
+ if ( ((type & N_STAB) == 0) && ((type & N_TYPE) == N_SECT) ) {
+ if ( p->n_sect() > fSectionCount ) {
+ throwf("symbol '%s' has n_sect=%d which is too large", &fStrings[p->n_strx()], p->n_sect());
+ }
+ }
+ }
+ }
+}
+
+
+template <typename A>
+void MachOChecker<A>::checkInitTerms()
+{
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+ const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+ const macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()];
+ for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+ // make sure all magic sections that use indirect symbol table fit within it
+ uint32_t count;
+ pint_t* arrayStart;
+ pint_t* arrayEnd;
+ const char* kind = "initializer";
+ switch ( sect->flags() & SECTION_TYPE ) {
+ case S_MOD_TERM_FUNC_POINTERS:
+ kind = "terminator";
+ // fall through
+ case S_MOD_INIT_FUNC_POINTERS:
+ count = sect->size() / sizeof(pint_t);
+ if ( (count*sizeof(pint_t)) != sect->size() )
+ throwf("%s section size is not an even multiple of element size", sect->sectname());
+ if ( (sect->addr() % sizeof(pint_t)) != 0 )
+ throwf("%s section size is not pointer size aligned", sect->sectname());
+ // check each pointer in array points within TEXT
+ arrayStart = (pint_t*)((char*)fHeader + sect->offset());
+ arrayEnd = (pint_t*)((char*)fHeader + sect->offset() + sect->size());
+ for (pint_t* p=arrayStart; p < arrayEnd; ++p) {
+ pint_t pointer = P::getP(*p);
+ if ( (pointer < fTEXTSegment->vmaddr()) || (pointer >= (fTEXTSegment->vmaddr()+fTEXTSegment->vmsize())) )
+ throwf("%s 0x%08llX points outside __TEXT segment", kind, (long long)pointer);
+ }
+ // check each pointer in array will be rebased and not bound
+ if ( fSlidableImage ) {
+ pint_t sectionBeginAddr = sect->addr();
+ pint_t sectionEndddr = sect->addr() + sect->size();
+ for(pint_t addr = sectionBeginAddr; addr < sectionEndddr; addr += sizeof(pint_t)) {
+ if ( addressIsBindingSite(addr) )
+ throwf("%s at 0x%0llX has binding to external symbol", kind, (long long)addr);
+ if ( ! addressIsRebaseSite(addr) )
+ throwf("%s at 0x%0llX is not rebased", kind, (long long)addr);
+ }
+ }
+ break;
+ }
+ }
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+
+}
+
+
+template <>
+ppc::P::uint_t MachOChecker<ppc>::relocBase()
+{
+ if ( fHeader->flags() & MH_SPLIT_SEGS )
+ return fFirstWritableSegment->vmaddr();
+ else
+ return fFirstSegment->vmaddr();
+}
+
+template <>
+ppc64::P::uint_t MachOChecker<ppc64>::relocBase()
+{
+ if ( fWriteableSegmentWithAddrOver4G )
+ return fFirstWritableSegment->vmaddr();
+ else
+ return fFirstSegment->vmaddr();
+}
+
+template <>
+x86::P::uint_t MachOChecker<x86>::relocBase()
+{
+ if ( fHeader->flags() & MH_SPLIT_SEGS )
+ return fFirstWritableSegment->vmaddr();
+ else
+ return fFirstSegment->vmaddr();
+}
+
+template <>
+x86_64::P::uint_t MachOChecker<x86_64>::relocBase()
+{
+ // check for split-seg
+ return fFirstWritableSegment->vmaddr();
+}
+
+template <>
+arm::P::uint_t MachOChecker<arm>::relocBase()
+{
+ if ( fHeader->flags() & MH_SPLIT_SEGS )
+ return fFirstWritableSegment->vmaddr();
+ else
+ return fFirstSegment->vmaddr();
+}
+
+
+template <typename A>
+bool MachOChecker<A>::addressInWritableSegment(pint_t address)
+{
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+ if ( (address >= segCmd->vmaddr()) && (address < segCmd->vmaddr()+segCmd->vmsize()) ) {
+ // if segment is writable, we are fine
+ if ( (segCmd->initprot() & VM_PROT_WRITE) != 0 )
+ return true;
+ // could be a text reloc, make sure section bit is set
+ const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+ const macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()];
+ for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+ if ( (sect->addr() <= address) && (address < (sect->addr()+sect->size())) ) {
+ // found section for this address, if has relocs we are fine
+ return ( (sect->flags() & (S_ATTR_EXT_RELOC|S_ATTR_LOC_RELOC)) != 0 );
+ }
+ }
+ }
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+ return false;
+}
+
+
+template <>
+void MachOChecker<ppc>::checkExternalReloation(const macho_relocation_info<P>* reloc)
+{
+ if ( reloc->r_length() != 2 )
+ throw "bad external relocation length";
+ if ( reloc->r_type() != GENERIC_RELOC_VANILLA )
+ throw "unknown external relocation type";
+ if ( reloc->r_pcrel() != 0 )
+ throw "bad external relocation pc_rel";
+ if ( reloc->r_extern() == 0 )
+ throw "local relocation found with external relocations";
+ if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) )
+ throw "external relocation address not in writable segment";
+ // FIX: check r_symbol
+}
+
+template <>
+void MachOChecker<ppc64>::checkExternalReloation(const macho_relocation_info<P>* reloc)
+{
+ if ( reloc->r_length() != 3 )
+ throw "bad external relocation length";
+ if ( reloc->r_type() != GENERIC_RELOC_VANILLA )
+ throw "unknown external relocation type";
+ if ( reloc->r_pcrel() != 0 )
+ throw "bad external relocation pc_rel";
+ if ( reloc->r_extern() == 0 )
+ throw "local relocation found with external relocations";
+ if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) )
+ throw "external relocation address not in writable segment";
+ // FIX: check r_symbol
+}
+
+template <>
+void MachOChecker<x86>::checkExternalReloation(const macho_relocation_info<P>* reloc)
+{
+ if ( reloc->r_length() != 2 )
+ throw "bad external relocation length";
+ if ( reloc->r_type() != GENERIC_RELOC_VANILLA )
+ throw "unknown external relocation type";
+ if ( reloc->r_pcrel() != 0 )
+ throw "bad external relocation pc_rel";
+ if ( reloc->r_extern() == 0 )
+ throw "local relocation found with external relocations";
+ if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) )
+ throw "external relocation address not in writable segment";
+ // FIX: check r_symbol
+}
+
+
+template <>
+void MachOChecker<x86_64>::checkExternalReloation(const macho_relocation_info<P>* reloc)
+{
+ if ( reloc->r_length() != 3 )
+ throw "bad external relocation length";
+ if ( reloc->r_type() != X86_64_RELOC_UNSIGNED )
+ throw "unknown external relocation type";
+ if ( reloc->r_pcrel() != 0 )
+ throw "bad external relocation pc_rel";
+ if ( reloc->r_extern() == 0 )
+ throw "local relocation found with external relocations";
+ if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) )
+ throw "exernal relocation address not in writable segment";
+ // FIX: check r_symbol
+}
+
+#if SUPPORT_ARCH_arm_any
+template <>
+void MachOChecker<arm>::checkExternalReloation(const macho_relocation_info<P>* reloc)
+{
+ if ( reloc->r_length() != 2 )
+ throw "bad external relocation length";
+ if ( reloc->r_type() != ARM_RELOC_VANILLA )
+ throw "unknown external relocation type";
+ if ( reloc->r_pcrel() != 0 )
+ throw "bad external relocation pc_rel";
+ if ( reloc->r_extern() == 0 )
+ throw "local relocation found with external relocations";
+ if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) )
+ throw "external relocation address not in writable segment";
+ // FIX: check r_symbol
+}
+#endif
+
+
+template <>
+void MachOChecker<ppc>::checkLocalReloation(const macho_relocation_info<P>* reloc)
+{
+ if ( reloc->r_address() & R_SCATTERED ) {
+ // scattered
+ const macho_scattered_relocation_info<P>* sreloc = (const macho_scattered_relocation_info<P>*)reloc;
+ // FIX
+
+ }
+ else {
+ // FIX
+ if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) )
+ throwf("local relocation address 0x%08X not in writable segment", reloc->r_address());
+ }
+}
+
+
+template <>
+void MachOChecker<ppc64>::checkLocalReloation(const macho_relocation_info<P>* reloc)
+{
+ if ( reloc->r_length() != 3 )
+ throw "bad local relocation length";
+ if ( reloc->r_type() != GENERIC_RELOC_VANILLA )
+ throw "unknown local relocation type";
+ if ( reloc->r_pcrel() != 0 )
+ throw "bad local relocation pc_rel";
+ if ( reloc->r_extern() != 0 )
+ throw "external relocation found with local relocations";
+ if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) )
+ throw "local relocation address not in writable segment";
+}
+
+template <>
+void MachOChecker<x86>::checkLocalReloation(const macho_relocation_info<P>* reloc)
+{
+ // FIX
+}
+
+template <>
+void MachOChecker<x86_64>::checkLocalReloation(const macho_relocation_info<P>* reloc)
+{
+ if ( reloc->r_length() != 3 )
+ throw "bad local relocation length";
+ if ( reloc->r_type() != X86_64_RELOC_UNSIGNED )
+ throw "unknown local relocation type";
+ if ( reloc->r_pcrel() != 0 )
+ throw "bad local relocation pc_rel";
+ if ( reloc->r_extern() != 0 )
+ throw "external relocation found with local relocations";
+ if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) )
+ throw "local relocation address not in writable segment";
+}
+
+#if SUPPORT_ARCH_arm_any
+template <>
+void MachOChecker<arm>::checkLocalReloation(const macho_relocation_info<P>* reloc)
+{
+ if ( reloc->r_address() & R_SCATTERED ) {
+ // scattered
+ const macho_scattered_relocation_info<P>* sreloc = (const macho_scattered_relocation_info<P>*)reloc;
+ if ( sreloc->r_length() != 2 )
+ throw "bad local scattered relocation length";
+ if ( sreloc->r_type() != ARM_RELOC_PB_LA_PTR )
+ throw "bad local scattered relocation type";
+ }
+ else {
+ if ( reloc->r_length() != 2 )
+ throw "bad local relocation length";
+ if ( reloc->r_extern() != 0 )
+ throw "external relocation found with local relocations";
+ if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) )
+ throw "local relocation address not in writable segment";
+ }
+}
+#endif
+
+template <typename A>
+void MachOChecker<A>::checkRelocations()
+{
+ // external relocations should be sorted to minimize dyld symbol lookups
+ // therefore every reloc with the same r_symbolnum value should be contiguous
+ std::set<uint32_t> previouslySeenSymbolIndexes;
+ uint32_t lastSymbolIndex = 0xFFFFFFFF;
+ const macho_relocation_info<P>* const externRelocsEnd = &fExternalRelocations[fExternalRelocationsCount];
+ for (const macho_relocation_info<P>* reloc = fExternalRelocations; reloc < externRelocsEnd; ++reloc) {
+ this->checkExternalReloation(reloc);
+ if ( reloc->r_symbolnum() != lastSymbolIndex ) {
+ if ( previouslySeenSymbolIndexes.count(reloc->r_symbolnum()) != 0 )
+ throw "external relocations not sorted";
+ previouslySeenSymbolIndexes.insert(lastSymbolIndex);
+ lastSymbolIndex = reloc->r_symbolnum();
+ }
+ }
+
+ const macho_relocation_info<P>* const localRelocsEnd = &fLocalRelocations[fLocalRelocationsCount];
+ for (const macho_relocation_info<P>* reloc = fLocalRelocations; reloc < localRelocsEnd; ++reloc) {
+ this->checkLocalReloation(reloc);
+ }
+
+ // verify any section with S_ATTR_LOC_RELOC bits set actually has text relocs
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+ // if segment is writable, we are fine
+ if ( (segCmd->initprot() & VM_PROT_WRITE) != 0 )
+ continue;
+ // look at sections that have text reloc bit set
+ const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+ const macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()];
+ for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+ if ( (sect->flags() & S_ATTR_LOC_RELOC) != 0 ) {
+ if ( ! hasTextRelocInRange(sect->addr(), sect->addr()+sect->size()) ) {
+ throwf("section %s has attribute set that it has relocs, but it has none", sect->sectname());
+ }
+ }
+ }
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+}
+
+template <typename A>
+typename A::P::uint_t MachOChecker<A>::segStartAddress(uint8_t segIndex)
+{
+ if ( segIndex > fSegments.size() )
+ throw "segment index out of range";
+ return fSegments[segIndex]->vmaddr();
+}
+
+template <typename A>
+bool MachOChecker<A>::hasTextRelocInRange(pint_t rangeStart, pint_t rangeEnd)
+{
+ // look at local relocs
+ const macho_relocation_info<P>* const localRelocsEnd = &fLocalRelocations[fLocalRelocationsCount];
+ for (const macho_relocation_info<P>* reloc = fLocalRelocations; reloc < localRelocsEnd; ++reloc) {
+ pint_t relocAddress = reloc->r_address() + this->relocBase();
+ if ( (rangeStart <= relocAddress) && (relocAddress < rangeEnd) )
+ return true;
+ }
+ // look rebase info
+ if ( fDyldInfo != NULL ) {
+ const uint8_t* p = (uint8_t*)fHeader + fDyldInfo->rebase_off();
+ const uint8_t* end = &p[fDyldInfo->rebase_size()];
+
+ uint8_t type = 0;
+ uint64_t segOffset = 0;
+ uint32_t count;
+ uint32_t skip;
+ int segIndex;
+ pint_t segStartAddr = 0;
+ pint_t addr;
+ bool done = false;
+ while ( !done && (p < end) ) {
+ uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
+ uint8_t opcode = *p & REBASE_OPCODE_MASK;
+ ++p;
+ switch (opcode) {
+ case REBASE_OPCODE_DONE:
+ done = true;
+ break;
+ case REBASE_OPCODE_SET_TYPE_IMM:
+ type = immediate;
+ break;
+ case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ segIndex = immediate;
+ segStartAddr = segStartAddress(segIndex);
+ segOffset = read_uleb128(p, end);
+ break;
+ case REBASE_OPCODE_ADD_ADDR_ULEB:
+ segOffset += read_uleb128(p, end);
+ break;
+ case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+ segOffset += immediate*sizeof(pint_t);
+ break;
+ case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+ for (int i=0; i < immediate; ++i) {
+ addr = segStartAddr+segOffset;
+ if ( (rangeStart <= addr) && (addr < rangeEnd) )
+ return true;
+ //printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+ segOffset += sizeof(pint_t);
+ }
+ break;
+ case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+ count = read_uleb128(p, end);
+ for (uint32_t i=0; i < count; ++i) {
+ addr = segStartAddr+segOffset;
+ if ( (rangeStart <= addr) && (addr < rangeEnd) )
+ return true;
+ //printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+ segOffset += sizeof(pint_t);
+ }
+ break;
+ case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+ addr = segStartAddr+segOffset;
+ if ( (rangeStart <= addr) && (addr < rangeEnd) )
+ return true;
+ //printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+ segOffset += read_uleb128(p, end) + sizeof(pint_t);
+ break;
+ case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
+ count = read_uleb128(p, end);
+ skip = read_uleb128(p, end);
+ for (uint32_t i=0; i < count; ++i) {
+ addr = segStartAddr+segOffset;
+ if ( (rangeStart <= addr) && (addr < rangeEnd) )
+ return true;
+ //printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+ segOffset += skip + sizeof(pint_t);
+ }
+ break;
+ default:
+ throwf("bad rebase opcode %d", *p);
+ }
+ }
+ }
+ return false;
+}
+
+template <typename A>
+bool MachOChecker<A>::addressIsRebaseSite(pint_t targetAddr)
+{
+ // look at local relocs
+ const macho_relocation_info<P>* const localRelocsEnd = &fLocalRelocations[fLocalRelocationsCount];
+ for (const macho_relocation_info<P>* reloc = fLocalRelocations; reloc < localRelocsEnd; ++reloc) {
+ pint_t relocAddress = reloc->r_address() + this->relocBase();
+ if ( relocAddress == targetAddr )
+ return true;
+ }
+ // look rebase info
+ if ( fDyldInfo != NULL ) {
+ const uint8_t* p = (uint8_t*)fHeader + fDyldInfo->rebase_off();
+ const uint8_t* end = &p[fDyldInfo->rebase_size()];
+
+ uint8_t type = 0;
+ uint64_t segOffset = 0;
+ uint32_t count;
+ uint32_t skip;
+ int segIndex;
+ pint_t segStartAddr = 0;
+ pint_t addr;
+ bool done = false;
+ while ( !done && (p < end) ) {
+ uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
+ uint8_t opcode = *p & REBASE_OPCODE_MASK;
+ ++p;
+ switch (opcode) {
+ case REBASE_OPCODE_DONE:
+ done = true;
+ break;
+ case REBASE_OPCODE_SET_TYPE_IMM:
+ type = immediate;
+ break;
+ case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ segIndex = immediate;
+ segStartAddr = segStartAddress(segIndex);
+ segOffset = read_uleb128(p, end);
+ break;
+ case REBASE_OPCODE_ADD_ADDR_ULEB:
+ segOffset += read_uleb128(p, end);
+ break;
+ case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+ segOffset += immediate*sizeof(pint_t);
+ break;
+ case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+ for (int i=0; i < immediate; ++i) {
+ addr = segStartAddr+segOffset;
+ if ( addr == targetAddr )
+ return true;
+ //printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+ segOffset += sizeof(pint_t);
+ }
+ break;
+ case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+ count = read_uleb128(p, end);
+ for (uint32_t i=0; i < count; ++i) {
+ addr = segStartAddr+segOffset;
+ if ( addr == targetAddr )
+ return true;
+ //printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+ segOffset += sizeof(pint_t);
+ }
+ break;
+ case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+ addr = segStartAddr+segOffset;
+ if ( addr == targetAddr )
+ return true;
+ //printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+ segOffset += read_uleb128(p, end) + sizeof(pint_t);
+ break;
+ case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
+ count = read_uleb128(p, end);
+ skip = read_uleb128(p, end);
+ for (uint32_t i=0; i < count; ++i) {
+ addr = segStartAddr+segOffset;
+ if ( addr == targetAddr )
+ return true;
+ //printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+ segOffset += skip + sizeof(pint_t);
+ }
+ break;
+ default:
+ throwf("bad rebase opcode %d", *p);
+ }
+ }
+ }
+ return false;
+}
+
+
+template <typename A>
+bool MachOChecker<A>::addressIsBindingSite(pint_t targetAddr)
+{
+ // look at external relocs
+ const macho_relocation_info<P>* const externRelocsEnd = &fExternalRelocations[fExternalRelocationsCount];
+ for (const macho_relocation_info<P>* reloc = fExternalRelocations; reloc < externRelocsEnd; ++reloc) {
+ pint_t relocAddress = reloc->r_address() + this->relocBase();
+ if ( relocAddress == targetAddr )
+ return true;
+ }
+ // look bind info
+ if ( fDyldInfo != NULL ) {
+ const uint8_t* p = (uint8_t*)fHeader + fDyldInfo->bind_off();
+ const uint8_t* end = &p[fDyldInfo->bind_size()];
+
+ uint8_t type = 0;
+ uint64_t segOffset = 0;
+ uint32_t count;
+ uint32_t skip;
+ uint8_t flags;
+ const char* symbolName = NULL;
+ int libraryOrdinal = 0;
+ int segIndex;
+ int64_t addend = 0;
+ pint_t segStartAddr = 0;
+ pint_t addr;
+ bool done = false;
+ while ( !done && (p < end) ) {
+ uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+ uint8_t opcode = *p & BIND_OPCODE_MASK;
+ ++p;
+ switch (opcode) {
+ case BIND_OPCODE_DONE:
+ done = true;
+ break;
+ case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+ libraryOrdinal = immediate;
+ break;
+ case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+ libraryOrdinal = read_uleb128(p, end);
+ break;
+ case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+ // the special ordinals are negative numbers
+ if ( immediate == 0 )
+ libraryOrdinal = 0;
+ else {
+ int8_t signExtended = BIND_OPCODE_MASK | immediate;
+ libraryOrdinal = signExtended;
+ }
+ break;
+ case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+ symbolName = (char*)p;
+ while (*p != '\0')
+ ++p;
+ ++p;
+ break;
+ case BIND_OPCODE_SET_TYPE_IMM:
+ type = immediate;
+ break;
+ case BIND_OPCODE_SET_ADDEND_SLEB:
+ addend = read_sleb128(p, end);
+ break;
+ case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ segIndex = immediate;
+ segStartAddr = segStartAddress(segIndex);
+ segOffset = read_uleb128(p, end);
+ break;
+ case BIND_OPCODE_ADD_ADDR_ULEB:
+ segOffset += read_uleb128(p, end);
+ break;
+ case BIND_OPCODE_DO_BIND:
+ if ( (segStartAddr+segOffset) == targetAddr )
+ return true;
+ segOffset += sizeof(pint_t);
+ break;
+ case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+ if ( (segStartAddr+segOffset) == targetAddr )
+ return true;
+ segOffset += read_uleb128(p, end) + sizeof(pint_t);
+ break;
+ case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+ if ( (segStartAddr+segOffset) == targetAddr )
+ return true;
+ segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
+ break;
+ case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+ count = read_uleb128(p, end);
+ skip = read_uleb128(p, end);
+ for (uint32_t i=0; i < count; ++i) {
+ if ( (segStartAddr+segOffset) == targetAddr )
+ return true;
+ segOffset += skip + sizeof(pint_t);
+ }
+ break;
+ default:
+ throwf("bad bind opcode %d", *p);
+ }
+ }
+ }
+ return false;
+}
+
+
+static void check(const char* path)
+{
+ struct stat stat_buf;
+
+ try {
+ int fd = ::open(path, O_RDONLY, 0);
+ if ( fd == -1 )
+ throw "cannot open file";
+ if ( ::fstat(fd, &stat_buf) != 0 )
+ throwf("fstat(%s) failed, errno=%d\n", path, errno);
+ uint32_t length = stat_buf.st_size;
+ uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+ if ( p == ((uint8_t*)(-1)) )
+ throw "cannot map file";
+ ::close(fd);
+ const mach_header* mh = (mach_header*)p;
+ if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+ const struct fat_header* fh = (struct fat_header*)p;
+ const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
+ for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
+ size_t offset = OSSwapBigToHostInt32(archs[i].offset);
+ size_t size = OSSwapBigToHostInt32(archs[i].size);
+ unsigned int cputype = OSSwapBigToHostInt32(archs[i].cputype);
+
+ switch(cputype) {
+ case CPU_TYPE_POWERPC:
+ if ( MachOChecker<ppc>::validFile(p + offset) )
+ MachOChecker<ppc>::make(p + offset, size, path);
+ else
+ throw "in universal file, ppc slice does not contain ppc mach-o";
+ break;
+ case CPU_TYPE_I386:
+ if ( MachOChecker<x86>::validFile(p + offset) )
+ MachOChecker<x86>::make(p + offset, size, path);
+ else
+ throw "in universal file, i386 slice does not contain i386 mach-o";
+ break;
+ case CPU_TYPE_POWERPC64:
+ if ( MachOChecker<ppc64>::validFile(p + offset) )
+ MachOChecker<ppc64>::make(p + offset, size, path);
+ else
+ throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
+ break;
+ case CPU_TYPE_X86_64:
+ if ( MachOChecker<x86_64>::validFile(p + offset) )
+ MachOChecker<x86_64>::make(p + offset, size, path);
+ else
+ throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
+ break;
+#if SUPPORT_ARCH_arm_any
+ case CPU_TYPE_ARM:
+ if ( MachOChecker<arm>::validFile(p + offset) )
+ MachOChecker<arm>::make(p + offset, size, path);
+ else
+ throw "in universal file, arm slice does not contain arm mach-o";
+ break;
+#endif
+ default:
+ throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
+ }
+ }
+ }
+ else if ( MachOChecker<x86>::validFile(p) ) {
+ MachOChecker<x86>::make(p, length, path);
+ }
+ else if ( MachOChecker<ppc>::validFile(p) ) {
+ MachOChecker<ppc>::make(p, length, path);
+ }
+ else if ( MachOChecker<ppc64>::validFile(p) ) {
+ MachOChecker<ppc64>::make(p, length, path);
+ }
+ else if ( MachOChecker<x86_64>::validFile(p) ) {
+ MachOChecker<x86_64>::make(p, length, path);
+ }
+#if SUPPORT_ARCH_arm_any
+ else if ( MachOChecker<arm>::validFile(p) ) {
+ MachOChecker<arm>::make(p, length, path);
+ }
+#endif
+ else {
+ throw "not a known file type";
+ }
+ }
+ catch (const char* msg) {
+ throwf("%s in %s", msg, path);
+ }
+}
+
+
+int main(int argc, const char* argv[])
+{
+ bool progress = false;
+ int result = 0;
+ for(int i=1; i < argc; ++i) {
+ const char* arg = argv[i];
+ if ( arg[0] == '-' ) {
+ if ( strcmp(arg, "-progress") == 0 ) {
+ progress = true;
+ }
+ else {
+ throwf("unknown option: %s\n", arg);
+ }
+ }
+ else {
+ bool success = true;
+ try {
+ check(arg);
+ }
+ catch (const char* msg) {
+ fprintf(stderr, "machocheck failed: %s %s\n", arg, msg);
+ result = 1;
+ success = false;
+ }
+ if ( success && progress )
+ printf("ok: %s\n", arg);
+ }
+ }
+
+ return result;
+}
+
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdint.h>
+
+
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/*
+ * prune_trie() is a C vended function that is used by strip(1) to prune out
+ * defined exported symbols from the export trie. It is passed a pointer to
+ * the start of bytes of the the trie and the size. The prune() funciton
+ * passed is called with each symbol name in the trie to determine if it is
+ * to be pruned (retuning 1) or not (returning 0). It writes the new trie
+ * back into the trie buffer and returns the new size in trie_new_size.
+ * If the pruning succeeds, NULL is returned. If there was an error processing
+ * the trie (e.f. it is malformed), then an error message string is returned.
+ * The error string can be freed.
+ */
+extern const char*
+prune_trie(
+ uint8_t* trie_start,
+ uint32_t trie_start_size,
+ int (*prune)(const char *name),
+ uint32_t* trie_new_size);
+
+
+#if __cplusplus
+}
+#endif /* __cplusplus */
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006-2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <mach/mach.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <vector>
+#include <set>
+
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+
+static bool verbose = false;
+
+__attribute__((noreturn))
+void throwf(const char* format, ...)
+{
+ va_list list;
+ char* p;
+ va_start(list, format);
+ vasprintf(&p, format, list);
+ va_end(list);
+
+ const char* t = p;
+ throw t;
+}
+
+
+class AbstractRebaser
+{
+public:
+ virtual cpu_type_t getArchitecture() const = 0;
+ virtual uint64_t getBaseAddress() const = 0;
+ virtual uint64_t getVMSize() const = 0;
+ virtual void setBaseAddress(uint64_t) = 0;
+};
+
+
+template <typename A>
+class Rebaser : public AbstractRebaser
+{
+public:
+ Rebaser(const void* machHeader);
+ virtual ~Rebaser() {}
+
+ virtual cpu_type_t getArchitecture() const;
+ virtual uint64_t getBaseAddress() const;
+ virtual uint64_t getVMSize() const;
+ virtual void setBaseAddress(uint64_t);
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ struct vmmap { pint_t vmaddr; pint_t vmsize; pint_t fileoff; };
+
+ void setRelocBase();
+ void buildSectionTable();
+ void adjustLoadCommands();
+ void adjustSymbolTable();
+ void adjustDATA();
+ void doLocalRelocation(const macho_relocation_info<P>* reloc);
+ pint_t* mappedAddressForVMAddress(uint32_t vmaddress);
+ void rebaseAt(int segIndex, uint64_t offset, uint8_t type);
+
+ const macho_header<P>* fHeader;
+ pint_t fOrignalVMRelocBaseAddress;
+ pint_t fSlide;
+ std::vector<vmmap> fVMMApping;
+};
+
+
+
+class MultiArchRebaser
+{
+public:
+ MultiArchRebaser(const char* path, bool writable=false);
+ ~MultiArchRebaser();
+
+ const std::vector<AbstractRebaser*>& getArchs() const { return fRebasers; }
+ void commit();
+
+private:
+ std::vector<AbstractRebaser*> fRebasers;
+ void* fMappingAddress;
+ uint64_t fFileSize;
+};
+
+
+
+MultiArchRebaser::MultiArchRebaser(const char* path, bool writable)
+ : fMappingAddress(0), fFileSize(0)
+{
+ // map in whole file
+ int fd = ::open(path, (writable ? O_RDWR : O_RDONLY), 0);
+ if ( fd == -1 )
+ throwf("can't open file %s, errno=%d", path, errno);
+ struct stat stat_buf;
+ if ( fstat(fd, &stat_buf) == -1)
+ throwf("can't stat open file %s, errno=%d", path, errno);
+ if ( stat_buf.st_size < 20 )
+ throwf("file too small %s", path);
+ const int prot = writable ? (PROT_READ | PROT_WRITE) : PROT_READ;
+ const int flags = writable ? (MAP_FILE | MAP_SHARED) : (MAP_FILE | MAP_PRIVATE);
+ uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, prot, flags, fd, 0);
+ if ( p == (uint8_t*)(-1) )
+ throwf("can't map file %s, errno=%d", path, errno);
+ ::close(fd);
+
+ // if fat file, process each architecture
+ const fat_header* fh = (fat_header*)p;
+ const mach_header* mh = (mach_header*)p;
+ if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+ // Fat header is always big-endian
+ const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
+ for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
+ uint32_t fileOffset = OSSwapBigToHostInt32(archs[i].offset);
+ try {
+ switch ( OSSwapBigToHostInt32(archs[i].cputype) ) {
+ case CPU_TYPE_POWERPC:
+ fRebasers.push_back(new Rebaser<ppc>(&p[fileOffset]));
+ break;
+ case CPU_TYPE_POWERPC64:
+ fRebasers.push_back(new Rebaser<ppc64>(&p[fileOffset]));
+ break;
+ case CPU_TYPE_I386:
+ fRebasers.push_back(new Rebaser<x86>(&p[fileOffset]));
+ break;
+ case CPU_TYPE_X86_64:
+ fRebasers.push_back(new Rebaser<x86_64>(&p[fileOffset]));
+ break;
+ case CPU_TYPE_ARM:
+ fRebasers.push_back(new Rebaser<arm>(&p[fileOffset]));
+ break;
+ default:
+ throw "unknown file format";
+ }
+ }
+ catch (const char* msg) {
+ fprintf(stderr, "rebase warning: %s for %s\n", msg, path);
+ }
+ }
+ }
+ else {
+ try {
+ if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC)) {
+ fRebasers.push_back(new Rebaser<ppc>(mh));
+ }
+ else if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC64)) {
+ fRebasers.push_back(new Rebaser<ppc64>(mh));
+ }
+ else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
+ fRebasers.push_back(new Rebaser<x86>(mh));
+ }
+ else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_X86_64)) {
+ fRebasers.push_back(new Rebaser<x86_64>(mh));
+ }
+ else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_ARM)) {
+ fRebasers.push_back(new Rebaser<arm>(mh));
+ }
+ else {
+ throw "unknown file format";
+ }
+ }
+ catch (const char* msg) {
+ fprintf(stderr, "rebase warning: %s for %s\n", msg, path);
+ }
+ }
+
+ fMappingAddress = p;
+ fFileSize = stat_buf.st_size;
+}
+
+
+MultiArchRebaser::~MultiArchRebaser()
+{
+ ::munmap(fMappingAddress, fFileSize);
+}
+
+void MultiArchRebaser::commit()
+{
+ ::msync(fMappingAddress, fFileSize, MS_ASYNC);
+}
+
+
+
+template <typename A>
+Rebaser<A>::Rebaser(const void* machHeader)
+ : fHeader((const macho_header<P>*)machHeader)
+{
+ switch ( fHeader->filetype() ) {
+ case MH_DYLIB:
+ if ( (fHeader->flags() & MH_SPLIT_SEGS) != 0 )
+ throw "split-seg dylibs cannot be rebased";
+ break;
+ case MH_BUNDLE:
+ break;
+ default:
+ throw "file is not a dylib or bundle";
+ }
+
+}
+
+template <> cpu_type_t Rebaser<ppc>::getArchitecture() const { return CPU_TYPE_POWERPC; }
+template <> cpu_type_t Rebaser<ppc64>::getArchitecture() const { return CPU_TYPE_POWERPC64; }
+template <> cpu_type_t Rebaser<x86>::getArchitecture() const { return CPU_TYPE_I386; }
+template <> cpu_type_t Rebaser<x86_64>::getArchitecture() const { return CPU_TYPE_X86_64; }
+template <> cpu_type_t Rebaser<arm>::getArchitecture() const { return CPU_TYPE_ARM; }
+
+template <typename A>
+uint64_t Rebaser<A>::getBaseAddress() const
+{
+ uint64_t lowestSegmentAddress = LLONG_MAX;
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+ if ( segCmd->vmaddr() < lowestSegmentAddress ) {
+ lowestSegmentAddress = segCmd->vmaddr();
+ }
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+ return lowestSegmentAddress;
+}
+
+template <typename A>
+uint64_t Rebaser<A>::getVMSize() const
+{
+ const macho_segment_command<P>* highestSegmentCmd = NULL;
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+ if ( (highestSegmentCmd == NULL) || (segCmd->vmaddr() > highestSegmentCmd->vmaddr()) ) {
+ highestSegmentCmd = segCmd;
+ }
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+
+ return ((highestSegmentCmd->vmaddr() + highestSegmentCmd->vmsize() - this->getBaseAddress() + 4095) & (-4096));
+}
+
+
+template <typename A>
+void Rebaser<A>::setBaseAddress(uint64_t addr)
+{
+ // calculate slide
+ fSlide = addr - this->getBaseAddress();
+
+ // compute base address for relocations
+ this->setRelocBase();
+
+ // build cache of section index to section
+ this->buildSectionTable();
+
+ // update load commands
+ this->adjustLoadCommands();
+
+ // update symbol table
+ this->adjustSymbolTable();
+
+ // update writable segments that have internal pointers
+ this->adjustDATA();
+}
+
+template <typename A>
+void Rebaser<A>::adjustLoadCommands()
+{
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch ( cmd->cmd() ) {
+ case LC_ID_DYLIB:
+ if ( (fHeader->flags() & MH_PREBOUND) != 0 ) {
+ // clear timestamp so that any prebound clients are invalidated
+ macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
+ dylib->set_timestamp(1);
+ }
+ break;
+ case LC_LOAD_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ case LC_REEXPORT_DYLIB:
+ case LC_LOAD_UPWARD_DYLIB:
+ if ( (fHeader->flags() & MH_PREBOUND) != 0 ) {
+ // clear expected timestamps so that this image will load with invalid prebinding
+ macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
+ dylib->set_timestamp(2);
+ }
+ break;
+ case macho_routines_command<P>::CMD:
+ // update -init command
+ {
+ macho_routines_command<P>* routines = (macho_routines_command<P>*)cmd;
+ routines->set_init_address(routines->init_address() + fSlide);
+ }
+ break;
+ case macho_segment_command<P>::CMD:
+ // update segment commands
+ {
+ macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
+ seg->set_vmaddr(seg->vmaddr() + fSlide);
+ macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
+ macho_section<P>* const sectionsEnd = §ionsStart[seg->nsects()];
+ for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+ sect->set_addr(sect->addr() + fSlide);
+ }
+ }
+ break;
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+}
+
+
+template <typename A>
+void Rebaser<A>::buildSectionTable()
+{
+ // build vector of sections
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
+ vmmap mapping;
+ mapping.vmaddr = seg->vmaddr();
+ mapping.vmsize = seg->vmsize();
+ mapping.fileoff = seg->fileoff();
+ fVMMApping.push_back(mapping);
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+}
+
+
+template <typename A>
+void Rebaser<A>::adjustSymbolTable()
+{
+ const macho_dysymtab_command<P>* dysymtab = NULL;
+ macho_nlist<P>* symbolTable = NULL;
+ const char* strings = NULL;
+
+ // get symbol table info
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch (cmd->cmd()) {
+ case LC_SYMTAB:
+ {
+ const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
+ symbolTable = (macho_nlist<P>*)(((uint8_t*)fHeader) + symtab->symoff());
+ strings = (char*)(((uint8_t*)fHeader) + symtab->stroff());
+ }
+ break;
+ case LC_DYSYMTAB:
+ dysymtab = (macho_dysymtab_command<P>*)cmd;
+ break;
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+
+ // walk all exports and slide their n_value
+ macho_nlist<P>* lastExport = &symbolTable[dysymtab->iextdefsym()+dysymtab->nextdefsym()];
+ for (macho_nlist<P>* entry = &symbolTable[dysymtab->iextdefsym()]; entry < lastExport; ++entry) {
+ if ( (entry->n_type() & N_TYPE) == N_SECT )
+ entry->set_n_value(entry->n_value() + fSlide);
+ }
+
+ // walk all local symbols and slide their n_value
+ macho_nlist<P>* lastLocal = &symbolTable[dysymtab->ilocalsym()+dysymtab->nlocalsym()];
+ for (macho_nlist<P>* entry = &symbolTable[dysymtab->ilocalsym()]; entry < lastLocal; ++entry) {
+ if ( ((entry->n_type() & N_STAB) == 0) && ((entry->n_type() & N_TYPE) == N_SECT) ) {
+ entry->set_n_value(entry->n_value() + fSlide);
+ }
+ else if ( entry->n_type() & N_STAB ) {
+ // some stabs need to be slid too
+ switch ( entry->n_type() ) {
+ case N_FUN:
+ // don't slide end-of-function FUN which is FUN with no string
+ if ( (entry->n_strx() == 0) || (strings[entry->n_strx()] == '\0') )
+ break;
+ case N_BNSYM:
+ case N_STSYM:
+ case N_LCSYM:
+ entry->set_n_value(entry->n_value() + fSlide);
+ break;
+ }
+ }
+ }
+
+ // FIXME ¥¥¥ adjust dylib_module if it exists
+}
+
+static uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end)
+{
+ uint64_t result = 0;
+ int bit = 0;
+ do {
+ if (p == end)
+ throwf("malformed uleb128");
+
+ uint64_t slice = *p & 0x7f;
+
+ if (bit >= 64 || slice << bit >> bit != slice)
+ throwf("uleb128 too big");
+ else {
+ result |= (slice << bit);
+ bit += 7;
+ }
+ }
+ while (*p++ & 0x80);
+ return result;
+}
+
+template <typename A>
+void Rebaser<A>::rebaseAt(int segIndex, uint64_t offset, uint8_t type)
+{
+ //fprintf(stderr, "rebaseAt(seg=%d, offset=0x%08llX, type=%d\n", segIndex, offset, type);
+ static int lastSegIndex = -1;
+ static uint8_t* lastSegMappedStart = NULL;
+ if ( segIndex != lastSegIndex ) {
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ int segCount = 0;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ if ( segIndex == segCount ) {
+ const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
+ lastSegMappedStart = (uint8_t*)fHeader + seg->fileoff();
+ lastSegIndex = segCount;
+ break;
+ }
+ ++segCount;
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+ }
+
+ pint_t* locationToFix = (pint_t*)(lastSegMappedStart+offset);
+ uint32_t* locationToFix32 = (uint32_t*)(lastSegMappedStart+offset);
+ switch (type) {
+ case REBASE_TYPE_POINTER:
+ P::setP(*locationToFix, A::P::getP(*locationToFix) + fSlide);
+ break;
+ case REBASE_TYPE_TEXT_ABSOLUTE32:
+ E::set32(*locationToFix32, E::get32(*locationToFix32) + fSlide);
+ break;
+ default:
+ throwf("bad rebase type %d", type);
+ }
+}
+
+
+template <typename A>
+void Rebaser<A>::adjustDATA()
+{
+ const macho_dysymtab_command<P>* dysymtab = NULL;
+ const macho_dyld_info_command<P>* dyldInfo = NULL;
+
+ // get symbol table info
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch (cmd->cmd()) {
+ case LC_DYSYMTAB:
+ dysymtab = (macho_dysymtab_command<P>*)cmd;
+ break;
+ case LC_DYLD_INFO:
+ case LC_DYLD_INFO_ONLY:
+ dyldInfo = (macho_dyld_info_command<P>*)cmd;
+ break;
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+
+ // use new encoding of rebase info if present
+ if ( dyldInfo != NULL ) {
+ if ( dyldInfo->rebase_size() != 0 ) {
+ const uint8_t* p = (uint8_t*)fHeader + dyldInfo->rebase_off();
+ const uint8_t* end = &p[dyldInfo->rebase_size()];
+
+ uint8_t type = 0;
+ uint64_t offset = 0;
+ uint32_t count;
+ uint32_t skip;
+ int segIndex;
+ bool done = false;
+ while ( !done && (p < end) ) {
+ uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
+ uint8_t opcode = *p & REBASE_OPCODE_MASK;
+ ++p;
+ switch (opcode) {
+ case REBASE_OPCODE_DONE:
+ done = true;
+ break;
+ case REBASE_OPCODE_SET_TYPE_IMM:
+ type = immediate;
+ break;
+ case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ segIndex = immediate;
+ offset = read_uleb128(p, end);
+ break;
+ case REBASE_OPCODE_ADD_ADDR_ULEB:
+ offset += read_uleb128(p, end);
+ break;
+ case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+ offset += immediate*sizeof(pint_t);
+ break;
+ case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+ for (int i=0; i < immediate; ++i) {
+ rebaseAt(segIndex, offset, type);
+ offset += sizeof(pint_t);
+ }
+ break;
+ case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+ count = read_uleb128(p, end);
+ for (uint32_t i=0; i < count; ++i) {
+ rebaseAt(segIndex, offset, type);
+ offset += sizeof(pint_t);
+ }
+ break;
+ case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+ rebaseAt(segIndex, offset, type);
+ offset += read_uleb128(p, end) + sizeof(pint_t);
+ break;
+ case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
+ count = read_uleb128(p, end);
+ skip = read_uleb128(p, end);
+ for (uint32_t i=0; i < count; ++i) {
+ rebaseAt(segIndex, offset, type);
+ offset += skip + sizeof(pint_t);
+ }
+ break;
+ default:
+ throwf("bad rebase opcode %d", *p);
+ }
+ }
+
+
+
+ }
+ }
+ else {
+ // walk all local relocations and slide every pointer
+ const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(((uint8_t*)fHeader) + dysymtab->locreloff());
+ const macho_relocation_info<P>* const relocsEnd = &relocsStart[dysymtab->nlocrel()];
+ for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
+ this->doLocalRelocation(reloc);
+ }
+
+ // walk non-lazy-pointers and slide the ones that are LOCAL
+ cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
+ const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
+ const macho_section<P>* const sectionsEnd = §ionsStart[seg->nsects()];
+ const uint32_t* const indirectTable = (uint32_t*)(((uint8_t*)fHeader) + dysymtab->indirectsymoff());
+ for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+ if ( (sect->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) {
+ const uint32_t indirectTableOffset = sect->reserved1();
+ uint32_t pointerCount = sect->size() / sizeof(pint_t);
+ pint_t* nonLazyPointer = (pint_t*)(((uint8_t*)fHeader) + sect->offset());
+ for (uint32_t i=0; i < pointerCount; ++i, ++nonLazyPointer) {
+ if ( E::get32(indirectTable[indirectTableOffset + i]) == INDIRECT_SYMBOL_LOCAL ) {
+ P::setP(*nonLazyPointer, A::P::getP(*nonLazyPointer) + fSlide);
+ }
+ }
+ }
+ }
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+ }
+}
+
+
+template <typename A>
+typename A::P::uint_t* Rebaser<A>::mappedAddressForVMAddress(uint32_t vmaddress)
+{
+ for(typename std::vector<vmmap>::iterator it = fVMMApping.begin(); it != fVMMApping.end(); ++it) {
+ //fprintf(stderr, "vmaddr=0x%08lX, vmsize=0x%08lX\n", it->vmaddr, it->vmsize);
+ if ( (vmaddress >= it->vmaddr) && (vmaddress < (it->vmaddr+it->vmsize)) ) {
+ return (pint_t*)((vmaddress - it->vmaddr) + it->fileoff + (uint8_t*)fHeader);
+ }
+ }
+ throwf("reloc address 0x%08X not found", vmaddress);
+}
+
+
+template <>
+void Rebaser<x86_64>::doLocalRelocation(const macho_relocation_info<x86_64::P>* reloc)
+{
+ if ( reloc->r_type() == X86_64_RELOC_UNSIGNED ) {
+ pint_t* addr = mappedAddressForVMAddress(reloc->r_address() + fOrignalVMRelocBaseAddress);
+ P::setP(*addr, P::getP(*addr) + fSlide);
+ }
+ else {
+ throw "invalid relocation type";
+ }
+}
+
+template <>
+void Rebaser<ppc>::doLocalRelocation(const macho_relocation_info<P>* reloc)
+{
+ if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+ if ( reloc->r_type() == GENERIC_RELOC_VANILLA ) {
+ pint_t* addr = mappedAddressForVMAddress(reloc->r_address() + fOrignalVMRelocBaseAddress);
+ P::setP(*addr, P::getP(*addr) + fSlide);
+ }
+ }
+ else {
+ throw "cannot rebase final linked image with scattered relocations";
+ }
+}
+
+template <>
+void Rebaser<x86>::doLocalRelocation(const macho_relocation_info<P>* reloc)
+{
+ if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+ if ( reloc->r_type() == GENERIC_RELOC_VANILLA ) {
+ pint_t* addr = mappedAddressForVMAddress(reloc->r_address() + fOrignalVMRelocBaseAddress);
+ P::setP(*addr, P::getP(*addr) + fSlide);
+ }
+ }
+ else {
+ macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
+ if ( sreloc->r_type() == GENERIC_RELOC_PB_LA_PTR ) {
+ sreloc->set_r_value( sreloc->r_value() + fSlide );
+ }
+ else {
+ throw "cannot rebase final linked image with scattered relocations";
+ }
+ }
+}
+
+#if SUPPORT_ARCH_arm_any
+template <>
+void Rebaser<arm>::doLocalRelocation(const macho_relocation_info<P>* reloc)
+{
+ if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+ if ( reloc->r_type() == ARM_RELOC_VANILLA ) {
+ pint_t* addr = mappedAddressForVMAddress(reloc->r_address() + fOrignalVMRelocBaseAddress);
+ P::setP(*addr, P::getP(*addr) + fSlide);
+ }
+ }
+ else {
+ macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
+ if ( sreloc->r_type() == ARM_RELOC_PB_LA_PTR ) {
+ sreloc->set_r_value( sreloc->r_value() + fSlide );
+ }
+ else {
+ throw "cannot rebase final linked image with scattered relocations";
+ }
+ }
+}
+#endif
+
+template <typename A>
+void Rebaser<A>::doLocalRelocation(const macho_relocation_info<P>* reloc)
+{
+ if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+ if ( reloc->r_type() == GENERIC_RELOC_VANILLA ) {
+ pint_t* addr = mappedAddressForVMAddress(reloc->r_address() + fOrignalVMRelocBaseAddress);
+ P::setP(*addr, P::getP(*addr) + fSlide);
+ }
+ }
+ else {
+ throw "cannot rebase final linked image with scattered relocations";
+ }
+}
+
+
+template <typename A>
+void Rebaser<A>::setRelocBase()
+{
+ // reloc addresses are from the start of the mapped file (base address)
+ fOrignalVMRelocBaseAddress = this->getBaseAddress();
+ //fprintf(stderr, "fOrignalVMRelocBaseAddress=0x%08X\n", fOrignalVMRelocBaseAddress);
+}
+
+template <>
+void Rebaser<ppc64>::setRelocBase()
+{
+ // reloc addresses either:
+ // 1) from the base address if no writable segment is > 4GB from base address
+ // 2) from start of first writable segment
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+ if ( segCmd->initprot() & VM_PROT_WRITE ) {
+ if ( (segCmd->vmaddr() + segCmd->vmsize() - this->getBaseAddress()) > 0x100000000ULL ) {
+ // found writable segment with address > 4GB past base address
+ fOrignalVMRelocBaseAddress = segCmd->vmaddr();
+ return;
+ }
+ }
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+ // just use base address
+ fOrignalVMRelocBaseAddress = this->getBaseAddress();
+}
+
+template <>
+void Rebaser<x86_64>::setRelocBase()
+{
+ // reloc addresses are always based from the start of the first writable segment
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+ if ( segCmd->initprot() & VM_PROT_WRITE ) {
+ fOrignalVMRelocBaseAddress = segCmd->vmaddr();
+ return;
+ }
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+ throw "no writable segment";
+}
+
+
+static void copyFile(const char* srcFile, const char* dstFile)
+{
+ // open files
+ int src = open(srcFile, O_RDONLY);
+ if ( src == -1 )
+ throwf("can't open file %s, errno=%d", srcFile, errno);
+ struct stat stat_buf;
+ if ( fstat(src, &stat_buf) == -1)
+ throwf("can't stat open file %s, errno=%d", srcFile, errno);
+
+ // create new file with all same permissions to hold copy of dylib
+ ::unlink(dstFile);
+ int dst = open(dstFile, O_CREAT | O_RDWR | O_TRUNC, stat_buf.st_mode);
+ if ( dst == -1 )
+ throwf("can't create temp file %s, errnor=%d", dstFile, errno);
+
+ // mark source as "don't cache"
+ (void)fcntl(src, F_NOCACHE, 1);
+ // we want to cache the dst because we are about to map it in and modify it
+
+ // copy permission bits
+ if ( chmod(dstFile, stat_buf.st_mode & 07777) == -1 )
+ throwf("can't chmod temp file %s, errno=%d", dstFile, errno);
+ if ( chown(dstFile, stat_buf.st_uid, stat_buf.st_gid) == -1)
+ throwf("can't chown temp file %s, errno=%d", dstFile, errno);
+
+ // copy contents
+ ssize_t len;
+ const uint32_t kBufferSize = 128*1024;
+ static uint8_t* buffer = NULL;
+ if ( buffer == NULL ) {
+ vm_address_t addr = 0;
+ if ( vm_allocate(mach_task_self(), &addr, kBufferSize, true /*find range*/) == KERN_SUCCESS )
+ buffer = (uint8_t*)addr;
+ else
+ throw "can't allcoate copy buffer";
+ }
+ while ( (len = read(src, buffer, kBufferSize)) > 0 ) {
+ if ( write(dst, buffer, len) == -1 )
+ throwf("write failure copying feil %s, errno=%d", dstFile, errno);
+ }
+
+ // close files
+ int result1 = close(dst);
+ int result2 = close(src);
+ if ( (result1 != 0) || (result2 != 0) )
+ throw "can't close file";
+}
+
+
+// scan dylibs and collect size info
+// calculate new base address for each dylib
+// rebase each file
+// copy to temp and mmap
+// update content
+// unmap/flush
+// rename
+
+struct archInfo {
+ cpu_type_t arch;
+ uint64_t vmSize;
+ uint64_t orgBase;
+ uint64_t newBase;
+};
+
+struct fileInfo
+{
+ fileInfo(const char* p) : path(p) {}
+
+ const char* path;
+ std::vector<archInfo> archs;
+};
+
+//
+// add archInfos to fileInfo for every slice of a fat file
+// for ppc, there may be duplicate architectures (with different sub-types)
+//
+static void setSizes(fileInfo& info, const std::set<cpu_type_t>& onlyArchs)
+{
+ const MultiArchRebaser mar(info.path);
+ const std::vector<AbstractRebaser*>& rebasers = mar.getArchs();
+ for(std::set<cpu_type_t>::iterator ait=onlyArchs.begin(); ait != onlyArchs.end(); ++ait) {
+ for(std::vector<AbstractRebaser*>::const_iterator rit=rebasers.begin(); rit != rebasers.end(); ++rit) {
+ AbstractRebaser* rebaser = *rit;
+ if ( rebaser->getArchitecture() == *ait ) {
+ archInfo ai;
+ ai.arch = *ait;
+ ai.vmSize = rebaser->getVMSize();
+ ai.orgBase = rebaser->getBaseAddress();
+ ai.newBase = 0;
+ //fprintf(stderr, "base=0x%llX, size=0x%llX\n", ai.orgBase, ai.vmSize);
+ info.archs.push_back(ai);
+ }
+ }
+ }
+}
+
+static const char* nameForArch(cpu_type_t arch)
+{
+ switch( arch ) {
+ case CPU_TYPE_POWERPC:
+ return "ppc";
+ case CPU_TYPE_POWERPC64:
+ return "ppca64";
+ case CPU_TYPE_I386:
+ return "i386";
+ case CPU_TYPE_X86_64:
+ return "x86_64";
+ case CPU_TYPE_ARM:
+ return "arm";
+ }
+ return "unknown";
+}
+
+static void rebase(const fileInfo& info)
+{
+ // generate temp file name
+ char realFilePath[PATH_MAX];
+ if ( realpath(info.path, realFilePath) == NULL ) {
+ throwf("realpath() failed on %s, errno=%d", info.path, errno);
+ }
+ const char* tempPath;
+ asprintf((char**)&tempPath, "%s_rebase", realFilePath);
+
+ // copy whole file to temp file
+ copyFile(info.path, tempPath);
+
+ try {
+ // rebase temp file
+ MultiArchRebaser mar(tempPath, true);
+ const std::vector<AbstractRebaser*>& rebasers = mar.getArchs();
+ for(std::vector<archInfo>::const_iterator fait=info.archs.begin(); fait != info.archs.end(); ++fait) {
+ for(std::vector<AbstractRebaser*>::const_iterator rit=rebasers.begin(); rit != rebasers.end(); ++rit) {
+ if ( (*rit)->getArchitecture() == fait->arch ) {
+ (*rit)->setBaseAddress(fait->newBase);
+ if ( verbose )
+ printf("%8s 0x%0llX -> 0x%0llX %s\n", nameForArch(fait->arch), fait->orgBase, fait->newBase, info.path);
+ }
+ }
+ }
+
+ // flush temp file out to disk
+ mar.commit();
+
+ // rename
+ int result = rename(tempPath, info.path);
+ if ( result != 0 ) {
+ throwf("can't swap temporary rebased file: rename(%s,%s) returned errno=%d", tempPath, info.path, errno);
+ }
+
+ // make sure every really gets out to disk
+ ::sync();
+ }
+ catch (const char* msg) {
+ // delete temp file
+ ::unlink(tempPath);
+
+ // throw exception with file name added
+ const char* newMsg;
+ asprintf((char**)&newMsg, "%s for file %s", msg, info.path);
+ throw newMsg;
+ }
+}
+
+static uint64_t totalVMSize(cpu_type_t arch, std::vector<fileInfo>& files)
+{
+ uint64_t totalSize = 0;
+ for(std::vector<fileInfo>::iterator fit=files.begin(); fit != files.end(); ++fit) {
+ fileInfo& fi = *fit;
+ for(std::vector<archInfo>::iterator fait=fi.archs.begin(); fait != fi.archs.end(); ++fait) {
+ if ( fait->arch == arch )
+ totalSize += fait->vmSize;
+ }
+ }
+ return totalSize;
+}
+
+static uint64_t startAddress(cpu_type_t arch, std::vector<fileInfo>& files, uint64_t lowAddress, uint64_t highAddress)
+{
+ if ( lowAddress != 0 )
+ return lowAddress;
+ else if ( highAddress != 0 ) {
+ uint64_t totalSize = totalVMSize(arch, files);
+ if ( highAddress < totalSize )
+ throwf("cannot use -high_address 0x%X because total size of images is greater: 0x%X", highAddress, totalSize);
+ return highAddress - totalSize;
+ }
+ else {
+ if ( (arch == CPU_TYPE_I386) || (arch == CPU_TYPE_POWERPC) ) {
+ // place dylibs below dyld
+ uint64_t topAddr = 0x8FE00000;
+ uint64_t totalSize = totalVMSize(arch, files);
+ if ( totalSize > topAddr )
+ throwf("total size of images (0x%X) does not fit below 0x8FE00000", totalSize);
+ return topAddr - totalSize;
+ }
+ else if ( arch == CPU_TYPE_POWERPC64 ) {
+ return 0x200000000ULL;
+ }
+ else if ( arch == CPU_TYPE_X86_64 ) {
+ return 0x200000000ULL;
+ }
+ else if ( arch == CPU_TYPE_ARM ) {
+ // place dylibs below dyld
+ uint64_t topAddr = 0x2FE00000;
+ uint64_t totalSize = totalVMSize(arch, files);
+ if ( totalSize > topAddr )
+ throwf("total size of images (0x%X) does not fit below 0x2FE00000", totalSize);
+ return topAddr - totalSize;
+ }
+ else
+ throw "unknown architecture";
+ }
+}
+
+static void usage()
+{
+ fprintf(stderr, "rebase [-low_address] [-high_address] [-v] [-arch <arch>] files...\n");
+}
+
+
+int main(int argc, const char* argv[])
+{
+ std::vector<fileInfo> files;
+ std::set<cpu_type_t> onlyArchs;
+ uint64_t lowAddress = 0;
+ uint64_t highAddress = 0;
+
+ try {
+ // parse command line options
+ char* endptr;
+ for(int i=1; i < argc; ++i) {
+ const char* arg = argv[i];
+ if ( arg[0] == '-' ) {
+ if ( strcmp(arg, "-v") == 0 ) {
+ verbose = true;
+ }
+ else if ( strcmp(arg, "-low_address") == 0 ) {
+ lowAddress = strtoull(argv[++i], &endptr, 16);
+ }
+ else if ( strcmp(arg, "-high_address") == 0 ) {
+ highAddress = strtoull(argv[++i], &endptr, 16);
+ }
+ else if ( strcmp(arg, "-arch") == 0 ) {
+ const char* archName = argv[++i];
+ if ( archName == NULL )
+ throw "-arch missing architecture name";
+ bool found = false;
+ for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+ if ( strcmp(t->archName,archName) == 0 ) {
+ onlyArchs.insert(t->cpuType);
+ found = true;
+ }
+ }
+ if ( !found )
+ throwf("unknown architecture %s", archName);
+ }
+ else {
+ usage();
+ throwf("unknown option: %s\n", arg);
+ }
+ }
+ else {
+ files.push_back(fileInfo(arg));
+ }
+ }
+
+ if ( files.size() == 0 )
+ throw "no files specified";
+
+ // use all architectures if no restrictions specified
+ if ( onlyArchs.size() == 0 ) {
+ onlyArchs.insert(CPU_TYPE_POWERPC);
+ onlyArchs.insert(CPU_TYPE_POWERPC64);
+ onlyArchs.insert(CPU_TYPE_I386);
+ onlyArchs.insert(CPU_TYPE_X86_64);
+ onlyArchs.insert(CPU_TYPE_ARM);
+ }
+
+ // scan files and collect sizes
+ for(std::vector<fileInfo>::iterator it=files.begin(); it != files.end(); ++it) {
+ setSizes(*it, onlyArchs);
+ }
+
+ // assign new base address for each arch
+ for(std::set<cpu_type_t>::iterator ait=onlyArchs.begin(); ait != onlyArchs.end(); ++ait) {
+ cpu_type_t arch = *ait;
+ uint64_t baseAddress = startAddress(arch, files, lowAddress, highAddress);
+ for(std::vector<fileInfo>::iterator fit=files.begin(); fit != files.end(); ++fit) {
+ fileInfo& fi = *fit;
+ for(std::vector<archInfo>::iterator fait=fi.archs.begin(); fait != fi.archs.end(); ++fait) {
+ if ( fait->arch == arch ) {
+ fait->newBase = baseAddress;
+ baseAddress += fait->vmSize;
+ baseAddress = (baseAddress + 4095) & (-4096); // page align
+ }
+ }
+ }
+ }
+
+ // rebase each file if it contains something rebaseable
+ for(std::vector<fileInfo>::iterator it=files.begin(); it != files.end(); ++it) {
+ fileInfo& fi = *it;
+ if ( fi.archs.size() > 0 )
+ rebase(fi);
+ }
+
+ }
+ catch (const char* msg) {
+ fprintf(stderr, "rebase failed: %s\n", msg);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <vector>
+#include <set>
+#include <ext/hash_set>
+
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+
+
+ __attribute__((noreturn))
+void throwf(const char* format, ...)
+{
+ va_list list;
+ char* p;
+ va_start(list, format);
+ vasprintf(&p, format, list);
+ va_end(list);
+
+ const char* t = p;
+ throw t;
+}
+
+
+template <typename A>
+class UnwindPrinter
+{
+public:
+ static bool validFile(const uint8_t* fileContent);
+ static UnwindPrinter<A>* make(const uint8_t* fileContent, uint32_t fileLength,
+ const char* path, bool showFunctionNames)
+ { return new UnwindPrinter<A>(fileContent, fileLength,
+ path, showFunctionNames); }
+ virtual ~UnwindPrinter() {}
+
+
+private:
+ typedef typename A::P P;
+ typedef typename A::P::E E;
+ typedef typename A::P::uint_t pint_t;
+
+ class CStringEquals
+ {
+ public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+ };
+
+ typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> StringSet;
+
+ UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength,
+ const char* path, bool showFunctionNames);
+ bool findUnwindSection();
+ void printUnwindSection(bool showFunctionNames);
+ void printObjectUnwindSection(bool showFunctionNames);
+ void getSymbolTableInfo();
+ const char* functionName(pint_t addr, uint32_t* offset=NULL);
+ const char* personalityName(const macho_relocation_info<typename A::P>* reloc);
+ bool hasExernReloc(uint64_t sectionOffset, const char** personalityStr, pint_t* addr=NULL);
+
+ static const char* archName();
+ static void decode(uint32_t encoding, const uint8_t* funcStart, char* str);
+
+ const char* fPath;
+ const macho_header<P>* fHeader;
+ uint64_t fLength;
+ const macho_section<P>* fUnwindSection;
+ const char* fStrings;
+ const char* fStringsEnd;
+ const macho_nlist<P>* fSymbols;
+ uint32_t fSymbolCount;
+ pint_t fMachHeaderAddress;
+};
+
+
+template <> const char* UnwindPrinter<x86>::archName() { return "i386"; }
+template <> const char* UnwindPrinter<x86_64>::archName() { return "x86_64"; }
+template <> const char* UnwindPrinter<arm>::archName() { return "arm"; }
+
+
+template <>
+bool UnwindPrinter<x86>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return false;
+ if ( header->cputype() != CPU_TYPE_I386 )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ case MH_OBJECT:
+ return true;
+ }
+ return false;
+}
+
+template <>
+bool UnwindPrinter<x86_64>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_X86_64 )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ case MH_OBJECT:
+ return true;
+ }
+ return false;
+}
+
+
+template <typename A>
+UnwindPrinter<A>::UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool showFunctionNames)
+ : fHeader(NULL), fLength(fileLength), fUnwindSection(NULL),
+ fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fMachHeaderAddress(0)
+{
+ // sanity check
+ if ( ! validFile(fileContent) )
+ throw "not a mach-o file that can be checked";
+
+ fPath = strdup(path);
+ fHeader = (const macho_header<P>*)fileContent;
+
+ getSymbolTableInfo();
+
+ if ( findUnwindSection() ) {
+ if ( fHeader->filetype() == MH_OBJECT )
+ printObjectUnwindSection(showFunctionNames);
+ else
+ printUnwindSection(showFunctionNames);
+ }
+}
+
+
+template <typename A>
+void UnwindPrinter<A>::getSymbolTableInfo()
+{
+ const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
+ const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ uint32_t size = cmd->cmdsize();
+ const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
+ if ( endOfCmd > endOfLoadCommands )
+ throwf("load command #%d extends beyond the end of the load commands", i);
+ if ( endOfCmd > endOfFile )
+ throwf("load command #%d extends beyond the end of the file", i);
+ if ( cmd->cmd() == LC_SYMTAB) {
+ const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
+ fSymbolCount = symtab->nsyms();
+ fSymbols = (const macho_nlist<P>*)((char*)fHeader + symtab->symoff());
+ fStrings = (char*)fHeader + symtab->stroff();
+ fStringsEnd = fStrings + symtab->strsize();
+ }
+ cmd = (const macho_load_command<P>*)endOfCmd;
+ }
+}
+
+template <typename A>
+const char* UnwindPrinter<A>::functionName(pint_t addr, uint32_t* offset)
+{
+ const macho_nlist<P>* closestSymbol = NULL;
+ if ( offset != NULL )
+ *offset = 0;
+ for (uint32_t i=0; i < fSymbolCount; ++i) {
+ uint8_t type = fSymbols[i].n_type();
+ if ( ((type & N_STAB) == 0) && ((type & N_TYPE) == N_SECT) ) {
+ if ( fSymbols[i].n_value() == addr ) {
+ const char* r = &fStrings[fSymbols[i].n_strx()];
+ //fprintf(stderr, "addr=0x%08llX, i=%u, n_type=0x%0X, r=%s\n", (long long)(fSymbols[i].n_value()), i, fSymbols[i].n_type(), r);
+ return r;
+ }
+ else if ( offset != NULL ) {
+ if ( closestSymbol == NULL ) {
+ if ( fSymbols[i].n_value() < addr )
+ closestSymbol = &fSymbols[i];
+ }
+ else {
+ if ( (fSymbols[i].n_value() < addr) && (fSymbols[i].n_value() > closestSymbol->n_value()) )
+ closestSymbol = &fSymbols[i];
+ }
+ }
+ }
+ }
+ if ( closestSymbol != NULL ) {
+ *offset = addr - closestSymbol->n_value();
+ return &fStrings[closestSymbol->n_strx()];
+ }
+ return "--anonymous function--";
+}
+
+
+
+template <typename A>
+bool UnwindPrinter<A>::findUnwindSection()
+{
+ const char* unwindSectionName = "__unwind_info";
+ const char* unwindSegmentName = "__TEXT";
+ if ( fHeader->filetype() == MH_OBJECT ) {
+ unwindSectionName = "__compact_unwind";
+ unwindSegmentName = "__LD";
+ }
+ const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
+ const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ uint32_t size = cmd->cmdsize();
+ const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
+ if ( endOfCmd > endOfLoadCommands )
+ throwf("load command #%d extends beyond the end of the load commands", i);
+ if ( endOfCmd > endOfFile )
+ throwf("load command #%d extends beyond the end of the file", i);
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+ const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+ const macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()];
+ for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+ if ( (strncmp(sect->sectname(), unwindSectionName, 16) == 0) && (strcmp(sect->segname(), unwindSegmentName) == 0) ) {
+ fUnwindSection = sect;
+ fMachHeaderAddress = segCmd->vmaddr();
+ return fUnwindSection;
+ }
+ }
+ }
+ cmd = (const macho_load_command<P>*)endOfCmd;
+ }
+ return false;
+}
+
+#define EXTRACT_BITS(value, mask) \
+ ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
+
+
+template <>
+void UnwindPrinter<x86_64>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
+{
+ *str = '\0';
+ switch ( encoding & UNWIND_X86_64_MODE_MASK ) {
+ case UNWIND_X86_64_MODE_RBP_FRAME:
+ {
+ uint32_t savedRegistersOffset = EXTRACT_BITS(encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
+ uint32_t savedRegistersLocations = EXTRACT_BITS(encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
+ if ( savedRegistersLocations == 0 ) {
+ strcpy(str, "rbp frame, no saved registers");
+ }
+ else {
+ sprintf(str, "rbp frame, at -%d:", savedRegistersOffset*8);
+ bool needComma = false;
+ for (int i=0; i < 5; ++i) {
+ if ( needComma )
+ strcat(str, ",");
+ else
+ needComma = true;
+ switch (savedRegistersLocations & 0x7) {
+ case UNWIND_X86_64_REG_NONE:
+ strcat(str, "-");
+ break;
+ case UNWIND_X86_64_REG_RBX:
+ strcat(str, "rbx");
+ break;
+ case UNWIND_X86_64_REG_R12:
+ strcat(str, "r12");
+ break;
+ case UNWIND_X86_64_REG_R13:
+ strcat(str, "r13");
+ break;
+ case UNWIND_X86_64_REG_R14:
+ strcat(str, "r14");
+ break;
+ case UNWIND_X86_64_REG_R15:
+ strcat(str, "r15");
+ break;
+ default:
+ strcat(str, "r?");
+ }
+ savedRegistersLocations = (savedRegistersLocations >> 3);
+ if ( savedRegistersLocations == 0 )
+ break;
+ }
+ }
+ }
+ break;
+ case UNWIND_X86_64_MODE_STACK_IMMD:
+ case UNWIND_X86_64_MODE_STACK_IND:
+ {
+ uint32_t stackSize = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+ uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
+ uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
+ if ( (encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_STACK_IND ) {
+ // stack size is encoded in subl $xxx,%esp instruction
+ uint32_t subl = x86_64::P::E::get32(*((uint32_t*)(funcStart+stackSize)));
+ sprintf(str, "stack size=0x%08X, ", subl + 8*stackAdjust);
+ }
+ else {
+ sprintf(str, "stack size=%d, ", stackSize*8);
+ }
+ if ( regCount == 0 ) {
+ strcat(str, "no registers saved");
+ }
+ else {
+ int permunreg[6];
+ switch ( regCount ) {
+ case 6:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ permunreg[5] = 0;
+ break;
+ case 5:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ break;
+ case 4:
+ permunreg[0] = permutation/60;
+ permutation -= (permunreg[0]*60);
+ permunreg[1] = permutation/12;
+ permutation -= (permunreg[1]*12);
+ permunreg[2] = permutation/3;
+ permutation -= (permunreg[2]*3);
+ permunreg[3] = permutation;
+ break;
+ case 3:
+ permunreg[0] = permutation/20;
+ permutation -= (permunreg[0]*20);
+ permunreg[1] = permutation/4;
+ permutation -= (permunreg[1]*4);
+ permunreg[2] = permutation;
+ break;
+ case 2:
+ permunreg[0] = permutation/5;
+ permutation -= (permunreg[0]*5);
+ permunreg[1] = permutation;
+ break;
+ case 1:
+ permunreg[0] = permutation;
+ break;
+ }
+ // renumber registers back to standard numbers
+ int registers[6];
+ bool used[7] = { false, false, false, false, false, false, false };
+ for (int i=0; i < regCount; ++i) {
+ int renum = 0;
+ for (int u=1; u < 7; ++u) {
+ if ( !used[u] ) {
+ if ( renum == permunreg[i] ) {
+ registers[i] = u;
+ used[u] = true;
+ break;
+ }
+ ++renum;
+ }
+ }
+ }
+ bool needComma = false;
+ for (int i=0; i < regCount; ++i) {
+ if ( needComma )
+ strcat(str, ",");
+ else
+ needComma = true;
+ switch ( registers[i] ) {
+ case UNWIND_X86_64_REG_RBX:
+ strcat(str, "rbx");
+ break;
+ case UNWIND_X86_64_REG_R12:
+ strcat(str, "r12");
+ break;
+ case UNWIND_X86_64_REG_R13:
+ strcat(str, "r13");
+ break;
+ case UNWIND_X86_64_REG_R14:
+ strcat(str, "r14");
+ break;
+ case UNWIND_X86_64_REG_R15:
+ strcat(str, "r15");
+ break;
+ case UNWIND_X86_64_REG_RBP:
+ strcat(str, "rbp");
+ break;
+ default:
+ strcat(str, "r??");
+ }
+ }
+ }
+ }
+ break;
+ case UNWIND_X86_64_MODE_DWARF:
+ sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_X86_64_DWARF_SECTION_OFFSET);
+ break;
+ default:
+ if ( encoding == 0 )
+ strcat(str, "no unwind information");
+ else
+ strcat(str, "tbd ");
+ }
+ if ( encoding & UNWIND_HAS_LSDA ) {
+ strcat(str, " LSDA");
+ }
+
+}
+
+template <>
+void UnwindPrinter<x86>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
+{
+ *str = '\0';
+ switch ( encoding & UNWIND_X86_MODE_MASK ) {
+ case UNWIND_X86_MODE_EBP_FRAME:
+ {
+ uint32_t savedRegistersOffset = EXTRACT_BITS(encoding, UNWIND_X86_EBP_FRAME_OFFSET);
+ uint32_t savedRegistersLocations = EXTRACT_BITS(encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
+ if ( savedRegistersLocations == 0 ) {
+ strcpy(str, "ebp frame, no saved registers");
+ }
+ else {
+ sprintf(str, "ebp frame, at -%d:", savedRegistersOffset*4);
+ bool needComma = false;
+ for (int i=0; i < 5; ++i) {
+ if ( needComma )
+ strcat(str, ",");
+ else
+ needComma = true;
+ switch (savedRegistersLocations & 0x7) {
+ case UNWIND_X86_REG_NONE:
+ strcat(str, "-");
+ break;
+ case UNWIND_X86_REG_EBX:
+ strcat(str, "ebx");
+ break;
+ case UNWIND_X86_REG_ECX:
+ strcat(str, "ecx");
+ break;
+ case UNWIND_X86_REG_EDX:
+ strcat(str, "edx");
+ break;
+ case UNWIND_X86_REG_EDI:
+ strcat(str, "edi");
+ break;
+ case UNWIND_X86_REG_ESI:
+ strcat(str, "esi");
+ break;
+ default:
+ strcat(str, "e??");
+ }
+ savedRegistersLocations = (savedRegistersLocations >> 3);
+ if ( savedRegistersLocations == 0 )
+ break;
+ }
+ }
+ }
+ break;
+ case UNWIND_X86_MODE_STACK_IMMD:
+ case UNWIND_X86_MODE_STACK_IND:
+ {
+ uint32_t stackSize = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
+ uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
+ uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
+ if ( (encoding & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_STACK_IND ) {
+ // stack size is encoded in subl $xxx,%esp instruction
+ uint32_t subl = x86::P::E::get32(*((uint32_t*)(funcStart+stackSize)));
+ sprintf(str, "stack size=0x%08X, ", subl+4*stackAdjust);
+ }
+ else {
+ sprintf(str, "stack size=%d, ", stackSize*4);
+ }
+ if ( regCount == 0 ) {
+ strcat(str, "no saved regs");
+ }
+ else {
+ int permunreg[6];
+ switch ( regCount ) {
+ case 6:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ permunreg[5] = 0;
+ break;
+ case 5:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ break;
+ case 4:
+ permunreg[0] = permutation/60;
+ permutation -= (permunreg[0]*60);
+ permunreg[1] = permutation/12;
+ permutation -= (permunreg[1]*12);
+ permunreg[2] = permutation/3;
+ permutation -= (permunreg[2]*3);
+ permunreg[3] = permutation;
+ break;
+ case 3:
+ permunreg[0] = permutation/20;
+ permutation -= (permunreg[0]*20);
+ permunreg[1] = permutation/4;
+ permutation -= (permunreg[1]*4);
+ permunreg[2] = permutation;
+ break;
+ case 2:
+ permunreg[0] = permutation/5;
+ permutation -= (permunreg[0]*5);
+ permunreg[1] = permutation;
+ break;
+ case 1:
+ permunreg[0] = permutation;
+ break;
+ }
+ // renumber registers back to standard numbers
+ int registers[6];
+ bool used[7] = { false, false, false, false, false, false, false };
+ for (int i=0; i < regCount; ++i) {
+ int renum = 0;
+ for (int u=1; u < 7; ++u) {
+ if ( !used[u] ) {
+ if ( renum == permunreg[i] ) {
+ registers[i] = u;
+ used[u] = true;
+ break;
+ }
+ ++renum;
+ }
+ }
+ }
+ bool needComma = false;
+ for (int i=0; i < regCount; ++i) {
+ if ( needComma )
+ strcat(str, ",");
+ else
+ needComma = true;
+ switch ( registers[i] ) {
+ case UNWIND_X86_REG_EBX:
+ strcat(str, "ebx");
+ break;
+ case UNWIND_X86_REG_ECX:
+ strcat(str, "ecx");
+ break;
+ case UNWIND_X86_REG_EDX:
+ strcat(str, "edx");
+ break;
+ case UNWIND_X86_REG_EDI:
+ strcat(str, "edi");
+ break;
+ case UNWIND_X86_REG_ESI:
+ strcat(str, "esi");
+ break;
+ case UNWIND_X86_REG_EBP:
+ strcat(str, "ebp");
+ break;
+ default:
+ strcat(str, "e??");
+ }
+ }
+ }
+ }
+ break;
+ case UNWIND_X86_MODE_DWARF:
+ sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_X86_DWARF_SECTION_OFFSET);
+ break;
+ default:
+ if ( encoding == 0 )
+ strcat(str, "no unwind information");
+ else
+ strcat(str, "tbd ");
+ }
+ if ( encoding & UNWIND_HAS_LSDA ) {
+ strcat(str, " LSDA");
+ }
+
+}
+
+
+
+template <>
+const char* UnwindPrinter<x86_64>::personalityName(const macho_relocation_info<x86_64::P>* reloc)
+{
+ //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+ //assert((reloc->r_type() == X86_64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
+ const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
+ return &fStrings[sym.n_strx()];
+}
+
+template <>
+const char* UnwindPrinter<x86>::personalityName(const macho_relocation_info<x86::P>* reloc)
+{
+ //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+ //assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section");
+ const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
+ return &fStrings[sym.n_strx()];
+}
+
+template <typename A>
+bool UnwindPrinter<A>::hasExernReloc(uint64_t sectionOffset, const char** personalityStr, pint_t* addr)
+{
+ const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((uint8_t*)fHeader + fUnwindSection->reloff());
+ const macho_relocation_info<P>* relocsEnd = &relocs[fUnwindSection->nreloc()];
+ for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
+ if ( reloc->r_extern() && (reloc->r_address() == sectionOffset) ) {
+ *personalityStr = this->personalityName(reloc);
+ if ( addr != NULL )
+ *addr = fSymbols[reloc->r_symbolnum()].n_value();
+ return true;
+ }
+ }
+ return false;
+}
+
+
+template <typename A>
+void UnwindPrinter<A>::printObjectUnwindSection(bool showFunctionNames)
+{
+ printf("Arch: %s, Section: __LD,__compact_unwind (size=0x%08llX, => %lld entries)\n",
+ archName(), fUnwindSection->size(), fUnwindSection->size() / sizeof(macho_compact_unwind_entry<P>));
+
+ const macho_compact_unwind_entry<P>* const entriesStart = (macho_compact_unwind_entry<P>*)((uint8_t*)fHeader + fUnwindSection->offset());
+ const macho_compact_unwind_entry<P>* const entriesEnd = (macho_compact_unwind_entry<P>*)((uint8_t*)fHeader + fUnwindSection->offset() + fUnwindSection->size());
+ for (const macho_compact_unwind_entry<P>* entry=entriesStart; entry < entriesEnd; ++entry) {
+ uint64_t entryAddress = ((char*)entry - (char*)entriesStart) + fUnwindSection->addr();
+ printf("0x%08llX:\n", entryAddress);
+ const char* functionNameStr;
+ pint_t funcAddress;
+ uint32_t offsetInFunction;
+ if ( hasExernReloc(((char*)entry-(char*)entriesStart)+macho_compact_unwind_entry<P>::codeStartFieldOffset(), &functionNameStr, &funcAddress) ) {
+ offsetInFunction = entry->codeStart();
+ }
+ else {
+ functionNameStr = this->functionName(entry->codeStart(), &offsetInFunction);
+ }
+ if ( offsetInFunction == 0 )
+ printf(" start: 0x%08llX %s\n", (uint64_t)funcAddress, functionNameStr);
+ else
+ printf(" start: 0x%08llX %s+0x%X\n", (uint64_t)funcAddress+offsetInFunction, functionNameStr, offsetInFunction);
+
+ printf(" end: 0x%08llX (len=0x%08X)\n", (uint64_t)(funcAddress+offsetInFunction+entry->codeLen()), entry->codeLen());
+
+ char encodingString[200];
+ this->decode(entry->compactUnwindInfo(), ((const uint8_t*)fHeader), encodingString);
+ printf(" unwind info: 0x%08X %s\n", entry->compactUnwindInfo(), encodingString);
+
+ const char* personalityNameStr;
+ if ( hasExernReloc(((char*)entry-(char*)entriesStart)+macho_compact_unwind_entry<P>::personalityFieldOffset(), &personalityNameStr) ) {
+ printf(" personality: %s\n", personalityNameStr);
+ }
+ else {
+ printf(" personality:\n");
+ }
+ if ( entry->lsda() == 0 ) {
+ printf(" lsda:\n");
+ }
+ else {
+ uint32_t lsdaOffset;
+ const char* lsdaName = this->functionName(entry->lsda(), &lsdaOffset);
+ if ( lsdaOffset == 0 )
+ printf(" lsda: 0x%08llX %s\n", (uint64_t)entry->lsda(), lsdaName);
+ else
+ printf(" lsda: 0x%08llX %s+0x%X\n", (uint64_t)entry->lsda(), lsdaName, lsdaOffset);
+ }
+ }
+
+}
+
+
+
+template <typename A>
+void UnwindPrinter<A>::printUnwindSection(bool showFunctionNames)
+{
+ const uint8_t* sectionContent = (uint8_t*)fHeader + fUnwindSection->offset();
+ macho_unwind_info_section_header<P>* sectionHeader = (macho_unwind_info_section_header<P>*)(sectionContent);
+
+ printf("Arch: %s, Section: __TEXT,__unwind_info (addr=0x%08llX, size=0x%08llX, fileOffset=0x%08X)\n",
+ archName(), fUnwindSection->addr(), fUnwindSection->size(), fUnwindSection->offset());
+ printf("\tversion=0x%08X\n", sectionHeader->version());
+ printf("\tcommonEncodingsArraySectionOffset=0x%08X\n", sectionHeader->commonEncodingsArraySectionOffset());
+ printf("\tcommonEncodingsArrayCount=0x%08X\n", sectionHeader->commonEncodingsArrayCount());
+ printf("\tpersonalityArraySectionOffset=0x%08X\n", sectionHeader->personalityArraySectionOffset());
+ printf("\tpersonalityArrayCount=0x%08X\n", sectionHeader->personalityArrayCount());
+ printf("\tindexSectionOffset=0x%08X\n", sectionHeader->indexSectionOffset());
+ printf("\tindexCount=0x%08X\n", sectionHeader->indexCount());
+ printf("\tcommon encodings: (count=%u)\n", sectionHeader->commonEncodingsArrayCount());
+ const uint32_t* commonEncodings = (uint32_t*)§ionContent[sectionHeader->commonEncodingsArraySectionOffset()];
+ for (uint32_t i=0; i < sectionHeader->commonEncodingsArrayCount(); ++i) {
+ printf("\t\tencoding[%3u]=0x%08X\n", i, A::P::E::get32(commonEncodings[i]));
+ }
+ printf("\tpersonalities: (count=%u)\n", sectionHeader->personalityArrayCount());
+ const uint32_t* personalityArray = (uint32_t*)§ionContent[sectionHeader->personalityArraySectionOffset()];
+ for (uint32_t i=0; i < sectionHeader->personalityArrayCount(); ++i) {
+ printf("\t\t[%2u]=0x%08X\n", i+1, A::P::E::get32(personalityArray[i]));
+ }
+ printf("\tfirst level index: (count=%u)\n", sectionHeader->indexCount());
+ macho_unwind_info_section_header_index_entry<P>* indexes = (macho_unwind_info_section_header_index_entry<P>*)§ionContent[sectionHeader->indexSectionOffset()];
+ for (uint32_t i=0; i < sectionHeader->indexCount(); ++i) {
+ printf("\t\t[%2u] funcOffset=0x%08X, pageOffset=0x%08X, lsdaOffset=0x%08X\n",
+ i, indexes[i].functionOffset(), indexes[i].secondLevelPagesSectionOffset(), indexes[i].lsdaIndexArraySectionOffset());
+ }
+ uint32_t lsdaIndexArraySectionOffset = indexes[0].lsdaIndexArraySectionOffset();
+ uint32_t lsdaIndexArrayEndSectionOffset = indexes[sectionHeader->indexCount()-1].lsdaIndexArraySectionOffset();
+ uint32_t lsdaIndexArrayCount = (lsdaIndexArrayEndSectionOffset-lsdaIndexArraySectionOffset)/sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
+ printf("\tLSDA table: (section offset 0x%08X, count=%u)\n", lsdaIndexArraySectionOffset, lsdaIndexArrayCount);
+ macho_unwind_info_section_header_lsda_index_entry<P>* lindex = (macho_unwind_info_section_header_lsda_index_entry<P>*)§ionContent[lsdaIndexArraySectionOffset];
+ for (uint32_t i=0; i < lsdaIndexArrayCount; ++i) {
+ const char* name = showFunctionNames ? functionName(lindex[i].functionOffset()+fMachHeaderAddress) : "";
+ printf("\t\t[%3u] funcOffset=0x%08X, lsdaOffset=0x%08X, %s\n", i, lindex[i].functionOffset(), lindex[i].lsdaOffset(), name);
+ if ( *(((uint8_t*)fHeader) + lindex[i].lsdaOffset()) != 0xFF )
+ fprintf(stderr, "BAD LSDA entry (does not start with 0xFF) for %s\n", functionName(lindex[i].functionOffset()+fMachHeaderAddress));
+ }
+ for (uint32_t i=0; i < sectionHeader->indexCount()-1; ++i) {
+ printf("\tsecond level index[%u] sectionOffset=0x%08X, count=%u, fileOffset=0x%08X\n", i, indexes[i].secondLevelPagesSectionOffset(),
+ sectionHeader->indexCount(), fUnwindSection->offset()+indexes[i].secondLevelPagesSectionOffset());
+ macho_unwind_info_regular_second_level_page_header<P>* page = (macho_unwind_info_regular_second_level_page_header<P>*)§ionContent[indexes[i].secondLevelPagesSectionOffset()];
+ if ( page->kind() == UNWIND_SECOND_LEVEL_REGULAR ) {
+ printf("\t\tkind=UNWIND_SECOND_LEVEL_REGULAR\n");
+ printf("\t\tentryPageOffset=0x%08X\n", page->entryPageOffset());
+ printf("\t\tentryCount=0x%08X\n", page->entryCount());
+ const macho_unwind_info_regular_second_level_entry<P>* entry = (macho_unwind_info_regular_second_level_entry<P>*)((char*)page+page->entryPageOffset());
+ for (uint32_t j=0; j < page->entryCount(); ++j) {
+ uint32_t funcOffset = entry[j].functionOffset();
+ if ( entry[j].encoding() & UNWIND_HAS_LSDA ) {
+ // verify there is a corresponding entry in lsda table
+ bool found = false;
+ for (uint32_t k=0; k < lsdaIndexArrayCount; ++k) {
+ if ( lindex[k].functionOffset() == funcOffset ) {
+ found = true;
+ break;
+ }
+ }
+ if ( !found ) {
+ fprintf(stderr, "MISSING LSDA entry for %s\n", functionName(funcOffset+fMachHeaderAddress));
+ }
+ }
+ char encodingString[100];
+ decode(entry[j].encoding(), ((const uint8_t*)fHeader)+funcOffset, encodingString);
+ const char* name = showFunctionNames ? functionName(funcOffset+fMachHeaderAddress) : "";
+ printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X (%-40s) %s\n",
+ j, funcOffset, entry[j].encoding(), encodingString, name);
+ }
+ }
+ else if ( page->kind() == UNWIND_SECOND_LEVEL_COMPRESSED ) {
+ macho_unwind_info_compressed_second_level_page_header<P>* cp = (macho_unwind_info_compressed_second_level_page_header<P>*)page;
+ printf("\t\tkind=UNWIND_SECOND_LEVEL_COMPRESSED\n");
+ printf("\t\tentryPageOffset=0x%08X\n", cp->entryPageOffset());
+ printf("\t\tentryCount=0x%08X\n", cp->entryCount());
+ printf("\t\tencodingsPageOffset=0x%08X\n", cp->encodingsPageOffset());
+ printf("\t\tencodingsCount=0x%08X\n", cp->encodingsCount());
+ const uint32_t* entries = (uint32_t*)(((uint8_t*)page)+cp->entryPageOffset());
+ const uint32_t* encodings = (uint32_t*)(((uint8_t*)page)+cp->encodingsPageOffset());
+ const uint32_t baseFunctionOffset = indexes[i].functionOffset();
+ for (uint32_t j=0; j < cp->entryCount(); ++j) {
+ uint8_t encodingIndex = UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entries[j]);
+ uint32_t encoding;
+ if ( encodingIndex < sectionHeader->commonEncodingsArrayCount() )
+ encoding = A::P::E::get32(commonEncodings[encodingIndex]);
+ else
+ encoding = A::P::E::get32(encodings[encodingIndex-sectionHeader->commonEncodingsArrayCount()]);
+ char encodingString[100];
+ uint32_t funcOff = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entries[j])+baseFunctionOffset;
+ decode(encoding, ((const uint8_t*)fHeader)+funcOff, encodingString);
+ const char* name = showFunctionNames ? functionName(funcOff+fMachHeaderAddress) : "";
+ if ( encoding & UNWIND_HAS_LSDA ) {
+ // verify there is a corresponding entry in lsda table
+ bool found = false;
+ for (uint32_t k=0; k < lsdaIndexArrayCount; ++k) {
+ if ( lindex[k].functionOffset() == funcOff ) {
+ found = true;
+ break;
+ }
+ }
+ if ( !found ) {
+ fprintf(stderr, "MISSING LSDA entry for %s\n", name);
+ }
+ }
+ printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%3u]=0x%08X (%-40s) %s\n",
+ j, funcOff, encodingIndex, encoding, encodingString, name);
+ }
+ }
+ else {
+ fprintf(stderr, "\t\tbad page header\n");
+ }
+ }
+
+}
+
+static void dump(const char* path, const std::set<cpu_type_t>& onlyArchs, bool showFunctionNames)
+{
+ struct stat stat_buf;
+
+ try {
+ int fd = ::open(path, O_RDONLY, 0);
+ if ( fd == -1 )
+ throw "cannot open file";
+ if ( ::fstat(fd, &stat_buf) != 0 )
+ throwf("fstat(%s) failed, errno=%d\n", path, errno);
+ uint32_t length = stat_buf.st_size;
+ uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+ if ( p == ((uint8_t*)(-1)) )
+ throw "cannot map file";
+ ::close(fd);
+ const mach_header* mh = (mach_header*)p;
+ if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+ const struct fat_header* fh = (struct fat_header*)p;
+ const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
+ for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
+ size_t offset = OSSwapBigToHostInt32(archs[i].offset);
+ size_t size = OSSwapBigToHostInt32(archs[i].size);
+ unsigned int cputype = OSSwapBigToHostInt32(archs[i].cputype);
+ if ( onlyArchs.count(cputype) ) {
+ switch(cputype) {
+ case CPU_TYPE_I386:
+ if ( UnwindPrinter<x86>::validFile(p + offset) )
+ UnwindPrinter<x86>::make(p + offset, size, path, showFunctionNames);
+ else
+ throw "in universal file, i386 slice does not contain i386 mach-o";
+ break;
+ case CPU_TYPE_X86_64:
+ if ( UnwindPrinter<x86_64>::validFile(p + offset) )
+ UnwindPrinter<x86_64>::make(p + offset, size, path, showFunctionNames);
+ else
+ throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
+ break;
+ default:
+ throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
+ }
+ }
+ }
+ }
+ else if ( UnwindPrinter<x86>::validFile(p) && onlyArchs.count(CPU_TYPE_I386) ) {
+ UnwindPrinter<x86>::make(p, length, path, showFunctionNames);
+ }
+ else if ( UnwindPrinter<x86_64>::validFile(p) && onlyArchs.count(CPU_TYPE_X86_64) ) {
+ UnwindPrinter<x86_64>::make(p, length, path, showFunctionNames);
+ }
+ else {
+ throw "not a known file type";
+ }
+ }
+ catch (const char* msg) {
+ throwf("%s in %s", msg, path);
+ }
+}
+
+
+int main(int argc, const char* argv[])
+{
+ std::set<cpu_type_t> onlyArchs;
+ std::vector<const char*> files;
+ bool showFunctionNames = true;
+
+ try {
+ for(int i=1; i < argc; ++i) {
+ const char* arg = argv[i];
+ if ( arg[0] == '-' ) {
+ if ( strcmp(arg, "-arch") == 0 ) {
+ const char* arch = argv[++i];
+ if ( strcmp(arch, "i386") == 0 )
+ onlyArchs.insert(CPU_TYPE_I386);
+ else if ( strcmp(arch, "x86_64") == 0 )
+ onlyArchs.insert(CPU_TYPE_X86_64);
+ else
+ throwf("unknown architecture %s", arch);
+ }
+ else if ( strcmp(arg, "-no_symbols") == 0 ) {
+ showFunctionNames = false;
+ }
+ else {
+ throwf("unknown option: %s\n", arg);
+ }
+ }
+ else {
+ files.push_back(arg);
+ }
+ }
+
+ // use all architectures if no restrictions specified
+ if ( onlyArchs.size() == 0 ) {
+ onlyArchs.insert(CPU_TYPE_I386);
+ onlyArchs.insert(CPU_TYPE_X86_64);
+ }
+
+ // process each file
+ for(std::vector<const char*>::iterator it=files.begin(); it != files.end(); ++it) {
+ dump(*it, onlyArchs, showFunctionNames);
+ }
+
+ }
+ catch (const char* msg) {
+ fprintf(stderr, "UnwindDump failed: %s\n", msg);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
--- /dev/null
+
+The easy way to run all tests is within Xcode. Just select "unit-tests" as the target and click Build.
+
+When run from within Xcode, the just built linker will be used. If you cd into a test case and run it, the
+installed linker (e.g. /usr/bin/ld) will be used.
+
+Each test case is a directory with a Makefile. The Makefile default target should do whatever work is necessary
+to perform the test. If successful is should print "PASS xxx" where xxx is the name of the test case. Otherwise
+it should print "FAIL xxx reason". If nothing is printed (for instance a tool crashed), the harness will
+automatically print that it failed. The harness will always pass ARCH to the Makefile to specify which
+architecture to test. The Makefile should also have a "clean" target which removes and generated files.
+
+
+There are some utility functions for use in Makefiles for generating the PASS/FAIL strings:
+
+ ${PASS_IFF} can be put in front of the last command in the make rule and it will print PASS
+ if the command returned 0 or FAIL otherwise. Example:
+ ${PASS_IFF} ${CC} foo.c -o foo
+ Will print PASS if and only if the compilation succeeded
+
+ ${PASS_IFF_EMPTY} can have data piped into it. It prints PASS if there is no data, otherwise FAIL.
+ Example:
+ otool -hv foo.o | grep SUBSECTIONS_VIA_SYMBOLS | ${PASS_IFF_EMPTY}
+ Will print PASS if and only if the output of otool does not contain SUBSECTIONS_VIA_SYMBOLS
+
+
+
+
--- /dev/null
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+# ${PASS_UNLESS} "test name" command
+#
+
+use strict;
+
+my $string = shift @ARGV;
+my $ret = system(@ARGV);
+my $exit_value = $ret >> 8;
+my $signal_num = $ret & 127;
+my $dumped_core = $ret & 128;
+my $crashed = $signal_num + $dumped_core;
+
+if(0 == $exit_value || 0 != $crashed)
+{
+ printf("FAIL $string\n");
+}
+else
+{
+ printf("PASS $string\n");
+}
+
+exit 0;
--- /dev/null
+#!/usr/bin/perl -w
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+ $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+if(system(@ARGV) != 0)
+{
+ printf("FAIL $test_name\n");
+ exit 1;
+}
+
+exit 0;
--- /dev/null
+#!/usr/bin/perl -w
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+ $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+my $ret = system(@ARGV);
+my $exit_value = $ret >> 8;
+my $signal_num = $ret & 127;
+my $dumped_core = $ret & 128;
+my $crashed = $signal_num + $dumped_core;
+
+if(0 == $exit_value || 0 != $crashed)
+{
+ printf("FAIL $test_name\n");
+ exit 1;
+}
+
+exit 0;
--- /dev/null
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+# command | ${FAIL_IF_EMPTY}
+#
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+ $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+if( eof STDIN )
+{
+ printf("FAIL $test_name\n");
+ exit 1;
+}
+
+exit 0;
--- /dev/null
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+# command | ${FAIL_IF_STDIN}
+#
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+ $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+if( eof STDIN )
+{
+ exit 0;
+}
+
+printf("FAIL $test_name\n");
+exit 1;
--- /dev/null
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+# ${FALL_IFF} command
+#
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+ $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+my $ret = system(@ARGV);
+my $exit_value = $ret >> 8;
+my $signal_num = $ret & 127;
+my $dumped_core = $ret & 128;
+my $crashed = $signal_num + $dumped_core;
+
+if(0 == $exit_value || 0 != $crashed)
+{
+ printf("FAIL $test_name\n");
+ exit 1;
+}
+
+printf("PASS $test_name\n");
+exit 0;
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+use Data::Dumper;
+use File::Find;
+use Cwd qw(realpath);
+
+my @args = @ARGV;
+
+$ENV{'LD_NO_CLASSSIC_LINKER'} = '1';
+$ENV{'LD_NO_CLASSSIC_LINKER_STATIC'} = '1';
+
+my $makefiles =
+{
+ 'makefile' => undef,
+ 'Makefile' => undef,
+ 'makefile.newtest' => undef,
+ 'Makefile.newtest' => undef,
+};
+
+my $find_opts =
+{
+ 'wanted' => \&find_callback,
+};
+
+my $keywords =
+{
+ 'root' => '',
+ 'cwd' => '',
+ 'cmd' => '',
+ 'exit' => '',
+ 'stdout' => [],
+ 'stderr' => [],
+};
+
+my $keyword;
+my $max_keyword_len = 0;
+foreach $keyword (keys %$keywords)
+{ if($max_keyword_len < length($keyword)) { $max_keyword_len = length($keyword); } }
+my $delim = ':';
+$max_keyword_len += length($delim) + length(' ');
+
+my $last_keyword = '';
+
+sub print_line
+{
+ my ($keyword, $val) = @_;
+
+ if(!exists($$keywords{$keyword}))
+ {
+ print STDERR "error: keyword $keyword not in \$keywords set\n";
+ exit(1);
+ }
+
+ my $keyword_len = 0;
+
+ if($keyword ne $last_keyword)
+ {
+ print("$keyword"); print($delim);
+ $keyword_len = length($keyword) + length($delim);
+ }
+ if($max_keyword_len > $keyword_len)
+ {
+ my $num_spaces = $max_keyword_len - $keyword_len;
+ print(' ' x $num_spaces);
+ }
+ print("$val");
+ if(0)
+ {
+ $last_keyword = $keyword;
+ }
+}
+
+my $root = '.';
+$root = &realpath($root);
+print_line("root", "$root\n");
+
+find($find_opts, $root);
+
+sub find_callback
+{
+ if(exists($$makefiles{$_}))
+ {
+ my $makefile = $_;
+ my $reldir = $File::Find::dir;
+ $reldir =~ s|^$root/||;
+
+ &print_line("cwd", "\$root/$reldir\n");
+ my $cmd = [ "make" ];
+
+ push @$cmd, "-f";
+ push @$cmd, $makefile;
+ my $arg; foreach $arg (@ARGV) { push @$cmd, $arg; } # better way to do this?
+ &print_line("cmd", "@$cmd\n");
+
+ open(SAVEOUT, ">&STDOUT") || die("$!");
+ open(SAVEERR, ">&STDERR") || die("$!");
+ open(STDOUT, ">/tmp/unit-tests-stdout") || die("$!");
+ open(STDERR, ">/tmp/unit-tests-stderr") || die("$!");
+
+ $ENV{UNIT_TEST_NAME} = $reldir;
+ my $exit = system(@$cmd);
+
+ close(STDOUT) || die("$!");
+ close(STDERR) || die("$!");
+ open(STDOUT, ">&SAVEOUT") || die("$!");
+ open(STDERR, ">&SAVEERR") || die("$!");
+
+ &print_line("exit", "$exit\n");
+
+ open(OUT, "</tmp/unit-tests-stdout") || die("$!");
+ while(<OUT>)
+ {
+ &print_line("stdout", "$_");
+ }
+ close(OUT) || die("$!");
+ unlink("/tmp/unit-tests-stdout");
+
+ open(ERR, "</tmp/unit-tests-stderr") || die("$!");
+ while(<ERR>)
+ {
+ &print_line("stderr", "$_");
+ }
+ close(ERR) || die("$!");
+ }
+ unlink("/tmp/unit-tests-stderr");
+}
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+use Data::Dumper;
+use File::Find;
+use Cwd qw(realpath);
+use English;
+
+my @args = @ARGV;
+
+$ENV{'LD_NO_CLASSSIC_LINKER'} = '1';
+$ENV{'LD_NO_CLASSSIC_LINKER_STATIC'} = '1';
+
+my $makefiles =
+{
+ 'makefile' => undef,
+ 'Makefile' => undef,
+};
+
+my $find_opts =
+{
+ 'wanted' => \&find_callback,
+};
+
+my $keywords =
+{
+ 'root' => '',
+ 'cwd' => '',
+ 'cmd' => '',
+ 'exit' => '',
+ 'stdout' => [],
+ 'stderr' => [],
+};
+
+# Determine how many tests to run at a time in parallel. Default to cpu count.
+my $max_concurrent_tests = $ENV{'LD_UNIT_TEST_CONCURRENCY'};
+if (!defined $max_concurrent_tests) {
+ # shell command returns cpu count in exit status
+ system("/bin/csh", "-c", "set n=`sysctl hw.ncpu`; exit \$n[2]");
+ if ($? == -1 || $? & 127) {
+ die("could not determine cpu count");
+ }
+ $max_concurrent_tests = $? >> 8;
+}
+
+my $keyword;
+my $max_keyword_len = 0;
+foreach $keyword (keys %$keywords)
+{ if($max_keyword_len < length($keyword)) { $max_keyword_len = length($keyword); } }
+my $delim = ':';
+$max_keyword_len += length($delim) + length(' ');
+
+my $last_keyword = '';
+
+sub print_line
+{
+ my ($file, $keyword, $val) = @_;
+
+ if(!exists($$keywords{$keyword}))
+ {
+ print STDERR "error: keyword $keyword not in \$keywords set\n";
+ exit(1);
+ }
+
+ my $keyword_len = 0;
+
+ if($keyword ne $last_keyword)
+ {
+ print($file "$keyword"); print($file $delim);
+ $keyword_len = length($keyword) + length($delim);
+ }
+ if($max_keyword_len > $keyword_len)
+ {
+ my $num_spaces = $max_keyword_len - $keyword_len;
+ print($file ' ' x $num_spaces);
+ }
+ print($file "$val");
+ if(0)
+ {
+ $last_keyword = $keyword;
+ }
+}
+
+my $root = '.';
+$root = &realpath($root);
+print_line(*STDOUT, "root", "$root\n");
+my $running_test_count=0;
+find($find_opts, $root);
+while ( $running_test_count > 0 ) {
+ &reaper;
+}
+
+sub find_callback
+{
+ if(exists($$makefiles{$_}))
+ {
+ my $makefile = $_;
+ my $reldir = $File::Find::dir;
+ $reldir =~ s|^$root/||;
+
+ my $cmd = [ "make" ];
+
+ my $arg; foreach $arg (@ARGV) { push @$cmd, $arg; } # better way to do this?
+
+ $ENV{UNIT_TEST_NAME} = $reldir;
+ my $pid = fork();
+ if (not defined $pid) {
+ die "Couldn't fork"
+ }
+ elsif ($pid == 0) {
+ # Child. Redirect stdout/stderr to files and exec test.
+ open(STDOUT, ">/tmp/unit-tests-stdout.$PID") || die("$!");
+ open(STDERR, ">/tmp/unit-tests-stderr.$PID") || die("$!");
+ exec 'make', @ARGV;
+ exit(-1); #just to be sure
+ }
+
+ # Write the test cwd/cmd to a temporary file associated with the child's pid, to be retrieved later.
+ my $info;
+ open($info, ">/tmp/unit-tests-info.$pid") || die("$!");
+ &print_line($info, "cwd", "\$root/$reldir\n"); # post filtering depends on this line being first
+ &print_line($info, "cmd", "@$cmd\n");
+ close($info) || die("$!");
+
+ $running_test_count++;
+ # if we have reached max # of concurrent tests, wait for one to exit
+ if ( $running_test_count == $max_concurrent_tests ) {
+ &reaper;
+ }
+ }
+}
+
+sub reaper {
+ if ( $running_test_count > 0 ) {
+ my $pid = wait;
+ if ( $pid == -1 ) {
+ die("no child\n");
+ }
+ my $exit = $?;
+
+ $running_test_count--;
+
+ open(INFO, "</tmp/unit-tests-info.$pid") || die("$!");
+ while(<INFO>)
+ {
+ print $_;
+ }
+ close(INFO) || die("$!");
+ unlink("/tmp/unit-tests-info.$pid");
+
+ &print_line(*STDOUT, "exit", "$exit\n");
+
+ open(OUT, "</tmp/unit-tests-stdout.$pid") || die("$!");
+ while(<OUT>)
+ {
+ &print_line(*STDOUT, "stdout", "$_");
+ }
+ close(OUT) || die("$!");
+ unlink("/tmp/unit-tests-stdout.$pid");
+
+ open(ERR, "</tmp/unit-tests-stderr.$pid") || die("$!");
+ while(<ERR>)
+ {
+ &print_line(*STDOUT, "stderr", "$_");
+ }
+ close(ERR) || die("$!");
+ unlink("/tmp/unit-tests-stderr.$pid");
+ }
+}
+
--- /dev/null
+#!/bin/sh
+
+hide()
+{
+ $PROCTOR set_hidden $1 1 >/dev/null
+}
+
+if [ -z "$1" ]
+ then echo "Usage: mkld HOST [ DBPATH ]" >&2
+ exit 1
+fi
+
+if [ -z "$PROCTOR" ]
+ then PROCTOR=proctor
+fi
+
+DBNAME="$2"
+[ -z "$DBNAME" ] && DBNAME=ld
+PROCTOR="$PROCTOR $1 $DBNAME"
+
+$PROCTOR tools gcc g++ objc obj-c++ libstdc++ ld ld ld_classic cctools
+$PROCTOR sysattrs \
+ ld64="ld64" \
+ ld="ld (ld_classic)" \
+ gcc="GCC" \
+ cctools="cctools" \
+ os="OS Build" \
+ processor=Processor \
+ platform=Platform \
+ hostname="Hostname" \
+ gcc_opts="gcc options" \
+ g++_opts="g++ options" \
+ objc_opts="objc options" \
+ obj-c++_opts="obj-c++ options" \
+ libstdc++_opts="libstdc++ options" \
+ LANG="LANG environment variable" \
+ LC_CTYPE="LC_CTYPE environment variable" \
+ LC_MESSAGES="LC_MESSAGES environment variable" \
+ LC_ALL="LC_ALL environment variable" \
+ TMPDIR="TMPDIR environment variable" \
+ GCC_EXEC_PREFIX="GCC_EXEC_PREFIX environment variable" \
+ COMPILER_PATH="COMPILER_PATH environment variable" \
+ LIBRARY_PATH="LIBRARY_PATH environment variable" \
+ LANG="LANG environment variable" \
+ CPATH="CPATH environment variable" \
+ C_INCLUDE_PATH="C_INCLUDE_PATH environment variable" \
+ CPLUS_INCLUDE_PATH="CPLUS_INCLUDE_PATH environment variable" \
+ OBJC_INCLUDE_PATH="OBJC_INCLUDE_PATH environment variable" \
+ DEPENDENCIES_OUTPUT="DEPENDENCIES_OUTPUT environment variable" \
+ SUNPRO_DEPENDENCIES="SUNPRO_DEPENDENCIES environment variable" \
+
+for TOOL in gcc g++ objc obj-c++ libstdc++
+ do hide ${TOOL}_opts
+done
+
+hide LANG
+hide LC_CTYPE
+hide LC_MESSAGES
+hide LC_ALL
+hide TMPDIR
+hide GCC_EXEC_PREFIX
+hide COMPILER_PATH
+hide LIBRARY_PATH
+hide LANG
+hide CPATH
+hide C_INCLUDE_PATH
+hide CPLUS_INCLUDE_PATH
+hide OBJC_INCLUDE_PATH
+hide DEPENDENCIES_OUTPUT
+hide SUNPRO_DEPENDENCIES
+
+$PROCTOR results PASS=1 XFAIL=1 KFAIL=1 FAIL=0 XPASS=0 KPASS=0 UNRESOLVED=0 TIMEDOUT=0 UNSUPPORTED=0 UNTESTED=0
+$PROCTOR severities logline NOTE WARNING ERROR
--- /dev/null
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+# ${PASS_IFF} command
+#
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+ $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+my $ret = system(@ARGV);
+my $exit_value = $ret >> 8;
+my $signal_num = $ret & 127;
+my $dumped_core = $ret & 128;
+my $crashed = $signal_num + $dumped_core;
+
+if(0 == $exit_value || 0 != $crashed)
+{
+ printf("FAIL $test_name\n");
+ exit 1;
+}
+
+printf("PASS $test_name\n");
+exit 0;
--- /dev/null
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+# ${PASS_IFF} command
+#
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+ $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+if(0 != system(@ARGV))
+{
+ printf("FAIL $test_name\n");
+ exit 1;
+}
+
+printf("PASS $test_name\n");
+exit 0;
--- /dev/null
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+# command | ${PASS_IFF_EMPTY}
+#
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+ $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+if( eof STDIN )
+{
+ printf("PASS $test_name\n");
+ exit 0;
+}
+
+printf("FAIL $test_name\n");
+exit 1;
--- /dev/null
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+# command | ${PASS_IFF_STDIN}
+#
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+ $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+if( eof STDIN )
+{
+ printf("FAIL $test_name\n");
+ exit 1
+}
+
+printf("PASS $test_name\n");
+exit 0;
+
--- /dev/null
+#!/usr/bin/perl -w
+
+use strict;
+use Data::Dumper;
+use File::Find;
+use Cwd;
+
+$Data::Dumper::Terse = 1;
+
+my $root = undef;
+my $entry = '';
+my $pass_count = 0;
+my $total_count = 0;
+
+# first match "root: "
+
+# a line starting with "cwd:" marks the beginning of a new test case
+# call process_entry() on each test case
+while(<>)
+{
+ if(m/^root:\s+(.*?)$/)
+ {
+ $root = $1;
+ }
+ elsif(m/^cwd:\s+(.*?)$/)
+ {
+ if(length($entry))
+ {
+ &process_entry($root, $entry);
+ $entry = '';
+ }
+ $entry .= $_;
+ }
+ else
+ {
+ $entry .= $_;
+ }
+}
+# don't forget last test case (no cwd: to mark end)
+if(length($entry))
+{
+ &process_entry($root, $entry);
+}
+
+# show totals
+my $percentage = $pass_count * 100 / $total_count;
+printf " * * * %d of %d unit-tests passed (%.1f percent) * * *\n", $pass_count, $total_count, $percentage;
+
+
+sub process_entry
+{
+ my ($root, $lines) = @_;
+
+ # build an associative array of keys to value(s)
+ my $lines_seq = [split /\n/, $lines];
+ #print Dumper($lines_seq);
+ my $tbl = { 'root' => $root, 'stdout' => [], 'stderr' => [] };
+ my $line;
+ foreach $line (@$lines_seq)
+ {
+ if($line =~ m/^(\w+):\s+(.*)$/)
+ {
+ my $key = $1;
+ my $val = $2;
+ if(!exists($$tbl{$key}))
+ { $$tbl{$key} = ''; }
+
+ if($key eq 'stdout' || $key eq 'stderr') # if type is @array
+ {
+ push @{$$tbl{$key}}, $val;
+ }
+ else
+ {
+ $$tbl{$key} .= $val;
+ }
+ }
+ else
+ {
+ print "ERROR: $line";
+ }
+ }
+ #print Dumper($tbl);
+ #return;
+
+ my $test_name = $$tbl{cwd};
+ if ($test_name =~ m|.*/([a-zA-Z0-9-+_]+)$|)
+ {
+ $test_name = $1;
+ }
+
+ #if make failed (exit was non-zero), mark this as a failure
+ if(0 ne $$tbl{exit})
+ {
+ printf "%-40s FAIL Makefile failure\n", $test_name;
+ $total_count++;
+ #my $line1;
+ #foreach $line1 (@{$$tbl{stdout}})
+ #{
+ # printf "stdout: %s\n", $line1;
+ #}
+ #foreach $line1 (@{$$tbl{stderr}})
+ #{
+ # printf "stderr: %s\n", $line1;
+ #}
+ return;
+ }
+
+ #if there was any output to stderr, mark this as a failure
+ foreach $line (@{$$tbl{stderr}})
+ {
+ printf "%-40s FAIL spurious stderr failure: %s\n", $test_name, $line;
+ $total_count++;
+ return;
+ }
+
+ # scan all stdout looking for lines that start with PASS or FAIL
+ my $seen_result = 0;
+ foreach $line (@{$$tbl{stdout}})
+ {
+ if($line =~ m/^(PASS|XPASS|FAIL|XFAIL).+/)
+ {
+ $total_count++;
+ if($line =~ m/^PASS.+/)
+ {
+ $pass_count++;
+ }
+ else
+ {
+ # only print failure lines
+ printf "%-40s %s\n", $test_name, $line;
+ }
+ $seen_result = 1;
+ }
+ }
+ if(!$seen_result)
+ {
+ printf "%-40s AMBIGIOUS missing [X]PASS/[X]FAIL\n", $test_name;
+ $total_count++;
+ #my $line1;
+ #foreach $line1 (@{$$tbl{stdout}})
+ #{
+ # printf "stdout: %s\n", $line1;
+ #}
+ #foreach $line1 (@{$$tbl{stderr}})
+ #{
+ # printf "stderr: %s\n", $line1;
+ #}
+ }
+}
--- /dev/null
+#!/bin/sh
+
+usage() {
+ echo Usage: $0 number-of-tests-logs-to-keep
+ echo where number-of-tests-logs-to-keep must be a non-zero integer
+ exit
+}
+
+# Usage: if no arguments
+[ -z "$1" ] && usage
+
+# Check if requesting 0 tests to remain!
+[ "$1" -ne 0 ]
+
+# don't test directly--use the result value
+# because the command can fail for badly formed integers
+[ $? -ne 0 ] && usage
+
+# get the dir names of all tests in date order
+ls -1dtr /tmp/proctor*>/tmp/all$$ 2>/dev/null
+
+# select the last few to keep
+tail -$1 /tmp/all$$>/tmp/keep$$
+
+# get a list of the others
+DELLIST=`diff /tmp/all$$ /tmp/keep$$|grep '^<'|sed -e 's/^< //'`
+
+# any work to do?
+if [ "$DELLIST" ]
+then
+ echo rm -rf $DELLIST
+ rm -rf $DELLIST
+fi
+
+# rm the temps
+rm /tmp/all$$ /tmp/keep$$
--- /dev/null
+find_makefile()
+{
+ local j
+
+ MF=""
+
+ if [ ! -d $1 ]
+ then
+ return 1
+ fi
+
+ for j in Makefile makefile Makefile.newtest makefile.newtest
+ do
+ [ -f $1/$j ] && MF=$j
+ done
+
+ [ "$MF" ] && return 0
+ return 1
+}
+
+find_path_to_test_dir()
+{
+ # FIND THE PATH TO THE TEST DIR
+ # SO THAT WE CAN ADD THE BIN DIR INTO
+ # THE SEARCH PATH
+
+ # remember the top level execution dir
+ chmod +x "$0" # just in case
+
+ #add path to $0 into search
+ savedir=$PWD
+ DIRNAME=`dirname $0`
+ [ -d "$DIRNAME" ] && cd "$DIRNAME"
+ PATH=$PATH:$PWD
+ cd "$savedir"
+
+ chmod +x "$0" # just in case
+ EXECNAME=`which $0`
+ DIRNAME=`dirname "$EXECNAME"`
+ if [ -d "$DIRNAME" ]
+ then
+ TEST_HOME_DIR="$DIRNAME"
+ else
+ TEST_HOME_DIR="$savedir" # Give up and assume current dir
+ fi
+
+ PATH="$PATH":"$TEST_HOME_DIR"/bin:"$savedir"
+}
+
+find_path_to_test_dir
+
+cd "$TEST_HOME_DIR/test-cases"
+
+for i in *
+do
+ [ -d "$i" ] &&
+ (
+ if find_makefile $i
+ then
+ make -C $i -f $MF -s -k clean >/dev/null 2>/dev/null
+ fi
+ )
+done
--- /dev/null
+# stuff to include in every test Makefile
+
+SHELL = /bin/sh
+
+# set default to be host
+ARCH ?= $(shell arch)
+
+# set default to be all
+VALID_ARCHS ?= "i386 x86_64 armv6"
+
+
+MYDIR=$(shell cd ../../bin;pwd)
+LD = ld
+OBJECTDUMP = ObjectDump
+MACHOCHECK = machocheck
+OTOOL = otool
+REBASE = rebase
+DYLDINFO = dyldinfo
+
+ifdef BUILT_PRODUCTS_DIR
+ # if run within Xcode, add the just built tools to the command path
+ PATH := ${BUILT_PRODUCTS_DIR}:${MYDIR}:${PATH}
+ COMPILER_PATH := ${BUILT_PRODUCTS_DIR}:${COMPILER_PATH}
+ LD_PATH = ${BUILT_PRODUCTS_DIR}
+ LD = ${BUILT_PRODUCTS_DIR}/ld
+ OBJECTDUMP = ${BUILT_PRODUCTS_DIR}/ObjectDump
+ MACHOCHECK = ${BUILT_PRODUCTS_DIR}/machocheck
+ REBASE = ${BUILT_PRODUCTS_DIR}/rebase
+ UNWINDDUMP = ${BUILT_PRODUCTS_DIR}/unwinddump
+ DYLDINFO = ${BUILT_PRODUCTS_DIR}/dyldinfo
+else
+ ifneq "$(findstring /unit-tests/test-cases/, $(shell pwd))" ""
+ # if run from Terminal inside unit-test directory
+ RELEASEADIR=$(shell cd ../../../build/Release-assert;pwd)
+ DEBUGDIR=$(shell cd ../../../build/Debug;pwd)
+ PATH := ${RELEASEADIR}:${RELEASEDIR}:${DEBUGDIR}:${MYDIR}:${PATH}
+ COMPILER_PATH := ${RELEASEADIR}:${RELEASEDIR}:${DEBUGDIR}:${COMPILER_PATH}
+ LD_PATH = ${DEBUGDIR}
+ LD = ${DEBUGDIR}/ld
+ OBJECTDUMP = ${DEBUGDIR}/ObjectDump
+ MACHOCHECK = ${DEBUGDIR}/machocheck
+ REBASE = ${DEBUGDIR}/rebase
+ UNWINDDUMP = ${DEBUGDIR}/unwinddump
+ DYLDINFO = ${DEBUGDIR}/dyldinfo
+ else
+ PATH := ${MYDIR}:${PATH}:
+ COMPILER_PATH := ${MYDIR}:${COMPILER_PATH}:
+ endif
+endif
+export PATH
+export COMPILER_PATH
+export GCC_EXEC_PREFIX=garbage
+
+ifeq ($(ARCH),ppc)
+ SDKExtra = -isysroot /Developer/SDKs/MacOSX10.6.sdk
+endif
+
+CC = $(shell xcrun -find clang) -arch ${ARCH} ${SDKExtra}
+CCFLAGS = -Wall
+ASMFLAGS =
+VERSION_NEW_LINKEDIT = -mmacosx-version-min=10.6
+VERSION_OLD_LINKEDIT = -mmacosx-version-min=10.4
+LD_NEW_LINKEDIT = -macosx_version_min 10.6
+
+CXX = $(shell xcrun -find clang++) -arch ${ARCH} ${SDKExtra}
+CXXFLAGS = -Wall -stdlib=libc++
+
+IOS_SDK = $(shell xcodebuild -sdk iphoneos6.0.internal -version Path)
+
+ifeq ($(ARCH),armv6)
+ LDFLAGS := -syslibroot $(IOS_SDK)
+ override FILEARCH = arm
+ CC = $(shell xcrun -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+ CXX = $(shell xcrun -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+ VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
+ VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
+ LD_SYSROOT = -syslibroot $(IOS_SDK)
+ LD_NEW_LINKEDIT = -ios_version_min 4.0
+else
+ FILEARCH = $(ARCH)
+endif
+
+ifeq ($(ARCH),armv7)
+ LDFLAGS := -syslibroot $(IOS_SDK)
+ override FILEARCH = arm
+ CC = $(shell xcrun -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+ CXX = $(shell xcrun -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+ VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
+ VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
+ LD_SYSROOT = -syslibroot $(IOS_SDK)
+ LD_NEW_LINKEDIT = -ios_version_min 4.0
+else
+ FILEARCH = $(ARCH)
+endif
+
+ifeq ($(ARCH),thumb)
+ LDFLAGS := -syslibroot $(IOS_SDK)
+ CCFLAGS += -mthumb
+ CXXFLAGS += -mthumb
+ override ARCH = armv6
+ override FILEARCH = arm
+ CC = $(shell xcrun -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+ CXX = $(shell xcrun -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+ VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
+ VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
+ LD_SYSROOT = -syslibroot $(IOS_SDK)
+ LD_NEW_LINKEDIT = -ios_version_min 4.0
+else
+ FILEARCH = $(ARCH)
+endif
+
+ifeq ($(ARCH),thumb2)
+ LDFLAGS := -syslibroot $(IOS_SDK)
+ CCFLAGS += -mthumb
+ CXXFLAGS += -mthumb
+ override ARCH = armv7
+ override FILEARCH = arm
+ CC = $(shell xcrun -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+ CXX = $(shell xcrun -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+ VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
+ VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
+ LD_SYSROOT = -syslibroot $(IOS_SDK)
+ LD_NEW_LINKEDIT = -ios_version_min 4.0
+else
+ FILEARCH = $(ARCH)
+endif
+
+
+RM = rm
+RMFLAGS = -rf
+
+# utilites for Makefiles
+PASS_IFF = ${MYDIR}/pass-iff-exit-zero.pl
+PASS_IFF_SUCCESS = ${PASS_IFF}
+PASS_IFF_EMPTY = ${MYDIR}/pass-iff-no-stdin.pl
+PASS_IFF_STDIN = ${MYDIR}/pass-iff-stdin.pl
+FAIL_IFF = ${MYDIR}/fail-iff-exit-zero.pl
+FAIL_IFF_SUCCESS = ${FAIL_IFF}
+PASS_IFF_ERROR = ${MYDIR}/pass-iff-exit-non-zero.pl
+FAIL_IF_ERROR = ${MYDIR}/fail-if-exit-non-zero.pl
+FAIL_IF_SUCCESS = ${MYDIR}/fail-if-exit-zero.pl
+FAIL_IF_EMPTY = ${MYDIR}/fail-if-no-stdin.pl
+FAIL_IF_STDIN = ${MYDIR}/fail-if-stdin.pl
+PASS_IFF_GOOD_MACHO = ${PASS_IFF} ${MACHOCHECK}
+FAIL_IF_BAD_MACHO = ${FAIL_IF_ERROR} ${MACHOCHECK}
+FAIL_IF_BAD_OBJ = ${FAIL_IF_ERROR} ${OBJECTDUMP} >/dev/null
--- /dev/null
+#include <stdarg.h>
+#include <stdio.h>
+
+#define DEFINE_TEST_FUNC(name) \
+ static \
+ inline \
+ void \
+ name(const char *format, ...) \
+ { \
+ va_list args; \
+ va_start(args, format); \
+ common(stdout, #name, format, args); \
+ va_end(args); \
+ return; \
+ }
+
+static
+inline
+void
+common(FILE *file, const char *prefix, const char *format, va_list args)
+{
+ fprintf(file, "%s \"", prefix);
+ vfprintf(file, format, args);
+ fprintf(file, "\"\n"); // should check for trailing newline
+ return;
+}
+
+DEFINE_TEST_FUNC(PASS);
+DEFINE_TEST_FUNC(XPASS);
+DEFINE_TEST_FUNC(FAIL);
+DEFINE_TEST_FUNC(XFAIL);
+
+DEFINE_TEST_FUNC(UNTESTED);
+DEFINE_TEST_FUNC(UNSUPPORTED);
+DEFINE_TEST_FUNC(UNRESOLVED);
--- /dev/null
+#!/bin/sh
+
+all_archs="ppc ppc64 i386 x86_64"
+
+sysattr()
+{
+ echo " <sysattr name=\"$1\" value=\"$2\" />"
+}
+
+doresults()
+{
+ local ver
+
+ echo "<tests end_time=\"`date +%s`\" start_time=\"$start_time\" comment=\""$comment"\">"
+
+ echo " <sysattrs>"
+ sysattr cctools "`as</dev/null -v 2>&1 |sed 's/.*cctools-//;s/,.*//'`"
+ sysattr hostname "`hostname`"
+ sysattr os "`uname -r`"
+ sysattr platform "`uname -m`"
+ sysattr ld64 "`ld64 -v 2>&1|sed 's/.*PROJECT://;s/ .*//'`"
+ sysattr ld "`ld_classic -v 2>&1|sed 's/.*cctools-//;s/ .*//'`"
+ sysattr gcc "`gcc --version|head -1`"
+ sysattr processor "`uname -p`"
+ sysattr LANG "$LANG"
+ sysattr LC_CTYPE "$LC_CTYPE"
+ sysattr LC_MESSAGES "$LC_MESSAGES"
+ sysattr LC_ALL "$LC_ALL"
+ sysattr TMPDIR "$TMPDIR"
+ sysattr GCC_EXEC_PREFIX "$GCC_EXEC_PREFIX"
+ sysattr COMPILER_PATH "$COMPILER_PATH"
+ sysattr LIBRARY_PATH "$LIBRARY_PATH"
+ sysattr LANG "$LANG"
+ sysattr CPATH "$CPATH"
+ sysattr C_INCLUDE_PATH "$C_INCLUDE_PATH"
+ sysattr CPLUS_INCLUDE_PATH "$CPLUS_INCLUDE_PATH"
+ sysattr OBJC_INCLUDE_PATH "$OBJC_INCLUDE_PATH"
+ sysattr DEPENDENCIES_OUTPUT "$DEPENDENCIES_OUTPUT"
+ sysattr SUNPRO_DEPENDENCIES "$SUNPRO_DEPENDENCIES"
+ echo " </sysattrs>"
+
+ echo "<tools>"
+ echo "<tool name=\"ld\">"
+ echo " <results incomplete=\"0\">"
+ for i in $*
+ do
+ echo " <testgroup name=\"$i\">"
+ cat $i
+ echo " </testgroup>"
+ done
+
+ echo " </results>"
+ echo "</tool>"
+ echo "</tools>"
+ echo "</tests>"
+
+ #rm $*
+}
+
+find_path_to_test_dir()
+{
+ # FIND THE PATH TO THE TEST DIR
+ # SO THAT WE CAN ADD THE BIN DIR INTO
+ # THE SEARCH PATH
+
+ # remember the top level execution dir
+ chmod +x "$0" # just in case
+
+ #add path to $0 into search
+ local savedir
+ savedir=$PWD
+ DIRNAME=`dirname $0`
+ [ -d "$DIRNAME" ] && cd "$DIRNAME"
+ PATH=$PATH:$PWD
+ cd "$savedir"
+
+ chmod +x "$0" # just in case
+ EXECNAME=`which $0`
+ DIRNAME=`dirname "$EXECNAME"`
+ if [ -d "$DIRNAME" ]
+ then
+ TEST_HOME_DIR=`cd "$DIRNAME";pwd`
+ fi
+
+ if [ -z "$TEST_HOME_DIR" ]
+ then
+ TEST_HOME_DIR="$savedir" # Give up and assume current dir
+ fi
+
+ cd "$TEST_HOME_DIR"
+ cd ../build/Release
+
+ PATH="$PWD":"$TEST_HOME_DIR/bin":"$PATH"
+ cd "$savedir"
+}
+
+start_time=`date +%s`
+
+find_path_to_test_dir
+
+# Execute from the location of the script; or if not found the current loc
+[ -d $TEST_HOME_DIR/test-cases ] && cd $TEST_HOME_DIR/test-cases || cd test-cases
+
+rm-stale-test-logs 3 >/dev/null &
+
+make -C ../src # make sure the binaries are available
+
+DATEFORMAT=`date +%F-%H%M | sed -e 's/ //'`
+tmpdir=/tmp/proctor$DATEFORMAT
+
+if ! mkdir $tmpdir >/dev/null 2>/dev/null
+then
+ rm -rf $tmpdir
+ mkdir $tmpdir
+fi
+
+
+linestart=0
+if [ x$1 = x-comment ]
+then
+ shift
+ comment="$1"
+ shift
+fi
+
+find_makefile()
+{
+ local j
+
+ MF=""
+
+ if [ ! -d $1 ]
+ then
+ return 1
+ fi
+
+ for j in Makefile makefile
+ do
+ [ -f $1/$j ] && MF=$j
+ done
+
+ if [ "$NEWTEST" ]
+ then
+ for j in Makefile.newtest makefile.newtest
+ do
+ [ -f $1/$j ] && MF=$j
+ done
+ fi
+
+ [ "$MF" ] && return 0
+ return 1
+}
+
+one_test()
+{
+ echo cwd: $1
+ echo cmd: $1 ARCH="$arch"
+ make -f "$MF" -C $1 ARCH="$arch" 2>$tmpdir/stderr >$tmpdir/stdout
+ result=$?
+ sed 's/^/stdout: /'<$tmpdir/stdout
+ sed 's/^/stderr: /'<$tmpdir/stderr
+ echo exit: $?
+}
+
+if [ "$1" ]
+then
+ i="$1"
+ for arch in $all_archs
+ do
+ rm -f $tmpdir/$arch
+ if find_makefile $i
+ then
+ one_test $i
+ fi
+ #fi | tee -a $tmpdir/raw | ../bin/results-to-xml $linestart>>$tmpdir/$arch
+ linestart=`expr $linestart + 10000`
+ done | tee -a $tmpdir/raw | ../bin/results-to-xml $linestart>>$tmpdir/$arch
+else
+ for arch in $all_archs
+ do
+ rm -f $tmpdir/$arch
+ for i in *
+ do
+ if find_makefile $i
+ then
+ one_test $i
+ fi
+ done | tee -a $tmpdir/raw | ../bin/results-to-xml $linestart>>$tmpdir/$arch
+ linestart=`expr $linestart + 10000`
+ done
+fi
+
+(cd $tmpdir; doresults $all_archs)>$tmpdir/o.xml
+../bin/xmlparser $tmpdir/o.xml >/dev/null
+if [ $? = 0 ]
+then
+ if ! proctor localhost ld import $tmpdir/o.xml
+ then
+ proctor database load failed!
+ fi
+else
+ echo Test results not loaded: internal xml error!
+ exit 1
+fi
--- /dev/null
+#!/bin/sh
+
+unset RC_TRACE_DYLIBS
+unset RC_TRACE_ARCHIVES
+unset LD_TRACE_DYLIBS
+unset LD_TRACE_ARCHIVES
+
+export DYLD_FALLBACK_LIBRARY_PATH=${DYLD_FALLBACK_LIBRARY_PATH}:/Developer/usr/lib
+export MACOSX_DEPLOYMENT_TARGET=10.7
+# cd into test-cases directory
+cd `echo "$0" | sed 's/run-all-unit-tests/test-cases/'`
+
+[ "$PROCTORRUN" ] && exec ../proctor-run
+
+all_archs="x86_64 i386"
+valid_archs="x86_64 i386"
+# only test arm code if iOS platform tools installed
+if [ -d /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs ]
+then
+ all_archs="${all_archs} armv7"
+ valid_archs="${valid_archs} armv7"
+fi
+
+
+# clean first
+../bin/make-recursive.pl clean > /dev/null
+
+mkdir /tmp/$$
+for arch in $all_archs
+do
+ echo ""
+ echo " * * * Running all unit tests for architecture $arch * * *"
+
+ # build architecture
+ [ "$NEWTEST" ] && NT=-newtest
+
+ ../bin/make-recursive$NT.pl ARCH=$arch VALID_ARCHS="$valid_archs" | ../bin/result-filter.pl
+
+ # clean up so svn is happy
+ ../bin/make-recursive.pl ARCH=$arch clean > /dev/null
+
+ echo ""
+done
--- /dev/null
+#!/bin/sh
+
+# cd into test-cases directory
+cd `echo "$0" | sed 's/run-all-unit-tests/test-cases/'`
+
+[ "$PROCTORRUN" ] && exec ../proctor-run
+
+all_archs="ppc ppc64 i386 x86_64"
+
+mkdir /tmp/$$
+for arch in $all_archs
+do
+ echo ""
+ echo " * * * Running all unit tests for architecture $arch * * *"
+
+ # build architecture
+ [ "$NEWTEST" ] && NT=-newtest
+
+ mkdir /tmp/$$
+ ../bin/make-recursive$NT.pl ARCH=$arch VALID_ARCHS="$all_archs" | tee /tmp/$$/raw | ../bin/result-filter.pl | tee /tmp/$$/sum
+
+ # clean up so svn is happy
+ ../bin/make-recursive.pl ARCH=$arch clean > /dev/null
+
+ echo ""
+done
--- /dev/null
+
+all: ../bin/results-to-xml ../bin/xmlparser
+
+../bin/results-to-xml: results-to-xml.cpp
+ g++ -g -O -Wall $< -o ../bin/results-to-xml
+
+../bin/xmlparser:
+ cd xmlparser; xcodebuild -alltargets
+ cp -p xmlparser/build/Release/xmlparser ../bin/.
--- /dev/null
+#include <string>
+#include <sstream>
+#include <iostream>
+
+using namespace std;
+
+#define NELEMENTS(a) (sizeof (a)/sizeof *(a))
+
+#define NO_RESULT (-1)
+#define PASS 1
+#define FAIL 0
+
+#define DBG bhole
+
+void
+bhole(...)
+{
+}
+
+class line_category
+{
+public:
+ const char *key;
+ char line[99999];
+ void (*test)(line_category &);
+ int test_result;
+} lc;
+
+void
+deft(line_category &l)
+{
+ l.test_result = PASS;
+}
+
+void
+pass_fail(line_category &l)
+{
+ if(FAIL!=l.test_result)
+ l.test_result = strnstr(l.line, "FAIL", 4)? FAIL: PASS;
+}
+
+void
+stderr_output(line_category &l)
+{
+ if(FAIL==l.test_result)
+ return;
+
+ if(l.line[0])
+ l.test_result = FAIL;
+}
+
+void
+exit_test(line_category &l)
+{
+ if(!atoi(l.line)) {
+ DBG("exit_test(%s)==%d\n", l.line, atoi(l.line));
+ l.test_result = PASS;
+ }
+}
+
+#define STDOUT "stdout: "
+#define STDERR "stderr: "
+#define CWD "cwd: "
+#define CMD "cmd: "
+#define SEXIT "exit: "
+line_category line_categories[] = {
+ { CWD, "" , deft, NO_RESULT}, /* must be first */
+ { CMD, "", deft, NO_RESULT},
+ { STDOUT, "", pass_fail, NO_RESULT},
+ { STDERR, "", stderr_output, NO_RESULT },
+ { SEXIT, "", exit_test, NO_RESULT },
+};
+
+static line_category no_line_category = { "none", "no test", deft, NO_RESULT };
+
+line_category &
+retrieve(line_category &l, const char *s)
+{
+ unsigned j;
+ line_category *lp = &l;
+ //int final_result = PASS;
+
+ for(j=0; j<NELEMENTS(line_categories); ++j,++lp) {//TODO: remove NELEMENTS
+ if(!strcmp(lp->key, s)) {
+ char *p;
+
+ for(p=(char *)lp->line; *p; ++p) {
+ switch(*p) {
+ case '\0':
+ break;
+ case '"':
+ case '<':
+ *p = ' ';
+ // fall thru
+ default:
+ continue;
+ }
+ }
+DBG("FOUND line_categories[j].line==%s\n", lp->line);
+ return line_categories[j];
+ }
+ }
+
+ return no_line_category;
+}
+
+void
+xml_string_print(FILE *strm, const char *s)
+{
+ fputc('"', strm);
+ for( ; ; ++s) {
+ switch(*s) {
+ case '\0':
+ break;
+ case '&':
+ fputs("&", strm);
+ continue;
+ default:
+ fputc(*s, strm);
+ continue;
+ }
+ break;
+ }
+ fputc('"', strm);
+}
+
+//
+// FAIL if stderr non-zero
+// FAIL if stdout=="FAIL"
+// UNRESOLVED if make exit non-zero
+// PASS otherwise
+//
+
+static int cnt;
+void
+dump_test(void)
+{
+ unsigned j;
+ int final_result = PASS;
+
+ for(j=0; j<NELEMENTS(line_categories); ++j) {
+ if(line_categories[j].line[0]) {
+ line_categories[j].line[strlen(line_categories[j].line)-1] = '\0';
+ DBG("%s%s RESULT %d\n"
+ , line_categories[j].key
+ , line_categories[j].line
+ , line_categories[j].test_result
+ );
+
+ if(PASS==final_result) {
+ final_result = line_categories[j].test_result;
+ if(NO_RESULT==line_categories[j].test_result) {
+ final_result = NO_RESULT;
+ } else if(FAIL==line_categories[j].test_result) {
+ final_result = FAIL;
+ }
+ }
+ }
+ }
+
+ printf("<test name=");
+ xml_string_print(stdout, retrieve(line_categories[0], CMD).line);
+ printf(" result=\"");
+ if(NO_RESULT==final_result) {
+ printf("UNRESOLVED");
+ } else if(FAIL==final_result) {
+ printf("FAIL");
+ } else {
+ printf("PASS");
+ }
+ printf("\" ");
+
+ char *s = retrieve(line_categories[0], CWD).line;
+ if(*s) {
+ char detail[9999];
+ char fn[9999];
+ FILE *strm;
+
+ strncpy(fn, s, sizeof fn);
+ strncat(fn, "/comment.txt", sizeof fn);
+ strm = fopen(fn, "r");
+ if(strm) {
+ if(fgets(detail, -1+sizeof detail, strm)) {
+ detail[strlen(detail)-1] = '\0';
+ printf("detail=");
+ xml_string_print(stdout, detail);
+ }
+ }
+ }
+ printf(">\n");
+
+ printf(" <diagnostics>\n");
+ s = retrieve(line_categories[0], STDERR).line;
+ if(*s) {
+ printf(" <diagnostic line=\"%d\" message=", ++cnt);
+ xml_string_print(stdout, s);
+ printf(" severity=\"ERROR\"/>\n");
+ }
+#if 1
+ s = retrieve(line_categories[0], STDOUT).line;
+ if(*s) {
+ printf(" <diagnostic line=\"%d\" message=", ++cnt);
+ xml_string_print(stdout, s);
+ printf(" severity=\"note\"/>\n");
+ }
+#endif
+ printf(" </diagnostics>\n");
+ printf("</test>\n\n");
+
+ for(j=0; j<NELEMENTS(line_categories); ++j) {
+ line_categories[j].line[0] = '\0';
+ line_categories[j].test_result = NO_RESULT;
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int firsttime = 1;
+
+
+ if(argc>1)
+ cnt = atoi(argv[1]);
+
+ for(;;) {
+ char line[99999];
+ int i;
+
+ line[0] = '\0';
+ fgets(line, sizeof line, stdin);
+ if(feof(stdin)) {
+ dump_test();
+ break;
+ }
+
+ for(i=0; ; ++i) {
+ size_t len = strlen(line_categories[i].key);
+
+ //DBG("strnstr(%s, %s, %u)\n", line, line_categories[i].key, len);
+ if(strnstr(line, line_categories[i].key, len)) {
+ if(firsttime)
+ firsttime = 0;
+ else if(0==i)
+ dump_test();
+
+ char *lp = &line[len];
+ //DBG("%s%s", line_categories[i].key, lp);
+ strncpy(line_categories[i].line, lp, sizeof line_categories[i].line);
+ line_categories[i].test(line_categories[i]);
+ break;
+ }
+
+ if(i==NELEMENTS(line_categories)-1) {
+ DBG("BADLINE:%s", line);
+ break;
+ }
+ }
+ }
+ return 0;
+}
--- /dev/null
+.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.\r
+.\"See Also:\r
+.\"man mdoc.samples for a complete listing of options\r
+.\"man mdoc for the short list of editing options\r
+.\"/usr/share/misc/mdoc.template\r
+.Dd 9/18/06 \" DATE \r
+.Dt xmlparser 1 \" Program name and manual section number \r
+.Os Darwin\r
+.Sh NAME \" Section Header - required - don't modify \r
+.Nm xmlparser,\r
+.\" The following lines are read in generating the apropos(man -k) database. Use only key\r
+.\" words here as the database is built based on the words here and in the .ND line. \r
+.Nm Other_name_for_same_program(),\r
+.Nm Yet another name for the same program.\r
+.\" Use .Nm macro to designate other names for the documented program.\r
+.Nd This line parsed for whatis database.\r
+.Sh SYNOPSIS \" Section Header - required - don't modify\r
+.Nm\r
+.Op Fl abcd \" [-abcd]\r
+.Op Fl a Ar path \" [-a path] \r
+.Op Ar file \" [file]\r
+.Op Ar \" [file ...]\r
+.Ar arg0 \" Underlined argument - use .Ar anywhere to underline\r
+arg2 ... \" Arguments\r
+.Sh DESCRIPTION \" Section Header - required - don't modify\r
+Use the .Nm macro to refer to your program throughout the man page like such:\r
+.Nm\r
+Underlining is accomplished with the .Ar macro like this:\r
+.Ar underlined text .\r
+.Pp \" Inserts a space\r
+A list of items with descriptions:\r
+.Bl -tag -width -indent \" Begins a tagged list \r
+.It item a \" Each item preceded by .It macro\r
+Description of item a\r
+.It item b\r
+Description of item b\r
+.El \" Ends the list\r
+.Pp\r
+A list of flags and their descriptions:\r
+.Bl -tag -width -indent \" Differs from above in tag removed \r
+.It Fl a \"-a flag as a list item\r
+Description of -a flag\r
+.It Fl b\r
+Description of -b flag\r
+.El \" Ends the list\r
+.Pp\r
+.\" .Sh ENVIRONMENT \" May not be needed\r
+.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1\r
+.\" .It Ev ENV_VAR_1\r
+.\" Description of ENV_VAR_1\r
+.\" .It Ev ENV_VAR_2\r
+.\" Description of ENV_VAR_2\r
+.\" .El \r
+.Sh FILES \" File used or created by the topic of the man page\r
+.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact\r
+.It Pa /usr/share/file_name\r
+FILE_1 description\r
+.It Pa /Users/joeuser/Library/really_long_file_name\r
+FILE_2 description\r
+.El \" Ends the list\r
+.\" .Sh DIAGNOSTICS \" May not be needed\r
+.\" .Bl -diag\r
+.\" .It Diagnostic Tag\r
+.\" Diagnostic informtion here.\r
+.\" .It Diagnostic Tag\r
+.\" Diagnostic informtion here.\r
+.\" .El\r
+.Sh SEE ALSO \r
+.\" List links in ascending order by section, alphabetically within a section.\r
+.\" Please do not reference files that do not exist without filing a bug report\r
+.Xr a 1 , \r
+.Xr b 1 ,\r
+.Xr c 1 ,\r
+.Xr a 2 ,\r
+.Xr b 2 ,\r
+.Xr a 3 ,\r
+.Xr b 3 \r
+.\" .Sh BUGS \" Document known, unremedied bugs \r
+.\" .Sh HISTORY \" Document history if command behaves in a unique manner
\ No newline at end of file
--- /dev/null
+#import <Foundation/Foundation.h>\r
+\r
+int main(int argc, char *argv[]) {\r
+ [[NSAutoreleasePool alloc] init];\r
+\r
+ if(argc != 2) {\r
+ NSLog(@"Usage: %s path-to-XML\n", argv[0]);\r
+ return 1;\r
+ }\r
+ NSString *path = [NSString stringWithUTF8String:argv[1]];\r
+\r
+ NSError *err = nil;\r
+ NSXMLDocument *doc = [[NSXMLDocument alloc]\r
+ initWithContentsOfURL:[NSURL\r
+ fileURLWithPath:path]\r
+ options:0\r
+ error:&err];\r
+ if(err) {\r
+ NSLog(@"ERROR: %@", err);\r
+ return 1;\r
+ } else {\r
+ NSLog(@"Parsed!");\r
+ return 0;\r
+ }\r
+}\r
--- /dev/null
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 8DD76F9A0486AA7600D96B5E /* xmlparser.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* xmlparser.m */; settings = {ATTRIBUTES = (); }; };
+ 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
+ 8DD76F9F0486AA7600D96B5E /* xmlparser.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6859EA3029092ED04C91782 /* xmlparser.1 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 8DD76F9E0486AA7600D96B5E /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ 8DD76F9F0486AA7600D96B5E /* xmlparser.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 08FB7796FE84155DC02AAC07 /* xmlparser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = xmlparser.m; sourceTree = "<group>"; };
+ 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+ 32A70AAB03705E1F00C91783 /* xmlparser_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xmlparser_Prefix.pch; sourceTree = "<group>"; };
+ 8DD76FA10486AA7600D96B5E /* xmlparser */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = xmlparser; sourceTree = BUILT_PRODUCTS_DIR; };
+ C6859EA3029092ED04C91782 /* xmlparser.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = xmlparser.1; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8DD76F9B0486AA7600D96B5E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 08FB7794FE84155DC02AAC07 /* xmlparser */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB7795FE84155DC02AAC07 /* Source */,
+ C6859EA2029092E104C91782 /* Documentation */,
+ 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
+ 1AB674ADFE9D54B511CA2CBB /* Products */,
+ );
+ name = xmlparser;
+ sourceTree = "<group>";
+ };
+ 08FB7795FE84155DC02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 32A70AAB03705E1F00C91783 /* xmlparser_Prefix.pch */,
+ 08FB7796FE84155DC02AAC07 /* xmlparser.m */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB779EFE84155DC02AAC07 /* Foundation.framework */,
+ );
+ name = "External Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 1AB674ADFE9D54B511CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8DD76FA10486AA7600D96B5E /* xmlparser */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ C6859EA2029092E104C91782 /* Documentation */ = {
+ isa = PBXGroup;
+ children = (
+ C6859EA3029092ED04C91782 /* xmlparser.1 */,
+ );
+ name = Documentation;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 8DD76F960486AA7600D96B5E /* xmlparser */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "xmlparser" */;
+ buildPhases = (
+ 8DD76F990486AA7600D96B5E /* Sources */,
+ 8DD76F9B0486AA7600D96B5E /* Frameworks */,
+ 8DD76F9E0486AA7600D96B5E /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = xmlparser;
+ productInstallPath = "$(HOME)/bin";
+ productName = xmlparser;
+ productReference = 8DD76FA10486AA7600D96B5E /* xmlparser */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 08FB7793FE84155DC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "xmlparser" */;
+ hasScannedForEncodings = 1;
+ mainGroup = 08FB7794FE84155DC02AAC07 /* xmlparser */;
+ projectDirPath = "";
+ targets = (
+ 8DD76F960486AA7600D96B5E /* xmlparser */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 8DD76F990486AA7600D96B5E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8DD76F9A0486AA7600D96B5E /* xmlparser.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB927508733DD40010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = xmlparser_Prefix.pch;
+ INSTALL_PATH = "$(HOME)/bin";
+ PRODUCT_NAME = xmlparser;
+ ZERO_LINK = YES;
+ };
+ name = Debug;
+ };
+ 1DEB927608733DD40010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = (
+ ppc,
+ i386,
+ );
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = xmlparser_Prefix.pch;
+ INSTALL_PATH = "$(HOME)/bin";
+ PRODUCT_NAME = xmlparser;
+ };
+ name = Release;
+ };
+ 1DEB927908733DD40010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ ZERO_LINK = YES;
+ };
+ name = Debug;
+ };
+ 1DEB927A08733DD40010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "xmlparser" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB927508733DD40010E9CD /* Debug */,
+ 1DEB927608733DD40010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "xmlparser" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB927908733DD40010E9CD /* Debug */,
+ 1DEB927A08733DD40010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
--- /dev/null
+//
+// Prefix header for all source files of the 'xmlparser' target in the 'xmlparser' project.
+//
+
+#ifdef __OBJC__
+ #import <Foundation/Foundation.h>
+#endif
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that -O2 optimization fails when trying to make a long 16-byte aligned.
+#
+
+run: all
+
+all:
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -arch ${ARCH} -c -O2 tl_test2.c -o tl_test2-${ARCH}.o
+
+ # verify that the alignment is correct in the .o
+ ${OBJECTDUMP} -only _ai -align -no_content tl_test2-${ARCH}.o|${FAIL_IF_ERROR} grep '0 mod 16' >/dev/null
+
+ # now verify the executable
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -arch ${ARCH} -O2 tl_test2-${ARCH}.o -o tl_test2-${ARCH}
+ ${FAIL_IF_ERROR} sh -c "nm tl_test2-${ARCH}|grep '0 D _ai' >/dev/null"
+ ${PASS_IFF_GOOD_MACHO} tl_test2-${ARCH}
+
+clean:
+ rm -rf tl_test2-*
--- /dev/null
+Test 16 byte alignment with -O2 optimization. Radar #4662185
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+
+int i = 1;
+int ai __attribute__ ((aligned (16))) = 1;
+
+int main() {
+
+ long addr = (long)&ai;
+ i = ai;
+
+ if (addr & 0xf) {
+ printf("failed: ai = %p\n", (void *)addr);
+ return 1;
+ }
+
+ printf("passed: ai = %p\n", (void *)addr);
+ return 0;
+
+}
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a hello-world program with no errors (or crashes)
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ mkdir -p hide
+ libtool foo.o -static -o hide/libfoo.a
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ ${LD} main.o -lfoo -Lhide -r -o mainfoo.o
+ ${LD} main.o -lfoo -L hide -r -o mainfoo.o
+ ${PASS_IFF} true
+
+clean:
+ rm -rf foo.o hide main.o mainfoo.o
--- /dev/null
+
+int foo() { return 0; }
--- /dev/null
+
+extern int foo();
+
+int main()
+{
+ foo();
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Validate linker processing of absolute symbols
+#
+
+all:
+ ${CC} ${CCFLAGS} main.c -static -c
+ ${CC} ${CCFLAGS} abs.s -static -c
+ ${LD} -arch ${ARCH} -static main.o abs.o -e _main -o main -new_linker -macosx_version_min 10.6
+ ${LD} -arch ${ARCH} -static -r main.o abs.o -o all.o -new_linker
+ nm -m all.o | grep _myAbs | grep absolute | ${FAIL_IF_EMPTY}
+ ${LD} -arch ${ARCH} -static all.o -e _main -o main2 -new_linker -macosx_version_min 10.6
+ ${PASS_IFF_GOOD_MACHO} main2
+
+clean:
+ rm -rf main.o abs.o all.o main main2
--- /dev/null
+
+ .globl _myAbs
+#if __LP64__
+ _myAbs = 0x102345678
+#else
+ _myAbs = 0xfe000000
+#endif
--- /dev/null
+
+extern int* myAbs;
+
+int main() { return *myAbs; }
+
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to verify that added aliases to a .o
+# file via the command line is the same as doing so in the sources.
+# The ObjectDump utility is used
+# dump a "canonical" textual representation of a .o file.
+# The before and after .o files are then diff'ed.
+# No differences means this test passes
+#
+
+run: all
+
+all:
+ ${CC} ${ASMFLAGS} aliases.s -DALIASES=1 -c -o aliases.source.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases.source.${ARCH}.o > aliases.source.${ARCH}.o.dump
+
+ ${CC} ${ASMFLAGS} aliases.s -c -o aliases.tmp.${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} aliases.tmp.${ARCH}.o
+
+ ${LD} -arch ${ARCH} -r -keep_private_externs aliases.tmp.${ARCH}.o -alias _foo _fooalt -alias _foo _fooalt2 -alias _hidden _glob -o aliases.cmdline.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases.cmdline.${ARCH}.o > aliases.cmdline.${ARCH}.o.dump
+ ${FAIL_IF_ERROR} diff aliases.source.${ARCH}.o.dump aliases.cmdline.${ARCH}.o.dump
+
+ ${LD} -arch ${ARCH} -r -keep_private_externs aliases.tmp.${ARCH}.o -alias_list aliases.txt -o aliases.file.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases.file.${ARCH}.o > aliases.file.${ARCH}.o.dump
+ ${PASS_IFF} diff aliases.source.${ARCH}.o.dump aliases.file.${ARCH}.o.dump
+
+clean:
+ rm -rf *.o *.dump
--- /dev/null
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+ .text
+ .align 4
+
+_temp: nop
+ nop
+
+ .globl _foo
+_foo: nop
+ nop
+
+ .globl _hidden
+ .private_extern _hidden
+_hidden: nop
+ nop
+
+#if ALIASES
+ .globl _fooalt
+ .globl _fooalt2
+ .globl _glob
+/* this should make an alias "_fooalt" for "_foo" */
+_fooalt = _foo
+_fooalt2 = _foo
+_glob = _hidden
+#endif
+
+_bar: nop
+ nop
+
+
+ .subsections_via_symbols
\ No newline at end of file
--- /dev/null
+_foo _fooalt
+# comment
+_foo _fooalt2
+
+_hidden _glob
+
+
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to verify a .o file with aliases
+# can round trip through ld -r correctly. The ObjectDump utility is used
+# dump a "canonical" textual representation of a .o file.
+# The before and after .o files are then diff'ed.
+# No differences means this test passes
+#
+
+run: all
+
+all:
+ ${CC} ${ASMFLAGS} aliases.s -c -o aliases.${ARCH}.o
+ ${LD} -arch ${ARCH} -r -keep_private_externs aliases.${ARCH}.o -o aliases-r.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases.${ARCH}.o > aliases.${ARCH}.o.dump
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases-r.${ARCH}.o > aliases-r.${ARCH}.o.dump
+ ${PASS_IFF} diff aliases.${ARCH}.o.dump aliases-r.${ARCH}.o.dump
+
+clean:
+ rm -rf *.o *.dump
--- /dev/null
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+ .text
+ .align 4
+
+_temp: nop
+ nop
+
+ .globl _foo
+_foo: nop
+ nop
+
+ .globl _fooalt
+ .globl _fooalt2
+/* this should make an alias "_fooalt" for "_foo" */
+_fooalt = _foo
+_fooalt2 = _foo
+
+_bar: nop
+ nop
+
+
+ .subsections_via_symbols
\ No newline at end of file
--- /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
+ ${FAIL_IF_BAD_MACHO} foo.${ARCH}.dylib
+ nm foo.${ARCH}.dylib | grep "3 d _b" | ${PASS_IFF_STDIN}
+
+clean:
+ rm -rf *.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
+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.
--- /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
+
+#
+# Test the we set the stack execution bit properly.
+#
+
+run: all
+
+all:
+
+# Test with the flag
+ ${CC} ${CCFLAGS} foo.c -o foo-${ARCH} -Wl,-allow_stack_execute
+ ${FAIL_IF_BAD_MACHO} foo-${ARCH}
+ ${OTOOL} -hv foo-${ARCH} | grep ALLOW_STACK_EXECUTION | ${FAIL_IF_EMPTY}
+ rm -f foo-${ARCH}
+
+# Test without the flag
+ ${CC} ${CCFLAGS} foo.c -o foo-${ARCH}
+ ${FAIL_IF_BAD_MACHO} foo-${ARCH}
+ ${OTOOL} -hv foo-${ARCH} | grep ALLOW_STACK_EXECUTION | ${PASS_IFF_EMPTY}
+
+clean:
+ rm -rf foo-*
--- /dev/null
+Test the we set the stack execution bit properly.
--- /dev/null
+int main (void)
+{
+ return 0;
+}
--- /dev/null
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test the we set the data execute bit for i386
+#
+
+run: run-${ARCH}
+
+run-x86_64:
+ ${PASS_IFF} true
+
+run-armv6:
+ ${PASS_IFF} true
+
+run-armv7:
+ ${PASS_IFF} true
+
+run-ppc:
+ ${PASS_IFF} true
+
+
+run-i386:
+ # Test with the flag
+ ${CC} ${CCFLAGS} main.c -o main-allow -Wl,-allow_heap_execute
+ ${FAIL_IF_BAD_MACHO} main-allow
+ ${OTOOL} -hv main-allow | grep MH_NO_HEAP_EXECUTION | ${FAIL_IF_STDIN}
+ # Test without the flag
+ ${CC} ${CCFLAGS} main.c -o main
+ ${OTOOL} -hv main | grep MH_NO_HEAP_EXECUTION | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main main-allow
--- /dev/null
+int main(void)
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that the -allowable_client and -client options
+# work when linking against subframeworks.
+#
+
+run: all
+
+all:
+# build with two allowable_clients
+ ${CC} ${CCFLAGS} -dynamiclib -umbrella foo -allowable_client bar -allowable_client baz foo.c -o foo.${ARCH}.dylib
+ ${FAIL_IF_BAD_MACHO} foo.${ARCH}.dylib
+
+# test that -o works
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.${ARCH}.dylib foo.${ARCH}.dylib
+ ${FAIL_IF_BAD_MACHO} libbar.${ARCH}.dylib
+
+# test that a framework style output works
+ mkdir -p bar.framework
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o bar.framework/bar foo.${ARCH}.dylib
+ ${FAIL_IF_BAD_MACHO} bar.framework/bar
+
+# test that second -o works
+ ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.${ARCH}.dylib foo.${ARCH}.dylib
+ ${FAIL_IF_BAD_MACHO} foo.${ARCH}.dylib
+
+# test that -o and -install_name works with install_name as an allowable
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o temp.${ARCH}.dylib -install_name /tmp/libbar.${ARCH}.dylib foo.${ARCH}.dylib
+ ${FAIL_IF_BAD_MACHO} temp.${ARCH}.dylib
+
+# test that -install_name works with variant name
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o temp.${ARCH}.dylib -install_name /tmp/libbar_profile foo.${ARCH}.dylib
+ ${FAIL_IF_BAD_MACHO} temp.${ARCH}.dylib
+
+# test that -o and -install_name fails with install_name different than allowable
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} -dynamiclib bar.c -o bar.${ARCH}.dylib -install_name /tmp/fail.${ARCH}.dylib foo.${ARCH}.dylib >& fail.log
+
+# test that a bundle and no client_name fails
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} -bundle bar.c -o temp.${ARCH}.bundle foo.${ARCH}.dylib >& fail.log
+
+# test that a bundle and an allowable client_name passes
+ ${CC} ${CCFLAGS} -bundle bar.c -client_name bar -o bar.${ARCH}.bundle foo.${ARCH}.dylib
+ ${FAIL_IF_BAD_MACHO} bar.${ARCH}.bundle
+
+# test umbrella can link against subs
+ mkdir -p foo.framework
+ ${CC} ${CCFLAGS} -dynamiclib foo.${ARCH}.dylib -o foo.framework/foo
+ ${FAIL_IF_BAD_MACHO} foo.framework/foo
+
+# test umbrella variant can link against subs
+ mkdir -p foo.framework
+ ${CC} ${CCFLAGS} -dynamiclib foo.${ARCH}.dylib -o foo.framework/foo_debug -install_name /path/foo.framework/foo_debug
+ ${FAIL_IF_BAD_MACHO} foo.framework/foo_debug
+
+# test sibling in umbrella can link against subs
+ ${CC} ${CCFLAGS} -dynamiclib main.c -umbrella foo foo.${ARCH}.dylib -o ./main.dylib
+ ${FAIL_IF_BAD_MACHO} main.dylib
+
+# test anyone can link against umbrella
+ ${CC} ${CCFLAGS} main.c -o main.${ARCH} -framework foo -F.
+ ${FAIL_IF_BAD_MACHO} main.${ARCH}
+
+# test that an executable and no client_name fails
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -o main.${ARCH} foo.${ARCH}.dylib >& fail.log
+
+# test that an executable and an allowable client_name passes
+ ${CC} ${CCFLAGS} main.c -o main.${ARCH} -client_name bar foo.${ARCH}.dylib
+ ${PASS_IFF_GOOD_MACHO} main.${ARCH}
+
+# test that a regular dylib can be made unlinkable by using -allowable_client
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -allowable_client '!' -o unlinkable_foo.${ARCH}.dylib
+ ${FAIL_IF_BAD_MACHO} unlinkable_foo.${ARCH}.dylib
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -o main.${ARCH} unlinkable_foo.${ARCH}.dylib >& fail.log
+
+# test that a regular dylib can be made linkable by only specially named clients
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -allowable_client special -o restrictive_foo.${ARCH}.dylib
+ ${FAIL_IF_BAD_MACHO} restrictive_foo.${ARCH}.dylib
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -o main.${ARCH} restrictive_foo.${ARCH}.dylib >& fail.log
+ ${CC} ${CCFLAGS} main.c -o main.${ARCH} -client_name special restrictive_foo.${ARCH}.dylib
+ ${FAIL_IF_BAD_MACHO} main.${ARCH}
+
+# print final pass
+ ${PASS_IFF_GOOD_MACHO} foo.${ARCH}.dylib
+
+clean:
+ rm -rf *.dylib *.bundle main.???* fail.log *.framework
--- /dev/null
+extern int foo ();
+
+int bar (void)
+{
+ return foo();
+}
--- /dev/null
+extern int foo ();
+
+int bar (void)
+{
+ return foo();
+}
--- /dev/null
+Test that the -allowable_client and -client options work when linking against subframeworks.
--- /dev/null
+int foo (void)
+{
+ return 1;
+}
--- /dev/null
+extern int foo ();
+
+int main (void)
+{
+ return foo();
+}
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# The point of this test is to check that -ObjC loads all (and only)
+# .o files that contain Objective-C code.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.m -c -o foo.o
+ ${CC} ${CCFLAGS} bar.m -c -o bar.o
+ libtool -static bar.o foo.o -o libfoo.a
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.m libfoo.a -o main -framework Foundation -dead_strip -Wl,-unexported_symbols_list,main.nexp 2>main.log
+ grep Foobar main.log | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_SUCCESS} true
+
+clean:
+ rm -rf foo.o bar.o libfoo.a main.log
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foobar : NSObject
+@end
+
+void other()
+{
+ [[Foobar alloc] init];
+}
+
+void bar()
+{
+}
+
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+@end
+
+@implementation Foo
+@end
+
--- /dev/null
+#include <stdio.h>
+
+extern void bar();
+
+int main()
+{
+ bar();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to check that -ObjC loads all (and only)
+# .o files that contain Objective-C code.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.m -c -o foo-${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} foo-${ARCH}.o
+ ${CC} ${CCFLAGS} bar.c -c -o bar-${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} bar-${ARCH}.o
+ ${CC} ${CCFLAGS} baz.m -c -o baz-${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} baz-${ARCH}.o
+ libtool -static foo-${ARCH}.o bar-${ARCH}.o baz-${ARCH}.o -o libfoobarbaz-${ARCH}.a
+ ${CC} ${CCFLAGS} main.c -lfoobarbaz-${ARCH} -L. -o main-${ARCH} -ObjC -framework Foundation -framework CoreFoundation
+ ${FAIL_IF_BAD_MACHO} main-${ARCH}
+ nm main-${ARCH} | grep "_bar" | ${FAIL_IF_STDIN}
+ nm main-${ARCH} | grep "_Foo" | ${FAIL_IF_EMPTY}
+ nm main-${ARCH} | grep "_Baz" | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main-${ARCH}
+
+clean:
+ rm -rf main-* *.o *.a
--- /dev/null
+
+int bar() { return 0; }
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Baz : NSObject
+@end
+
+@implementation Baz
+@end
+
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+@end
+
+@implementation Foo
+@end
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that .o files
+# can be found in archives.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo-${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} foo-${ARCH}.o
+ ${CC} ${CCFLAGS} bar.c -c -o bar-${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} bar-${ARCH}.o
+ libtool -static foo-${ARCH}.o bar-${ARCH}.o -o libfoobar-${ARCH}.a
+ ${CC} ${CCFLAGS} main.c -lfoobar-${ARCH} -L. -o main-${ARCH}
+ ${FAIL_IF_BAD_MACHO} main-${ARCH}
+ nm main-${ARCH} | grep "_bar" | ${PASS_IFF_EMPTY}
+ ${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoobar-${ARCH}.a -o main-${ARCH}
+ ${FAIL_IF_BAD_MACHO} main-${ARCH}
+
+clean:
+ rm -rf main-* *.o *.a
--- /dev/null
+int bar() { return 0; }
--- /dev/null
+The point of this test is a sanity check that .o files can be found in archives.
--- /dev/null
+int foo() { return 1; }
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+extern int foo();
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ return foo();
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ia an archive
+# is listed multiple times, the extras are ignored.
+# This is done in some makefiles because the traditional linker
+# semantics is to only search an archive once.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo-${ARCH}.o
+ ${CC} ${CCFLAGS} bar.c -c -o bar-${ARCH}.o
+ libtool -static foo-${ARCH}.o bar-${ARCH}.o -o libfoobar-${ARCH}.a
+ ${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoobar-${ARCH}.a -lfoobar-${ARCH} -L. -o main-${ARCH}
+ ${FAIL_IF_BAD_MACHO} main-${ARCH}
+ ${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoobar-${ARCH}.a ./libfoobar-${ARCH}.a -L. -o main-${ARCH}
+ ${PASS_IFF_GOOD_MACHO} main-${ARCH}
+
+clean:
+ rm -rf main-* *.o *.a
--- /dev/null
+int bar() { return 0; }
--- /dev/null
+int foo() { return 1; }
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+extern int foo();
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ return foo();
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check the -force_load option.
+# <rdar://problem/3738966> Need a linker option to load all objects from one library
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ ${CC} ${CCFLAGS} bar.c -c -o bar.o
+ ${CC} ${CCFLAGS} baz.c -c -o baz.o
+ ${CC} ${CCFLAGS} bat.c -c -o bat.o
+ libtool -static foo.o bar.o -o libfoobar.a
+ libtool -static baz.o bat.o -o libbazbat.a
+ ${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoobar.a libbazbat.a -o main -Wl,-why_load
+ nm main | grep "_bar" | ${FAIL_IF_EMPTY}
+ nm main | grep "_foo" | ${FAIL_IF_EMPTY}
+ nm main | grep "_baz" | ${FAIL_IF_STDIN}
+ nm main | grep "_bat" | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main *.o *.a
--- /dev/null
+void bar() {}
--- /dev/null
+void bat() {}
--- /dev/null
+void baz() {}
+
--- /dev/null
+void foo() {}
--- /dev/null
+
+int main()
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that objc files loaded from archives set image info
+#
+
+IMAGE_INFO = "__image_info"
+
+ifeq ($(ARCH),x86_64)
+ IMAGE_INFO = "__objc_imageinfo"
+endif
+ifeq (${FILEARCH},arm)
+ IMAGE_INFO = "__objc_imageinfo"
+endif
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.m -c -o main.o
+ libtool -static main.o -o libmain.a
+ ${CC} ${CCFLAGS} libmain.a -o main -framework Foundation
+ size -l main | grep ${IMAGE_INFO} | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main.o libmain.a main
--- /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 <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+@end
+
+@implementation Foo
+@end
+
+int main()
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check the order of functions from archives.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ ${CC} ${CCFLAGS} foo2.c -c -o foo2.o
+ ${CC} ${CCFLAGS} foo3.c -c -o foo3.o
+ ${CC} ${CCFLAGS} bar.c -c -o bar.o
+ ${CC} ${CCFLAGS} bar2.c -c -o bar2.o
+ ${CC} ${CCFLAGS} bar3.c -c -o bar3.o
+ libtool -static foo.o foo2.o foo3.o -o libfoo.a
+ libtool -static bar3.o bar2.o bar.o -o libbar.a
+ ${CC} ${CCFLAGS} main.c -lbar -lfoo -L. -o main -Wl,-map,main.map
+ grep anon main.map | awk '{ print $$4}' > main-actual.txt
+ sort main-actual.txt > main-should.txt
+ diff main-actual.txt main-should.txt
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf *.o *.a main main.map main*.txt
--- /dev/null
+int bar() { return 0; }
+
+__attribute__((constructor))
+void bar_init() { }
--- /dev/null
+int bar2() { return 0; }
+
+__attribute__((constructor))
+void bar2_init() { }
--- /dev/null
+int bar3() { return 0; }
+
+__attribute__((constructor))
+void bar3_init() { }
--- /dev/null
+int foo() { return 1; }
+
+__attribute__((constructor))
+void foo_init() { }
--- /dev/null
+int foo2() { return 1; }
+
+__attribute__((constructor))
+void foo2_init() { }
--- /dev/null
+int foo3() { return 1; }
+
+__attribute__((constructor))
+void foo3_init() { }
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+extern int foo();
+extern int foo2();
+extern int foo3();
+extern int bar();
+extern int bar2();
+extern int bar3();
+
+int main()
+{
+ foo();
+ bar();
+ foo2();
+ bar2();
+ foo3();
+ bar3();
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check the order of functions from archives.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ ${CC} ${CCFLAGS} foo2.c -c -o foo2.o
+ ${CC} ${CCFLAGS} foo3.c -c -o foo3.o
+ ${CC} ${CCFLAGS} bar.c -c -o bar.o
+ ${CC} ${CCFLAGS} bar2.c -c -o bar2.o
+ ${CC} ${CCFLAGS} bar3.c -c -o bar3.o
+ libtool -static foo.o foo2.o foo3.o -o libfoo.a
+ libtool -static bar3.o bar2.o bar.o -o libbar.a
+ ${CC} ${CCFLAGS} main.c -lbar -lfoo -L. -o main
+ nm -njg main | egrep 'foo|bar' > found.order
+ diff found.order expected.order
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main *.o *.a found.order
--- /dev/null
+int bar() { return 0; }
--- /dev/null
+int bar2() { return 0; }
--- /dev/null
+int bar3() { return 0; }
--- /dev/null
+_bar3
+_bar2
+_bar
+_foo
+_foo2
+_foo3
--- /dev/null
+int foo() { return 1; }
--- /dev/null
+int foo2() { return 1; }
--- /dev/null
+int foo3() { return 1; }
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+extern int foo();
+extern int foo2();
+extern int foo3();
+extern int bar();
+extern int bar2();
+extern int bar3();
+
+int main()
+{
+ foo();
+ bar();
+ foo2();
+ bar2();
+ foo3();
+ bar3();
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2012 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to check that -ObjC loads all (and only)
+# .o files that contain Objective-C code that has gone through ld -r.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.m -c -o foo.o
+ ${LD} -r -arch ${ARCH} foo.o -o foo-r.o
+ ${CC} ${CCFLAGS} bar.c -c -o bar.o
+ ${LD} -r -arch ${ARCH} bar.o -o bar-r.o
+ ${CC} ${CCFLAGS} baz.m -c -o baz.o
+ ${LD} -r -arch ${ARCH} baz.o -o baz-r.o
+ ${CC} ${CCFLAGS} cat.m -c -o cat.o
+ ${LD} -r -arch ${ARCH} cat.o -o cat-r.o
+ libtool -static foo-r.o bar-r.o baz-r.o cat-r.o -o liball.a
+ ${CC} ${CCFLAGS} main.c liball.a -o main -ObjC -framework Foundation -framework CoreFoundation
+ ${FAIL_IF_BAD_MACHO} main
+ nm main | grep "_bar" | ${FAIL_IF_STDIN}
+ nm main | grep "_Foo" | ${FAIL_IF_EMPTY}
+ nm main | grep "_Baz" | ${FAIL_IF_EMPTY}
+ nm main | grep "_mycatfunc" | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main *.o *.a
--- /dev/null
+
+int bar() { return 0; }
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Baz : NSObject
+@end
+
+@implementation Baz
+@end
+
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface NSObject(Cat)
+@end
+
+@implementation NSObject(Cat)
+@end
+
+@interface NSObject(Dog)
+@end
+
+@implementation NSObject(Dog)
+@end
+
+void mycatfunc() {}
+
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+@end
+
+@implementation Foo
+@end
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test if the linker already has a weak definition
+# it does not try to find another copy in an archive
+#
+# There are two case to test:
+# 1) both the main .o files and the archive have the same weak symbol (_foo)
+# 2) main.o has a weak symbol and the archive has a non-weak symbol (_baz)
+# In both cases the linker should ignore the archive.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo-${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} foo-${ARCH}.o
+ ${CC} ${CCFLAGS} bar.c -c -o bar-${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} bar-${ARCH}.o
+ ${CC} ${CCFLAGS} baz.c -c -o baz-${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} baz-${ARCH}.o
+ libtool -static foo-${ARCH}.o bar-${ARCH}.o baz-${ARCH}.o -o libfoobar-${ARCH}.a
+ ${CC} ${CCFLAGS} main.c foo.c -lfoobar-${ARCH} -L. -o main-${ARCH}
+ ${FAIL_IF_BAD_MACHO} main-${ARCH}
+ nm -m main-${ARCH} | grep _baz | grep weak | ${PASS_IFF_STDIN}
+
+clean:
+ rm -rf main-* *.o *.a
--- /dev/null
+int bar() { return 0; }
--- /dev/null
+
+
+
+// intentionally not-weak
+int baz()
+{
+ return 1;
+}
+
+
+
--- /dev/null
+The point of this test if the linker already has a weak definition
+it does not try to find another copy in an archive
+
+There are two case to test:
+1) both the main .o files and the archive have the same weak symbol (_foo)
+2) main.o has a weak symbol and the archive has a non-weak symbol (_baz)
+In both cases the linker should ignore the archive.
--- /dev/null
+
+
+void collisionChecker() { }
+
+
+int __attribute__((weak)) foo()
+{
+ collisionChecker();
+ return 1;
+}
+
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+extern int foo();
+extern int bar();
+
+// intentionally weak
+int __attribute__((weak)) baz()
+{
+ return 1;
+}
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ return foo() + bar() + baz();
+}
+
+
+
--- /dev/null
+##
+# Copyright (c) 2006-2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+ifeq ($(FILEARCH),arm)
+ LD_VERS = -ios_version_min 4.0 -syslibroot $(IOS_SDK)
+else
+ LD_VERS = -macosx_version_min 10.6
+endif
+
+
+#
+# Check that ld can figure out architecture from .o files without -arch option
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} hello.c -c -o hello.o
+ ${FAIL_IF_BAD_OBJ} hello.o
+ ${LD} ${LDFLAGS} hello.o -dylib -o hello.dylib -lSystem $(LD_VERS)
+ file hello.dylib | grep ${FILEARCH} | ${PASS_IFF_STDIN}
+
+clean:
+ rm -rf hello.o hello.dylib
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test -bind-at-load option
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+ ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib
+ ${CC} ${CCFLAGS} main.c libfoo.dylib libbar.dylib -o main -Wl,-bind_at_load
+ ${DYLDINFO} -lazy_bind main | grep "no compressed lazy binding info" | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -bind main | grep _bar | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -f libfoo.dylib libbar.dylib main
--- /dev/null
+
+void bar() {}
--- /dev/null
+
+void foo() {}
+void foo2() {}
--- /dev/null
+#include <stddef.h>
+
+extern void foo();
+extern void foo2() __attribute__((weak_import));
+extern void bar();
+
+int main()
+{
+ foo();
+ bar();
+ if ( &foo2 != NULL )
+ foo2();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+ALL_ARCH_OPTIONS = $(patsubst %,-arch %,$(subst ppc,,$(VALID_ARCHS)) )
+
+#
+# Test that blank stubs are handled properly
+#
+
+run: all
+
+all:
+# build example fully fat dylib
+
+ gcc `echo ${ALL_ARCH_OPTIONS}` -dynamiclib foo.c -o libfoo.dylib -install_name libfoo.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+ # handle the case of a native ppc compile--this sets the subtype, which must be passed to lipo
+ if [ x${ARCH} != xppc ]; \
+ then \
+ SUB_ARCH=${ARCH}; \
+ else \
+ SUB_ARCH=`lipo -info libfoo.dylib | sed 's/.*://;s/ppc64 //;s/.* \(ppc[^ ]*\).*/\1/'`; \
+ echo SUB_ARCH $$SUB_ARCH; \
+ if [ x$$SUB_ARCH = xALL ]; \
+ then \
+ SUB_ARCH=ppc; \
+ fi \
+ fi; \
+ lipo libfoo.dylib -remove $$SUB_ARCH -output libfoo.dylib
+
+ lipo -create libfoo.dylib -arch_blank ${ARCH} -output libfoo.dylib
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
+ ${OTOOL} -L main | grep libfoo | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+ rm -rf libfoo.dylib main
--- /dev/null
+Test that blank stubs are handled properly
--- /dev/null
+int foo (void)
+{
+ return 1;
+}
--- /dev/null
+
+int main (void)
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+
+#
+# test thumb2 branch ranges
+#
+
+run: all
+
+
+all:
+ ${CC} ${CCFLAGS} foo.s -c
+ ${CC} ${CCFLAGS} bar.s -c
+ ${CC} ${CCFLAGS} foo.o bar.o -e _foo -o foobar ${ARCH_FLAGS} -nostdlib -lSystem
+ ${LD} -arch ${ARCH} -r foo.o bar.o -o foobar.o
+ ${CC} ${CCFLAGS} foobar.o -e _foo -o foobar2 ${ARCH_FLAGS} -nostdlib -lSystem
+ ${PASS_IFF_GOOD_MACHO} foobar
+
+clean:
+ rm *.o foobar*
--- /dev/null
+
+ .text
+ .align 4
+
+#if __thumb__
+ .thumb_func _bar
+ .code 16
+#endif
+
+ .globl _bar
+_bar:
+ nop
+#if __arm__
+ bl _foo
+ blx _foo
+// b _foo
+#endif
+
+
+
+
+ .subsections_via_symbols
+
\ No newline at end of file
--- /dev/null
+
+
+ .text
+ .align 4
+
+#if __thumb__
+ .thumb_func _foo
+ .code 16
+#endif
+ .globl _foo
+_foo:
+ nop
+#if __arm__
+ bl _bar
+ blx _bar
+// b _bar
+
+ .align 4
+_space1:
+
+#if __thumb2__
+ .space 16*1024*1024 -100
+#elif __thumb__
+ .space 4*1024*1024 -100
+#else
+ .space 16*1024*1024 -100
+#endif
+
+#endif // __arm__
+
+
+
+ .subsections_via_symbols
+
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+
+#
+# test thumb2 branch ranges
+#
+
+run: all
+
+
+all:
+ ${CC} ${CCFLAGS} mythumb.s -c
+ ${CC} ${CCFLAGS} myarm.s -c
+ ${LD} -arch ${ARCH} mythumb.o myarm.o -r -o all.o
+ ${CC} ${CCFLAGS} mythumb.o myarm.o -dynamiclib -o liball.dylib
+ ${PASS_IFF_GOOD_MACHO} liball.dylib
+
+clean:
+ rm *.o liball.dylib
--- /dev/null
+
+ .text
+ .align 4
+#if __arm__
+ .code 32
+ .align 2
+#endif
+
+ .globl _myarm
+_myarm:
+ nop
+#if __arm__
+ //bl _mythumb
+ b _mythumb
+#elif __i386__ || __x86_64__
+ jmp _mythumb
+#endif
+
+
+ .subsections_via_symbols
--- /dev/null
+
+ .text
+ .align 4
+_junk:
+ nop
+ nop
+ nop
+ nop
+#if __arm__
+ .syntax unified
+ .thumb_func _mythumb
+ .code 16
+#endif
+
+ .globl _mythumb
+_mythumb:
+ nop
+#if __arm__
+ //bl _myarm
+ b.w _myarm
+#elif __i386__ || __x86_64__
+ jmp _myarm
+#endif
+
+
+ .subsections_via_symbols
--- /dev/null
+##
+# Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Simple test for branch islands
+#
+
+run: all
+
+
+all:
+ # Verify that we fail if there is no valid place to insert branch islands.
+ ${CC} ${CCFLAGS} hello.c atomic_space.s extra.c -o hello ${ARCH_FLAGS} 2>&1 | grep "Unable to insert branch island. No insertion point available." | ${PASS_IFF_STDIN}
+
+ ${CC} ${CCFLAGS} hello.c space.s extra.c -o hello ${ARCH_FLAGS}
+ ${PASS_IFF_GOOD_MACHO} hello
+
+
+clean:
+ rm hello
--- /dev/null
+
+#if __ppc__
+
+ .text
+
+_prejunk:
+ mr r3,r5
+ mr r3,r4
+ blr
+
+
+_space1:
+ .space 15*1024*1024 + 2
+
+ .align 5
+_junk:
+ mr r3,r5
+ mr r3,r4
+ blr
+
+
+_space2:
+ .space 2*1024*1024
+
+#endif
+
+
+#if __arm__
+
+ .text
+_prejunk:
+ mov r0, #1
+ nop
+
+#if __thumb2__
+ // thumb2 branches are +/- 16MB
+_space1:
+ .space 14*1024*1024
+_space2:
+ .space 14*1024*1024
+_space3:
+ .space 14*1024*1024
+
+
+#elif __thumb__
+ // thumb1 branches are +/- 4MB
+_space1:
+ .space 3*1024*1024
+_space2:
+ .space 3*1024*1024
+_space3:
+ .space 3*1024*1024
+
+#else
+
+ // ARM branches are +/- 32MB
+_space1:
+ .space 14*1024*1024
+_space2:
+ .space 14*1024*1024
+_space3:
+ .space 14*1024*1024
+
+#endif
+
+ .align 5
+_junk:
+ mov r0, #1
+ nop
+
+
+_space4:
+ .space 2*1024*1024
+#endif
+
+ //.subsections_via_symbols
--- /dev/null
+#include <stdio.h>
+
+
+void foo()
+{
+ fprintf(stdout, "foo\n");
+}
+
--- /dev/null
+#include <stdio.h>
+
+extern void foo();
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ foo();
+ return 0;
+}
+
--- /dev/null
+
+#if __ppc__
+
+ .text
+
+_prejunk:
+ mr r3,r5
+ mr r3,r4
+ blr
+
+
+_space1:
+ .space 15*1024*1024 + 2
+
+ .align 5
+_junk:
+ mr r3,r5
+ mr r3,r4
+ blr
+
+
+_space2:
+ .space 2*1024*1024
+
+#endif
+
+
+#if __arm__
+
+ .text
+_prejunk:
+ mov r0, #1
+ nop
+
+#if __thumb2__
+ // thumb2 branches are +/- 16MB
+_space1:
+ .space 14*1024*1024
+_space2:
+ .space 14*1024*1024
+_space3:
+ .space 14*1024*1024
+
+
+#elif __thumb__
+ // thumb1 branches are +/- 4MB
+_space1:
+ .space 3*1024*1024
+_space2:
+ .space 3*1024*1024
+_space3:
+ .space 3*1024*1024
+
+#else
+
+ // ARM branches are +/- 32MB
+_space1:
+ .space 14*1024*1024
+_space2:
+ .space 14*1024*1024
+_space3:
+ .space 14*1024*1024
+
+#endif
+
+ .align 5
+_junk:
+ mov r0, #1
+ nop
+
+
+_space4:
+ .space 2*1024*1024
+#endif
+
+ .subsections_via_symbols
--- /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
+
+#
+# Ccheck that ld -bundle_loader works with bundles and executable,
+# and _bar is found in the loader and not in libbar.dylib
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ # test with loader as main executable
+ ${CC} ${CCFLAGS} main.c bar.c -o main
+ ${FAIL_IF_BAD_MACHO} main
+ ${CC} ${CCFLAGS} bundle.c -bundle -bundle_loader main libbar.dylib -o bundle.bundle
+ ${FAIL_IF_BAD_MACHO} bundle.bundle
+ nm -m bundle.bundle | grep _bar | grep "from executable" | ${PASS_IFF_STDIN}
+ # test with loader as another bundle
+ ${CC} ${CCFLAGS} -bundle main.c bar.c -o mainbundle
+ ${FAIL_IF_BAD_MACHO} main
+ ${CC} ${CCFLAGS} bundle.c -bundle -bundle_loader mainbundle libbar.dylib -o bundle.bundle
+ ${FAIL_IF_BAD_MACHO} bundle.bundle
+ nm -m bundle.bundle | grep _bar | grep "from executable" | ${PASS_IFF_STDIN}
+ # verify error message when linking with raw bundle
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c bar.c -o main bundle.bundle 2> error.log
+ grep "link with bundle" error.log | ${PASS_IFF_STDIN}
+
+clean:
+ rm *.dylib main bundle.bundle mainbundle error.log
--- /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@
+ */
+
+
+// funcation 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>
+
+int main()
+{
+ return 0;
+}
+
--- /dev/null
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c bar.c -Os -o foo -framework CoreFoundation
+ ${PASS_IFF_GOOD_MACHO} foo
+
+clean:
+ rm -rf foo
--- /dev/null
+#include <CoreFoundation/CFString.h>
+
+
+//
+// llvm may make cfstring that has backing store of kTest
+//
+
+
+const char kTest[] = "test";
+
+void bar()
+{
+ CFStringGetLength(CFSTR("test"));
+}
--- /dev/null
+#include <CoreFoundation/CFString.h>
+
+extern void bar();
+
+int main()
+{
+ CFStringGetLength(CFSTR("stuff"));
+ bar();
+ return 0;
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2007-2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Test that cfstring literals are coalesced and dead stripped
+# There is 3 CFSTR in foo.c and 1 CFSTR in bar.c
+# After coalescing and dead stripping there should be only one CFSTR in the output
+#
+
+ifeq (,${findstring 64,$(ARCH)})
+ CFSTRING_SIZE = 16
+else
+ CFSTRING_SIZE = 32
+endif
+
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c bar.c -o foo -framework CoreFoundation -dead_strip
+ size -l foo | grep "__cfstring: ${CFSTRING_SIZE}" | ${FAIL_IF_EMPTY}
+ # now try with -fwritable-strings
+ ${CC} ${CCFLAGS} foo.c bar.c -o foo_writable -framework CoreFoundation -dead_strip -fwritable-strings 2>/dev/null
+ size -l foo_writable | grep "__cfstring: ${CFSTRING_SIZE}" | ${PASS_IFF_STDIN}
+
+clean:
+ rm -rf foo foo_writable
--- /dev/null
+#include <CoreFoundation/CFString.h>
+
+CFStringRef OtherCFString = CFSTR("other");
+
+void bar()
+{
+ CFStringGetLength(CFSTR("live"));
+}
--- /dev/null
+#include <CoreFoundation/CFString.h>
+
+extern void bar();
+
+extern CFStringRef OtherCFString;
+
+void foo()
+{
+ CFStringGetLength(CFSTR("hello"));
+ CFStringGetLength(CFSTR("world"));
+ CFStringGetLength(OtherCFString);
+}
+
+
+int main()
+{
+ CFStringGetLength(CFSTR("live"));
+ bar();
+ return 0;
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that utf16 cfstring literals are coalesced.
+# There is 3 CFSTR in foo.m and 1 CFSTR in bar.m
+# After coalescing and dead stripping there should be only two CFSTR in the output
+#
+
+ifeq (,${findstring 64,$(ARCH)})
+ CFSTRING_SIZE = 32
+else
+ CFSTRING_SIZE = 64
+endif
+ USTRING_SIZE = 28
+
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.m bar.m -o foo -framework CoreFoundation -dead_strip
+ size -l foo | grep "__cfstring: ${CFSTRING_SIZE}" | ${FAIL_IF_EMPTY}
+ size -l foo | grep "__ustring: ${USTRING_SIZE}" | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} foo
+
+clean:
+ rm -rf foo
--- /dev/null
+#include <CoreFoundation/CFString.h>
+
+
+void bar()
+{
+ CFStringGetLength(CFSTR("über"));
+}
--- /dev/null
+#include <CoreFoundation/CFString.h>
+
+extern void bar();
+
+void foo()
+{
+ CFStringGetLength(CFSTR("hello"));
+ CFStringGetLength(CFSTR("überhund"));
+}
+
+
+int main()
+{
+ CFStringGetLength(CFSTR("über"));
+ CFStringGetLength(CFSTR("überhund"));
+ bar();
+ return 0;
+}
+
+
--- /dev/null
+ .long 0x12340000
+
--- /dev/null
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Verify machochecker catchs init routines to abolute addresses outside image
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c init.s -o init.exe
+ ${FAIL_IF_SUCCESS} ${MACHOCHECK} init.exe 2>/dev/null
+ ${CC} ${CCFLAGS} main.c term.s -o term.exe
+ ${FAIL_IF_SUCCESS} ${MACHOCHECK} term.exe 2>/dev/null
+ ${PASS_IFF} /usr/bin/true
+
+clean:
+ rm -f init.exe term.exe
--- /dev/null
+
+
+ .mod_init_func
+#if __LP64__
+ .quad 0x7FFF123400000000
+#else
+ .long 0x12340000
+#endif
+
+
--- /dev/null
+int main() { return 0; }
+
--- /dev/null
+
+
+ .mod_term_func
+#if __LP64__
+ .quad 0x7FFF123400000000
+#else
+ .long 0x12340000
+#endif
+
+
--- /dev/null
+ .long 0x12340000
+
--- /dev/null
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Verify machochecker catchs init routines with bindings to external symbols
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c init.s -Wl,-pie -o init.exe
+ ${FAIL_IF_SUCCESS} ${MACHOCHECK} init.exe 2>/dev/null
+ ${CC} ${CCFLAGS} main.c term.s -Wl,-pie -o term.exe
+ ${FAIL_IF_SUCCESS} ${MACHOCHECK} term.exe 2>/dev/null
+ ${PASS_IFF} /usr/bin/true
+
+clean:
+ rm -f init.exe term.exe
--- /dev/null
+
+
+ .mod_init_func
+#if __LP64__
+ .quad _malloc + 0x100000010
+#else
+ .long _malloc + 0x1010
+#endif
+
+
--- /dev/null
+int main() { return 0; }
+
--- /dev/null
+
+
+ .mod_term_func
+#if __LP64__
+ .quad _malloc + 0x100000010
+#else
+ .long _malloc + 0x1010
+#endif
+
+
--- /dev/null
+ .long 0x12340000
+
--- /dev/null
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Verify machochecker catchs init routines in slidable images that are missing rebasing info
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c init.s -Wl,-pie -o init.exe
+ ${FAIL_IF_SUCCESS} ${MACHOCHECK} init.exe 2>/dev/null
+ ${CC} ${CCFLAGS} main.c term.s -Wl,-pie -o term.exe
+ ${FAIL_IF_SUCCESS} ${MACHOCHECK} term.exe 2>/dev/null
+ ${PASS_IFF} /usr/bin/true
+
+clean:
+ rm -f init.exe term.exe
--- /dev/null
+
+
+ .mod_init_func
+#if __LP64__
+ .quad 0x100000010
+#else
+ .long 0x1010
+#endif
+
+
--- /dev/null
+int main() { return 0; }
+
--- /dev/null
+
+
+ .mod_term_func
+#if __LP64__
+ .quad 0x100000010
+#else
+ .long 0x1010
+#endif
+
+
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test the if all symbols from a dylib are weak_import, that the whole dylib is weakly loaded
+#
+
+run: all-${FILEARCH}
+
+
+all-ppc:
+ ${PASS_IFF} true
+
+all-arm:
+ ${PASS_IFF} true
+
+all-i386: all-real
+
+all-x86_64: all-real
+
+
+all-real:
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+ ${CC} ${CCFLAGS} main.c -o main libfoo.dylib
+ ${DYLDINFO} -bind main | grep wfoo | ${FAIL_IF_EMPTY}
+
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+ rm -rf libfoo.dylib main
--- /dev/null
+
+
+__attribute__((weak)) void wfoo() {}
+void foo() {}
--- /dev/null
+
+extern void foo();
+extern void wfoo();
+
+void* pfoo = &foo;
+void* pwfoo = &wfoo;
+
+int main (void)
+{
+ if (pfoo != &foo)
+ return 1;
+ if (pwfoo != &wfoo)
+ return 1;
+
+ return 0;
+}
+
--- /dev/null
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that an object file can be code signed
+#
+# <rdar://problem/5881324> when linking a kext the static linker should leave a pad in the headers to allow code signing
+#
+
+CODE_SIGN_ARCH = ${ARCH}
+ifeq (${ARCH},ppc)
+ CODE_SIGN_ARCH = ppc7400
+endif
+
+
+run: all
+
+all:
+ ${CC} foo.c -c -o foo.o
+ ${LD} -r foo.o -o foo2.o
+ codesign_allocate -i foo2.o -a ${CODE_SIGN_ARCH} 256 -o foo3.o
+ ${PASS_IFF} true
+
+clean:
+ rm foo.o foo2.o foo3.o
--- /dev/null
+void foo() {}
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Validate linker preserves commons with custom alignment
+#
+
+all:
+ ${CC} ${CCFLAGS} foo.s -c -o foo.o
+ nm -m foo.o | grep _mycomm64aligned | grep '(alignment 2^6)' | ${FAIL_IF_EMPTY}
+ nm -m foo.o | grep _mycomm16kaligned | grep '(alignment 2^14)' | ${FAIL_IF_EMPTY}
+ ${LD} foo.o -r -o foo2.o
+ nm -m foo2.o | grep _mycomm64aligned | grep '(alignment 2^6)' | ${FAIL_IF_EMPTY}
+ nm -m foo2.o | grep _mycomm16kaligned | grep '(alignment 2^14)' | ${FAIL_IF_EMPTY}
+ ${PASS_IFF} true
+
+clean:
+ rm -rf foo.o foo2.o
--- /dev/null
+
+ .comm _mycomm64aligned,15,6
+ .comm _mycomm16kaligned,256,14
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# The point of this test is to verify if a header file is missing an extern that there won't be
+# duplicates definitions when using -dead_strip.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} a.c -c -o a.o
+ ${CC} ${CCFLAGS} b.c -c -o b.o
+ ${CC} ${CCFLAGS} c.c -c -o c.o
+ ${CC} -arch ${ARCH} -dynamiclib a.o b.o c.o -o libabc.dylib -dead_strip
+ ${PASS_IFF_GOOD_MACHO} libabc.dylib
+
+clean:
+ rm -rf a.o b.o c.o libabc.dylib one abc.bar.count
--- /dev/null
+#include "c.h"
+
+float aa() { return bar; }
+
--- /dev/null
+#include "c.h"
+
+float bb() { return bar; }
+
--- /dev/null
+
+const float bar = 1.0;
+
--- /dev/null
+
+// missing extern
+const float bar;
+
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# The point of this test is to verify a .o built with
+# commons and one built without commons can be merged.
+#
+# <rdar://problem/4743925> problem merging .o files built with and without -fno-common
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} foo.${ARCH}.o
+ ${CC} ${CCFLAGS} bar.c -c -fno-common -o bar.${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} bar.${ARCH}.o
+ ${LD} -arch ${ARCH} -r -keep_private_externs foo.${ARCH}.o bar.${ARCH}.o -o foobar.${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} foobar.${ARCH}.o
+ nm -m foobar.${ARCH}.o | grep bar | grep __common | ${PASS_IFF_STDIN}
+
+clean:
+ rm -rf *.o
--- /dev/null
+
+int bar;
--- /dev/null
+
+int foo;
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Validate linker puts commons in the correct order.
+# -fno-commons come first, followed by all other commons
+# in .o order and alphabetically within each .o
+#
+
+all:
+ ${CC} ${CCFLAGS} baz.c -fno-common -c -o baz.o
+ ${CC} ${CCFLAGS} main.c foo.c bar.c baz.o -o main
+ nm -j -n main | grep _common > symbol.order
+ ${FAIL_IF_ERROR} diff symbol.order expected.order
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main baz.o symbol.order
--- /dev/null
+int ddd_common;
+int iii_common[4];
+int bbb_common[4];
--- /dev/null
+int fff_common;
+int iii_common[4];
+int ttt_common;
--- /dev/null
+_fff_common
+_iii_common
+_ttt_common
+_aaa_common
+_eee_common
+_ggg_common
+_bbb_common
+_ddd_common
--- /dev/null
+int aaa_common;
+int ggg_common[4];
+int eee_common;
--- /dev/null
+
+
+int main() { return 0; }
+
--- /dev/null
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check compiler emitted compact unwind info
+#
+
+all: all-${FILEARCH}
+
+all-i386: all-cu
+all-x86_64: all-cu
+all-arm: all-good
+
+all-cu:
+ ${CC} ${CCFLAGS} test.s -c -o test.o
+ ${OBJECTDUMP} test.o > test.o.dump
+ ${LD} -r -arch ${ARCH} test.o -o test-r.o
+ ${OBJECTDUMP} test-r.o > test-r.o.dump
+ ${PASS_IFF} diff test.o.dump test-r.o.dump
+
+all-good:
+ ${PASS_IFF} true
+
+clean:
+ rm -f test.o test-r.o test.o.dump test-r.o.dump
--- /dev/null
+#if __LP64__
+ #define pointer quad
+#else
+ #define pointer long
+#endif
+
+
+
+ .text
+
+_basic:
+ nop
+ nop
+Lbasicend:
+
+
+_multi:
+ nop
+ nop
+Lmulti1:
+ nop
+Lmulti1a:
+ nop
+ nop
+Lmulti2:
+ nop
+Lmultiend:
+
+
+_person:
+ nop
+ nop
+Lpersonend:
+
+
+_person_lsda:
+ nop
+ nop
+Lpersonlsdaend:
+
+
+ .section __TEXT,__gcc_except_tab
+_lsda1:
+ .long 1
+ .long 2
+
+
+ .section __LD,__compact_unwind,regular,debug
+
+ .pointer _basic
+ .set L1,Lbasicend-_basic
+ .long L1
+ .long 0
+ .pointer 0
+ .pointer 0
+
+ .pointer _multi
+ .set L2,Lmulti1-_multi
+ .long L2
+ .long 1
+ .pointer 0
+ .pointer 0
+
+ .pointer Lmulti1
+ .set L3,Lmulti2-Lmulti1
+ .long L3
+ .long 2
+ .pointer 0
+ .pointer 0
+
+ .pointer Lmulti2
+ .set L4,Lmultiend-Lmulti2
+ .long L4
+ .long 3
+ .pointer 0
+ .pointer 0
+
+
+ .pointer _person
+ .set L5,Lpersonend-_person
+ .long L5
+ .long 0
+ .pointer _gxx_personality_v0
+ .pointer 0
+
+
+ .pointer _person_lsda
+ .set L6,Lpersonlsdaend-_person_lsda
+ .long L6
+ .long 0
+ .pointer _gxx_personality_v0
+ .pointer _lsda1
+
+
+ .subsections_via_symbols
+
+
+
+
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Validate cpu subtype preference
+#
+
+test: test-${ARCH}
+
+test-ppc64:
+ ${PASS_IFF} true
+
+test-i386:
+ ${PASS_IFF} true
+
+test-x86_64:
+ ${PASS_IFF} true
+
+test-armv6: test-arm
+test-armv7: test-arm
+
+test-arm:
+ clang foo.c -arch armv4t -c -DAAA=1 -o foo4.o
+ clang foo.c -arch armv5 -c -DBBB=1 -o foo5.o
+ clang foo.c -arch armv6 -c -DCCC=1 -o foo6.o
+ clang foo.c -arch armv7 -c -DDDD=1 -o foo7.o
+ lipo foo4.o foo5.o foo6.o foo7.o -create -output foo.o
+
+ # check -arch armv4t pulls out V4 slice
+ ${LD} -r -arch armv4t foo.o -o fooa.o
+ otool -hv fooa.o | grep V4T | ${FAIL_IF_EMPTY}
+ nm fooa.o | grep _aaa | ${FAIL_IF_EMPTY}
+
+ # check -arch armv5 pulls out V5 slice
+ ${LD} -r -arch armv5 foo.o -o foob.o
+ otool -hv foob.o | grep V5 | ${FAIL_IF_EMPTY}
+ nm foob.o | grep _bbb | ${FAIL_IF_EMPTY}
+
+ # check -arch armv6 pulls out V6 slice
+ ${LD} -r -arch armv6 foo.o -o fooc.o
+ otool -hv fooc.o | grep V6 | ${FAIL_IF_EMPTY}
+ nm fooc.o | grep _ccc | ${FAIL_IF_EMPTY}
+
+ # check -arch armv7 pulls out V7 slice
+ ${LD} -r -arch armv7 foo.o -o fooc.o
+ otool -hv fooc.o | grep V7 | ${FAIL_IF_EMPTY}
+ nm fooc.o | grep _ddd | ${FAIL_IF_EMPTY}
+
+ ${PASS_IFF} true
+
+
+test-ppc:
+ gcc foo.c -arch ppc750 -c -DAAA=1 -o foog3.o
+ gcc foo.c -arch ppc7400 -c -DBBB=1 -o foog4.o
+ gcc foo.c -arch ppc970 -c -DCCC=1 -o foog5.o
+ lipo foog3.o foog4.o foog5.o -create -output foo.o
+
+ # check -arch ppc750 pulls out g3 slice
+ ${LD} -r -arch ppc750 foo.o -o fooa.o
+ otool -hv fooa.o | grep ppc750 | ${FAIL_IF_EMPTY}
+ nm fooa.o | grep _aaa | ${FAIL_IF_EMPTY}
+
+ # check -arch ppc7400 pulls out g4 slice
+ ${LD} -r -arch ppc7400 foo.o -o foob.o
+ otool -hv foob.o | grep ppc7400 | ${FAIL_IF_EMPTY}
+ nm foob.o | grep _bbb | ${FAIL_IF_EMPTY}
+
+ # check -arch ppc970 pulls out g5 slice
+ ${LD} -r -arch ppc970 foo.o -o fooc.o
+ otool -hv fooc.o | grep ppc970 | ${FAIL_IF_EMPTY}
+ nm fooc.o | grep _ccc | ${FAIL_IF_EMPTY}
+
+ ${PASS_IFF} true
+
+
+clean:
+ rm -f *.o
--- /dev/null
+
+
+#if AAA
+ void aaa() {}
+#endif
+
+#if BBB
+ void bbb() {}
+#endif
+
+#if CCC
+ void ccc() {}
+#endif
+
+#if DDD
+ void ddd() {}
+#endif
+
+#if EEE
+ void eee() {}
+#endif
+
+#if FFFF
+ void fff() {}
+#endif
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Validate cpu subtypes processing
+#
+
+test: test-${ARCH}
+
+test-ppc64:
+ ${PASS_IFF} true
+
+test-i386:
+ ${PASS_IFF} true
+
+test-x86_64:
+ ${PASS_IFF} true
+
+test-armv6: test-arm
+test-armv7: test-arm
+
+test-arm:
+ clang foo.c -arch armv4t -c -o foo-v4.o
+ ${FAIL_IF_BAD_OBJ} foo-v4.o
+ clang foo.c -arch armv5 -c -o foo-v5.o
+ ${FAIL_IF_BAD_OBJ} foo-v5.o
+ clang foo.c -arch armv6 -c -o foo-v6.o
+ ${FAIL_IF_BAD_OBJ} foo-v6.o
+ clang foo.c -arch armv7 -c -o foo-v7.o
+ ${FAIL_IF_BAD_OBJ} foo-v7.o
+ clang foo.c -arch xscale -c -o foo-xscale.o
+ ${FAIL_IF_BAD_OBJ} foo-xscale.o
+ clang main.c -arch armv4t -c -o main-v4.o
+ ${FAIL_IF_BAD_OBJ} main-v4.o
+ clang main.c -arch armv5 -c -o main-v5.o
+ ${FAIL_IF_BAD_OBJ} main-v5.o
+ clang main.c -arch armv6 -c -o main-v6.o
+ ${FAIL_IF_BAD_OBJ} main-v6.o
+ clang main.c -arch xscale -c -o main-xscale.o
+ ${FAIL_IF_BAD_OBJ} main-xscale.o
+ clang main.c -arch armv7 -c -o main-v7.o
+ ${FAIL_IF_BAD_OBJ} main-v7.o
+
+ # check V4+V4 -> V4
+ ${LD} -r main-v4.o foo-v4.o -o all.o
+ ${FAIL_IF_BAD_OBJ} all.o
+ otool -hv all.o | grep V4T | ${FAIL_IF_EMPTY}
+
+ # check V4+V5 -> V5
+ #${LD} -r main-v4.o foo-v5.o -o all.o
+ #${FAIL_IF_BAD_OBJ} all.o
+ #otool -hv all.o | grep V5 | ${FAIL_IF_EMPTY}
+
+ # check V4+V6 -> V6
+ #${LD} -r main-v4.o foo-v6.o -o all.o
+ #${FAIL_IF_BAD_OBJ} all.o
+ #otool -hv all.o | grep V6 | ${FAIL_IF_EMPTY}
+
+ # check V4+xscale -> xscale
+ #${LD} -r main-v4.o foo-xscale.o -o all.o
+ #${FAIL_IF_BAD_OBJ} all.o
+ #otool -hv all.o | grep XSCALE | ${FAIL_IF_EMPTY}
+
+ # check V5+V5 -> V5
+ ${LD} -r main-v5.o foo-v5.o -o all.o
+ ${FAIL_IF_BAD_OBJ} all.o
+ otool -hv all.o | grep V5 | ${FAIL_IF_EMPTY}
+
+ # check V5+V6 -> V6
+ #${LD} -r main-v5.o foo-v6.o -o all.o
+ #${FAIL_IF_BAD_OBJ} all.o
+ #otool -hv all.o | grep V6 | ${FAIL_IF_EMPTY}
+
+ # check V5+xscale -> xscale
+ #${LD} -r main-v5.o foo-xscale.o -o all.o
+ #${FAIL_IF_BAD_OBJ} all.o
+ #otool -hv all.o | grep XSCALE | ${FAIL_IF_EMPTY}
+
+ # check V6+V6 -> V6
+ ${LD} -r main-v6.o foo-v6.o -o all.o
+ ${FAIL_IF_BAD_OBJ} all.o
+ otool -hv all.o | grep V6 | ${FAIL_IF_EMPTY}
+
+ # check V7+V7 -> V7
+ ${LD} -r main-v7.o foo-v7.o -o all.o
+ ${FAIL_IF_BAD_OBJ} all.o
+ otool -hv all.o | grep V7 | ${FAIL_IF_EMPTY}
+
+ # check xscale+xscale -> xscale
+ #${LD} -r main-xscale.o foo-xscale.o -o all.o
+ #${FAIL_IF_BAD_OBJ} all.o
+ #otool -hv all.o | grep XSCALE | ${FAIL_IF_EMPTY}
+
+ ${PASS_IFF} true
+
+
+test-ppc:
+ gcc foo.c -arch ppc -mmacosx-version-min=10.4 -c -o foo.o
+ ${FAIL_IF_BAD_OBJ} foo.o
+ gcc foo.c -arch ppc750 -c -o foo-G3.o
+ ${FAIL_IF_BAD_OBJ} foo-G3.o
+ gcc foo.c -arch ppc7400 -c -o foo-G4.o
+ ${FAIL_IF_BAD_OBJ} foo-G4.o
+ gcc foo.c -arch ppc970 -c -o foo-G5.o
+ ${FAIL_IF_BAD_OBJ} foo-G5.o
+ gcc main.c -arch ppc -mmacosx-version-min=10.4 -c -o main.o
+ ${FAIL_IF_BAD_OBJ} main.o
+ gcc main.c -arch ppc970 -c -o main-G5.o
+ ${FAIL_IF_BAD_OBJ} main-G5.o
+
+ # check ALL+ALL -> ALL
+ ${LD} -r main.o foo.o -o main-r.o
+ ${FAIL_IF_BAD_OBJ} main-r.o
+ otool -hv main-r.o | grep ALL | ${FAIL_IF_EMPTY}
+
+ # check G3+ALL -> G3
+ ${LD} -r main.o foo-G3.o -o main-r.o
+ ${FAIL_IF_BAD_OBJ} main-r.o
+ otool -hv main-r.o | grep ppc750 | ${FAIL_IF_EMPTY}
+
+ # check G4+ALL -> G4
+ ${LD} -r main.o foo-G4.o -o main-r.o
+ ${FAIL_IF_BAD_OBJ} main-r.o
+ otool -hv main-r.o | grep ppc7400 | ${FAIL_IF_EMPTY}
+
+ # check G5+ALL -> G5
+ ${LD} -r main.o foo-G5.o -o main-r.o
+ ${FAIL_IF_BAD_OBJ} main-r.o
+ otool -hv main-r.o | grep ppc970 | ${FAIL_IF_EMPTY}
+
+ # check G5+G4 -> G5
+ ${LD} -r main-G5.o foo-G4.o -o main-r.o
+ ${FAIL_IF_BAD_OBJ} main-r.o
+ otool -hv main-r.o | grep ppc970 | ${FAIL_IF_EMPTY}
+
+ # check G4+G5 -> G5
+ ${LD} -r foo-G4.o main-G5.o -o main-r.o
+ ${FAIL_IF_BAD_OBJ} main-r.o
+ otool -hv main-r.o | grep ppc970 | ${FAIL_IF_EMPTY}
+
+ # check -force_cpusubtype_ALL
+ ${LD} -r main.o foo-G5.o -o main-r.o -force_cpusubtype_ALL
+ ${FAIL_IF_BAD_OBJ} main-r.o
+ otool -hv main-r.o | grep ALL | ${PASS_IFF_STDIN}
+
+clean:
+ rm -f *.o
--- /dev/null
+The point of this test is validate cpu subtypes processsing for PowerPC
+
--- /dev/null
+void foo()
+{
+}
--- /dev/null
+#include <stdio.h>
+
+extern void foo();
+extern void bar();
+
+int main()
+{
+ foo();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that __cstring sections in other segments are not coalesced
+#<rdar://problem/6535736> ld coalesces C strings in different segments
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c custom.s -o main
+ size -l main | grep __cstring | wc -l | grep 2 | ${FAIL_IF_EMPTY}
+ size -l main | grep -A2 __MYSEG | grep __cstring | grep " 10 " | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm main
--- /dev/null
+
+
+
+ .section __MYSEG, __cstring, cstring_literals
+LC1: .ascii "hello\0"
+LC2: .ascii "bye\0"
+LC3: .ascii "hello\0"
+
+
+
--- /dev/null
+#include <stdio.h>
+
+int main()
+{
+ printf("hello");
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that cstrings in custom sections are not uniqued with
+# cstrings in the standard section.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -c foo.s -o foo.o
+ ${CC} ${CCFLAGS} -c bar.s -o bar.o
+ ${LD} -arch ${ARCH} -r foo.o bar.o -o foobar.o
+ size -l foobar.o | grep "(__TEXT, __cstring): 13" | ${FAIL_IF_EMPTY}
+ size -l foobar.o | grep "(__TEXT, __mystring): 15" | ${FAIL_IF_EMPTY}
+ otool -lv foobar.o | grep -A10 __mystring | grep S_CSTRING_LITERALS | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} foo.o bar.o -dynamiclib -o libfoobar.dylib
+ size -l libfoobar.dylib | grep "__cstring: 13" | ${FAIL_IF_EMPTY}
+ size -l libfoobar.dylib | grep "__mystring: 15" | ${FAIL_IF_EMPTY}
+ otool -lv libfoobar.dylib | grep -A10 __mystring | grep S_CSTRING_LITERALS | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libfoobar.dylib
+
+clean:
+ rm foo.o bar.o libfoobar.dylib foobar.o
--- /dev/null
+ .cstring
+LC0:
+ .ascii "bar\0"
+LC1:
+ .ascii "coal\0"
+ .text
+
+
+ .section __TEXT, __mystring, cstring_literals
+LC4:
+ .ascii "bar\0"
+LC5:
+ .ascii "mycoal\0"
+
+
+ .data
+#if __LP64__
+ .quad LC0
+ .quad LC1
+ .quad LC4
+ .quad LC5
+#else
+ .long LC0
+ .long LC1
+ .long LC4
+ .long LC5
+#endif
+
+ .subsections_via_symbols
+
+
--- /dev/null
+ .cstring
+LC0:
+ .ascii "foo\0"
+LC1:
+ .ascii "coal\0"
+ .text
+
+
+ .section __TEXT, __mystring, cstring_literals
+LC4:
+ .ascii "foo\0"
+LC5:
+ .ascii "mycoal\0"
+
+
+ .data
+#if __LP64__
+ .quad LC0
+ .quad LC1
+ .quad LC4
+ .quad LC5
+#else
+ .long LC0
+ .long LC1
+ .long LC4
+ .long LC5
+#endif
+
+ .subsections_via_symbols
+
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# verify labled empty strings are preserved
+#
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -c foo.s -o foo.o
+ ${LD} -arch ${ARCH} -r foo.o -o foo-r.o
+ ${LD} -arch ${ARCH} -r foo-r.o -o foo-r2.o
+ ${OBJECTDUMP} foo-r.o > foo-r.dump
+ ${OBJECTDUMP} foo-r2.o > foo-r2.dump
+ ${PASS_IFF} diff foo-r.dump foo-r2.dump
+
+clean:
+ rm foo.o foo-r.o foo-r2.o foo.dump foo-r.dump foo-r2.dump
--- /dev/null
+ .cstring
+LC2:
+ .ascii "bye\0"
+ .ascii "\0"
+ .ascii "\0"
+
+.globl _empty
+_empty:
+ .ascii "\0"
+
+LC0:
+ .ascii "hello\0"
+ .ascii "\0"
+ .ascii "\0"
+ .ascii "\0"
+
+LC1:
+ .ascii "\0"
+
+
+ .subsections_via_symbols
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/6069861> ld -r for x86_64 is changing visibility of cstring constants
+#
+# In order to coalesce strings from different .o files, the linker internally
+# makes them weak/hidden. Test to make sure that weak/hidden does not leak out.
+#
+
+STRING_LABEL_COUNT = 0
+
+ifeq (${ARCH},x86_64)
+ STRING_LABEL_COUNT = 3
+endif
+ifeq (${ARCH},i386)
+ STRING_LABEL_COUNT = 1
+endif
+
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -c foo.c -o foo.o
+ ${CC} ${CCFLAGS} -c bar.c -o bar.o
+ ${LD} -arch ${ARCH} -r foo.o bar.o -o foobar.o
+ nm -nm foobar.o | grep __cstring | grep "weak private external" | ${FAIL_IF_STDIN}
+ ${LD} -arch ${ARCH} -r foo.o bar.o -o foobar.o -keep_private_externs
+ nm -nm foobar.o | grep __cstring | grep "weak private external" | ${FAIL_IF_STDIN}
+ nm -m foobar.o | grep __cstring | wc -l | grep ${STRING_LABEL_COUNT} | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} foo.o bar.o -dynamiclib -o libfoobar.dylib
+ nm -m libfoobar.dylib | grep __cstring | wc -l | egrep '[01]' | ${FAIL_IF_EMPTY}
+ ${PASS_IFF} /usr/bin/true
+
+clean:
+ rm foo.o bar.o foobar.o libfoobar.dylib
--- /dev/null
+const char* kBar = "hello";
+const char* kBar2 = "there";
--- /dev/null
+
+void func() {}
+
+const char kFoo[] = "foo";
+
+const char* kFoo2 = "hello";
--- /dev/null
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that a large page zero works
+#
+ifeq (,${findstring "macosx","$(VERSION_NEW_LINKEDIT)"})
+ SEG_ADDR = 0x20000000
+else
+ SEG_ADDR = 0xb8000000
+endif
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c zero.s -o main -pagezero_size 0 -segaddr __TEXT $(SEG_ADDR) -segaddr __MYZEROPAGE 0
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -f main
--- /dev/null
+
+int x = 5;
+
+int main()
+{
+ return 0;
+}
+
--- /dev/null
+
+ .section __MYZEROPAGE,_data
+_min: .long 0
+
+#if __arm__
+ .zerofill __MYZEROPAGE,__zerofill,_padding,536870910
+#else
+ .zerofill __MYZEROPAGE,__zerofill,_padding,2147483644
+#endif
+
+
+
+
--- /dev/null
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that L$start$.. labels are tracked
+#
+
+all:
+ ${CC} ${CCFLAGS} -c test.s -o test.o
+ ${LD} -r -arch ${ARCH} test.o -o test2.o
+ #nm main | grep _dtrace_probe | ${FAIL_IF_EMPTY}
+ #${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf test.o test2.o
--- /dev/null
+
+#include <stdio.h>
+
+#define DTRACE_STRINGIFY(s) #s
+#define DTRACE_TOSTRING(s) DTRACE_STRINGIFY(s)
+
+#define DTRACE_NOPS \
+ "nop" "\n\t" \
+ "nop" "\n\t" \
+ "nop" "\n\t"
+
+
+#define DTRACE_LAB(p, n) \
+ "__dtrace_probe$" DTRACE_TOSTRING(%=__LINE__) DTRACE_STRINGIFY(_##p##___##n)
+
+#define DTRACE_LABEL(p, n) \
+ ".section __DATA, __data\n\t" \
+ ".globl " DTRACE_LAB(p, n) "\n\t" \
+ DTRACE_LAB(p, n) ":\n\t" ".long 1f""\n\t" \
+ ".text" "\n\t" \
+ "1:"
+
+#define DTRACE_CALL(p,n) \
+ DTRACE_LABEL(p,n) \
+ DTRACE_NOPS
+
+#define DTRACE_CALL0ARGS(provider, name) \
+ __asm volatile ( \
+ DTRACE_CALL(provider, name) \
+ : \
+ : \
+ );
+
+int deadwood()
+{
+ DTRACE_CALL0ARGS(__foo__, test2)
+ return 0;
+}
+
+
+int main() {
+ int a = 1;
+
+ while(a) {
+ DTRACE_CALL0ARGS(__foo__, test1)
+ }
+
+ return 0;
+}
--- /dev/null
+
+ .text
+
+_foo:
+ nop
+ nop
+l$start$data$1:
+ nop
+ nop
+ nop
+l$start$jt8$2:
+ nop
+ nop
+l$start$jt16$3:
+ nop
+ nop
+l$start$code$n4:
+ nop
+ nop
+
+
+
+ .subsections_via_symbols
+
+
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Tests that if an unused function is pulled in from an archive
+# because another function in the same .o file is needed, that the
+# first does not cause a duplicate definition error.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ ${CC} ${CCFLAGS} bar.c -c -o bar.o
+ libtool -static foo.o bar.o -o libfoobar.a
+ ${CC} ${CCFLAGS} main.c libfoobar.a -dead_strip -o main -Wl,-w
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+ rm -rf main libfoobar.a foo.o bar.o
--- /dev/null
+
+void bar() { }
+
+int baz()
+{
+ return -1;
+}
+
--- /dev/null
+
+void foo() { }
+
+extern void bar();
+
+void deadwood()
+{
+ bar();
+}
+
--- /dev/null
+
+extern void foo();
+
+int baz()
+{
+ return 0;
+}
+
+int main()
+{
+ foo();
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Tests that a non-weak symbol in an archive cleanly overrides
+# a weak symbol in a .o file with dead code stripping
+#
+# <rdar://problem/6294378> duplicate typeinfo in executable
+#
+
+run: all
+
+all:
+ ${CXX} ${CXXFLAGS} foo.cxx -c -o foo.o
+ ${CXX} ${CXXFLAGS} bar.cxx -c -o bar.o
+ libtool -static foo.o bar.o -o libfoobar.a
+ ${CXX} ${CXXFLAGS} main.cxx libfoobar.a -dead_strip -o main
+ dwarfdump --eh-frame --verify main >/dev/null
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+ rm -rf main foo.o bar.o libfoobar.a
--- /dev/null
+
+#include <stdio.h>
+
+void doit()
+{
+ printf("hello there %s\n", "world");
+
+}
+
+void bar()
+{
+ doit();
+}
+
--- /dev/null
+#include <stdio.h>
+
+__attribute__((weak)) void doit()
+{
+ printf("hello %s\n", "world");
+}
+
+
+void foo()
+{
+ doit();
+}
+
--- /dev/null
+
+extern void foo();
+extern void bar();
+
+int main()
+{
+ foo();
+ bar();
+ return 0;
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Tests that a global symbol in an archive will stil be exported (and not dead stripped).
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ ${FAIL_IF_BAD_OBJ} foo.o
+ libtool -static foo.o -o libfoo.a
+ ${CC} ${CCFLAGS} main.c -dynamiclib -Os libfoo.a -dead_strip -o libmain.dylib
+ nm libmain.dylib | grep _bar | ${FAIL_IF_EMPTY}
+ nm libmain.dylib | grep _baz | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} libmain.dylib
+
+
+clean:
+ rm -rf *.dylib *.a *.o
--- /dev/null
+
+static int foo_count = 0;
+static int bar_count = 0;
+static int baz_count = 0;
+
+
+void foo() { ++foo_count; }
+
+void bar() { ++bar_count; }
+
+void __attribute__((visibility("hidden")))
+ baz() { ++baz_count; }
--- /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();
+
+int main()
+{
+ foo();
+ return 0;
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Tests that a non-weak symbol in an archive cleanly overrides
+# a weak symbol in a .o file with dead code stripping
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ ${CC} ${CCFLAGS} bar.c -c -o bar.o
+ libtool -static foo.o bar.o -o libfoobar.a
+ ${CC} ${CCFLAGS} main.c libfoobar.a -dead_strip -o main
+ nm main | grep _bar | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+ rm -rf main foo.o bar.o libfoobar.a
--- /dev/null
+
+
+void bar()
+{
+}
+
--- /dev/null
+
+extern void bar();
+
+
+// strong definition of foo overrides weak definition
+// in main.c, but this foo needs bar()
+void foo()
+{
+ bar();
+}
+
+void loadme()
+{
+}
+
--- /dev/null
+
+extern void loadme();
+
+
+void bad()
+{
+}
+
+// foo is first found be live here
+// then the use of loadme causes libfoo.a(foo.o)
+// to be loaded which overrides foo
+__attribute__((weak)) void foo()
+{
+ bad();
+}
+
+int main()
+{
+ foo();
+ loadme();
+ foo();
+ return 0;
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Tests that a non-weak symbol in an archive cleanly overrides
+# a weak symbol in a .o file with dead code stripping
+#
+# <rdar://problem/6294378> duplicate typeinfo in executable
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ libtool -static foo.o -o libfoo.a
+ ${CC} ${CCFLAGS} main.c libfoo.a -dead_strip -o main
+ nm main | grep _foo | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+ rm -rf main foo.o libfoo.a
--- /dev/null
+
+extern void good();
+
+void foo()
+{
+ good();
+}
+
+void loadme()
+{
+// foo();
+}
+
--- /dev/null
+
+extern void loadme();
+
+void good()
+{
+}
+
+void bad()
+{
+}
+
+// foo is first found be dead stripping here
+// then the use of loadme causes libfoo.a(foo.o)
+// to be loaded which overrides foo
+__attribute__((weak)) void foo()
+{
+ bad();
+}
+
+int main()
+{
+ foo();
+ loadme();
+ return 0;
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Tests that a common symbol can be used from an archive with -dead_strip. The tricky
+# part is that common symbols are not in the table of contents for archives.
+# If the linker seens a need for my_common, that won't trigger pulling in the .o
+# file from the archive. But the later use of foo will.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ ${FAIL_IF_BAD_OBJ} foo.o
+ libtool -static foo.o -o libfoo.a
+ ${CC} ${CCFLAGS} main.c -Os libfoo.a -dead_strip -o main
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main *.a *.o
--- /dev/null
+The point of this test that -dead_strip removes unreference code/data from archives
--- /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;
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2009-2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/7043256> ld64 can not find a -e entry point from an archive
+# <rdar://problem/8866673> "start" and other special symbols should start out initially undefined
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ libtool -static foo.o -o libfoo.a
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} bar.c -Os libfoo.a -o foo -Wl,-e,_foo -nostartfiles
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} bar.c -Os libfoo.a -dead_strip -o foo -Wl,-e,_foo
+ ${PASS_IFF_GOOD_MACHO} foo
+
+clean:
+ rm -rf foo libfoo.a foo.o
+
--- /dev/null
+
+void bar() {}
+
+
--- /dev/null
+
+
+void foo() {}
+
+
+
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Tests that a -init function can be pulled from an archive when using -dead_strip.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ libtool -static foo.o -o libfoo.a
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} bar.c -dynamiclib -Os libfoo.a -dead_strip -o libbar.dylib -init _foo
+ ${PASS_IFF_GOOD_MACHO} libbar.dylib
+
+clean:
+ rm -rf libbar.dylib libfoo.a foo.o
+
--- /dev/null
+
+void bar() {}
+
+
--- /dev/null
+
+
+void foo() {}
+
+
+
--- /dev/null
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Sanity check -dead_strip does not remove initializers and terminators
+#
+
+
+run: all
+
+all:
+ ${CXX} ${CCFLAGS} main.cxx other.cxx -dead_strip -o main
+ ${FAIL_IF_BAD_MACHO} main
+ nm main | grep dead_door_knob | ${FAIL_IF_STDIN}
+ nm main | grep ctr | ${FAIL_IF_EMPTY}
+ nm main | grep dtr | ${FAIL_IF_EMPTY}
+ ${CXX} ${CCFLAGS} -static main.cxx other.cxx -dead_strip -nostdlib -e _main -o main-static -Wl,-new_linker
+ ${FAIL_IF_BAD_MACHO} main-static
+ nm main-static | grep dead_door_knob | ${FAIL_IF_STDIN}
+ nm main-static | grep ctr | ${FAIL_IF_EMPTY}
+ nm main-static | grep dtr | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main-static
+
+clean:
+ rm -rf main main-static
--- /dev/null
+
+int main()
+{
+ return 0;
+}
+
+
+
+void dead_door_knob() { }
+
+
+extern "C" int ctr();
+extern "C" void dtr();
+
+
+int ctr() { return 10; }
+void dtr() { }
+
+
+#if __STATIC__
+extern "C" void __cxa_atexit();
+void __cxa_atexit() {}
+#endif
+
--- /dev/null
+
+extern "C" int ctr();
+extern "C" void dtr();
+
+class Foo
+{
+public:
+ Foo() : field(ctr()) { }
+ ~Foo() { dtr(); }
+private:
+ int field;
+};
+
+
+Foo f1;
+Foo f2;
+
+
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that N_NO_DEAD_STRIP bit survives ld -r
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ nm -m main.o | grep _bar | grep "no dead strip" | ${FAIL_IF_EMPTY}
+ nm -m main.o | grep _foo | grep "no dead strip" | ${FAIL_IF_EMPTY}
+ ${LD} -r main.o -o main2.o
+ nm -m main2.o | grep _bar | grep "no dead strip" | ${FAIL_IF_EMPTY}
+ nm -m main2.o | grep _foo | grep "no dead strip" | ${FAIL_IF_EMPTY}
+ ${CC} main2.o -o main
+ nm -m main | grep _bar | grep "no dead strip" | ${PASS_IFF_EMPTY}
+
+clean:
+ rm -rf main.o main2.o main
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+__attribute__((used)) static void foo()
+{
+}
+
+
+__attribute__((used)) void bar()
+{
+}
+
+
+int main()
+{
+ foo();
+ bar();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that symbols in no-dead-strip sections can be coalesced.
+# <rdar://problem/6578360> -dead_strip inhibits weak coalescing in no_dead_strip section
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} baz.c -c -o baz.o
+ libtool -static baz.o -o libbaz.a
+ ${CC} ${CCFLAGS} main.c foo.c libbaz.a -dead_strip -o main
+ nm -j main | grep _hidden | wc -l | grep 1 | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main baz.o libbaz.a
--- /dev/null
+void baz()
+{
+}
+
+
+#include "foo.c"
+
--- /dev/null
+
+// function can be coalesced and should not be dead stripped
+void __attribute__ ((weak, section ("__TEXT,__text_no_strip,regular,no_dead_strip"))) foo()
+{
+
+}
+
+
+// function should not be exported, can be coalesced, and should not be dead stripped
+void __attribute__ ((weak, visibility("hidden"), section ("__TEXT,__text_no_strip,regular,no_dead_strip"))) hidden()
+{
+
+}
+
+// bar should be dead stripped
+void __attribute__ ((weak, section ("__DATA,__text2"))) bar()
+{
+
+}
+
+__attribute__((constructor)) static void init()
+{
+ foo();
+ hidden();
+}
--- /dev/null
+
+// baz is in a lazily loaded archive
+extern void baz();
+
+int main()
+{
+ baz();
+ return 0;
+}
+
+
+#include "foo.c"
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check -dead_strip
+#
+# 1) in a main executable, dead globals are removed
+# 2) in a dylib/bundle with -exported_symbols_list, dead globals are removed
+# 3) in a dylib/bundle without -exported_symbols_list, dead globals are *not* removed
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c deadwood.c -dead_strip -o main-${ARCH}
+ size -l main-${ARCH} | grep __PAGEZERO | ${FAIL_IF_EMPTY}
+ ${FAIL_IF_BAD_MACHO} main-${ARCH}
+ nm -j main-${ARCH} | egrep 'dead_wood|dead_door' | ${FAIL_IF_STDIN}
+ ${CC} ${CCFLAGS} -dynamiclib main.c deadwood.c -dead_strip -exported_symbols_list main.exp -o dylib-${ARCH}
+ ${FAIL_IF_BAD_MACHO} dylib-${ARCH}
+ nm -j dylib-${ARCH} | grep dead | ${FAIL_IF_STDIN}
+ ${CC} ${CCFLAGS} -dynamiclib main.c deadwood.c -dead_strip -o dylib2-${ARCH}
+ ${FAIL_IF_BAD_MACHO} dylib2-${ARCH}
+ nm -j dylib2-${ARCH} | grep dead_door_knob | ${FAIL_IF_EMPTY}
+ nm -j dylib2-${ARCH} | grep deadwood | ${PASS_IFF_EMPTY}
+
+clean:
+ rm -rf main-* dylib-* dylib2-*
--- /dev/null
+The point of this test is a sanity check -dead_strip
+
+1) in a main executable, dead globals are removed
+2) in a dylib/bundle with -exported_symbols_list, dead globals are removed
+3) in a dylib/bundle without -exported_symbols_list, dead globals are *not* removed
--- /dev/null
+
+
+// deadwood() is local to its linkage unit and is unsed,
+// so reference to undef() is ok
+
+extern void undef();
+
+void dead_wood() __attribute__((visibility("hidden")));
+void dead_wood() { undef(); }
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+int main()
+{
+ return 0;
+}
+
+
+
+void dead_door_knob() { }
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test -dead_strip_dylibs
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib
+ ${CC} ${CCFLAGS} main.c libfoo.dylib libbar.dylib libbaz.dylib -o main
+ ${FAIL_IF_BAD_MACHO} main
+ otool -L main | grep libfoo.dylib | ${FAIL_IF_EMPTY}
+ otool -L main | grep libbar.dylib | ${FAIL_IF_EMPTY}
+ otool -L main | grep libbaz.dylib | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} main.c -DCALL_BAR libfoo.dylib libbar.dylib libbaz.dylib -o main -Wl,-dead_strip_dylibs
+ ${FAIL_IF_BAD_MACHO} main
+ otool -L main | grep libfoo.dylib | ${FAIL_IF_STDIN}
+ otool -L main | grep libbar.dylib | ${FAIL_IF_EMPTY}
+ otool -L main | grep libbaz.dylib | ${FAIL_IF_STDIN}
+ ${PASS_IFF} /usr/bin/true
+
+
+clean:
+
+ rm -rf libbar.dylib libfoo.dylib libbaz.dylib main
--- /dev/null
+
+int bar (void)
+{
+ return 1;
+}
--- /dev/null
+
+int baz (void)
+{
+ return 1;
+}
--- /dev/null
+int foo (void)
+{
+ return 1;
+}
--- /dev/null
+
+extern void bar();
+
+int main()
+{
+#if CALL_BAR
+ bar();
+#endif
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to check that -dead_strip does not remove
+# atoms in sections with the S_ATTR_NO_DEAD_STRIP bit set
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -dead_strip -o main-${ARCH}
+ ${FAIL_IF_BAD_MACHO} main-${ARCH}
+ nm -j main-${ARCH} | grep _bar | ${FAIL_IF_STDIN}
+ nm -j main-${ARCH} | grep _foo | ${PASS_IFF_STDIN}
+
+clean:
+ rm -rf main-*
--- /dev/null
+The point of this test is to check that -dead_strip does not remove
+atoms in sections with the S_ATTR_NO_DEAD_STRIP bit set
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+int main()
+{
+ return 0;
+}
+
+
+// foo should not be dead stripped
+void __attribute__ ((section ("__TEXT,__text_no_strip,regular,no_dead_strip"))) foo()
+{
+
+}
+
+// bar should be dead stripped
+void __attribute__ ((section ("__DATA,__text2"))) bar()
+{
+
+}
+
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test -mark_dead_strippable_dylib
+#
+# foo is used.
+# bar is not used by should still be linked
+# baz is not used and should be automatically not linked
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib -Wl,-mark_dead_strippable_dylib
+ ${CC} ${CCFLAGS} main.c libfoo.dylib libbar.dylib libbaz.dylib -o main
+ otool -L main | grep libfoo.dylib | ${FAIL_IF_EMPTY}
+ otool -L main | grep libbar.dylib | ${FAIL_IF_EMPTY}
+ otool -L main | grep libbaz.dylib | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+
+ rm -rf libbar.dylib libfoo.dylib libbaz.dylib main
--- /dev/null
+
+int bar (void)
+{
+ return 1;
+}
--- /dev/null
+
+int baz (void)
+{
+ return 1;
+}
--- /dev/null
+int foo (void)
+{
+ return 1;
+}
--- /dev/null
+
+extern void foo();
+
+int main()
+{
+ foo();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+# Test that linker option -demangle works
+#
+
+run: all
+
+all:
+ ${CXX} ${CXXFLAGS} main.cxx -c
+ ${FAIL_IF_SUCCESS} ${LD} -arch ${ARCH} -dylib main.o ${LD_SYSROOT} ${LD_NEW_LINKEDIT} -lSystem -o main 2>main1.fail
+ grep __ZN3Foo4doitEv main1.fail | ${FAIL_IF_EMPTY}
+ ${FAIL_IF_SUCCESS} ${LD} -arch ${ARCH} -dylib main.o ${LD_SYSROOT} ${LD_NEW_LINKEDIT} -lSystem -demangle -o main 2>main2.fail
+ grep 'Foo::doit()' main2.fail | ${PASS_IFF_STDIN}
+
+
+clean:
+ rm -f main.o main1.fail main2.fail main
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+class Foo
+{
+public:
+ Foo() {}
+
+ void doit();
+};
+
+
+
+int main()
+{
+ Foo f;
+ f.doit();
+
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2010-2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that LD_TRACE_* work
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ libtool -static foo.o -o libfoo.a
+ rm -rf trace_ars
+ export LD_TRACE_ARCHIVES=1 && export LD_TRACE_FILE=trace_ars && ${CC} ${CCFLAGS} main.c libfoo.a -o main
+ grep 'libfoo.a' trace_ars | ${FAIL_IF_EMPTY}
+ export LD_TRACE_ARCHIVES=1 && export LD_TRACE_FILE=trace_ars2 && ${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoo.a -o main
+ grep 'libfoo.a' trace_ars2 | ${FAIL_IF_EMPTY}
+ export LD_TRACE_ARCHIVES=1 && export LD_TRACE_FILE=trace_ars3 && ${CC} ${CCFLAGS} main.c libfoo.a -o main -all_load
+ grep 'libfoo.a' trace_ars3 | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+ rm -rf trace_dylibs
+ export LD_TRACE_DYLIBS=1 && export LD_TRACE_FILE=trace_dylibs && ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
+ grep 'libfoo.dylib' trace_dylibs | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+ rm -rf foo.o libfoo.a libfoo.dylib main trace_ars trace_ars2 trace_ars3 trace_dylibs
--- /dev/null
+void foo() {}
--- /dev/null
+extern void foo();
+
+int main()
+{
+ foo();
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Verify the linker errors out nicely when __dso_handle is defined in source.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.c -o test
+ ${FAIL_IF_BAD_MACHO} test
+ ${CC} ${CCFLAGS} test.c -DDSO_DEF=1 -o test-def 2>warnings.txt
+ ${FAIL_IF_BAD_MACHO} test-def
+ ${CC} ${CCFLAGS} test.c -DDSO_TENT=1 -o test-tent
+ ${PASS_IFF_GOOD_MACHO} test-tent
+
+
+clean:
+ rm -f test test-def test-tent warnings.txt
--- /dev/null
+#include <stdio.h>
+
+#if DSO_DEF
+ void* __dso_handle = NULL;
+#elif DSO_TENT
+ void* __dso_handle;
+#else
+ extern void* __dso_handle;
+#endif
+
+int main()
+{
+ printf("dso_handle=%p\n", __dso_handle);
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that old style _dtrace_probe$ labels are preserved
+#
+
+all:
+ ${CC} ${CCFLAGS} main.c -o main
+ nm main | grep _dtrace_probe | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main
--- /dev/null
+
+#include <stdio.h>
+
+#define DTRACE_STRINGIFY(s) #s
+#define DTRACE_TOSTRING(s) DTRACE_STRINGIFY(s)
+
+#define DTRACE_NOPS \
+ "nop" "\n\t" \
+ "nop" "\n\t" \
+ "nop" "\n\t"
+
+
+#define DTRACE_LAB(p, n) \
+ "__dtrace_probe$" DTRACE_TOSTRING(%=__LINE__) DTRACE_STRINGIFY(_##p##___##n)
+
+#define DTRACE_LABEL(p, n) \
+ ".section __DATA, __data\n\t" \
+ ".globl " DTRACE_LAB(p, n) "\n\t" \
+ DTRACE_LAB(p, n) ":\n\t" ".long 1f""\n\t" \
+ ".text" "\n\t" \
+ "1:"
+
+#define DTRACE_CALL(p,n) \
+ DTRACE_LABEL(p,n) \
+ DTRACE_NOPS
+
+#define DTRACE_CALL0ARGS(provider, name) \
+ __asm volatile ( \
+ DTRACE_CALL(provider, name) \
+ : \
+ : \
+ );
+
+int deadwood()
+{
+ DTRACE_CALL0ARGS(__foo__, test2)
+ return 0;
+}
+
+
+int main() {
+ int a = 1;
+
+ while(a) {
+ DTRACE_CALL0ARGS(__foo__, test1)
+ }
+
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that C++ coalescing throws away static probes associated
+# with weak functions that are coalesced away.
+# Build two programs that both should have the same number of probes
+# and hence the same DOF section size
+#
+
+all: simp coal
+ otool -lv coal | grep -A3 __dof_Number | grep size > coal-dof-size
+ otool -lv simp | grep -A3 __dof_Number | grep size > simp-dof-size
+ ${PASS_IFF_SUCCESS} diff coal-dof-size simp-dof-size
+
+Number.h: Number.d
+ dtrace -h -s Number.d
+
+a.o : a.cxx Number.h header.h
+ ${CXX} ${CXXFLAGS} -c -DFUNC=a a.cxx -o a.o
+
+b.o : a.cxx Number.h header.h
+ ${CXX} ${CXXFLAGS} -c -DFUNC=b a.cxx -o b.o
+
+c.o : a.cxx Number.h header.h
+ ${CXX} ${CXXFLAGS} -c -DFUNC=c a.cxx -o c.o
+
+coal : a.o b.o c.o
+ ${CXX} -dynamiclib a.o b.o c.o -o coal
+
+simp : x.cxx Number.h
+ ${CXX} -dynamiclib x.cxx -o simp
+
+
+
+clean:
+ rm -rf coal simp a.o b.o c.o Number.h coal-dof-size simp-dof-size
--- /dev/null
+provider Number {
+ probe hit(int value);
+};
--- /dev/null
+
+#include <stdio.h>
+
+#include "header.h"
+
+
+void FUNC() { foo(); }
+
--- /dev/null
+
+#include "Number.h"
+
+#define LOTS_O_PROBES { NUMBER_HIT(1); NUMBER_HIT(2); NUMBER_HIT(3); NUMBER_HIT(4); }
+
+
+inline void foo() {
+ LOTS_O_PROBES
+}
+
+
--- /dev/null
+
+#include "header.h"
+
+void bar() { LOTS_O_PROBES }
+
+
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a progam with dtrace static probes
+#
+
+all: run
+
+run: main main-dead_strip libmain.dylib main-r
+ ${FAIL_IF_BAD_MACHO} main
+ ${PASS_IFF_GOOD_MACHO} main-r
+
+main: main.c foo.h bar.h
+ ${CC} ${CCFLAGS} main.c -o main
+
+main-dead_strip: main.c foo.h bar.h
+ ${CC} ${CCFLAGS} main.c -o main-dead_strip -dead_strip
+
+main-r: main.c foo.h bar.h
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ #${FAIL_IF_BAD_OBJ} main.o
+ ${LD} -r main.o -o main-r.o
+ #${FAIL_IF_BAD_OBJ} main-r.o
+ ${CC} ${CCFLAGS} main-r.o -o main-r
+
+libmain.dylib: main.c foo.h bar.h
+ ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain.dylib
+
+foo.h: foo.d
+ dtrace -h -s foo.d
+
+bar.h: bar.d
+ dtrace -h -s bar.d
+
+clean:
+ rm -rf main libmain.dylib main-r main-dead_strip foo.h bar.h *.o
--- /dev/null
+typedef int weirdType;
+
+provider Bar {
+ probe count1(weirdType);
+};
+
+#pragma D attributes Evolving/Evolving/Common provider Bar args
--- /dev/null
+The point of this test is a sanity check that ld can link a progam with dtrace static probes
--- /dev/null
+typedef int weirdType2;
+
+provider Foo {
+ probe count1(weirdType2);
+};
+
+
+#pragma D attributes Evolving/Evolving/Common provider Foo args
--- /dev/null
+
+#include <stdio.h>
+
+typedef int weirdType;
+typedef int weirdType2;
+
+#include "foo.h"
+#include "bar.h"
+
+
+int deadwood()
+{
+ if ( BAR_COUNT1_ENABLED() )
+ BAR_COUNT1(2);
+ return 0;
+}
+
+
+int main() {
+ int a = 1;
+
+ while(a) {
+ if ( FOO_COUNT1_ENABLED() )
+ FOO_COUNT1(1);
+ printf("test\n");
+ if ( BAR_COUNT1_ENABLED() )
+ BAR_COUNT1(2);
+ sleep(1);
+ }
+
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2007-2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that multiple duplicate symbols are reported.
+#
+
+all:
+ ${CC} -arch ${ARCH} -c main_extern.c
+ ${CC} -arch ${ARCH} -c main_no_extern.c
+ ${CC} -arch ${ARCH} -c duplicates.c
+ ${CC} -arch ${ARCH} -dynamiclib -o duplicates.dylib duplicates.o
+ libtool -static -o duplicates.a duplicates.o
+
+ # simple case of directly linking duplicates should fail
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main_extern.o duplicates.o 2>&1 | grep "2 duplicate symbols" | ${FAIL_IF_EMPTY}
+
+
+ # duplicates in a dylib succeed
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} main_extern.o duplicates.dylib 2>&1 | grep "2 duplicate symbols" | ${FAIL_IF_STDIN}
+
+ # static lib - only fail if module containing duplicate symbols is actually referenced
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main_extern.o duplicates.a 2>&1 | grep "2 duplicate symbols" | ${FAIL_IF_EMPTY}
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} main_no_extern.o duplicates.a 2>&1 | grep "2 duplicate symbols" | ${FAIL_IF_STDIN}
+
+ # simple case should succeed if we dead strip because none of the duplicates are referenced
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -dead_strip main_extern.o duplicates.o
+
+ rm -f a.out *.o *.a *.dylib
+ ${PASS_IFF} true
--- /dev/null
+#include <stdio.h>
+
+void a() {
+}
+
+void b() {
+}
+
+void c() {
+}
--- /dev/null
+/*
+This file references an extern function c() that lives in
+a separate compilation unit that also has a() and b().
+*/
+
+extern void c();
+
+void a() {
+}
+
+void b() {
+}
+
+int main() {
+c();
+}
--- /dev/null
+/*
+This file contains symbols that are duplicated in another file,
+but does not reference anything that would pull in the duplicates.
+*/
+
+void a() {
+}
+
+void b() {
+}
+
+int main() {
+}
--- /dev/null
+##
+# Copyright (c) 2007-2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that using -all_load to pull all .o files out of an archive
+# proeduces good "debug notes".
+#
+
+run:
+ ${CC} ${CCFLAGS} -gdwarf-2 foo.c -c -o foo.o
+ ${FAIL_IF_BAD_OBJ} foo.o
+ ${CC} ${CCFLAGS} -gdwarf-2 bar.c -c -o bar.o
+ ${FAIL_IF_BAD_OBJ} bar.o
+ ${CC} ${CCFLAGS} -gdwarf-2 baz.c -c -o baz.o
+ ${FAIL_IF_BAD_OBJ} baz.o
+ libtool -static bar.o baz.o foo.o -o liball.a
+ ${CC} ${CCFLAGS} liball.a -all_load -dynamiclib -o liball.dylib -nodefaultlibs -lSystem
+ ${FAIL_IF_BAD_MACHO} liball.dylib
+ nm -fap liball.dylib | ./stabs-filter.pl > liball.dylib.stabs
+ ${PASS_IFF} diff liball.dylib.stabs expected-stabs
+
+clean:
+ rm -rf *.o liball.a liball.dylib liball.dylib.stabs
--- /dev/null
+void bar() {}
+
--- /dev/null
+void baz() {}
--- /dev/null
+Test that using -all_load to pull all .o files out of an archive
+proeduces good "debug notes".
--- /dev/null
+0000 SO CWD/
+0000 SO bar.c
+0001 OSO CWD/liball.a(bar.o)
+0000 BNSYM
+0000 FUN _bar
+0000 FUN
+0000 ENSYM
+0000 SO
+0000 SO CWD/
+0000 SO baz.c
+0001 OSO CWD/liball.a(baz.o)
+0000 BNSYM
+0000 FUN _baz
+0000 FUN
+0000 ENSYM
+0000 SO
+0000 SO CWD/
+0000 SO foo.c
+0001 OSO CWD/liball.a(foo.o)
+0000 BNSYM
+0000 FUN _foo
+0000 FUN
+0000 ENSYM
+0000 SO
--- /dev/null
+void foo() {}
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+use Cwd;
+
+my $dir = getcwd;
+#my $xxx = $ARGV[1];
+
+while(<>)
+{
+ # get stabs lines that match "NNNNNNN - xxx"
+ if(m/^([0-9a-f]+) - ([0-9a-f]+) (.*?)$/)
+ {
+ # replace any occurances of cwd path with $CWD
+ my $line = $3;
+ if($line =~ m/(.*?)$dir(.*?)$/)
+ {
+ $line = $1 . "CWD" . $2;
+ }
+
+ printf "$line\n";
+ }
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# produces good "debug notes" stabs from dwarf .o files after
+# some of the .o files are merged with ld -r.
+# Running nm through stabs-filter.pl produces connonical stabs
+# that can be diffed against a checked in know good set of stabs
+#
+
+run: all
+
+all:
+ ${CXX} ${CCXXFLAGS} -gdwarf-2 foo.cxx -c -o foo.o -mdynamic-no-pic
+ ${CXX} ${CCXXFLAGS} -gdwarf-2 bar.cxx -c -o bar.o -mdynamic-no-pic
+ ${LD} -r -arch ${ARCH} foo.o bar.o -o foobar.o
+ ${CXX} ${CCXXFLAGS} -gdwarf-2 main.cxx -c -o main.o -mdynamic-no-pic
+ ${CXX} ${CCXXFLAGS} foobar.o main.o -o main
+ ${FAIL_IF_BAD_MACHO} main
+ nm -ap main | ./stabs-filter.pl > main.stabs
+ ${PASS_IFF} diff main.stabs expected-stabs
+
+
+clean:
+ rm -rf foo.o bar.o main.o foobar.o main main.stabs
--- /dev/null
+int bar()
+{
+ return 10;
+}
--- /dev/null
+The point of this test is a sanity check that ld
+produces good "debug notes" stabs from dwarf .o files after
+some of the .o files are merged with ld -r.
+Running nm through stabs-filter.pl produces connonical stabs
+that can be diffed against a checked in know good set of stabs
--- /dev/null
+0000 SO CWD/
+0000 SO main.cxx
+0001 OSO CWD/main.o
+0000 BNSYM
+0000 FUN _main
+0000 FUN
+0000 ENSYM
+0000 SO
+0000 SO CWD/
+0000 SO foo.cxx
+0001 OSO CWD/foo.o
+0000 BNSYM
+0000 FUN __Z3foov
+0000 FUN
+0000 ENSYM
+0000 SO
+0000 SO CWD/
+0000 SO bar.cxx
+0001 OSO CWD/bar.o
+0000 BNSYM
+0000 FUN __Z3barv
+0000 FUN
+0000 ENSYM
+0000 SO
--- /dev/null
+int foo()
+{
+ return 10;
+}
--- /dev/null
+int main()
+{
+ return 0;
+}
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+use Cwd;
+
+my $dir = getcwd;
+#my $xxx = $ARGV[1];
+
+while(<>)
+{
+ # get stabs lines that match "NNNNNNN - xxx"
+ if(m/^([0-9a-f]+) - ([0-9a-f]+) (.*?)$/)
+ {
+ # replace any occurances of cwd path with $CWD
+ my $line = $3;
+ if($line =~ m/(.*?)$dir(.*?)$/)
+ {
+ $line = $1 . "CWD" . $2;
+ }
+
+ printf "$line\n";
+ }
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify that UUID is the same for the two binaries built
+# from the same source file but with different intermediate
+# object file paths.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -gdwarf-2 main.c -c -o main1.o
+ ${CC} ${CCFLAGS} -gdwarf-2 main.c -c -o main2.o
+ ${CC} ${CCFLAGS} main1.o -o main1
+ ${CC} ${CCFLAGS} main2.o -o main2
+ otool -lv main1 | grep -A3 UUID > main1.uuid
+ otool -lv main2 | grep -A3 UUID > main2.uuid
+ ${PASS_IFF} diff main1.uuid main2.uuid
+
+
+clean:
+ rm -rf main1.o main2.o main1 main2 main1.uuid main2.uuid
--- /dev/null
+
+
+void foo()
+{
+
+}
+
+
+void bar()
+{
+ foo();
+}
+
+
+
+int main()
+{
+ bar();
+ return 0;
+}
+
+
+
--- /dev/null
+##
+# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# produces good "debug notes" stabs from dwarf .o files
+# Running nm through stabs-filter.pl produces connonical stabs
+# that can be diffed against a checked in know good set of stabs
+#
+
+run: all
+
+all:
+ ${CXX} ${CCXXFLAGS} -gdwarf-2 hello.cxx -c -o hello.o
+ ${CXX} ${CCXXFLAGS} -gdwarf-2 other.cxx -c -o other.o
+ ${CXX} ${CCXXFLAGS} -gdwarf-2 hello.o other.o -o hello -Wl,-order_file,hello.order
+ ${FAIL_IF_BAD_MACHO} hello
+ nm -ap hello | ./stabs-filter.pl > hello.stabs
+ ${PASS_IFF} diff hello.stabs expected-stabs
+
+clean:
+ rm -rf hello hello.o other.o hello.stabs
--- /dev/null
+The point of this test is a sanity check that ld
+produces good "debug notes" stabs from dwarf .o files
+Running nm through stabs-filter.pl produces connonical stabs
+that can be diffed against a checked in know good set of stabs
--- /dev/null
+0000 SO CWD/
+0000 SO hello.cxx
+0001 OSO CWD/hello.o
+0000 BNSYM
+0000 FUN _main
+0000 FUN
+0000 ENSYM
+0000 BNSYM
+0000 FUN __Z3fooi
+0000 SOL ./header.h
+0000 FUN
+0000 ENSYM
+0000 SO
+0000 SO CWD/
+0000 SO other.cxx
+0001 OSO CWD/other.o
+0000 BNSYM
+0000 FUN __Z3bari
+0000 FUN
+0000 ENSYM
+0000 BNSYM
+0000 FUN .my_non_standard_function_name
+0000 FUN
+0000 ENSYM
+0000 STSYM .my_non_standard_name_static
+0000 STSYM .my_non_standard_name
+0000 STSYM __ZZ3bariE8bar_init
+0000 GSYM _init
+0000 GSYM _uninit
+0000 STSYM __ZZ3bariE10bar_uninit
+0000 STSYM __ZL7suninit
+0000 STSYM __ZL5sinit
+0000 SO
--- /dev/null
+
+
+inline int foo(int x)
+{
+ return x + 10;
+}
+
+extern int bar(int x);
\ No newline at end of file
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+#include "header.h"
+
+
+int main()
+{
+ foo(bar(3));
+ fprintf(stdout, "hello\n");
+}
\ No newline at end of file
--- /dev/null
+
+# order __data section so even if different compiler lays out data
+# differently, linker lays out the same, so stabs are in same order
+.my_non_standard_name_static
+.my_non_standard_name
+__ZZ3bariE8bar_init
+_init
+_uninit
+__ZZ3bariE10bar_uninit
+__ZL7suninit
+__ZL5sinit
+
+
+
+
+
--- /dev/null
+
+#include "header.h"
+
+int uninit;
+int init = 1;
+static int custom __asm__(".my_non_standard_name") = 1;
+static int suninit;
+static int sinit=0;
+static int scustominit __asm__(".my_non_standard_name_static") = 1;
+
+int bar(int x)
+{
+ static int bar_uninit;
+ static int bar_init=3;
+ bar_uninit = x;
+ scustominit = x;
+ custom = x;
+ return 20 + suninit + sinit +
+ bar_init + bar_uninit + foo(x);
+}
+
+extern void disappear() __asm__("lbegone");
+void disappear() {}
+
+extern void foo() __asm__(".my_non_standard_function_name");
+void foo() { disappear(); }
+
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+use Cwd;
+
+my $dir = getcwd;
+#my $xxx = $ARGV[1];
+
+while(<>)
+{
+ # get stabs lines that match "NNNNNNN - xxx"
+ if(m/^([0-9a-f]+) - ([0-9a-f]+) (.*?)$/)
+ {
+ # replace any occurances of cwd path with $CWD
+ my $line = $3;
+ if($line =~ m/(.*?)$dir(.*?)$/)
+ {
+ $line = $1 . "CWD" . $2;
+ }
+
+ printf "$line\n";
+ }
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# strips out the dwarf segment by default
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -gdwarf-2 hello.c -o dwarf-hello-${ARCH}
+ ${FAIL_IF_BAD_MACHO} dwarf-hello-${ARCH}
+ size -l dwarf-hello-${ARCH} | grep __DWARF | ${PASS_IFF_EMPTY}
+
+clean:
+ rm -rf dwarf-hello-*
--- /dev/null
+The point of this test is a sanity check that ld strips out the dwarf segment by default
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify that ld -r -S preserves the __objc_imageinfo section
+#
+
+IMAGE_INFO = "__image_info"
+
+ifeq ($(ARCH),x86_64)
+ IMAGE_INFO = "__objc_imageinfo"
+endif
+ifeq ($(FILEARCH),arm)
+ IMAGE_INFO = "__objc_imageinfo"
+endif
+
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -gdwarf-2 hello.m -c -o hello.o
+ ${LD} -r -S hello.o -o hello-r.o
+ size -l hello-r.o | grep ${IMAGE_INFO} | ${PASS_IFF_STDIN}
+
+
+
+clean:
+ rm -rf hello.o hello-r.o
--- /dev/null
+#include <Foundation/Foundation.h>
+
+
+int main()
+{
+ [NSString stringWithUTF8String: "hello"];
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld -S
+# produces no debug notes (stabs)
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -gdwarf-2 hello.c -Wl,-S -o hello
+ #${CC} ${CCFLAGS} -gdwarf-2 hello.c -o hello
+ ${FAIL_IF_BAD_MACHO} hello
+ nm -ap hello | grep -e " - " | ${PASS_IFF_EMPTY}
+
+clean:
+ rm -rf hello hello.dSYM
--- /dev/null
+The point of this test is a sanity check that ld -S produces no debug notes (stabs)
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that libfoo.dylib can be aliases with a symlink or
+# as another dylib and still link
+#
+
+run: all
+
+all: libfoo.dylib libbar.dylib libbaz.dylib
+ ${CC} ${CCFLAGS} main.c -o main -lfoo -lbar -lbaz -L. -Wl,-w
+ ${PASS_IFF_GOOD_MACHO} main
+
+libfoo.dylib : foo.c
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+
+libbar.dylib : bar.c
+ ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib -install_name libfoo.dylib
+
+libbaz.dylib : libfoo.dylib
+ ln -s libfoo.dylib libbaz.dylib
+
+clean:
+ rm -rf *.dylib main
--- /dev/null
+void bar() { }
--- /dev/null
+void foo() { }
--- /dev/null
+extern void foo();
+extern void bar();
+
+int main() {
+ foo();
+ bar();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that a program can have is "main" in a dylib
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain.dylib
+ ${CC} ${CCFLAGS} foo.c libmain.dylib -o main -Wl,-new_main
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf libmain.dylib main
--- /dev/null
+void foo() {}
--- /dev/null
+#include <stdio.h>
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2007-2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Test that searches for indirect libraries does not cause a cycle
+# <rdar://problem/5277857> OpenGL.framework and X11 both have a libGL.dylib which can cause ld to segfault if both are found
+#
+
+all: all-${ARCH}
+
+all-i386: all-mac
+all-x86_64: all-mac
+all-armv6: all-good
+all-armv7: all-good
+
+
+all-mac:
+ mkdir -p other
+ ${CC} foo.c -dynamiclib -o other/libfoo.dylib -mmacosx-version-min=10.4
+ ${CC} bar.c -dynamiclib -o libbar.dylib other/libfoo.dylib -sub_library libfoo -mmacosx-version-min=10.4
+ ${CC} foo.c -dynamiclib -o libfoo.dylib libbar.dylib -sub_library libbar -mmacosx-version-min=10.4
+ ${CC} main.c libfoo.dylib -o main -L. 2>errmsg || true
+ grep "cycle" errmsg | ${PASS_IFF_STDIN}
+
+all-good:
+ ${PASS_IFF} true
+
+
+clean:
+ rm -rf other libfoo.dylib libbar.dylib main errmsg
--- /dev/null
+void bar() { }
--- /dev/null
+void foo() { }
--- /dev/null
+extern void unfindable();
+
+int main() {
+ unfindable();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+# Verify upward dylib options work
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -Wl,-upward-lbar -L.
+ otool -lv libfoo.dylib | grep -A2 LC_LOAD_UPWARD_DYLIB | grep libbar.dylib | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -Wl,-upward_library,libbar.dylib
+ otool -lv libfoo.dylib | grep -A2 LC_LOAD_UPWARD_DYLIB | grep libbar.dylib | ${FAIL_IF_EMPTY}
+ mkdir -p Bar.framework
+ ${CC} ${CCFLAGS} bar.c -dynamiclib -o Bar.framework/Bar
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -Wl,-upward_framework,Bar -F.
+ otool -lv libfoo.dylib | grep -A2 LC_LOAD_UPWARD_DYLIB | grep Bar.framework/Bar | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+clean:
+ rm -rf libfoo.dylib libbar.dylib Bar.framework
--- /dev/null
+void bar() {}
--- /dev/null
+extern void bar();
+
+void foo()
+{
+ bar();
+}
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+PWD = $(shell pwd)
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+# Verify that if -dylib_file option points to a missing, file the link does not fail
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib -install_name "${PWD}/libbar.dylib"
+ ${CC} ${CCFLAGS} foo.c "${PWD}/libbar.dylib" -dynamiclib -o libfoo.dylib -sub_library libbar
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -dylib_file "${PWD}/libbar.dylib:libbar2.dylib" 2>warnings.log
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf *.dylib main warnings.log
--- /dev/null
+
+
+
+void bar()
+{
+}
+
+#if BAR_EXTRA
+void bar_extra()
+{
+}
+#endif
+
--- /dev/null
+
+extern void bar();
+
+void foo()
+{
+ bar();
+}
--- /dev/null
+
+extern void foo();
+extern void bar();
+extern void bar_extra();
+
+int main()
+{
+ foo();
+ bar();
+#if BAR_EXTRA
+ bar_extra();
+#endif
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+PWD = $(shell pwd)
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+# Verify that -dylib_file option allows you to replace an indirect dylib
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib -install_name "${PWD}/libbar.dylib"
+ ${CC} ${CCFLAGS} bar.c -DBAR_EXTRA -dynamiclib -o libbar2.dylib -install_name "${PWD}/libbar.dylib"
+ ${CC} ${CCFLAGS} foo.c "${PWD}/libbar.dylib" -dynamiclib -o libfoo.dylib -sub_library libbar
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
+ # verify that if main needs bar_extra, it fails
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -DBAR_EXTRA libfoo.dylib -o main 2> fail.log
+ # verify that if main needs bar_extra, it works with -dylib_file option
+ ${CC} ${CCFLAGS} main.c -DBAR_EXTRA libfoo.dylib -o main -dylib_file "${PWD}/libbar.dylib:libbar2.dylib"
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf *.dylib main fail.log
--- /dev/null
+
+
+
+void bar()
+{
+}
+
+#if BAR_EXTRA
+void bar_extra()
+{
+}
+#endif
+
--- /dev/null
+Verify that -dylib_file option allows you to replace an indirect dylib
--- /dev/null
+
+extern void bar();
+
+void foo()
+{
+ bar();
+}
--- /dev/null
+
+extern void foo();
+extern void bar();
+extern void bar_extra();
+
+int main()
+{
+ foo();
+ bar();
+#if BAR_EXTRA
+ bar_extra();
+#endif
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+# Verify -init option creates a LC_ROUTINES load command
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -init __init
+ otool -lv libfoo.dylib | grep LC_ROUTINES | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+clean:
+ rm -rf libfoo.dylib
--- /dev/null
+void _init() {
+}
--- /dev/null
+ \r
+char *gS = (void *)0;\r
+\r
+void LibInit(void)\r
+{\r
+}\r
+ \r
+\r
+void OutputString(char *String)\r
+{ \r
+ gS = String;\r
+}\r
+\r
--- /dev/null
+##
+# Copyright (c) 2005-2010 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@
+##
+
+#
+# This test verifies ld -preload support required for mtoc
+# to create a PE/COFF image that will work with EFI.
+# The mach-o file and pecoff files are parsed with the
+# test.py script to make sure the images look OK.
+#
+# Note: We should fail with an error condition if any of the all:
+# commands fail.
+# Note: Currently does not support ARM due to no ARM support in
+# /usr/local/efi/bin/objdump
+#
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+LOCAL_CC_FLAGS = -g -Os -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-missing-braces
+
+#ARCH=x86_64
+#ARCH=i386
+
+
+ifeq (${ARCH},x86_64)
+ OBJ_DUMP_ARCH=efi-app-x86-64
+ LD_ARG=
+else
+ OBJ_DUMP_ARCH=efi-app-ia32
+ LD_ARG=-read_only_relocs suppress
+endif
+
+
+#
+# Compile the file
+#
+
+all:
+ ${CC} -arch $(ARCH) -o LibTest1.obj $(LOCAL_CC_FLAGS) -c LibTest.c
+ libtool -static -o LibTest1.lib LibTest1.obj
+ ${CC} -arch $(ARCH) -o MtocTest1.obj $(LOCAL_CC_FLAGS) -c MtocTest.c
+ libtool -static -o MtocTest1.lib MtocTest1.obj
+ ${LD} -arch $(ARCH) -o MtocTest1.macho -u __ModuleEntryPoint -e __ModuleEntryPoint $(LD_ARG) -preload -segalign 0x20 -pie -seg1addr 0x240 -map MtocTest1.map LibTest1.lib MtocTest1.lib
+ /usr/local/efi/bin/mtoc -subsystem application -align 0x20 -d MtocTest1.macho MtocTest1.macho MtocTest1.pecoff
+ otool -rR MtocTest1.macho > otool-reloc.log
+ otool -l MtocTest1.macho > otool-load.log
+ /usr/local/efi/bin/objdump -b $(OBJ_DUMP_ARCH) -x MtocTest1.pecoff > objdump-raw.log
+ ${PASS_IFF_SUCCESS} ./mtoctest.py --arch $(ARCH)
+
+
+clean:
+ rm -rf *.pecoff *.macho *.obj *.log *.lib *.map
+
+
--- /dev/null
+\r
+extern void LibInit(void);\r
+\r
+extern void OutputString(char *String);\r
+\r
+\r
+\r
+char * gString = "\nHello world via mtoc - reloc\n"; \r
+\r
+int gWhyAreUninitializedGlobalsBad;\r
+ \r
+\r
+void _ModuleEntryPoint(void)\r
+{ \r
+ //__asm__ __volatile__ ("int $3"); \r
+\r
+ LibInit ();\r
+ gWhyAreUninitializedGlobalsBad =1;\r
+ OutputString(gString);\r
+}\r
+\r
--- /dev/null
+#!/usr/bin/python
+
+import sys
+import getopt
+
+def Usage():
+ print "Unkown command line args"
+
+
+def main():
+ try:
+ opts, args = getopt.getopt(sys.argv[1:],"hav:",["help","arch=","verbose"])
+ except getopt.GetoptError:
+ print "Unkown command line args"
+ sys.exit(2)
+
+ Verbose = 0
+ for o,a in opts:
+ if o in ("-h", "--help"):
+ Usage ()
+ sys.exit ()
+ elif o in ("-a", "--arch"):
+ Arch = a
+ else:
+ Usage ()
+ sys.exit ()
+
+
+ if Verbose:
+ print "\nmach-o load commands:"
+ otoolload = open("otool-load.log", "r")
+ data = otoolload.read()
+ otoolload.close()
+
+
+ # extract extry point from ' ss 0x00000000 eflags 0x00000000 eip 0x00000259 cs 0x00000000'
+ if Arch == "i386":
+ eip = data.find("eip")
+ if eip != -1:
+ EntryPoint = int (data[eip + 4:eip + 4 + 10], 16)
+
+ if Arch == "arm":
+ r15 = data.find("r15")
+ if r15 != -1:
+ EntryPoint = int (data[r15 + 4:r15 + 4 + 10], 16)
+
+ # extract entry point from ' r15 0x0000000000000000 rip 0x0000000000000253'
+ if Arch == "x86_64":
+ rip = data.find("rip")
+ if rip != -1:
+ EntryPoint = int (data[rip + 4:rip + 4 + 18], 16)
+
+ if EntryPoint == 0:
+ print "FAIL - no entry point for PE/COFF image"
+ sys.exit(-1)
+ else:
+ if Verbose:
+ print "Entry Point = 0x%08x" % EntryPoint
+
+
+ if Verbose:
+ print "\nPE/COFF dump:"
+ objdump = open("objdump-raw.log", "r")
+ data = objdump.read()
+ objdump.close()
+
+ # Extract 'SizeOfImage 00000360'
+ Index = data.find("SizeOfImage")
+ End = data[Index:].find("\n")
+ SizeOfImage = int (data[Index+11:Index + End], 16);
+ if Verbose:
+ print "SizeOfImage = 0x%08x" % SizeOfImage
+
+ #Parse ' 0 .text 00000080 00000240 00000240 00000240 2**2'
+ # ' CONTENTS, ALLOC, LOAD, READONLY, CODE '
+ EndOfTable = data.find("SYMBOL TABLE:")
+ Index = data.find("Idx Name")
+ End = data[Index:].find("\n")
+ Index = Index + End + 1
+
+ PeCoffEnd = 0
+ while Index < EndOfTable:
+ End = data[Index:].find("\n")
+ Split = data[Index:Index+End].split()
+ # Split[0] Indx
+ # Split[1] Name i.e. .text
+ # Split[2] Size
+ # Split[3] VMA
+ # Split[4] LMA
+ # Split[5] File Off
+ # Split[6] Align
+ if int(Split[3],16) != int(Split[5],16):
+ print "FAIL - %s VMA %08x not equal File off %08x XIP will not work" % (Split[1], int(Split[3],16), int(Split[5],16))
+ sys.exit(-1)
+
+ if int(Split[3],16) + int(Split[2],16) > PeCoffEnd:
+ PeCoffEnd = int(Split[3],16) + int(Split[2],16)
+
+ if Split[1] == ".text":
+ SecStart = int(Split[3],16)
+ SecEnd = int(Split[3],16) + int(Split[2],16)
+ if (EntryPoint < SecStart) or (EntryPoint > SecEnd):
+ print "FAIL - Entry point (0x%x) not in .text section (0x%x - 0x%x)" % (EntryPoint, SecStart, SecEnd)
+ sys.exit(-1)
+
+ if Verbose:
+ print "%10s" % Split[1] + ' ' + Split[2] + ' ' + Split[3] + ' ' + Split[4] + ' ' + Split[5] + " End = %x" % PeCoffEnd
+ Index += data[Index:].find("\n") + 1
+ Index += data[Index:].find("\n") + 1
+
+ if SizeOfImage < PeCoffEnd:
+ print "FAIL - PE/COFF Header SizeOfImage (0x%x) is not correct. Image larger than size (0x%x)." % (SizeOfImage, PeCoffEnd)
+ sys.exit(-1)
+
+ if Verbose:
+ print "\nmach-o relocations:"
+ otoolreloc = open("otool-reloc.log", "r")
+ lines = otoolreloc.readlines()
+ otoolreloc.close()
+
+ found = False
+ for line in lines:
+ if found:
+ chunk = line.split()
+ if Verbose:
+ print chunk[0]
+ if line.find ("address") > -1:
+ found = True
+
+ if Verbose:
+ print
+
+
+if __name__ == "__main__":
+ main()
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+# Verify label in __eh_frame can be removed with no impact
+#
+run: all
+
+all:
+ ${CC} ${CCXXFLAGS} foo.c -c -o foo.o -fexceptions
+ ${CC} ${CCXXFLAGS} bar.c -c -o bar.o -fexceptions
+ ${CC} ${CCXXFLAGS} baz.c -c -o baz.o -fexceptions
+ ${LD} -r foo.o -no_eh_labels -o foo.no.o
+ ${LD} -r bar.o -no_eh_labels -o bar.no.o
+ ${LD} -r baz.o -no_eh_labels -o baz.no.o
+ ${LD} -r foo.o bar.o baz.o -o foobarbaz.o
+ ${LD} -r foo.no.o bar.no.o baz.no.o -o foobarbaz.no.o
+ ${OBJECTDUMP} -no_content -no_sort foobarbaz.o > foobarbaz.dump
+ ${OBJECTDUMP} -no_content -no_sort foobarbaz.no.o > foobarbaz.no.dump
+ ${FAIL_IF_ERROR} dwarfdump --eh-frame --verify foobarbaz.no.o >/dev/null
+ ${PASS_IFF_SUCCESS} diff foobarbaz.dump foobarbaz.no.dump
+
+
+clean:
+ rm -f foo.o bar.o baz.o foo.no.o bar.no.o baz.no.o foobarbaz.*
--- /dev/null
+
+extern void other();
+
+void bar() {
+ other();
+ other();
+}
+
+void __attribute__((weak)) my_weak() {
+ other();
+ other();
+}
+
+void bar2() {
+ other();
+ other();
+}
+
--- /dev/null
+
+extern void other();
+
+void baz() {
+ other();
+ other();
+}
+
+void __attribute__((weak)) my_weak() {
+ other();
+ other();
+}
+
+void baz2() {
+ other();
+ other();
+}
+
--- /dev/null
+
+extern void other();
+
+void foo() {
+ other();
+ other();
+}
+
+void __attribute__((weak)) my_weak() {
+ other();
+ other();
+}
+
+void foo2() {
+ other();
+ other();
+}
+
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+#
+# <rdar://problem/5726215> comdat warnings in ld -r
+#
+# also use -falign-functions to force an out of order coalesing
+#
+run: all
+
+all:
+ ${CXX} ${CCXXFLAGS} foo.cxx -c -o foo.o
+ ${CXX} ${CCXXFLAGS} bar.cxx -c -o bar.o -falign-functions=32
+ ${CXX} ${CCXXFLAGS} baz.cxx -c -o baz.o
+ ${LD} -r foo.o bar.o baz.o -o foobarbaz.o 2> warnings.log
+ grep warning warnings.log | ${PASS_IFF_EMPTY}
+
+
+clean:
+ rm foo.o bar.o baz.o foobarbaz.o warnings.log
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include "func.h"
+
+void bar()
+{
+ func();
+}
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include "func.h"
+
+void baz()
+{
+ func();
+}
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+#include "func.h"
+
+
+void test()
+{
+ func();
+}
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+extern int global;
+extern void foo(int);
+
+
+// this weak func() will have unwind info and a LSDA
+inline int func()
+{
+ global = 1;
+ return global;
+}
+
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# There are two copies of func(). The one from
+# foo.o is weak and has an FDE (.eh) and LSDA.
+# The one from bar.o is not weak and does not have
+# exception info. Verify that since linker uses func()
+# from bar.o that it does not use exception info
+# from foo.o
+#
+# <rdar://problem/5667688> wrong EH information might be used
+#
+
+run: all
+
+all:
+ ${CXX} ${CCXXFLAGS} foo.cxx -c -o foo.o
+ ${CXX} ${CCXXFLAGS} foo2.cxx -c -o foo2.o
+ ${CXX} ${CCXXFLAGS} bar.cxx -c -o bar.o -fno-exceptions
+ ${CXX} ${CCXXFLAGS} -dynamiclib foo.o foo2.o bar.o -o libfoobar.dylib -Wl,-map,libfoobar.map
+ # verify .eh symbol is missing or is from bar.o (file 3)
+ grep '\[ 2\] __Z4funcv.eh' libfoobar.map | ${FAIL_IF_STDIN}
+ # verify no LSDA
+ size -l libfoobar.dylib | grep __gcc_except_tab | ${PASS_IFF_EMPTY}
+
+clean:
+ rm foo.o foo2.o bar.o libfoobar.map libfoobar.dylib
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+// this non-weak func() will have no unwind info and no LSDA
+int func() { return 0; }
+
+void foo(int x) {}
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+#include "func.h"
+
+int global;
+
+void test()
+{
+ func();
+}
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+#include "func.h"
+
+void test2()
+{
+ func();
+}
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+extern int global;
+extern void foo(int);
+
+
+// this weak func() will have unwind info and a LSDA
+inline int func()
+{
+ global = 1;
+ try {
+ foo(1);
+ global = 2;
+ }
+ catch (int x) {
+ foo(2);
+ global = 3;
+ }
+ return global;
+}
+
--- /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
+
+run: all
+
+
+all:
+ ${FAIL_IF_ERROR} $(CXX) main.cxx -arch ${ARCH} -o main
+ ${FAIL_IF_ERROR} nm -j main | grep '\.eh$$'| ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} main
+clean:
+ rm -rf *.o main main-* *.nm
--- /dev/null
+Test strip: symbols referenced by indirect symbol table entries can't be stripped (4096290)
+
+__ZN9__gnu_cxx13new_allocatorIiE7destroyEPi
+__ZNKSt12_Vector_baseIiSaIiEE13get_allocatorEv
+__ZN9__gnu_cxx13new_allocatorIiEC2ERKS1_
+__ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPim
+__ZN9__gnu_cxx13new_allocatorIiED2Ev
+__ZNSt6vectorIiSaIiEEC1ERKS0_
+__ZNSaIiEC1ERKS_
+__ZN9__gnu_cxx13new_allocatorIiE10deallocateEPim
+__ZNSt12_Vector_baseIiSaIiEE12_Vector_implC1ERKS0_
+__ZNSaIiED2Ev
+__ZNSt12_Vector_baseIiSaIiEED2Ev
+__ZNSaIiEC1Ev
+__ZNSt12_Vector_baseIiSaIiEEC2ERKS0_
+__ZNSt6vectorIiSaIiEED1Ev
+__ZNSaIiED1Ev
+__ZSt8_DestroyIPiSaIiEEvT_S2_T0_
+__ZN9__gnu_cxx13new_allocatorIiEC2Ev
+__ZNSaIiEC2ERKS_
+__ZNSt12_Vector_baseIiSaIiEE12_Vector_implD1Ev
--- /dev/null
+#include <vector>
+int main()
+{
+ std::vector<int> stuff;
+ return 0;
+}
--- /dev/null
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# verify that if symbols are stripped out of .o files
+# the linker can still process unwind info from .o files
+# correctly
+
+ifeq (${FILEARCH},arm)
+ FILE_TYPE = KEXTBUNDLE
+endif
+
+
+all: all-${FILEARCH}
+all-i386: all-zce
+all-x86_64: all-zce
+all-arm: all-good
+
+all-zce:
+ ${CXX} ${CCXXFLAGS} main.cxx -g -c -o main1.o -Os
+ #strip main1.o -u -s keep.exp -o main2.o
+ ${LD} main1.o -r -x -exported_symbols_list keep.exp -o main2.o
+ ${CXX} ${CCXXFLAGS} main1.o -o main1
+ ${CXX} ${CCXXFLAGS} main2.o -o main2
+ ${UNWINDDUMP} -arch ${ARCH} -no_symbols main1 > main1.unwind
+ ${UNWINDDUMP} -arch ${ARCH} -no_symbols main2 > main2.unwind
+ ${PASS_IFF} diff main1.unwind main2.unwind
+
+all-good:
+ ${PASS_IFF} true
+
+clean:
+ rm -f main1* main2*
--- /dev/null
+_main
+__Z3barv
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include <stdlib.h>
+
+int global = 0;
+
+int bar()
+{
+ global = 1;
+ throw 10;
+
+}
+
+
+void foo()
+{
+ try {
+ bar();
+ }
+ catch(int x) {
+ global = 2;
+ throw x;
+ }
+}
+
+
+
+int main()
+{
+ int state = 1;
+ try {
+ state = 2;
+ foo();
+ state = 3;
+ }
+ catch (int x) {
+ if ( state != 2 )
+ return 1;
+ if ( x != 10 )
+ return 1;
+ state = 4;
+ }
+
+ if ( (state == 4) && (global == 2) )
+ return 0;
+ else
+ return 1;
+}
+
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# strips .eh symbols out of final linked images,
+# even when an intermediate ld -r was used.
+#
+
+run: all
+
+all:
+ ${CXX} ${CCXXFLAGS} foo.cxx -dynamiclib -o libfoo.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ nm libfoo.dylib | grep '.eh' | ${FAIL_IF_STDIN}
+ ${CXX} ${CCXXFLAGS} foo.cxx -c -o foo.o
+ ${FAIL_IF_BAD_OBJ} foo.o
+ ${LD} -r foo.o -o foo2.o
+ ${FAIL_IF_BAD_OBJ} foo2.o
+ ${CXX} ${CCXXFLAGS} foo2.o bar.cxx -dynamiclib -o libfoobar.dylib
+ ${FAIL_IF_BAD_MACHO} libfoobar.dylib
+ dwarfdump --eh-frame --verify libfoobar.dylib > /dev/null
+ nm libfoobar.dylib | grep '.eh' | ${PASS_IFF_EMPTY}
+
+clean:
+ rm *.dylib *.o
--- /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>
+
+
+static void bar1()
+{
+ fprintf(stderr, "hello\n");
+}
+
+void bar2()
+{
+ bar1();
+ fprintf(stderr, "world\n");
+}
+
+
--- /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>
+
+
+static void foo1()
+{
+ fprintf(stderr, "hello\n");
+}
+
+void foo2()
+{
+ foo1();
+ fprintf(stderr, "world\n");
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that the n_sect number for __mh_dylib_header is valid when there is no __text section
+# Also check that codesigning works on empty dylib.
+#
+
+CODESIGN_ARCH = ${ARCH}
+ifeq (${ARCH},ppc)
+ CODESIGN_ARCH = ppc7400
+endif
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -dynamiclib justdata.c -o libjustdata.dylib -Wl,-no_compact_unwind
+ ${PASS_IFF_GOOD_MACHO} libjustdata.dylib
+ ${CC} ${CCFLAGS} -dynamiclib empty.c -o libempty.dylib -Wl,-no_compact_unwind
+ codesign_allocate -i libempty.dylib -a ${CODESIGN_ARCH} 1024 -o libsigned.dylib
+ ${PASS_IFF_GOOD_MACHO} libsigned.dylib
+
+clean:
+ rm -rf libempty.dylib libjustdata.dylib libsigned.dylib
--- /dev/null
+int data = 1;
--- /dev/null
+##
+# Copyright (c) 2007 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can handle an empty (no load commands) .o file
+#
+
+run: all
+
+all:
+ touch empty.s
+ as -arch ${ARCH} -n empty.s -o empty.o
+ ${CC} ${CCFLAGS} main.c empty.o -o main
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm main empty.s empty.o
--- /dev/null
+int main() { return 0; }
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that ld maintains two symbols with the same address and in different sections
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.s -c -o foo.o
+ ${CC} ${CCFLAGS} bar.s -c -o bar.o
+ ${LD} -r foo.o bar.o -o foobar.o
+ nm -m foobar.o | grep _next | grep __other | ${FAIL_IF_EMPTY}
+ ${LD} -r foobar.o -o foobar2.o
+ nm -m foobar2.o | grep _next | grep __other | ${PASS_IFF_STDIN}
+
+clean:
+ rm -rf *.o
--- /dev/null
+
+ .section __DATA,__other,regular
+
+ .globl _next
+_next:
+ nop
+
\ No newline at end of file
--- /dev/null
+
+ .data
+
+ .globl _start
+ .globl _end
+ .globl _endAlias
+_start:
+ .long 0
+ .long 0
+_end:
+_endAlias:
+
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+# Tests that link fails if undefined symbol is in export list
+#
+
+run: all
+
+all:
+ ${PASS_IFF_ERROR} ${CC} -dynamiclib foo.c -o libfoo.dylib -exported_symbols_list foo.exp -dead_strip 2>/dev/null
+
+clean:
+ rm libfoo.dylib
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stddef.h>
+
+void good() {}
+void bad() {}
+
+
+void ABC() {}
+void ABD() { good(); }
+void DEF() {}
+void DEG() { bad(); }
+
--- /dev/null
+_ABC
+_ABCD
+_DEF
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Tests the use of wildcards in exported symbol lists and dead stripping
+#
+
+run: all
+
+all:
+ ${CC} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_AB*' -dead_strip
+ nm -j -f libfoo.dylib | grep _good | ${FAIL_IF_EMPTY}
+ nm -j -f libfoo.dylib | grep _bad | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+clean:
+ rm libfoo.dylib
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stddef.h>
+
+void good() {}
+void bad() {}
+
+
+void ABC() {}
+void ABD() { good(); }
+void DEF() {}
+void DEG() { bad(); }
+
--- /dev/null
+##
+# Copyright (c) 2007-2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Tests the use of wildcards in exported symbol lists
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_foo*bar'
+ nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect1 | ${FAIL_IF_STDIN}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f?o'
+ nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect2 | ${FAIL_IF_STDIN}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_foo*'
+ nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect3 | ${FAIL_IF_STDIN}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f*o*'
+ nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect4 | ${FAIL_IF_STDIN}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,_foo -Wl,-exported_symbol -Wl,'_*bar'
+ nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect5 | ${FAIL_IF_STDIN}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -exported_symbols_list list5
+ nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect5 | ${FAIL_IF_STDIN}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-unexported_symbol -Wl,'_*2*'
+ nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect6 | ${FAIL_IF_STDIN}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f[abcdef]o'
+ nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect7 | ${FAIL_IF_STDIN}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f[a-f]o'
+ nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect7 | ${FAIL_IF_STDIN}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f[a-z]o'
+ nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect8 | ${FAIL_IF_STDIN}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f[a-fnop]o'
+ nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect8 | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+clean:
+ rm libfoo.dylib
--- /dev/null
+_foo2bar
+_foobar
--- /dev/null
+_fao
+_ffo
+_foo
--- /dev/null
+_foo
+_foo2
+_foo2bar
+_foobar
--- /dev/null
+_fao
+_ffo
+_foo
+_foo2
+_foo2bar
+_foobar
--- /dev/null
+_foo
+_foo2bar
+_foobar
--- /dev/null
+_fao
+_ffo
+_foo
+_foobar
--- /dev/null
+_fao
+_ffo
--- /dev/null
+_fao
+_ffo
+_foo
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stddef.h>
+
+
+int foo()
+{
+ return 1;
+}
+
+int foo2()
+{
+ return 1;
+}
+
+int foobar()
+{
+ return 1;
+}
+
+int foo2bar()
+{
+ return 1;
+}
+
+int fao()
+{
+ return 1;
+}
+
+int ffo()
+{
+ return 1;
+}
--- /dev/null
+_foo
+_*bar
--- /dev/null
+##
+# Copyright (c) 2007-2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Verify that -exported_symbols_list can be used with a file with Mac (0x0D) line endings
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.c -dynamiclib -exported_symbols_list test.exp -o libtest.dylib
+ nm -jg libtest.dylib | grep '^_' > test.nm
+ diff test.nm expected.nm
+ ${PASS_IFF_GOOD_MACHO} libtest.dylib
+
+clean:
+ rm -rf libtest.dylib test.nm
--- /dev/null
+_common_global2
+_func_global2
--- /dev/null
+
+
+
+static int data_static1 = 1;
+static int data_static2 = 2;
+
+void func_global1() { ++data_static1; }
+void func_global2() { ++data_static2; }
+
+void __attribute__((visibility("hidden"))) func_hidden1() {}
+void __attribute__((visibility("hidden"))) func_hidden2() {}
+
+int common_global1;
+int common_global2;
+
+int __attribute__((visibility("hidden"))) common_hidden1;
+int __attribute__((visibility("hidden"))) common_hidden2;
+
--- /dev/null
+_func_global2\r_common_global2\r
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Verify that -exported_symbols_list of a hidden symbol causes a warning
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.c -dynamiclib -exported_symbols_list test.exp -o libtest.dylib 2>warning.log
+ grep _func_hidden1 warning.log | ${FAIL_IF_EMPTY}
+ grep _common_hidden1 warning.log | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libtest.dylib
+
+clean:
+ rm -rf libtest.dylib warning.log
--- /dev/null
+
+
+
+static int data_static1 = 1;
+static int data_static2 = 2;
+
+void func_global1() { ++data_static1; }
+void func_global2() { ++data_static2; }
+
+void __attribute__((visibility("hidden"))) func_hidden1() {}
+void __attribute__((visibility("hidden"))) func_hidden2() {}
+
+int common_global1;
+int common_global2;
+
+int __attribute__((visibility("hidden"))) common_hidden1;
+int __attribute__((visibility("hidden"))) common_hidden2;
+
--- /dev/null
+_func_global1
+_func_hidden1
+_common_global1
+_common_hidden1
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Verify that -exported_symbols_list can be used with -r
+# to reduce visibility of symbols and any missing symbols
+# causes an error
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.c -c -o test.o
+ ${FAIL_IF_BAD_OBJ} test.o
+ ${LD} -arch ${ARCH} -r -keep_private_externs test.o -exported_symbols_list test.exp -o test-r.o
+ ${FAIL_IF_BAD_OBJ} test-r.o
+ # verify common not in export-list got demoted to private extern
+ nm -m test-r.o | grep "private external _common_global1" | ${FAIL_IF_EMPTY}
+ # verify only _common_global1 and _func_global1 changed
+ nm -m test.o | egrep -v '_common_global1|_func_global1|__eh_frame|__data' > test.nm
+ nm -m test-r.o | egrep -v '_common_global1|_func_global1|__eh_frame|__data' > test-r.nm
+ diff test.nm test-r.nm
+ # verify without -keep_private_externs that commons stay private extern
+ ${LD} -arch ${ARCH} -r test.o -exported_symbols_list test.exp -o test-rr.o
+ nm -m test-rr.o | grep _common_hidden | grep ') external' | ${FAIL_IF_STDIN}
+ nm -m test-rr.o | grep _common_global1 | grep ') external' | ${FAIL_IF_STDIN}
+ # should error out if told to export unavailable symbol
+ ${FAIL_IFF_SUCCESS} ${LD} -arch ${ARCH} -r test.o -exported_symbols_list test-bad.exp -o test2.o 2>/dev/null
+
+clean:
+ rm -rf test.o test-r.o test-rr.o test.nm test-r.nm test2.o
--- /dev/null
+_bar
+_baz
+_foobar
--- /dev/null
+
+
+
+static int data_static1 = 1;
+static int data_static2 = 2;
+
+void func_global1() { ++data_static1; }
+void func_global2() { ++data_static2; }
+
+void __attribute__((visibility("hidden"))) func_hidden1() {}
+void __attribute__((visibility("hidden"))) func_hidden2() {}
+
+int common_global1;
+int common_global2;
+
+int __attribute__((visibility("hidden"))) common_hidden1;
+int __attribute__((visibility("hidden"))) common_hidden2;
+
--- /dev/null
+_func_global2
+_common_global2
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to see that external relocations
+# are sorted so that dyld only has to look up symbols once.
+# The machochecker tool verifies that the relocs are sorted.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main libfoo.dylib
--- /dev/null
+
+int foo = 1;
+int bar = 2;
+int baz = 3;
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+// in libfoo.dylib
+extern int foo;
+extern int bar;
+extern int baz;
+
+// this initialilzed data will result in external relocations
+// alternating the values, will create relocs that need sorting
+int* array[] = { &foo, &bar, &baz, &foo, &bar, &baz, &foo, &bar, &baz };
+
+
+int main()
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+# Check that warning under -fatal_warnings causes error
+#
+
+run: all
+
+all:
+ ${PASS_IFF_ERROR} ${CC} ${CCFLAGS} main.c -o main -pagezero_size 123 -Wl,-fatal_warnings 2>msgs.txt
+
+
+clean:
+ rm -f main msgs.txt
--- /dev/null
+
+int main()
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+PWD = $(shell pwd)
+
+#
+# Check the two forms of the -filelist option
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -c hello.c -o hello.o
+ ${FAIL_IF_BAD_OBJ} hello.o
+ echo "${PWD}/hello.o" > "${PWD}/filelist1"
+ cd /tmp && ${CC} ${CCFLAGS} -filelist "${PWD}/filelist1" -o "${PWD}/hello"
+ ${FAIL_IF_BAD_MACHO} hello
+ echo "hello.o" > "${PWD}/filelist2"
+ cd /tmp && ${CC} ${CCFLAGS} -filelist "${PWD}/filelist2,${PWD}" -o "${PWD}/hello"
+ ${FAIL_IF_BAD_MACHO} hello
+ echo "${PWD}/hello.o" > "${PWD}/filelist,withComma"
+ cd /tmp && ${CC} ${CCFLAGS} -filelist "${PWD}/filelist,withComma" -o "${PWD}/hello"
+ ${PASS_IFF_GOOD_MACHO} hello
+
+clean:
+ rm -f hello.o hello filelist1 filelist2 filelist,withComma
--- /dev/null
+The point of this test is to check the two forms of the -filelist option
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a small dylib -flat_namespace and
+# indirect internal references.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain.dylib -flat_namespace
+ otool -Iv libmain.dylib | grep _foo | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libmain.dylib
+
+clean:
+ rm *.dylib
--- /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>
+
+void foo() {}
+
+
+int main()
+{
+ foo();
+ fprintf(stdout, "hello\n");
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that when linking a main executable for flat-namespace
+# that undefines in loaded flat-namespace dylibs are resolved.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -flat_namespace -dynamiclib -o libfoo.dylib -undefined suppress
+ ${CC} ${CCFLAGS} bar.c -c -o bar.o
+ libtool -static bar.o -o libbar.a
+ # test that linking main executable -twolevel_namespace does not pull in bar()
+ ${CC} ${CCFLAGS} main.c libfoo.dylib libbar.a -o main
+ nm -mn main | grep _bar | ${FAIL_IF_STDIN}
+ # test that linking dylib -flat_namespace does not pull in bar()
+ ${CC} ${CCFLAGS} main.c -flat_namespace libfoo.dylib libbar.a -dynamiclib -o main.dylib
+ nm -mn main.dylib | grep _bar | ${FAIL_IF_STDIN}
+ # test that linking main executable -flat_namespace pulls in bar()
+ ${CC} ${CCFLAGS} main.c -flat_namespace libfoo.dylib libbar.a -o main_flat
+ nm -mn main_flat | grep _bar | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main_flat
+
+clean:
+ rm libfoo.dylib libbar.a bar.o main main_flat main.dylib
--- /dev/null
+
+void bar() {}
+
+
--- /dev/null
+
+extern void bar();
+
+void foo()
+{
+ bar();
+}
+
--- /dev/null
+#include <stdio.h>
+
+extern void foo();
+
+
+int main()
+{
+ foo();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a hello-world program -flat_namespace and
+# does not indirect internal references.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -o main-${ARCH} -flat_namespace
+ otool -Iv main-${ARCH} | grep _foo | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} main-${ARCH}
+
+clean:
+ rm main-*
--- /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>
+
+void foo() {}
+
+
+int main()
+{
+ foo();
+ fprintf(stdout, "hello\n");
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2011 Apple, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that forcing a symbol weak does not cause spurious warnings
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c test.c -dynamiclib -o libtest.dylib -Wl,-force_symbols_weak_list,weak.exp
+ otool -Iv libtest.dylib | grep _foo | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libtest.dylib
+
+clean:
+ rm libtest.dylib
--- /dev/null
+
+int foo = 5;
\ No newline at end of file
--- /dev/null
+
+extern int foo;
+
+int getfoo() { return foo; }
+
--- /dev/null
+
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check -function_starts
+#
+
+run: all
+
+all:
+ # as main executable
+ ${CC} ${CCFLAGS} main.c -o main -Wl,-function_starts
+ ${DYLDINFO} -function_starts main | grep _bar | ${FAIL_IF_EMPTY}
+ # as dylib
+ ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain.dylib -Wl,-function_starts
+ ${DYLDINFO} -function_starts libmain.dylib | grep _bar | ${FAIL_IF_EMPTY}
+ # as dylib with prefered load address
+ ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain2.dylib -seg1addr 0x200000 -Wl,-function_starts
+ ${DYLDINFO} -function_starts libmain2.dylib | grep _bar | ${FAIL_IF_EMPTY}
+ # as dylib with aliases
+ ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain3.dylib -Wl,-function_starts -Wl,-alias,_mid,midalias
+ ${DYLDINFO} -function_starts libmain3.dylib | grep _bar | ${FAIL_IF_EMPTY}
+ # as static main executable
+ ${CC} ${CCFLAGS} main.c -static -e _main -o main_static -nostdlib -Wl,-new_linker -Wl,-alias,_myexit,_exit
+ ${DYLDINFO} -function_starts main_static | grep _bar | ${FAIL_IF_STDIN}
+ ${CC} ${CCFLAGS} main.c -static -e _main -o main_static -nostdlib -Wl,-new_linker -Wl,-alias,_myexit,_exit -Wl,-function_starts
+ ${DYLDINFO} -function_starts main_static | grep _bar | ${FAIL_IF_EMPTY}
+
+
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+ rm main libmain.dylib libmain2.dylib libmain3.dylib main_static
--- /dev/null
+
+void foo() {}
+
+void mid() {}
+
+static void bar() { foo(); }
+
+int main() { bar(); return 0; }
+
+
+#if __STATIC__
+void myexit() {}
+#endif
+
--- /dev/null
+##
+# Copyright (c) 2007-2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that ld can remove non-lazy pointers for x86_64
+#
+
+all: all-${FILEARCH}
+
+all-arm: all-true
+
+all-ppc: all-true
+
+all-ppc64: all-true
+
+all-i386: all-true
+
+all-true:
+ ${PASS_IFF} true
+
+all-x86_64:
+ ${CC} ${CCFLAGS} foo.c bar.c -dynamiclib -o libfoobar.dylib
+ otool -Iv libfoobar.dylib | grep 0x | grep _ | ${FAIL_IF_STDIN}
+ ${CC} ${CCFLAGS} foo.c bar.c -dynamiclib -o libfoobar.dylib -flat_namespace
+ otool -Iv libfoobar.dylib | grep 0x | ${PASS_IFF_STDIN}
+
+clean:
+ rm -rf libfoobar.dylib
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+int bar1 = 1;
+int bar2 = 2;
+int bar3 = 3;
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+extern int bar1;
+extern int bar2; // just under 2GB array
+extern int bar3;
+
+int getbar1()
+{
+ return bar1;
+}
+
+int getbar2()
+{
+ return bar2;
+}
+
+int getbar3()
+{
+ return bar3;
+}
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a hello-world program with no errors (or crashes)
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} hello.c -o hello-${ARCH} -Wl,-headerpad -Wl,0x3000
+ ${PASS_IFF_GOOD_MACHO} hello-${ARCH}
+
+clean:
+ rm hello-*
--- /dev/null
+The point of this test is a sanity check that ld can link a hello-world program with no errors (or crashes)
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a hello-world program with no errors (or crashes)
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} hello.c -o hello-${ARCH}
+ ${PASS_IFF_GOOD_MACHO} hello-${ARCH}
+
+clean:
+ rm hello-*
--- /dev/null
+The point of this test is a sanity check that ld can link a hello-world program with no errors (or crashes)
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Tests that a hidden tentative or weak hidden symbol survives -r
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ ${LD} -r main.o foo.o -o all.o
+ ${CC} ${CCFLAGS} all.o -o main
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -f main.o foo.o all.o main
--- /dev/null
+void __attribute__((weak,visibility("hidden"))) my_weak()
+{
+}
+
+int __attribute__((visibility("hidden"))) my_tent;
--- /dev/null
+#include <stdio.h>
+
+extern void my_weak();
+extern int my_tent;
+
+int main()
+{
+ my_tent = 0;
+ my_weak();
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a program with a large zero-fill section
+#
+
+run: all
+
+all:
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c test.c -o test-${ARCH}.o
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c a.c -o a-${ARCH}.o
+ ${FAIL_IF_ERROR} ar -r libtest-${ARCH}.a test-${ARCH}.o 2>/dev/null
+ #ranlib libtest-${ARCH}.a
+ #${FAIL_IF_ERROR} ${CC} ${LDFLAGS} a-${ARCH}.o -L. -ltest-${ARCH} -o a-${ARCH}
+ #${PASS_IFF_GOOD_MACHO} a-${ARCH}
+
+ ${FAIL_IF_ERROR} ar -r libtest-${ARCH}.a test-${ARCH}.o a-${ARCH}.o 2>/dev/null
+ ${FAIL_IF_ERROR} ranlib libtest-${ARCH}.a
+ ${FAIL_IF_ERROR} ${CC} ${LDFLAGS} a-${ARCH}.o -L. -ltest-${ARCH} -o a-${ARCH}
+ ${PASS_IFF_GOOD_MACHO} a-${ARCH}
+
+clean:
+ rm -rf *.o *.a
--- /dev/null
+extern int common_variable;
+
+int
+main(int argc, char **argv)
+{
+ return common_variable;
+}
--- /dev/null
+The point of this test is a sanity check that ld can link a program with a large zero-fill section
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+int common_variable;
+extern int main();
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a program with a large zero-fill section
+#
+
+run: all
+
+all:
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c test.c -o test-${ARCH}.o
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c a.c -o a-${ARCH}.o
+ ${FAIL_IF_ERROR} libtool -o libtest-${ARCH}.a test-${ARCH}.o
+ #${FAIL_IF_ERROR} ${CC} ${LDFLAGS} a-${ARCH}.o -L. -ltest-${ARCH} -o a-${ARCH}
+ #${PASS_IFF_GOOD_MACHO} a-${ARCH}
+
+ ${FAIL_IF_ERROR} libtool -o libtest-${ARCH}.a test-${ARCH}.o a-${ARCH}.o
+ ${FAIL_IF_ERROR} ${CC} ${LDFLAGS} a-${ARCH}.o -L. -ltest-${ARCH} -o a-${ARCH}
+ ${PASS_IFF_GOOD_MACHO} a-${ARCH}
+
+clean:
+ rm -rf *.o *.a
--- /dev/null
+extern int common_variable;
+
+int
+main(int argc, char **argv)
+{
+ return common_variable;
+}
--- /dev/null
+The point of this test is a sanity check that ld can link a program with a large zero-fill section
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+int common_variable;
+extern int main();
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a program with a large zero-fill section
+#
+
+run: all
+
+all:
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c test.c -o test-${ARCH}.o
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c a.c -o a-${ARCH}.o
+ ${FAIL_IF_ERROR} libtool -o libtest-${ARCH}.a test-${ARCH}.o
+ ${FAIL_IF_ERROR} ${CC} ${LDFLAGS} a-${ARCH}.o -L. -ltest-${ARCH} -o a-${ARCH}
+ ${PASS_IFF_GOOD_MACHO} a-${ARCH}
+
+clean:
+ rm -rf *.o *a
--- /dev/null
+extern int common_variable;
+
+int
+main(int argc, char **argv)
+{
+ return common_variable;
+}
--- /dev/null
+The point of this test is a sanity check that ld can link a program with a large zero-fill section
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+int common_variable;
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+PWD = $(shell pwd)
+
+
+# Verify -no_implicit_dylibs option
+# <rdar://problem/5451987> add option to disable implicit load commands for indirectly used public dylibs
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib -install_name /usr/lib/libbar.dylib
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -Wl,-reexport_library,libbar.dylib -sub_library libbar
+ # verify that main gets bar from libbar
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -L.
+ nm -m main | grep _bar | grep libbar | ${FAIL_IF_EMPTY}
+ # verify that -no_implicit_dylibs causes main to get bar from libfoo
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -Wl,-no_implicit_dylibs -L.
+ nm -m main | grep _bar | grep libfoo | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf libfoo.dylib libbar.dylib main
--- /dev/null
+
+
+
+void bar()
+{
+}
+
--- /dev/null
+
+
+void foo()
+{
+}
--- /dev/null
+
+extern void foo();
+extern void bar();
+
+int main()
+{
+ foo();
+ bar();
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+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
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} foo.c libbar.dylib -dynamiclib -o libfoo.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -o main libfoo.dylib 2> fail.log
+ grep ordinal fail.log | ${PASS_IFF_EMPTY}
+
+clean:
+ rm -f *.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
+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#
--- /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;
+}
+
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that -F and -L work when finding indirect libraries
+#
+
+
+run: all
+
+all:
+
+# build foo that re-exports bar
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lbar -L. -sub_library libbar
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+# build an alternate libbar that also has baz
+ mkdir -p hide
+ ${CC} ${CCFLAGS} -dynamiclib bar.c baz.c -o hide/libbar.dylib -install_name libbar.dylib
+ ${FAIL_IF_BAD_MACHO} hide/libbar.dylib
+
+# build an executable that depends on a symbol in the alternate bar to validate that -L is used for indirect dylibs
+ ${CC} ${CCFLAGS} main.c -o main -lfoo -Lhide -L.
+ ${FAIL_IF_BAD_MACHO} main
+
+
+
+# build Foo.framework that re-exports Bar.framework
+ mkdir -p Bar.framework Foo.framework
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar"
+ ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -framework Bar -sub_umbrella Bar
+ ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
+
+# build an alternate Bar.framework that also has baz
+ mkdir -p hide/Bar.framework
+ ${CC} ${CCFLAGS} -dynamiclib bar.c baz.c -o hide/Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar"
+ ${FAIL_IF_BAD_MACHO} hide/Bar.framework/Bar
+
+# build an executable that depends on a symbol in the alternate Bar.framework to validate that -F is used for indirect dylibs
+ ${CC} ${CCFLAGS} main.c -o main -Fhide -F. -framework Foo
+ ${FAIL_IF_BAD_MACHO} main
+
+
+
+# build foo that links against bar
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+# build an alternate libbar that also has baz
+ mkdir -p hide
+ ${CC} ${CCFLAGS} -dynamiclib bar.c baz.c -o hide/libbar.dylib -install_name libbar.dylib
+ ${FAIL_IF_BAD_MACHO} hide/libbar.dylib
+
+# build a flat executable that depends on a symbol in the alternate bar to validate that -L is used for indirect dylibs
+ ${CC} ${CCFLAGS} -flat_namespace main.c -o main -lfoo -Lhide -L.
+ ${FAIL_IF_BAD_MACHO} main
+
+
+
+# build Foo.framework that re-exports libbar.dylib embedded in framework
+ mkdir -p Foo.framework
+ ${CC} ${CCFLAGS} -dynamiclib bar.c baz.c -o Foo.framework/libbar.dylib -install_name "`pwd`/Foo.framework/libbar.dylib"
+ ${FAIL_IF_BAD_MACHO} Foo.framework/libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. Foo.framework/libbar.dylib -sub_library libbar
+ ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
+
+# build an alternate libbar.dylib that does not have baz
+ mkdir -p hide
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o hide/libbar.dylib
+ ${FAIL_IF_BAD_MACHO} hide/libbar.dylib
+
+# build an executable that depends on a symbol not in the alternate libbar.dylib to validate dylibs embedded in frameworks are not searched for
+ ${CC} ${CCFLAGS} main.c -o main -Lhide -F. -framework Foo
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+
+ rm -rf hide libbar.dylib libfoo.dylib Foo.framework Bar.framework main
--- /dev/null
+
+int bar (void)
+{
+ return 1;
+}
--- /dev/null
+
+int baz (void)
+{
+ return 1;
+}
--- /dev/null
+int foo (void)
+{
+ return 1;
+}
--- /dev/null
+extern int foo ();
+extern int bar ();
+extern int baz ();
+
+int main (void)
+{
+ return foo() + bar() + baz();
+}
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that initializers are automatically sorted to start of __text
+# and terminators are sorted to end of __text
+#
+# <rdar://problem/6061904> automatically order initializers to start of __TEXT
+#
+
+run: all
+
+all:
+ ${CXX} ${CXXFLAGS} main.cxx foo.cxx bar.cxx -o main -dead_strip
+ nm -s __TEXT __text -nj main | grep -v dyld_stub_binding_helper | c++filt > actual-order.txt
+ ${PASS_IFF} diff actual-order.txt expected-order.txt
+
+
+clean:
+ rm -rf main actual-order.txt
--- /dev/null
+
+
+
+class Bar {
+public:
+ Bar() : a(20) {}
+ ~Bar() {}
+private:
+ int a;
+};
+
+
+Bar b1;
+Bar b2;
+
+
--- /dev/null
+M::M()
+__static_initialization_and_destruction_0(int, int)
+global constructors keyed to m1
+Foo::Foo()
+__static_initialization_and_destruction_0(int, int)
+global constructors keyed to f1
+Bar::Bar()
+__static_initialization_and_destruction_0(int, int)
+global constructors keyed to b1
+start
+_main
+M::~M()
+Foo::~Foo()
+Bar::~Bar()
+___tcf_0
+___tcf_1
+___tcf_0
+___tcf_1
+___tcf_0
+___tcf_1
--- /dev/null
+
+
+
+class Foo {
+public:
+ Foo() : a(20) {}
+ ~Foo() {}
+private:
+ int a;
+};
+
+
+Foo f1;
+Foo f2;
--- /dev/null
+#include <stdio.h>
+
+class M {
+public:
+ M() : a(20) {}
+ ~M() {}
+private:
+ int a;
+};
+
+
+M m1;
+M m2;
+
+int main()
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# verify $ld$install_name$osXX$/new/path overides install_name
+#
+
+FORCE_MIN_OS_VERSION = -mmacosx-version-min=10.5
+
+ifeq ($(FILEARCH),arm)
+ FORCE_MIN_OS_VERSION = -miphoneos-version-min=4.0
+endif
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -install_name /usr/local/lib/libfoo.dylib
+ otool -L libfoo.dylib | grep /usr/local/lib/libfoo.dylib | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
+ otool -L main | grep /usr/local/lib/libfoo.dylib | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o mainAlt ${FORCE_MIN_OS_VERSION}
+ otool -L mainAlt | grep /usr/lib/libfoo.dylib | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+clean:
+ rm -f libfoo.dylib main mainAlt
--- /dev/null
+
+int foo()
+{
+ return 0;
+}
+
+
+#if __arm__
+ #define INSTALL_NAME_4_0(sym) \
+ extern const char install_name_4_0 __asm("$ld$install_name$os4.0$" #sym ); const char install_name_4_0 = 0;
+
+ INSTALL_NAME_4_0(/usr/lib/libfoo.dylib)
+#else
+ #define INSTALL_NAME_10_5(sym) \
+ extern const char install_name_10_5 __asm("$ld$install_name$os10.5$" #sym ); const char install_name_10_5 = 0;
+
+ INSTALL_NAME_10_5(/usr/lib/libfoo.dylib)
+#endif
--- /dev/null
+
+extern int foo();
+
+int main()
+{
+ foo();
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that -interposable and -interposable_list work
+#
+
+run: all
+
+all:
+ # by default, no test* functions should go through stubs
+ ${CC} ${CCFLAGS} test.c -dynamiclib -o libtest.dylib
+ # -interposable should make all four test* functions go through stubs
+ ${CC} ${CCFLAGS} test.c -dynamiclib -Wl,-interposable -o libtest.dylib
+ otool -Iv libtest.dylib | grep '4 entries' | ${FAIL_IF_EMPTY}
+ otool -Iv libtest.dylib | grep '_test' | ${FAIL_IF_EMPTY}
+ # -interposable_list should make just two test* functions go through stubs
+ ${CC} ${CCFLAGS} test.c -dynamiclib -Wl,-interposable_list test.exp -o libtest.dylib
+ otool -Iv libtest.dylib | grep '2 entries' | ${FAIL_IF_EMPTY}
+ otool -Iv libtest.dylib | grep '_test3' | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} libtest.dylib
+
+
+clean:
+ rm libtest.dylib
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+const char kMyStr[] = "hello";
+
+int test1()
+{
+ return 10;
+}
+
+int test2()
+{
+ return 10;
+}
+
+int test3()
+{
+ return 10;
+}
+
+int test4()
+{
+ return 10;
+}
+
+const char* getstr()
+{
+ test1();
+ test2();
+ test3();
+ test4();
+ return kMyStr;
+}
+
+
--- /dev/null
+_test1
+_test2
--- /dev/null
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Sanity check that ld can link a kext
+#
+FILE_TYPE = OBJECT
+ifeq (${ARCH},x86_64)
+ FILE_TYPE = KEXTBUNDLE
+endif
+ifeq (${FILEARCH},arm)
+ FILE_TYPE = KEXTBUNDLE
+endif
+
+#CC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -static -mkernel -c mykext.c -o mykext.o
+ ${CC} ${CCFLAGS} -static -mkernel -c mykextinfo.c -o mykextinfo.o
+ ${CC} ${CCFLAGS} -Wl,-kext mykext.o mykextinfo.o -nostdlib -lkmodc++ -lkmod -lcc_kext -o mykext -Wl,-w -Wl,-new_linker
+ otool -hv mykext | grep ${FILE_TYPE} | ${FAIL_IF_EMPTY}
+ nm -nm mykext | grep '(undefined) external _extern_global' | ${FAIL_IF_EMPTY}
+ nm -nm mykext | grep '(__DATA,__data) external _my_global' | ${FAIL_IF_EMPTY}
+ otool -rv mykext | grep '_extern_global' | ${FAIL_IF_EMPTY}
+ ${PASS_IFF} true
+
+clean:
+ rm -f mykext.o mykextinfo.o mykext
--- /dev/null
+#include <mach/mach_types.h>
+
+extern void extern_func();
+
+int my_global = 3;
+extern int extern_global;
+
+kern_return_t mykext_start (kmod_info_t * ki, void * d) {
+ ++my_global;
+ ++extern_global;
+ extern_func();
+ return KERN_SUCCESS;
+}
+
+
+kern_return_t mykext_stop (kmod_info_t * ki, void * d) {
+ --my_global;
+ --extern_global;
+ return KERN_SUCCESS;
+}
--- /dev/null
+#include <mach/mach_types.h>
+
+extern kern_return_t _start(kmod_info_t *ki, void *data);
+extern kern_return_t _stop(kmod_info_t *ki, void *data);
+__private_extern__ kern_return_t mykext_start(kmod_info_t *ki, void *data);
+__private_extern__ kern_return_t mykext_stop(kmod_info_t *ki, void *data);
+
+KMOD_EXPLICIT_DECL(com.yourcompany.kext.mykext, "1.0.0d1", _start, _stop)
+__private_extern__ kmod_start_func_t *_realmain = mykext_start;
+__private_extern__ kmod_stop_func_t *_antimain = mykext_stop;
+__private_extern__ int _kext_apple_cc = __APPLE_CC__ ;
+
--- /dev/null
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Sanity check that ld can link a kext
+#
+
+EXPORT_LIST = mykext.exp
+FILE_TYPE = OBJECT
+ifeq (${ARCH},x86_64)
+ FILE_TYPE = KEXTBUNDLE
+endif
+ifeq (${FILEARCH},arm)
+ FILE_TYPE = KEXTBUNDLE
+endif
+ifeq (${ARCH},i386)
+ EXPORT_LIST = mykext-i386.exp
+endif
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -static -mkernel -c mykext.c -o mykext.o
+ ${CC} ${CCFLAGS} -static -mkernel -c mykextinfo.c -o mykextinfo.o
+ ${CC} ${CCFLAGS} -Wl,-kext mykext.o mykextinfo.o -nostdlib -lkmodc++ -lkmod -lcc_kext -exported_symbols_list $(EXPORT_LIST) -o mykext -Wl,-w -Wl,-new_linker
+ otool -hv mykext | grep ${FILE_TYPE} | ${FAIL_IF_EMPTY}
+ nm -nm mykext | grep '(undefined) external _extern_global' | ${FAIL_IF_EMPTY}
+ nm -nm mykext | grep '(undefined) external _foo' | ${FAIL_IF_STDIN}
+ nm -nm mykext | grep '(undefined) external _my_used_external_global' | ${FAIL_IF_EMPTY}
+ otool -rv mykext | grep '_extern_global' | ${FAIL_IF_EMPTY}
+ ${PASS_IFF} true
+
+clean:
+ rm -f mykext.o mykextinfo.o mykext
--- /dev/null
+_kmod_info
--- /dev/null
+#include <mach/mach_types.h>
+
+extern void extern_func();
+
+int my_global = 3;
+extern int extern_global;
+extern int extern_unused_global;
+extern int my_used_external_global;
+
+kern_return_t mykext_start (kmod_info_t * ki, void * d) {
+ ++my_global;
+ ++extern_global;
+ ++my_used_external_global;
+ extern_func();
+ return KERN_SUCCESS;
+}
+
+
+kern_return_t mykext_stop (kmod_info_t * ki, void * d) {
+ --my_global;
+ --extern_global;
+ return KERN_SUCCESS;
+}
+
+void my_dead_code() {
+ ++extern_unused_global;
+}
\ No newline at end of file
--- /dev/null
+_kmod_info
+_foo
+_my_used_external_global
--- /dev/null
+#include <mach/mach_types.h>
+
+extern kern_return_t _start(kmod_info_t *ki, void *data);
+extern kern_return_t _stop(kmod_info_t *ki, void *data);
+__private_extern__ kern_return_t mykext_start(kmod_info_t *ki, void *data);
+__private_extern__ kern_return_t mykext_stop(kmod_info_t *ki, void *data);
+
+KMOD_EXPLICIT_DECL(com.yourcompany.kext.mykext, "1.0.0d1", _start, _stop)
+__private_extern__ kmod_start_func_t *_realmain = mykext_start;
+__private_extern__ kmod_stop_func_t *_antimain = mykext_stop;
+__private_extern__ int _kext_apple_cc = __APPLE_CC__ ;
+
--- /dev/null
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/9452006> assert when wacky section order and label at end of section
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.s -c -o foo.o
+ ${PASS_IFF} ${LD} -r foo.o -arch ${ARCH} -o foo-r.o
+
+clean:
+ rm -f foo.o foo-r.o
--- /dev/null
+ .lcomm _mybss ,4, 2
+
+ .text
+ .align 4
+ .globl _main
+_main:
+#if __x86_64__
+ movl $0, _mybss(%rip)
+#elif __i386__
+ movl $0, _mybss
+#elif __arm__
+ .long _mybss
+#endif
+
+ .section __DATA, _stuff
+ .align 4
+_start_stuff:
+ .long 0x0
+ .long 0x0
+_end_stuff:
+
+
+ .subsections_via_symbols
+
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that ld handles labels at the end of a section
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.s -c -o foo.o
+ ${OBJECTDUMP} foo.o | grep "address of direct(_end)" | ${PASS_IFF_STDIN}
+
+clean:
+ rm foo.o
--- /dev/null
+
+
+ .section __MY, __data
+_start:
+ .long 0
+_end:
+
+# _var is a pointer to the end of the __MY/__data section
+ .data
+_var:
+#if __x86_64__
+ .quad _end
+#else
+ .long _end
+#endif
+
+ .subsections_via_symbols
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that ld can link > 4GB zero fill section
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.s -dynamiclib -o libtest.dylib
+ ${PASS_IFF_GOOD_MACHO} libtest.dylib
+
+clean:
+ rm -rf libtest.dylib
--- /dev/null
+
+#if __x86_64__
+
+
+.lcomm _mediumarray1,4000,5
+.lcomm _bigarray1,2000000000,5
+.lcomm _bigarray2,2000000000,5
+.lcomm _bigarray3,2000000000,5
+.lcomm _small1,4,2
+.lcomm _small2,4,2
+.lcomm _small3,4,2
+
+
+ .text
+.globl _test
+_test:
+ pushq %rbp
+ movq %rsp, %rbp
+ movq _bigarray1@GOTPCREL(%rip), %rax
+ movq _bigarray2@GOTPCREL(%rip), %rax
+ movq _bigarray3@GOTPCREL(%rip), %rax
+ leaq _small1(%rip),%rax
+ leaq _small2(%rip),%rax
+ leaq _small3(%rip),%rax
+ leaq _mediumarray1(%rip),%rax
+ leave
+ ret
+
+
+#endif
+
+
+
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that ld can link > 4GB zero fill section
+#
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+ifeq (,${findstring 64,$(ARCH)})
+ 32BIT_SHOULD_FAIL = ${FAIL_IF_SUCCESS}
+else
+ 32BIT_SHOULD_FAIL =
+endif
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test1.c -c -o test1.o
+ ${CC} ${CCFLAGS} test2.c -c -o test2.o
+ ${CC} ${CCFLAGS} test3.c -c -o test3.o
+ ${CC} ${CCFLAGS} test4.c -c -o test4.o
+ ${32BIT_SHOULD_FAIL} ${CC} ${CCFLAGS} test1.o test2.o test3.o test4.o -dynamiclib -o libtest.dylib 2> fail.log
+ ${PASS_IFF} true
+
+clean:
+ rm -rf test*.o libtest.dylib fail.log
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+int mediumarray1[1000];
+int bigarray1[500000000]; // just under 2GB array
+int small1;
+
+int getbig1()
+{
+ return bigarray1[0];
+}
+
+int getmedium1()
+{
+ return mediumarray1[0];
+}
+
+int getsmall1()
+{
+ return small1;
+}
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+int bigarray2[500000000]; // just under 2GB array
+int small2;
+
+int getbig2()
+{
+ return bigarray2[0];
+}
+
+
+int getsmall2()
+{
+ return small2;
+}
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+int bigarray3[500000000]; // just under 2GB array
+int small3;
+
+int getbig3()
+{
+ return bigarray3[0];
+}
+
+
+int getsmall3()
+{
+ return small3;
+}
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+int bigarray4[500000000]; // just under 2GB array
+int small4;
+
+int getbig4()
+{
+ return bigarray4[0];
+}
+
+
+int getsmall4()
+{
+ return small4;
+}
--- /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 if
+# ld errors out during linking, that no output file is remaining
+#
+
+run: all
+
+all:
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} link_error.s -dynamiclib -o link_error-${ARCH} 2> fail.log
+ ${FAIL_IFF} cat link_error-${ARCH} 2> fail.log
+
+clean:
+ rm link_error-* fail.log
--- /dev/null
+The point of this test is a sanity check that if
+ld errors out during linking, that no output file is remaining
--- /dev/null
+
+
+#if __ppc__ || __ppc64__
+ ; illegal absolute load
+_foo: lis r2,ha16(_strcmp)
+#endif
+
+#if __i386__
+ // illegal absolute load
+_foo: movl _strcmp, %eax
+#endif
+
+
+#if __x86_64__
+ // illegal external load
+_foo: movl _strcmp(%rip), %eax
+#endif
+
+#if __arm__
+ ; illegal absolute load
+_foo: ldr r2, _strcmp
+#endif
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+# Verify that -lazy_library fails if an objc class is referenced
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.m -dynamiclib -o libfoo.dylib -framework Foundation
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.m -Wl,-lazy_library,libfoo.dylib -o main -framework Foundation 2> fail.log
+ ${CC} ${CCFLAGS} main.m libfoo.dylib -o main -framework Foundation
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+
+clean:
+ rm -f libfoo.dylib main rm fail.log
--- /dev/null
+
+#include <Foundation/Foundation.h>
+
+
+@interface Foo : NSObject
+
+
+
+@end
--- /dev/null
+
+#include "foo.h"
+
+@implementation Foo
+
+
+
+@end
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "foo.h"
+
+
+int main()
+{
+ [[Foo alloc] init];
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Verify that -lazy_library works for function calls
+# but fails for data references
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+ ${CC} ${CCFLAGS} main.c -Wl,-lazy_library,libfoo.dylib -o main
+ ${CC} ${CCFLAGS} main.c -lazy-lfoo -L. -o main
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bad.c -Wl,-lazy_library,libfoo.dylib -o bad 2> fail.log
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bad2.c -Wl,-lazy_library,libfoo.dylib -o bad2 2> fail.log
+
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -f libfoo.dylib main bad bad2 fail.log
+
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+
+extern int data;
+
+static int* pd = &data;
+
+int main()
+{
+ return *pd;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+
+extern int foo();
+
+int main()
+{
+ int (*func)() = foo;
+ if ( func != NULL )
+ (*func)();
+ return 0;
+}
--- /dev/null
+
+int data = 5;
+
+int foo() { return 1; }
+int bar() { return 1; }
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+
+extern int foo();
+extern int bar();
+
+int main()
+{
+ // two regular external function calls
+ void* x = malloc(16);
+ free(x);
+ // two lazy dylib external function calls
+ int result = foo();
+ fprintf(stderr, "foo() returned %d\n", result);
+ bar();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to verify that when two cstrings
+# are coalesced that the one with greater alignment is used.
+#
+
+run: all
+
+all:
+ ${CC} ${ASMFLAGS} cstring-align-0.s -c -o cstring-align-0-${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} cstring-align-0-${ARCH}.o
+
+ ${CC} ${ASMFLAGS} cstring-align-3.s -c -o cstring-align-3-${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} cstring-align-3-${ARCH}.o | grep 'align:' > align-3
+
+ ${LD} -arch ${ARCH} -r cstring-align-0-${ARCH}.o cstring-align-3-${ARCH}.o -o cstring-r-${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} cstring-r-${ARCH}.o | grep 'align:' > align-r
+
+ ${PASS_IFF} diff align-3 align-r
+
+clean:
+ rm -rf *.o align-3 align-r
--- /dev/null
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+ .cstring
+L21: .ascii "hello\0"
--- /dev/null
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+ .cstring
+ .align 3
+L21: .ascii "hello\0"
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+LD=ld
+
+#
+# The point of this test is to verify that when two cstrings
+# are coalesced that the one with greater alignment is used.
+#
+
+run: all
+
+all:
+ ${CC} ${ASMFLAGS} cstring-align-0.s -c -o cstring-align-0-${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} cstring-align-0-${ARCH}.o
+
+ ${CC} ${ASMFLAGS} cstring-align-3.s -c -o cstring-align-3-${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -align -only cstring=hello cstring-align-3-${ARCH}.o > align-3
+
+ ${LD} -arch ${ARCH} -r cstring-align-0-${ARCH}.o cstring-align-3-${ARCH}.o -o cstring-r-${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -align -only cstring=hello cstring-r-${ARCH}.o > align-r
+ ${PASS_IFF} diff -C 6 align-3 align-r
+
+clean:
+ rm -rf *.o align-3 align-r
--- /dev/null
+The point of this test is to verify that when two cstrings are coalesced that the one with greater alignment is used.
--- /dev/null
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+ .cstring
+L20: .asciz "XXX"
+L22: .ascii "hell\0"
--- /dev/null
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+ .cstring
+ .align 2
+L21: .ascii "hell\0"
+ .align 13
+L99: .ascii "\0"
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#LD=ld64
+
+#
+# The point of this test is to verify that when two cstrings
+# are coalesced that the one with greater alignment is used.
+#
+
+run: all
+
+all:
+ ${CC} ${ASMFLAGS} cstring-align-0.s -c -o cstring-align-0-${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} cstring-align-0-${ARCH}.o
+
+ ${CC} ${ASMFLAGS} cstring-align-3.s -c -o cstring-align-3-${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -align -only cstring=hello cstring-align-3-${ARCH}.o > align-3
+
+ ${LD} -arch ${ARCH} -r cstring-align-0-${ARCH}.o cstring-align-3-${ARCH}.o -o cstring-r-${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -align -only cstring=hello cstring-r-${ARCH}.o > align-r
+
+ ${PASS_IFF} diff -C 6 align-3 align-r
+
+clean:
+ rm -rf *.o align-3 align-r
--- /dev/null
+The point of this test is to verify that when two cstrings are coalesced that the one with greater alignment is used.
--- /dev/null
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+ .cstring
+L20: .asciz "XXX"
+L22: .ascii "hell\0"
--- /dev/null
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+ .cstring
+ .align 2
+L21: .ascii "hell\0"
+ .align 13
+L99: .ascii "\0"
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to verify that literals are uniqued.
+# After running ld -r all duplicates should be removed.
+#
+
+run: all
+
+all:
+ ${CC} ${ASMFLAGS} literals.s -c -o literals-${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} literals-${ARCH}.o | grep 'name:'| uniq -c | grep -v '^ [1|2]' | ${FAIL_IF_STDIN}
+ ${LD} -arch ${ARCH} -r literals-${ARCH}.o -o literals-r-${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} literals-r-${ARCH}.o | grep 'name:' | uniq -d | ${PASS_IFF_EMPTY}
+
+clean:
+ rm -rf *.o
--- /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@
+ */
+
+ .literal16
+L01:.long 12345678
+ .long 87654321
+ .long 12345678
+ .long 87654321
+
+L02:.long 12345678
+ .long 87654321
+ .long 12345678
+ .long 87654322
+
+L03:.long 22345678
+ .long 87654321
+ .long 12345678
+ .long 87654321
+
+L04:.long 12345678
+ .long 87654321
+ .long 12345678
+ .long 87654321
+
+
+ .literal8
+L1: .long 12345678
+ .long 87654321
+
+L2: .long 12345678
+ .long 87654322
+
+L3: .long 22345678
+ .long 87654321
+
+L4: .long 12345678
+ .long 87654321
+
+ .literal4
+L11:.long 12345678
+L12:.long 12345679
+L13:.long 22345678
+L14:.long 12345678
+
+ .cstring
+L21: .ascii "hello\0"
+L22: .ascii "hello,there\0"
+L23: .ascii "there\0"
+L24: .ascii "hello\0"
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to verify that literals are uniqued.
+# After running ld -r all duplicates should be removed.
+#
+
+run: all
+
+all:
+ ${FAIL_IF_ERROR} ${CC} ${ASMFLAGS} literals.s -c -o literals-${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -only literals-${ARCH}.o | uniq -c | grep -v '^ [1|2]' | ${FAIL_IF_STDIN}
+ ${FAIL_IF_ERROR} ${LD} -arch ${ARCH} -r literals-${ARCH}.o -o literals-r-${ARCH}.o
+ ${PASS_IFF} ./test.sh literals-r-${ARCH}.o
+
+clean:
+ rm -rf *.o
--- /dev/null
+The point of this test is to verify that literals are uniqued. After running ld -r all duplicates should be removed.
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+ .literal8
+
+L1: .long 12345678
+ .long 87654321
+
+L2: .long 12345678
+ .long 87654322
+
+L3: .long 22345678
+ .long 87654321
+
+L4: .long 12345678
+ .long 87654321
+
+ .literal4
+L11:.long 12345678
+L12:.long 12345679
+L13:.long 22345678
+L14:.long 12345678
+
+ .cstring
+L21: .ascii "hello\0"
+L22: .ascii "hello,there\0"
+L23: .ascii "there\0"
+L24: .ascii "hello\0"
--- /dev/null
+#!/bin/sh
+
+SZ=`size "$1" | tail -n 1 | sed 's,\([0-9]*\).*,\1,'`
+[ "$SZ" ] && [ "$SZ" = 54 ] && exit 0
+exit 1
--- /dev/null
+
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Support mulitple labels on the same literal by cloning the literal
+# into an atom per label.
+#
+
+run: all
+
+all:
+ ${CC} ${ASMFLAGS} literals.s -c -o literals.o
+ ${OBJECTDUMP} literals.o > literals.o.dump
+ ${LD} -arch ${ARCH} -r literals.o -o literals-r.o
+ ${OBJECTDUMP} literals-r.o > literals-r.o.dump
+ ${PASS_IFF} diff literals.o.dump literals-r.o.dump
+
+clean:
+ rm -rf literals.o literals-r.o literals.o.dump literals-r.o.dump
--- /dev/null
+/*
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+ .literal16
+L01:.long 12345678
+ .long 87654321
+ .long 12345678
+ .long 87654321
+
+L02:.long 12345678
+ .long 87654321
+ .long 12345678
+ .long 87654322
+
+_foo16:
+_bar16:
+ .long 22345678
+ .long 87654321
+ .long 12345678
+ .long 87654323
+
+L04:.long 12345678
+ .long 87654321
+ .long 12345678
+ .long 87654324
+
+
+ .literal8
+L1: .long 12345678
+ .long 87654321
+
+L2: .long 12345678
+ .long 87654322
+
+_foo8:
+_bar8:
+ .long 22345678
+ .long 87654323
+
+L4: .long 12345678
+ .long 87654324
+
+ .literal4
+L11:.long 12345678
+L12:.long 12345679
+_foo4:
+_bar4:
+ .long 22345670
+L14:.long 12345671
+
+ .cstring
+L21: .ascii "hello\0"
+L22: .ascii "hello,there\0"
+_string1:
+_string2:
+ .ascii "there\0"
+L24: .ascii "bye\0"
--- /dev/null
+##
+# Copyright (c) 2006-2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+LLVMAR = /usr/local/bin/llvm-ar
+
+#
+# Test the we set the stack execution bit properly.
+
+
+all: zero one two three four five six seven eight nine ten \
+ eleven twelve thirteen fourteen fifteen sixteen seventeen \
+ eighteen nineteen
+
+zero:
+ #
+ # llvm : a.c : Dfoo3
+ # llvm : b.c : Dfoo2
+ # MachO : main.c : Ufoo2, Ufoo3
+ #
+ #echo "Zero..."
+ ${CC} ${CCFLAGS} -flto a.c -c -o a.o
+ ${CC} ${CCFLAGS} -flto b.c -c -o b.o
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ ${CC} ${CCFLAGS} a.o b.o main.o -o main.exe
+ ${PASS_IFF_GOOD_MACHO} main.exe
+
+one:
+ #
+ # llvm : a1.c : Dfoo3, Ufoo4
+ # llvm : b1.c : Dfoo2, Ufoo4
+ # MachO : main1.c : Dfoo4, Ufoo2, Ufoo3
+ #
+ #echo "One..."
+ ${CC} ${CCFLAGS} -flto a1.c -c -o a1.o
+ ${CC} ${CCFLAGS} -flto b1.c -c -o b1.o
+ ${CC} ${CCFLAGS} main1.c -c -o main1.o
+ ${CC} ${CCFLAGS} a1.o b1.o main1.o -o main1.exe
+ ${PASS_IFF_GOOD_MACHO} main1.exe
+
+two:
+ #
+ # llvm : a2.c : Dfoo3, Ufoo4
+ # llvm : b2.c : Dfoo2, Dfoo4
+ # MachO : main2.c : Ufoo2, Ufoo3
+ #
+ #echo "Two..."
+ ${CC} ${CCFLAGS} -flto a2.c -c -o a2.o
+ ${CC} ${CCFLAGS} -flto b2.c -c -o b2.o
+ ${CC} ${CCFLAGS} main2.c -c -o main2.o
+ ${CC} ${CCFLAGS} a2.o b2.o main2.o -o main2.exe
+ ${PASS_IFF_GOOD_MACHO} main2.exe
+
+three:
+ #
+ # llvm : a3.c : Dfoo1, Dbar
+ # llvm : b3.c : Dfoo2, Ubar
+ # MachO : main3.c : Ufoo1, Ufoo2, Ubar
+ #
+ #echo "Three..."
+ ${CC} ${CCFLAGS} -flto a3.c -c -o a3.o
+ ${CC} ${CCFLAGS} -flto b3.c -c -o b3.o
+ ${CC} ${CCFLAGS} main3.c -c -o main3.o
+ ${CC} ${CCFLAGS} a3.o b3.o main3.o -o main3.exe
+ ${PASS_IFF_GOOD_MACHO} main3.exe
+
+four:
+ #
+ # llvm : a4.c : Dfoo3, Ufoo4
+ # llvm : b4.c : Dfoo2, DLmyfoo, Ufoo4
+ # MachO : main4.c : Dfoo4, Ufoo2, Ufoo3
+ #
+ #echo "Four..."
+ ${CC} ${CCFLAGS} -flto a4.c -c -o a4.o
+ ${CC} ${CCFLAGS} -flto b4.c -c -o b4.o
+ ${CC} ${CCFLAGS} main4.c -c -o main4.o
+ ${CC} ${CCFLAGS} a4.o b4.o main4.o -o main4.exe
+ ${PASS_IFF_GOOD_MACHO} main4.exe
+
+five:
+ #
+ # llvm : a5.c : Dfoo1, Ufoo2, Ufoo3
+ # llvm : b5.c : Dfoo2
+ # MachO : main5.c : Dfoo3, Ufoo1
+ #
+ #echo "verify that if call to mach-o is optimized away, mach-o func is dead stripped"
+ ${CC} ${CCFLAGS} -flto a5.c -c -o a5.o
+ ${CC} ${CCFLAGS} -flto b5.c -c -o b5.o
+ ${CC} ${CCFLAGS} main5.c -c -o main5.o
+ ${CC} ${CCFLAGS} a5.o b5.o main5.o -o main5.exe -Wl,-dead_strip
+ ${OTOOL} -tV main5.exe | grep foo3 | ${PASS_IFF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main5.exe
+
+six:
+ #
+ # llvm : a6.c : Dfoo1, Dfoo2
+ # MachO : main6.c : Ufoo1
+ #
+ #echo "verify dead stripping of foo2 in main executable"
+ ${CC} ${CCFLAGS} -flto a6.c -c -o a6.o
+ ${CC} ${CCFLAGS} main6.c -c -o main6.o
+ ${CC} ${CCFLAGS} a6.o main6.o -o main6.exe -Wl,-dead_strip
+ ${PASS_IFF_GOOD_MACHO} main6.exe
+ ${OTOOL} -tV main6.exe | grep foo2 | ${PASS_IFF_EMPTY}
+
+seven:
+ #
+ # llvm : a7.c : Dfoo1, Dfoo2, Ufoo3
+ # llvm : b7.c : Dfoo3, ufoo2
+ # MachO : main7.c : Ufoo1
+ #
+ #echo "Seven..."
+ ${CC} ${CCFLAGS} -flto a7.c -c -o a7.o
+ ${CC} ${CCFLAGS} -flto b7.c -c -o b7.o
+ ${CC} ${CCFLAGS} main7.c -c -o main7.o
+ ${CC} ${CCFLAGS} a7.o b7.o main7.o -o main7.exe
+ ${PASS_IFF_GOOD_MACHO} main7.exe
+
+eight:
+ #
+ # llvm : a8.c : Dfoo1, Dfoo2
+ # MachO : main8.c : Ufoo1
+ #
+ #echo "Eight..."
+ ${CC} ${CCFLAGS} -flto a8.c -c -o a8.o
+ ${CC} ${CCFLAGS} main8.c -c -o main8.o
+ ${CC} ${CCFLAGS} a8.o main8.o -o main8.exe -Wl,-dead_strip
+ ${OTOOL} -tV main8.exe | grep foo2 | ${PASS_IFF_EMPTY}
+ ${OTOOL} -tV main8.exe | grep unnamed_2_1 | ${PASS_IFF_EMPTY}
+
+nine:
+ #
+ # llvm : a9.c : Dfoo1, Dfoo2, Dfoo3, Ufoo3, Ufoo4
+ # MachO : main9.c : Ufoo1, Dfoo4
+ #
+ #echo "Nine..."
+ ${CC} ${CCFLAGS} -flto a9.c -c -o a9.o
+ ${CC} ${CCFLAGS} main9.c -c -o main9.o
+ ${CC} ${CCFLAGS} a9.o main9.o -o main9.exe -Wl,-dead_strip
+ ${OTOOL} -tV main9.exe | grep foo2 | ${PASS_IFF_EMPTY}
+ ${OTOOL} -tV main9.exe | grep foo4 | ${PASS_IFF_EMPTY}
+ ${OTOOL} -tV main9.exe | grep unnamed_2_1 | ${PASS_IFF_EMPTY}
+
+ten:
+ #
+ # llvm : a10.c
+ # llvm : b10.c
+ # MachO : main10.c
+ #
+ #echo "Ten..."
+ ${CC} ${CCFLAGS} -flto a10.c -c -o a10.o
+ ${CC} ${CCFLAGS} -flto b10.c -c -o b10.o
+ ${CC} ${CCFLAGS} main10.c -c -o main10.o
+ ${CC} ${CCFLAGS} a10.o b10.o main10.o -o main10.exe
+ ${PASS_IFF_GOOD_MACHO} main10.exe
+
+eleven:
+ #
+ # llvm : a11.c
+ # MachO : main11.c
+ #
+ #echo "Eleven..."
+ ${CC} ${CCFLAGS} -flto a11.c -c -o a11.o
+ ${CC} ${CCFLAGS} main11.c -c -o main11.o
+ ${CC} ${CCFLAGS} a11.o main11.o -o main11.exe
+ ${PASS_IFF_GOOD_MACHO} main11.exe
+
+twelve:
+ #
+ # llvm : a12.c
+ # MachO : main12.c
+ #
+ #echo "verify tentative def in llvm .o referenced from mach-o"
+ ${CC} ${CCFLAGS} -flto a12.c -c -o a12.o
+ ${CC} ${CCFLAGS} main12.c -c -o main12.o
+ ${CC} ${CCFLAGS} a12.o main12.o -o main12.exe
+ ${PASS_IFF_GOOD_MACHO} main12.exe
+
+thirteen:
+ #
+ # llvm : a13.cc
+ # MachO : main13.cc
+ #
+ # echo "Thirteen..."
+ ${CC} ${CXXFLAGS} -flto a13.cc -c -o a13.o
+ ${CC} ${CXXFLAGS} main13.cc -c -o main13.o
+ ${CXX} a13.o main13.o -o main13.exe
+
+fourteen:
+ #
+ # llvm : a14.c b14.c
+ #
+ # echo "verify an used hidden symbol is removed from a dylib"
+ ${CC} ${CXXFLAGS} -O4 -dynamiclib a14.c b14.c -o ab14.dylib
+ ${FAIL_IF_BAD_MACHO} ab14.dylib
+ nm -m ab14.dylib | grep _X | ${PASS_IFF_EMPTY}
+
+fifteen:
+ # echo "verify -dead_strip works with hidden symbols"
+ ${CC} ${CXXFLAGS} -O4 -Wl,-dead_strip a15.c c15.c -o main15.exe
+ ${CC} ${CXXFLAGS} -O4 a15.c c15.c -o main15.exe
+ ${FAIL_IF_BAD_MACHO} main15.exe
+ ${CC} ${CXXFLAGS} -O4 -Wl,-dead_strip -dynamiclib a15.c b15.c -o a15.dylib
+ ${CC} ${CXXFLAGS} -O4 a15.c b15.c -dynamiclib -o a15.dylib
+ ${FAIL_IF_BAD_MACHO} a15.dylib
+
+sixteen:
+ # echo "verify -save-temps"
+ ${CC} ${CCFLAGS} -flto main16.c -c -o main16.o
+ ${CC} ${CCFLAGS} main16.o -o main16.exe -Wl,-save-temps
+ ${PASS_IFF} test -e main16.exe.lto.bc
+ ${PASS_IFF} test -e main16.exe.lto.o
+
+seventeen:
+ # echo "verify ld -r of all bitcode files produces a bitcode file"
+ ${CC} ${CCFLAGS} -flto a17.c -c -o a17.o
+ ${CC} ${CCFLAGS} -flto b17.c -c -o b17.o
+ ${LD} -arch ${ARCH} -r a17.o b17.o -o ab17.o
+ file ab17.o | grep "Mach-O" | ${PASS_IFF_EMPTY}
+ # echo "verify ld -r of bitcode and mach-o produces mach-o"
+ ${CC} ${CCFLAGS} b17.c -c -o b17m.o
+ ${LD} -arch ${ARCH} -r a17.o b17m.o -o ab17m.o
+ file ab17m.o | grep "Mach-O" | ${PASS_IFF_STDIN}
+
+eighteen:
+ #echo verify ld -r -keep_private_externs works
+ ${CC} ${CCFLAGS} -flto a18.c -c -o a18.o
+ ${LD} -arch ${ARCH} -r -keep_private_externs a18.o -o a18-rkpe.o
+ nm -nm a18-rkpe.o | grep _common_hidden1 | grep "private external" | ${FAIL_IF_EMPTY}
+ nm -nm a18-rkpe.o | grep _func_hidden2 | grep "private external" | ${FAIL_IF_EMPTY}
+ #echo verify ld -r makes hidden symbols internal (except for commons)
+ ${LD} -arch ${ARCH} -r a18.o -o a18-r.o
+ #ObjectDump -nm a18-r.o | grep _common_hidden1 | grep " hidden" | ${FAIL_IF_EMPTY}
+ #ObjectDump -nm a18-r.o | grep _func_hidden2 | grep " internal" | ${FAIL_IF_EMPTY}
+
+nineteen:
+ #echo verify missing symbol error
+ ${CC} ${CCFLAGS} -flto main19.c -c -o main19.o
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main19.o -o main19.exe 2>fail.log
+ grep _foo fail.log | ${PASS_IFF_STDIN}
+
+twenty:
+ #echo verify bitcode files in archives works
+ #${CC} ${CCFLAGS} -flto a20.c -c -o a20.o
+ #${CC} ${CCFLAGS} -flto b20.c -c -o b20.o
+ #libtool -static a20.o b20.o -o lib20.a
+ #${CC} ${CCFLAGS} main20.c lib20.a -all_load -o main20.exe
+ #nm main20.exe | grep _foo | ${PASS_IFF_STDIN}
+
+
+
+
+
+clean:
+ rm -rf *.o main*.exe big.* *.dylib main16.*.bc fail.log lib20.a main21.preload lib21.a
+
--- /dev/null
+int foo3()
+{
+ return 21;
+}
+
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+extern int foo4();
+int foo3()
+{
+/* printf ("%s\n",strerror(errno)); */
+ return foo4();
+}
+
--- /dev/null
+extern void foo(void);
+
+void foo(void)
+{
+}
--- /dev/null
+#include <stdio.h>
+void foo3(void)
+{
+ fputc ('x', stderr);
+ printf ("\n");
+}
--- /dev/null
+#include "a12.h"
+
+enum E e[1000];
+void foo(void)
+{
+ e[1] = ONE;
+}
+
--- /dev/null
+enum E
+ {
+ ZERO,
+ ONE
+ };
+
+extern enum E e[1000];
+extern void foo(void);
--- /dev/null
+#include "a13.h"
+
+A::~A() {}
--- /dev/null
+#include <stdio.h>
+
+class A {
+ public:
+ virtual ~A();
+ void foo() { printf ("Hi\n"); }
+};
--- /dev/null
+int X __attribute__((visibility("hidden"))) = 14;
--- /dev/null
+void __attribute__((visibility("hidden"))) foo()
+{
+}
--- /dev/null
+
+int a = 0;
+int func_a() { return a; }
+
+// add code that will cause stack canary
+extern void fill(char*);
+void test()
+{
+ char buf[100];
+ fill(buf);
+}
+
--- /dev/null
+
+
+
+static int data_static1 = 1;
+static int data_static2 = 2;
+
+void func_global1() { ++data_static1; }
+void func_global2() { ++data_static2; }
+
+void __attribute__((visibility("hidden"))) func_hidden1() {}
+void __attribute__((visibility("hidden"))) func_hidden2() {}
+
+int common_global1;
+int common_global2;
+
+int __attribute__((visibility("hidden"))) common_hidden1;
+int __attribute__((visibility("hidden"))) common_hidden2;
+
--- /dev/null
+extern int foo4(void);
+int foo3()
+{
+ return foo4();
+}
+
--- /dev/null
+void foo() {}
+void bar() {}
--- /dev/null
+int bar;
+int foo1()
+{
+ return bar;
+}
+
--- /dev/null
+extern int foo4(void);
+int foo3()
+{
+ return foo4();
+}
+
--- /dev/null
+extern int foo2(void);
+extern int foo3(void);
+
+int foo1()
+{
+ int i = 42;
+ if (foo2())
+ i = foo3();
+ return i;
+}
--- /dev/null
+
+int foo1()
+{
+ return 42;
+}
+
+int foo2()
+{
+ return 21;
+}
--- /dev/null
+extern int foo3(void);
+
+int foo1(void)
+{
+ return foo3();
+}
+
+int foo2(void)
+{
+ return 42;
+}
--- /dev/null
+
+static signed int i = 0;
+extern int foo1(void);
+extern void foo2(void);
+
+void foo2(void) {
+
+ i = -1;
+
+}
+
+static int foo3() {
+ return 10;
+}
+
+int foo1(void)
+{
+ int data = 0;
+ if (i < 0)
+ data = foo3();
+ data += 42;
+ return data;
+}
--- /dev/null
+
+static signed int i = 0;
+extern int foo1(void);
+extern void foo2(void);
+extern void foo4(void);
+
+void foo2(void) {
+
+ i = -1;
+
+}
+
+static int foo3() {
+ foo4();
+ return 10;
+}
+
+int foo1(void)
+{
+ int data = 0;
+ if (i < 0)
+ data = foo3();
+ data += 42;
+ return data;
+}
--- /dev/null
+_foo1
+_main
+_bar
--- /dev/null
+int foo2() {
+ return 21;
+}
--- /dev/null
+extern int foo4();
+int foo2() {
+ return foo4();
+}
--- /dev/null
+#include "b10.h"
+extern void foo(void);
+
+struct my_struct my_hooks = {
+ foo
+};
+
--- /dev/null
+struct my_struct
+{
+ void (*f)(void);
+};
+
+extern struct my_struct my_hooks;
--- /dev/null
+#include <stdio.h>
+
+int Y;
+extern int X __attribute__((visibility("hidden")));
+void foo() {
+ printf ("%d\n", X);
+}
--- /dev/null
+extern void foo();
+void bar() {
+ foo();
+}
+
+void __attribute__((visibility("hidden"))) f2()
+{}
+
--- /dev/null
+int b = 0;
+int func_b() { return b; }
+
+
--- /dev/null
+extern int foo4(void);
+
+int foo4(void)
+{
+ return 21;
+}
+int foo2() {
+ return foo4();
+}
--- /dev/null
+void frob() {}
--- /dev/null
+extern int bar;
+int foo2() {
+ return bar;
+}
--- /dev/null
+extern int foo4(void);
+
+int foo4(void)
+{
+ return 21;
+}
+static int myfoo()
+{
+ return foo4();
+}
+int foo2() {
+ return myfoo();
+}
--- /dev/null
+int foo2(void)
+{
+ return 0;
+}
--- /dev/null
+extern int foo2(void);
+extern int foo3(void);
+
+int foo3(void)
+{
+ return foo2();
+}
--- /dev/null
+extern void foo();
+int main() {
+ foo();
+ return 0;
+}
+
+void __attribute__((visibility("hidden"))) f2()
+{
+}
--- /dev/null
+extern int foo2();
+extern int foo3();
+int main(){
+ int i = foo3() + foo2();
+ if (i == 42)
+ return 0;
+ else
+ return 1;
+}
--- /dev/null
+extern int foo2();
+extern int foo3();
+int foo4()
+{
+ return 21;
+}
+int main(){
+ int i = foo3() + foo2();
+ if (i == 42)
+ return 0;
+ else
+ return 1;
+}
--- /dev/null
+#include "b10.h"
+
+int main()
+{
+ struct my_struct *mh = &my_hooks;
+
+ mh->f();
+
+ return 0;
+}
--- /dev/null
+
+extern void foo3(void);
+int main()
+{
+ foo3();
+ return 0;
+}
--- /dev/null
+#include "a12.h"
+int main()
+{
+ e[0] = ZERO;
+ foo();
+ return e[0];
+}
--- /dev/null
+#include "a13.h"
+
+int main()
+{
+ A a;
+ a.foo();
+ return 0;
+}
--- /dev/null
+
+int tent;
+int global = 5;
+
+int foo() { return tent + global; }
+
+int main() { foo(); return 0; }
+
--- /dev/null
+extern int foo();
+
+int main()
+{
+ foo();
+ return 0;
+}
+
--- /dev/null
+extern int foo2();
+extern int foo3();
+int main(){
+ int i = foo3() + foo2();
+ if (i == 42)
+ return 0;
+ else
+ return 1;
+}
--- /dev/null
+extern void foo();
+
+int main()
+{
+ foo();
+ return 0;
+}
--- /dev/null
+extern int foo1();
+extern int foo2();
+extern int bar;
+int main(){
+ int i;
+ bar = 14;
+ i = foo1() + foo2() + bar;
+ if (i == 42)
+ return 0;
+ else
+ return 1;
+
+}
--- /dev/null
+extern int foo2();
+extern int foo3();
+int main(){
+ int i = foo3() + foo2();
+ if (i == 42)
+ return 0;
+ else
+ return 1;
+}
--- /dev/null
+
+extern int foo1(void);
+
+int foo3(void)
+{
+ return 42;
+}
+
+int main()
+{
+ int i = foo1();
+ if (i == 42)
+ return 0;
+ else
+ return 1;
+}
--- /dev/null
+extern int foo1();
+
+int main()
+{
+ int i = foo1();
+ if (i == 42)
+ return 0;
+ else
+ return 1;
+}
--- /dev/null
+extern int foo1(void);
+
+int main(void)
+{
+ int i = foo1();
+ if (i == 42)
+ return 0;
+ else
+ return 1;
+}
--- /dev/null
+extern int foo1(void);
+extern void foo2(void);
+
+int main()
+{
+ int i = foo1();
+ if (i == 42)
+ return 0;
+ else
+ return 1;
+}
--- /dev/null
+extern int foo1(void);
+extern void foo2(void);
+
+void foo4(void)
+{
+}
+int main()
+{
+ int i = foo1();
+ if (i == 42)
+ return 0;
+ else
+ return 1;
+}
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# The point of this test is a sanity check that an indirect
+# library loaded with @loader_path works
+#
+# <rdar://problem/4019497> ld64 should handle linking against dylibs that have @loader_path based dylib load commands
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib -install_name @loader_path/libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} foo.c libbar.dylib -dynamiclib -o libfoo.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ ${CC} ${CCFLAGS} main.c -o main libfoo.dylib
+ ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+clean:
+ rm *.dylib main
--- /dev/null
+
+int bar()
+{
+ return 1;
+}
+
--- /dev/null
+
+extern int bar();
+
+int foo()
+{
+ return bar();
+}
--- /dev/null
+extern void foo();
+
+int main()
+{
+ foo();
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# This test case checks -non_global_symbols_no_strip_list and -non_global_symbols_strip_list
+# with and without wildcards
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c foo.c -o main
+ ${FAIL_IF_BAD_MACHO} main
+ nm -j main > main.nm
+ # build stripping a.list
+ ${CC} ${CCFLAGS} main.c foo.c -Wl,-non_global_symbols_strip_list,a.list -o main-a
+ ${FAIL_IF_BAD_MACHO} main-a
+ nm -j main-a > main-a.nm
+ diff main.nm main-a.nm | egrep '<|>' > a.diff
+ diff a.diff a.expect | ${FAIL_IF_STDIN}
+ # build but strip at .o file level a.list
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ ${LD} -r -arch ${ARCH} main.o foo.o -o all-a.o -non_global_symbols_strip_list a.list
+ ${CC} ${CCFLAGS} all-a.o -Wl,-non_global_symbols_strip_list,a.list -o main-a
+ ${FAIL_IF_BAD_MACHO} main-a
+ nm -j main-a > main-a.nm
+ diff main.nm main-a.nm | egrep '<|>' > a.diff
+ diff a.diff a.expect | ${FAIL_IF_STDIN}
+ # build stripping b.list
+ ${CC} ${CCFLAGS} main.c foo.c -Wl,-non_global_symbols_strip_list,b.list -o main-b
+ ${FAIL_IF_BAD_MACHO} main-b
+ nm -j main-b > main-b.nm
+ diff main.nm main-b.nm | egrep '<|>' > b.diff
+ diff b.diff b.expect | ${FAIL_IF_STDIN}
+ # build but strip at .o file level b.list
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ ${LD} -r -arch ${ARCH} main.o foo.o -o all-b.o -non_global_symbols_strip_list b.list
+ ${CC} ${CCFLAGS} all-b.o -Wl,-non_global_symbols_strip_list,b.list -o main-b
+ ${FAIL_IF_BAD_MACHO} main-b
+ nm -j main-b > main-b.nm
+ diff main.nm main-b.nm | egrep '<|>' > b.diff
+ diff b.diff b.expect | ${FAIL_IF_STDIN}
+ # build stripping c.list
+ ${CC} ${CCFLAGS} main.c foo.c -Wl,-non_global_symbols_no_strip_list,c.list -o main-c
+ nm -m main-c | grep non-external | grep -v my | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} main-c
+
+
+clean:
+ rm -rf main main.nm main-a main-a.nm a.diff main-b main-b.nm b.diff main-c all-a.o all-b.o foo.o main.o
--- /dev/null
+< _myglobal
+< _xmyglobal2
--- /dev/null
+_myglobal
+_xmyglobal2
--- /dev/null
+< _myfunction
+< _myglobal2
+< _xmyglobal2
--- /dev/null
+*2
+_myf*on
--- /dev/null
+
+
+int __attribute__((visibility("hidden"))) myglobal = 3;
+int __attribute__((visibility("hidden"))) myglobal2 = 3;
+int __attribute__((visibility("hidden"))) xmyglobal = 3;
+int __attribute__((visibility("hidden"))) xmyglobal2 = 3;
+
+void __attribute__((visibility("hidden"))) myfunction(int x) { }
+
+
+
--- /dev/null
+#include <stdio.h>
+
+extern int myglobal;
+extern void myfunction(int);
+
+int main()
+{
+ myfunction(myglobal);
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/5935600> LTO : 176.gcc and 177.mesa build failure at -O4
+#
+# Check that LTO can bring in an archive member and that member needs a
+# symbol from a dylib.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ libtool -static foo.o -o libfoo.a
+ ${CC} ${CCFLAGS} -flto main.c -c -o main.o
+ ${CC} ${CCFLAGS} main.o -o main libfoo.a
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main foo.o libfoo.a main.o
--- /dev/null
+#include <stdio.h>
+void foo()
+{
+ fprintf(stderr, "hello\n");
+}
--- /dev/null
+extern void foo();
+
+int main()
+{
+ foo();
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/6806033> Link Time Optimization error with 'dead code strip' + hidden symbol
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -flto bar.c -c -o bar.o -fvisibility=hidden
+ ${CC} ${CCFLAGS} -dynamiclib bar.o -o libbar.dylib -dead_strip
+ ${PASS_IFF_GOOD_MACHO} libbar.dylib
+
+clean:
+ rm bar.o libbar.dylib
--- /dev/null
+
+
+void bar() {}
+
--- /dev/null
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+# Test case for <rdar://problem/9777977>
+# mach-o has coalescable strings which are dead stripped away
+# but come back from bitcode file.
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -flto -o foo.o
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ ${CC} ${CCFLAGS} main.o foo.o -o main -dead_strip -framework Foundation
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main main.o foo.o
--- /dev/null
+
+#include <string.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+void foo1()
+{
+ CFStringGetLength(CFSTR("test1"));
+ strlen("str1");
+}
+
+void foo2()
+{
+ CFStringGetLength(CFSTR("test2"));
+ strlen("str2");
+}
+
+void foo3()
+{
+ CFStringGetLength(CFSTR("test3"));
+ strlen("str3");
+}
--- /dev/null
+
+#include <string.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+
+extern void foo1();
+extern void foo2();
+
+
+void t1()
+{
+ CFStringGetLength(CFSTR("test1"));
+ strlen("str1");
+}
+
+void t2()
+{
+ CFStringGetLength(CFSTR("test2"));
+ strlen("str2");
+}
+
+void t3()
+{
+ CFStringGetLength(CFSTR("test3"));
+ strlen("str3");
+}
+
+// <rdar://problem/12005173> error with LTO and dead strip of non-lazy-pointer
+void* foo2p() {
+ return &foo2;
+}
+
+int main()
+{
+ t2();
+ foo1();
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2012 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# <rdar://problem/11124216> [lto] Linking libLTO.dylib causing an assertion in ld
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -flto bar.c -c -o bar.o
+ ${CC} ${CCFLAGS} bar.o -dynamiclib -o libbar.dylib -dead_strip -Wl,-exported_symbol,_bar
+ ${PASS_IFF_GOOD_MACHO} libbar.dylib
+
+clean:
+ rm -f bar.o libbar.dylib
+
--- /dev/null
+
+
+void qux() {}
+
+asm("\t.text\n"
+ "\t.globl _foo\n"
+ "_foo:\n"
+ "\tnop\n");
+
+extern void foo();
+
+void (*bar())() {
+ return foo;
+}
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/8481987> Link Time Optimization crashes linker with 'dead code strip' + hidden symbol
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -flto foo.m -c -o foo.o -fvisibility=hidden
+ ${CC} ${CCFLAGS} -dynamiclib foo.o -o libfoo.dylib -dead_strip -framework Foundation
+ ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+clean:
+ rm -f foo.o libfoo.dylib
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+- (NSString*) foo;
+@end
+
+
+@implementation Foo
+- (NSString*) foo
+{
+ return [NSString stringWithUTF8String:"hello"];
+}
+@end
+
+
+@interface Bar : NSData
+- (NSArray*) bar;
+@end
+
+
+@implementation Bar
+- (NSArray*) bar
+{
+ return [NSArray array];
+}
+@end
+
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/8481987> Link Time Optimization crashes linker with 'dead code strip' + hidden symbol
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -flto bar.c -c -o bar.o -fvisibility=hidden
+ ${CC} ${CCFLAGS} -dynamiclib bar.o -o libbar.dylib -dead_strip
+ ${PASS_IFF_GOOD_MACHO} libbar.dylib
+
+clean:
+ rm bar.o libbar.dylib
--- /dev/null
+
+int data[] = { 4, 5, 6 };
+int deaddata[] = { 7, 8, 9 };
+
+int func() { return 0; }
+int deadfunc() { return 0; }
+
+__attribute__((visibility("default")))
+int* foo()
+{
+ return data;
+}
+
+__attribute__((visibility("default")))
+void* foo2()
+{
+ return func;
+}
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/8708091> Link Time Optimization error with tentative defs and -dead_strip
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -flto foo.c -c -o foo.o
+ ${CC} ${CCFLAGS} -flto bar.c -c -o bar.o
+ ${CC} ${CCFLAGS} -flto baz.c -c -o baz.o
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ ${CC} ${CCFLAGS} main.o foo.o bar.o baz.o -o main -dead_strip
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf foo.o bar.o baz.o main.o main
--- /dev/null
+
+int tent;
+
+int bar() { return tent; }
--- /dev/null
+
+int tent;
+
+int baz() { return tent; }
+
--- /dev/null
+
+int tent;
+
+int foo() { return tent; }
--- /dev/null
+
+extern int foo();
+extern int bar();
+extern int baz();
+
+int main()
+{
+ foo();
+ bar();
+ baz();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2010-2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# <rdar://problem/7438246> LTO with 'dead code strip' can't ignore unused functions with undefined references
+# <rdar://problem/10052396> LTO many have eliminated need for some undefines
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -flto bar.c -c -o bar.o
+ ${CC} ${CCFLAGS} -flto main.c -c -o main.o
+ ${CC} ${CCFLAGS} main.o bar.o -o main
+ ${CC} ${CCFLAGS} main.o bar.o -o main -dead_strip
+ ${CC} ${CCFLAGS} main.o bar.o -dynamiclib -o libmain.dylib -Wl,-exported_symbol,_main
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.o bar.o -dynamiclib -o libmain.dylib -dead_strip 2>/dev/null
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -f bar.o main.o main
+
--- /dev/null
+
+
+void bar()
+{
+}
+
+
+extern void unused1();
+
+void unused2()
+{
+ unused1();
+}
+
+
--- /dev/null
+extern void bar();
+
+int main()
+{
+ bar();
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that -mllvm optiions work. Verify --disable-inlining
+# results in foo() not being inlined
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -flto main.c -c -o main.o -fvisibility=hidden
+ ${CC} ${CCFLAGS} main.o -o main
+ nm main | grep _foo | ${FAIL_IF_STDIN}
+ ${CC} ${CCFLAGS} main.o -o main2 -fvisibility=hidden -Wl,-mllvm -Wl,--disable-inlining
+ nm main2 | grep _foo | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm main main.o main2
--- /dev/null
+
+#include <stdio.h>
+
+
+void foo(int x)
+{
+ printf("hello, world %d\n", x);
+}
+
+int main()
+{
+ foo(10);
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/6927148> link failure with -O4 on i386#
+# Check that LTO can bring in an ObjC class from an archive member
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.m -c -o foo.o
+ ${CC} ${CCFLAGS} bar.m -c -o bar.o
+ ${CC} ${CCFLAGS} foo2.c -c -o foo2.o
+ ${CC} ${CCFLAGS} bar2.c -c -o bar2.o
+ libtool -static foo.o bar.o foo2.o bar2.o -o libfoobar.a
+ ${CC} ${CCFLAGS} -flto main.m -c -o main.o
+ ${CC} ${CCFLAGS} main.o -o main libfoobar.a -framework Foundation
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main foo.o bar.o foo2.o bar2.o libfoobar.a main.o
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Bar : NSObject
+@end
+
+extern void bar2();
--- /dev/null
+#include "bar.h"
+
+@implementation Bar
+- (void) test {
+ bar2();
+}
+@end
--- /dev/null
+
+void bar2() {}
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+@end
+
+
+extern void foo2();
+
--- /dev/null
+
+#include "foo.h"
+
+@implementation Foo
+- (void) test {
+ foo2();
+}
+@end
--- /dev/null
+
+void foo2() {}
--- /dev/null
+
+#include <Foundation/Foundation.h>
+#include "foo.h"
+#include "bar.h"
+
+
+@interface FooSubClass : Foo
+@end
+
+
+@implementation FooSubClass
+@end
+
+
+int main()
+{
+ [Bar alloc];
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/8198537> trivial Objective-C app fails when using libLTO
+#
+
+
+IMAGE_INFO = "__image_info"
+
+ifeq ($(ARCH),x86_64)
+ IMAGE_INFO = "__objc_imageinfo"
+endif
+ifeq ($(FILEARCH),arm)
+ IMAGE_INFO = "__objc_imageinfo"
+endif
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -flto main.m -c -o main.o
+ ${CC} ${CCFLAGS} main.o -o main -framework Foundation
+ size -l main | grep ${IMAGE_INFO} | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main main.o
--- /dev/null
+
+#include <Foundation/Foundation.h>
+
+int main() {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [pool drain];
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that linker option -object_path_lto results in tmp .o file
+# being produced.
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -flto main.c -c -o main.o -fvisibility=hidden
+ ${CC} ${CCFLAGS} main.o -o main -Wl,-object_path_lto,`pwd`/main.tmp.o
+ nm main.tmp.o | grep _main | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm main main.o main.tmp.o main
--- /dev/null
+
+#include <stdio.h>
+
+
+void foo(int x)
+{
+ printf("hello, world %d\n", x);
+}
+
+int main()
+{
+ foo(10);
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# verify -preload -pie produces relocations
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -flto a.c -c -o a.o
+ ${CC} ${CCFLAGS} -flto b.c -c -o b.o
+ ${CC} ${CCFLAGS} -flto main.c -c -o main.o
+ ${CC} ${CCFLAGS} main.o a.o b.o -Wl,-preload -Wl,-pie -o main.preload \
+ -e _entry -nostdlib -Wl,-segalign,0x20 -Wl,-seg1addr,0x200
+ otool -rv main.preload | grep "Local relocation information" | ${PASS_IFF_STDIN}
+
+
+
+
+clean:
+ rm a.o b.o main.o main.preload
--- /dev/null
+
+extern const char* mystring;
+
+const char** myp = &mystring;
--- /dev/null
+ const char* mystring = "hello";
--- /dev/null
+
+extern const char** myp;
+
+
+const char** entry(int i) {
+ if ( i ) {
+ *myp = "help";
+ }
+ return myp;
+}
+
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that LTO works when a llvm bitcode has a weak symbol _foo
+# and mach-o has a strong _foo.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ ${CC} ${CCFLAGS} -flto main.c -c -o main.o
+ ${CC} ${CCFLAGS} main.o foo.o -o main
+ otool -Iv main | grep _abort | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm main foo.o main.o
+
\ No newline at end of file
--- /dev/null
+
+
+void foo()
+{
+ // do nothing
+}
--- /dev/null
+
+#include <stdlib.h>
+
+static void die() { abort(); }
+
+
+__attribute__((visibility("hidden"),weak)) void foo()
+{
+ die();
+}
+
+int main()
+{
+ foo();
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/6927148> link failure with -O4 on i386#
+# Check that LTO can bring in an ObjC class from an archive member
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+ ${CC} ${CCFLAGS} -flto main.c -c -o main.o
+ ${CC} ${CCFLAGS} main.o -o main libfoo.dylib
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main main.o libfoo.dylib
--- /dev/null
+
+
+void foo() {}
--- /dev/null
+
+#include <stdlib.h>
+
+extern void foo() __attribute__((weak_import));
+
+
+int main()
+{
+ if ( &foo != NULL )
+ foo();
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2006-2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that a dynamically referenced symbol is always exported
+#
+
+run: all
+
+all:
+ ${CC} main.c -o main -exported_symbols_list main.exp
+ nm -m main | grep _magicSymbol | grep "referenced dynamically" | ${FAIL_IF_EMPTY}
+ nm -m main | grep _hiddenSymbol | grep "referenced dynamically" | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+ rm main
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stddef.h>
+
+// set magic "dynamically referenced" bit on magicSymbol
+int magicSymbol = 1;
+asm(".desc _magicSymbol, 0x10");
+
+// this symbol will be suppressed by .exp file
+int hiddenSymbol = 1;
+asm(".desc _hiddenSymbol, 0x10");
+
+int main()
+{
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+_main
+_magicSymbol
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that the -merge_zero_fill_sections works
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -o main -Wl,-merge_zero_fill_sections
+ size -l main | grep __bss | ${FAIL_IF_STDIN}
+ size -l main | grep __common | ${FAIL_IF_STDIN}
+ size -l main | grep __zerofill | grep "offset 0" | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm main
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+static int a[2000];
+int b[2000];
+
+extern void* zerofill_start __asm("section$start$__DATA$__zerofill");
+extern void* zerofill__end __asm("section$end$__DATA$__zerofill");
+
+void* start = &zerofill_start;
+void* end = &zerofill__end;
+
+int main()
+{
+ a[0] = 0;
+ b[0] = 0;
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2007 Apple, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify that missing arguments don't cause ld to crash
+# This tests 64-bit arguments only
+#
+
+
+OUTPUT=2>/dev/null
+LDCMD=${FAIL_IF_SUCCESS} ${LD} -arch ${ARCH} ${OUTPUT}
+
+run: all
+
+all:
+ ${FAIL_IF_SUCCESS} ${LD} -arch 2>/dev/null
+ ${LDCMD} -filelist
+ ${LDCMD} -o
+ ${LDCMD} -read_only_relocs
+ ${LDCMD} -sect_diff_relocs
+ ${LDCMD} -weak_reference_mismatches
+ ${LDCMD} -l
+ ${LDCMD} -weak-l
+ ${LDCMD} -weak-library
+ ${LDCMD} -L
+ ${LDCMD} -syslibroot
+ ${LDCMD} -framework
+ ${LDCMD} -framework name,
+ ${LDCMD} -weak_framework
+ ${LDCMD} -weak_framework name
+ ${LDCMD} -weak_framework name,
+ ${LDCMD} -F
+ ${LDCMD} -dylib_file
+ ${LDCMD} -dylib_file install_name
+ ${LDCMD} -sectcreate segname sectname
+ ${LDCMD} -sectorder
+ ${LDCMD} -sectorder segname sectname
+ ${LDCMD} -u
+ ${LDCMD} -e
+ ${LDCMD} -i
+ ${LDCMD} -idefinition:
+ ${LDCMD} -undefined
+ ${LDCMD} -U
+ ${LDCMD} -commons
+ ${LDCMD} -warn_commons
+ ${LDCMD} -exported_symbols_list
+ ${LDCMD} -unexported_symbols_list
+ ${LDCMD} -filelist
+ ${LDCMD} -filelist listfile,
+ ${LDCMD} -headerpad
+ ${LDCMD} -A
+ ${LDCMD} -dylib_install_name
+ ${LDCMD} -umbrella
+ ${LDCMD} -allowable_client
+ ${LDCMD} -client_name
+ ${LDCMD} -sub_umbrella
+ ${LDCMD} -sub_library
+ ${LDCMD} -init
+ ${LDCMD} -dylinker_install_name
+ ${LDCMD} -macosx_version_min
+ ${LDCMD} -final_output
+ ${LDCMD} -seg1addr
+ ${LDCMD} -pagezero_size
+ ${LDCMD} -dylib_compatibility_version
+ ${LDCMD} -stack_addr
+ ${LDCMD} -stack_size
+ ${LDCMD} -sectcreate
+ ${LDCMD} -sectcreate segname
+ ${LDCMD} -sectalign
+ ${LDCMD} -sectalign segname
+ ${LDCMD} -sectalign segname sectname
+ ${LDCMD} -sectorder segname
+ ${LDCMD} -dylib_current_version
+ ${PASS_IFF} true
+
+clean:
--- /dev/null
+Verify that missing arguments don't cause ld to crash
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to verify a .o file can round-trip
+# through ld -r correctly. The ObjectDump utility is used
+# dump a "canonical" textual representation of a .o file.
+# The before and after .o files are then diff'ed.
+# No differences means this test passes
+#
+
+run: all
+
+all:
+ ${CC} ${ASMFLAGS} test.s -c -o test.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_sort test.${ARCH}.o > test.${ARCH}.o.dump
+
+ ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_sort test-r.${ARCH}.o > test-r.${ARCH}.o.dump
+
+ ${PASS_IFF} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+clean:
+ rm -rf *.o *.dump
--- /dev/null
+The point of this test is to verify a .o file can round-trip through ld -r correctly. The ObjectDump utility is used
+dump a "canonical" textual representation of a .o file. The before and after .o files are then diff'ed.
+No differences means this test passes
--- /dev/null
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+ .text
+ .align 2
+
+ .globl _foo
+ .globl _foo2
+ .globl _foo3
+_foo:
+_foo2:
+_foo3:
+ nop
+
+
+
+ .align 2
+_bar:
+ nop
+
+
+ .align 2
+ .globl _xx
+ .globl __xx
+_xx:
+__xx:
+ nop
+
+
+ .align 2
+_ok:
+ nop
+
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that a bundle built with no data links
+# <rdar://problem/6532377> gcc DejaGnu failure: building longcall/dylib library
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -bundle -o foo.bundle
+ ${PASS_IFF_GOOD_MACHO} foo.bundle
+
+clean:
+ rm foo.bundle
--- /dev/null
+#include <stdlib.h>
+
+void foo()
+{
+ rand();
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to determine if
+# common symbols are not allowed with MH_DYLIB output format with the -multi_module option
+#
+
+run: all
+
+all:
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c test.c -o test-${ARCH}.o
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c a.c -o a-${ARCH}.o
+ ${PASS_IFF_ERROR} libtool -dynamic -o libtest-${ARCH}.a test-${ARCH}.o 2>/dev/null
+
+clean:
+ rm -rf *.o *.a
--- /dev/null
+extern int common_variable;
+
+int
+main(int argc, char **argv)
+{
+ return common_variable;
+}
--- /dev/null
+The point of this test is to determine if common symbols are not allowed with MH_DYLIB output format with the -multi_module option
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+int common_variable;
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that when ld creates an object file with no symbols
+# and no section content, that the segment size is zero
+# and the LC_SYMTAB is empty.
+#
+# <rdar://problem/6048484> LC_SEGMENT_64 filesize incorrect for MH_OBJECT filetype
+#
+
+run: all
+
+all:
+ as -arch ${ARCH} -n empty.s -o empty.o
+ ${LD} -r empty.o -x -o empty2.o
+ otool -lv empty2.o | egrep 'vmsize 0x0[0]+$$' | ${FAIL_IF_EMPTY}
+ otool -lv empty2.o | grep 'filesize 0' | ${FAIL_IF_EMPTY}
+ otool -lv empty2.o | grep 'nsyms 0' | ${FAIL_IF_EMPTY}
+ otool -lv empty2.o | grep 'symoff 0' | ${FAIL_IF_EMPTY}
+ ${PASS_IFF} true
+
+clean:
+ rm empty.o empty2.o
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test the we set emit LC_UUID correctly
+#
+
+run: all
+
+all:
+
+# Test main executable built with dwarf has uuid
+ ${CC} ${CCFLAGS} foo.c -o foo -gdwarf-2
+ ${FAIL_IF_BAD_MACHO} foo
+ ${OTOOL} -hlv foo | grep LC_UUID | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} foo
+
+clean:
+ rm -rf foo foo.dSYM
--- /dev/null
+int bar (void)
+{
+ return 1;
+}
--- /dev/null
+Test the we set emit LC_UUID correctly
--- /dev/null
+int main (void)
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that the -no_zero_fill_sections works
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -o main -Wl,-no_zero_fill_sections
+ size -l main | grep __bss | grep "offset 0" | ${FAIL_IF_STDIN}
+ size -l main | grep __common | grep "offset 0" | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm main
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+static int a[2000];
+int b[2000];
+
+int main()
+{
+ a[0] = 0;
+ b[0] = 0;
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that non-lazy-pointers are properly handled by -r
+#
+
+
+all: all-${ARCH}
+
+all-ppc: hasnl
+
+all-ppc64: hasnl
+
+all-i386: hasnl
+
+all-armv6: hasnl
+
+all-armv7: hasnl
+
+all-x86_64: all-true
+
+all-true:
+ ${PASS_IFF} true
+
+
+hasnl:
+ ${CC} ${CCFLAGS} -c foo.c -o foo.o
+ ${CC} ${CCFLAGS} -c other.c -o other.o
+ ${LD} -r -arch ${ARCH} foo.o other.o -o fooall.o -exported_symbol _foo
+ # make sure there are two indirect symbols: _foo and LOCAL
+ otool -Iv fooall.o | grep "4 entries" | ${FAIL_IF_EMPTY}
+ otool -Iv fooall.o | grep _foo | ${FAIL_IF_EMPTY}
+ otool -Iv fooall.o | grep _tent | ${FAIL_IF_EMPTY}
+ otool -Iv fooall.o | grep _other | ${FAIL_IF_STDIN}
+ ${OBJECTDUMP} fooall.o | grep name: | grep 'non-lazy-pointer-to:_foo' | ${FAIL_IF_EMPTY}
+ ${OBJECTDUMP} fooall.o | grep name: | grep 'non-lazy-pointer-to-local:_other' | ${FAIL_IF_EMPTY}
+ ${OBJECTDUMP} fooall.o | grep name: | grep 'non-lazy-pointer-to:_tent' | ${FAIL_IF_EMPTY}
+ ${OBJECTDUMP} fooall.o | grep name: | grep 'non-lazy-pointer-to:_foo' | ${FAIL_IF_EMPTY}
+ ${LD} -r -arch ${ARCH} fooall.o -o fooall2.o
+ ${OBJECTDUMP} fooall.o > fooall.dump
+ ${OBJECTDUMP} fooall2.o > fooall2.dump
+ ${PASS_IFF} diff fooall.dump fooall2.dump
+
+clean:
+ rm -rf *.o fooall.dump fooall2.dump
--- /dev/null
+
+
+
+extern int foo;
+
+int getfoo() { return foo; }
+
+
+extern int other;
+
+int getother() { return other; }
+
+
+extern int tent;
+
+int gettent() { return tent; }
+
+
+extern void* func;
+void* getfunc() { return func; }
--- /dev/null
+int foo = 2;
+int other = 3;
+int tent;
+void func() {}
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that non-lazy-pointers in different section are properly handled by -r
+#
+
+
+all: all-${ARCH}
+
+all-ppc: hasnl
+
+all-i386: hasnl
+
+all-armv6: hasnl
+
+all-armv7: hasnl
+
+all-x86_64: all-true
+
+all-true:
+ ${PASS_IFF} true
+
+
+hasnl:
+ ${CC} ${CCFLAGS} -c foo.s -o foo.o
+ ${LD} -r -arch ${ARCH} foo.o -o foo-r.o
+ ${OBJECTDUMP} foo.o > foo.o.dump
+ ${OBJECTDUMP} foo-r.o > foo-r.o.dump
+ ${PASS_IFF} diff foo.o.dump foo-r.o.dump
+
+clean:
+ rm -rf *.o *.dump
--- /dev/null
+ .text
+ .align 4
+ .globl _test
+_test:
+#if __i386__
+ movl L_foo$non_lazy_ptr, %eax
+ movl L_bar$non_lazy_ptr, %eax
+ movl L_other$non_lazy_ptr, %eax
+ ret
+#endif
+#if __arm__ || __ppc__
+ .long L_foo$non_lazy_ptr
+ .long L_bar$non_lazy_ptr
+ .long L_other$non_lazy_ptr
+#endif
+
+
+
+ .section __IMPORT,__pointers,non_lazy_symbol_pointers
+L_foo$non_lazy_ptr:
+.indirect_symbol _foo
+ .long 0
+
+ .section __DATA,__one,non_lazy_symbol_pointers
+L_bar$non_lazy_ptr:
+.indirect_symbol _bar
+ .long 0
+
+ .section __DATA,__two,non_lazy_symbol_pointers
+L_other$non_lazy_ptr:
+.indirect_symbol _other
+ .long 0
+
+
+.subsections_via_symbols
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify -objc_abi_version 2 works for i386
+#
+ifeq (${ARCH},i386)
+ ALL = all-i386
+else
+ ALL = all
+endif
+
+run: ${ALL}
+
+all:
+ ${PASS_IFF_GOOD_MACHO} /usr/bin/true
+
+all-i386:
+ ${CC} ${CCFLAGS} test.m -framework Foundation -o test1
+ size -l test1 | grep __image_info | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} test.m -fobjc-abi-version=2 -Wl,-objc_abi_version,2 -framework Foundation -o test2
+ size -l test2 | grep __objc_imageinfo | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} test2
+
+
+clean:
+ rm -rf test1 test2
--- /dev/null
+
+@interface Foo
+@end
+
+@implementation Foo
+@end
+
+
+int main()
+{
+ return 0;
+}
+
+
+#if __i386__ && __OBJC2__
+ int _objc_empty_vtable = 1;
+#endif
--- /dev/null
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Verify -ObjC works with x86_64 categories
+# Verify stripped archives keep don't-strip bit
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -g test.m -c -o test.o
+ ${CC} ${CCFLAGS} -g test2.m -c -o test2.o
+ libtool -static test.o test2.o -o libtest.a
+ ${CC} ${CCFLAGS} main.m libtest.a -ObjC -o main -framework Foundation
+ nm main | grep mycatmethod1 | ${FAIL_IF_EMPTY}
+ nm main | grep mycatmethod2 | ${FAIL_IF_EMPTY}
+ nm main | grep mymethod2 | ${FAIL_IF_EMPTY}
+ ${LD} -arch ${ARCH} -r -S -keep_private_externs test.o test2.o -o test-stripped.o
+ libtool -static test-stripped.o -o libtest-stripped.a
+ ${CC} ${CCFLAGS} main.m libtest-stripped.a -all_load -dead_strip -o main2 -framework Foundation
+ nm main2 | grep mycatmethod1 | ${FAIL_IF_EMPTY}
+ nm main2 | grep mycatmethod2 | ${FAIL_IF_EMPTY}
+ nm main2 | grep mymethod2 | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main2
+
+clean:
+ rm -rf test.o test2.o test-stripped.o libtest.a libtest-stripped.a main main2
--- /dev/null
+
+int main()
+{
+ return 0;
+}
+
--- /dev/null
+
+#include <Foundation/Foundation.h>
+
+int some_global_to_stop_libtool_warning = 5;
+
+@interface NSObject (stuff)
+- (void) mycatmethod1;
+@end
+
+@implementation NSObject (stuff)
+- (void) mycatmethod1 { }
+@end
+
+@interface NSObject (other)
+- (void) mycatmethod2;
+@end
+
+@implementation NSObject (other)
+- (void) mycatmethod2 { }
+@end
+
--- /dev/null
+
+#include <Foundation/Foundation.h>
+
+@interface MyClass : NSObject
+- (void) mymethod2;
+@end
+
+@implementation MyClass
+- (void) mymethod2 { }
+@end
+
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Verify no GSYM for .objc_category_*
+# <rdar://problem/5774231> Linker should not make GSYM debug note for .objc_category_* symbols#
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.m -g -o test -framework Foundation -Wno-objc-protocol-method-implementation
+ nm -ap test | grep GSYM | grep category | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} test
+
+clean:
+ rm -rf test test.dSYM
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <Foundation/Foundation.h>
+
+
+@interface NSObject (stuff)
+@end
+
+@implementation NSObject (stuff)
+@end
+
+@interface NSObject (other)
+@end
+
+@implementation NSObject (other)
+- (id) init { return self; }
+@end
+
+int main()
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify optimization where categories are merged into classes
+#
+OPTIONS =
+
+ifeq ($(ARCH),i386)
+ OPTIONS = -fobjc-abi-version=2 -Wl,-objc_abi_version,2 -isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk -fobjc-legacy-dispatch
+endif
+
+all: all-${ARCH}
+
+all-ppc:
+ ${PASS_IFF} true
+
+all-i386: all-rest
+all-x86_64: all-rest
+all-armv6: all-rest
+all-armv7: all-rest
+
+all-rest:
+ # check optimzation of category methods
+ ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat1.m -framework Foundation -o libfoo.dylib
+ size -l libfoo.dylib | grep "__objc_catlist:" | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+
+clean:
+ rm -rf libfoo.dylib
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+-(void) method1;
+@end
+
+
+@interface Foo(mycat)
++(void) load;
+@end
+
+@implementation Foo(mycat)
++(void) load {}
+@end
+
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+@end
+
+
+@implementation Foo
+@end
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify optimization where categories are merged into classes
+#
+OPTIONS =
+
+ifeq ($(ARCH),i386)
+ OPTIONS = -fobjc-abi-version=2 -Wl,-objc_abi_version,2 -isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk -fobjc-legacy-dispatch
+endif
+
+ifeq ($(ARCH),arm)
+ OPTIONS = -isysroot=${IOS_SDK}
+endif
+
+all: all-${ARCH}
+
+all-ppc:
+ ${PASS_IFF} true
+
+all-i386: all-rest
+all-x86_64: all-rest
+all-armv6: all-rest
+all-armv7: all-rest
+
+all-rest:
+ # check optimization can be turned off
+ ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat1.m cat2.m -framework Foundation -Wl,-no_objc_category_merging -o libno.dylib
+ size -l libno.dylib | grep "__objc_catlist: 0" | ${FAIL_IF_STDIN}
+ otool -ov libno.dylib | grep -A17 __objc_classlist | grep -A16 '_OBJC_CLASS_$$_Foo' | grep "count 1" | ${FAIL_IF_EMPTY}
+ # check optimzation of category methods
+ ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat1.m cat2.m -framework Foundation -o libfoo.dylib
+ size -l libfoo.dylib | grep "__objc_catlist: 0" | ${FAIL_IF_EMPTY}
+ otool -ov libfoo.dylib | grep -A20 __objc_classlist | grep -A20 '_OBJC_CLASS_$$_Foo' | grep "count 4" | ${FAIL_IF_EMPTY}
+ # check optimzation of protocol and category methods
+ ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat1.m cat2.m -DPROTOCOLS -framework Foundation -o libfoo2.dylib
+ size -l libfoo2.dylib | grep "__objc_catlist: 0" | ${FAIL_IF_EMPTY}
+ otool -ov libfoo2.dylib | grep -A20 __objc_classlist | grep -A20 '_OBJC_CLASS_$$_Foo' | grep "count 6" | ${FAIL_IF_EMPTY}
+ # check optimzation of properties and category methods
+ ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat1.m cat2.m -DPROPERTIES -framework Foundation -o libfoo3.dylib
+ size -l libfoo3.dylib | grep "__objc_catlist: 0" | ${FAIL_IF_EMPTY}
+ otool -ov libfoo3.dylib | grep -A20 __objc_classlist | grep -A20 '_OBJC_CLASS_$$_Foo' | grep "count 6" | ${FAIL_IF_EMPTY}
+ # check optimzation of category methods and no base methods
+ ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat1.m cat2.m -DNO_BASE_METHODS -framework Foundation -o libfoo4.dylib
+ size -l libfoo4.dylib | grep "__objc_catlist: 0" | ${FAIL_IF_EMPTY}
+ otool -ov libfoo4.dylib | grep -A20 __objc_classlist | grep -A20 '_OBJC_CLASS_$$_Foo' | grep "count 3" | ${FAIL_IF_EMPTY}
+ otool -ov libfoo4.dylib | grep -A20 "Meta Class" | grep "count 2" | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libfoo3.dylib
+
+
+
+clean:
+ rm -rf lib*.dylib
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+-(void) method1;
+@end
+
+
+
+
+@interface Foo(mycat)
+-(void) instance_method_mycat1;
+-(void) instance_method_mycat2;
++(void) class_method_mycat;
+#if PROPERTIES
+ @property(readonly) int property1;
+ @property(readonly) int property2;
+#endif
+@end
+
+@implementation Foo(mycat)
+-(void) instance_method_mycat1 {}
+-(void) instance_method_mycat2 {}
++(void) class_method_mycat {}
+#if PROPERTIES
+ -(int) property1 { return 0; }
+ -(int) property2 { return 0; }
+#endif
+@end
+
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+-(void) method1;
+@end
+
+#if PROTOCOLS
+ @protocol myotherprotocol
+ - (void) instance_method_myotherprotocol1;
+ - (void) instance_method_myotherprotocol2;
+ @end
+
+ @interface Foo(myothercat) < myotherprotocol >
+ - (void) instance_method_myothercat;
+ + (void) class_method_myothercat;
+ @end
+
+ @implementation Foo(myothercat)
+ - (void) instance_method_myothercat {}
+ + (void) class_method_myothercat {}
+ - (void) instance_method_myotherprotocol1 {}
+ - (void) instance_method_myotherprotocol2 {}
+ @end
+
+#else
+ @interface Foo(myothercat)
+ - (void) instance_method_myothercat;
+ + (void) class_method_myothercat;
+ @end
+
+ @implementation Foo(myothercat)
+ - (void) instance_method_myothercat {}
+ + (void) class_method_myothercat {}
+ @end
+#endif
+
+
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+#ifndef NO_BASE_METHODS
+-(void) instance_method;
++(void) class_method;
+#endif
+@end
+
+
+@implementation Foo
+#ifndef NO_BASE_METHODS
+-(void) instance_method {}
++(void) class_method {}
+#endif
+@end
+
--- /dev/null
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Verify optimization in which categories are merged into classes
+#
+OPTIONS =
+
+ifeq ($(ARCH),i386)
+ OPTIONS = -fobjc-abi-version=2 -Wl,-objc_abi_version,2 -isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk -fobjc-legacy-dispatch
+endif
+
+all: all-${FILEARCH}
+
+all-ppc:
+ ${PASS_IFF} true
+
+all-i386: all-rest
+all-x86_64: all-rest
+all-arm: all-rest
+
+all-rest:
+ ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat.m -DOVERRIDE_CLASS=1 -framework Foundation -o libfoo.dylib 2> warnings1.txt
+ grep warning warnings1.txt | grep instance_method | ${FAIL_IF_EMPTY}
+ grep warning warnings1.txt | grep class_method | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat.m copycat.m -framework Foundation -o libfoo2.dylib 2> warnings2.txt
+ grep warning warnings2.txt | grep instance_method_fromcat | ${FAIL_IF_EMPTY}
+ grep warning warnings2.txt | grep class_method_fromcat | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libfoo2.dylib
+
+clean:
+ rm -rf lib*.dylib warnings*.txt
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+-(void) method1;
+@end
+
+@interface Foo(fromcat)
+- (void) instance_method_fromcat;
++ (void) class_method_fromcat;
+#if OVERRIDE_CLASS
+- (void) instance_method;
++ (void) class_method;
+#endif
+@end
+
+@implementation Foo(fromcat)
+- (void) instance_method_fromcat {}
++ (void) class_method_fromcat {}
+#if OVERRIDE_CLASS
+- (void) instance_method {}
++ (void) class_method {}
+#endif
+@end
+
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+-(void) method1;
+@end
+
+@interface Foo(copycat)
+- (void) instance_method_fromcat;
++ (void) class_method_fromcat;
+@end
+
+@implementation Foo(copycat)
+- (void) instance_method_fromcat {}
++ (void) class_method_fromcat {}
+@end
+
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+-(void) instance_method;
++(void) class_method;
+@end
+
+
+@implementation Foo
+-(void) instance_method {}
++(void) class_method {}
+@end
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify -alias works with ObjC classes
+#
+CLASS_NAME_FOO = .objc_class_name_Foo
+ifeq (${ARCH},x86_64)
+ CLASS_NAME_FOO = '_OBJC_CLASS_$$_Foo'
+endif
+ifeq (${FILEARCH},arm)
+ CLASS_NAME_FOO = '_OBJC_CLASS_$$_Foo'
+endif
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.m -Wl,-alias,${CLASS_NAME_FOO},_MagicName -framework Foundation -o test
+ ${DYLDINFO} -export test | grep ${CLASS_NAME_FOO} | awk '{ print $$1}' > foo.addr
+ ${DYLDINFO} -export test | grep _MagicName | awk '{ print $$1}' > magic.addr
+ ${PASS_IFF} diff foo.addr magic.addr
+
+clean:
+ rm -rf test foo.addr magic.addr
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+@end
+
+@implementation Foo
+@end
+
+
+int main()
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Test that ObjC class exports can be suppressed
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -dynamiclib foo.m -framework Foundation -exported_symbols_list foo.exp -o libfoo.dylib
+ nm -m libfoo.dylib | grep Foo | grep ') external' | ${FAIL_IF_EMPTY}
+ nm -m libfoo.dylib | grep Bar | grep non-external | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+clean:
+ rm -rf *~ libfoo.dylib
--- /dev/null
+.objc_class_name_Foo
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+@end
+
+@implementation Foo
+@end
+
+
+
+@interface Bar : NSObject
+@end
+
+@implementation Bar
+@end
+
+
+
--- /dev/null
+##
+# Copyright (c) 2007-2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+IMAGE_INFO = "__image_info"
+
+ifeq ($(ARCH),x86_64)
+ IMAGE_INFO = "__objc_imageinfo"
+endif
+
+test: test-${FILEARCH}
+
+test-i386: test-macosx
+test-x86_64: test-macosx
+test-arm: test-good
+
+#
+# Validate that the linker catches illegal combinations of .o files
+# compiled with different GC settings.
+#
+
+test-macosx:
+ ${CC} ${CCFLAGS} foo.m -c -o foo.o
+ ${FAIL_IF_BAD_OBJ} foo.o
+
+ ${CC} ${CCFLAGS} foo.m -c -o foo-gc.o -fobjc-gc
+ ${FAIL_IF_BAD_OBJ} foo-gc.o
+
+ ${CC} ${CCFLAGS} foo.m -c -o foo-gc-only.o -fobjc-gc-only
+ ${FAIL_IF_BAD_OBJ} foo-gc-only.o
+
+ ${CC} ${CCFLAGS} bar.m -c -o bar.o
+ ${FAIL_IF_BAD_OBJ} bar.o
+
+ ${CC} ${CCFLAGS} bar.m -c -o bar-gc.o -fobjc-gc
+ ${FAIL_IF_BAD_OBJ} bar-gc.o
+
+ ${CC} ${CCFLAGS} bar.m -c -o bar-gc-only.o -fobjc-gc-only
+ ${FAIL_IF_BAD_OBJ} bar-gc-only.o
+
+ # check RR + RR -> RR
+ ${CC} ${CCFLAGS} foo.o bar.o runtime.c -dynamiclib -o libfoobar.dylib
+ ${FAIL_IF_BAD_MACHO} libfoobar.dylib
+
+ # check GC/RR + GC/RR -> GC/RR
+ ${CC} ${CCFLAGS} foo-gc.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib
+ ${FAIL_IF_BAD_MACHO} libfoobar.dylib
+ otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x2 | ${FAIL_IF_EMPTY}
+
+ # check GC + GC -> GC
+ ${CC} ${CCFLAGS} foo-gc-only.o bar-gc-only.o runtime.c -dynamiclib -o libfoobar.dylib
+ ${FAIL_IF_BAD_MACHO} libfoobar.dylib
+ otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x6 | ${FAIL_IF_EMPTY}
+
+ # check RR + GC/RR -> RR
+ ${CC} ${CCFLAGS} foo.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib
+ ${FAIL_IF_BAD_MACHO} libfoobar.dylib
+ otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x[26] | ${FAIL_IF_STDIN}
+
+ # check GC/RR + RR -> RR
+ ${CC} ${CCFLAGS} bar-gc.o foo.o runtime.c -dynamiclib -o libfoobar.dylib
+ ${FAIL_IF_BAD_MACHO} libfoobar.dylib
+ otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x[26] | ${FAIL_IF_STDIN}
+
+ # check GC + GC/RR -> GC
+ ${CC} ${CCFLAGS} foo-gc-only.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib
+ ${FAIL_IF_BAD_MACHO} libfoobar.dylib
+ otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x6 | ${FAIL_IF_EMPTY}
+
+ # check RR + GC -> error
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} foo.o bar-gc-only.o runtime.c -dynamiclib -o libfoobar.dylib 2> fail.log
+
+ # check cmd line GC/RR, GC/RR + RR -> error
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} foo-gc.o foo.o runtime.c -dynamiclib -o libfoobar.dylib -Wl,-objc_gc 2> fail.log
+
+ # check GC/RR + compaction
+ ${CC} ${CCFLAGS} foo-gc.o bar-gc.o runtime.c -dynamiclib -Wl,-objc_gc_compaction -o libfoobar.dylib
+ otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x12 | ${FAIL_IF_EMPTY}
+
+ # check GC + compaction
+ ${CC} ${CCFLAGS} foo-gc-only.o bar-gc-only.o runtime.c -dynamiclib -Wl,-objc_gc_compaction -o libfoobar.dylib
+ otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x16 | ${FAIL_IF_EMPTY}
+
+ # none + GC/RR-dylib -> none
+ ${CC} ${CCFLAGS} foo-gc.o runtime.c -dynamiclib -o libfoo.dylib
+ ${CC} ${CCFLAGS} none.c libfoo.dylib -dynamiclib -o libnone.dylib
+ size -l libnone.dylib | grep ${IMAGE_INFO} | ${FAIL_IF_STDIN}
+
+ # none + GC-dylib -> none
+ ${CC} ${CCFLAGS} foo-gc-only.o runtime.c -dynamiclib -o libfoo.dylib
+ ${CC} ${CCFLAGS} none.c libfoo.dylib -dynamiclib -o libnone.dylib
+ size -l libnone.dylib | grep ${IMAGE_INFO} | ${FAIL_IF_STDIN}
+
+ # none + RR-dylib -> none
+ ${CC} ${CCFLAGS} foo.o runtime.c -dynamiclib -o libfoo.dylib
+ ${CC} ${CCFLAGS} none.c libfoo.dylib -dynamiclib -o libnone.dylib
+ size -l libnone.dylib | grep ${IMAGE_INFO} | ${FAIL_IF_STDIN}
+
+ # check RR + GC-dylib -> error
+ ${CC} ${CCFLAGS} foo-gc-only.o runtime.c -dynamiclib -o libfoo.dylib
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bar.o runtime.c -dynamiclib libfoo.dylib -o libbar.dylib 2> fail.log
+
+ # check GC + RR-dylib -> error
+ ${CC} ${CCFLAGS} foo.o runtime.c -dynamiclib -o libfoo.dylib
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bar-gc-only.o runtime.c -dynamiclib libfoo.dylib -o libbar.dylib 2> fail.log
+
+ ${PASS_IFF} true
+
+test-good:
+ ${PASS_IFF} true
+
+clean:
+ rm -rf foo*.o bar*.o libfoobar.dylib fail.log libfoo.dylib libnone.dylib
--- /dev/null
+
+@interface Bar {
+ int f;
+}
+- (void) doit;
+@end
+
+@implementation Bar
+- (void) doit { }
+@end
+
--- /dev/null
+Validate that the linker catches illegal combintations of .o files compiled with different GC settings
--- /dev/null
+
+@interface Foo {
+ int f;
+}
+- (void) doit;
+@end
+
+
+@implementation Foo
+- (void) doit { }
+@end
+
--- /dev/null
+void none() {}
--- /dev/null
+void _objc_empty_cache() {}
+void _objc_empty_vtable() {}
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Verify an Objective-C object file when run through
+# ld -r -x
+# <rdar://problem/6605499> x86_64 obj-c runtime confused when static lib is stripped
+#
+#
+
+SELECTOR_REFS = "__OBJC,__message_refs"
+
+ifeq ($(ARCH),x86_64)
+ SELECTOR_REFS = "__DATA,__objc_selrefs"
+endif
+ifeq ($(ARCH),armv6)
+ SELECTOR_REFS = "__DATA,__objc_selrefs"
+endif
+
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.m -c -o test.o
+ ${OBJECTDUMP} -no_content test.o | grep -B3 -A6 ${SELECTOR_REFS} > test.dump
+
+ ${LD} -arch ${ARCH} -r test.o -x -o test-r.o
+ ${OBJECTDUMP} -no_content test-r.o | grep -B3 -A6 ${SELECTOR_REFS} > test-r.dump
+
+ diff test.dump test-r.dump | ${PASS_IFF_EMPTY}
+
+clean:
+ rm -rf test.o test.dump test-r.o test-r.dump
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+@interface Foo @end
+@implementation Foo
++(void)initialize { }
++(void)foo {
+ fprintf(stderr, "GOOD\n");
+ exit(0);
+}
++(void)bar {
+ fprintf(stderr, "BAD\n");
+ abort();
+}
+@end
+
+void PublicFunction(void)
+{
+ [Foo foo];
+ [Foo bar];
+}
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Verify an Objective-C object file when run through
+# ld -r is unaltered.
+# <rdar://problem/5680988> __cls_refs section losing S_LITERAL_POINTERS section type
+#
+# note: i386 and ppc objc use some anonymous zerofill that moves and needs to be ignore to compare
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.m -c -o test.o
+ ${OBJECTDUMP} -no_content test.o > test.dump
+
+ ${LD} -arch ${ARCH} -r test.o -keep_private_externs -o test-r.o
+ ${OBJECTDUMP} -no_content test-r.o > test-r.dump
+
+ diff test.dump test-r.dump | ${PASS_IFF_EMPTY}
+
+clean:
+ rm -rf test.o test.dump test-r.o test-r.dump
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <Foundation/Foundation.h>
+
+void test()
+{
+ // two class references
+ // two selector references
+ [NSObject superclass];
+ [NSString description];
+}
\ No newline at end of file
--- /dev/null
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Verify an Objective-C object file when run through ld -r is unaltered.
+#
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.m -dynamiclib -framework Foundation -o libtest.dylib
+ ${PASS_IFF_GOOD_MACHO} libtest.dylib
+
+clean:
+ rm -rf libtest.dylib
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <Foundation/Foundation.h>
+
+@interface Test
+{
+ BOOL one;
+ NSString* two;
+ BOOL three;
+}
+@property BOOL one;
+@property (retain) NSString* two;
+@property BOOL three;
+@end
+
+
+@implementation Test
+@synthesize one;
+@synthesize two;
+@synthesize three;
+@end
+
+
+int main()
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# The point of this test is to verify an Objective-C object file
+# is parsed to find the proper class references
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.m -c -o test.${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} test.${ARCH}.o
+
+ ${LD} -arch ${ARCH} -r test.${ARCH}.o -o test-r.${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} test-r.${ARCH}.o
+
+ nm test-r.${ARCH}.o | grep -i 'objc_class_.*_NSObject' | ${FAIL_IF_EMPTY}
+ nm test-r.${ARCH}.o | grep -i 'objc_class_.*_NSData' | ${FAIL_IF_EMPTY}
+ nm test-r.${ARCH}.o | grep -i 'objc_class_.*_NSArray' | ${FAIL_IF_EMPTY}
+ nm test-r.${ARCH}.o | grep -i 'objc_class_.*_NSString' | ${PASS_IFF_STDIN}
+
+clean:
+ rm -rf *.o *.dump
--- /dev/null
+The point of this test is to verify an Objective-C object file is parsed to find the proper class references
--- /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 <Foundation/Foundation.h>
+
+
+@interface Foo : NSObject
+- (NSString*) foo;
+@end
+
+
+@implementation Foo
+- (NSString*) foo
+{
+ return [NSString stringWithUTF8String:"hello"];
+}
+@end
+
+
+@interface Bar : NSData
+- (NSArray*) bar;
+@end
+
+
+@implementation Bar
+- (NSArray*) bar
+{
+ return [NSArray array];
+}
+@end
+
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Test that two ObjC translation units that use the same selector
+# link together.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.m other.m -o main -framework Foundation
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main
--- /dev/null
+#include <Foundation/Foundation.h>
+
+
+NSString* other()
+{
+ return [NSString stringWithUTF8String:"hello"];
+}
--- /dev/null
+
+#include <Foundation/Foundation.h>
+
+
+int main()
+{
+ [NSString stringWithUTF8String:"hello"];
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Tests when a hidden class is made file scoped (via ld -r)
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.m -c -o foo.o
+ ${CC} ${CCFLAGS} bar.m -c -o bar.o
+ ${CC} ${CCFLAGS} foo.o bar.o -dynamiclib -o libtfoobar.dylib -framework Foundation
+ ${LD} -r -arch ${ARCH} foo.o bar.o -o bar2.o
+ ${CC} ${CCFLAGS} bar2.o -dynamiclib -o liball.dylib -framework Foundation
+ ${PASS_IFF_GOOD_MACHO} liball.dylib
+
+clean:
+ rm -rf *.o *.dylib
--- /dev/null
+
+#include <Foundation/Foundation.h>
+
+__attribute__((visibility("hidden")))
+@interface Bar : NSData
+- (NSArray*) bar;
+@end
+
--- /dev/null
+#include <Foundation/Foundation.h>
+
+
+#include "bar.h"
+
+
+@implementation Bar
+- (NSArray*) bar
+{
+ return [NSArray array];
+}
+@end
+
--- /dev/null
+
+#include <Foundation/Foundation.h>
+
+
+@interface Foo : NSObject
+- (NSString*) foo;
+@end
+
--- /dev/null
+
+#include <Foundation/Foundation.h>
+
+#include "foo.h"
+#include "bar.h"
+
+@implementation Foo
+- (NSString*) foo
+{
+ [Bar alloc];
+ return [NSString stringWithUTF8String:"hello"];
+}
+@end
+
--- /dev/null
+##
+# Copyright (c) 2006-2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+run: all
+
+all:
+ # verify if operator new is overridden that WEAK_DEFINES is set
+ ${CXX} ${CXXFLAGS} -DOP_NEW -I${TESTROOT}/include -o main main.cxx
+ otool -hv main | grep WEAK_DEFINES | ${FAIL_IF_EMPTY}
+ # verify if operator new is overridden but not exported, WEAK_DEFINES is not set
+ ${CXX} ${CXXFLAGS} -DOP_NEW -I${TESTROOT}/include -o main main.cxx -Wl,-exported_symbol,_main
+ otool -hv main | grep WEAK_DEFINES | ${FAIL_IF_STDIN}
+ # verify if operator new is not overridden that WEAK_DEFINES is not set
+ ${CXX} ${CXXFLAGS} -I${TESTROOT}/include -o main main.cxx
+ otool -hv main | grep WEAK_DEFINES | ${PASS_IFF_EMPTY}
+
+
+clean:
+ ${RM} ${RMFLAGS} *~ main
+
--- /dev/null
+/*
+ * Copyright (c) 2006-2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h> // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+#include <stdlib.h>
+#include <new>
+
+
+//
+// This test case verifies overriding operator new sets the MH_WEAK_DEFINES bit
+//
+
+#if OP_NEW
+void* operator new(size_t s) throw (std::bad_alloc)
+{
+ return malloc(s);
+}
+#endif
+
+class Foo {
+ int a;
+ int b;
+public:
+ void print();
+};
+
+void Foo::print() {
+ printf("%d\n", a);
+}
+
+
+int main()
+{
+ Foo* f = new Foo();
+ f->print();
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2007-2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify that -order_file can be used to order symbols with anonymous name spaces
+#
+
+run: all
+
+all:
+ ${CXX} ${CXXFLAGS} main.cxx -o main -Wl,-order_file -Wl,main.order
+ ${FAIL_IF_BAD_MACHO} main
+ nm -n -j main | grep "_GLOBAL__N" > main.actual
+ ${PASS_IFF} diff main.actual main.expected
+
+
+clean:
+ rm -rf main main.actual
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+
+
+namespace {
+ struct myanonstruct { int a; };
+}
+
+// function defined in anonymous namespace
+namespace {
+ void foo() { }
+}
+
+// function that has an anonymous namespace parameter
+void bar(myanonstruct* x) { }
+
+
+// function in anonymous namespace that has an anonymous namespace parameter
+namespace {
+ void baz(myanonstruct* x) { }
+}
+
+// nested namespace
+namespace wow {
+ namespace {
+ void inner() { }
+ }
+}
+
+
+
+
+int main()
+{
+ wow::inner();
+ baz(NULL);
+ bar(NULL);
+ foo();
+ return 0;
+}
--- /dev/null
+__Z3barPN12_GLOBAL__N_112myanonstructE
+__ZN3wow12_GLOBAL__N_15innerEv
+__ZN12_GLOBAL__N_13bazEPNS_12myanonstructE
+__ZN12_GLOBAL__N_13fooEv
--- /dev/null
+__Z3barPN12_GLOBAL__N_112myanonstructE
+__ZN3wow12_GLOBAL__N_15innerEv
+__ZN12_GLOBAL__N_13bazEPNS_12myanonstructE
+__ZN12_GLOBAL__N_13fooEv
--- /dev/null
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that -order_file will transform zero-fill (tentative def)
+# symbols to __data symbols to achieve ordering.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c foo.c -Wl,-order_file,main.order -o main
+ nm -nj main | grep _xyz_ > main.actual
+ diff main.expected main.actual
+ nm -nm main | grep _xyz_f4 | grep __data | ${FAIL_IF_EMPTY}
+ nm -nm main | grep _other | grep __common | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -f main main.actual
--- /dev/null
+
+int xyz_f2;
+int xyz_f4;
+int other;
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+int xyz_m1;
+int xyz_m3;
+static int xyz_ms1;
+int xyz_mi3 = 4;
+int xyz_mi4 = 4;
+int main_common;
+
+
+int main()
+{
+ fprintf(stdout, "hello %p\n", &xyz_ms1);
+ return 0;
+}
--- /dev/null
+_xyz_f4
+_xyz_mi4
+_xyz_f2
+_xyz_m3
+_xyz_m1
+_xyz_ms1
+_xyz_mi3
--- /dev/null
+_xyz_f4
+_xyz_mi4
+_xyz_f2
+_xyz_m3
+_xyz_m1
+_xyz_ms1
+
--- /dev/null
+##
+# Copyright (c) 2006-2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check -order_file.
+# The main1 test verifies that C functions can be re-ordered
+# The main2 test verifies that a block of assembly is not moves en mas
+# The main1 test verifies that an order file with spaces and comments works
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c extra.s -o main1 -Wl,-order_file -Wl,main1.order
+ ${FAIL_IF_BAD_MACHO} main1
+ nm -n -g -j main1 | grep "_main" > main1.nm
+ ${PASS_IFF} diff main1.nm main1.expected
+
+ ${CC} ${CCFLAGS} main.c extra.s -o main2 -Wl,-order_file -Wl,main2.order
+ ${FAIL_IF_BAD_MACHO} main2
+ nm -n -j main2 | egrep '^_[a-z]+[0-9]$$' > main2.nm
+ ${PASS_IFF} diff main2.nm main2.expected
+
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ ${CC} ${CCFLAGS} main.o extra.s -o main3 -Wl,-order_file -Wl,main3.order
+ ${FAIL_IF_BAD_MACHO} main3
+ nm -n -g -j main3 | grep "_main" > main3.nm
+ ${PASS_IFF} diff main3.nm main3.expected
+
+ ${CC} ${CCFLAGS} main.c extra.s -DSUBSECTIONS=1 -o main4 -Wl,-order_file -Wl,main4.order
+ ${FAIL_IF_BAD_MACHO} main4
+ nm -n -g -j main4 | egrep '_[a-zA-Z]+[1-9]' > main4.nm
+ ${PASS_IFF} diff main4.nm main4.expected
+
+
+
+
+clean:
+ rm -rf main1 main2 main3 main4 main.o *.nm
--- /dev/null
+
+
+ .text
+ .align 4
+
+ .globl _foo1
+_foo1: nop
+
+ .globl _aaa2
+_aaa2:
+ .globl _bbb2
+ .private_extern _bbb2
+_bbb2:
+_ccc2:
+ nop
+
+ .globl _bbb3
+_aaa3:
+_bbb3:
+_ccc3:
+ nop
+
+
+_aaa4:
+ nop
+
+#if SUBSECTIONS
+ .subsections_via_symbols
+#endif
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+int main()
+{
+ return 0;
+}
+
+void main2() {}
+void main3() {}
+void main4() {}
--- /dev/null
+_main4
+_main3
+_main
+_main2
--- /dev/null
+_main4
+_main3
+
+
--- /dev/null
+_main3
+_foo1
+_aaa2
+_bbb2
+_ccc2
+_aaa3
+_bbb3
+_ccc3
+_aaa4
+_main4
+_main2
--- /dev/null
+_main3
+_aaa3
+_main4
+
+
+
--- /dev/null
+_main4
+_main3
+_main
+_main2
--- /dev/null
+
+# spaces before and after main4
+main.o: _main4
+#
+main.o: _main3# trailing comment
+#
+
+
--- /dev/null
+_aaa2
+_main3
+_main2
+_main4
+_foo1
+_bbb3
--- /dev/null
+
+
+_bbb2
+_main3
--- /dev/null
+##
+# Copyright (c) 2012 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Validate these pipelined linking cases:
+# - missing pipe
+# - bad file passed via pipe
+# - eof on pipe
+# - success case
+# - differing file orders produce same binary
+#
+# When testing the success case take care to verify that pipelined linking is actually
+# enabled (environment variable is set). Because there is no difference in the command
+# line the test will still succeed with pipelined linking turned off, without testing
+# pipelined linking.
+#
+
+all:
+ # Make some object files
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ ${CC} ${CCFLAGS} bar.c -c -o bar.o
+ ${CC} ${CCFLAGS} cat.c -c -o cat.o
+ ls *.o > filelist
+
+ # missing fifo
+ (LD_PIPELINE_FIFO=bad_fifo ; export LD_PIPELINE_FIFO ; ${CC} ${CCFLAGS} -filelist filelist -o partial ; exit 0) 2>&1 | ${PASS_IFF_STDIN}
+
+ # partial file list passed via pipe
+ head -1 filelist > pipelineFile
+ (LD_PIPELINE_FIFO=pipelineFile ; export LD_PIPELINE_FIFO ; ${CC} ${CCFLAGS} -filelist filelist -o partial ; exit 0) 2>&1 | ${PASS_IFF_STDIN}
+ ${FAIL_IFF} ${MACHOCHECK} partial 2>&1 > /dev/null
+
+ # bogus file passed via pipe
+ echo "bogus_file.o" > pipelineFile
+ (LD_PIPELINE_FIFO=pipelineFile ; export LD_PIPELINE_FIFO ; ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} -filelist filelist -o bogus ; exit 0) 2>&1 | ${PASS_IFF_STDIN}
+ ${FAIL_IFF} ${MACHOCHECK} bogus 2>&1 > /dev/null
+
+ # success cases - check different orderings of files
+ sort < filelist > pipelineFile
+ (LD_PIPELINE_FIFO=pipelineFile ; export LD_PIPELINE_FIFO ; ${CC} ${CCFLAGS} -filelist filelist -o normal)
+ ${FAIL_IF_BAD_MACHO} normal
+ sort -r < filelist > pipelineFile
+ (LD_PIPELINE_FIFO=pipelineFile ; export LD_PIPELINE_FIFO ; ${CC} ${CCFLAGS} -filelist filelist -o reverse)
+ ${FAIL_IF_BAD_MACHO} reverse
+
+ # verify that the same binary was generated using both forward and reverse ordering
+ ${PASS_IFF} cmp reverse normal
+
+
+clean:
+ rm -f *.o filelist partial bogus reverse normal pipelineFile
+
--- /dev/null
+void bar()
+{
+}
+
--- /dev/null
+void cat()
+{
+}
+
--- /dev/null
+
+void foo()
+{
+}
+
+int main()
+{
+return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# The point of this test is to build a prebound split-seg library
+#
+
+all: all-${ARCH}
+
+all-i386: all-32
+all-ppc: all-32
+all-x86_64: all-good
+all-armv6: all-good
+all-armv7: all-good
+
+
+all-good:
+ ${PASS_IFF} true
+
+
+all-32:
+ ${CC} ${CCFLAGS} -seg_addr_table address_table -prebind bar.c -dynamiclib -o libbar.dylib -install_name /foo/bar/libbar.dylib
+ ${PASS_IFF_GOOD_MACHO} libbar.dylib
+
+clean:
+ rm -rf *.dylib
--- /dev/null
+# comment
+0x91000000 0xA1000000 /foo/bar/libbar.dylib
+#
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+int x = 3;
+int* xp = &x;
+
+
+int bar()
+{
+ return *xp;
+}
+
+void* pbar = &bar;
+
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to check that a non-lazy-pointer
+# in foo.o to a private-extern symbol in bar.o will
+# properly survive ld -r
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -c foo.c -o foo.o
+ ${FAIL_IF_BAD_OBJ} foo.o
+
+ ${CC} ${CCFLAGS} -c bar.c -o bar.o
+ ${FAIL_IF_BAD_OBJ} bar.o
+
+ ${LD} -r foo.o bar.o -o foobar.o -arch ${ARCH}
+ ${FAIL_IF_BAD_OBJ} foobar.o
+
+ ${CC} ${CCFLAGS} hello.c foobar.o -o hello
+ ${FAIL_IF_BAD_MACHO} hello
+
+ ${LD} -r foo.o bar.o -o foobar2.o -arch ${ARCH} -keep_private_externs
+ ${FAIL_IF_BAD_OBJ} foobar2.o
+
+ ${CC} ${CCFLAGS} hello.c foobar2.o -o hello2
+ ${PASS_IFF_GOOD_MACHO} hello2
+
+clean:
+ rm -rf *.o hello hello2
--- /dev/null
+
+int __attribute__((visibility("hidden"))) foo = 0;
+
--- /dev/null
+The point of this test is to check that a non-lazy-pointer in foo.o to a private-extern symbol in bar.o will properly survive ld -r
--- /dev/null
+
+
+extern int foo;
+
+int getfoo() { return foo; }
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+extern int getfoo();
+
+int main()
+{
+ return getfoo();
+}
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that a public re-exported library is automatically added as a dependent
+# unless nothing is used from it.
+#
+
+
+run: all
+
+all:
+
+ ${CC} ${CCFLAGS} -dynamiclib pub.c -o libpub.dylib -install_name /usr/lib/libpub.dylib
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib
+ # verify uses of symbols from re-exported dylibs have ordinal that allows dyld to search amoung re-exported dylibs
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -DUSE_BAZ -o libfoo2.dylib -Wl,-reexport_library libpub.dylib -Wl,-reexport_library libbar.dylib -Wl,-reexport_library libbaz.dylib
+ ${DYLDINFO} -bind libfoo2.dylib | grep _bar | grep this-image | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -lazy_bind libfoo2.dylib | grep _bar | grep this-image | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -bind libfoo2.dylib | grep _baz | grep this-image | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -lazy_bind libfoo2.dylib | grep _baz | grep this-image | ${FAIL_IF_EMPTY}
+ # verify that if only one non-publc re-exported dylib, don't use magic ordinal
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo1.dylib -Wl,-reexport_library libpub.dylib -Wl,-reexport_library libbar.dylib
+ ${DYLDINFO} -bind libfoo1.dylib | grep _bar | grep this-image | ${FAIL_IF_STDIN}
+ ${DYLDINFO} -lazy_bind libfoo1.dylib | grep _bar | grep this-image | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} libfoo2.dylib
+
+
+clean:
+
+ rm -rf libbar.dylib libbaz.dylib libpub.dylib libfoo1.dylib libfoo2.dylib
--- /dev/null
+
+int bar()
+{
+ return 1;
+}
--- /dev/null
+
+int baz()
+{
+ return 1;
+}
--- /dev/null
+extern int bar();
+extern int baz();
+
+void* pbar = &bar;
+
+#if USE_BAZ
+void* pbaz = &baz;
+#endif
+
+int foo()
+{
+#if USE_BAZ
+ baz();
+#endif
+ return bar();
+}
--- /dev/null
+
+int pub()
+{
+ return 1;
+}
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test all the different ways that re-exports can be specified and implemented
+#
+
+
+all: all-${ARCH}
+
+all-i386: all-new all-old
+all-x86_64: all-new all-old
+all-armv6: all-new
+all-armv7: all-new
+
+
+all-new:
+ # -sub_library for 10.5
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib ${VERSION_NEW_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lbar -L. -sub_library libbar ${VERSION_NEW_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
+ otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_STDIN}
+
+ # -sub_umbrella for 10.5
+ mkdir -p Bar.framework Foo.framework
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" ${VERSION_NEW_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -framework Bar -sub_umbrella Bar ${VERSION_NEW_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
+ otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
+ otool -lv Foo.framework/Foo | grep LC_SUB_UMBRELLA | ${FAIL_IF_STDIN}
+
+ # -umbrella for 10.5
+ mkdir -p Bar.framework Foo.framework
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" -umbrella Foo ${VERSION_NEW_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -framework Bar ${VERSION_NEW_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
+ otool -lv Bar.framework/Bar | grep LC_SUB_FRAMEWORK | ${FAIL_IF_EMPTY}
+ otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
+
+ # -reexport_library for 10.5
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib ${VERSION_NEW_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport_library,libbar.dylib ${VERSION_NEW_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
+ otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_STDIN}
+
+ # -reexport-l for 10.5
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib ${VERSION_NEW_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport-lbar -L. ${VERSION_NEW_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
+ otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_STDIN}
+
+ # -reexport_framework for 10.5
+ mkdir -p Bar.framework Foo.framework
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" ${VERSION_NEW_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -Wl,-reexport_framework,Bar ${VERSION_NEW_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
+ otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
+ otool -lv Foo.framework/Foo | grep LC_SUB_UMBRELLA | ${FAIL_IF_STDIN}
+
+ # -reexport_framework and -umbrella for 10.4
+ mkdir -p Bar.framework Foo.framework
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" -umbrella Foo ${VERSION_NEW_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -Wl,-reexport_framework,Bar ${VERSION_NEW_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
+ otool -lv Bar.framework/Bar | grep LC_SUB_FRAMEWORK | ${FAIL_IF_EMPTY}
+ otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_EMPTY}
+
+ ${PASS_IFF} /usr/bin/true
+
+
+
+all-old:
+ # -sub_library for 10.4
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib ${VERSION_OLD_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lbar -L. -sub_library libbar ${VERSION_OLD_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_EMPTY}
+ otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
+
+ # -sub_umbrella for 10.4
+ mkdir -p Bar.framework Foo.framework
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" ${VERSION_OLD_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -framework Bar -sub_umbrella Bar ${VERSION_OLD_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
+ otool -lv Foo.framework/Foo | grep LC_SUB_UMBRELLA | ${FAIL_IF_EMPTY}
+ otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
+
+ # -umbrella for 10.4
+ mkdir -p Bar.framework Foo.framework
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" -umbrella Foo ${VERSION_OLD_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -framework Bar ${VERSION_OLD_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
+ otool -lv Bar.framework/Bar | grep LC_SUB_FRAMEWORK | ${FAIL_IF_EMPTY}
+ otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
+
+ # -reexport_library for 10.4
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib ${VERSION_OLD_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport_library,libbar.dylib ${VERSION_OLD_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_EMPTY}
+ otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
+
+ # -reexport-l for 10.4
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib ${VERSION_OLD_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport-lbar -L. ${VERSION_OLD_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ otool -lv libfoo.dylib | grep LC_SUB_LIBRARY | ${FAIL_IF_EMPTY}
+ otool -lv libfoo.dylib | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
+
+ # -reexport_framework for 10.4
+ mkdir -p Bar.framework Foo.framework
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" ${VERSION_OLD_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -Wl,-reexport_framework,Bar ${VERSION_OLD_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
+ otool -lv Foo.framework/Foo | grep LC_SUB_UMBRELLA | ${FAIL_IF_EMPTY}
+ otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
+
+ # -reexport_framework and -umbrella for 10.4
+ mkdir -p Bar.framework Foo.framework
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o Bar.framework/Bar -install_name "`pwd`/Bar.framework/Bar" -umbrella Foo ${VERSION_OLD_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Bar.framework/Bar
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o Foo.framework/Foo -F. -Wl,-reexport_framework,Bar ${VERSION_OLD_LINKEDIT}
+ ${FAIL_IF_BAD_MACHO} Foo.framework/Foo
+ otool -lv Bar.framework/Bar | grep LC_SUB_FRAMEWORK | ${FAIL_IF_EMPTY}
+ otool -lv Foo.framework/Foo | grep LC_REEXPORT_DYLIB | ${FAIL_IF_STDIN}
+
+ ${PASS_IFF} /usr/bin/true
+
+
+clean:
+
+ rm -rf hide libbar.dylib libfoo.dylib Foo.framework Bar.framework
--- /dev/null
+
+int bar (void)
+{
+ return 1;
+}
--- /dev/null
+
+int baz (void)
+{
+ return 1;
+}
--- /dev/null
+int foo (void)
+{
+ return 1;
+}
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that the MH_NO_REEXPORTED_DYLIBS bit is set in dylibs with no re-exports
+#
+
+run: all
+
+all:
+# build base library
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o `pwd`/libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+
+# build library the re-exports base library
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib -sub_library libbar
+# test that foo does not have MH_NO_REEXPORTED_DYLIBS bit
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+# build libray that links with base but does not re-export it
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo2.dylib libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ otool -hv libfoo2.dylib | grep NO_REEXPORTED_DYLIBS | ${PASS_IFF_STDIN}
+
+clean:
+ rm -rf *.dylib
--- /dev/null
+
+int bar(void)
+{
+ return 1;
+}
--- /dev/null
+int foo(void)
+{
+ return 1;
+}
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test all the different ways that re-exports can be specified and implemented
+#
+
+
+
+all: all-${ARCH}
+
+all-i386: all-new all-old
+all-x86_64: all-new all-old
+all-armv6: all-new
+all-armv7: all-new
+
+
+all-new:
+ # -reexport_library for 10.5 and later
+ ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib
+ ${FAIL_IF_BAD_MACHO} libbaz.dylib
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -Wl,-reexport_library,libbaz.dylib
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport_library,libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
+ ${PASS_IFF_GOOD_MACHO} main
+
+all-old:
+ # -reexport_library for 10.4
+ ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib -mmacosx-version-min=10.4
+ ${FAIL_IF_BAD_MACHO} libbaz.dylib
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -Wl,-reexport_library,libbaz.dylib -mmacosx-version-min=10.4
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport_library,libbar.dylib -mmacosx-version-min=10.4
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
+ ${FAIL_IF_BAD_MACHO} main
+
+
+
+clean:
+
+ rm -rf libbaz.dylib libbar.dylib libfoo.dylib main
+
--- /dev/null
+
+int bar (void)
+{
+ return 1;
+}
--- /dev/null
+
+int baz (void)
+{
+ return 1;
+}
--- /dev/null
+int foo (void)
+{
+ return 1;
+}
--- /dev/null
+
+
+extern void baz();
+extern void bar();
+extern void foo();
+
+
+int main()
+{
+ baz();
+ bar();
+ foo();
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that a public re-exported library is automatically added as a dependent
+# unless nothing is used from it.
+#
+
+
+all: all-${ARCH}
+
+all-i386: all-new all-old
+all-x86_64: all-new all-old
+all-armv6: all-new
+all-armv7: all-new
+
+all-old:
+ # -sub_library for 10.4
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -install_name /usr/lib/libbar.dylib -mmacosx-version-min=10.4
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib middle.c -o libmiddle.dylib -lbar -L. -sub_library libbar -install_name /mid/libmiddle.dylib -mmacosx-version-min=10.4
+ ${FAIL_IF_BAD_MACHO} libmiddle.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lmiddle -L. -sub_library libmiddle -install_name /usr/lib/libfoo.dylib -mmacosx-version-min=10.4
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ ${CC} ${CCFLAGS} -dynamiclib other.c -o libother.dylib -lbar -L. -sub_library libbar -install_name /usr/lib/libother.dylib -mmacosx-version-min=10.4
+ ${FAIL_IF_BAD_MACHO} libother.dylib
+ ${CC} ${CCFLAGS} main.c -DCALL_BAR libfoo.dylib libother.dylib -o main -L. -mmacosx-version-min=10.4
+ nm -m main | grep _bar | grep libbar | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+all-new:
+ # -sub_library for 10.5
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -install_name /usr/lib/libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib middle.c -o libmiddle.dylib -lbar -L. -sub_library libbar -install_name /mid/libmiddle.dylib
+ ${FAIL_IF_BAD_MACHO} libmiddle.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lmiddle -L. -sub_library libmiddle -install_name /usr/lib/libfoo.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ ${CC} ${CCFLAGS} -dynamiclib other.c -o libother.dylib -lbar -L. -sub_library libbar -install_name /usr/lib/libother.dylib
+ ${FAIL_IF_BAD_MACHO} libother.dylib
+ ${CC} ${CCFLAGS} main.c -DCALL_BAR libfoo.dylib libother.dylib -o main -L.
+ nm -m main | grep _bar | grep libbar | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+ rm -rf libbar.dylib libfoo.dylib libmiddle.dylib libother.dylib main
--- /dev/null
+
+int bar (void)
+{
+ return 1;
+}
--- /dev/null
+int foo (void)
+{
+ return 1;
+}
--- /dev/null
+
+extern void bar();
+
+int main()
+{
+ bar();
+ return 0;
+}
--- /dev/null
+
+void middle() {}
+
--- /dev/null
+void other() {}
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that a public re-exported library is automatically added as a dependent
+# unless nothing is used from it.
+#
+
+
+
+all: all-${ARCH}
+
+all-i386: all-new all-old
+all-x86_64: all-new all-old
+all-armv6: all-new
+all-armv7: all-new
+
+
+all-old:
+ # -sub_library for 10.4
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -install_name /usr/lib/libbar.dylib -mmacosx-version-min=10.4
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lbar -L. -sub_library libbar -mmacosx-version-min=10.4
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ ${CC} ${CCFLAGS} main.c -DCALL_BAR libfoo.dylib -o main -L. -mmacosx-version-min=10.4
+ otool -L main | grep libbar | ${FAIL_IF_EMPTY}
+ nm -m main | grep _bar | grep libbar | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -L. -mmacosx-version-min=10.4
+ otool -L main | grep libbar | ${FAIL_IF_STDIN}
+
+
+all-new:
+ # -sub_library for 10.5
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -install_name /usr/lib/libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lbar -L. -sub_library libbar
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ ${CC} ${CCFLAGS} main.c -DCALL_BAR libfoo.dylib -o main -L.
+ otool -L main | grep libbar | ${FAIL_IF_EMPTY}
+ nm -m main | grep _bar | grep libbar | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -L.
+ otool -L main | grep libbar | ${FAIL_IF_STDIN}
+
+
+ ${PASS_IFF} /usr/bin/true
+
+
+clean:
+
+ rm -rf libbar.dylib libfoo.dylib main
--- /dev/null
+
+int bar (void)
+{
+ return 1;
+}
--- /dev/null
+int foo (void)
+{
+ return 1;
+}
--- /dev/null
+
+extern void bar();
+
+int main()
+{
+#if CALL_BAR
+ bar();
+#endif
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that @loader_path and @executable_path can be resolved finding indirect dylibs
+#
+
+
+run: all
+
+all:
+ mkdir -p hide
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -install_name '@loader_path/libfoo.dylib' -o hide/libfoo.dylib
+ ${FAIL_IF_BAD_MACHO} hide/libfoo.dylib
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o hide/libbar.dylib -install_name '@executable_path/hide/libbar.dylib'
+ ${FAIL_IF_BAD_MACHO} hide/libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib wrap.c -o hide/libwrap.dylib -Wl,-reexport-lfoo -Wl,-reexport-lbar -Lhide
+ ${FAIL_IF_BAD_MACHO} hide/libwrap.dylib
+ ${CC} ${CCFLAGS} main.c -o main hide/libwrap.dylib
+ ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain.dylib hide/libwrap.dylib -Wl,-executable_path,`pwd`/main
+ ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain.dylib hide/libwrap.dylib -Wl,-executable_path,`pwd`
+ ${PASS_IFF} /usr/bin/true
+
+
+clean:
+
+ rm -rf hide libbar.dylib libfoo.dylib libwrap.dylib main libmain.dylib
--- /dev/null
+
+int bar (void)
+{
+ return 1;
+}
--- /dev/null
+int foo (void)
+{
+ return 1;
+}
--- /dev/null
+extern int foo();
+extern int bar();
+extern int wrap();
+
+int main()
+{
+ foo();
+ bar();
+ wrap();
+ return 0;
+}
--- /dev/null
+int wrap() { return 0; }
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that fine grain re-exports works
+#
+
+run: all
+
+all:
+ # build base library
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o `pwd`/libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+
+ # build library the re-exports _bar from base library
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib -exported_symbols_list foo.exp
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ ${DYLDINFO} -export libfoo.dylib | grep _bar | grep 're-export' | ${FAIL_IF_EMPTY}
+ # link against dylib and verify _bar is marked as coming from libfoo
+ ${CC} ${CCFLAGS} main1.c libfoo.dylib -o main1
+ ${DYLDINFO} -bind -lazy_bind main1 | grep _bar | grep libfoo | ${FAIL_IF_EMPTY}
+
+ # build library the re-exports _bar from base library as _mybar
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo2.dylib libbar.dylib -Wl,-alias,_bar,_mybar -exported_symbols_list foo2.exp
+ ${FAIL_IF_BAD_MACHO} libfoo2.dylib
+ ${DYLDINFO} -export libfoo2.dylib | grep _mybar | grep 're-export' | grep _bar | ${FAIL_IF_EMPTY}
+ # link against dylib and verify _mybar is marked as coming from libfoo
+ ${CC} ${CCFLAGS} main2.c libfoo2.dylib -o main2
+ ${DYLDINFO} -bind -lazy_bind main2 | grep _mybar | grep libfoo2 | ${FAIL_IF_EMPTY}
+
+ ${PASS_IFF_GOOD_MACHO} libfoo2.dylib
+
+clean:
+ rm -rf libbar.dylib libfoo.dylib libfoo2.dylib main1 main2
--- /dev/null
+
+int bar(void)
+{
+ return 1;
+}
--- /dev/null
+int foo(void)
+{
+ return 1;
+}
--- /dev/null
+_foo
+_bar
--- /dev/null
+_foo
+_mybar
--- /dev/null
+extern int foo();
+extern int bar();
+
+int main()
+{
+ foo();
+ bar();
+ return 0;
+}
--- /dev/null
+extern int foo();
+extern int mybar();
+
+int main()
+{
+ foo();
+ mybar();
+ return 0;
+}
+
--- /dev/null
+ ##
+# Copyright (c) 2006-2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that ld can linke a dylib built with -mdynamic-no-pic
+#
+
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+NO_PIC =
+STATIC =
+RELOC_FAIL = ${FAIL_IF_SUCCESS}
+LRELOCS_NEEDED = ${FAIL_IF_EMPTY}
+XRELOCS_NEEDED = ${FAIL_IF_EMPTY}
+
+ifeq (${ARCH},i386)
+ NO_PIC = -mdynamic-no-pic
+ STATIC = -static
+endif
+ifeq (${ARCH},ppc)
+ NO_PIC = -mdynamic-no-pic
+ STATIC = -mdynamic-no-pic
+ XRELOCS_NEEDED = ${FAIL_IF_STDIN}
+ LRELOCS_NEEDED = ${FAIL_IF_EMPTY}
+endif
+ifeq (${ARCH},x86_64)
+ RELOC_FAIL =
+ XRELOCS_NEEDED = ${FAIL_IF_STDIN}
+ LRELOCS_NEEDED = ${FAIL_IF_STDIN}
+endif
+ifeq (${FILEARCH},arm)
+ NO_PIC = -mdynamic-no-pic
+ STATIC = -static
+endif
+
+
+
+all:
+ # build libfoo.dylib as regular dylib
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+ # build libtest.dylib using -mdynamic-no-pic, should fail
+ ${CC} ${CCFLAGS} test_rebase.c -c ${NO_PIC}
+ ${RELOC_FAIL} ${CC} ${CCFLAGS} test_rebase.o libfoo.dylib -dynamiclib -o libtestrebase.dylib -read_only_relocs error 2>/dev/null
+ ${CC} ${CCFLAGS} test_bind.c -c ${NO_PIC}
+ ${RELOC_FAIL} ${CC} ${CCFLAGS} test_bind.o libfoo.dylib -dynamiclib -o libtestbind.dylib -read_only_relocs error 2>/dev/null
+ # build libtest.dylib using -mdynamic-no-pic and -read_only_relocs suppress
+ ${CC} ${CCFLAGS} test_rebase.c -c ${NO_PIC}
+ ${CC} ${CCFLAGS} test_bind.c -c ${NO_PIC}
+ ${CC} ${CCFLAGS} test_rebase.o test_bind.o libfoo.dylib -dynamiclib -o libtest-no-pic.dylib -read_only_relocs suppress -Wl,-w
+ # build libtest.dylib using -static and -read_only_relocs suppress
+ ${CC} ${CCFLAGS} test_rebase.c -c ${STATIC}
+ ${CC} ${CCFLAGS} test_bind.c -c ${STATIC}
+ ${CC} ${CCFLAGS} test_rebase.o test_bind.o libfoo.dylib -dynamiclib -o libtest-static.dylib -read_only_relocs suppress -Wl,-w
+ otool -lv libtest-static.dylib | grep -A9 "sectname __text" | grep attributes | grep EXT_RELOC | ${XRELOCS_NEEDED}
+ otool -lv libtest-static.dylib | grep -A9 "sectname __text" | grep attributes | grep LOC_RELOC | ${LRELOCS_NEEDED}
+ # build main using -static and -read_only_relocs suppress
+ ${CC} ${CCFLAGS} main.c -c ${STATIC}
+ ${CC} ${CCFLAGS} main.o libfoo.dylib -o main -read_only_relocs suppress -Wl,-w
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf test_bind.o test_rebase.o libfoo.dylib libtestrebase.dylib libtestbind.dylib libtest-no-pic.dylib libtest-static.dylib main.o main
--- /dev/null
+
+int b=0;
+
+void func() {}
+
+
--- /dev/null
+
+extern int b;
+extern void func();
+
+int main()
+{
+ func();
+ return b;
+}
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+int a=0;
+extern int b;
+extern void func();
+
+int main()
+{
+ func();
+ return a+b;
+}
+
--- /dev/null
+
+extern int b;
+extern void func();
+
+int test_bind()
+{
+ func();
+ return b;
+}
+
--- /dev/null
+
+int a=0;
+
+int test_rebase()
+{
+ return a;
+}
+
--- /dev/null
+##
+# Copyright (c) 2006-2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to see that a dylib
+# run through the rebase tool is the same as if
+# the dylib was originally built at that address
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -c -g foo.c -o foo.${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} foo.${ARCH}.o
+
+ ${CC} ${CCFLAGS} -c -g bar.m -o bar.${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} bar.${ARCH}.o
+
+ ${CC} ${CCFLAGS} foo.${ARCH}.o bar.${ARCH}.o -dynamiclib -Wl,-no_uuid -Wl,-no_order_data -o libfoo.${ARCH}.dylib -framework Foundation -framework CoreFoundation
+ ${FAIL_IF_BAD_MACHO} libfoo.${ARCH}.dylib
+
+ ${CC} ${CCFLAGS} foo.${ARCH}.o bar.${ARCH}.o -dynamiclib -Wl,-no_uuid -Wl,-no_order_data -o libfoo-alt.${ARCH}.dylib -framework Foundation -framework CoreFoundation -seg1addr 0x12340000 -install_name libfoo.${ARCH}.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo-alt.${ARCH}.dylib
+
+ ${REBASE} -arch ${ARCH} -low_address 0x12340000 libfoo.${ARCH}.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo.${ARCH}.dylib
+
+ ${PASS_IFF} diff libfoo.${ARCH}.dylib libfoo-alt.${ARCH}.dylib
+
+clean:
+ rm -f *.o *.dylib
--- /dev/null
+#include <Foundation/Foundation.h>
+
+@interface Bar : NSObject
+
+-(void) blah;
+
+@end
+
+@implementation Bar
+
+-(void) blah {}
+
+@end
\ No newline at end of file
--- /dev/null
+The point of this test is to see that a dylib run through the rebase tool is the same as if the dylib was originally built at that address
--- /dev/null
+
+int foo() { return 10; }
+
+void* foop = &foo;
+
+int glob = 5;
+
+int* globp = &glob;
+
+
+int big[3000];
+
+
+
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Test -reexport_symbols_list
+#
+
+run: all
+
+all:
+ # build base library
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o `pwd`/libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+
+ # verify re-export fails with -bundle
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} -bundle foo.c -o libfoo.bundle libbar.dylib -Wl,-reexported_symbols_list,bart.exp 2>/dev/null
+
+ # verify failure if re-exported symbol does not exist
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib -Wl,-reexported_symbols_list,junk.exp 2>/dev/null
+
+ # verify failure if re-exported symbol is from .o file
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib -Wl,-reexported_symbols_list,foo.exp 2>/dev/null
+
+ # build library the re-exports _bart from base library
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib -Wl,-reexported_symbols_list,bart.exp
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ ${DYLDINFO} -export libfoo.dylib | grep _barb | ${FAIL_IF_STDIN}
+ ${DYLDINFO} -export libfoo.dylib | grep _bart | grep 're-export' | ${FAIL_IF_EMPTY}
+
+ # link against dylib and verify _bart is marked as coming from libfoo
+ ${CC} ${CCFLAGS} main1.c libfoo.dylib -o main1
+ ${DYLDINFO} -bind -lazy_bind main1 | grep _bart | grep libfoo | ${FAIL_IF_EMPTY}
+
+ ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+clean:
+ rm -rf libbar.dylib libfoo.dylib main1
--- /dev/null
+
+int barb(void)
+{
+ return 1;
+}
+
+int bart(void)
+{
+ return 0;
+}
--- /dev/null
+int foo(void)
+{
+ return 1;
+}
--- /dev/null
+extern int foo();
+extern int bart();
+
+int main()
+{
+ foo();
+ bart();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to verify a .o file can round-trip
+# through ld -r correctly. The ObjectDump utility is used
+# dump a "canonical" textual representation of a .o file.
+# The before and after .o files are then diff'ed.
+# No differences means this test passes
+#
+
+run: all
+
+all:
+ ${CC} ${ASMFLAGS} relocs-asm.s -c -o relocs-asm.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content relocs-asm.${ARCH}.o > relocs-asm.${ARCH}.o.dump
+
+ ${LD} -arch ${ARCH} -r -keep_private_externs relocs-asm.${ARCH}.o -o relocs-asm-r.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content relocs-asm-r.${ARCH}.o > relocs-asm-r.${ARCH}.o.dump
+
+ ${PASS_IFF} diff relocs-asm.${ARCH}.o.dump relocs-asm-r.${ARCH}.o.dump
+
+clean:
+ rm -rf *.o *.dump
--- /dev/null
+The point of this test is to verify a .o file can round-trip through ld -r correctly. The ObjectDump utility is used
+dump a "canonical" textual representation of a .o file. The before and after .o files are then diff'ed.
+No differences means this test passes
--- /dev/null
+/*
+ * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+
+#if __arm__
+ .text
+ .align 2
+
+ .globl _test_loads
+_test_loads:
+ @ PIC load of a
+ ldr r0, L100
+L0:
+ ldr r0, [pc, r0]
+
+ @ PIC load of c
+ ldr r0, L100+4
+L1:
+ ldr r0, [pc, r0]
+
+ @ sorta-absolute load of a
+ ldr r0, L100+8
+ ldr r0, [r0, #0]
+
+ @ sorta-absolute load of c
+ ldr r0, L100+12
+ ldr r0, [r0, #0]
+
+ @ sorta-absolute load of external
+ ldr r0, L100+16
+ ldr r0, [r0, #0]
+
+ @ PIC load of a + addend ??
+ bx lr
+
+L100:
+ .long _a-(L0+8)
+ .long _c-(L1+8)
+ .long _a
+ .long _c
+ .long _ax
+
+_test_calls:
+ @ call internal
+ bl _test_branches
+
+ @ call internal + addend
+ bl _test_branches+0x19000
+
+ @ call external
+ bl _external
+
+ @ call external + addend
+ bl _external+0x19000
+
+
+_test_branches:
+ @ call internal
+ bne _test_calls
+
+ @ call internal + addend
+ bne _test_calls+16
+
+ @ call internal - addend
+ bne _test_calls-16
+
+ @ call external
+ bne _external
+
+ @ call external + addend
+ bne _external+16
+
+ nop
+ bl 1f
+1: nop
+
+
+ .globl _test_weak
+ .weak_definition _test_weak
+_test_weak:
+ nop
+ nop
+
+ .globl _test_hidden_weak
+ .private_extern _test_hidden_weak
+ .weak_definition _test_hidden_weak
+_test_hidden_weak:
+ nop
+ nop
+
+
+_test_weak_call:
+ bl _test_weak
+ bl _test_weak+4
+
+
+_test_weak_hidden_pointer_call:
+ ldr r12,L3
+ add r12, pc, r12
+ nop
+ bx r12
+L101:
+ .long _test_hidden_weak - L101
+
+
+ .text
+_pointer_diffs:
+1: .long _foo-1b
+ .long _foo+10-1b
+ .long _test_branches-1b
+ .long _test_branches+3-1b
+ .long (_test_branches - _test_loads) + -2097152
+ .long (_test_calls - _test_loads) + -2097152
+
+
+ .text
+ .code 32
+_arm1:
+ bx lr
+_arm2:
+ bx lr
+ .weak_definition _arm3
+ .globl _arm3
+ .private_extern _arm3
+_arm3:
+ bx lr
+ .weak_definition _arm4
+ .globl _arm4
+ .private_extern _arm4
+_arm4:
+ bx lr
+
+ .code 16
+ .thumb_func _thumb1
+_thumb1:
+ bx lr
+ .thumb_func _thumb2
+_thumb2:
+ bx lr
+ .weak_definition _thumb3
+ .globl _thumb3
+ .private_extern _thumb3
+ .thumb_func _thumb3
+_thumb3:
+ bx lr
+ .weak_definition _thumb4
+ .globl _thumb4
+ .private_extern _thumb4
+ .thumb_func _thumb4
+_thumb4:
+ bx lr
+
+ .thumb_func _thumb_func_ref_test
+_thumb_func_ref_test:
+ push {r7, lr}
+ add r7, sp, #0
+ ldr r3, L6
+L2: add r3, pc
+ ldr r3, L7
+L3: add r3, pc
+ ldr r3, L8
+L4: add r3, pc
+ ldr r3, L9
+L5: add r3, pc
+ pop {r7, pc}
+ .align 2
+L6: .long _thumb1-(L2+4)
+L7: .long _thumb2-(L3+4)
+L7a:.long _thumb3-(L3+4)
+L7b:.long _thumb4-(L3+4)
+L8: .long _arm1-(L4+4)
+L9: .long _arm2-(L5+4)
+L9a:.long _arm3-(L5+4)
+L9b:.long _arm4-(L5+4)
+
+ .code 32
+ .align 2
+_arm_func_ref_test:
+ push {r7, lr}
+ add r7, sp, #0
+ ldr r3, L16
+L12:add r3, pc
+ ldr r3, L17
+L13:add r3, pc
+ ldr r3, L18
+L14:add r3, pc
+ ldr r3, L19
+L15:add r3, pc
+ pop {r7, pc}
+ .align 2
+L16: .long _thumb1-(L12+8)
+L17: .long _thumb2-(L13+8)
+L17a: .long _thumb3-(L13+8)
+L17b: .long _thumb4-(L13+8)
+L18: .long _arm1-(L14+8)
+L19: .long _arm2-(L15+8)
+L19a: .long _arm3-(L15+8)
+L19b: .long _arm4-(L15+8)
+
+ .section __DATA,__const
+_myVTable:
+ .long _thumb1
+ .long _thumb2
+ .long _thumb3
+ .long _arm1
+ .long _arm2
+
+#if __ARM_ARCH_7A__
+ .text
+ .align 2
+_arm16tests:
+ movw r0, :lower16:_datahilo16
+ movt r0, :upper16:_datahilo16
+ movw r0, :lower16:_datahilo16+4
+ movt r0, :upper16:_datahilo16+4
+ movw r0, :lower16:_datahilo16alt
+ movt r0, :upper16:_datahilo16alt
+ movw r0, :lower16:_datahilo16alt+61440
+ movt r0, :upper16:_datahilo16alt+61440
+ movw r0, :lower16:_datahilo16alt+2048
+ movt r0, :upper16:_datahilo16alt+2048
+ movw r0, :lower16:_datahilo16alt+1792
+ movt r0, :upper16:_datahilo16alt+1792
+ movw r0, :lower16:_datahilo16alt+165
+ movt r0, :upper16:_datahilo16alt+165
+ movw r0, :lower16:_thumbTarget
+ movt r0, :upper16:_thumbTarget
+ movw r0, :lower16:_externalTarget
+ movt r0, :upper16:_externalTarget
+ movw r0, :lower16:_externalTarget+61447
+ movt r0, :upper16:_externalTarget+61447
+Lpicbase:
+ movw r0, :lower16:_datahilo16 - Lpicbase
+ movt r0, :upper16:_datahilo16 - Lpicbase
+ movw r0, :lower16:_datahilo16+4 - Lpicbase
+ movt r0, :upper16:_datahilo16+4 - Lpicbase
+ movw r0, :lower16:_datahilo16alt - Lpicbase
+ movt r0, :upper16:_datahilo16alt - Lpicbase
+ movw r0, :lower16:_datahilo16alt+61440 - Lpicbase
+ movt r0, :upper16:_datahilo16alt+61440 - Lpicbase
+ movw r0, :lower16:_datahilo16alt+2048 - Lpicbase
+ movt r0, :upper16:_datahilo16alt+2048 - Lpicbase
+ movw r0, :lower16:_datahilo16alt+1792 - Lpicbase
+ movt r0, :upper16:_datahilo16alt+1792 - Lpicbase
+ movw r0, :lower16:_datahilo16alt+165 - Lpicbase
+ movt r0, :upper16:_datahilo16alt+165 - Lpicbase
+ movw r0, :lower16:_thumbTarget - Lpicbase
+ movt r0, :upper16:_thumbTarget - Lpicbase
+ bx lr
+
+ .code 16
+ .thumb_func _thumb16tests
+_thumb16tests:
+ movw r0, :lower16:_datahilo16
+ movt r0, :upper16:_datahilo16
+ movw r0, :lower16:_datahilo16+4
+ movt r0, :upper16:_datahilo16+4
+ movw r0, :lower16:_datahilo16alt
+ movt r0, :upper16:_datahilo16alt
+ movw r0, :lower16:_datahilo16alt+61440
+ movt r0, :upper16:_datahilo16alt+61440
+ movw r0, :lower16:_datahilo16alt+2048
+ movt r0, :upper16:_datahilo16alt+2048
+ movw r0, :lower16:_datahilo16alt+1792
+ movt r0, :upper16:_datahilo16alt+1792
+ movw r0, :lower16:_datahilo16alt+165
+ movt r0, :upper16:_datahilo16alt+165
+ movw r0, :lower16:_thumbTarget
+ movt r0, :upper16:_thumbTarget
+ movw r0, :lower16:_externalTarget
+ movt r0, :upper16:_externalTarget
+ movw r0, :lower16:_externalTarget+61447
+ movt r0, :upper16:_externalTarget+61447
+Lpicbase2:
+ movw r0, :lower16:_datahilo16 - Lpicbase2
+ movt r0, :upper16:_datahilo16 - Lpicbase2
+ movw r0, :lower16:_datahilo16+4 - Lpicbase2
+ movt r0, :upper16:_datahilo16+4 - Lpicbase2
+ movw r0, :lower16:_datahilo16alt - Lpicbase2
+ movt r0, :upper16:_datahilo16alt - Lpicbase2
+ movw r0, :lower16:_datahilo16alt+61440 - Lpicbase2
+ movt r0, :upper16:_datahilo16alt+61440 - Lpicbase2
+ movw r0, :lower16:_datahilo16alt+2048 - Lpicbase2
+ movt r0, :upper16:_datahilo16alt+2048 - Lpicbase2
+ movw r0, :lower16:_datahilo16alt+1792 - Lpicbase2
+ movt r0, :upper16:_datahilo16alt+1792 - Lpicbase2
+ movw r0, :lower16:_datahilo16alt+165 - Lpicbase2
+ movt r0, :upper16:_datahilo16alt+165 - Lpicbase2
+ movw r0, :lower16:_thumbTarget - Lpicbase2
+ movt r0, :upper16:_thumbTarget - Lpicbase2
+ bx lr
+
+ .code 16
+ .thumb_func _thumbTarget
+_thumbTarget:
+ nop
+ bx lr
+
+ .data
+_datahilo16: .long 0
+_datahilo16alt: .long 0
+
+
+
+#endif
+
+#endif
+
+#if __ppc__ || __ppc64__
+
+ .text
+ .align 2
+
+ .globl _test_loads
+_test_loads:
+ stmw r30,-8(r1)
+ stwu r1,-48(r1)
+Lpicbase:
+
+ ; PIC load of a
+ addis r2,r10,ha16(_a-Lpicbase)
+ lwz r2,lo16(_a-Lpicbase)(r2)
+
+ ; PIC load of c
+ addis r2,r10,ha16(_c-Lpicbase)
+ lwz r2,lo16(_c-Lpicbase)(r2)
+
+ ; absolute load of a
+ lis r2,ha16(_a)
+ lwz r2,lo16(_a)(r2)
+
+ ; absolute load of c
+ lis r2,ha16(_c)
+ lwz r2,lo16(_c)(r2)
+
+ ; absolute load of external
+ lis r2,ha16(_ax)
+ lwz r2,lo16(_ax)(r2)
+
+ ; absolute lea of external
+ lis r2,hi16(_ax)
+ ori r2,r2,lo16(_ax)
+
+
+ ; PIC load of a + addend
+ addis r2,r10,ha16(_a+0x19000-Lpicbase)
+ lwz r2,lo16(_a+0x19000-Lpicbase)(r2)
+
+ ; absolute load of a + addend
+ lis r2,ha16(_a+0x19000)
+ lwz r2,lo16(_a+0x19000)(r2)
+
+ ; lea of a + addend
+ lis r2,ha16(_a+0x19000)
+ addi r2,r2,lo16(_a+0x19000)
+
+ ; alt lea of a + addend
+ lis r2,hi16(_a+0x19000)
+ ori r2,r2,lo16(_a+0x19000)
+
+ ; absolute load of external + addend
+ lis r2,ha16(_ax+0x19000)
+ lwz r2,lo16(_ax+0x19000)(r2)
+
+ ; absolute lea of external + addend
+ lis r2,hi16(_ax+0x19000)
+ ori r2,r2,lo16(_ax+0x19000)
+
+
+ ; PIC load of a + addend
+ addis r2,r10,ha16(_a+0x09000-Lpicbase)
+ lwz r2,lo16(_a+0x09000-Lpicbase)(r2)
+
+ ; absolute load of a + addend
+ lis r2,ha16(_a+0x09000)
+ lwz r2,lo16(_a+0x09000)(r2)
+
+ ; lea of a + addend
+ lis r2,ha16(_a+0x09000)
+ addi r2,r2,lo16(_a+0x09000)
+
+ ; alt lea of a + addend
+ lis r2,hi16(_a+0x09000)
+ ori r2,r2,lo16(_a+0x09000)
+
+ ; absolute load of external + addend
+ lis r2,ha16(_ax+0x09000)
+ lwz r2,lo16(_ax+0x09000)(r2)
+
+ ; absolute lea of external + addend
+ lis r2,hi16(_ax+0x09000)
+ ori r2,r2,lo16(_ax+0x09000)
+
+ blr
+
+
+_test_calls:
+ ; call internal
+ bl _test_branches
+
+ ; call internal + addend
+ bl _test_branches+0x19000
+
+ ; call external
+ bl _external
+
+ ; call external + addend
+ bl _external+0x19000
+
+
+_test_branches:
+ ; call internal
+ bne _test_calls
+
+ ; call internal + addend
+ bne _test_calls+16
+
+ ; call external
+ bne _external
+
+ ; call external + addend
+ bne _external+16
+
+ .globl _test_weak
+ .weak_definition _test_weak
+_test_weak:
+ nop
+ nop
+
+_test_weak_call:
+ bl _test_weak
+ bl _test_weak+4
+
+#endif
+
+
+
+#if __i386__
+ .text
+ .align 2
+
+Ltest_data:
+ .long 1
+ .long 2
+ .long 3
+
+ .globl _test_loads
+_test_loads:
+ pushl %ebp
+Lpicbase:
+
+ # PIC load of a
+ movl _a-Lpicbase(%ebx), %eax
+
+ # absolute load of a
+ movl _a, %eax
+
+ # absolute load of external
+ movl _ax, %eax
+
+ # absolute lea of external
+ leal _ax, %eax
+
+
+ # PIC load of a + addend
+ movl _a-Lpicbase+0x19000(%ebx), %eax
+
+ # absolute load of a + addend
+ movl _a+0x19000(%ebx), %eax
+
+ # absolute load of external + addend
+ movl _ax+0x19000(%ebx), %eax
+
+ # absolute lea of external + addend
+ leal _ax+0x1900, %eax
+
+ # absolute load of _test_data with negative addend and local label
+ movl Ltest_data-16(%edi),%eax
+ movq Ltest_data-16(%edi),%mm4
+
+ ret
+
+
+_test_calls:
+ # call internal
+ call _test_branches
+
+ # call internal + addend
+ call _test_branches+0x19000
+
+ # 16-bit call internal
+ callw _test_branches
+
+ # 16-bit call internal + addend
+ callw _test_branches+13
+
+ # call external
+ call _external
+
+ # call external + addend
+ call _external+0x19000
+
+
+_test_branches:
+ # call internal
+ jne _test_calls
+
+ # call internal + addend
+ jne _test_calls+16
+
+ # call external
+ jne _external
+
+ # call external + addend
+ jne _external+16
+
+_pointer_diffs:
+ nop
+ call _get_ret_eax
+1: movl _foo-1b(%eax),%esi
+ movl _foo+10-1b(%eax),%esi
+ movl _test_branches-1b(%eax),%esi
+ movl _test_branches+3-1b(%eax),%esi
+ cmpl $(( (_test_branches - _test_loads) + -2097152 )),(%esp)
+ cmpl $(( (_test_calls - _test_loads) + -2097152 )),(%esp)
+
+
+_word_relocs:
+ callw _pointer_diffs
+
+_byte_relocs:
+ mov $100, %ecx
+c_1:
+ loop c_1
+ mov $100, %ecx
+c_2:
+ sub $(1), %ecx
+ jcxz c_2
+
+ .globl _test_weak
+ .weak_definition _test_weak
+_test_weak:
+ nop
+ nop
+
+_test_weak_call:
+ call _test_weak
+ call _test_weak+1
+
+#endif
+
+
+
+#if __x86_64__
+ .text
+ .align 2
+
+ .globl _test_loads
+_test_loads:
+
+ # PIC load of a
+ movl _a(%rip), %eax
+
+ # PIC load of a + addend
+ movl _a+0x1234(%rip), %eax
+
+ # PIC lea
+ leaq _a(%rip), %rax
+
+ # PIC lea through GOT
+ movq _a@GOTPCREL(%rip), %rax
+
+ # PIC access of GOT
+ pushq _a@GOTPCREL(%rip)
+
+ # PIC lea external through GOT
+ movq _ax@GOTPCREL(%rip), %rax
+
+ # PIC external access of GOT
+ pushq _ax@GOTPCREL(%rip)
+
+ # 1-byte store
+ movb $0x12, _a(%rip)
+ movb $0x12, _a+2(%rip)
+ movb $0x12, L0(%rip)
+
+ # 4-byte store
+ movl $0x12345678, _a(%rip)
+ movl $0x12345678, _a+4(%rip)
+ movl $0x12345678, L0(%rip)
+
+ # test local labels
+ lea L1(%rip), %rax
+ movl L0(%rip), %eax
+
+ ret
+
+
+_test_calls:
+ # call internal
+ call _test_branches
+
+ # call internal + addend
+ call _test_branches+0x19000
+
+ # call external
+ call _external
+
+ # call external + addend
+ call _external+0x19000
+
+
+_test_branches:
+ # call internal
+ jne _test_calls
+
+ # call internal + addend
+ jne _test_calls+16
+
+ # call external
+ jne _external
+
+ # call external + addend
+ jne _external+16
+
+_byte_relocs:
+ # nonsense loop that creates byte branch relocation
+ mov $100, %ecx
+c_1:
+ loop _byte_relocs
+ nop
+
+ .globl _test_weak
+ .weak_definition _test_weak
+_test_weak:
+ nop
+ nop
+
+_test_weak_call:
+ call _test_weak
+ call _test_weak+1
+
+#endif
+
+
+
+ # test that pointer-diff relocs are preserved
+ .text
+ .align 2
+_test_diffs:
+Llocal2:
+ .long 0
+ .long Llocal2-_test_branches
+ .long . - _test_branches
+ .long . - _test_branches + 8
+ .long _test_branches - .
+ .long _test_branches - . + 8
+ .long _test_branches - . - 8
+ .long 0
+ .long 0
+#if __ppc64__
+ .quad Llocal2-_test_branches
+#endif
+
+_foo: nop
+Lfoo: nop
+
+ .align 2
+_distance_from_foo:
+ .long 0
+ .long . - _foo
+ .long . - 8 - _foo
+
+
+_distance_to_foo:
+ .long _foo - .
+ .long _foo - . + 4
+
+
+_distance_to_here:
+ .long _foo - _distance_to_here
+ .long _foo - _distance_to_here - 4
+ .long _foo - _distance_to_here - 12
+ .long Lfoo - _distance_to_here
+Ltohere:
+ .long Lfoo - Ltohere
+ .long Lfoo - Ltohere - 4
+ .long 0
+
+
+#if __x86_64__
+ .data
+L0: .quad _test_branches
+_prev:
+ .quad _test_branches+4
+L1: .quad _test_branches - _test_diffs
+ .quad _test_branches - _test_diffs + 4
+ .long _test_branches - _test_diffs
+# .long LCL0-. ### assembler bug: should SUB/UNSIGNED with content= LCL0-24, or single pc-rel SIGNED reloc with content = LCL0-.+4
+ .quad L1
+ .quad L0
+ .quad _test_branches - .
+ .quad _test_branches - L1
+ .quad L1 - _prev
+ .quad _prev+100 - _test_branches
+ #tests support for 32-bit absolute pointers
+ .long _prev
+ .long L1
+
+# the following generates: _foo cannot be undefined in a subtraction expression
+# but it should be ok (it will be a linker error if _foo and _bar are not in same linkage unit)
+# .quad _foo - _bar ### assembler bug
+
+ .section __DATA,__data2
+LCL0: .long 2
+
+
+#endif
+
+
+ .data
+_a:
+ .long 0
+
+_b:
+#if __ppc__ || __i386__ || __arm__
+ .long _test_calls
+ .long _test_calls+16
+ .long _external
+ .long _external+16
+ .long _test_weak
+ .long _test_weak+16
+ .long Lother - . + 0x4000000
+Lother:
+ .long 0
+#elif __ppc64__ || __x86_64__
+ .quad _test_calls
+ .quad _test_calls+16
+ .quad _external
+ .quad _external+16
+ .quad _test_weak
+ .quad _test_weak+16
+ .quad Lother - . + 0x4000000
+Lother:
+ .quad 0
+#endif
+
+ # test that reloc sizes are the same
+Llocal3:
+ .long 0
+
+Llocal4:
+ .long 0
+
+ .long Llocal4-Llocal3
+
+Lfiller:
+ .space 0x9000
+_c:
+ .long 0
+
--- /dev/null
+##
+# Copyright (c) 2005-2008 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# The point of this test is to verify a .o file can round-trip
+# through ld -r correctly. The ObjectDump utility is used
+# dump a "canonical" textual representation of a .o file.
+# The before and after .o files are then diff'ed.
+# No differences means this test passes
+#
+
+ifeq (${ARCH},x86_64)
+ ADDR_SHIFT = 0x1FF000000
+else
+ ADDR_SHIFT = 0xF0000000
+endif
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.c -c -o test.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump
+
+ ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump
+ ${FAIL_IF_ERROR} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+ ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -seg1addr ${ADDR_SHIFT} -o test2-r.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test2-r.${ARCH}.o > test2-r.${ARCH}.o.dump
+ ${PASS_IFF} diff test.${ARCH}.o.dump test2-r.${ARCH}.o.dump
+
+clean:
+ rm -rf *.o *.dump
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+static int foo;
+
+int __attribute__((visibility("hidden"))) foofoo;
+
+static int uninit_static;
+static int init_static = 1;
+ int __attribute__((visibility("hidden"))) uninit_hidden;
+ int __attribute__((visibility("hidden"))) init_hidden = 1;
+ int uninit_global;
+ int init_global = 1;
+extern int extern_global;
+extern int __attribute__((visibility("hidden"))) extern_hidden;
+
+static int uninit_static_array[4];
+static int init_static_array[4] = {1,2,3,4};
+ int __attribute__((visibility("hidden"))) uninit_hidden_array[4];
+ int __attribute__((visibility("hidden"))) init_hidden_array[4] = {1,2,3,4};
+ int uninit_global_array[4];
+ int init_global_array[4] = {1,2,3,4};
+extern int extern_global_array[4];
+
+int test1() { return uninit_static; }
+int test2() { return init_static; }
+int test3() { return uninit_hidden; }
+int test4() { return init_hidden; }
+int test5() { return uninit_global; }
+int test6() { return init_global; }
+int test7() { return extern_global; }
+int test8() { return extern_hidden; }
+
+int test_array1() { return uninit_static_array[2]; }
+int test_array2() { return init_static_array[2]; }
+int test_array3() { return uninit_hidden_array[2]; }
+int test_array4() { return init_hidden_array[2]; }
+int test_array5() { return uninit_global_array[2]; }
+int test_array6() { return init_global_array[2]; }
+int test_array7() { return extern_global_array[2]; }
+
+static int foo2;
+int test9() { return foo2; }
+
+
+int* p_init_global = &init_global;
+void* p_test1 = (void*)&test1;
+unsigned char pad = 2;
+unsigned char pad2 = 3; // this padding throws off alignment on compiler generated anonymous non-lazy pointers...
+
+int func() __attribute__((visibility("hidden")));
+int func() { return foo; }
+
+int func2() { return func() + 1; }
+
--- /dev/null
+##
+# Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# The point of this test is to verify a .o file can round-trip
+# through ld -r correctly. The ObjectDump utility is used
+# dump a "canonical" textual representation of a .o file.
+# The before and after .o files are then diff'ed.
+# No differences means this test passes
+#
+# Currently for ppc64 the .o's alternate! in content
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.c -c -o test.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump
+ #grep "plus" test.${ARCH}.o.dump | ${FAIL_IF_STDIN}
+
+ ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump
+ #grep "plus" test-r.${ARCH}.o.dump | ${FAIL_IF_STDIN}
+
+ ${LD} -arch ${ARCH} -r -keep_private_externs test-r.${ARCH}.o -o test-r-r.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r-r.${ARCH}.o > test-r-r.${ARCH}.o.dump
+
+ ${LD} -arch ${ARCH} -r -keep_private_externs test-r-r.${ARCH}.o -o test-r-r-r.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r-r-r.${ARCH}.o > test-r-r-r.${ARCH}.o.dump
+
+ ${PASS_IFF} diff -c -w test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+clean:
+ rm -rf *.o *.dump
--- /dev/null
+The point of this test is to verify a .o file can round-trip through ld -r correctly. The ObjectDump utility is used
+dump a "canonical" textual representation of a .o file. The before and after .o files are then diff'ed.
+No differences means this test passes
+
+Currently for ppc64 the .o's alternate! in content
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+static int foo;
+
+int __attribute__((visibility("hidden"))) foofoo;
+
+static int uninit_static;
+static int init_static = 1;
+ int __attribute__((visibility("hidden"))) uninit_hidden;
+ int __attribute__((visibility("hidden"))) init_hidden = 1;
+ int uninit_global;
+ int init_global = 1;
+extern int extern_global;
+extern int __attribute__((visibility("hidden"))) extern_hidden;
+
+static int uninit_static_array[4];
+static int init_static_array[4] = {1,2,3,4};
+ int __attribute__((visibility("hidden"))) uninit_hidden_array[4];
+ int __attribute__((visibility("hidden"))) init_hidden_array[4] = {1,2,3,4};
+ int uninit_global_array[4];
+ int init_global_array[4] = {1,2,3,4};
+extern int extern_global_array[4];
+
+int test1() { return uninit_static; }
+int test2() { return init_static; }
+int test3() { return uninit_hidden; }
+int test4() { return init_hidden; }
+int test5() { return uninit_global; }
+int test6() { return init_global; }
+int test7() { return extern_global; }
+int test8() { return extern_hidden; }
+
+int test_array1() { return uninit_static_array[2]; }
+int test_array2() { return init_static_array[2]; }
+int test_array3() { return uninit_hidden_array[2]; }
+int test_array4() { return init_hidden_array[2]; }
+int test_array5() { return uninit_global_array[2]; }
+int test_array6() { return init_global_array[2]; }
+int test_array7() { return extern_global_array[2]; }
+
+static int foo2;
+int test9() { return foo2; }
+
+
+int* p_init_global = &init_global;
+void* p_test1 = (void*)&test1;
+unsigned char pad = 2;
+unsigned char pad2 = 3; // this padding throws off alignment on compiler generated anonymous non-lazy pointers...
+
+int func() __attribute__((visibility("hidden")));
+int func() { return foo; }
+
+int func2() { return func() + 1; }
+
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# The point of this test is to verify a .o file can round-trip
+# through ld -r correctly. The ObjectDump utility is used
+# dump a "canonical" textual representation of a .o file.
+# The before and after .o files are then diff'ed.
+# No differences means this test passes
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -Os $(MDYNAMIC_NO_PIC) test.c -c -o test.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump
+
+ ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump
+
+ ${PASS_IFF} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+clean:
+ rm -rf *.o *.dump
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+const char* foo = "foo";
+const char* const bar = "bar";
+
+const char charArray1[] = "charArray1";
+static const char charArray2[] = "charArray2";
+
+
+const char* getString() { return "string"; }
+const char* getString2() { return charArray2; }
+const char* getString3() { return charArray1; }
+const char* getString4() { return foo; }
+
+
+float f1 = 3.0;
+double d1 = 3.0;
+long double ld1 = 3.0;
+
+
+
+float getSingle() { return 1.0; }
+double getDouble() { return 2.0; }
+long double getLongDouble() { return 3.0; }
+
+
+// rdar://problem/4732996
+const char* stringFutz(int x) {
+ return "hello" + 0x1000 + x;
+}
+
+const char* usesAddend = "teststr" + 0x2000;
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# The point of this test is to verify a .o file can round-trip
+# through ld -r correctly. The ObjectDump utility is used
+# dump a "canonical" textual representation of a .o file.
+# The before and after .o files are then diff'ed.
+# No differences means this test passes
+#
+ifneq (${ARCH},x86_64)
+ PIC=-mdynamic-no-pic
+endif
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -Os $(PIC) test.c -c -o test.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump
+
+ ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump
+
+ ${PASS_IFF} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+clean:
+ rm -rf *.o *.dump
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+const char* foo = "foo";
+const char* const bar = "bar";
+
+const char charArray1[] = "charArray1";
+static const char charArray2[] = "charArray2";
+
+
+const char* getString() { return "string"; }
+const char* getString2() { return charArray2; }
+const char* getString3() { return charArray1; }
+const char* getString4() { return foo; }
+
+
+float f1 = 3.0;
+double d1 = 3.0;
+long double ld1 = 3.0;
+
+
+
+float getSingle() { return 1.0; }
+double getDouble() { return 2.0; }
+long double getLongDouble() { return 3.0; }
+
+
+// rdar://problem/4732996
+const char* stringFutz(int x) {
+ return "hello" + 0x1000 + x;
+}
+
+const char* usesAddend = "teststr" + 0x2000;
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# The point of this test is to verify a .o file can round-trip
+# through ld -r correctly. The ObjectDump utility is used
+# dump a "canonical" textual representation of a .o file.
+# The before and after .o files are then diff'ed.
+# No differences means this test passes
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -Os -mdynamic-no-pic test.c -c -o test.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump
+
+ ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump
+
+ ${PASS_IFF} diff -C 6 test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+clean:
+ rm -rf *.o *.dump
--- /dev/null
+The point of this test is to verify a .o file can round-trip through ld -r correctly. The ObjectDump utility is used
+dump a "canonical" textual representation of a .o file. The before and after .o files are then diff'ed.
+No differences means this test passes
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+const char* foo = "foo";
+const char* const bar = "bar";
+
+const char charArray1[] = "charArray1";
+static const char charArray2[] = "charArray2";
+
+
+const char* getString() { return "string"; }
+const char* getString2() { return charArray2; }
+const char* getString3() { return charArray1; }
+const char* getString4() { return foo; }
+
+
+float f1 = 3.0;
+double d1 = 3.0;
+long double ld1 = 3.0;
+
+
+
+float getSingle() { return 1.0; }
+double getDouble() { return 2.0; }
+long double getLongDouble() { return 3.0; }
+
--- /dev/null
+##
+# Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/6583757> i386 relocation error with negative offsets from local labels
+#
+
+ifeq (${ARCH},i386)
+ TARGET = run-i386
+else
+ TARGET = run-other
+endif
+
+run: ${TARGET}
+
+run-other:
+ ${PASS_IFF} /usr/bin/true
+
+
+run-i386:
+ ${CC} ${ASMFLAGS} test.s -c -o test.o
+ ${OBJECTDUMP} test.o | grep "direct(anon@__data+0x00000000) + 0xFFFFFFFFFFFFFFE2" | ${FAIL_IF_EMPTY}
+
+ ${LD} -arch ${ARCH} -r -keep_private_externs test.o -o test-r.o
+ ${OBJECTDUMP} test-r.o | grep "direct(anon@__data+0x00000000) + 0xFFFFFFFFFFFFFFE2" | ${PASS_IFF_STDIN}
+
+
+clean:
+ rm -rf *.o
--- /dev/null
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+
+#if __i386__
+ .text
+ .align 2
+
+_negative_offset_from_local_label:
+ nop
+ .space 100
+ movl -80+L3(,%eax,4), %edx
+ ret
+
+ .data
+L2: .space 50
+L3: .space 50
+_d: .long 0
+
+#endif
+
+
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# The point of this test is to verify a .o file can round-trip
+# through ld -r correctly. The ObjectDump utility is used
+# dump a "canonical" textual representation of a .o file.
+# The before and after .o files are then diff'ed.
+# No differences means this test passes
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.m -c -o test.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump
+
+ ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump
+
+ ${PASS_IFF} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+clean:
+ rm -rf *.o *.dump
--- /dev/null
+The point of this test is to verify a .o file can round-trip through ld -r correctly. The ObjectDump utility is used
+dump a "canonical" textual representation of a .o file. The before and after .o files are then diff'ed.
+No differences means this test passes
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <Foundation/Foundation.h>
+
+
+@interface Foo : NSObject
+{
+ int ivar;
+}
+- (id) init;
+- (void) foo;
+@end
+
+
+@implementation Foo
+- (id) init
+{
+ self = [super init];
+ return self;
+}
+
+- (void) foo
+{
+ [self class];
+}
+@end
+
+
+
+@interface Base
+@end
+
+
+@implementation Base
+@end
+
+
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a hello-world program with no errors (or crashes)
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -o main -sectcreate __MYSEG __mysect sect_content -dead_strip
+ size -l main | grep __MYSEG | ${FAIL_IF_EMPTY}
+ size -l main | grep __mysect | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -f main
--- /dev/null
+
+int main()
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that ld resolves the magic section start/end symbols.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} common.c -o common
+ otool -lv common | grep -A8 __common | grep S_ZEROFILL | ${FAIL_IF_EMPTY}
+ ${FAIL_IF_BAD_MACHO} common
+ ${CC} ${CCFLAGS} bss.c -o bss
+ otool -lv bss | grep -A8 __bss | grep S_ZEROFILL | ${FAIL_IF_EMPTY}
+ ${FAIL_IF_BAD_MACHO} bss
+ ${CC} ${CCFLAGS} both.c -o both
+ otool -lv both | grep -A8 __common | grep S_ZEROFILL | ${FAIL_IF_EMPTY}
+ otool -lv both | grep -A8 __bss | grep S_ZEROFILL | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} both
+
+clean:
+ rm -f common bss both
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+
+extern int bss_start __asm("section$start$__DATA$__bss");
+extern int bss_end __asm("section$end$__DATA$__bss");
+extern int common_start __asm("section$start$__DATA$__common");
+extern int common_end __asm("section$end$__DATA$__common");
+
+int mycommon[2];
+static int mybss[2];
+
+int main()
+{
+ mybss[0] = 0;
+ printf("bss start = %p\n", &bss_start);
+ printf("bss end = %p\n", &bss_end);
+ printf("common start = %p\n", &common_start);
+ printf("common end = %p\n", &common_end);
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+
+extern int bss_start __asm("section$start$__DATA$__bss");
+extern int bss_end __asm("section$end$__DATA$__bss");
+
+static int mybss[2];
+
+int main()
+{
+ mybss[0] = 0;
+ printf("bss start = %p\n", &bss_start);
+ printf("bss end = %p\n", &bss_end);
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+
+extern int common_start __asm("section$start$__DATA$__common");
+extern int common_end __asm("section$end$__DATA$__common");
+
+int mycommon[2];
+
+int main()
+{
+ printf("common start = %p\n", &common_start);
+ printf("common end = %p\n", &common_end);
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that ld resolves the magic section start/end symbols.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -o main
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm main
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+struct stuff { int a; int b; };
+
+struct stuff stuff1 __attribute__ ((section ("__DATA,__my"))) = { 1, 2};
+struct stuff stuff2 __attribute__ ((section ("__DATA,__my"))) = { 3 ,4 };
+
+extern struct stuff* stuff_start __asm("section$start$__DATA$__my");
+extern struct stuff* stuff_end __asm("section$end$__DATA$__my");
+
+
+int main()
+{
+ struct stuff* p;
+ for (p = stuff_start; p < stuff_end; ++p) {
+ p->a = 0;
+ }
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Validate long section names are preserved
+# <rdar://problem/6805002> corrupt metaclass entry in dynamic library
+#
+
+all:
+ ${CC} ${CCFLAGS} main.c a.s c.s b.s -o main
+ nm -m main | grep __aaaaaaaaaaaaaa | grep __TEXT | grep _at | ${FAIL_IF_EMPTY}
+ nm -m main | grep __bbbbbbbbbbbbbb | grep __TEXT | grep _bt | ${FAIL_IF_EMPTY}
+ nm -m main | grep __cccccccccccccc | grep __TEXT | grep _ct | ${FAIL_IF_EMPTY}
+ nm -m main | grep __aaaaaaaaaaaaaa | grep __DATA | grep _ad | ${FAIL_IF_EMPTY}
+ nm -m main | grep __bbbbbbbbbbbbbb | grep __DATA | grep _bd | ${FAIL_IF_EMPTY}
+ nm -m main | grep __cccccccccccccc | grep __DATA | grep _cd | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main
--- /dev/null
+
+ .section __TEXT,__aaaaaaaaaaaaaa
+_at: .space 128
+
+ .section __DATA,__aaaaaaaaaaaaaa
+_ad: .space 128
+
+
+
--- /dev/null
+
+ .section __TEXT,__bbbbbbbbbbbbbb
+_bt: .space 128
+
+ .section __DATA,__bbbbbbbbbbbbbb
+_bd: .space 128
+
+
+
--- /dev/null
+
+ .section __TEXT,__cccccccccccccc
+_ct: .space 128
+
+
+ .section __DATA,__cccccccccccccc
+_cd: .space 128
+
+
+
+
--- /dev/null
+
+
+int main() { return 0; }
+
--- /dev/null
+##
+# Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that ld resolves the magic segment start/end symbols.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain.dylib
+ ${CC} ${CCFLAGS} main.c -o main
+ ${CC} ${CCFLAGS} test.c -o test.preload -Wl,-preload -nostartfiles -nodefaultlibs -e _start
+ ${CC} ${CCFLAGS} test.c -o test.preload-pie -Wl,-preload -Wl,-pie -nostartfiles -nodefaultlibs -e _start
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -f libmain.dylib main test.preload test.preload-pie
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+
+extern void* data_start __asm("segment$start$__DATA");
+extern void* data_end __asm("segment$end$__DATA");
+extern void* text_start __asm("segment$start$__TEXT");
+extern void* text_end __asm("segment$end$__TEXT");
+extern void* other_start __asm("segment$start$__OTHER");
+extern void* other_end __asm("segment$end$__OTHER");
+
+
+int other[100] __attribute__ ((section ("__OTHER,__my"))) = { 1, 2 };
+
+int mytent[1000];
+static int mybss[1000];
+
+int main()
+{
+ mytent[0] = 0;
+ mybss[0] = 0;
+ printf("text %p -> %p\n", &text_start, &text_end);
+ printf("data %p -> %p\n", &data_start, &data_end);
+ printf("other %p -> %p\n", &other_start, &other_end);
+ return 0;
+}
+
+
--- /dev/null
+extern char text_start[] __asm("segment$start$__TEXT");
+extern char text_end[] __asm("segment$end$__TEXT");
+extern char text_text_start[] __asm("section$start$__TEXT$__text");
+
+void* a = &text_start;
+void* b = &text_end;
+void* c = &text_text_start;
+
+void start(void)
+{
+}
+
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Validate linker puts non-standard segments in order of discovery
+#
+
+all:
+ ${CC} ${CCFLAGS} main.c segKKK.s segJJJ.s segLLL.s -o main
+ nm -j -n main | grep _sym_ > symbol.order
+ ${FAIL_IF_ERROR} diff symbol.order expected.order
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main symbol.order
--- /dev/null
+_sym_kkk
+_sym_jjj
+_sym_lll
--- /dev/null
+
+
+int main() { return 0; }
+
--- /dev/null
+
+ .section __JJJ,__jjj
+_sym_jjj: .space 128
+
+
+
+
--- /dev/null
+
+ .section __KKK,__kkk
+_sym_kkk: .space 128
+
+
+
+
--- /dev/null
+
+ .section __LLL,__lll
+_sym_lll: .space 128
+
+
+
+
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify only dylibs with install paths in /System/Library or /usr/lib
+# get LC_SEGMENT_SPLIT_INFO
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -install_name /usr/lib/libfoo.dylib
+ otool -lv libfoo.dylib | grep LC_SEGMENT_SPLIT_INFO | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -install_name /System/Library/Frameworks/Foo.framework/Foo
+ otool -lv libfoo.dylib | grep LC_SEGMENT_SPLIT_INFO | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -install_name /usr/local/lib/libfoo.dylib
+ otool -lv libfoo.dylib | grep LC_SEGMENT_SPLIT_INFO | ${FAIL_IF_STDIN}
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+ otool -lv libfoo.dylib | grep LC_SEGMENT_SPLIT_INFO | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+clean:
+ rm libfoo.dylib
--- /dev/null
+
+
+int x;
+
+int foo() { return x; }
+
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Sanity check that i386 for 10.6 does not use __IMPORT segment
+#
+
+run: all
+
+
+
+all:
+ ${CC} ${CCFLAGS} hello.c -o hello
+ size -l hello | grep __IMPORT | ${FAIL_IF_STDIN}
+ ${CC} ${CCFLAGS} hello.c -dynamiclib -o libhello.dylib
+ size -l libhello.dylib | grep __IMPORT | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} hello
+
+clean:
+ rm hello libhello.dylib
--- /dev/null
+#include <stdio.h>
+
+int main()
+{
+ fprintf(stdout, "hello\n");
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# automatically strips labels starting with 'l' and 'L'
+#
+
+run: all
+
+all:
+ as -arch ${ARCH} -L extra.s -o extra.o
+ ${CC} ${CCFLAGS} main.c extra.o -o main
+ nm main | grep "lother" | ${FAIL_IF_STDIN}
+ nm main | grep "L123" | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main *.o
--- /dev/null
+
+
+ .data
+
+_foo: .long 0
+lother: .long 0
+L123: .long 0
+_bar: .long 0
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+int main()
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# removes the stabs associated with a copy of a coalesced
+# function that was removed.
+# Running nm through stabs-filter.pl produces connonical stabs
+# that can be diffed against a checked in know good set of stabs
+#
+
+run: all
+
+all: hello.o other.o
+ g++-4.2 ${CCXXFLAGS} -gstabs+ -gused hello.o other.o -o stabs-hello-${ARCH}
+ ${FAIL_IF_BAD_MACHO} stabs-hello-${ARCH}
+ nm -ap stabs-hello-${ARCH} | grep FUN | grep _Z3fooi | wc -l > stabs-hello-foo-count
+ echo " 1" > one
+ ${PASS_IFF} diff stabs-hello-foo-count one
+
+hello.o : hello.cxx
+ g++-4.2 ${CCXXFLAGS} -gstabs+ -gused hello.cxx -c -o $@
+ ${FAIL_IF_BAD_OBJ} $@
+
+other.o : other.cxx
+ g++-4.2 ${CCXXFLAGS} -gstabs+ -gused other.cxx -c -o $@
+ ${FAIL_IF_BAD_OBJ} $@
+
+clean:
+ rm -rf stabs-hello-* *.o *.stabs stabs-hello-foo-count one
--- /dev/null
+The point of this test is a sanity check that ld removes the stabs associated with a copy of a coalesced
+function that was removed. Running nm through stabs-filter.pl produces connonical stabs
+that can be diffed against a checked in know good set of stabs
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+inline int foo(int x)
+{
+ return x + 10;
+}
+
+extern int bar(int x);
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+#include "header.h"
+
+
+int main()
+{
+ foo(bar(3));
+ fprintf(stdout, "hello\n");
+}
\ No newline at end of file
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "header.h"
+
+int uninit;
+int init = 1;
+static int suninit;
+static int sinit=0;
+
+int bar(int x)
+{
+ static int bar_uninit;
+ static int bar_init=3;
+ bar_uninit = x;
+ return 20 + suninit + sinit +
+ bar_init + bar_uninit + foo(x);
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+# Test that file paths in a stab reference ends with a /
+# if there is no terminating /, gdb does not recognize this as a file path
+# The provided files coalesced1a.o coalesced1b.o are ppc64 linked
+# rdar://problem/4565088
+
+run: all
+
+all:
+ $(CC) -gstabs+ main.c -o outfile
+ ${FAIL_IF_BAD_MACHO} outfile
+ nm -ap outfile | grep '.*\<SO\>.*test-cases.*/$$' | ${PASS_IFF_STDIN}
+
+clean:
+ rm -rf outfile*
--- /dev/null
+int main()
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+# Test the ld commands -stack_addr, -stack_size
+# Test using -stack_addr only
+
+
+ifeq (,${findstring 64,$(ARCH)})
+ STACK_ADDR = 0xC0000000
+ STACK_SIZE = 0x04000000
+ STACK_TOP = 0xbc000000
+else
+#ifeq (${ARCH},x86_64)
+ STACK_ADDR = 0x0007fff5fc000000
+ STACK_TOP = 0x00007fff57000000
+ STACK_SIZE = 0x0000000005000000
+#else
+ #STACK_ADDR = 0x0007ffff00000000
+ #STACK_TOP = 0x0007fffefb000000
+ #STACK_SIZE = 0x0000000005000000
+#endif
+endif
+
+
+run: all
+
+all:
+# info seems to not work, use warning:
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c main.c -o main-${ARCH}.o
+
+
+ ${FAIL_IF_ERROR} ${LD} -arch ${ARCH} \
+ -stack_addr ${STACK_ADDR} \
+ -lcrt1.o -lSystem \
+ main-${ARCH}.o -o main \
+ 2>lderr.out
+
+# Can check warning if desired.
+#ifeq (,${findstring 64,$(ARCH)})
+# grep "warning no -stack_size specified using the default size" lderr.out | ${FAIL_IF_EMPTY}
+#else
+# grep "failed: -stack_addr must be used with -stack_size" lderr.out | ${FAIL_IF_EMPTY}
+#endif
+
+
+# Check for __UNIXSTACK section in object, check that it has the correct value
+ ${FAIL_IF_ERROR} ${OTOOL} -l main>ldcmds.out
+ (echo '1,/^[ ]*segname __UNIXSTACK$$/-d'; echo '/^[ ]*segname /,$$d'; echo w; echo q) | ed ldcmds.out >/dev/null
+ grep __UNIXSTACK ldcmds.out | ${FAIL_IF_EMPTY}
+ grep " vmsize[ ]*${STACK_SIZE}" ldcmds.out | ${FAIL_IF_EMPTY}
+ grep " vmaddr[ ]*${STACK_TOP}" ldcmds.out | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf *.o *.err *.out main
--- /dev/null
+Test the ld commands -stack_addr, -stack_size (3939852 and 4729162)
+
+
+-stack_addr value
+Specifies the initial address of the stack pointer value, where value is a hexadecimal number rounded to the segment alignment. The default segment alignment is the target pagesize (currently, 1000 hexadecimal for the PowerPC and for i386). If -stack_size is specified and -stack_addr is not, a default stack address specific for the architecture being linked will be used and its value printed as a warning message. This creates a segment named __UNIXSTACK. Note that the initial stack address will be either at the high address of the segment or the low address of the segment depending on which direction the stack grows for the architecture being linked.
+
+
+-stack_size value
+Specifies the size of the stack segment value, where value is a hexadecimal number rounded to the segment alignment. The default segment alignment is the target pagesize (currently, 1000 hexadecimal for the PowerPC and for i386). If -stack_addr is specified and -stack_size is not, a default stack size specific for the architecture being linked will be used and its value printed as a warning message. This creates a segment named __UNIXSTACK .
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+int main()
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+# Test the ld option -stack_addr and -stack_size used together
+
+ifeq ($(FILEARCH),arm)
+ STACK_ADDR = 0x2C000000
+ STACK_SIZE = 0x05000000
+ STACK_TOP = 0x27000000
+else
+ifeq (,${findstring 64,$(ARCH)})
+ STACK_ADDR = 0xCC000000
+ STACK_SIZE = 0x05000000
+ STACK_TOP = 0xc7000000
+else
+ STACK_ADDR = 0x110000000
+ STACK_TOP = 0x000000010b000000
+ STACK_SIZE = 0x0000000005000000
+endif
+endif
+
+run: all
+
+
+
+all:
+ ${CC} ${CCFLAGS} main.c -o main -Wl,-stack_size,${STACK_SIZE} -Wl,-stack_addr,${STACK_ADDR}
+ # Check for __UNIXSTACK section in object, check that it has the correct value
+ otool -l main | grep -A6 __UNIXSTACK > main.otool
+ grep " vmsize[ ]*${STACK_SIZE}" main.otool | ${FAIL_IF_EMPTY}
+ grep " vmaddr[ ]*${STACK_TOP}" main.otool | ${FAIL_IF_EMPTY}
+ ${FAIL_IF_BAD_MACHO} main
+ ${CC} ${CCFLAGS} -static main.c -o main2 -e _main -nostdlib -Wl,-new_linker -Wl,-stack_size,${STACK_SIZE} -Wl,-stack_addr,${STACK_ADDR}
+ otool -l main2 | grep -A6 __UNIXSTACK > main2.otool
+ grep " vmsize[ ]*${STACK_SIZE}" main2.otool | ${FAIL_IF_EMPTY}
+ grep " vmaddr[ ]*${STACK_TOP}" main2.otool | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main2
+
+clean:
+ rm -rf main main.otool main2.otool main2
--- /dev/null
+Test the ld commands -stack_addr, -stack_size (3939852 and 4729162)
+
+
+-stack_addr value
+Specifies the initial address of the stack pointer value, where value is a hexadecimal number rounded to the segment alignment. The default segment alignment is the target pagesize (currently, 1000 hexadecimal for the PowerPC and for i386). If -stack_size is specified and -stack_addr is not, a default stack address specific for the architecture being linked will be used and its value printed as a warning message. This creates a segment named __UNIXSTACK. Note that the initial stack address will be either at the high address of the segment or the low address of the segment depending on which direction the stack grows for the architecture being linked.
+
+
+-stack_size value
+Specifies the size of the stack segment value, where value is a hexadecimal number rounded to the segment alignment. The default segment alignment is the target pagesize (currently, 1000 hexadecimal for the PowerPC and for i386). If -stack_addr is specified and -stack_size is not, a default stack size specific for the architecture being linked will be used and its value printed as a warning message. This creates a segment named __UNIXSTACK .
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+int main()
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2005-2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+# Test the ld option -stack_size adds a custom stack segment
+
+ifeq (${FILEARCH},arm)
+ STACK_ADDR = 0x30000000
+ STACK_SIZE = 0x05000000
+ STACK_TOP = 0x2a000000
+else
+ifeq (,${findstring 64,$(ARCH)})
+ STACK_ADDR = 0xC0000000
+ STACK_SIZE = 0x05000000
+ STACK_TOP = 0xbb000000
+else
+ STACK_ADDR = 0x0007fff5fc000000
+ STACK_TOP = 0x00007fff57000000
+ STACK_SIZE = 0x0000000005000000
+endif
+endif
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -o main -Wl,-stack_size,${STACK_SIZE}
+ # Check for __UNIXSTACK section in object, check that it has the correct value
+ otool -l main | grep -A6 __UNIXSTACK > main.otool
+ grep " vmsize[ ]*${STACK_SIZE}" main.otool | ${FAIL_IF_EMPTY}
+ grep " vmaddr[ ]*${STACK_TOP}" main.otool | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main main.otool
--- /dev/null
+Test the ld commands -stack_addr, -stack_size
+
+
+-stack_addr value
+Specifies the initial address of the stack pointer value, where value is a hexadecimal number rounded to the segment alignment. The default segment alignment is the target pagesize (currently, 1000 hexadecimal for the PowerPC and for i386). If -stack_size is specified and -stack_addr is not, a default stack address specific for the architecture being linked will be used and its value printed as a warning message. This creates a segment named __UNIXSTACK. Note that the initial stack address will be either at the high address of the segment or the low address of the segment depending on which direction the stack grows for the architecture being linked.
+
+
+-stack_size value
+Specifies the size of the stack segment value, where value is a hexadecimal number rounded to the segment alignment. The default segment alignment is the target pagesize (currently, 1000 hexadecimal for the PowerPC and for i386). If -stack_addr is specified and -stack_size is not, a default stack size specific for the architecture being linked will be used and its value printed as a warning message. This creates a segment named __UNIXSTACK .
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006-2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+#if __x86_64__
+static char buffer[8000000000];
+#elif __arm__
+static char buffer[100000000];
+#else
+static char buffer[2000000000];
+#endif
+
+int main()
+{
+ return buffer[0];
+}
--- /dev/null
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+RELOC_COUNT = 3
+ifeq (${ARCH},x86_64)
+ RELOC_COUNT = 2
+endif
+
+
+#
+# Test that ld can link a pie static executable
+#
+
+all:
+ ${CC} ${CCFLAGS} test.c -c -o test.o
+ ${CC} ${CCFLAGS} test.o -static -Wl,-pie -o test -e _entry -nostdlib -Wl,-new_linker
+ otool -rv test | grep __DATA | wc -l | grep ${RELOC_COUNT} | ${FAIL_IF_EMPTY}
+ # verify trying to use absolute addressing fails
+ ${CC} ${CCFLAGS} -static bad.c -c -o bad.o
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} test.o bad.o -static -Wl,-pie -o test.bad -e _entry -nostdlib -Wl,-new_linker 2>/dev/null
+ ${PASS_IFF_GOOD_MACHO} test
+
+clean:
+ rm -rf test test.o bad.o test.bad
+
+
--- /dev/null
+static int my;
+
+int getmy()
+{
+#if __x86_64__
+ __asm(" .quad _my");
+#endif
+ return my;
+}
--- /dev/null
+
+int a;
+int b = 5;
+int* pa = &a;
+int* pb = &b;
+
+int foo()
+{
+ *pa = 4;
+ return a+b;
+}
+
+
+int entry()
+{
+ return foo();
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that ld can link a static executable with a weak definition
+#
+
+all:
+ ${CC} ${CCFLAGS} test.c -static -o test -e _entry -nostdlib -Wl,-new_linker
+ strip -S test -o test.stripped
+ ${PASS_IFF_GOOD_MACHO} test
+
+clean:
+ rm -rf test test.stripped
--- /dev/null
+
+
+
+__attribute__((weak)) int foo()
+{
+ return 0;
+}
+
+
+int entry()
+{
+ return foo();
+}
+
+// pointer to weak function might trigger external relocation
+void* pfoo = &foo;
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that ld can link a static executable
+#
+
+all:
+ ${CC} ${CCFLAGS} test.c -static -o test -e _entry -nostdlib -Wl,-new_linker
+ ${PASS_IFF_GOOD_MACHO} test
+
+clean:
+ rm -rf test
--- /dev/null
+
+int a;
+int b = 5;
+
+int foo()
+{
+ return a+b;
+}
+
+
+int entry()
+{
+ return foo();
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a static executable (requires non-public archives)
+#
+
+run: all
+
+all:
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} test.c -static -o test-${ARCH} -L/usr/local/lib/system -lc_static -lm_static -Wl,-new_linker
+ ${FAIL_IF_BAD_MACHO} test-${ARCH}
+ ${FAIL_IF_ERROR} strip test-${ARCH}
+ ${PASS_IFF_GOOD_MACHO} test-${ARCH}
+
+clean:
+ rm -rf test-*
--- /dev/null
+The point of this test is a sanity check that ld can link a static executable (requires non-public archives)
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+int main()
+{
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+# Test strip: symbols referenced by indirect symbol table entries that can'tÊ
+# be stripped in:
+# __ZN9__gnu_cxx13new_allocatorIiE7destroyEPi
+# __ZNKSt12_Vector_baseIiSaIiEE13get_allocatorEv
+# __ZN9__gnu_cxx13new_allocatorIiEC2ERKS1_
+# __ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPim
+# __ZN9__gnu_cxx13new_allocatorIiED2Ev
+# __ZNSt6vectorIiSaIiEEC1ERKS0_
+# __ZNSaIiEC1ERKS_
+# __ZN9__gnu_cxx13new_allocatorIiE10deallocateEPim
+# __ZNSt12_Vector_baseIiSaIiEE12_Vector_implC1ERKS0_
+# __ZNSaIiED2Ev
+# __ZNSt12_Vector_baseIiSaIiEED2Ev
+# __ZNSaIiEC1Ev
+# __ZNSt12_Vector_baseIiSaIiEEC2ERKS0_
+# __ZNSt6vectorIiSaIiEED1Ev
+# __ZNSaIiED1Ev
+# __ZSt8_DestroyIPiSaIiEEvT_S2_T0_
+# __ZN9__gnu_cxx13new_allocatorIiEC2Ev
+# __ZNSaIiEC2ERKS_
+# __ZNSt12_Vector_baseIiSaIiEE12_Vector_implD1Ev
+
+
+run: all
+
+
+all:
+ $(CXX) main.cxx -arch ${ARCH} -o main
+ ${FAIL_IF_BAD_MACHO} main
+ ${FAIL_IF_ERROR} nm -j main >main-no-strip.nm
+ $(CXX) main.cxx -arch ${ARCH} -o main
+ ${FAIL_IF_BAD_MACHO} main
+
+ # Make sure there are no symbols in the stripped file that aren't
+ # in the unstripped
+ nm -j main | comm -23 - main-no-strip.nm | ${FAIL_IF_STDIN}
+
+ # Now make sure that all the __Z symbols exist
+ strip_cnt=`nm -j main | comm -12 - main-no-strip.nm | grep -c __Z`; \
+ nostrip_cnt=`nm -j main|grep -c __Z`; \
+ [ x"$$strip_cnt" = x"$$nostrip_cnt" ]
+ @echo PASS $$UNIT_TEST_NAME
+
+clean:
+ rm -rf *.o main-* main
--- /dev/null
+Test strip: symbols referenced by indirect symbol table entries can't be stripped (4096290)
+
+__ZN9__gnu_cxx13new_allocatorIiE7destroyEPi
+__ZNKSt12_Vector_baseIiSaIiEE13get_allocatorEv
+__ZN9__gnu_cxx13new_allocatorIiEC2ERKS1_
+__ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPim
+__ZN9__gnu_cxx13new_allocatorIiED2Ev
+__ZNSt6vectorIiSaIiEEC1ERKS0_
+__ZNSaIiEC1ERKS_
+__ZN9__gnu_cxx13new_allocatorIiE10deallocateEPim
+__ZNSt12_Vector_baseIiSaIiEE12_Vector_implC1ERKS0_
+__ZNSaIiED2Ev
+__ZNSt12_Vector_baseIiSaIiEED2Ev
+__ZNSaIiEC1Ev
+__ZNSt12_Vector_baseIiSaIiEEC2ERKS0_
+__ZNSt6vectorIiSaIiEED1Ev
+__ZNSaIiED1Ev
+__ZSt8_DestroyIPiSaIiEEvT_S2_T0_
+__ZN9__gnu_cxx13new_allocatorIiEC2Ev
+__ZNSaIiEC2ERKS_
+__ZNSt12_Vector_baseIiSaIiEE12_Vector_implD1Ev
--- /dev/null
+#include <vector>
+int main()
+{
+ std::vector<int> stuff;
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+# Test strip: symbols referenced by indirect symbol table entries that can'tÊ
+# be stripped in:
+# __ZN9__gnu_cxx13new_allocatorIiE7destroyEPi
+# __ZNKSt12_Vector_baseIiSaIiEE13get_allocatorEv
+# __ZN9__gnu_cxx13new_allocatorIiEC2ERKS1_
+# __ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPim
+# __ZN9__gnu_cxx13new_allocatorIiED2Ev
+# __ZNSt6vectorIiSaIiEEC1ERKS0_
+# __ZNSaIiEC1ERKS_
+# __ZN9__gnu_cxx13new_allocatorIiE10deallocateEPim
+# __ZNSt12_Vector_baseIiSaIiEE12_Vector_implC1ERKS0_
+# __ZNSaIiED2Ev
+# __ZNSt12_Vector_baseIiSaIiEED2Ev
+# __ZNSaIiEC1Ev
+# __ZNSt12_Vector_baseIiSaIiEEC2ERKS0_
+# __ZNSt6vectorIiSaIiEED1Ev
+# __ZNSaIiED1Ev
+# __ZSt8_DestroyIPiSaIiEEvT_S2_T0_
+# __ZN9__gnu_cxx13new_allocatorIiEC2Ev
+# __ZNSaIiEC2ERKS_
+# __ZNSt12_Vector_baseIiSaIiEE12_Vector_implD1Ev
+
+
+run: all
+
+
+all:
+ ${FAIL_IF_ERROR} $(CXX) main.cxx -arch ${ARCH} -o main
+ ${FAIL_IF_BAD_MACHO} main
+ ${FAIL_IF_ERROR} nm -j main >main-no-strip.nm
+ ${FAIL_IF_ERROR} strip main
+ ${FAIL_IF_BAD_MACHO} main
+ ${FAIL_IF_ERROR} $(CXX) main.cxx -arch ${ARCH} -s -o main
+ ${PASS_IFF_GOOD_MACHO} main
+
+ # Make sure there are no symbols in the stripped file that aren't
+ # in the unstripped
+ nm -j main | comm -23 - main-no-strip.nm | ${FAIL_IF_STDIN}
+
+ # Now make sure that all the __Z symbols exist
+ strip_cnt=`nm -j main | comm -12 - main-no-strip.nm | grep -c __Z`; \
+ nostrip_cnt=`nm -j main|grep -c __Z`; \
+ [ x"$$strip_cnt" = x"$$nostrip_cnt" ]
+ @echo PASS $$UNIT_TEST_NAME
+clean:
+ rm -rf *.o main main-* *.nm *.out
--- /dev/null
+Test strip: symbols referenced by indirect symbol table entries can't be stripped (4096290)
+
+__ZN9__gnu_cxx13new_allocatorIiE7destroyEPi
+__ZNKSt12_Vector_baseIiSaIiEE13get_allocatorEv
+__ZN9__gnu_cxx13new_allocatorIiEC2ERKS1_
+__ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPim
+__ZN9__gnu_cxx13new_allocatorIiED2Ev
+__ZNSt6vectorIiSaIiEEC1ERKS0_
+__ZNSaIiEC1ERKS_
+__ZN9__gnu_cxx13new_allocatorIiE10deallocateEPim
+__ZNSt12_Vector_baseIiSaIiEE12_Vector_implC1ERKS0_
+__ZNSaIiED2Ev
+__ZNSt12_Vector_baseIiSaIiEED2Ev
+__ZNSaIiEC1Ev
+__ZNSt12_Vector_baseIiSaIiEEC2ERKS0_
+__ZNSt6vectorIiSaIiEED1Ev
+__ZNSaIiED1Ev
+__ZSt8_DestroyIPiSaIiEEvT_S2_T0_
+__ZN9__gnu_cxx13new_allocatorIiEC2Ev
+__ZNSaIiEC2ERKS_
+__ZNSt12_Vector_baseIiSaIiEE12_Vector_implD1Ev
--- /dev/null
+#include <vector>
+int main()
+{
+ std::vector<int> stuff;
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2006-2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# This test case checks merges two .o files. One uses
+# a lazy and non-lazy pointer to access the second.
+# The result then has local symbols stripped. So the
+# end result is a .o file with a lazy and non-lazy pointer to
+# anonymous stuff.
+#
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} hello.c -c
+ ${FAIL_IF_BAD_OBJ} hello.o
+
+ ${CC} ${CCFLAGS} foo.c -c
+ ${FAIL_IF_BAD_OBJ} foo.o
+
+ ${LD} -r hello.o foo.o -o hellofoo.o
+ ${FAIL_IF_BAD_OBJ} hellofoo.o
+
+ strip -x hellofoo.o -o hellofoostripped.o
+ ${CC} ${CCFLAGS} hellofoostripped.o -o main
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf *.o main
--- /dev/null
+
+
+int __attribute__((visibility("hidden"))) data = 3;
+
+void __attribute__((visibility("hidden"))) func(int x) { }
+
+
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+extern int data;
+extern void func(int);
+
+int main()
+{
+ func(data);
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2007-2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+POINTER_SEGMENT = __DATA
+POINTER_SECTION = __nl_symbol_ptr
+
+
+#
+# Test that using strip -R to selectively strip symbol names
+# of of a .o file still works with ld.
+# And for i386 that there are no __IMPORT/__pointers left <rdar://problem/6666004>
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} a.c -c -o a.o
+ ${CC} ${CCFLAGS} b.c -c -o b.o
+ ${CC} ${CCFLAGS} c.c -c -o c.o
+ ${CC} ${CCFLAGS} func.c -c -o func.o
+ ${LD} -arch ${ARCH} -r a.o b.o c.o -o most.o
+ strip -x -R strip.list most.o -o most.stripped.o
+ ${CC} ${CCFLAGS} most.stripped.o func.o -dynamiclib -o dylib1
+ ${LD} -arch ${ARCH} -r most.stripped.o func.o -o all.o
+ ${CC} ${CCFLAGS} all.o -dynamiclib -o dylib2
+ otool -X -s ${POINTER_SEGMENT} ${POINTER_SECTION} dylib1 >dylib1.pointers
+ otool -X -s ${POINTER_SEGMENT} ${POINTER_SECTION} dylib2 >dylib2.pointers
+ size -l dylib1 | grep __IMPORT | ${FAIL_IF_STDIN}
+ size -l dylib2 | grep __IMPORT | ${FAIL_IF_STDIN}
+ ${PASS_IFF} diff dylib1.pointers dylib2.pointers
+
+clean:
+ rm -rf *.o dylib1 dylib2 *.pointers
--- /dev/null
+
+int aData = 0;
+
+void a()
+{
+ ++aData;
+}
--- /dev/null
+
+int bData = 0;
+
+void b()
+{
+ ++bData;
+}
+
+void bb()
+{
+ ++bData;
+}
--- /dev/null
+extern void b();
+extern void bb();
+
+extern void func(void*);
+
+
+void c()
+{
+ func(&b);
+ func(&bb);
+}
\ No newline at end of file
--- /dev/null
+void func(void* x) {}
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that ld generates correct stubs when some are weak_import
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
+ otool -Iv main | grep '_foo' | ${FAIL_IF_EMPTY}
+ otool -Iv main | grep '_bar' | ${FAIL_IF_EMPTY}
+ otool -Iv main | grep '_baz' | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+ rm libfoo.dylib main
--- /dev/null
+
+void foo() {}
+void bar() {}
+void baz() {}
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+extern void foo() __attribute__((weak_import));
+extern void bar() __attribute__((weak_import));
+extern void baz();
+
+int main()
+{
+ if ( &foo != 0 ) {
+ foo();
+ bar();
+ }
+ baz();
+ return 0;
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that ld generates correct stubs
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.c -dynamiclib -Wl,-interposable -o libtest.dylib
+ # only stub should be to _test
+ otool -Iv libtest.dylib | grep '1 entries' | ${FAIL_IF_EMPTY}
+ otool -Iv libtest.dylib | grep '_test' | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libtest.dylib
+
+
+clean:
+ rm libtest.dylib
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+const char kMyStr[] = "hello";
+
+int test()
+{
+ return 10;
+}
+
+
+const char* getstr()
+{
+ test();
+ return kMyStr;
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that -mdynamic-no-pic jump table in the middle of
+# a function does not cause relocations.
+#
+# <rdar://problem/5847206> SPEC2000/eon built with -mdynamic-no-pic won't run
+#
+
+all: test-${FILEARCH}
+
+
+test-ppc: test-good
+test-x86_64: test-good
+test-i386: test
+test-arm: test
+
+test:
+ # check jump table in a weak function
+ ${CC} ${CCFLAGS} main.c switch.s -o main -Wl,-no_pie
+ otool -rv main | grep _foo | ${FAIL_IF_STDIN}
+ otool -rv main | grep _bar | ${FAIL_IF_STDIN}
+ # check jump table in a regular function with -flat_namespace
+ ${CC} ${CCFLAGS} main.c switch.s -o main -flat_namespace -Wl,-no_pie
+ otool -rv main | grep _foo | ${FAIL_IF_STDIN}
+ otool -rv main | grep _bar | ${FAIL_IF_STDIN}
+ # check jump table in a regular function that is interposable
+ ${CC} ${CCFLAGS} main.c switch.s -o main -Wl,-interposable_list,interpose.exp -Wl,-no_pie
+ otool -rv main | grep _foo | ${FAIL_IF_STDIN}
+ otool -rv main | grep _bar | ${FAIL_IF_STDIN}
+ # check jump table with -pie, should have no external and some local relocations
+ ${CC} ${CCFLAGS} main.c switch.s -o main -Wl,-pie -read_only_relocs suppress
+ otool -rv main | grep "External relocation" | ${FAIL_IF_STDIN}
+# otool -rv main | grep "Local relocation" | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+test-good:
+ ${PASS_IFF} true
+
+clean:
+ rm -f main
--- /dev/null
+_foo
+_bar
--- /dev/null
+int main()
+{
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+
+ .section __TEXT,__textcoal_nt,coalesced,pure_instructions
+
+
+
+/*
+ Simulate a switch statement in a weak function compiled
+ to a jump table
+*/
+ .globl _foo
+ .weak_definition _foo
+ .align 4
+_foo:
+ nop
+ nop
+#if __arm__ || __i386__
+ .long L1
+ .long L2
+ .long L3
+#endif
+ nop
+L1: nop
+L2: nop
+L3: nop
+ nop
+
+
+/*
+ Simulate a switch statement in a regular function compiled
+ to a jump table
+*/
+ .text
+ .align 4
+ .globl _bar
+_bar: nop
+ nop
+ nop
+ nop
+#if __arm__ || __i386__
+ .long L5
+ .long L6
+ .long L7
+#endif
+ nop
+L5: nop
+L6: nop
+L7: nop
+ nop
+
+
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test magic $ld$hide works with public sub library
+# <rdar://problem/8388362> RedGarnet's linker does not honor $ld$hide for umbrella libraries
+#
+
+
+run: all
+
+all:
+ # In this test case aaa and bbb both moved between libfoo and libar
+ # between 10.4 and 10.5.
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -install_name /usr/lib/libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -Wl,-reexport_library,libbar.dylib -o libfoo.dylib
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -install_name /usr/lib/libbar_alt.dylib
+ ${CC} ${CCFLAGS} main.c -o main-10.5 libfoo.dylib -L. -mmacosx-version-min=10.5
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -o main-10.6 libfoo.dylib -L. -mmacosx-version-min=10.6 2>/dev/null
+ ${CC} ${CCFLAGS} main.c -o main-10.7 libfoo.dylib -L. -mmacosx-version-min=10.7
+ ${PASS_IFF_GOOD_MACHO} main-10.7
+
+
+clean:
+
+ rm -rf libbar.dylib libfoo.dylib main-10.5 main-10.6 main-10.7
--- /dev/null
+void bar() {}
--- /dev/null
+
+void foo() {}
+
+#define SYMBOL_NOT_HERE_IN_10_6(sym) \
+ extern const char sym##_tmp __asm("$ld$hide$os10.6$_" #sym ); const char sym##_tmp = 0;
+
+SYMBOL_NOT_HERE_IN_10_6(bar)
--- /dev/null
+
+extern void foo();
+extern void bar();
+
+
+int main()
+{
+ foo();
+ bar();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test magic $ld$ symbols which tell ld to view exported symbols
+# differently than dyld sees them.
+#
+# In this test case aaa and bbb both moved between libfoo and libar
+# between 10.4 and 10.5.
+#
+
+
+run: all
+
+all:
+ # In this test case aaa and bbb both moved between libfoo and libar
+ # between 10.4 and 10.5.
+ ${CC} ${CCFLAGS} -dynamiclib bar.c bbb.c anotb.c -o libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c aaa.c bnota.c -o libfoo.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ ${CC} ${CCFLAGS} main.c -o main-10.4 libfoo.dylib libbar.dylib -mmacosx-version-min=10.4
+ nm -m main-10.4 | grep _aaa | grep libbar | ${FAIL_IF_EMPTY}
+ nm -m main-10.4 | grep _bbb | grep libfoo | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} main.c -o main-10.4a libbar.dylib libfoo.dylib -mmacosx-version-min=10.4
+ nm -m main-10.4a | grep _aaa | grep libbar | ${FAIL_IF_EMPTY}
+ nm -m main-10.4a | grep _bbb | grep libfoo | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} main.c -o main-10.5 libfoo.dylib libbar.dylib -mmacosx-version-min=10.5
+ nm -m main-10.5 | grep _aaa | grep libfoo | ${FAIL_IF_EMPTY}
+ nm -m main-10.5 | grep _bbb | grep libbar | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} main.c -o main-10.5a libbar.dylib libfoo.dylib -mmacosx-version-min=10.5
+ nm -m main-10.5a | grep _aaa | grep libfoo | ${FAIL_IF_EMPTY}
+ nm -m main-10.5a | grep _bbb | grep libbar | ${FAIL_IF_EMPTY}
+ # In this test case aaa and bbb both moved between subframeworks of Foo and Bar
+ # between 10.4 and 10.5.
+ mkdir -p Frameworks/Foo.framework/Frameworks/subFoo.framework
+ ${CC} ${CCFLAGS} -dynamiclib foo.c aaa.c -o Frameworks/Foo.framework/Frameworks/subFoo.framework/subFoo \
+ -install_name /System/Library/Frameworks/Foo.framework/Frameworks/subFoo.framework/subFoo \
+ -umbrella Foo
+ ${CC} ${CCFLAGS} -dynamiclib bnota.c -o Frameworks/Foo.framework/Foo \
+ -install_name /System/Library/Frameworks/Frameworks/Foo.framework/Foo \
+ Frameworks/Foo.framework/Frameworks/subFoo.framework/subFoo
+ mkdir -p Frameworks/Bar.framework/Frameworks/subBar.framework
+ ${CC} ${CCFLAGS} -dynamiclib bar.c bbb.c -o Frameworks/Bar.framework/Frameworks/subBar.framework/subBar \
+ -install_name /System/Library/Frameworks/Bar.framework/Frameworks/subBar.framework/subBar \
+ -umbrella Bar
+ ${CC} ${CCFLAGS} -dynamiclib anotb.c -o Frameworks/Bar.framework/Bar \
+ -install_name /System/Library/Frameworks/Frameworks/Bar.framework/Bar \
+ Frameworks/Bar.framework/Frameworks/subBar.framework/subBar
+ ${CC} ${CCFLAGS} main.c -o main-10.4 -framework Foo -framework Bar -mmacosx-version-min=10.4 \
+ -F./Frameworks -F./Frameworks/Bar.framework/Frameworks -F./Frameworks/Foo.framework/Frameworks
+ nm -m main-10.4 | grep _aaa | grep " Bar" | ${FAIL_IF_EMPTY}
+ nm -m main-10.4 | grep _bbb | grep " Foo" | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} main.c -o main-10.4a -framework Bar -framework Foo -mmacosx-version-min=10.4 \
+ -F./Frameworks -F./Frameworks/Bar.framework/Frameworks -F./Frameworks/Foo.framework/Frameworks
+ nm -m main-10.4a | grep _aaa | grep " Bar" | ${FAIL_IF_EMPTY}
+ nm -m main-10.4a | grep _bbb | grep " Foo" | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} main.c -o main-10.5 -framework Foo -framework Bar -mmacosx-version-min=10.5 \
+ -F./Frameworks -F./Frameworks/Bar.framework/Frameworks -F./Frameworks/Foo.framework/Frameworks
+ nm -m main-10.5 | grep _aaa | grep " Foo" | ${FAIL_IF_EMPTY}
+ nm -m main-10.5 | grep _bbb | grep " Bar" | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} main.c -o main-10.5a -framework Bar -framework Foo -mmacosx-version-min=10.5 \
+ -F./Frameworks -F./Frameworks/Bar.framework/Frameworks -F./Frameworks/Foo.framework/Frameworks
+ nm -m main-10.5a | grep _aaa | grep " Foo" | ${FAIL_IF_EMPTY}
+ nm -m main-10.5a | grep _bbb | grep " Bar" | ${FAIL_IF_EMPTY}
+ ${PASS_IFF} /usr/bin/true
+
+
+clean:
+
+ rm -rf libbar.dylib libfoo.dylib main-10.4 main-10.5 main-10.4a main-10.5a Frameworks
--- /dev/null
+
+void aaa() {}
+
--- /dev/null
+
+
+#define SYMBOL_IS_HERE_IN_10_4(sym) \
+ extern const char sym##_tmp __asm("$ld$add$os10.4$_" #sym ); const char sym##_tmp = 0;
+
+#define SYMBOL_IS_HERE_IN_10_5(sym) \
+ extern const char sym##_tmp __asm("$ld$add$os10.5$_" #sym ); const char sym##_tmp = 0;
+
+#define SYMBOL_NOT_HERE_IN_10_4(sym) \
+ extern const char sym##_tmp __asm("$ld$hide$os10.4$_" #sym ); const char sym##_tmp = 0;
+
+#define SYMBOL_NOT_HERE_IN_10_5(sym) \
+ extern const char sym##_tmp __asm("$ld$hide$os10.5$_" #sym ); const char sym##_tmp = 0;
+
+
+// 10.4 10.5
+// aaa libbar libfoo
+// bbb libfoo libbar
+//
+
+// bbb is new here in 10.5. It was elsewhere in 10.4
+SYMBOL_NOT_HERE_IN_10_4(bbb)
+
+// aaa was here in 10.4 and move elsewhere
+SYMBOL_IS_HERE_IN_10_4(aaa)
+
--- /dev/null
+void bar() {}
--- /dev/null
+void bbb() {}
--- /dev/null
+#define SYMBOL_IS_HERE_IN_10_4(sym) \
+ extern const char sym##_tmp __asm("$ld$add$os10.4$_" #sym ); const char sym##_tmp = 0;
+
+#define SYMBOL_IS_HERE_IN_10_5(sym) \
+ extern const char sym##_tmp __asm("$ld$add$os10.5$_" #sym ); const char sym##_tmp = 0;
+
+#define SYMBOL_NOT_HERE_IN_10_4(sym) \
+ extern const char sym##_tmp __asm("$ld$hide$os10.4$_" #sym ); const char sym##_tmp = 0;
+
+#define SYMBOL_NOT_HERE_IN_10_5(sym) \
+ extern const char sym##_tmp __asm("$ld$hide$os10.5$_" #sym ); const char sym##_tmp = 0;
+
+
+// 10.4 10.5
+// aaa libbar libfoo
+// bbb libfoo libbar
+//
+
+
+// bbb was here in 10.4 and move elsewhere
+SYMBOL_IS_HERE_IN_10_4(bbb)
+
+// aaa is new here in 10.5. It was elsewhere in 10.4
+SYMBOL_NOT_HERE_IN_10_4(aaa)
+
--- /dev/null
+
+void foo() {}
+
--- /dev/null
+
+extern void foo();
+extern void bar();
+
+extern void aaa();
+extern void bbb();
+
+
+int main()
+{
+ foo();
+ bar();
+ aaa();
+ bbb();
+
+ return 0;
+}
--- /dev/null
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test a simple symbol resolver function
+#
+TARGET = all
+ifeq (${ARCH},ppc)
+ TARGET = all-ppc
+endif
+
+
+run: ${TARGET}
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ ${CC} ${CCFLAGS} foo.o -dynamiclib -o libfoo.dylib
+ ${DYLDINFO} -export libfoo.dylib | grep _foo | grep resolver | ${FAIL_IF_EMPTY}
+ ${LD} -arch ${ARCH} -r foo.o -o foo-r.o
+ ${CC} ${CCFLAGS} foo-r.o -dynamiclib -o libfoo-r.dylib
+ ${DYLDINFO} -export libfoo-r.dylib | grep _foo | grep resolver | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libfoo-r.dylib
+
+all-ppc:
+ echo "PASS"
+
+clean:
+ rm -f foo.o libfoo.dylib foo-r.o libfoo-r.dylib
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+
+int foo_real()
+{
+ return 10;
+}
+
+// This foo is a "resolver" function that return the actual address of "foo"
+void* foo()
+{
+ __asm__(".desc _foo, 0x100");
+ return &foo_real;
+}
+
--- /dev/null
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test a simple symbol resolver function
+#
+TARGET = all
+ifeq (${ARCH},ppc)
+ TARGET = all-ppc
+endif
+
+
+run: ${TARGET}
+
+all:
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -Wl,-w
+ ${DYLDINFO} -lazy_bind libfoo.dylib | grep _a | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+all-ppc:
+ echo "PASS"
+
+clean:
+ rm -f libfoo.dylib
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+
+extern void a();
+
+void b() {
+ a();
+}
+
+static void a_impl() {
+ printf("Hello World!\n");
+}
+
+void *a_chooser() __asm__("_a") __attribute__((visibility("hidden"), noinline));
+void *a_chooser() {
+ __asm__(".symbol_resolver _a");
+ return a_impl;
+}
+
--- /dev/null
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+# Test how tentative definitions interact with archives
+# main.c has a tenative definition for _foo which
+# should cause libfoo_data.a to be loaded, but not libfoo_tent.a
+# nor libfoo_code.a.
+#
+# <rdar://problem/7890410> Snow Leopard linker bug with common symbols
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} junk.c -c -o junk.o
+ # verify data symbol does get pulled in
+ ${CC} ${CCFLAGS} foo_data.c -c -o foo_data.o
+ libtool -static junk.o foo_data.o -o libfoo_data.a
+ ${CC} ${CCFLAGS} main.c libfoo_data.a -o main_data
+ nm -m main_data | grep _foo | grep __TEXT | ${FAIL_IF_STDIN}
+ # verify tentative does not
+ ${CC} ${CCFLAGS} foo_tent.c -c -o foo_tent.o
+ libtool -static junk.o foo_tent.o -o libfoo_tent.a
+ ${CC} ${CCFLAGS} main.c libfoo_tent.a -o main_tent
+ nm -m main_tent | grep _foo | grep __TEXT | ${FAIL_IF_STDIN}
+ # verify code does not
+ ${CC} ${CCFLAGS} foo_code.c -c -o foo_code.o
+ libtool -static junk.o foo_code.o -o libfoo_code.a
+ ${CC} ${CCFLAGS} main.c libfoo_code.a -o main_code
+ nm -m main_code | grep _foo | grep __TEXT | ${FAIL_IF_STDIN}
+ # verify warning when code force to override tent
+ #${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoo_code.a -o main_code_force 2>main_code_force_warnings.txt
+ #grep warning main_code_force_warnings.txt | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main_code
+
+clean:
+ rm -rf junk.o foo_data.o libfoo_data.a main_data foo_tent.o libfoo_tent.a main_tent foo_code.o libfoo_code.a main_code main_code_force main_code_force_warnings.txt
+
--- /dev/null
+
+int foo() { return 10; }
+
--- /dev/null
+
+int foo = 5;
--- /dev/null
+
+int foo;
--- /dev/null
+void junk() {}
--- /dev/null
+
+int foo;
+
+int main()
+{
+ foo = 3;
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+# Test how tentative definitions interact with archives
+# main.c has a tenative definition for _var which
+# should cause libfoo.a(foo.o) to be loaded which in turn
+# should cause _bar from libbar.dylib to be used.
+#
+# <rdar://problem/5779681> ld crashes building XsanFS
+# <rdar://problem/5852023> -undefined dynamic_lookup causes spurious extra symbols
+# <rdar://problem/5613343> need to search for definitions for common symbols
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ libtool -static foo.o -o libfoo.a
+ ${CC} ${CCFLAGS} main.c libfoo.a libbar.dylib -o main
+ # verify _foo got pulled in because _var was a tentative in main.o
+ nm main | grep "_foo" | ${FAIL_IF_EMPTY}
+ # verify -dead_strip pulls in non-tentative _var from libfoo.a
+ ${CC} ${CCFLAGS} main.c libfoo.a libbar.dylib -o main -dead_strip
+ nm -m main | grep "_var" | grep __data | ${FAIL_IF_EMPTY}
+ # verify dynamic_lookup works and has no duplicate symbols
+ ${CC} ${CCFLAGS} main.c libfoo.a -o main -undefined dynamic_lookup
+ nm -m main | grep "looked up" | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+ rm -rf main libfoo.a foo.o libbar.dylib
--- /dev/null
+void bar() {}
--- /dev/null
+
+extern void bar();
+
+void foo() { bar(); }
+
+int var = 9;
--- /dev/null
+
+int var;
+int other_tent;
+
+int main()
+{
+ var = 3;
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+# Test how tentative definitions interact with dylibs
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -Wl,-reexport_library,libbar.dylib
+ # verify -warn_commons works
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -Wl,-warn_commons 2> warnings.log
+ grep "using common symbol" warnings.log | ${FAIL_IF_EMPTY}
+ # verify -commons use_dylibs works
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -Wl,-commons,use_dylibs
+ nm -m main | grep _var | grep libfoo | ${FAIL_IF_EMPTY}
+ # verify -commons ignore_dylibs works
+ ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -Wl,-commons,ignore_dylibs
+ nm -m main | grep _var | grep __DATA | ${FAIL_IF_EMPTY}
+ # verify -commons error works
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c libfoo.dylib -o main -Wl,-commons,error 2> warnings.log
+ # verify -commons use_dylibs works with indirect dylibs
+ ${CC} ${CCFLAGS} main.c -Dvar=bar libfoo.dylib -o main -Wl,-commons,use_dylibs
+ nm -m main | grep _bar | grep libfoo | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+ rm -rf main libfoo.dylib libbar.dylib warnings.log
--- /dev/null
+void bar() {}
--- /dev/null
+void foo() {}
+int var = 9;
--- /dev/null
+
+int var;
+
+int main()
+{
+ var = 3;
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Verify that -r -d -exported_symbol_list uses proper relocations for hidden
+# newly defined (no longer tentative) definitions.
+#
+
+ifneq (${ARCH},x86_64)
+ BETTER_NOT_FIND = _tent
+else
+ # x86_64 uses a different style of relocations, so external relocs are ok to have
+ BETTER_NOT_FIND = blahblah
+endif
+
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.c -c -o test.o
+ ${FAIL_IF_BAD_OBJ} test.o
+
+ ${LD} -arch ${ARCH} -d -r test.o -exported_symbol _tent1 -o test-r.o
+ otool -rv test-r.o | grep ${BETTER_NOT_FIND} | ${PASS_IFF_EMPTY}
+
+
+clean:
+ rm -rf *.o
--- /dev/null
+
+// tentative definitions
+int tent1;
+int tent2;
+int __attribute__((visibility("hidden"))) tent3;
+
+// initialized to point to tentative definitions
+int* pa = &tent1;
+int* pb = &tent2;
+int* pc = &tent3;
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Test that references to commons survive -r -d
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.c -c -o test.${ARCH}.o
+ ${OBJECTDUMP} -no_content -no_definition -no_section -no_combine test.${ARCH}.o > test.${ARCH}.o.dump
+
+ ${LD} -arch ${ARCH} -r -d test.${ARCH}.o -o test-r-d.${ARCH}.o
+ ${OBJECTDUMP} -no_content -no_definition -no_section -no_combine test-r-d.${ARCH}.o > test-r-d.${ARCH}.o.dump
+
+ ${PASS_IFF} diff test.${ARCH}.o.dump test-r-d.${ARCH}.o.dump
+
+
+clean:
+ rm -rf *.o *.dump
+
--- /dev/null
+
+void foo() {}
+
+int a;
+int b;
+int c;
+
+
+
+int* pa = &a;
+int* pb = &b;
+int* pc = &c;
+
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# The point of this test is to verify that -r -d
+# will transform a tentative definition into a real one.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.c -c -o test.${ARCH}.o
+ ${FAIL_IF_BAD_OBJ} test.${ARCH}.o
+
+ ${LD} -arch ${ARCH} -r test.${ARCH}.o -o test-r.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} test-r.${ARCH}.o | grep tentative | ${FAIL_IF_EMPTY}
+
+ ${LD} -arch ${ARCH} -r -d test.${ARCH}.o -o test-r-d.${ARCH}.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} test-r-d.${ARCH}.o | grep tentative | ${PASS_IFF_EMPTY}
+
+clean:
+ rm -rf *.o
--- /dev/null
+The point of this test is to verify that -r -d will transform a tentative definition into a real one.
--- /dev/null
+
+// a tentative definition
+int a;
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Verify the linker parses call sites correctly.
+# The tricky case is thumb, which uses a blx to call to
+# the arm stubs. This test verifies that there is no
+# +2 error by checking for "plus" and that when the file
+# is regenerated through ld -r that the dumped output
+# remains unchanged.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.c -c -o test.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.o > test.o.dump
+ # verify no +2 errors
+ grep "plus" test.o.dump | ${FAIL_IF_STDIN}
+ # verify .o file can be regenerated to an equivalent state
+ ${LD} -arch ${ARCH} -r -keep_private_externs test.o -o test-r.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test-r.o > test-r.o.dump
+ # verify final linked image has no +2 errors
+ ${CC} ${CCFLAGS} test.o -o test
+ otool -tV -p _main test | grep blx | grep -v _malloc | ${FAIL_IF_STDIN}
+ ${CC} ${CCFLAGS} test-r.o -o test-r
+ otool -tV -p _main test-r | grep blx | grep -v _malloc | ${FAIL_IF_STDIN}
+ ${PASS_IFF} diff test.o.dump test-r.o.dump
+
+clean:
+ rm -rf test.o test-r.o test.o.dump test-r.o.dump test test-r
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdlib.h>
+
+int main()
+{
+ malloc(1);
+ malloc(2);
+ malloc(3);
+ malloc(4);
+ return 0;
+}
+
+
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# <rdar://problem/6401277> pointers to thumb symbols can be mangled
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ ${CC} ${CCFLAGS} bar.c -c -o bar.o
+ # verify no +1 thumb errors
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} foo.o | grep "plus 0x00000001" | ${FAIL_IF_STDIN}
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} bar.o | grep "plus 0x00000001" | ${FAIL_IF_STDIN}
+ ${LD} -arch ${ARCH} -r -keep_private_externs foo.o bar.o -o foobar.o
+ ${LD} -arch ${ARCH} -r -keep_private_externs foobar.o -o foobar2.o
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content foobar.o > foobar.o.dump
+ ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content foobar2.o > foobar2.o.dump
+ # verify no +1 thumb errors in merged result
+ grep "plus 0x00000001" foobar.o.dump | ${FAIL_IF_STDIN}
+ # verify round trip though ld -r works
+ ${PASS_IFF} diff foobar.o.dump foobar2.o.dump
+
+clean:
+ rm -rf foo.o bar.o foobar.o foobar2.o foobar.o.dump foobar2.o.dump
--- /dev/null
+
+void bar1() {}
+void bar2() {}
+char bar_array[3] = { 1,2,3 };
+
--- /dev/null
+
+
+extern void bar1();
+extern void bar2();
+extern char bar_array[];
+
+void foo1() {}
+void foo2() {}
+char foo_array[3] = { 1,2,3 };
+
+
+
+void* foostuff[] = { &foo1, &foo2, foo_array, &foo_array[3] };
+void* barstuff[] = { &bar1, &bar2, bar_array, &bar_array[3] };
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that main executable can use TLVs
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c get.s -o main
+ otool -lv main | grep S_THREAD_LOCAL_VARIABLES | ${FAIL_IF_EMPTY}
+ otool -lv main | grep S_THREAD_LOCAL_REGULAR | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm main
--- /dev/null
+
+ # _a is zerofill global TLV
+ .tbss _a$tlv$init,4,2
+
+ # _b is an initialized global TLV
+ .tdata
+_b$tlv$init:
+ .long 5
+
+ # _c is zerofill non-external TLV
+ .tbss _c$tlv$init,4,2
+
+ # _d is an initialized non-external TLV
+ .tdata
+_d$tlv$init:
+ .long 5
+
+#if __x86_64__
+
+ # _a is global TLV
+ .tlv
+ .globl _a
+_a: .quad __tlv_bootstrap
+ .quad 0
+ .quad _a$tlv$init
+
+ # _b is a global TLV
+ .tlv
+ .globl _b
+_b: .quad __tlv_bootstrap
+ .quad 0
+ .quad _b$tlv$init
+
+ # _c is a non-external TLV
+ .tlv
+_c: .quad __tlv_bootstrap
+ .quad 0
+ .quad _c$tlv$init
+
+ # _d is a non-external TLV
+ .tlv
+_d: .quad __tlv_bootstrap
+ .quad 0
+ .quad _d$tlv$init
+
+
+ .text
+ .globl _get_a
+_get_a:
+ pushq %rbp
+ movq %rsp, %rbp
+ movq _a@TLVP(%rip), %rdi
+ call *(%rdi)
+ popq %rbp
+ ret
+
+ .globl _get_b
+_get_b:
+ pushq %rbp
+ movq %rsp, %rbp
+ movq _b@TLVP(%rip), %rdi
+ call *(%rdi)
+ popq %rbp
+ ret
+
+ .globl _get_c
+_get_c:
+ pushq %rbp
+ movq %rsp, %rbp
+ movq _c@TLVP(%rip), %rdi
+ call *(%rdi)
+ popq %rbp
+ ret
+
+ .globl _get_d
+_get_d:
+ pushq %rbp
+ movq %rsp, %rbp
+ movq _d@TLVP(%rip), %rdi
+ call *(%rdi)
+ popq %rbp
+ ret
+
+#endif
+
+#if __i386__
+
+ # _a is global TLV
+ .tlv
+ .globl _a
+_a: .long __tlv_bootstrap
+ .long 0
+ .long _a$tlv$init
+
+ # _b is a global TLV
+ .tlv
+ .globl _b
+_b: .long __tlv_bootstrap
+ .long 0
+ .long _b$tlv$init
+
+ # _c is a non-external TLV
+ .tlv
+_c: .long __tlv_bootstrap
+ .long 0
+ .long _c$tlv$init
+
+ # _d is a non-external TLV
+ .tlv
+_d: .long __tlv_bootstrap
+ .long 0
+ .long _d$tlv$init
+
+
+ .text
+ .globl _get_a
+_get_a:
+ pushl %ebp
+ movl %esp, %ebp
+ subl $8, %esp
+ movl _a@TLVP, %eax
+ call *(%eax)
+ movl %ebp, %esp
+ popl %ebp
+ ret
+
+ .globl _get_b
+_get_b:
+ pushl %ebp
+ movl %esp, %ebp
+ subl $8, %esp
+ movl _b@TLVP, %eax
+ call *(%eax)
+ movl %ebp, %esp
+ popl %ebp
+ ret
+
+ .globl _get_c
+_get_c:
+ pushl %ebp
+ movl %esp, %ebp
+ subl $8, %esp
+ movl _c@TLVP, %eax
+ call *(%eax)
+ movl %ebp, %esp
+ popl %ebp
+ ret
+
+ .globl _get_d
+_get_d:
+ pushl %ebp
+ movl %esp, %ebp
+ subl $8, %esp
+ movl _d@TLVP, %eax
+ call *(%eax)
+ movl %ebp, %esp
+ popl %ebp
+ ret
+
+#endif
+
+.subsections_via_symbols
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+// work around until compiler supports __thread
+extern int* get_a();
+extern int* get_b();
+extern int* get_c();
+extern int* get_d();
+
+int main()
+{
+ get_a();
+ get_b();
+ get_c();
+ get_d();
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that main executable can use TLVs with -dead_strip
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -o main -dead_strip -mmacosx-version-min=10.7
+ otool -lv main | grep S_THREAD_LOCAL_VARIABLES | ${FAIL_IF_EMPTY}
+ otool -lv main | egrep 'S_THREAD_LOCAL_REGULAR|S_THREAD_LOCAL_ZEROFILL' | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm main
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+__thread int gTLSThreadID = 0;
+
+int foobar() {
+ return gTLSThreadID;
+}
+
+int main(void) {
+ return foobar();
+}
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Check that dylibs can export TLVs
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.s -dynamiclib -o libfoo.dylib
+ # check trying to access TLV _foo as regular variable is an error
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -DUSE_FOO libfoo.dylib -o main 2>/dev/null
+ # check trying to access regular variable _bar as TLV is an error
+ ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c getbar.s libfoo.dylib -o main 2>/dev/null
+ # check can link with TLV _foo in dylib
+ ${CC} ${CCFLAGS} main.c getfoo.s libfoo.dylib -o main
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf libfoo.dylib main
--- /dev/null
+
+// _foo is an exported thread local variable
+// _bar is an exported regular variable
+
+ # _a is zerofill global TLV
+ .tbss _a$tlv$init,4,2
+
+#if __x86_64__
+ .tlv
+ .globl _foo
+_foo: .quad __tlv_bootstrap
+ .quad 0
+ .quad _a$tlv$init
+
+
+#endif
+
+#if __i386__
+ .tlv
+ .globl _foo
+_foo: .long __tlv_bootstrap
+ .long 0
+ .long _a$tlv$init
+#endif
+
+
+ .data
+ .globl _bar
+_bar: .long 0
+
+
+
+ .subsections_via_symbols
--- /dev/null
+
+#if __x86_64__
+ .text
+ .globl _get_bar
+_get_bar:
+ pushq %rbp
+ movq %rsp, %rbp
+ movq _bar@TLVP(%rip), %rdi
+ call *(%rdi)
+ popq %rbp
+ ret
+#endif
+
+
+#if __i386__
+ .text
+ .globl _get_bar
+_get_bar:
+ pushl %ebp
+ movl %esp, %ebp
+ subl $8, %esp
+ movl _bar@TLVP, %eax
+ call *(%eax)
+ movl %ebp, %esp
+ popl %ebp
+ ret
+#endif
+
+.subsections_via_symbols
--- /dev/null
+
+#if __x86_64__
+ .text
+ .globl _get_foo
+_get_foo:
+ pushq %rbp
+ movq %rsp, %rbp
+ movq _foo@TLVP(%rip), %rdi
+ call *(%rdi)
+ popq %rbp
+ ret
+#endif
+
+
+#if __i386__
+ .text
+ .globl _get_foo
+_get_foo:
+ pushl %ebp
+ movl %esp, %ebp
+ subl $8, %esp
+ movl _foo@TLVP, %eax
+ call *(%eax)
+ movl %ebp, %esp
+ popl %ebp
+ ret
+#endif
+
+.subsections_via_symbols
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#if USE_FOO
+ extern int foo;
+#endif
+
+int main()
+{
+#if USE_FOO
+ foo = 1;
+#endif
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2012 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that main executable can use TLVs with -dead_strip
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o #-mdynamic-no-pic
+ ${LD} -arch ${ARCH} -r foo.o -o foo-r.o
+ ${OBJECTDUMP} foo.o > foo.o.dump
+ ${OBJECTDUMP} foo-r.o > foo-r.o.dump
+ ${PASS_IFF} diff foo.o.dump foo-r.o.dump
+
+clean:
+ rm -f foo.o foo-r.o foo.o.dump foo-r.o.dump
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+__thread int a = 0;
+__thread static int b = 0;
+extern __thread int c;
+
+int foo() {
+ return a+b+c;
+}
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test out building an umbrella dylib. a and c are co-dependent. b depends on c.
+#
+
+
+run: all
+
+all:
+ # build bootstrap dylib of with all code
+ ${CC} ${CCFLAGS} -dynamiclib a.c b.c c.c -o libBig.stub -install_name /usr/lib/libBig.dylib
+ # link each sub library against bootstrap to intra-Big symbols
+ ${CC} ${CCFLAGS} -dynamiclib a.c -o liba.dylib libBig.stub -install_name /usr/local/lib/big/liba.dylib -umbrella Big
+ ${CC} ${CCFLAGS} -dynamiclib b.c -o libb.dylib libBig.stub -install_name /usr/local/lib/big/libb.dylib -umbrella Big
+ ${CC} ${CCFLAGS} -dynamiclib c.c -o libc.dylib libBig.stub -install_name /usr/local/lib/big/libc.dylib -umbrella Big
+ ${CC} ${CCFLAGS} -dynamiclib -Wl,-reexport_library,liba.dylib -Wl,-reexport_library,libb.dylib -Wl,-reexport_library,libc.dylib -o libBig.dylib -install_name /usr/lib/libBig.dylib
+ # re-link against correct dylibs now that everything is built
+ ${CC} ${CCFLAGS} -dynamiclib a.c -o liba.dylib libc.dylib -install_name /usr/local/lib/big/liba.dylib -umbrella Big
+ ${DYLDINFO} -lazy_bind liba.dylib | grep c2 | grep libc | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} -dynamiclib b.c -o libb.dylib libc.dylib -install_name /usr/local/lib/big/libb.dylib -umbrella Big
+ ${CC} ${CCFLAGS} -dynamiclib c.c -o libc.dylib liba.dylib -install_name /usr/local/lib/big/libc.dylib -umbrella Big
+ ${DYLDINFO} -lazy_bind libc.dylib | grep a2 | grep liba | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} -dynamiclib -Wl,-reexport_library,liba.dylib -Wl,-reexport_library,libb.dylib -Wl,-reexport_library,libc.dylib -o libBig.dylib -install_name /usr/lib/libBig.dylib
+ ${CC} ${CCFLAGS} main.c -o main libBig.dylib -L.
+ ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+
+ rm -rf libBig.stub liba.dylib libb.dylib libc.dylib libBig.dylib main
--- /dev/null
+
+extern void c2();
+
+void a1(void)
+{
+ c2();
+}
+
+void a2(void)
+{
+}
--- /dev/null
+
+extern void c1();
+
+void b1(void)
+{
+ c1();
+}
--- /dev/null
+
+extern void a2();
+
+void c1(void)
+{
+ a2();
+}
+
+void c2(void)
+{
+}
--- /dev/null
+extern void c1();
+extern void a1();
+int main()
+{
+ a1();
+ c1();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2007-2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that -U and -undefined dynamic_lookup work
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -o main -undefined dynamic_lookup
+ nm -m main | grep _foo | grep "dynamically looked up" | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -lazy_bind -bind main | grep _foo | grep "flat-namespace" | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -lazy_bind -bind main | grep _exit | grep "flat-namespace" | ${FAIL_IF_STDIN}
+ ${FAIL_IF_BAD_MACHO} main
+
+ ${CC} ${CCFLAGS} main.c -o main -Wl,-U,_foo
+ nm -m main | grep _foo | grep "dynamically looked up" | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -lazy_bind -bind main | grep _foo | grep "flat-namespace" | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -lazy_bind -bind main | grep _exit | grep "flat-namespace" | ${FAIL_IF_STDIN}
+ ${FAIL_IF_BAD_MACHO} main
+
+ ${CC} ${CCFLAGS} main.c -o main -flat_namespace -Wl,-U,_foo
+ nm -m main | grep _foo | grep "dynamically looked up" | ${FAIL_IF_STDIN}
+ ${DYLDINFO} -lazy_bind -bind main | grep _foo | grep "flat-namespace" | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -lazy_bind -bind main | grep _exit | grep "flat-namespace" | ${FAIL_IF_EMPTY}
+ ${FAIL_IF_BAD_MACHO} main
+
+ ${CC} ${CCFLAGS} main.c -bundle -o main.bundle -nodefaultlibs -undefined dynamic_lookup
+ nm -m main.bundle | grep _foo | grep "dynamically looked up" | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -lazy_bind -bind main.bundle | grep _foo | grep "flat-namespace" | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -lazy_bind -bind main.bundle | grep _exit | grep "flat-namespace" | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} main.bundle
+
+
+
+clean:
+ rm -f main main.bundle
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+extern void foo();
+
+int main()
+{
+ foo();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Verify -unexported_symbols_list works with -r
+# <rdar://problem/5905900> Building kext x86_64 with unexported symbols file causes linking problems
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ ${LD} -arch ${ARCH} foo.o -r -unexported_symbols_list foo.exp -o foo2.o
+ nm -m foo2.o | grep _foo | grep "non-external" | ${PASS_IFF_STDIN}
+
+clean:
+ rm -rf foo.o foo2.o
--- /dev/null
+
+extern int fooCount;
+extern int barCount;
+
+void foo() { fooCount++; }
+void bar() { barCount++; }
+int global = 4;
+int googoo = 5;
+
--- /dev/null
+_foo
+_global
+
--- /dev/null
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that a dynamically referenced symbol is always exported
+#
+
+run: all
+
+all:
+ ${CC} foo.c -dynamiclib -o libfoo.dylib
+ nm -m libfoo.dylib | grep _keep_global | grep "referenced dynamically" | ${FAIL_IF_EMPTY}
+ nm -m libfoo.dylib | grep _keep_hidden | grep "referenced dynamically" | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+clean:
+ rm libfoo.dylib
--- /dev/null
+#include <stddef.h>
+
+int keep_global = 1;
+asm(".desc _keep_global, 0x10");
+
+__attribute__((visibility("hidden"))) int keep_hidden = 1;
+asm(".desc _keep_hidden, 0x10");
+
+static int keep_static = 1;
+asm(".desc _keep_static, 0x10");
+
+
+int lose_global = 1;
+
+__attribute__((visibility("hidden"))) int lose_hidden = 1;
+
+static int lose_static = 1;
+
+
+
+int get()
+{
+ return keep_global + keep_hidden + keep_static + lose_global + lose_hidden + lose_static;
+}
--- /dev/null
+##
+# Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that utf16 cfstring literals are coalesced.
+# There is 3 CFSTR in foo.m and 1 CFSTR in bar.m
+# After coalescing and dead stripping there should be only two CFSTR in the output
+#
+
+
+all:
+ ${CC} ${CCFLAGS} withnul.s -c -o withnul.o
+ ${CC} ${CCFLAGS} other.s -c -o other.o
+ ${LD} -r -arch ${ARCH} withnul.o other.o -o all.o
+ size -l all.o | grep "__ustring): 44" | ${PASS_IFF_STDIN}
+
+
+clean:
+ rm -rf withnul.o other.o all.o
--- /dev/null
+
+
+ .section __TEXT,__ustring
+ .align 1
+___utf16_string_3:
+ .short 0x00fc, 0x0062, 0x0065, 0x0072, 0x0000
+
+___utf16_string_4:
+ .short 0x0073, 0x0074, 0x00fc, 0x0066, 0x0066, 0x0000
+
+
+
--- /dev/null
+
+
+ .section __TEXT,__ustring
+ .align 1
+___utf16_string_1:
+ .short 0x00fc, 0x0062, 0x0065, 0x0072, 0x0000, 0x0073, 0x0074, 0x00fc, 0x0066, 0x0066, 0x0000
+
+
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that a late loaded hidden symbol from an archive does not conflict
+# with a symbol previously found in a dylib.
+# <rdar://problem/5342320> gcc 4.2: DejaGnu failures due to libgcc visibility issues with -m64 -mmacosx-version-min=10.4 (G5)
+#
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+ ${CC} ${CCFLAGS} -c bar.c -o bar.o
+ libtool -static bar.o -o libbar.a
+ ${CC} ${CCFLAGS} main.c -o main libfoo.dylib libbar.a 2>warning.log
+ cat warning.log | ${PASS_IFF_EMPTY}
+
+
+clean:
+ rm -f libfoo.dylib bar.o libbar.a main warning.log
--- /dev/null
+
+
+void __attribute__((weak,visibility("hidden"))) foo()
+{
+
+}
+
+
+void bar()
+{
+}
--- /dev/null
+
+
+void __attribute__((weak)) foo()
+{
+}
--- /dev/null
+
+extern void foo();
+extern void bar();
+
+
+int main()
+{
+ foo();
+ bar();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2007-2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that two weak symbols with different visibility causes a warning
+# and a weak and strong with different visibilities do not cause a warning.
+# <rdar://problem/5459546> Spurious link warnings for inline members of C++ template classes
+#
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -c foo_weak_hidden.c -o foo_weak_hidden.o
+ ${CC} ${CCFLAGS} -c foo_weak.c -o foo_weak.o
+ ${CC} ${CCFLAGS} -c foo.c -o foo.o
+ ${CC} ${CCFLAGS} -c foo_hidden.c -o foo_hidden.o
+ # weak default and weak hidden should pick default
+ ${CC} ${CCFLAGS} foo_weak_hidden.o foo_weak.o -dynamiclib -o libfoo.dylib
+ nm -m libfoo.dylib | grep _foo | grep "private external" | ${FAIL_IF_STDIN}
+ # weak default and weak hidden should pick default
+ ${CC} ${CCFLAGS} foo_weak.o foo_weak_hidden.o -dynamiclib -o libfoo.dylib
+ nm -m libfoo.dylib | grep _foo | grep "private external" | ${FAIL_IF_STDIN}
+ # weak hidden and strong should not warn and pick strong
+ ${CC} ${CCFLAGS} foo_weak_hidden.o foo.o -dynamiclib -o libfoo.dylib
+ nm -m libfoo.dylib | grep _foo | grep weak | ${FAIL_IF_STDIN}
+ nm -m libfoo.dylib | grep _foo | grep "private external" | ${FAIL_IF_STDIN}
+ # weak default and strong hidden should not warn and pick hidden
+ ${CC} ${CCFLAGS} foo_weak.o foo_hidden.o -dynamiclib -o libfoo.dylib
+ nm -m libfoo.dylib | grep _foo | grep weak | ${FAIL_IF_STDIN}
+ nm -m libfoo.dylib | grep _foo | grep "private external" | ${FAIL_IF_EMPTY}
+ # weak default and strong hidden should not warn and pick hidden
+ ${CC} ${CCFLAGS} foo_hidden.o foo_weak.o -dynamiclib -o libfoo.dylib
+ nm -m libfoo.dylib | grep _foo | grep weak | ${FAIL_IF_STDIN}
+ nm -m libfoo.dylib | grep _foo | grep "private external" | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+clean:
+ rm libfoo.dylib foo_weak_hidden.o foo_weak.o foo.o foo_hidden.o warnings.log
--- /dev/null
+
+
+void foo()
+{
+}
--- /dev/null
+
+
+void __attribute__((visibility("hidden"))) foo()
+{
+}
--- /dev/null
+
+
+void __attribute__((weak)) foo()
+{
+}
--- /dev/null
+
+
+void __attribute__((weak, visibility("hidden"))) foo()
+{
+}
--- /dev/null
+##
+# Copyright (c) 2010Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Tests weak-external and weak-can-be-hidden symbols work.
+#
+
+run: all
+
+all:
+ # test that _my_other_weak is hidden
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ ${CC} ${CCFLAGS} other.s -c -o other.o
+ ${CC} ${CCFLAGS} main.o other.o -o main
+ nm -m main | grep _my_weak | grep "weak external" | ${FAIL_IF_EMPTY}
+ nm -m main | grep _my_other_weak | grep "non-external" | ${FAIL_IF_EMPTY}
+ ${FAIL_IF_BAD_MACHO} main
+ # test that .exp file can override auto-hide
+ ${CC} ${CCFLAGS} main.o other.o -o main2 -Wl,-exported_symbol,_my_other_weak
+ nm -m main2 | grep _my_weak | grep "non-external" | ${FAIL_IF_EMPTY}
+ nm -m main2 | grep _my_other_weak | grep "weak external" | ${FAIL_IF_EMPTY}
+ ${FAIL_IF_BAD_MACHO} main2
+ ${CC} ${CCFLAGS} main.o other.o -o main2 -Wl,-exported_symbol,_main
+ nm -m main2 | grep _my_weak | grep "non-external" | ${FAIL_IF_EMPTY}
+ nm -m main2 | grep _my_other_weak | grep "non-external" | ${FAIL_IF_EMPTY}
+ ${FAIL_IF_BAD_MACHO} main2
+ # test that auto-hide bit survives ld -r
+ ${LD} -r -arch ${ARCH} other.o -o other-r.o
+ ${OBJECTDUMP} other.o > other.o.dump
+ ${OBJECTDUMP} other-r.o > other-r.o.dump
+ ${PASS_IFF} diff other.o.dump other-r.o.dump
+
+clean:
+ rm -f main.o other.o main main2 other-r.o other.o.dump other-r.o.dump
--- /dev/null
+#include <stdio.h>
+
+void __attribute__((weak)) my_weak()
+{
+}
+
+extern void my_other_weak();
+
+int main()
+{
+ my_weak();
+ my_other_weak();
+ return 0;
+}
+
--- /dev/null
+
+
+ .text
+ .align 4
+
+ .globl _my_weak
+ .weak_def_can_be_hidden _my_weak
+_my_weak: nop
+ nop
+
+
+ .globl _my_other_weak
+ .weak_def_can_be_hidden _my_other_weak
+_my_other_weak: nop
+ nop
+
--- /dev/null
+##
+# Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+#
+# Tests that a main executable with a weak symbol has MH_WEAK_DEFINES
+# Tests that a main executable with a weak symbol made non-global by
+# an export list does not has MH_WEAK_DEFINES
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -o main
+ otool -hv main | grep WEAK_DEFINES | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} main.c -o main -Wl,-exported_symbol,_main
+ otool -hv main | grep WEAK_DEFINES | ${FAIL_IF_STDIN}
+ ${CC} ${CCFLAGS} main.c -o main -Wl,-exported_symbol,_my_weak
+ otool -hv main | grep WEAK_DEFINES | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} main-strip-weak.c -o main-strip-weak
+ otool -hv main-strip-weak | grep WEAK_DEFINES | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -f main main-strip-weak
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+
+// the 'l' prefix makes this an auto-strip symbol
+void my_auto_strip_weak() __asm ( "lautostrip" );
+
+void __attribute__((weak)) my_auto_strip_weak()
+{
+
+}
+
+int main()
+{
+ my_auto_strip_weak();
+ return 0;
+}
+
--- /dev/null
+#include <stdio.h>
+
+void __attribute__((weak)) my_weak()
+{
+
+}
+
+int main()
+{
+ my_weak();
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+# <rdar://problem/9551362> clang ld: bad codegen, pointer diff
+# Test that codegen needing direct access to a weak symbol just issues
+# a warning. Check that if export list makes weak symbol hidden, there is
+# no warning.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} myglobal.c myhidden.s -dynamiclib -o libmy.dylib 2>warnings.txt
+ grep "global weak" warnings.txt | ${FAIL_IF_EMPTY}
+ ${FAIL_IF_BAD_MACHO} libmy.dylib
+ ${CC} ${CCFLAGS} myglobal.c myhidden.s -dynamiclib -Wl,-exported_symbol,_test -o libmy2.dylib
+ ${PASS_IFF_GOOD_MACHO} libmy2.dylib
+
+clean:
+ rm -f libmy.dylib libmy2.dylib warnings.txt
--- /dev/null
+
+__attribute__((weak))
+int myweak = 10;
+
--- /dev/null
+ .data
+ .globl _myweak
+ .private_extern _myweak
+ .weak_definition _myweak
+_myweak:
+ .long 0
+
+
+ .text
+ .align 2
+#if __ARM_ARCH_7A__
+ .code 16
+ .thumb_func _test
+#endif
+
+ .globl _test
+_test:
+#if __x86_64__
+ nop
+ movl _myweak(%rip), %eax
+ ret
+#elif __i386__
+ call L1
+L1: popl %eax
+ movl _myweak-L1(%eax), %eax
+ ret
+#elif __arm__
+
+#if __ARM_ARCH_7A__
+ movw r0, :lower16:(_myweak-(L4+4))
+ movt r0, :upper16:(_myweak-(L4+4))
+L4: add r0, pc
+ ldr r0, [r0]
+ bx lr
+#else
+ ldr r0, L2
+L3: ldr r0, [pc, r0]
+ bx lr
+ .align 2
+L2: .long _myweak-(L3+8)
+#endif
+
+
+#endif
+
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# libfoo.dylib has weak defintiion of _foo
+# libbar.dylib has strong defintiion of _foo
+#
+# Tests that if you link against libfoo.dylib and libbar.dylib
+# that the two-level-namespace ordinal is set to the non-weak definition
+#
+#<rdar://problem/5137732> ld should keep looking when it finds a weak definition in a dylib#
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} main.c -o main libfoo.dylib libbar.dylib
+ nm -m main | grep _aaa | grep libbar | ${FAIL_IF_EMPTY}
+ nm -m main | grep _bbb | grep libfoo | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm libfoo.dylib libbar.dylib main
--- /dev/null
+
+int aaa()
+{
+ return 1;
+}
+
--- /dev/null
+
+int __attribute__((weak)) aaa()
+{
+ return 0;
+}
+
+int __attribute__((weak)) bbb()
+{
+ return 0;
+}
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+extern void aaa();
+extern void bbb();
+
+int main()
+{
+ aaa();
+ bbb();
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -dynamiclib -Wl,-force_symbols_weak_list foo1.exp foo.c -o libfoo.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ nm -m libfoo.dylib | grep _foo1 | grep weak | ${FAIL_IF_EMPTY}
+ nm -m libfoo.dylib | grep _wildcheck | grep weak | ${FAIL_IF_EMPTY}
+ nm -m libfoo.dylib | grep _foo3 | grep weak | ${FAIL_IF_STDIN}
+ nm -m libfoo.dylib | grep _willnot | grep weak | ${FAIL_IF_STDIN}
+ ${CC} ${CCFLAGS} -dynamiclib -Wl,-force_symbols_not_weak_list foo2.exp foo.c -o libfoo.dylib
+ nm -m libfoo.dylib | grep _foo2 | grep weak | ${FAIL_IF_STDIN}
+ nm -m libfoo.dylib | grep _patterncheck | grep weak | ${FAIL_IF_STDIN}
+ nm -m libfoo.dylib | grep _foo4 | grep weak | ${FAIL_IF_EMPTY}
+ nm -m libfoo.dylib | grep _patnot | grep weak | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+
+
+clean:
+ rm -rf libfoo.dylib
--- /dev/null
+
+
+void foo1() {}
+void foo3() {}
+
+
+__attribute__((weak)) void foo2() {}
+__attribute__((weak)) void foo4() {}
+
+
+void wildcheck() {}
+void willnot() {}
+
+
+
+__attribute__((weak)) void patterncheck() {}
+__attribute__((weak)) void patnot() {}
--- /dev/null
+_foo1
+_wild*
--- /dev/null
+_foo2
+_pattern*
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test the if all symbols from a dylib are weak_import, that the whole dylib is weakly loaded
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+
+ ${CC} ${CCFLAGS} ${VERSION_OLD_LINKEDIT} main.c -o main libfoo.dylib libbar.dylib
+ # libfoo.dylib should be weakly loaded because all symbols are weakly imported
+ otool -lv main | grep -B2 libfoo.dylib | grep LC_LOAD_WEAK_DYLIB | ${FAIL_IF_EMPTY}
+ # libbar.dylib should not be weakly loaded because _bar1 is not weakly imported
+ otool -lv main | grep -B2 libbar.dylib | grep LC_LOAD_DYLIB | ${FAIL_IF_EMPTY}
+ ${FAIL_IF_BAD_MACHO} main
+
+ ${CC} ${CCFLAGS} ${VERSION_NEW_LINKEDIT} main.c -o main2 libfoo.dylib libbar.dylib
+ # libfoo.dylib should be weakly loaded because all symbols are weakly imported
+ otool -lv main2 | grep -B2 libfoo.dylib | grep LC_LOAD_WEAK_DYLIB | ${FAIL_IF_EMPTY}
+ # libbar.dylib should not be weakly loaded because _bar1 is not weakly imported
+ otool -lv main2 | grep -B2 libbar.dylib | grep LC_LOAD_DYLIB | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main2
+
+ ${CC} ${CCFLAGS} ${VERSION_NEW_LINKEDIT} data.c -o data libfoo.dylib libbar.dylib
+ # libfoo.dylib should be weakly loaded because all symbols are weakly imported
+ otool -lv data | grep -B2 libfoo.dylib | grep LC_LOAD_WEAK_DYLIB | ${FAIL_IF_EMPTY}
+ # libbar.dylib should not be weakly loaded because _bar1 is not weakly imported
+ otool -lv data | grep -B2 libbar.dylib | grep LC_LOAD_DYLIB | ${FAIL_IF_EMPTY}
+ ${FAIL_IF_BAD_MACHO} data
+
+ ${CC} ${CCFLAGS} ${VERSION_NEW_LINKEDIT} data.c -o data2 libfoo.dylib libbar.dylib
+ # libfoo.dylib should be weakly loaded because all symbols are weakly imported
+ otool -lv data2 | grep -B2 libfoo.dylib | grep LC_LOAD_WEAK_DYLIB | ${FAIL_IF_EMPTY}
+ # libbar.dylib should not be weakly loaded because _bar1 is not weakly imported
+ otool -lv data2 | grep -B2 libbar.dylib | grep LC_LOAD_DYLIB | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} data2
+
+clean:
+ rm -rf libfoo.dylib libbar.dylib main main2 data data2
--- /dev/null
+
+
+#include "bar.h"
+
+void bar1() {}
+void bar2() {}
+void bar3() {}
+void bar4() {}
+
--- /dev/null
+
+
+extern void bar1();
+extern void bar2() __attribute__((weak_import));
+extern void bar3();
+extern void bar4() __attribute__((weak_import));
+
+
+
--- /dev/null
+
+#include "foo.h"
+#include "bar.h"
+
+void* pfoo4 = &foo4;
+void* pfoo2 = &foo2;
+
+void* pbar2 = &bar2;
+void* pbar1 = &bar1; // not weak
+
+int main (void)
+{
+ return 0;
+}
+
--- /dev/null
+
+
+#include "foo.h"
+
+void foo1() {}
+void foo2() {}
+void foo3() {}
+void foo4() {}
+
--- /dev/null
+
+
+extern void foo1();
+extern void foo2() __attribute__((weak_import));
+extern void foo3();
+extern void foo4() __attribute__((weak_import));
--- /dev/null
+
+#include "foo.h"
+#include "bar.h"
+
+void* p;
+
+int main (void)
+{
+ // non-lazy reference to foo2
+ p = &foo2;
+ // lazy reference to foo4
+ foo4();
+
+ // non-lazy reference to bar2
+ p = &bar2;
+ // lazy reference to bar4 and bar1
+ bar4();
+ bar1();
+
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test the weak_import attribute works
+#
+
+all: all-${ARCH}
+
+all-ppc: all-true
+
+all-ppc64: all-true
+
+all-i386: all-true
+
+all-armv6: all-true
+
+all-armv7: all-true
+
+all-true:
+ ${PASS_IFF} true
+
+all-x86_64:
+ ${CC} ${CCFLAGS} -dynamiclib test.s -o libtest.dylib -mmacosx-version-min=10.6
+ ${DYLDINFO} -bind -lazy_bind libtest.dylib | grep _malloc | grep weak | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -bind -lazy_bind libtest.dylib | grep _free | grep weak | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libtest.dylib
+
+clean:
+ rm -rf libtest.dylib
--- /dev/null
+
+
+ .text
+_foo:
+#if __x86_64__
+ .weak_reference _malloc
+ .weak_reference _free
+ cmpq $0, _malloc@GOTPCREL(%rip)
+ cmpq $0xFFFF, _free@GOTPCREL(%rip)
+#endif
+ nop
+
--- /dev/null
+##
+# Copyright (c) 2008 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that -weak_library marks all symbols used as weak
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo.dylib
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib
+ ${FAIL_IF_BAD_MACHO} libbar.dylib
+ ${CC} ${CCFLAGS} main.c -o main -weak_library libfoo.dylib libbar.dylib
+ nm -m main | grep _foo1 | grep weak | ${FAIL_IF_EMPTY}
+ nm -m main | grep _bar | grep weak | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf libfoo.dylib libbar.dylib main
--- /dev/null
+
+
+
+void bar1() {}
+void bar2() {}
+
+
+int bar_data1 = 0;
+int bar_data2 = 0;
--- /dev/null
+
+
+
+void foo1() {}
+void foo2() {}
+
+
+int foo_data1 = 0;
+int foo_data2 = 0;
--- /dev/null
+
+extern void foo1();
+extern void foo2();
+extern void bar1();
+extern void bar2();
+
+extern int foo_data1;
+extern int foo_data2;
+extern int bar_data1;
+extern int bar_data2;
+
+
+
+// make external relocation to foo_data1 and bar_data1
+int* pfoo = &foo_data1;
+int* pbar = &bar_data1;
+
+void* pfoo1;
+void* pbar1;
+
+int main (void)
+{
+ // make non-lazy reference to foo1 and bar1
+ pfoo1 = &foo1;
+ pbar1 = &bar1;
+
+ // make lazy reference to foo2 and bar2
+ foo2();
+ bar2();
+
+ // make non-lazy reference to foo_data2 and bar_data2
+ return *pfoo + *pbar + foo_data2 + bar_data2;
+}
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that setting weak_import on symbols in a linkage unit works
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c foo.c -o main
+ ${FAIL_IF_BAD_MACHO} main
+ ${CC} ${CCFLAGS} main.c foo.c -o main ${VERSION_OLD_LINKEDIT}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main
--- /dev/null
+
+
+#include "foo.h"
+
+void func2() {}
+int data2 = 0; // weak_import initialized
+
--- /dev/null
+
+
+extern void func2() __attribute__((weak_import));
+
+extern int data2 __attribute__((weak_import));
+
--- /dev/null
+#include <stddef.h>
+
+#include "foo.h"
+
+void* pf2 = &func2;
+int* pd2 = &data2;
+
+int main (void)
+{
+ if ( &func2 != NULL )
+ func2();
+
+ if ( &data2 != NULL )
+ data2 = 1;
+
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2012 Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test the weak_import attribute is preserved in -r mode.
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ nm -m main.o | grep _func1 | grep -v weak >/dev/null
+ nm -m main.o | grep _func2 | grep weak >/dev/null
+ nm -m main.o | grep _func3 | grep -v weak >/dev/null
+ nm -m main.o | grep _func4 | grep weak >/dev/null
+ nm -m main.o | grep _data1 | grep -v weak >/dev/null
+ nm -m main.o | grep _data2 | grep weak >/dev/null
+ nm -m main.o | grep _data3 | grep -v weak >/dev/null
+ nm -m main.o | grep _data4 | grep weak >/dev/null
+ nm -m main.o | grep _data5 | grep -v weak >/dev/null
+ nm -m main.o | grep _data6 | grep weak >/dev/null
+
+ ${LD} -r -arch ${ARCH} main.o -o main-r.o
+ nm -m main-r.o | grep _func1 | grep -v weak >/dev/null
+ nm -m main-r.o | grep _func2 | grep weak >/dev/null
+ nm -m main-r.o | grep _func3 | grep -v weak >/dev/null
+ nm -m main-r.o | grep _func4 | grep weak >/dev/null
+ nm -m main-r.o | grep _data1 | grep -v weak >/dev/null
+ nm -m main-r.o | grep _data2 | grep weak >/dev/null
+ nm -m main-r.o | grep _data3 | grep -v weak >/dev/null
+ nm -m main-r.o | grep _data4 | grep weak >/dev/null
+ ${PASS_IFF} true
+
+clean:
+ rm -rf *.o
--- /dev/null
+
+
+extern void func1();
+extern void func2() __attribute__((weak_import));
+extern void func3();
+extern void func4() __attribute__((weak_import));
+
+extern int data1;
+extern int data2 __attribute__((weak_import));
+extern int data3;
+extern int data4 __attribute__((weak_import));
+extern int data5;
+extern int data6 __attribute__((weak_import));
+
+
+
--- /dev/null
+#include <stddef.h>
+
+#include "foo.h"
+
+
+int* pdata5 = &data5;
+int* pdata6 = &data6;
+
+void* pf3;
+
+int main (void)
+{
+ // make non-lazy reference to func3 and func4
+ pf3 = &func3;
+ if ( &func4 == NULL ) {
+ // make lazy reference to func1 and func2
+ func1();
+ func2();
+ }
+
+ return data1 + data2 + data3 + data4;
+}
+
--- /dev/null
+##
+# Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that setting weak_import on symbols in a linkage unit works
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -o weak weak.c -undefined dynamic_lookup
+ ${DYLDINFO} -bind weak | grep _myweakfunc | grep "weak import" | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -lazy_bind weak | grep _myweakfunc | grep "weak import" | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} weak
+
+clean:
+ rm -rf main
--- /dev/null
+#include <stdio.h>
+
+char *myweakfunc(void) __attribute__((weak)) ;
+
+int main(int argc, char **argv)
+{
+ if (myweakfunc)
+ printf ("found myweakfunc %s\n", myweakfunc());
+ else
+ printf("Weak func not found\n");
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test the weak_import attribute works
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -dynamiclib -single_module foo.c -o libfoo-${ARCH}.dylib
+ ${FAIL_IF_BAD_MACHO} libfoo-${ARCH}.dylib
+
+ ${CC} ${CCFLAGS} main.c -o main-${ARCH} libfoo-${ARCH}.dylib
+ nm -m main-${ARCH} | grep _func1 | grep -v weak >/dev/null
+ nm -m main-${ARCH} | grep _func2 | grep weak >/dev/null
+ nm -m main-${ARCH} | grep _func3 | grep -v weak >/dev/null
+ nm -m main-${ARCH} | grep _func4 | grep weak >/dev/null
+ nm -m main-${ARCH} | grep _data1 | grep -v weak >/dev/null
+ nm -m main-${ARCH} | grep _data2 | grep weak >/dev/null
+ nm -m main-${ARCH} | grep _data3 | grep -v weak >/dev/null
+ nm -m main-${ARCH} | grep _data4 | grep weak >/dev/null
+ nm -m main-${ARCH} | grep _data5 | grep -v weak >/dev/null
+ nm -m main-${ARCH} | grep _data6 | grep weak >/dev/null
+ #otool -rv main-${ARCH} | grep _data6 > /dev/null
+ ${FAIL_IF_BAD_MACHO} main-${ARCH}
+
+ ${CC} ${CCFLAGS} main.c -dynamiclib -o main-${ARCH}.dylib libfoo-${ARCH}.dylib
+ nm -m main-${ARCH}.dylib | grep _func1 | grep -v weak >/dev/null
+ nm -m main-${ARCH}.dylib | grep _func2 | grep weak >/dev/null
+ nm -m main-${ARCH}.dylib | grep _func3 | grep -v weak >/dev/null
+ nm -m main-${ARCH}.dylib | grep _func4 | grep weak >/dev/null
+ nm -m main-${ARCH}.dylib | grep _data1 | grep -v weak >/dev/null
+ nm -m main-${ARCH}.dylib | grep _data2 | grep weak >/dev/null
+ nm -m main-${ARCH}.dylib | grep _data3 | grep -v weak >/dev/null
+ nm -m main-${ARCH}.dylib | grep _data4 | grep weak >/dev/null
+ #otool -rv main-${ARCH}.dylib | grep _data6 > /dev/null
+ ${PASS_IFF_GOOD_MACHO} main-${ARCH}.dylib
+
+clean:
+ rm -rf *.dylib main-*
--- /dev/null
+
+
+#include "foo.h"
+
+void func1() {}
+void func2() {}
+void func3() {}
+void func4() {}
+
+
+int data1 = 0;
+int data2 = 0; // weak_import initialized
+int data3;
+int data4; // weak_import uninitialized
+int data5 = 0;
+int data6 = 0; // weak_import
+
--- /dev/null
+
+
+extern void func1();
+extern void func2() __attribute__((weak_import));
+extern void func3();
+extern void func4() __attribute__((weak_import));
+
+extern int data1;
+extern int data2 __attribute__((weak_import));
+extern int data3;
+extern int data4 __attribute__((weak_import));
+extern int data5;
+extern int data6 __attribute__((weak_import));
+
+
+
--- /dev/null
+#include <stddef.h>
+
+#include "foo.h"
+
+
+int* pdata5 = &data5;
+int* pdata6 = &data6;
+
+void* pf3;
+
+int main (void)
+{
+ // make non-lazy reference to func3 and func4
+ pf3 = &func3;
+ if ( &func4 == NULL ) {
+ // make lazy reference to func1 and func2
+ func1();
+ func2();
+ }
+
+ return data1 + data2 + data3 + data4;
+}
+
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test the weak_import attribute works
+#
+
+
+run: all
+
+all:
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c foo.c -o foo-${ARCH}.o
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -c foo1.c -o foo1-${ARCH}.o
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -dynamiclib foo-${ARCH}.o foo1-${ARCH}.o -o libfoo-${ARCH}.dylib
+ ${PASS_IFF_ERROR} ${CC} ${CCFLAGS} -mmacosx-version-min=10.4 main.c -o main-${ARCH} libfoo-${ARCH}.dylib
+ nm -m main-${ARCH} | grep _func1 | grep -v weak >/dev/null
+ nm -m main-${ARCH} | grep _func2 | grep weak >/dev/null
+ nm -m main-${ARCH} | grep _func3 | grep -v weak >/dev/null
+ nm -m main-${ARCH} | grep _func4 | grep weak >/dev/null
+ nm -m main-${ARCH} | grep _data1 | grep -v weak >/dev/null
+ nm -m main-${ARCH} | grep _data2 | grep weak >/dev/null
+ nm -m main-${ARCH} | grep _data3 | grep -v weak >/dev/null
+ nm -m main-${ARCH} | grep _data4 | grep weak >/dev/null
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -mmacosx-version-min=10.4 main.c -dynamiclib -o main-${ARCH}.dylib libfoo-${ARCH}.dylib
+ nm -m main-${ARCH}.dylib | grep _func1 | grep -v weak >/dev/null
+ nm -m main-${ARCH}.dylib | grep _func2 | grep weak >/dev/null
+ nm -m main-${ARCH}.dylib | grep _func3 | grep -v weak >/dev/null
+ nm -m main-${ARCH}.dylib | grep _func4 | grep weak >/dev/null
+ nm -m main-${ARCH}.dylib | grep _data1 | grep -v weak >/dev/null
+ nm -m main-${ARCH}.dylib | grep _data2 | grep weak >/dev/null
+ nm -m main-${ARCH}.dylib | grep _data3 | grep -v weak >/dev/null
+ nm -m main-${ARCH}.dylib | grep _data4 | grep weak >/dev/null
+ ${PASS_IFF_GOOD_MACHO} main-${ARCH}.dylib
+
+clean:
+ rm -rf *.dylib main-* *.o
--- /dev/null
+Test the weak_import attribute works
--- /dev/null
+
+
+#include "foo.h"
+
+void func1() {}
+void func2() {}
+void func3() {}
+void func4() {}
+
+
+int data1 = 0;
+int data2 = 0; // weak_import initialized
+int data3;
+int data4; // weak_import uninitialized
+int data5 = 0;
+int data6 = 0; // weak_import
+
--- /dev/null
+
+
+extern void func1();
+extern void func2() __attribute__((weak_import));
+extern void func3();
+extern void func4() __attribute__((weak_import));
+
+extern int data1;
+extern int data2 __attribute__((weak_import));
+extern int data3;
+extern int data4 __attribute__((weak_import));
+extern int data5;
+extern int data6 __attribute__((weak_import));
+
+
+
--- /dev/null
+
+
+void func2() {}
+void func4() {}
+
+
+int data2 = 0; // foo.c also has weak_import initialized
+int data4; // foo.c also has weak_import uninitialized
+int data6 = 0; // foo.c also has weak_import
+
--- /dev/null
+
+#include "foo.h"
+
+
+int* pdata5 = &data5;
+int* pdata6 = &data6;
+
+
+int main (void)
+{
+ // make non-lazy reference to func3 and func4
+ if ( &func3 == &func4 ) {
+ // make lazy reference to func3 and func4
+ func1();
+ func2();
+ }
+
+ return data1 + data2 + data3 + data4;
+}
+
--- /dev/null
+##
+# Copyright (c) 2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+# Text -why_live option with dead code stripping
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c foo.c bar.c -o main -dead_strip -Wl,-why_live,_bar 2>call_chains
+ grep _bar call_chains | ${FAIL_IF_EMPTY}
+ grep _foo call_chains | ${FAIL_IF_EMPTY}
+ grep _main call_chains | ${FAIL_IF_EMPTY}
+ grep _frob call_chains | ${FAIL_IF_STDIN}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm main call_chains
--- /dev/null
+void bar() {}
--- /dev/null
+
+extern void bar();
+
+void foo()
+{
+ bar();
+}
+
+void frob()
+{
+ bar();
+}
\ No newline at end of file
--- /dev/null
+extern void foo();
+
+int main()
+{
+ foo();
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a program with a large zero-fill section
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.c -o test-${ARCH}
+ ${PASS_IFF_GOOD_MACHO} test-${ARCH}
+
+clean:
+ rm -rf test-*
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+// if we used one big array, the linker would page align it
+// but we want to test a non-page align big chunk of zero-fill data
+int bigarray1[256];
+int bigarray2[256];
+int bigarray3[256];
+int bigarray4[256];
+int bigarray5[256];
+int bigarray6[256];
+static int staticbigarray1[256];
+static int staticbigarray2[256];
+static int staticbigarray3[256];
+static int staticbigarray4[256];
+static int staticbigarray5[256];
+static int staticbigarray6[256];
+
+int main()
+{
+ staticbigarray1[10] = 4;
+ staticbigarray2[10] = 4;
+ staticbigarray3[10] = 4;
+ staticbigarray4[10] = 4;
+ staticbigarray5[10] = 4;
+ staticbigarray6[10] = 4;
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2006-2007 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a program with a large zero-fill section
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.c -o test
+ ${PASS_IFF_GOOD_MACHO} test
+
+clean:
+ rm -rf test
--- /dev/null
+The point of this test is a sanity check that ld can link a program with a large zero-fill section
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+// if we used one big array, the linker would page align it
+// but we want to test a non-page align big chunk of zero-fill data
+
+#if __LP64__
+ #define BOOST 100UL
+#else
+ #define BOOST 1
+#endif
+
+int bigarray1[256];
+int bigarray2[2560];
+int bigarray3[25600];
+int bigarray4[256000];
+int bigarray5[2560000];
+#ifndef __arm__
+int bigarray6[256000000*BOOST];
+#endif
+static int staticbigarray1[256];
+static int staticbigarray2[2560];
+static int staticbigarray3[25600];
+static int staticbigarray4[256000];
+static int staticbigarray5[2560000];
+#ifndef __arm__
+static int staticbigarray6[25600000*BOOST];
+#endif
+int main()
+{
+ staticbigarray1[10] = 4;
+ staticbigarray2[10] = 4;
+ staticbigarray3[10] = 4;
+ staticbigarray4[10] = 4;
+ staticbigarray5[10] = 4;
+#ifndef __arm__
+ staticbigarray6[10] = 4;
+#endif
+ return 0;
+}
+
--- /dev/null
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a program with a large zero-fill section
+#
+
+all: test-${FILEARCH}
+
+# i386 catches the problem in the assembler phase
+test-i386:
+ ${PASS_IFF} true
+
+test-x86_64:
+ ${CC} ${CCFLAGS} -DSHRINK=1 test.c --save-temps -o test-${ARCH}
+ ${PASS_IFF_GOOD_MACHO} test-${ARCH}
+
+test-ppc:
+ ${PASS_IFF_ERROR} ${CC} ${CCFLAGS} -DSHRINK=4 test.c --save-temps -o test-${ARCH} 2>/dev/null
+
+test-arm:
+ ${PASS_IFF_ERROR} ${CC} ${CCFLAGS} -DSHRINK=4 test.c --save-temps -o test-${ARCH} 2>/dev/null
+
+clean:
+ rm -rf test-* *.o *.s *.i
--- /dev/null
+The point of this test is a sanity check that ld can link a program with a large zero-fill section
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+// if we used one big array, the linker would page align it
+// but we want to test a non-page align big chunk of zero-fill data
+int bigarray1[256];
+int bigarray2[2560];
+int bigarray3[25600];
+int bigarray4[256000];
+int bigarray5[2560000];
+int bigarray7[16777216L+1];
+int bigarray8[2*16777216L+1];
+int bigarray9[4*16777216L+1];
+int bigarray10[8*16777216L+1];
+int bigarray11[16*16777216L+1];
+int bigarray99[2147483647U/SHRINK];
+static int staticbigarray1[256];
+static int staticbigarray2[2560];
+static int staticbigarray3[25600];
+static int staticbigarray4[256000];
+static int staticbigarray5[2560000];
+static int staticbigarray6[25600000];
+//static int staticbigarray99[2147483647U/SHRINK];
+
+int main()
+{
+ bigarray5[10] = 4;
+ bigarray7[10] = 4;
+ bigarray8[10] = 4;
+ bigarray9[10] = 4;
+ bigarray10[10] = 4;
+ bigarray11[10] = 4;
+ bigarray99[10] = 4;
+ staticbigarray1[10] = 4;
+ staticbigarray2[10] = 4;
+ staticbigarray3[10] = 4;
+ staticbigarray4[10] = 4;
+ staticbigarray5[10] = 4;
+ staticbigarray6[10] = 4;
+ return 0;
+}
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
- B3B672411406D42800A376BB /* Snapshot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Snapshot.cpp; path = src/ld/Snapshot.cpp; sourceTree = "<group>"; };
- B3B672441406D44300A376BB /* Snapshot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Snapshot.h; path = src/ld/Snapshot.h; sourceTree = "<group>"; };
- B3C7A09914295B9C005FC714 /* compile_stubs */ = {isa = PBXFileReference; lastKnownFileType = text.script.csh; path = compile_stubs; sourceTree = "<group>"; };
+ B3B672411406D42800A376BB /* Snapshot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Snapshot.cpp; path = src/ld/Snapshot.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ B3B672441406D44300A376BB /* Snapshot.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = Snapshot.h; path = src/ld/Snapshot.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ B3C7A09914295B9C005FC714 /* compile_stubs */ = {isa = PBXFileReference; lastKnownFileType = text.script.csh; path = compile_stubs; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F9023C3906D5A23E001BBF46 /* ld */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ld; sourceTree = BUILT_PRODUCTS_DIR; };
- F9023C3F06D5A254001BBF46 /* ld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ld.cpp; path = src/ld/ld.cpp; sourceTree = "<group>"; };
- F92D9C2710657AAB00FF369B /* stub_x86_64_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_64_classic.hpp; sourceTree = "<group>"; };
- F933D9460929277C0083EAC8 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FileAbstraction.hpp; path = src/abstraction/FileAbstraction.hpp; sourceTree = "<group>"; };
- F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOFileAbstraction.hpp; path = src/abstraction/MachOFileAbstraction.hpp; sourceTree = "<group>"; };
- F933DC37092A82480083EAC8 /* Architectures.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Architectures.hpp; path = src/ld/Architectures.hpp; sourceTree = "<group>"; };
- F93CB246116E69EB003233B8 /* tlvp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tlvp.cpp; sourceTree = "<group>"; };
- F93CB247116E69EB003233B8 /* tlvp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tlvp.h; sourceTree = "<group>"; };
+ F9023C3F06D5A254001BBF46 /* ld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ld.cpp; path = src/ld/ld.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F92D9C2710657AAB00FF369B /* stub_x86_64_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_64_classic.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F933D9460929277C0083EAC8 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FileAbstraction.hpp; path = src/abstraction/FileAbstraction.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOFileAbstraction.hpp; path = src/abstraction/MachOFileAbstraction.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F933DC37092A82480083EAC8 /* Architectures.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Architectures.hpp; path = src/ld/Architectures.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F93CB246116E69EB003233B8 /* tlvp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tlvp.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F93CB247116E69EB003233B8 /* tlvp.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = tlvp.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F971EED306D5ACF60041D381 /* ObjectDump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ObjectDump; sourceTree = BUILT_PRODUCTS_DIR; };
- F971EED706D5AD240041D381 /* ObjectDump.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ObjectDump.cpp; path = src/other/ObjectDump.cpp; sourceTree = "<group>"; };
- F97F5028070D0BB200B9FCD7 /* ld.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = ld.1; path = doc/man/man1/ld.1; sourceTree = "<group>"; };
- F9849E3410B38EF5009E9878 /* order.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = order.cpp; sourceTree = "<group>"; };
- F9849E3510B38EF5009E9878 /* order.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = order.h; sourceTree = "<group>"; };
- F984A13B10B614CF009E9878 /* stub_arm_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_arm_classic.hpp; sourceTree = "<group>"; };
- F984A38010BB4B0D009E9878 /* branch_island.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = branch_island.cpp; sourceTree = "<group>"; };
- F984A38110BB4B0D009E9878 /* branch_island.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = branch_island.h; sourceTree = "<group>"; };
- F989D0391062E6350014B60C /* stub_x86_64.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_64.hpp; sourceTree = "<group>"; };
- F989D30B106826020014B60C /* OutputFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OutputFile.cpp; path = src/ld/OutputFile.cpp; sourceTree = "<group>"; };
- F989D30C106826020014B60C /* OutputFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OutputFile.h; path = src/ld/OutputFile.h; sourceTree = "<group>"; };
- F989D3AA10684F5B0014B60C /* LinkEdit.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = LinkEdit.hpp; path = src/ld/LinkEdit.hpp; sourceTree = "<group>"; };
- F989D44B10694F2E0014B60C /* LinkEditClassic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = LinkEditClassic.hpp; path = src/ld/LinkEditClassic.hpp; sourceTree = "<group>"; };
- F989D7E91072DEC20014B60C /* HeaderAndLoadCommands.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = HeaderAndLoadCommands.hpp; path = src/ld/HeaderAndLoadCommands.hpp; sourceTree = "<group>"; };
+ F971EED706D5AD240041D381 /* ObjectDump.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ObjectDump.cpp; path = src/other/ObjectDump.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F97F5028070D0BB200B9FCD7 /* ld.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = ld.1; path = doc/man/man1/ld.1; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9849E3410B38EF5009E9878 /* order.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = order.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9849E3510B38EF5009E9878 /* order.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = order.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F984A13B10B614CF009E9878 /* stub_arm_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_arm_classic.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F984A38010BB4B0D009E9878 /* branch_island.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = branch_island.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F984A38110BB4B0D009E9878 /* branch_island.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = branch_island.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F989D0391062E6350014B60C /* stub_x86_64.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_64.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F989D30B106826020014B60C /* OutputFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OutputFile.cpp; path = src/ld/OutputFile.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F989D30C106826020014B60C /* OutputFile.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = OutputFile.h; path = src/ld/OutputFile.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F989D3AA10684F5B0014B60C /* LinkEdit.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; name = LinkEdit.hpp; path = src/ld/LinkEdit.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F989D44B10694F2E0014B60C /* LinkEditClassic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; name = LinkEditClassic.hpp; path = src/ld/LinkEditClassic.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F989D7E91072DEC20014B60C /* HeaderAndLoadCommands.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; name = HeaderAndLoadCommands.hpp; path = src/ld/HeaderAndLoadCommands.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F9A3DDCA0ED762B700C590B9 /* libprunetrie.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libprunetrie.a; sourceTree = BUILT_PRODUCTS_DIR; };
- F9A3DDD20ED762E400C590B9 /* PruneTrie.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PruneTrie.cpp; path = src/other/PruneTrie.cpp; sourceTree = "<group>"; };
- F9A3DE0F0ED76D1900C590B9 /* prune_trie.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = prune_trie.h; path = src/other/prune_trie.h; sourceTree = "<group>"; };
- F9A4DB8F10F816FF00BD8423 /* objc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = objc.cpp; sourceTree = "<group>"; };
- F9A4DB9010F816FF00BD8423 /* objc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = objc.h; sourceTree = "<group>"; };
- F9AA44DA1294885F00CB8390 /* branch_shim.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = branch_shim.cpp; sourceTree = "<group>"; };
- F9AA44DB1294885F00CB8390 /* branch_shim.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = branch_shim.h; sourceTree = "<group>"; };
- F9AA5FCC103F5CD1003E3539 /* ld.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ld.hpp; path = src/ld/ld.hpp; sourceTree = "<group>"; };
- F9AA650D1051BD2B003E3539 /* make_stubs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = make_stubs.h; sourceTree = "<group>"; };
- F9AA650F1051BD2B003E3539 /* stub_arm.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_arm.hpp; sourceTree = "<group>"; };
- F9AA65101051BD2B003E3539 /* stubs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stubs.cpp; sourceTree = "<group>"; };
- F9AA65871051E750003E3539 /* macho_relocatable_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_relocatable_file.cpp; sourceTree = "<group>"; };
- F9AA65881051E750003E3539 /* macho_relocatable_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macho_relocatable_file.h; sourceTree = "<group>"; };
- F9AA65D71051EC4A003E3539 /* archive_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = archive_file.cpp; sourceTree = "<group>"; };
- F9AA65D81051EC4A003E3539 /* archive_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive_file.h; sourceTree = "<group>"; };
- F9AA65D91051EC4A003E3539 /* lto_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lto_file.cpp; sourceTree = "<group>"; };
- F9AA65DA1051EC4A003E3539 /* lto_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lto_file.h; sourceTree = "<group>"; };
- F9AA65DB1051EC4A003E3539 /* macho_dylib_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_dylib_file.cpp; sourceTree = "<group>"; };
- F9AA65DC1051EC4A003E3539 /* macho_dylib_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macho_dylib_file.h; sourceTree = "<group>"; };
- F9AA6784105700C2003E3539 /* opaque_section_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opaque_section_file.cpp; sourceTree = "<group>"; };
- F9AA6785105700C2003E3539 /* opaque_section_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opaque_section_file.h; sourceTree = "<group>"; };
- F9AA67B410570C41003E3539 /* dtrace_dof.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dtrace_dof.h; sourceTree = "<group>"; };
- F9AA67B510570C41003E3539 /* dtrace_dof.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dtrace_dof.cpp; sourceTree = "<group>"; };
- F9AA687A10572E27003E3539 /* InputFiles.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InputFiles.cpp; path = src/ld/InputFiles.cpp; sourceTree = "<group>"; };
- F9AA687B10572E27003E3539 /* InputFiles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InputFiles.h; path = src/ld/InputFiles.h; sourceTree = "<group>"; };
- F9AA69B410583C0C003E3539 /* SymbolTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SymbolTable.cpp; path = src/ld/SymbolTable.cpp; sourceTree = "<group>"; };
- F9AA69B510583C0C003E3539 /* SymbolTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SymbolTable.h; path = src/ld/SymbolTable.h; sourceTree = "<group>"; };
- F9AA69BF10583E19003E3539 /* Resolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Resolver.cpp; path = src/ld/Resolver.cpp; sourceTree = "<group>"; };
- F9AA69C010583E19003E3539 /* Resolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Resolver.h; path = src/ld/Resolver.h; sourceTree = "<group>"; };
- F9AB1063107D380700E54C9E /* got.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = got.cpp; sourceTree = "<group>"; };
- F9AB1064107D380700E54C9E /* got.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = got.h; sourceTree = "<group>"; };
- F9AE20FD1107D1440007ED5D /* dylibs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dylibs.cpp; sourceTree = "<group>"; };
- F9AE20FE1107D1440007ED5D /* dylibs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dylibs.h; sourceTree = "<group>"; };
- F9B1A2580A3A448800DA8FAB /* rebase.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = rebase.1; path = doc/man/man1/rebase.1; sourceTree = "<group>"; };
+ F9A3DDD20ED762E400C590B9 /* PruneTrie.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PruneTrie.cpp; path = src/other/PruneTrie.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9A3DE0F0ED76D1900C590B9 /* prune_trie.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = prune_trie.h; path = src/other/prune_trie.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9A4DB8F10F816FF00BD8423 /* objc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = objc.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9A4DB9010F816FF00BD8423 /* objc.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = objc.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA44DA1294885F00CB8390 /* branch_shim.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = branch_shim.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA44DB1294885F00CB8390 /* branch_shim.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = branch_shim.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA5FCC103F5CD1003E3539 /* ld.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; name = ld.hpp; path = src/ld/ld.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA650D1051BD2B003E3539 /* make_stubs.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = make_stubs.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA650F1051BD2B003E3539 /* stub_arm.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_arm.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65101051BD2B003E3539 /* stubs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stubs.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65871051E750003E3539 /* macho_relocatable_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_relocatable_file.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65881051E750003E3539 /* macho_relocatable_file.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = macho_relocatable_file.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65D71051EC4A003E3539 /* archive_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = archive_file.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65D81051EC4A003E3539 /* archive_file.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = archive_file.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65D91051EC4A003E3539 /* lto_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lto_file.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65DA1051EC4A003E3539 /* lto_file.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = lto_file.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65DB1051EC4A003E3539 /* macho_dylib_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_dylib_file.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA65DC1051EC4A003E3539 /* macho_dylib_file.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = macho_dylib_file.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA6784105700C2003E3539 /* opaque_section_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opaque_section_file.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA6785105700C2003E3539 /* opaque_section_file.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = opaque_section_file.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA67B410570C41003E3539 /* dtrace_dof.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = dtrace_dof.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA67B510570C41003E3539 /* dtrace_dof.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dtrace_dof.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA687A10572E27003E3539 /* InputFiles.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InputFiles.cpp; path = src/ld/InputFiles.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA687B10572E27003E3539 /* InputFiles.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = InputFiles.h; path = src/ld/InputFiles.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA69B410583C0C003E3539 /* SymbolTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SymbolTable.cpp; path = src/ld/SymbolTable.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA69B510583C0C003E3539 /* SymbolTable.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = SymbolTable.h; path = src/ld/SymbolTable.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA69BF10583E19003E3539 /* Resolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Resolver.cpp; path = src/ld/Resolver.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AA69C010583E19003E3539 /* Resolver.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = Resolver.h; path = src/ld/Resolver.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AB1063107D380700E54C9E /* got.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = got.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AB1064107D380700E54C9E /* got.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = got.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AE20FD1107D1440007ED5D /* dylibs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dylibs.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9AE20FE1107D1440007ED5D /* dylibs.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = dylibs.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9B1A2580A3A448800DA8FAB /* rebase.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = rebase.1; path = doc/man/man1/rebase.1; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F9B670080DDA176100E6D0DA /* unwinddump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = unwinddump; sourceTree = BUILT_PRODUCTS_DIR; };
- F9B670110DDA17E800E6D0DA /* UnwindDump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindDump.cpp; path = src/other/unwinddump.cpp; sourceTree = "<group>"; };
- F9B813810EC2653000F94C13 /* unwinddump.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = unwinddump.1; path = doc/man/man1/unwinddump.1; sourceTree = "<group>"; };
- F9B813BF0EC27C6700F94C13 /* MachOTrie.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = MachOTrie.hpp; path = src/abstraction/MachOTrie.hpp; sourceTree = "<group>"; };
- F9BA515B0ECE58AA00D1D62E /* dyldinfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dyldinfo.cpp; path = src/other/dyldinfo.cpp; sourceTree = "<group>"; };
+ F9B670110DDA17E800E6D0DA /* UnwindDump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindDump.cpp; path = src/other/unwinddump.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9B813810EC2653000F94C13 /* unwinddump.1 */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = text.man; name = unwinddump.1; path = doc/man/man1/unwinddump.1; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9B813BF0EC27C6700F94C13 /* MachOTrie.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; name = MachOTrie.hpp; path = src/abstraction/MachOTrie.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9BA515B0ECE58AA00D1D62E /* dyldinfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dyldinfo.cpp; path = src/other/dyldinfo.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F9BA51610ECE58BE00D1D62E /* dyldinfo */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dyldinfo; sourceTree = BUILT_PRODUCTS_DIR; };
- F9BA8A7E1096150F0097A440 /* stub_x86_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_classic.hpp; sourceTree = "<group>"; };
- F9BA8A7F1096150F0097A440 /* stub_x86.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86.hpp; sourceTree = "<group>"; };
- F9BA955C10A233000097A440 /* huge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = huge.cpp; sourceTree = "<group>"; };
- F9BA955D10A233000097A440 /* huge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = huge.h; sourceTree = "<group>"; };
- F9BA963310A2545C0097A440 /* compact_unwind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compact_unwind.cpp; sourceTree = "<group>"; };
- F9BA963410A2545C0097A440 /* compact_unwind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compact_unwind.h; sourceTree = "<group>"; };
- F9C0D48A06DD1E1B001C7193 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Options.cpp; path = src/ld/Options.cpp; sourceTree = "<group>"; };
- F9C0D48B06DD1E1B001C7193 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Options.h; path = src/ld/Options.h; sourceTree = "<group>"; };
- F9C12E9F0ED63DB1005BC69D /* dyldinfo.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = dyldinfo.1; path = doc/man/man1/dyldinfo.1; sourceTree = "<group>"; };
- F9CC24141461FB4300A92174 /* blob.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blob.cpp; sourceTree = "<group>"; };
- F9CC24151461FB4300A92174 /* blob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blob.h; sourceTree = "<group>"; };
- F9CC24161461FB4300A92174 /* endian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endian.h; sourceTree = "<group>"; };
- F9CC24171461FB4300A92174 /* memutils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memutils.h; sourceTree = "<group>"; };
- F9CC24181461FB4300A92174 /* superblob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = superblob.h; sourceTree = "<group>"; };
- F9CCF761144CE1AD007CB524 /* create_configure */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = create_configure; path = src/create_configure; sourceTree = "<group>"; };
+ F9BA8A7E1096150F0097A440 /* stub_x86_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_classic.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9BA8A7F1096150F0097A440 /* stub_x86.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9BA955C10A233000097A440 /* huge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = huge.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9BA955D10A233000097A440 /* huge.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = huge.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9BA963310A2545C0097A440 /* compact_unwind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compact_unwind.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9BA963410A2545C0097A440 /* compact_unwind.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = compact_unwind.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9C0D48A06DD1E1B001C7193 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Options.cpp; path = src/ld/Options.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9C0D48B06DD1E1B001C7193 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Options.h; path = src/ld/Options.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9C12E9F0ED63DB1005BC69D /* dyldinfo.1 */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = text.man; name = dyldinfo.1; path = doc/man/man1/dyldinfo.1; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9CC24141461FB4300A92174 /* blob.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blob.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9CC24151461FB4300A92174 /* blob.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = blob.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9CC24161461FB4300A92174 /* endian.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = endian.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9CC24171461FB4300A92174 /* memutils.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = memutils.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9CC24181461FB4300A92174 /* superblob.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = superblob.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9CCF761144CE1AD007CB524 /* create_configure */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = text.script.sh; name = create_configure; path = src/create_configure; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F9EA72CB097454A6008B4F1D /* machocheck */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = machocheck; sourceTree = BUILT_PRODUCTS_DIR; };
- F9EA72D4097454FF008B4F1D /* machochecker.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = machochecker.cpp; path = src/other/machochecker.cpp; sourceTree = "<group>"; };
+ F9EA72D4097454FF008B4F1D /* machochecker.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = machochecker.cpp; path = src/other/machochecker.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F9EA7582097882F3008B4F1D /* debugline.c */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.c; name = debugline.c; path = src/ld/debugline.c; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
- F9EA7583097882F3008B4F1D /* debugline.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = debugline.h; path = src/ld/debugline.h; sourceTree = "<group>"; };
+ F9EA7583097882F3008B4F1D /* debugline.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = debugline.h; path = src/ld/debugline.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
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/other/rebase.cpp; sourceTree = "<group>"; };
+ F9EC78050A2F8674002A3E39 /* rebase.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = rebase.cpp; path = src/other/rebase.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
#ifndef CPU_SUBTYPE_ARM_V7K
#define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t) 12)
#endif
+#ifndef CPU_SUBTYPE_ARM_V7S
+ #define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t) 11)
+#endif
#ifndef LC_SOURCE_VERSION
#if SUPPORT_ARCH_armv7
{ "armv7", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7, "thumbv7-", "armv7-", true, true },
#define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv7f
+ { "armv7f", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7F, "thumbv7f-", "", true, true },
+ #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv7k
+ { "armv7k", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7K, "thumbv7k-", "", true, true },
+ #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv7s
+ { "armv7s", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S, "thumbv7s-", "armv7s", true, true },
+ #define SUPPORT_ARCH_arm_any 1
#endif
{ NULL, 0, 0, NULL, NULL, false, false }
};
// empty trie has no entries
if ( start == end )
return;
- char cummulativeString[4000];
+ // worst case largest exported symbol names is length of whole trie
+ char* cummulativeString = new char[end-start];
std::vector<EntryWithOffset> entries;
processExportNode(start, start, end, cummulativeString, 0, entries);
// to preserve tie layout order, sort by node offset
output.reserve(entries.size());
for (std::vector<EntryWithOffset>::iterator it=entries.begin(); it != entries.end(); ++it)
output.push_back(it->entry);
+ delete cummulativeString;
}
for ANARCH in ${RC_SUPPORTED_ARCHS}
do
- KNOWN_ARCHS=",armv4t,armv5,armv6,armv7,i386,x86_64,"
+ KNOWN_ARCHS=",armv4t,armv5,armv6,armv7,armv7f,armv7k,armv7s,i386,x86_64,"
FOUND=`echo "$KNOWN_ARCHS" | grep ",$ANARCH,"`
if [ $FOUND ]; then
echo "#define SUPPORT_ARCH_$ANARCH 1" >> ${DERIVED_FILE_DIR}/configure.h
// overrides of ld::Atom
virtual ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return "mach-o header and load commands"; }
virtual uint64_t size() const;
virtual uint64_t objectAddress() const { return _address; }
return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
else if ( (strncmp(sect->sectionName(), "__objc_nlclslist", 16) == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+ else if ( (strncmp(sect->sectionName(), "__objc_nlcatlist", 16) == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+ return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
else
return S_REGULAR;
case ld::Section::typeCode:
class DSOHandleAtom : public ld::Atom {
public:
DSOHandleAtom(const char* nm, ld::Atom::Scope sc,
- ld::Atom::SymbolTableInclusion inc, bool preload=false)
- : ld::Atom(preload ? _s_section_preload : _s_section,
- ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::SymbolTableInclusion inc, ld::Section& sect=_s_section)
+ : ld::Atom(sect, ld::Atom::definitionRegular,
+ (sect == _s_section_text) ? ld::Atom::combineByName : ld::Atom::combineNever,
+ // make "weak def" so that link succeeds even if app defines __dso_handle
sc, ld::Atom::typeUnclassified, inc, true, false, false,
ld::Atom::Alignment(1)), _name(nm) {}
virtual ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
- virtual const char* name() const { return _name; }
+ virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 0; }
virtual uint64_t objectAddress() const { return 0; }
virtual void copyRawContent(uint8_t buffer[]) const
static ld::Section _s_section;
static ld::Section _s_section_preload;
+ static ld::Section _s_section_text;
static DSOHandleAtom _s_atomAll;
static DSOHandleAtom _s_atomExecutable;
static DSOHandleAtom _s_atomDylib;
static DSOHandleAtom _s_atomDyld;
static DSOHandleAtom _s_atomObjectFile;
static DSOHandleAtom _s_atomPreload;
+ static DSOHandleAtom _s_atomPreloadDSO;
private:
const char* _name;
};
ld::Section DSOHandleAtom::_s_section("__TEXT", "__mach_header", ld::Section::typeMachHeader, true);
ld::Section DSOHandleAtom::_s_section_preload("__HEADER", "__mach_header", ld::Section::typeMachHeader, true);
+ld::Section DSOHandleAtom::_s_section_text("__TEXT", "__text", ld::Section::typeCode, false);
DSOHandleAtom DSOHandleAtom::_s_atomAll("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
DSOHandleAtom DSOHandleAtom::_s_atomExecutable("__mh_execute_header", ld::Atom::scopeGlobal, ld::Atom::symbolTableInAndNeverStrip);
DSOHandleAtom DSOHandleAtom::_s_atomDylib("__mh_dylib_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
DSOHandleAtom DSOHandleAtom::_s_atomBundle("__mh_bundle_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
DSOHandleAtom DSOHandleAtom::_s_atomDyld("__mh_dylinker_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
DSOHandleAtom DSOHandleAtom::_s_atomObjectFile("__mh_object_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
-DSOHandleAtom DSOHandleAtom::_s_atomPreload("__mh_preload_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, true);
+DSOHandleAtom DSOHandleAtom::_s_atomPreload("__mh_preload_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, _s_section_preload);
+DSOHandleAtom DSOHandleAtom::_s_atomPreloadDSO("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, _s_section_text);
_size(sz) {}
virtual ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return "page zero"; }
virtual uint64_t size() const { return _size; }
virtual uint64_t objectAddress() const { return 0; }
_size(sz) {}
virtual ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return "custom stack"; }
virtual uint64_t size() const { return _size; }
virtual uint64_t objectAddress() const { return 0; }
}
// see if it is an llvm object file
- objResult = lto::parse(p, len, info.path, info.modTime, _options.architecture(), _options.subArchitecture(), _options.logAllFiles());
+ objResult = lto::parse(p, len, info.path, info.modTime, info.ordinal, _options.architecture(), _options.subArchitecture(), _options.logAllFiles());
if ( objResult != NULL ) {
OSAtomicAdd64(len, &_totalObjectSize);
OSAtomicIncrement32(&_totalObjectLoaded);
case Options::kPreload:
// add implicit __mh_preload_header label
handler.doAtom(DSOHandleAtom::_s_atomPreload);
- handler.doAtom(DSOHandleAtom::_s_atomAll);
+ // add implicit __dso_handle label, but put it in __text section because
+ // with -preload the mach_header is no in the address space.
+ handler.doAtom(DSOHandleAtom::_s_atomPreloadDSO);
break;
case Options::kObjectFile:
handler.doAtom(DSOHandleAtom::_s_atomObjectFile);
// overrides of ld::Atom
virtual ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual uint64_t objectAddress() const { return 0; }
virtual uint64_t size() const;
virtual void copyRawContent(uint8_t buffer[]) const;
void FunctionStartsAtom<A>::encode() const
{
this->_encodedData.reserve(8192);
- const uint64_t badAddress = 1;
+ const uint64_t badAddress = 0xFFFFFFFFFFFFFFFF;
uint64_t addr = badAddress;
// delta compress all function addresses
for (std::vector<ld::Internal::FinalSection*>::iterator it = this->_state.sections.begin(); it != this->_state.sections.end(); ++it) {
entry.set_length(len);
switch ( kind ) {
case ld::Fixup::kindDataInCodeStartData:
- entry.set_kind(1);
+ entry.set_kind(DICE_KIND_DATA);
break;
case ld::Fixup::kindDataInCodeStartJT8:
- entry.set_kind(2);
+ entry.set_kind(DICE_KIND_JUMP_TABLE8);
break;
case ld::Fixup::kindDataInCodeStartJT16:
- entry.set_kind(3);
+ entry.set_kind(DICE_KIND_JUMP_TABLE16);
break;
case ld::Fixup::kindDataInCodeStartJT32:
- entry.set_kind(4);
+ entry.set_kind(DICE_KIND_JUMP_TABLE32);
break;
case ld::Fixup::kindDataInCodeStartJTA32:
- entry.set_kind(5);
+ entry.set_kind(DICE_KIND_ABS_JUMP_TABLE32);
break;
default:
assert(0 && "bad L$start$ label to encode");
for(size_t i=0; i < topBlob->length(); ++i)
_encodedData.append_byte(data[i]);
+ this->_encodedData.pad_to_size(sizeof(pint_t));
+
this->_encoded = true;
}
// overrides of ld::Atom
virtual ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual uint64_t objectAddress() const { return 0; }
virtual void encode() = 0;
uint32_t stringOffsetForStab(const ld::relocatable::File::Stab& stab, StringPoolAtom* pool);
uint64_t valueForStab(const ld::relocatable::File::Stab& stab);
uint8_t sectionIndexForStab(const ld::relocatable::File::Stab& stab);
- void addDataInCodeLabels(const ld::Atom* atom, uint32_t& symbolIndex);
mutable std::vector<macho_nlist<P> > _globals;
}
-template <typename A>
-void SymbolTableAtom<A>::addDataInCodeLabels(const ld::Atom* atom, uint32_t& symbolIndex)
-{
- char label[64];
- for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
- label[0] = '\0';
- switch ( fit->kind ) {
- case ld::Fixup::kindDataInCodeStartData:
- sprintf(label, "L$start$data$%03u", symbolIndex);
- break;
- case ld::Fixup::kindDataInCodeStartJT8:
- sprintf(label, "L$start$jt8$%03u", symbolIndex);
- break;
- case ld::Fixup::kindDataInCodeStartJT16:
- sprintf(label, "L$start$jt16$%03u", symbolIndex);
- break;
- case ld::Fixup::kindDataInCodeStartJT32:
- sprintf(label, "L$start$jt32$%03u", symbolIndex);
- break;
- case ld::Fixup::kindDataInCodeStartJTA32:
- sprintf(label, "L$start$jta32$%03u", symbolIndex);
- break;
- case ld::Fixup::kindDataInCodeEnd:
- sprintf(label, "L$start$code$%03u", symbolIndex);
- break;
- default:
- break;
- }
- if ( label[0] != '\0' ) {
- macho_nlist<P> entry;
- entry.set_n_type(N_SECT);
- entry.set_n_sect(atom->machoSection());
- entry.set_n_desc(0);
- entry.set_n_value(atom->finalAddress() + fit->offsetInAtom);
- entry.set_n_strx(this->_writer._stringPoolAtom->add(label));
- _locals.push_back(entry);
- ++symbolIndex;
- }
- }
-}
-
-
template <typename A>
void SymbolTableAtom<A>::encode()
{
if ( this->addLocal(atom, this->_writer._stringPoolAtom) )
this->_writer._atomToSymbolIndex[atom] = symbolIndex++;
}
- // <rdar://problem/9218847> recreate L$start$ labels in -r mode
- if ( (_options.outputKind() == Options::kObjectFile) && this->_writer.hasDataInCode ) {
- for (std::vector<const ld::Atom*>::const_iterator it=globalAtoms.begin(); it != globalAtoms.end(); ++it) {
- this->addDataInCodeLabels(*it, symbolIndex);
- }
- for (std::vector<const ld::Atom*>::const_iterator it=localAtoms.begin(); it != localAtoms.end(); ++it) {
- this->addDataInCodeLabels(*it, symbolIndex);
- }
- }
this->_writer._localSymbolsCount = symbolIndex;
relocs.push_back(reloc1);
}
break;
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(X86_64_RELOC_TLV);
+ relocs.push_back(reloc1);
+ break;
default:
assert(0 && "need to handle -r reloc");
}
template <>
-void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection* sect,
+void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection* sect,
const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
{
macho_relocation_info<P> reloc1;
fromExternal = entry.fromTargetUsesExternalReloc;
fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
}
-
-
+
switch ( entry.kind ) {
case ld::Fixup::kindStoreX86PCRel32:
case ld::Fixup::kindStoreX86BranchPCRel32:
relocs.push_back(reloc1);
}
break;
+ case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreX86Abs32TLVLoad:
+ case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(entry.kind == ld::Fixup::kindStoreX86PCRel32TLVLoad);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(GENERIC_RLEOC_TLV);
+ relocs.push_back(reloc1);
+ break;
default:
assert(0 && "need to handle -r reloc");
}
+
#if SUPPORT_ARCH_arm_any
template <>
void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection* sect,
fVersionLoadCommand(false), fVersionLoadCommandForcedOn(false),
fVersionLoadCommandForcedOff(false), fFunctionStartsLoadCommand(false),
fFunctionStartsForcedOn(false), fFunctionStartsForcedOff(false),
- fDataInCodeInfoLoadCommand(false),
+ fDataInCodeInfoLoadCommand(false), fDataInCodeInfoLoadCommandForcedOn(false), fDataInCodeInfoLoadCommandForcedOff(false),
fCanReExportSymbols(false), fObjcCategoryMerging(true), fPageAlignDataAtoms(false),
fNeedsThreadLoadCommand(false), fEntryPointLoadCommand(false),
fEntryPointLoadCommandForceOn(false), fEntryPointLoadCommandForceOff(false),
uint32_t Options::maxSegProtection(const char* segName) const
{
// iPhoneOS always uses same protection for max and initial
- if ( fIOSVersionMin != ld::iOSVersionUnset )
+ // <rdar://problem/11663436> simulator apps need to use MacOSX max-prot
+ if ( (fIOSVersionMin != ld::iOSVersionUnset) && (fArchitecture != CPU_TYPE_I386) )
return initialSegProtection(segName);
for(std::vector<Options::SegmentProtect>::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) {
fFunctionStartsForcedOn = false;
}
else if ( strcmp(arg, "-no_data_in_code_info") == 0 ) {
- fDataInCodeInfoLoadCommand = false;
+ fDataInCodeInfoLoadCommandForcedOff = true;
+ fDataInCodeInfoLoadCommandForcedOn = false;
}
else if ( strcmp(arg, "-data_in_code_info") == 0 ) {
- fDataInCodeInfoLoadCommand = true;
+ fDataInCodeInfoLoadCommandForcedOn = true;
+ fDataInCodeInfoLoadCommandForcedOff = false;
}
else if ( strcmp(arg, "-object_path_lto") == 0 ) {
fTempLtoObjectPath = argv[++i];
// iOS 5.0 and later use new MH_KEXT_BUNDLE type
fMakeCompressedDyldInfo = false;
fMakeCompressedDyldInfoForceOff = true;
- fAllowTextRelocs = true;
+ // kexts are PIC in iOS 6.0 and later
+ fAllowTextRelocs = (fIOSVersionMin < ld::iOS_6_0);
fKextsUseStubs = !fAllowTextRelocs;
fUndefinedTreatment = kUndefinedDynamicLookup;
break;
// default to adding functions start for dynamic code, static code must opt-in
switch ( fOutputKind ) {
- case Options::kObjectFile:
- fFunctionStartsLoadCommand = false;
- fDataInCodeInfoLoadCommand = false;
- break;
case Options::kPreload:
case Options::kStaticExecutable:
case Options::kKextBundle:
- fDataInCodeInfoLoadCommand = false;
+ if ( fDataInCodeInfoLoadCommandForcedOn )
+ fDataInCodeInfoLoadCommand = true;
if ( fFunctionStartsForcedOn )
fFunctionStartsLoadCommand = true;
break;
+ case Options::kObjectFile:
case Options::kDynamicExecutable:
case Options::kDyld:
case Options::kDynamicLibrary:
case Options::kDynamicBundle:
+ if ( !fDataInCodeInfoLoadCommandForcedOff )
+ fDataInCodeInfoLoadCommand = true;
if ( !fFunctionStartsForcedOff )
fFunctionStartsLoadCommand = true;
break;
fNeedsThreadLoadCommand = true;
}
else {
- if ( minOS(ld::mac10_8, ld::iOS_Future) ) {
+ if ( (fIOSVersionMin != ld::iOSVersionUnset) && (fArchitecture == CPU_TYPE_I386) ) {
+ // don't use LC_MAIN for simulator until min host OS is 10.8 for simulator
+ fNeedsThreadLoadCommand = true;
+ fEntryPointLoadCommand = false;
+ }
+ else if ( minOS(ld::mac10_8, ld::iOS_6_0) ) {
fEntryPointLoadCommand = true;
fEntryName = "_main";
}
fSourceVersionLoadCommand = false;
}
else {
- if ( minOS(ld::mac10_8, ld::iOS_Future) ) {
+ if ( minOS(ld::mac10_8, ld::iOS_6_0) ) {
fSourceVersionLoadCommand = true;
}
else
fDependentDRInfo = false;
}
else {
- if ( minOS(ld::mac10_8, ld::iOS_Future) )
+ if ( minOS(ld::mac10_8, ld::iOS_6_0) )
fDependentDRInfo = true;
else
fDependentDRInfo = false;
bool fFunctionStartsForcedOn;
bool fFunctionStartsForcedOff;
bool fDataInCodeInfoLoadCommand;
+ bool fDataInCodeInfoLoadCommandForcedOn;
+ bool fDataInCodeInfoLoadCommandForcedOff;
bool fCanReExportSymbols;
bool fObjcCategoryMerging;
bool fPageAlignDataAtoms;
printSectionLayout(state);
const ld::Atom* target;
- throwf("32-bit branch out of range (%lld max is +/-4GB): from %s (0x%08llX) to %s (0x%08llX)",
+ throwf("32-bit branch out of range (%lld max is +/-2GB): from %s (0x%08llX) to %s (0x%08llX)",
displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),
addressOf(state, fixup, &target));
}
case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
case ld::Fixup::kindStoreTargetAddressARMBranch24:
case ld::Fixup::kindStoreTargetAddressThumbBranch22:
case ld::Fixup::kindStoreTargetAddressARMLoad12:
}
}
}
+
+ if ( (_options.architecture() == CPU_TYPE_I386) && (_options.outputKind() == Options::kObjectFile) ) {
+ if ( target->contentType() == ld::Atom::typeTLV )
+ return true;
+ }
// most architectures use external relocations only for references
// to a symbol in another translation unit or for references to "weak symbols" or tentative definitions
// pc-rel instructions are funny. If the target is _foo+8 and _foo is
// external, then the pc-rel instruction *evalutates* to the address 8.
if ( targetUsesExternalReloc ) {
- if ( isPcRelStore(fixupWithStore->kind) ) {
+ // TLV support for i386 acts like RIP relative addressing
+ // The addend is the offset from the PICBase to the end of the instruction
+ if ( (_options.architecture() == CPU_TYPE_I386)
+ && (_options.outputKind() == Options::kObjectFile)
+ && (fixupWithStore->kind == ld::Fixup::kindStoreX86PCRel32TLVLoad) ) {
+ fixupWithTarget->contentAddendOnly = true;
+ fixupWithStore->contentAddendOnly = true;
+ }
+ else if ( isPcRelStore(fixupWithStore->kind) ) {
fixupWithTarget->contentDetlaToAddendOnly = true;
fixupWithStore->contentDetlaToAddendOnly = true;
}
const ld::Atom* atom = *it;
const ld::File* atomFile = atom->file();
const ld::relocatable::File* atomObjFile = dynamic_cast<const ld::relocatable::File*>(atomFile);
- const char* newDirPath;
- const char* newFilename;
//fprintf(stderr, "debug note for %s\n", atom->name());
- // guard against dwarf info that has no directory <rdar://problem/10991352>
- if ( atom->translationUnitSource(&newDirPath, &newFilename) && (newDirPath != NULL)) {
+ const char* newPath = atom->translationUnitSource();
+ if ( newPath != NULL ) {
+ const char* newDirPath;
+ const char* newFilename;
+ const char* lastSlash = strrchr(newPath, '/');
+ if ( lastSlash == NULL )
+ continue;
+ newFilename = lastSlash+1;
+ char* temp = strdup(newPath);
+ newDirPath = temp;
+ // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
+ temp[lastSlash-newPath+1] = '\0';
// 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 '/'
- size_t len = strlen(newDirPath);
- if ( (newDirPath != NULL) && (len > 1 ) && (newDirPath[len-1] != '/') )
- asprintf((char**)&newDirPath, "%s/", newDirPath);
+ if ( (filename == NULL) || (strcmp(newFilename,filename) != 0) ) {
if ( filename != NULL ) {
// translation unit change, emit ending SO
ld::relocatable::File::Stab endFileStab;
_name(nm) {}
// overrides of ld::Atom
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 0; }
virtual uint64_t objectAddress() const { return 0; }
// overrides of ld::Atom
virtual const ld::File* file() const { return _aliasOf.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return _aliasOf.translationUnitSource(dir, nm); }
+ virtual const char* translationUnitSource() const
+ { return _aliasOf.translationUnitSource(); }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 0; }
virtual uint64_t objectAddress() const { return _aliasOf.objectAddress(); }
static SectionBoundaryAtom* makeOldSectionBoundaryAtom(const char* name, bool start);
// overrides of ld::Atom
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const ld::File* file() const { return NULL; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 0; }
static SegmentBoundaryAtom* makeOldSegmentBoundaryAtom(const char* name, bool start);
// overrides of ld::Atom
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const ld::File* file() const { return NULL; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 0; }
}
};
-void Resolver::deadStripOptimize()
+void Resolver::deadStripOptimize(bool force)
{
// only do this optimization with -dead_strip
if ( ! _options.deadCodeStrip() )
}
}
- if ( _haveLLVMObjs ) {
+ if ( _haveLLVMObjs && !force ) {
// <rdar://problem/9777977> don't remove combinable atoms, they may come back in lto output
_atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), NotLiveLTO()), _atoms.end());
}
// <rdar://problem/7783918> make sure there is a __text section so that codesigning works
if ( (_options.outputKind() == Options::kDynamicLibrary) || (_options.outputKind() == Options::kDynamicBundle) )
_internal.getFinalSection(ld::Section("__TEXT", "__text", ld::Section::typeCode));
+}
- // add entry point
+void Resolver::fillInEntryPoint()
+{
_internal.entryPoint = this->entryPoint(true);
}
// only do work here if some llvm obj files where loaded
if ( ! _haveLLVMObjs )
return;
-
+
// run LLVM lto code-gen
lto::OptimizeOptions optOpt;
optOpt.outputFilePath = _options.outputFilePath();
(const_cast<ld::Atom*>(*it))->setLive((*it)->dontDeadStrip());
}
// and re-compute dead code
- this->deadStripOptimize();
+ this->deadStripOptimize(true);
}
if ( _options.outputKind() == Options::kObjectFile ) {
this->checkUndefines();
this->checkDylibSymbolCollisions();
this->removeCoalescedAwayAtoms();
+ this->fillInEntryPoint();
this->linkTimeOptimize();
this->fillInInternalState();
this->tweakWeakness();
void initializeState();
void buildAtomList();
void addInitialUndefines();
- void deadStripOptimize();
+ void deadStripOptimize(bool force=false);
void resolveUndefines();
void checkUndefines(bool force=false);
void checkDylibSymbolCollisions();
void fillInInternalState();
void fillInHelpersInInternalState();
void removeCoalescedAwayAtoms();
+ void fillInEntryPoint();
void linkTimeOptimize();
void convertReferencesToIndirect(const ld::Atom& atom);
const ld::Atom* entryPoint(bool searchArchives);
uint32_t curClusterOffsetInAtom = 0;
for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
//fprintf(stderr, " fixup offset=%d, cluster=%d\n", fit->offsetInAtom, fit->clusterSize);
- assert((fit->offsetInAtom < atom.size()) || (fit->offsetInAtom == 0));
+ assert((fit->offsetInAtom <= atom.size()) || (fit->offsetInAtom == 0));
if ( fit->firstInCluster() ) {
assert(lastWasClusterEnd);
curClusterOffsetInAtom = fit->offsetInAtom;
mac10_Future=0x10000000 };
enum IOSVersionMin { iOSVersionUnset=0, iOS_2_0=0x00020000, iOS_3_1=0x00030100,
iOS_4_2=0x00040200, iOS_4_3=0x00040300, iOS_5_0=0x00050000,
- iOS_Future=0x10000000};
+ iOS_6_0=0x00060000, iOS_Future=0x10000000};
namespace relocatable {
//
bool finalAddressMode() const { return (_mode == modeFinalAddress); }
#endif
virtual const File* file() const = 0;
- virtual bool translationUnitSource(const char** dir, const char** name) const = 0;
+ virtual const char* translationUnitSource() const { return NULL; }
virtual const char* name() const = 0;
virtual uint64_t objectAddress() const = 0;
virtual uint64_t size() const = 0;
}
// see if member is llvm bitcode file
result = lto::parse(member->content(), member->contentSize(),
- mPath, member->modificationTime(),
+ mPath, member->modificationTime(), ordinal,
_objOpts.architecture, _objOpts.subType, _logAllFiles);
if ( result != NULL ) {
MemberState state = {result, member, false, false, memberIndex};
InternalAtom(class File& f);
// overrides of ld::Atom
virtual ld::File* file() const { return &_file; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return "import-atom"; }
virtual uint64_t size() const { return 0; }
virtual uint64_t objectAddress() const { return 0; }
class File : public ld::relocatable::File
{
public:
- File(const char* path, time_t mTime, const uint8_t* content,
- uint32_t contentLength, cpu_type_t arch);
+ File(const char* path, time_t mTime, ld::File::Ordinal ordinal,
+ const uint8_t* content, uint32_t contentLength, cpu_type_t arch);
virtual ~File();
// overrides of ld::File
// overrides of ld::Atom
virtual ld::File* file() const { return &_file; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return (_compiledAtom ? _compiledAtom->translationUnitSource(dir, nm) : false); }
+ virtual const char* translationUnitSource() const
+ { return (_compiledAtom ? _compiledAtom->translationUnitSource() : NULL); }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return (_compiledAtom ? _compiledAtom->size() : 0); }
virtual uint64_t objectAddress() const { return (_compiledAtom ? _compiledAtom->objectAddress() : 0); }
static bool validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch);
static const char* fileKind(const uint8_t* fileContent, uint64_t fileLength);
static File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
- time_t modTime, cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles);
+ time_t modTime, ld::File::Ordinal ordinal, cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles);
static bool libLTOisLoaded() { return (::lto_get_version() != NULL); }
static bool optimize( const std::vector<const ld::Atom*>& allAtoms,
ld::Internal& state,
return NULL;
}
-File* Parser::parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime,
+File* Parser::parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, ld::File::Ordinal ordinal,
cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles)
{
- File* f = new File(path, modTime, fileContent, fileLength, architecture);
+ File* f = new File(path, modTime, ordinal, fileContent, fileLength, architecture);
_s_files.push_back(f);
if ( logAllFiles )
printf("%s\n", path);
-File::File(const char* pth, time_t mTime, const uint8_t* content, uint32_t contentLength, cpu_type_t arch)
- : ld::relocatable::File(pth,mTime,ld::File::Ordinal::LTOOrdinal()), _architecture(arch), _internalAtom(*this),
+File::File(const char* pth, time_t mTime, ld::File::Ordinal ordinal, const uint8_t* content, uint32_t contentLength, cpu_type_t arch)
+ : ld::relocatable::File(pth,mTime,ordinal), _architecture(arch), _internalAtom(*this),
_atomArray(NULL), _atomArrayCount(0), _module(NULL), _debugInfoPath(pth),
_section("__TEXT_", "__tmp_lto", ld::Section::typeTempLTO),
_fixupToInternal(0, ld::Fixup::k1of1, ld::Fixup::kindNone, &_internalAtom),
// main function used by linker to instantiate ld::Files
//
ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength,
- const char* path, time_t modTime,
+ const char* path, time_t modTime, ld::File::Ordinal ordinal,
cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles)
{
Mutex lock;
if ( Parser::validFile(fileContent, fileLength, architecture, subarch) )
- return Parser::parse(fileContent, fileLength, path, modTime, architecture, subarch, logAllFiles);
+ return Parser::parse(fileContent, fileLength, path, modTime, ordinal, architecture, subarch, logAllFiles);
else
return NULL;
}
extern bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch);
extern ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength,
- const char* path, time_t modTime,
+ const char* path, time_t modTime, ld::File::Ordinal ordinal,
cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles);
struct OptimizeOptions {
_file(f), _name(nm), _address(address) {}
// overrides of ld::Atom
virtual const ld::File* file() const { return &_file; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 0; }
virtual uint64_t objectAddress() const { return _address; }
// overrides of ld::Atom
virtual ld::File* file() const { return &_file; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return "import-atom"; }
virtual uint64_t size() const { return 0; }
virtual uint64_t objectAddress() const { return 0; }
// pass 2 builds list of all dependent libraries
_dependentDylibs.reserve(dependentLibCount);
cmd = cmds;
+ unsigned int reExportDylibCount = 0;
for (uint32_t i = 0; i < cmd_count; ++i) {
switch (cmd->cmd()) {
case LC_LOAD_DYLIB:
if ( compressedLinkEdit && !linkingFlatNamespace )
break;
case LC_REEXPORT_DYLIB:
+ ++reExportDylibCount;
Dependent entry;
entry.path = strdup(((macho_dylib_command<P>*)cmd)->name());
entry.dylib = NULL;
}
// verify MH_NO_REEXPORTED_DYLIBS bit was correct
if ( compressedLinkEdit && !linkingFlatNamespace ) {
- assert(_dependentDylibs.size() != 0);
+ assert(reExportDylibCount != 0);
}
// pass 3 add re-export info
cmd = cmds;
_sectionsArray(NULL), _atomsArray(NULL),
_sectionsArrayCount(0), _atomsArrayCount(0),
_debugInfoKind(ld::relocatable::File::kDebugInfoNone),
- _dwarfTranslationUnitDir(NULL), _dwarfTranslationUnitFile(NULL),
+ _dwarfTranslationUnitPath(NULL),
_dwarfDebugInfoSect(NULL), _dwarfDebugAbbrevSect(NULL),
_dwarfDebugLineSect(NULL), _dwarfDebugStringSect(NULL),
_objConstraint(ld::File::objcConstraintNone),
virtual DebugInfoKind debugInfo() const { return _debugInfoKind; }
virtual const std::vector<ld::relocatable::File::Stab>* stabs() const { return &_stabs; }
virtual bool canScatterAtoms() const { return _canScatterAtoms; }
- bool translationUnitSource(const char** dir, const char** name) const;
+ virtual const char* translationUnitSource() const;
const uint8_t* fileContent() { return _fileContent; }
private:
std::vector<ld::Atom::LineInfo> _lineInfos;
std::vector<ld::relocatable::File::Stab>_stabs;
ld::relocatable::File::DebugInfoKind _debugInfoKind;
- const char* _dwarfTranslationUnitDir;
- const char* _dwarfTranslationUnitFile;
+ const char* _dwarfTranslationUnitPath;
const macho_section<P>* _dwarfDebugInfoSect;
const macho_section<P>* _dwarfDebugAbbrevSect;
const macho_section<P>* _dwarfDebugLineSect;
public:
// overrides of ld::Atom
virtual ld::File* file() const { return §().file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return sect().file().translationUnitSource(dir, nm); }
+ virtual const char* translationUnitSource() const
+ { return sect().file().translationUnitSource(); }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return _size; }
virtual uint64_t objectAddress() const { return _objAddress; }
bool convertUnwindInfo() { return _convertUnwindInfo; }
bool hasDataInCodeLabels() { return _hasDataInCodeLabels; }
+ macho_data_in_code_entry<P>* dataInCodeStart() { return _dataInCodeStart; }
+ macho_data_in_code_entry<P>* dataInCodeEnd() { return _dataInCodeEnd; }
void addFixups(const SourceLocation& src, ld::Fixup::Kind kind, const TargetDesc& target);
void addFixups(const SourceLocation& src, ld::Fixup::Kind kind, const TargetDesc& target, const TargetDesc& picBase);
const macho_section<P>* _sectionsStart;
uint32_t _machOSectionsCount;
bool _hasUUID;
-
+ macho_data_in_code_entry<P>* _dataInCodeStart;
+ macho_data_in_code_entry<P>* _dataInCodeEnd;
+
// filled in by parse()
CFISection<A>* _EHFrameSection;
CUSection<A>* _compactUnwindSection;
_indirectTable(NULL), _indirectTableCount(0),
_undefinedStartIndex(0), _undefinedEndIndex(0),
_sectionsStart(NULL), _machOSectionsCount(0), _hasUUID(false),
+ _dataInCodeStart(NULL), _dataInCodeEnd(NULL),
_EHFrameSection(NULL), _compactUnwindSection(NULL), _absoluteSection(NULL),
_tentativeDefinitionCount(0), _absoluteSymbolCount(0),
_symbolsInSections(0), _hasLongBranchStubs(false), _AppleObjc(false),
case LC_UUID:
_hasUUID = true;
break;
-
+ case LC_DATA_IN_CODE:
+ {
+ const macho_linkedit_data_command<P>* dc = (macho_linkedit_data_command<P>*)cmd;
+ _dataInCodeStart = (macho_data_in_code_entry<P>*)(_fileContent + dc->dataoff());
+ _dataInCodeEnd = (macho_data_in_code_entry<P>*)(_fileContent + dc->dataoff() + dc->datasize());
+ if ( _dataInCodeEnd > (macho_data_in_code_entry<P>*)endOfFile )
+ throw "LC_DATA_IN_CODE table extends beyond end of file";
+ }
default:
if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
if ( segment != NULL )
return;
uint64_t stmtList;
- if ( !read_comp_unit(&_file->_dwarfTranslationUnitFile, &_file->_dwarfTranslationUnitDir, &stmtList) ) {
+ const char* tuDir;
+ const char* tuName;
+ if ( !read_comp_unit(&tuName, &tuDir, &stmtList) ) {
// if can't parse dwarf, warn and give up
- _file->_dwarfTranslationUnitFile = NULL;
- _file->_dwarfTranslationUnitDir = NULL;
+ _file->_dwarfTranslationUnitPath = NULL;
warning("can't parse dwarf compilation unit info in %s", _path);
_file->_debugInfoKind = ld::relocatable::File::kDebugInfoNone;
return;
}
+ if ( (tuName != NULL) && (tuName[1] == '/') ) {
+ _file->_dwarfTranslationUnitPath = tuName;
+ }
+ else if ( (tuDir != NULL) && (tuName != NULL) ) {
+ asprintf((char**)&(_file->_dwarfTranslationUnitPath), "%s/%s", tuDir, tuName);
+ }
+ else if ( tuDir == NULL ) {
+ _file->_dwarfTranslationUnitPath = tuName;
+ }
+ else {
+ _file->_dwarfTranslationUnitPath = NULL;
+ }
// add line number info to atoms from dwarf
std::vector<AtomAndLineInfo<A> > entries;
}
template <typename A>
-bool File<A>::translationUnitSource(const char** dir, const char** name) const
+const char* File<A>::translationUnitSource() const
{
- if ( _debugInfoKind == ld::relocatable::File::kDebugInfoDwarf ) {
- *dir = _dwarfTranslationUnitDir;
- *name = _dwarfTranslationUnitFile;
- return (_dwarfTranslationUnitFile != NULL);
- }
- return false;
+ return _dwarfTranslationUnitPath;
}
}
}
+ // <rdar://problem/11150575> Handle LC_DATA_IN_CODE in object files
+ if ( this->type() == ld::Section::typeCode ) {
+ const pint_t startAddr = this->_machOSection->addr();
+ const pint_t endAddr = startAddr + this->_machOSection->size();
+ for ( const macho_data_in_code_entry<P>* p = parser.dataInCodeStart(); p != parser.dataInCodeEnd(); ++p ) {
+ if ( (p->offset() >= startAddr) && (p->offset() < endAddr) ) {
+ ld::Fixup::Kind kind = ld::Fixup::kindNone;
+ switch ( p->kind() ) {
+ case DICE_KIND_DATA:
+ kind = ld::Fixup::kindDataInCodeStartData;
+ break;
+ case DICE_KIND_JUMP_TABLE8:
+ kind = ld::Fixup::kindDataInCodeStartJT8;
+ break;
+ case DICE_KIND_JUMP_TABLE16:
+ kind = ld::Fixup::kindDataInCodeStartJT16;
+ break;
+ case DICE_KIND_JUMP_TABLE32:
+ kind = ld::Fixup::kindDataInCodeStartJT32;
+ break;
+ case DICE_KIND_ABS_JUMP_TABLE32:
+ kind = ld::Fixup::kindDataInCodeStartJTA32;
+ break;
+ default:
+ kind = ld::Fixup::kindDataInCodeStartData;
+ warning("uknown LC_DATA_IN_CODE kind (%d) at offset 0x%08X", p->kind(), p->offset());
+ break;
+ }
+ Atom<A>* inAtom = parser.findAtomByAddress(p->offset());
+ typename Parser<A>::SourceLocation srcStart(inAtom, p->offset() - inAtom->objectAddress());
+ parser.addFixup(srcStart, ld::Fixup::k1of1, kind);
+ typename Parser<A>::SourceLocation srcEnd(inAtom, p->offset() + p->length() - inAtom->objectAddress());
+ parser.addFixup(srcEnd, ld::Fixup::k1of1, ld::Fixup::kindDataInCodeEnd);
+ }
+ }
+ }
+
+
// add follow-on fixups for aliases
if ( _hasAliases ) {
for(Atom<A>* p = _beginAtoms; p < _endAtoms; ++p) {
class Atom : public ld::Atom {
public:
virtual ld::File* file() const { return (ld::File*)&_file; }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return _size; }
virtual uint64_t objectAddress() const { return 0; }
_finalTarget(finalTarget) { }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 4; }
virtual uint64_t objectAddress() const { return 0; }
_finalTarget(finalTarget) { }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 16; }
virtual uint64_t objectAddress() const { return 0; }
_finalTarget(finalTarget) { }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 4; }
virtual uint64_t objectAddress() const { return 0; }
_finalTarget(finalTarget) { }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 8; }
virtual uint64_t objectAddress() const { return 0; }
{ asprintf((char**)&_name, "%s$shim", target->name()); }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 12; }
virtual uint64_t objectAddress() const { return 0; }
{ asprintf((char**)&_name, "%s$shim", target->name()); }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 12; }
virtual uint64_t objectAddress() const { return 0; }
{ asprintf((char**)&_name, "%s$shim", target->name()); }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 16; }
virtual uint64_t objectAddress() const { return 0; }
{ asprintf((char**)&_name, "%s$shim", target->name()); }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 16; }
virtual uint64_t objectAddress() const { return 0; }
{ asprintf((char**)&_name, "%s$shim", target->name()); }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 12; }
virtual uint64_t objectAddress() const { return 0; }
~UnwindInfoAtom();
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return "compact unwind info"; }
virtual uint64_t size() const { return _headerSize+_pagesSize; }
virtual uint64_t objectAddress() const { return 0; }
~CompactUnwindAtom() {}
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return "compact unwind info"; }
virtual uint64_t size() const { return sizeof(macho_compact_unwind_entry<P>); }
virtual uint64_t objectAddress() const { return 0; }
Atom(class File& f, const char* n, const uint8_t* content, uint64_t sz);
virtual ld::File* file() const { return (ld::File*)&_file; }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return _size; }
virtual uint64_t objectAddress() const { return 0; }
{
// const bool log = false;
- // only optimize dylibs in final linked images
- if ( opts.outputKind() == Options::kObjectFile )
- return;
-
// clear "willRemoved" bit on all dylibs
for (std::vector<ld::dylib::File*>::iterator it = state.dylibs.begin(); it != state.dylibs.end(); ++it) {
ld::dylib::File* aDylib = *it;
{ _fixup.weakImport = weakImport; internal.addAtom(*this); }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return _target->name(); }
virtual uint64_t size() const { return 8; }
virtual uint64_t objectAddress() const { return 0; }
bool compaction, bool abi2);
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return "objc image info"; }
virtual uint64_t size() const { return sizeof(objc_image_info); }
virtual uint64_t objectAddress() const { return 0; }
std::set<const ld::Atom*>& deadAtoms);
virtual const ld::File* file() const { return _file; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return "objc merged method list"; }
virtual uint64_t size() const { return _methodCount*3*sizeof(pint_t) + 8; }
virtual uint64_t objectAddress() const { return 0; }
std::set<const ld::Atom*>& deadAtoms);
virtual const ld::File* file() const { return _file; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return "objc merged protocol list"; }
virtual uint64_t size() const { return (_protocolCount+1)*sizeof(pint_t); }
virtual uint64_t objectAddress() const { return 0; }
std::set<const ld::Atom*>& deadAtoms);
virtual const ld::File* file() const { return _file; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return "objc merged property list"; }
virtual uint64_t size() const { return _propertyCount*2*sizeof(pint_t) + 8; }
virtual uint64_t objectAddress() const { return 0; }
// overrides of ld::Atom
virtual const ld::File* file() const { return _atom->file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return _atom->translationUnitSource(dir, nm); }
virtual const char* name() const { return _atom->name(); }
virtual uint64_t size() const { return _atom->size(); }
virtual uint64_t objectAddress() const { return _atom->objectAddress(); }
{ pass.addAtom(*this); }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return "fast binder pointer"; }
virtual uint64_t size() const { return 4; }
virtual uint64_t objectAddress() const { return 0; }
symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)) { pass.addAtom(*this); }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return "non-lazy pointer"; }
virtual uint64_t size() const { return 4; }
virtual uint64_t objectAddress() const { return 0; }
{ pass.addAtom(*this); }
virtual ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return " stub helpers"; }
virtual uint64_t size() const { return 36; }
virtual uint64_t objectAddress() const { return 0; }
_fixup3(8, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32) { }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 12; }
virtual uint64_t objectAddress() const { return 0; }
_fixup5(32, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32) { }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 36; }
virtual uint64_t objectAddress() const { return 0; }
}
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 4; }
virtual uint64_t objectAddress() const { return 0; }
}
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 4; }
virtual uint64_t objectAddress() const { return 0; }
}
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 16; }
virtual uint64_t objectAddress() const { return 0; }
{ pass.addAtom(*this); }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 16; }
virtual uint64_t objectAddress() const { return 0; }
{ pass.addAtom(*this); }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 12; }
virtual uint64_t objectAddress() const { return 0; }
{ pass.addAtom(*this); }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 4; }
virtual uint64_t objectAddress() const { return 0; }
{ _fixup2.weakImport = weakImport; pass.addAtom(*this); }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 4; }
virtual uint64_t objectAddress() const { return 0; }
{ pass.addAtom(*this); }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 16; }
virtual uint64_t objectAddress() const { return 0; }
{ pass.addAtom(*this); }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 12; }
virtual uint64_t objectAddress() const { return 0; }
{ pass.addAtom(*this); }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return "fast binder pointer"; }
virtual uint64_t size() const { return 4; }
virtual uint64_t objectAddress() const { return 0; }
symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)) { pass.addAtom(*this); }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return "image cache pointer"; }
virtual uint64_t size() const { return 4; }
virtual uint64_t objectAddress() const { return 0; }
{ pass.addAtom(*this); }
virtual ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return "helper helper"; }
virtual uint64_t size() const { return 12; }
virtual uint64_t objectAddress() const { return 0; }
_fixup3(6, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32, helperHelper(pass)) { }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 10; }
virtual uint64_t objectAddress() const { return 0; }
_fixup3(18, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, lazyPointer) { }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 22; }
virtual uint64_t objectAddress() const { return 0; }
}
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 4; }
virtual uint64_t objectAddress() const { return 0; }
_fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &_lazyPointer) { pass.addAtom(*this); }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 6; }
virtual uint64_t objectAddress() const { return 0; }
{ pass.addAtom(*this); }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return "fast binder pointer"; }
virtual uint64_t size() const { return 8; }
virtual uint64_t objectAddress() const { return 0; }
symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)) { pass.addAtom(*this); }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return "image cache pointer"; }
virtual uint64_t size() const { return 8; }
virtual uint64_t objectAddress() const { return 0; }
{ pass.addAtom(*this); }
virtual ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return "helper helper"; }
virtual uint64_t size() const { return 16; }
virtual uint64_t objectAddress() const { return 0; }
_fixup3(6, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32, helperHelper(pass)) { }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 10; }
virtual uint64_t objectAddress() const { return 0; }
_fixup3(32, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, lazyPointer) { }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 36; }
virtual uint64_t objectAddress() const { return 0; }
}
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 8; }
virtual uint64_t objectAddress() const { return 0; }
_fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &_lazyPointer) { pass.addAtom(*this); }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 6; }
virtual uint64_t objectAddress() const { return 0; }
}
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 8; }
virtual uint64_t objectAddress() const { return 0; }
_fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &_nonLazyPointer) { pass.addAtom(*this); }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 6; }
virtual uint64_t objectAddress() const { return 0; }
{ pass.addAtom(*this); }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 12; }
virtual uint64_t objectAddress() const { return 0; }
{ _fixup2.weakImport = weakImport; pass.addAtom(*this); }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 8; }
virtual uint64_t objectAddress() const { return 0; }
_fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &_lazyPointer) { pass.addAtom(*this); }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 6; }
virtual uint64_t objectAddress() const { return 0; }
{ pass.addAtom(*this); }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 10; }
virtual uint64_t objectAddress() const { return 0; }
{ _fixup2.weakImport = weakImport; pass.addAtom(*this); }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 4; }
virtual uint64_t objectAddress() const { return 0; }
_fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &_lazyPointer) { pass.addAtom(*this); }
virtual const ld::File* file() const { return _stubTo.file(); }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return _stubTo.name(); }
virtual uint64_t size() const { return 6; }
virtual uint64_t objectAddress() const { return 0; }
{ _fixup.weakImport = weakImport; internal.addAtom(*this); }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return _target->name(); }
virtual uint64_t size() const { return 8; }
virtual uint64_t objectAddress() const { return 0; }
return objResult;
// see if it is an llvm object file
- objResult = lto::parse(p, fileLen, path, stat_buf.st_mtime, sPreferredArch, sPreferredSubArch, false);
+ objResult = lto::parse(p, fileLen, path, stat_buf.st_mtime, ld::File::Ordinal::NullOrdinal(), sPreferredArch, sPreferredSubArch, false);
if ( objResult != NULL )
return objResult;
LD_NEW_LINKEDIT = -macosx_version_min 10.6
CXX = $(shell xcrun -find clang++) -arch ${ARCH} ${SDKExtra}
-CXXFLAGS = -Wall
+CXXFLAGS = -Wall -stdlib=libc++
IOS_SDK = $(shell xcodebuild -sdk iphoneos6.0.internal -version Path)
ifeq ($(ARCH),armv6)
LDFLAGS := -syslibroot $(IOS_SDK)
override FILEARCH = arm
- CC = $(shell xcrun -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
- CXX = $(shell xcrun -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+ CC = $(shell xcrun -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+ CXX = $(shell xcrun -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
LD_SYSROOT = -syslibroot $(IOS_SDK)
0000 ENSYM
0000 BNSYM
0000 FUN __Z3fooi
-0000 SOL CWD/header.h
+0000 SOL ./header.h
0000 FUN
0000 ENSYM
0000 SO
extern void foo1();
+extern void foo2();
void t1()
strlen("str3");
}
+// <rdar://problem/12005173> error with LTO and dead strip of non-lazy-pointer
+void* foo2p() {
+ return &foo2;
+}
int main()
{
${PASS_IFF_GOOD_MACHO} foo
clean:
- rm -rf foo
+ rm -rf foo foo.dSYM
}
#endif
+class Foo {
+ int a;
+ int b;
+public:
+ void print();
+};
+
+void Foo::print() {
+ printf("%d\n", a);
+}
+
+
int main()
{
+ Foo* f = new Foo();
+ f->print();
return 0;
}
nm -ap outfile | grep '.*\<SO\>.*test-cases.*/$$' | ${PASS_IFF_STDIN}
clean:
- rm outfile*
+ rm -rf outfile*
--- /dev/null
+##
+# Copyright (c) 2012 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that main executable can use TLVs with -dead_strip
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o #-mdynamic-no-pic
+ ${LD} -arch ${ARCH} -r foo.o -o foo-r.o
+ ${OBJECTDUMP} foo.o > foo.o.dump
+ ${OBJECTDUMP} foo-r.o > foo-r.o.dump
+ ${PASS_IFF} diff foo.o.dump foo-r.o.dump
+
+clean:
+ rm -f foo.o foo-r.o foo.o.dump foo-r.o.dump
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+__thread int a = 0;
+__thread static int b = 0;
+extern __thread int c;
+
+int foo() {
+ return a+b+c;
+}
+
--- /dev/null
+##
+# Copyright (c) 2012 Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test the weak_import attribute is preserved in -r mode.
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ nm -m main.o | grep _func1 | grep -v weak >/dev/null
+ nm -m main.o | grep _func2 | grep weak >/dev/null
+ nm -m main.o | grep _func3 | grep -v weak >/dev/null
+ nm -m main.o | grep _func4 | grep weak >/dev/null
+ nm -m main.o | grep _data1 | grep -v weak >/dev/null
+ nm -m main.o | grep _data2 | grep weak >/dev/null
+ nm -m main.o | grep _data3 | grep -v weak >/dev/null
+ nm -m main.o | grep _data4 | grep weak >/dev/null
+ nm -m main.o | grep _data5 | grep -v weak >/dev/null
+ nm -m main.o | grep _data6 | grep weak >/dev/null
+
+ ${LD} -r -arch ${ARCH} main.o -o main-r.o
+ nm -m main-r.o | grep _func1 | grep -v weak >/dev/null
+ nm -m main-r.o | grep _func2 | grep weak >/dev/null
+ nm -m main-r.o | grep _func3 | grep -v weak >/dev/null
+ nm -m main-r.o | grep _func4 | grep weak >/dev/null
+ nm -m main-r.o | grep _data1 | grep -v weak >/dev/null
+ nm -m main-r.o | grep _data2 | grep weak >/dev/null
+ nm -m main-r.o | grep _data3 | grep -v weak >/dev/null
+ nm -m main-r.o | grep _data4 | grep weak >/dev/null
+ ${PASS_IFF} true
+
+clean:
+ rm -rf *.o
--- /dev/null
+
+
+extern void func1();
+extern void func2() __attribute__((weak_import));
+extern void func3();
+extern void func4() __attribute__((weak_import));
+
+extern int data1;
+extern int data2 __attribute__((weak_import));
+extern int data3;
+extern int data4 __attribute__((weak_import));
+extern int data5;
+extern int data6 __attribute__((weak_import));
+
+
+
--- /dev/null
+#include <stddef.h>
+
+#include "foo.h"
+
+
+int* pdata5 = &data5;
+int* pdata6 = &data6;
+
+void* pf3;
+
+int main (void)
+{
+ // make non-lazy reference to func3 and func4
+ pf3 = &func3;
+ if ( &func4 == NULL ) {
+ // make lazy reference to func1 and func2
+ func1();
+ func2();
+ }
+
+ return data1 + data2 + data3 + data4;
+}
+