]> git.saurik.com Git - apple/ld64.git/commitdiff
ld64-21.tar.gz mac-os-x-104 mac-os-x-1041 mac-os-x-1042 v21
authorApple <opensource@apple.com>
Thu, 14 Apr 2005 21:30:21 +0000 (21:30 +0000)
committerApple <opensource@apple.com>
Thu, 14 Apr 2005 21:30:21 +0000 (21:30 +0000)
20 files changed:
APPLE_LICENSE [new file with mode: 0644]
doc/man/man1/ld64.1 [new file with mode: 0644]
ld64.xcode/project.pbxproj [new file with mode: 0644]
src/ExecutableFile.h [new file with mode: 0644]
src/MachOAbstraction.h [new file with mode: 0644]
src/ObjDump.cpp [new file with mode: 0644]
src/ObjectFile.h [new file with mode: 0644]
src/Options.cpp [new file with mode: 0644]
src/Options.h [new file with mode: 0644]
src/Readers/ObjectFileArchiveMachO.cpp [new file with mode: 0644]
src/Readers/ObjectFileDylibMachO.cpp [new file with mode: 0644]
src/Readers/ObjectFileMachO-all.cpp [new file with mode: 0644]
src/Readers/ObjectFileMachO-all.h [new file with mode: 0644]
src/Readers/ObjectFileMachO.cpp [new file with mode: 0644]
src/SectCreate.cpp [new file with mode: 0644]
src/SectCreate.h [new file with mode: 0644]
src/Writers/ExecutableFileMachO-all.cpp [new file with mode: 0644]
src/Writers/ExecutableFileMachO-all.h [new file with mode: 0644]
src/Writers/ExecutableFileMachO.cpp [new file with mode: 0644]
src/ld.cpp [new file with mode: 0644]

diff --git a/APPLE_LICENSE b/APPLE_LICENSE
new file mode 100644 (file)
index 0000000..fe81a60
--- /dev/null
@@ -0,0 +1,367 @@
+APPLE PUBLIC SOURCE LICENSE
+Version 2.0 - August 6, 2003
+
+Please read this License carefully before downloading this software.
+By downloading or using this software, you are agreeing to be bound by
+the terms of this License. If you do not or cannot agree to the terms
+of this License, please do not download or use the software.
+
+1. General; Definitions. This License applies to any program or other
+work which Apple Computer, Inc. ("Apple") makes publicly available and
+which contains a notice placed by Apple identifying such program or
+work as "Original Code" and stating that it is subject to the terms of
+this Apple Public Source License version 2.0 ("License"). As used in
+this License:
+
+1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is
+the grantor of rights, (i) claims of patents that are now or hereafter
+acquired, owned by or assigned to Apple and (ii) that cover subject
+matter contained in the Original Code, but only to the extent
+necessary to use, reproduce and/or distribute the Original Code
+without infringement; and (b) in the case where You are the grantor of
+rights, (i) claims of patents that are now or hereafter acquired,
+owned by or assigned to You and (ii) that cover subject matter in Your
+Modifications, taken alone or in combination with Original Code.
+
+1.2 "Contributor" means any person or entity that creates or
+contributes to the creation of Modifications.
+
+1.3 "Covered Code" means the Original Code, Modifications, the
+combination of Original Code and any Modifications, and/or any
+respective portions thereof.
+
+1.4 "Externally Deploy" means: (a) to sublicense, distribute or
+otherwise make Covered Code available, directly or indirectly, to
+anyone other than You; and/or (b) to use Covered Code, alone or as
+part of a Larger Work, in any way to provide a service, including but
+not limited to delivery of content, through electronic communication
+with a client other than You.
+
+1.5 "Larger Work" means a work which combines Covered Code or portions
+thereof with code not governed by the terms of this License.
+
+1.6 "Modifications" mean any addition to, deletion from, and/or change
+to, the substance and/or structure of the Original Code, any previous
+Modifications, the combination of Original Code and any previous
+Modifications, and/or any respective portions thereof. When code is
+released as a series of files, a Modification is: (a) any addition to
+or deletion from the contents of a file containing Covered Code;
+and/or (b) any new file or other representation of computer program
+statements that contains any part of Covered Code.
+
+1.7 "Original Code" means (a) the Source Code of a program or other
+work as originally made available by Apple under this License,
+including the Source Code of any updates or upgrades to such programs
+or works made available by Apple under this License, and that has been
+expressly identified by Apple as such in the header file(s) of such
+work; and (b) the object code compiled from such Source Code and
+originally made available by Apple under this License.
+
+1.8 "Source Code" means the human readable form of a program or other
+work that is suitable for making modifications to it, including all
+modules it contains, plus any associated interface definition files,
+scripts used to control compilation and installation of an executable
+(object code).
+
+1.9 "You" or "Your" means an individual or a legal entity exercising
+rights under this License. For legal entities, "You" or "Your"
+includes any entity which controls, is controlled by, or is under
+common control with, You, where "control" means (a) the power, direct
+or indirect, to cause the direction or management of such entity,
+whether by contract or otherwise, or (b) ownership of fifty percent
+(50%) or more of the outstanding shares or beneficial ownership of
+such entity.
+
+2. Permitted Uses; Conditions & Restrictions. Subject to the terms
+and conditions of this License, Apple hereby grants You, effective on
+the date You accept this License and download the Original Code, a
+world-wide, royalty-free, non-exclusive license, to the extent of
+Apple's Applicable Patent Rights and copyrights covering the Original
+Code, to do the following:
+
+2.1 Unmodified Code. You may use, reproduce, display, perform,
+internally distribute within Your organization, and Externally Deploy
+verbatim, unmodified copies of the Original Code, for commercial or
+non-commercial purposes, provided that in each instance:
+
+(a) You must retain and reproduce in all copies of Original Code the
+copyright and other proprietary notices and disclaimers of Apple as
+they appear in the Original Code, and keep intact all notices in the
+Original Code that refer to this License; and
+
+(b) You must include a copy of this License with every copy of Source
+Code of Covered Code and documentation You distribute or Externally
+Deploy, and You may not offer or impose any terms on such Source Code
+that alter or restrict this License or the recipients' rights
+hereunder, except as permitted under Section 6.
+
+2.2 Modified Code. You may modify Covered Code and use, reproduce,
+display, perform, internally distribute within Your organization, and
+Externally Deploy Your Modifications and Covered Code, for commercial
+or non-commercial purposes, provided that in each instance You also
+meet all of these conditions:
+
+(a) You must satisfy all the conditions of Section 2.1 with respect to
+the Source Code of the Covered Code;
+
+(b) You must duplicate, to the extent it does not already exist, the
+notice in Exhibit A in each file of the Source Code of all Your
+Modifications, and cause the modified files to carry prominent notices
+stating that You changed the files and the date of any change; and
+
+(c) If You Externally Deploy Your Modifications, You must make
+Source Code of all Your Externally Deployed Modifications either
+available to those to whom You have Externally Deployed Your
+Modifications, or publicly available. Source Code of Your Externally
+Deployed Modifications must be released under the terms set forth in
+this License, including the license grants set forth in Section 3
+below, for as long as you Externally Deploy the Covered Code or twelve
+(12) months from the date of initial External Deployment, whichever is
+longer. You should preferably distribute the Source Code of Your
+Externally Deployed Modifications electronically (e.g. download from a
+web site).
+
+2.3 Distribution of Executable Versions. In addition, if You
+Externally Deploy Covered Code (Original Code and/or Modifications) in
+object code, executable form only, You must include a prominent
+notice, in the code itself as well as in related documentation,
+stating that Source Code of the Covered Code is available under the
+terms of this License with information on how and where to obtain such
+Source Code.
+
+2.4 Third Party Rights. You expressly acknowledge and agree that
+although Apple and each Contributor grants the licenses to their
+respective portions of the Covered Code set forth herein, no
+assurances are provided by Apple or any Contributor that the Covered
+Code does not infringe the patent or other intellectual property
+rights of any other entity. Apple and each Contributor disclaim any
+liability to You for claims brought by any other entity based on
+infringement of intellectual property rights or otherwise. As a
+condition to exercising the rights and licenses granted hereunder, You
+hereby assume sole responsibility to secure any other intellectual
+property rights needed, if any. For example, if a third party patent
+license is required to allow You to distribute the Covered Code, it is
+Your responsibility to acquire that license before distributing the
+Covered Code.
+
+3. Your Grants. In consideration of, and as a condition to, the
+licenses granted to You under this License, You hereby grant to any
+person or entity receiving or distributing Covered Code under this
+License a non-exclusive, royalty-free, perpetual, irrevocable license,
+under Your Applicable Patent Rights and other intellectual property
+rights (other than patent) owned or controlled by You, to use,
+reproduce, display, perform, modify, sublicense, distribute and
+Externally Deploy Your Modifications of the same scope and extent as
+Apple's licenses under Sections 2.1 and 2.2 above.
+
+4. Larger Works. You may create a Larger Work by combining Covered
+Code with other code not governed by the terms of this License and
+distribute the Larger Work as a single product. In each such instance,
+You must make sure the requirements of this License are fulfilled for
+the Covered Code or any portion thereof.
+
+5. Limitations on Patent License. Except as expressly stated in
+Section 2, no other patent rights, express or implied, are granted by
+Apple herein. Modifications and/or Larger Works may require additional
+patent licenses from Apple which Apple may grant in its sole
+discretion.
+
+6. Additional Terms. You may choose to offer, and to charge a fee for,
+warranty, support, indemnity or liability obligations and/or other
+rights consistent with the scope of the license granted herein
+("Additional Terms") to one or more recipients of Covered Code.
+However, You may do so only on Your own behalf and as Your sole
+responsibility, and not on behalf of Apple or any Contributor. You
+must obtain the recipient's agreement that any such Additional Terms
+are offered by You alone, and You hereby agree to indemnify, defend
+and hold Apple and every Contributor harmless for any liability
+incurred by or claims asserted against Apple or such Contributor by
+reason of any such Additional Terms.
+
+7. Versions of the License. Apple may publish revised and/or new
+versions of this License from time to time. Each version will be given
+a distinguishing version number. Once Original Code has been published
+under a particular version of this License, You may continue to use it
+under the terms of that version. You may also choose to use such
+Original Code under the terms of any subsequent version of this
+License published by Apple. No one other than Apple has the right to
+modify the terms applicable to Covered Code created under this
+License.
+
+8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in
+part pre-release, untested, or not fully tested works. The Covered
+Code may contain errors that could cause failures or loss of data, and
+may be incomplete or contain inaccuracies. You expressly acknowledge
+and agree that use of the Covered Code, or any portion thereof, is at
+Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND
+WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND
+APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE
+PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
+ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF
+MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR
+PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD
+PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST
+INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE
+FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS,
+THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
+ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO
+ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE
+AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.
+You acknowledge that the Covered Code is not intended for use in the
+operation of nuclear facilities, aircraft navigation, communication
+systems, or air traffic control machines in which case the failure of
+the Covered Code could lead to death, personal injury, or severe
+physical or environmental damage.
+
+9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
+EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL,
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING
+TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR
+ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY,
+TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF
+APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY
+REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF
+INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY
+TO YOU. In no event shall Apple's total liability to You for all
+damages (other than as may be required by applicable law) under this
+License exceed the amount of fifty dollars ($50.00).
+
+10. Trademarks. This License does not grant any rights to use the
+trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS",
+"QuickTime", "QuickTime Streaming Server" or any other trademarks,
+service marks, logos or trade names belonging to Apple (collectively
+"Apple Marks") or to any trademark, service mark, logo or trade name
+belonging to any Contributor. You agree not to use any Apple Marks in
+or as part of the name of products derived from the Original Code or
+to endorse or promote products derived from the Original Code other
+than as expressly permitted by and in strict compliance at all times
+with Apple's third party trademark usage guidelines which are posted
+at http://www.apple.com/legal/guidelinesfor3rdparties.html.
+
+11. Ownership. Subject to the licenses granted under this License,
+each Contributor retains all rights, title and interest in and to any
+Modifications made by such Contributor. Apple retains all rights,
+title and interest in and to the Original Code and any Modifications
+made by or on behalf of Apple ("Apple Modifications"), and such Apple
+Modifications will not be automatically subject to this License. Apple
+may, at its sole discretion, choose to license such Apple
+Modifications under this License, or on different terms from those
+contained in this License or may choose not to license them at all.
+
+12. Termination.
+
+12.1 Termination. This License and the rights granted hereunder will
+terminate:
+
+(a) automatically without notice from Apple if You fail to comply with
+any term(s) of this License and fail to cure such breach within 30
+days of becoming aware of such breach;
+
+(b) immediately in the event of the circumstances described in Section
+13.5(b); or
+
+(c) automatically without notice from Apple if You, at any time during
+the term of this License, commence an action for patent infringement
+against Apple; provided that Apple did not first commence
+an action for patent infringement against You in that instance.
+
+12.2 Effect of Termination. Upon termination, You agree to immediately
+stop any further use, reproduction, modification, sublicensing and
+distribution of the Covered Code. All sublicenses to the Covered Code
+which have been properly granted prior to termination shall survive
+any termination of this License. Provisions which, by their nature,
+should remain in effect beyond the termination of this License shall
+survive, including but not limited to Sections 3, 5, 8, 9, 10, 11,
+12.2 and 13. No party will be liable to any other for compensation,
+indemnity or damages of any sort solely as a result of terminating
+this License in accordance with its terms, and termination of this
+License will be without prejudice to any other right or remedy of
+any party.
+
+13. Miscellaneous.
+
+13.1 Government End Users. The Covered Code is a "commercial item" as
+defined in FAR 2.101. Government software and technical data rights in
+the Covered Code include only those rights customarily provided to the
+public as defined in this License. This customary commercial license
+in technical data and software is provided in accordance with FAR
+12.211 (Technical Data) and 12.212 (Computer Software) and, for
+Department of Defense purchases, DFAR 252.227-7015 (Technical Data --
+Commercial Items) and 227.7202-3 (Rights in Commercial Computer
+Software or Computer Software Documentation). Accordingly, all U.S.
+Government End Users acquire Covered Code with only those rights set
+forth herein.
+
+13.2 Relationship of Parties. This License will not be construed as
+creating an agency, partnership, joint venture or any other form of
+legal association between or among You, Apple or any Contributor, and
+You will not represent to the contrary, whether expressly, by
+implication, appearance or otherwise.
+
+13.3 Independent Development. Nothing in this License will impair
+Apple's right to acquire, license, develop, have others develop for
+it, market and/or distribute technology or products that perform the
+same or similar functions as, or otherwise compete with,
+Modifications, Larger Works, technology or products that You may
+develop, produce, market or distribute.
+
+13.4 Waiver; Construction. Failure by Apple or any Contributor to
+enforce any provision of this License will not be deemed a waiver of
+future enforcement of that or any other provision. Any law or
+regulation which provides that the language of a contract shall be
+construed against the drafter will not apply to this License.
+
+13.5 Severability. (a) If for any reason a court of competent
+jurisdiction finds any provision of this License, or portion thereof,
+to be unenforceable, that provision of the License will be enforced to
+the maximum extent permissible so as to effect the economic benefits
+and intent of the parties, and the remainder of this License will
+continue in full force and effect. (b) Notwithstanding the foregoing,
+if applicable law prohibits or restricts You from fully and/or
+specifically complying with Sections 2 and/or 3 or prevents the
+enforceability of either of those Sections, this License will
+immediately terminate and You must immediately discontinue any use of
+the Covered Code and destroy all copies of it that are in your
+possession or control.
+
+13.6 Dispute Resolution. Any litigation or other dispute resolution
+between You and Apple relating to this License shall take place in the
+Northern District of California, and You and Apple hereby consent to
+the personal jurisdiction of, and venue in, the state and federal
+courts within that District with respect to this License. The
+application of the United Nations Convention on Contracts for the
+International Sale of Goods is expressly excluded.
+
+13.7 Entire Agreement; Governing Law. This License constitutes the
+entire agreement between the parties with respect to the subject
+matter hereof. This License shall be governed by the laws of the
+United States and the State of California, except that body of
+California law concerning conflicts of law.
+
+Where You are located in the province of Quebec, Canada, the following
+clause applies: The parties hereby confirm that they have requested
+that this License and all related documents be drafted in English. Les
+parties ont exige que le present contrat et tous les documents
+connexes soient rediges en anglais.
+
+EXHIBIT A.
+
+"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
+Reserved.
+
+This file contains Original Code and/or Modifications of Original Code
+as defined in and that are subject to the Apple Public Source License
+Version 2.0 (the 'License'). You may not use this file except in
+compliance with the License. Please obtain a copy of the License at
+http://www.opensource.apple.com/apsl/ and read it before using this
+file.
+
+The Original Code and all software distributed under the License are
+distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+Please see the License for the specific language governing rights and
+limitations under the License."
diff --git a/doc/man/man1/ld64.1 b/doc/man/man1/ld64.1
new file mode 100644 (file)
index 0000000..615b0e5
--- /dev/null
@@ -0,0 +1 @@
+.so man1/ld.1
diff --git a/ld64.xcode/project.pbxproj b/ld64.xcode/project.pbxproj
new file mode 100644 (file)
index 0000000..ef5a16d
--- /dev/null
@@ -0,0 +1,423 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 39;
+       objects = {
+               F9023C2C06D5A227001BBF46 = {
+                       children = (
+                               F971EED706D5AD240041D381,
+                               F9023C3F06D5A254001BBF46,
+                               F9C0D48A06DD1E1B001C7193,
+                               F9C0D48B06DD1E1B001C7193,
+                               F9023C3E06D5A254001BBF46,
+                               F9023C4006D5A254001BBF46,
+                               F9023C4106D5A254001BBF46,
+                               F97288E607D277570031794D,
+                               F972890007D27FD00031794D,
+                               F9023C4206D5A254001BBF46,
+                               F9023C4806D5A254001BBF46,
+                               F97F5028070D0BB200B9FCD7,
+                               F9023C3A06D5A23E001BBF46,
+                       );
+                       isa = PBXGroup;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9023C2E06D5A227001BBF46 = {
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                       };
+                       isa = PBXBuildStyle;
+                       name = Development;
+               };
+               F9023C2F06D5A227001BBF46 = {
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                       };
+                       isa = PBXBuildStyle;
+                       name = Deployment;
+               };
+               F9023C3006D5A227001BBF46 = {
+                       buildSettings = {
+                       };
+                       buildStyles = (
+                               F9023C2E06D5A227001BBF46,
+                               F9023C2F06D5A227001BBF46,
+                       );
+                       hasScannedForEncodings = 0;
+                       isa = PBXProject;
+                       mainGroup = F9023C2C06D5A227001BBF46;
+                       productRefGroup = F9023C3A06D5A23E001BBF46;
+                       projectDirPath = "";
+                       targets = (
+                               F9023C3806D5A23E001BBF46,
+                               F971EED206D5ACF60041D381,
+                       );
+               };
+               F9023C3606D5A23E001BBF46 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               F9023C4E06D5A272001BBF46,
+                               F9C0D4BD06DD28D2001C7193,
+                               F9023C4F06D5A272001BBF46,
+                               F9023C5006D5A272001BBF46,
+                               F97288E707D277570031794D,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               F9023C3706D5A23E001BBF46 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               F9023C3806D5A23E001BBF46 = {
+                       buildPhases = (
+                               F9023C3606D5A23E001BBF46,
+                               F9023C3706D5A23E001BBF46,
+                               F97F5025070D0B6300B9FCD7,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 3;
+                               INSTALL_PATH = /usr/bin;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = ld64;
+                               SECTORDER_FLAGS = "";
+                               VERSIONING_SYSTEM = "apple-generic";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = ld64;
+                       productName = ld64;
+                       productReference = F9023C3906D5A23E001BBF46;
+                       productType = "com.apple.product-type.tool";
+               };
+               F9023C3906D5A23E001BBF46 = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = ld64;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               F9023C3A06D5A23E001BBF46 = {
+                       children = (
+                               F9023C3906D5A23E001BBF46,
+                               F971EED306D5ACF60041D381,
+                       );
+                       isa = PBXGroup;
+                       name = Products;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9023C3E06D5A254001BBF46 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ExecutableFile.h;
+                       path = src/ExecutableFile.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9023C3F06D5A254001BBF46 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.cpp.cpp;
+                       name = ld.cpp;
+                       path = src/ld.cpp;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9023C4006D5A254001BBF46 = {
+                       fileEncoding = 30;
+                       indentWidth = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = MachOAbstraction.h;
+                       path = src/MachOAbstraction.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+                       tabWidth = 4;
+                       usesTabs = 1;
+               };
+               F9023C4106D5A254001BBF46 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = ObjectFile.h;
+                       path = src/ObjectFile.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9023C4206D5A254001BBF46 = {
+                       children = (
+                               F9023C4706D5A254001BBF46,
+                               F9023C4406D5A254001BBF46,
+                               F95DD3B106EE395A007CAFEB,
+                               F9023C4506D5A254001BBF46,
+                               F9023C4606D5A254001BBF46,
+                       );
+                       isa = PBXGroup;
+                       name = Readers;
+                       path = src/Readers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9023C4406D5A254001BBF46 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.cpp.cpp;
+                       path = ObjectFileDylibMachO.cpp;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9023C4506D5A254001BBF46 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.cpp.cpp;
+                       path = "ObjectFileMachO-all.cpp";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9023C4606D5A254001BBF46 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "ObjectFileMachO-all.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9023C4706D5A254001BBF46 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.cpp.cpp;
+                       path = ObjectFileMachO.cpp;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9023C4806D5A254001BBF46 = {
+                       children = (
+                               F9023C4906D5A254001BBF46,
+                               F9023C4A06D5A254001BBF46,
+                               F9023C4B06D5A254001BBF46,
+                       );
+                       isa = PBXGroup;
+                       name = Writers;
+                       path = src/Writers;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9023C4906D5A254001BBF46 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.cpp.cpp;
+                       path = "ExecutableFileMachO-all.cpp";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9023C4A06D5A254001BBF46 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "ExecutableFileMachO-all.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9023C4B06D5A254001BBF46 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.cpp.cpp;
+                       path = ExecutableFileMachO.cpp;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9023C4E06D5A272001BBF46 = {
+                       fileRef = F9023C3F06D5A254001BBF46;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               F9023C4F06D5A272001BBF46 = {
+                       fileRef = F9023C4506D5A254001BBF46;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               F9023C5006D5A272001BBF46 = {
+                       fileRef = F9023C4906D5A254001BBF46;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               F95DD3B106EE395A007CAFEB = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.cpp.cpp;
+                       path = ObjectFileArchiveMachO.cpp;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F971EED006D5ACF60041D381 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               F971EED806D5AD240041D381,
+                               F971EEDA06D5AD450041D381,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               F971EED106D5ACF60041D381 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               F971EED206D5ACF60041D381 = {
+                       buildPhases = (
+                               F971EED006D5ACF60041D381,
+                               F971EED106D5ACF60041D381,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = ObjectDump;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = ObjectDump;
+                       productName = ObjectDump;
+                       productReference = F971EED306D5ACF60041D381;
+                       productType = "com.apple.product-type.tool";
+               };
+               F971EED306D5ACF60041D381 = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = ObjectDump;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               F971EED706D5AD240041D381 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.cpp.cpp;
+                       name = ObjDump.cpp;
+                       path = src/ObjDump.cpp;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F971EED806D5AD240041D381 = {
+                       fileRef = F971EED706D5AD240041D381;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               F971EEDA06D5AD450041D381 = {
+                       fileRef = F9023C4506D5A254001BBF46;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               F97288E607D277570031794D = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.cpp.cpp;
+                       name = SectCreate.cpp;
+                       path = src/SectCreate.cpp;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F97288E707D277570031794D = {
+                       fileRef = F97288E607D277570031794D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               F972890007D27FD00031794D = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = SectCreate.h;
+                       path = src/SectCreate.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F97F5025070D0B6300B9FCD7 = {
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man1;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               F97F5029070D0BB200B9FCD7,
+                       );
+                       isa = PBXCopyFilesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               F97F5028070D0BB200B9FCD7 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.man;
+                       name = ld64.1;
+                       path = doc/man/man1/ld64.1;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F97F5029070D0BB200B9FCD7 = {
+                       fileRef = F97F5028070D0BB200B9FCD7;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               F9C0D48A06DD1E1B001C7193 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.cpp.cpp;
+                       name = Options.cpp;
+                       path = src/Options.cpp;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9C0D48B06DD1E1B001C7193 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       name = Options.h;
+                       path = src/Options.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               F9C0D4BD06DD28D2001C7193 = {
+                       fileRef = F9C0D48A06DD1E1B001C7193;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+       };
+       rootObject = F9023C3006D5A227001BBF46;
+}
diff --git a/src/ExecutableFile.h b/src/ExecutableFile.h
new file mode 100644 (file)
index 0000000..e2e1e8c
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __EXECUTABLEFILE__
+#define __EXECUTABLEFILE__
+
+#include <stdint.h>
+#include <vector>
+
+#include "ObjectFile.h"
+#include "Options.h"
+
+
+namespace ExecutableFile {
+
+       struct DyLibUsed 
+       {
+               ObjectFile::Reader*             reader;
+               DynamicLibraryOptions   options;
+               bool                                    indirect;               // library found indirect.  Do not make load command
+               ObjectFile::Reader*             directReader;   // direct library which re-exports this library
+       };
+       
+       class Writer : public ObjectFile::Reader
+       {
+       public:         
+               virtual                                                         ~Writer() {};
+               
+               virtual const char*                                                             getPath() = 0;
+               virtual std::vector<class ObjectFile::Atom*>&   getAtoms() = 0;
+               virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name) = 0;
+               virtual std::vector<ObjectFile::StabsInfo>*             getStabsDebugInfo() = 0;
+
+               virtual class ObjectFile::Atom*                                 getUndefinedProxyAtom(const char* name) = 0;
+               virtual void                                                                    write(std::vector<class ObjectFile::Atom*>& atoms, class ObjectFile::Atom* entryPointAtom) = 0;
+
+
+
+       protected:
+                                                                                       Writer(std::vector<DyLibUsed>&) {};
+       };
+
+};
+
+
+
+
+#endif // __EXECUTABLEFILE__
+
+
+
diff --git a/src/MachOAbstraction.h b/src/MachOAbstraction.h
new file mode 100644 (file)
index 0000000..211a189
--- /dev/null
@@ -0,0 +1,1978 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdint.h>
+#include <string.h>
+#include <mach-o/nlist.h>
+#include <mach-o/loader.h>
+#include <libkern/OSByteOrder.h>
+
+
+#undef ENDIAN_READ16
+#undef ENDIAN_WRITE16
+#undef ENDIAN_READ32
+#undef ENDIAN_WRITE32
+#undef ENDIAN_SWAP64
+#undef ENDIAN_SWAP_POINTER
+
+#if defined(MACHO_32_SAME_ENDIAN) || defined(MACHO_64_SAME_ENDIAN)
+       #define ENDIAN_READ16(x)                        (x)
+       #define ENDIAN_WRITE16(into, value) into = (value);
+       
+       #define ENDIAN_READ32(x)                        (x)
+       #define ENDIAN_WRITE32(into, value) into = (value);
+
+       #define ENDIAN_SWAP64(x)                        (x)
+       
+#elif defined(MACHO_32_OPPOSITE_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
+       #define ENDIAN_READ16(x)                        OSReadSwapInt16((uint16_t*)&(x), 0)
+       #define ENDIAN_WRITE16(into, value)     OSWriteSwapInt16(&(into), 0, value);
+
+       #define ENDIAN_READ32(x)                        OSReadSwapInt32((uint32_t*)&(x), 0)
+       #define ENDIAN_WRITE32(into, value) OSWriteSwapInt32(&(into), 0, value);
+       
+       #define ENDIAN_SWAP64(x)                        OSSwapInt64(x)
+       
+#else
+       #error file format undefined
+#endif
+
+
+#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
+       typedef uint64_t        macho_uintptr_t;
+       typedef int64_t         macho_intptr_t;
+#else
+       typedef uint32_t        macho_uintptr_t;
+       typedef int32_t         macho_intptr_t;
+#endif
+
+#if defined(MACHO_32_SAME_ENDIAN) 
+       #define ENDIAN_SWAP_POINTER(x)                          (x)
+#elif defined(MACHO_64_SAME_ENDIAN)
+       #define ENDIAN_SWAP_POINTER(x)                          (x)
+#elif defined(MACHO_32_OPPOSITE_ENDIAN) 
+       #define ENDIAN_SWAP_POINTER(x)                          OSSwapInt32(x)
+#elif defined(MACHO_64_OPPOSITE_ENDIAN)
+       #define ENDIAN_SWAP_POINTER(x)                          OSSwapInt64(x)
+#else
+       #error file format undefined
+#endif
+
+
+#undef mach_header 
+#undef mach_header_64 
+class macho_header {
+public:
+       uint32_t        magic() const;
+       void            set_magic(uint32_t);
+
+       cpu_type_t      cputype() const;
+       void            set_cputype(cpu_type_t);
+
+       cpu_subtype_t   cpusubtype() const;
+       void            set_cpusubtype(cpu_subtype_t);
+
+       uint32_t        filetype() const;
+       void            set_filetype(uint32_t);
+
+       uint32_t        ncmds() const;
+       void            set_ncmds(uint32_t);
+
+       uint32_t        sizeofcmds() const;
+       void            set_sizeofcmds(uint32_t);
+
+       uint32_t        flags() const;
+       void            set_flags(uint32_t);
+
+       void            set_reserved();
+        
+#if defined(MACHO_64_SAME_ENDIAN) 
+       enum { size = sizeof(mach_header_64) };
+       enum { magic_value = MH_MAGIC_64 };
+#elif defined(MACHO_64_OPPOSITE_ENDIAN)
+       enum { size = sizeof(mach_header_64) };
+       enum { magic_value = MH_MAGIC_64 };
+#elif defined(MACHO_32_SAME_ENDIAN)
+       enum { size = sizeof(mach_header) };
+       enum { magic_value = MH_MAGIC };
+#elif defined(MACHO_32_OPPOSITE_ENDIAN)
+       enum { size = sizeof(mach_header) };
+       enum { magic_value = MH_MAGIC };
+#endif
+
+private:
+#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
+       struct mach_header_64 content;
+#else
+       struct mach_header content;
+#endif
+};
+#define mach_header __my_bad
+#define mach_header_64 __my_bad
+
+inline  __attribute__((always_inline))
+uint32_t macho_header::magic() const {
+       return ENDIAN_READ32(content.magic);
+}
+
+inline  __attribute__((always_inline))
+void macho_header::set_magic(uint32_t _value) {
+       ENDIAN_WRITE32(content.magic, _value);
+}
+
+inline  __attribute__((always_inline))
+cpu_type_t macho_header::cputype() const {
+       return ENDIAN_READ32(content.cputype);
+}
+
+inline  __attribute__((always_inline))
+void macho_header::set_cputype(cpu_type_t _value) {
+       ENDIAN_WRITE32(content.cputype, _value);
+}
+
+inline  __attribute__((always_inline))
+cpu_subtype_t macho_header::cpusubtype() const {
+       return ENDIAN_READ32(content.cpusubtype);
+}
+
+inline  __attribute__((always_inline))
+void macho_header::set_cpusubtype(cpu_subtype_t _value) {
+       ENDIAN_WRITE32(content.cpusubtype, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_header::filetype() const {
+       return ENDIAN_READ32(content.filetype);
+}
+
+inline  __attribute__((always_inline))
+void macho_header::set_filetype(uint32_t _value) {
+       ENDIAN_WRITE32(content.filetype, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_header::ncmds() const {
+       return ENDIAN_READ32(content.ncmds);
+}
+
+inline  __attribute__((always_inline))
+void macho_header::set_ncmds(uint32_t _value) {
+       ENDIAN_WRITE32(content.ncmds, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_header::sizeofcmds() const {
+       return ENDIAN_READ32(content.sizeofcmds);
+}
+
+inline  __attribute__((always_inline))
+void macho_header::set_sizeofcmds(uint32_t _value) {
+       ENDIAN_WRITE32(content.sizeofcmds, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_header::flags() const {
+       return ENDIAN_READ32(content.flags);
+}
+
+inline  __attribute__((always_inline))
+void macho_header::set_flags(uint32_t _value) {
+       ENDIAN_WRITE32(content.flags, _value);
+}
+
+inline  __attribute__((always_inline))
+void macho_header::set_reserved() {
+#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
+       content.reserved = 0;
+#endif
+}
+
+
+#undef load_command
+class macho_load_command {
+public:
+       uint32_t        cmd() const;
+       void            set_cmd(uint32_t);
+
+       uint32_t        cmdsize() const;
+       void            set_cmdsize(uint32_t);
+       
+private:
+       struct load_command content;
+};
+
+inline  __attribute__((always_inline))
+uint32_t macho_load_command::cmd() const {
+       return ENDIAN_READ32(content.cmd);
+}
+
+inline  __attribute__((always_inline))
+void macho_load_command::set_cmd(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmd, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_load_command::cmdsize() const {
+       return ENDIAN_READ32(content.cmdsize);
+}
+
+inline  __attribute__((always_inline))
+void macho_load_command::set_cmdsize(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmdsize, _value);
+}
+#define load_command __my_bad
+
+
+#undef segment_command
+#undef segment_command_64
+class macho_segment_command {
+public:
+       uint32_t        cmd() const;
+       void            set_cmd(uint32_t);
+
+       uint32_t        cmdsize() const;
+       void            set_cmdsize(uint32_t);
+
+       const char*     segname() const;
+       void            set_segname(const char*);
+
+       uint64_t        vmaddr() const;
+       void            set_vmaddr(uint64_t);
+
+       uint64_t        vmsize() const;
+       void            set_vmsize(uint64_t);
+
+       uint64_t        fileoff() const;
+       void            set_fileoff(uint64_t);
+
+       uint64_t        filesize() const;
+       void            set_filesize(uint64_t);
+
+       vm_prot_t       maxprot() const;
+       void            set_maxprot(vm_prot_t);
+
+       vm_prot_t       initprot() const;
+       void            set_initprot(vm_prot_t);
+
+       uint32_t        nsects() const;
+       void            set_nsects(uint32_t);
+
+       uint32_t        flags() const;
+       void            set_flags(uint32_t);
+
+       enum { size = 
+#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
+       sizeof(segment_command_64) };
+#else
+       sizeof(segment_command) };
+#endif
+
+       enum { command = 
+#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
+               LC_SEGMENT_64
+#else
+               LC_SEGMENT
+#endif
+       };
+
+private:
+#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
+       struct segment_command_64 content;
+#else
+       struct segment_command content;
+#endif
+};
+#define segment_command __my_bad
+#define segment_command_64 __my_bad
+
+inline  __attribute__((always_inline))
+uint32_t macho_segment_command::cmd() const {
+       return ENDIAN_READ32(content.cmd);
+}
+
+inline  __attribute__((always_inline))
+void macho_segment_command::set_cmd(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmd, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_segment_command::cmdsize() const {
+       return ENDIAN_READ32(content.cmdsize);
+}
+
+inline  __attribute__((always_inline))
+void macho_segment_command::set_cmdsize(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmdsize, _value);
+}
+
+inline  __attribute__((always_inline))
+const char* macho_segment_command::segname() const {
+       return content.segname;
+}
+
+inline  __attribute__((always_inline))
+void macho_segment_command::set_segname(const char* _value) {
+       strncpy(content.segname, _value, 16);
+}
+
+inline  __attribute__((always_inline))
+uint64_t macho_segment_command::vmaddr() const {
+#if defined(ARCH_PPC64)
+       return ENDIAN_SWAP64(content.vmaddr);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       return ENDIAN_READ32(content.vmaddr);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+void macho_segment_command::set_vmaddr(uint64_t _value) {
+#if defined(ARCH_PPC64)
+       content.vmaddr = ENDIAN_SWAP64(_value);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       ENDIAN_WRITE32(content.vmaddr, _value);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+uint64_t macho_segment_command::vmsize() const {
+#if defined(ARCH_PPC64)
+       return ENDIAN_SWAP64(content.vmsize);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       return ENDIAN_READ32(content.vmsize);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+void macho_segment_command::set_vmsize(uint64_t _value) {
+#if defined(ARCH_PPC64)
+       content.vmsize = ENDIAN_SWAP64(_value);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       ENDIAN_WRITE32(content.vmsize, _value);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+uint64_t macho_segment_command::fileoff() const {
+#if defined(ARCH_PPC64)
+       return ENDIAN_SWAP64(content.fileoff);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       return ENDIAN_READ32(content.fileoff);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+void macho_segment_command::set_fileoff(uint64_t _value) {
+#if defined(ARCH_PPC64)
+       content.fileoff = ENDIAN_SWAP64(_value);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       ENDIAN_WRITE32(content.fileoff, _value);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+uint64_t macho_segment_command::filesize() const {
+#if defined(ARCH_PPC64)
+       return ENDIAN_SWAP64(content.filesize);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       return ENDIAN_READ32(content.filesize);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+void macho_segment_command::set_filesize(uint64_t _value) {
+#if defined(ARCH_PPC64)
+       content.filesize = ENDIAN_SWAP64(_value);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       ENDIAN_WRITE32(content.filesize, _value);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+vm_prot_t macho_segment_command::maxprot() const {
+       return ENDIAN_READ32(content.maxprot);
+}
+
+inline  __attribute__((always_inline))
+void macho_segment_command::set_maxprot(vm_prot_t _value) {
+       ENDIAN_WRITE32(content.maxprot, _value);
+}
+
+inline  __attribute__((always_inline))
+vm_prot_t macho_segment_command::initprot() const {
+       return ENDIAN_READ32(content.initprot);
+}
+
+inline  __attribute__((always_inline))
+void macho_segment_command::set_initprot(vm_prot_t _value) {
+       ENDIAN_WRITE32(content.initprot, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_segment_command::nsects() const {
+       return ENDIAN_READ32(content.nsects);
+}
+
+inline  __attribute__((always_inline))
+void macho_segment_command::set_nsects(uint32_t _value) {
+       ENDIAN_WRITE32(content.nsects, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_segment_command::flags() const {
+       return ENDIAN_READ32(content.flags);
+}
+
+inline  __attribute__((always_inline))
+void macho_segment_command::set_flags(uint32_t _value) {
+       ENDIAN_WRITE32(content.flags, _value);
+}
+
+#undef section
+#undef section_64
+class macho_section {
+public:
+       const char*     sectname() const;
+       void            set_sectname(const char*);
+
+       const char*     segname() const;
+       void            set_segname(const char*);
+
+       uint64_t        addr() const;
+       void            set_addr(uint64_t);
+
+       uint64_t        size() const;
+       void            set_size(uint64_t);
+
+       uint32_t        offset() const;
+       void            set_offset(uint32_t);
+
+       uint32_t        align() const;
+       void            set_align(uint32_t);
+
+       uint32_t        reloff() const;
+       void            set_reloff(uint32_t);
+
+       uint32_t        nreloc() const;
+       void            set_nreloc(uint32_t);
+
+       uint32_t        flags() const;
+       void            set_flags(uint32_t);
+
+       uint32_t        reserved1() const;
+       void            set_reserved1(uint32_t);
+
+       uint32_t        reserved2() const;
+       void            set_reserved2(uint32_t);
+
+       enum { content_size = 
+#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
+       sizeof(section_64) };
+#else
+       sizeof(section) };
+#endif
+
+private:
+#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
+       struct section_64 content;
+#else
+       struct section content;
+#endif
+};
+#define section __my_bad
+#define section_64 __my_bad
+
+inline  __attribute__((always_inline))
+const char* macho_section::sectname() const {
+       return content.sectname;
+}
+
+inline  __attribute__((always_inline))
+void macho_section::set_sectname(const char* _value) {
+       strncpy(content.sectname, _value, 16);
+}
+
+inline  __attribute__((always_inline))
+const char* macho_section::segname() const {
+       return content.segname;
+}
+
+inline  __attribute__((always_inline))
+void macho_section::set_segname(const char* _value) {
+       strncpy(content.segname, _value, 16);
+}
+
+inline  __attribute__((always_inline))
+uint64_t macho_section::addr() const {
+#if defined(ARCH_PPC64)
+       return ENDIAN_SWAP64(content.addr);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       return ENDIAN_READ32(content.addr);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+void macho_section::set_addr(uint64_t _value) {
+#if defined(ARCH_PPC64)
+       content.addr = ENDIAN_SWAP64(_value);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       ENDIAN_WRITE32(content.addr, _value);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+uint64_t macho_section::size() const {
+#if defined(ARCH_PPC64)
+       return ENDIAN_SWAP64(content.size);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       return ENDIAN_READ32(content.size);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+void macho_section::set_size(uint64_t _value) {
+#if defined(ARCH_PPC64)
+       content.size = ENDIAN_SWAP64(_value);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       ENDIAN_WRITE32(content.size, _value);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_section::offset() const {
+       return ENDIAN_READ32(content.offset);
+}
+
+inline  __attribute__((always_inline))
+void macho_section::set_offset(uint32_t _value) {
+       ENDIAN_WRITE32(content.offset, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_section::align() const {
+       return ENDIAN_READ32(content.align);
+}
+
+inline  __attribute__((always_inline))
+void macho_section::set_align(uint32_t _value) {
+       ENDIAN_WRITE32(content.align, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_section::reloff() const {
+       return ENDIAN_READ32(content.reloff);
+}
+
+inline  __attribute__((always_inline))
+void macho_section::set_reloff(uint32_t _value) {
+       ENDIAN_WRITE32(content.reloff, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_section::nreloc() const {
+       return ENDIAN_READ32(content.nreloc);
+}
+
+inline  __attribute__((always_inline))
+void macho_section::set_nreloc(uint32_t _value) {
+       ENDIAN_WRITE32(content.nreloc, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_section::flags() const {
+       return ENDIAN_READ32(content.flags);
+}
+
+inline  __attribute__((always_inline))
+void macho_section::set_flags(uint32_t _value) {
+       ENDIAN_WRITE32(content.flags, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_section::reserved1() const {
+       return ENDIAN_READ32(content.reserved1);
+}
+
+inline  __attribute__((always_inline))
+void macho_section::set_reserved1(uint32_t _value) {
+       ENDIAN_WRITE32(content.reserved1, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_section::reserved2() const {
+       return ENDIAN_READ32(content.reserved2);
+}
+
+inline  __attribute__((always_inline))
+void macho_section::set_reserved2(uint32_t _value) {
+       ENDIAN_WRITE32(content.reserved2, _value);
+}
+
+#undef dylib_command
+class macho_dylib_command {
+public:
+       uint32_t        cmd() const;
+       void            set_cmd(uint32_t);
+
+       uint32_t        cmdsize() const;
+       void            set_cmdsize(uint32_t);
+
+       const char*     name() const;
+       void            set_name_offset();
+
+       uint32_t        timestamp() const;
+       void            set_timestamp(uint32_t);
+
+       uint32_t        current_version() const;
+       void            set_current_version(uint32_t);
+
+       uint32_t        compatibility_version() const;
+       void            set_compatibility_version(uint32_t);
+
+       enum { name_offset = sizeof(struct dylib_command) };
+
+private:
+       struct dylib_command content;
+};
+#define dylib_command __my_bad
+
+inline  __attribute__((always_inline))
+uint32_t macho_dylib_command::cmd() const {
+       return ENDIAN_READ32(content.cmd);
+}
+
+inline  __attribute__((always_inline))
+void macho_dylib_command::set_cmd(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmd, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dylib_command::cmdsize() const {
+       return ENDIAN_READ32(content.cmdsize);
+}
+
+inline  __attribute__((always_inline))
+void macho_dylib_command::set_cmdsize(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmdsize, _value);
+}
+
+inline  __attribute__((always_inline))
+const char* macho_dylib_command::name() const {
+       return (char*)(&content) + ENDIAN_READ32(content.dylib.name.offset);
+}
+
+inline  __attribute__((always_inline))
+void macho_dylib_command::set_name_offset() {
+       ENDIAN_WRITE32(content.dylib.name.offset, name_offset);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dylib_command::timestamp() const {
+       return ENDIAN_READ32(content.dylib.timestamp);
+}
+
+inline  __attribute__((always_inline))
+void macho_dylib_command::set_timestamp(uint32_t _value) {
+       ENDIAN_WRITE32(content.dylib.timestamp, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dylib_command::current_version() const {
+       return ENDIAN_READ32(content.dylib.current_version);
+}
+
+inline  __attribute__((always_inline))
+void macho_dylib_command::set_current_version(uint32_t _value) {
+       ENDIAN_WRITE32(content.dylib.current_version, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dylib_command::compatibility_version() const {
+       return ENDIAN_READ32(content.dylib.compatibility_version);
+}
+
+inline  __attribute__((always_inline))
+void macho_dylib_command::set_compatibility_version(uint32_t _value) {
+       ENDIAN_WRITE32(content.dylib.compatibility_version, _value);
+}
+
+
+
+#undef dylinker_command
+class macho_dylinker_command {
+public:
+       uint32_t        cmd() const;
+       void            set_cmd(uint32_t);
+
+       uint32_t        cmdsize() const;
+       void            set_cmdsize(uint32_t);
+
+       void            set_name_offset();
+
+       enum { name_offset = sizeof(struct dylinker_command) };
+
+private:
+       struct dylinker_command content;
+};
+#define dylinker_command __my_bad
+
+inline  __attribute__((always_inline))
+uint32_t macho_dylinker_command::cmd() const {
+       return ENDIAN_READ32(content.cmd);
+}
+
+inline  __attribute__((always_inline))
+void macho_dylinker_command::set_cmd(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmd, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dylinker_command::cmdsize() const {
+       return ENDIAN_READ32(content.cmdsize);
+}
+
+inline  __attribute__((always_inline))
+void macho_dylinker_command::set_cmdsize(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmdsize, _value);
+}
+
+inline  __attribute__((always_inline))
+void macho_dylinker_command::set_name_offset() {
+       ENDIAN_WRITE32(content.name.offset, name_offset);
+}
+
+
+
+#undef sub_framework_command 
+class macho_sub_framework_command {
+public:
+       uint32_t        cmd() const;
+       void            set_cmd(uint32_t);
+
+       uint32_t        cmdsize() const;
+       void            set_cmdsize(uint32_t);
+
+       const char*     name() const;
+       void            set_name_offset();
+
+       enum { name_offset = sizeof(struct sub_framework_command) };
+
+private:
+       struct sub_framework_command content;
+};
+#define sub_framework_command __my_bad
+
+inline  __attribute__((always_inline))
+uint32_t macho_sub_framework_command::cmd() const {
+       return ENDIAN_READ32(content.cmd);
+}
+
+inline  __attribute__((always_inline))
+void macho_sub_framework_command::set_cmd(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmd, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_sub_framework_command::cmdsize() const {
+       return ENDIAN_READ32(content.cmdsize);
+}
+
+inline  __attribute__((always_inline))
+void macho_sub_framework_command::set_cmdsize(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmdsize, _value);
+}
+
+inline  __attribute__((always_inline))
+const char* macho_sub_framework_command::name() const {
+       return (char*)(&content) + ENDIAN_READ32(content.umbrella.offset);
+}
+
+inline  __attribute__((always_inline))
+void macho_sub_framework_command::set_name_offset() {
+       ENDIAN_WRITE32(content.umbrella.offset, name_offset);
+}
+
+#undef sub_client_command 
+class macho_sub_client_command {
+public:
+       uint32_t        cmd() const;
+       void            set_cmd(uint32_t);
+
+       uint32_t        cmdsize() const;
+       void            set_cmdsize(uint32_t);
+
+       const char*     name() const;
+       void            set_name_offset();
+
+       enum { name_offset = sizeof(struct sub_client_command) };
+private:
+       struct sub_client_command content;
+};
+#define sub_client_command __my_bad
+
+inline  __attribute__((always_inline))
+uint32_t macho_sub_client_command::cmd() const {
+       return ENDIAN_READ32(content.cmd);
+}
+
+inline  __attribute__((always_inline))
+void macho_sub_client_command::set_cmd(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmd, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_sub_client_command::cmdsize() const {
+       return ENDIAN_READ32(content.cmdsize);
+}
+
+inline  __attribute__((always_inline))
+void macho_sub_client_command::set_cmdsize(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmdsize, _value);
+}
+
+inline  __attribute__((always_inline))
+const char* macho_sub_client_command::name() const {
+       return (char*)(&content) + ENDIAN_READ32(content.client.offset);
+}
+
+inline  __attribute__((always_inline))
+void macho_sub_client_command::set_name_offset() {
+       ENDIAN_WRITE32(content.client.offset, name_offset);
+}
+
+
+
+#undef sub_umbrella_command 
+class macho_sub_umbrella_command {
+public:
+       uint32_t        cmd() const;
+       void            set_cmd(uint32_t);
+
+       uint32_t        cmdsize() const;
+       void            set_cmdsize(uint32_t);
+
+       const char*     name() const;
+       void            set_name_offset();
+
+       enum { name_offset = sizeof(struct sub_umbrella_command) };
+private:
+       struct sub_umbrella_command content;
+};
+#define sub_umbrella_command __my_bad
+
+inline  __attribute__((always_inline))
+uint32_t macho_sub_umbrella_command::cmd() const {
+       return ENDIAN_READ32(content.cmd);
+}
+
+inline  __attribute__((always_inline))
+void macho_sub_umbrella_command::set_cmd(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmd, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_sub_umbrella_command::cmdsize() const {
+       return ENDIAN_READ32(content.cmdsize);
+}
+
+inline  __attribute__((always_inline))
+void macho_sub_umbrella_command::set_cmdsize(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmdsize, _value);
+}
+
+inline  __attribute__((always_inline))
+const char* macho_sub_umbrella_command::name() const {
+       return (char*)(&content) + ENDIAN_READ32(content.sub_umbrella.offset);
+}
+
+inline  __attribute__((always_inline))
+void macho_sub_umbrella_command::set_name_offset() {
+       ENDIAN_WRITE32(content.sub_umbrella.offset, name_offset);
+}
+
+
+
+
+#undef sub_library_command 
+class macho_sub_library_command {
+public:
+       uint32_t        cmd() const;
+       void            set_cmd(uint32_t);
+
+       uint32_t        cmdsize() const;
+       void            set_cmdsize(uint32_t);
+
+       const char*     name() const;
+       void            set_name_offset();
+
+       enum { name_offset = sizeof(struct sub_library_command) };
+private:
+       struct sub_library_command content;
+};
+#define sub_library_command __my_bad
+
+inline  __attribute__((always_inline))
+uint32_t macho_sub_library_command::cmd() const {
+       return ENDIAN_READ32(content.cmd);
+}
+
+inline  __attribute__((always_inline))
+void macho_sub_library_command::set_cmd(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmd, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_sub_library_command::cmdsize() const {
+       return ENDIAN_READ32(content.cmdsize);
+}
+
+inline  __attribute__((always_inline))
+void macho_sub_library_command::set_cmdsize(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmdsize, _value);
+}
+
+inline  __attribute__((always_inline))
+const char* macho_sub_library_command::name() const {
+       return (char*)(&content) + ENDIAN_READ32(content.sub_library.offset);
+}
+
+inline  __attribute__((always_inline))
+void macho_sub_library_command::set_name_offset() {
+       ENDIAN_WRITE32(content.sub_library.offset, name_offset);
+}
+
+
+
+#undef routines_command 
+#undef routines_command_64 
+class macho_routines_command {
+public:
+       uint32_t        cmd() const;
+       void            set_cmd(uint32_t);
+
+       uint32_t        cmdsize() const;
+       void            set_cmdsize(uint32_t);
+
+       uint64_t        init_address() const;
+       void            set_init_address(uint64_t);
+
+       uint64_t        init_module() const;
+       void            set_init_module(uint64_t);
+
+#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
+       enum { size = sizeof(struct routines_command_64) };
+       enum { command = LC_ROUTINES_64 };
+#else
+       enum { size = sizeof(struct routines_command) };
+       enum { command = LC_ROUTINES };
+#endif
+
+private:
+#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
+       struct routines_command_64 content;
+#else
+       struct routines_command content;
+#endif
+};
+#define routines_command __my_bad
+#define routines_command_64 __my_bad
+
+inline  __attribute__((always_inline))
+uint32_t macho_routines_command::cmd() const {
+       return ENDIAN_READ32(content.cmd);
+}
+
+inline  __attribute__((always_inline))
+void macho_routines_command::set_cmd(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmd, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_routines_command::cmdsize() const {
+       return ENDIAN_READ32(content.cmdsize);
+}
+
+inline  __attribute__((always_inline))
+void macho_routines_command::set_cmdsize(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmdsize, _value);
+}
+
+inline  __attribute__((always_inline))
+uint64_t macho_routines_command::init_address() const {
+       return ENDIAN_SWAP64(content.init_address);
+}
+
+inline  __attribute__((always_inline))
+void macho_routines_command::set_init_address(uint64_t _value) {
+       content.init_address = ENDIAN_SWAP64(_value);
+}
+
+inline  __attribute__((always_inline))
+uint64_t macho_routines_command::init_module() const {
+       return ENDIAN_SWAP64(content.init_module);
+}
+
+inline  __attribute__((always_inline))
+void macho_routines_command::set_init_module(uint64_t _value) {
+       content.init_module = ENDIAN_SWAP64(_value);
+}
+
+
+
+#undef symtab_command 
+class macho_symtab_command {
+public:
+       uint32_t        cmd() const;
+       void            set_cmd(uint32_t);
+
+       uint32_t        cmdsize() const;
+       void            set_cmdsize(uint32_t);
+
+       uint32_t        symoff() const;
+       void            set_symoff(uint32_t);
+
+       uint32_t        nsyms() const;
+       void            set_nsyms(uint32_t);
+
+       uint32_t        stroff() const;
+       void            set_stroff(uint32_t);
+
+       uint32_t        strsize() const;
+       void            set_strsize(uint32_t);
+       
+       enum { size = sizeof(struct symtab_command ) };
+       
+private:
+       struct symtab_command content;
+};
+#define symtab_command __my_bad
+
+
+inline  __attribute__((always_inline))
+uint32_t macho_symtab_command::cmd() const {
+       return ENDIAN_READ32(content.cmd);
+}
+
+inline  __attribute__((always_inline))
+void macho_symtab_command::set_cmd(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmd, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_symtab_command::cmdsize() const {
+       return ENDIAN_READ32(content.cmdsize);
+}
+
+inline  __attribute__((always_inline))
+void macho_symtab_command::set_cmdsize(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmdsize, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_symtab_command::symoff() const {
+       return ENDIAN_READ32(content.symoff);
+}
+
+inline  __attribute__((always_inline))
+void macho_symtab_command::set_symoff(uint32_t _value) {
+       ENDIAN_WRITE32(content.symoff, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_symtab_command::nsyms() const {
+       return ENDIAN_READ32(content.nsyms);
+}
+
+inline  __attribute__((always_inline))
+void macho_symtab_command::set_nsyms(uint32_t _value) {
+       ENDIAN_WRITE32(content.nsyms, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_symtab_command::stroff() const {
+       return ENDIAN_READ32(content.stroff);
+}
+
+inline  __attribute__((always_inline))
+void macho_symtab_command::set_stroff(uint32_t _value) {
+       ENDIAN_WRITE32(content.stroff, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_symtab_command::strsize() const {
+       return ENDIAN_READ32(content.strsize);
+}
+
+inline  __attribute__((always_inline))
+void macho_symtab_command::set_strsize(uint32_t _value) {
+       ENDIAN_WRITE32(content.strsize, _value);
+}
+
+
+#undef dysymtab_command 
+class macho_dysymtab_command {
+public:
+       uint32_t        cmd() const;
+       void            set_cmd(uint32_t);
+
+       uint32_t        cmdsize() const;
+       void            set_cmdsize(uint32_t);
+
+       uint32_t        ilocalsym() const;
+       void            set_ilocalsym(uint32_t);
+
+       uint32_t        nlocalsym() const;
+       void            set_nlocalsym(uint32_t);
+
+       uint32_t        iextdefsym() const;
+       void            set_iextdefsym(uint32_t);
+
+       uint32_t        nextdefsym() const;
+       void            set_nextdefsym(uint32_t);
+
+       uint32_t        iundefsym() const;
+       void            set_iundefsym(uint32_t);
+
+       uint32_t        nundefsym() const;
+       void            set_nundefsym(uint32_t);
+
+       uint32_t        tocoff() const;
+       void            set_tocoff(uint32_t);
+
+       uint32_t        ntoc() const;
+       void            set_ntoc(uint32_t);
+
+       uint32_t        modtaboff() const;
+       void            set_modtaboff(uint32_t);
+
+       uint32_t        nmodtab() const;
+       void            set_nmodtab(uint32_t);
+
+       uint32_t        extrefsymoff() const;
+       void            set_extrefsymoff(uint32_t);
+
+       uint32_t        nextrefsyms() const;
+       void            set_nextrefsyms(uint32_t);
+
+       uint32_t        indirectsymoff() const;
+       void            set_indirectsymoff(uint32_t);
+
+       uint32_t        nindirectsyms() const;
+       void            set_nindirectsyms(uint32_t);
+
+       uint32_t        extreloff() const;
+       void            set_extreloff(uint32_t);
+
+       uint32_t        nextrel() const;
+       void            set_nextrel(uint32_t);
+
+       uint32_t        locreloff() const;
+       void            set_locreloff(uint32_t);
+
+       uint32_t        nlocrel() const;
+       void            set_nlocrel(uint32_t);
+
+       enum { size = sizeof(struct dysymtab_command ) };
+private:
+       struct dysymtab_command content;
+};
+#define dysymtab_command __my_bad
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::cmd() const {
+       return ENDIAN_READ32(content.cmd);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_cmd(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmd, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::cmdsize() const {
+       return ENDIAN_READ32(content.cmdsize);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_cmdsize(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmdsize, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::ilocalsym() const {
+       return ENDIAN_READ32(content.ilocalsym);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_ilocalsym(uint32_t _value) {
+       ENDIAN_WRITE32(content.ilocalsym, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::nlocalsym() const {
+       return ENDIAN_READ32(content.nlocalsym);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_nlocalsym(uint32_t _value) {
+       ENDIAN_WRITE32(content.nlocalsym, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::iextdefsym() const {
+       return ENDIAN_READ32(content.iextdefsym);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_iextdefsym(uint32_t _value) {
+       ENDIAN_WRITE32(content.iextdefsym, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::nextdefsym() const {
+       return ENDIAN_READ32(content.nextdefsym);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_nextdefsym(uint32_t _value) {
+       ENDIAN_WRITE32(content.nextdefsym, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::iundefsym() const {
+       return ENDIAN_READ32(content.iundefsym);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_iundefsym(uint32_t _value) {
+       ENDIAN_WRITE32(content.iundefsym, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::nundefsym() const {
+       return ENDIAN_READ32(content.nundefsym);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_nundefsym(uint32_t _value) {
+       ENDIAN_WRITE32(content.nundefsym, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::tocoff() const {
+       return ENDIAN_READ32(content.tocoff);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_tocoff(uint32_t _value) {
+       ENDIAN_WRITE32(content.tocoff, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::ntoc() const {
+       return ENDIAN_READ32(content.ntoc);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_ntoc(uint32_t _value) {
+       ENDIAN_WRITE32(content.ntoc, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::modtaboff() const {
+       return ENDIAN_READ32(content.modtaboff);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_modtaboff(uint32_t _value) {
+       ENDIAN_WRITE32(content.modtaboff, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::nmodtab() const {
+       return ENDIAN_READ32(content.nmodtab);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_nmodtab(uint32_t _value) {
+       ENDIAN_WRITE32(content.nmodtab, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::extrefsymoff() const {
+       return ENDIAN_READ32(content.extrefsymoff);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_extrefsymoff(uint32_t _value) {
+       ENDIAN_WRITE32(content.extrefsymoff, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::nextrefsyms() const {
+       return ENDIAN_READ32(content.nextrefsyms);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_nextrefsyms(uint32_t _value) {
+       ENDIAN_WRITE32(content.nextrefsyms, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::indirectsymoff() const {
+       return ENDIAN_READ32(content.indirectsymoff);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_indirectsymoff(uint32_t _value) {
+       ENDIAN_WRITE32(content.indirectsymoff, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::nindirectsyms() const {
+       return ENDIAN_READ32(content.nindirectsyms);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_nindirectsyms(uint32_t _value) {
+       ENDIAN_WRITE32(content.nindirectsyms, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::extreloff() const {
+       return ENDIAN_READ32(content.extreloff);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_extreloff(uint32_t _value) {
+       ENDIAN_WRITE32(content.extreloff, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::nextrel() const {
+       return ENDIAN_READ32(content.nextrel);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_nextrel(uint32_t _value) {
+       ENDIAN_WRITE32(content.nextrel, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::locreloff() const {
+       return ENDIAN_READ32(content.locreloff);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_locreloff(uint32_t _value) {
+       ENDIAN_WRITE32(content.locreloff, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_dysymtab_command::nlocrel() const {
+       return ENDIAN_READ32(content.nlocrel);
+}
+
+inline  __attribute__((always_inline))
+void macho_dysymtab_command::set_nlocrel(uint32_t _value) {
+       ENDIAN_WRITE32(content.nlocrel, _value);
+}
+
+
+
+#undef twolevel_hints_command 
+class macho_twolevel_hints_command {
+public:
+       uint32_t        cmd() const;
+       void            set_cmd(uint32_t);
+
+       uint32_t        cmdsize() const;
+       void            set_cmdsize(uint32_t);
+
+       uint32_t        offset() const;
+       void            set_offset(uint32_t);
+
+       uint32_t        nhints() const;
+       void            set_nhints(uint32_t);
+
+private:
+       struct twolevel_hints_command content;
+};
+#define twolevel_hints_command __my_bad
+
+inline  __attribute__((always_inline))
+uint32_t macho_twolevel_hints_command::cmd() const {
+       return ENDIAN_READ32(content.cmd);
+}
+
+inline  __attribute__((always_inline))
+void macho_twolevel_hints_command::set_cmd(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmd, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_twolevel_hints_command::cmdsize() const {
+       return ENDIAN_READ32(content.cmdsize);
+}
+
+inline  __attribute__((always_inline))
+void macho_twolevel_hints_command::set_cmdsize(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmdsize, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_twolevel_hints_command::offset() const {
+       return ENDIAN_READ32(content.offset);
+}
+
+inline  __attribute__((always_inline))
+void macho_twolevel_hints_command::set_offset(uint32_t _value) {
+       ENDIAN_WRITE32(content.offset, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_twolevel_hints_command::nhints() const {
+       return ENDIAN_READ32(content.nhints);
+}
+
+inline  __attribute__((always_inline))
+void macho_twolevel_hints_command::set_nhints(uint32_t _value) {
+       ENDIAN_WRITE32(content.nhints, _value);
+}
+
+
+#undef thread_command
+class macho_thread_command {
+public:
+       uint32_t        cmd() const;
+       void            set_cmd(uint32_t);
+
+       uint32_t        cmdsize() const;
+       void            set_cmdsize(uint32_t);
+
+       uint32_t        flavor() const;
+       void            set_flavor(uint32_t);
+
+       uint32_t        count() const;
+       void            set_count(uint32_t);
+
+       uint32_t        threadState32(uint32_t index) const;
+       void            set_threadState32(uint32_t index, uint32_t value);
+
+       uint64_t        threadState64(uint32_t offset) const;
+       void            set_threadState64(uint32_t index, uint64_t value);
+
+       enum { size = sizeof(struct thread_command) + 8 };
+
+private:
+       struct thread_command   content;
+       uint32_t                                content_flavor;
+       uint32_t                                content_count;
+       uint32_t                                threadState[1];
+};
+#define thread_command __my_bad
+
+inline  __attribute__((always_inline))
+uint32_t macho_thread_command::cmd() const {
+       return ENDIAN_READ32(content.cmd);
+}
+
+inline  __attribute__((always_inline))
+void macho_thread_command::set_cmd(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmd, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_thread_command::cmdsize() const {
+       return ENDIAN_READ32(content.cmdsize);
+}
+
+inline  __attribute__((always_inline))
+void macho_thread_command::set_cmdsize(uint32_t _value) {
+       ENDIAN_WRITE32(content.cmdsize, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_thread_command::flavor() const {
+       return ENDIAN_READ32(content_flavor);
+}
+
+inline  __attribute__((always_inline))
+void macho_thread_command::set_flavor(uint32_t _value) {
+       ENDIAN_WRITE32(content_flavor, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_thread_command::count() const {
+       return ENDIAN_READ32(content_count);
+}
+
+inline  __attribute__((always_inline))
+void macho_thread_command::set_count(uint32_t _value) {
+       ENDIAN_WRITE32(content_count, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_thread_command::threadState32(uint32_t index) const
+{
+       return ENDIAN_READ32(threadState[index]);
+}
+
+inline  __attribute__((always_inline))
+void macho_thread_command::set_threadState32(uint32_t index, uint32_t _value)
+{
+       ENDIAN_WRITE32(threadState[index], _value);
+}
+
+inline  __attribute__((always_inline))
+uint64_t macho_thread_command::threadState64(uint32_t index) const
+{
+       uint64_t temp = *((uint64_t*)(&threadState[index]));
+       return ENDIAN_SWAP64(temp);
+}
+
+inline  __attribute__((always_inline))
+void macho_thread_command::set_threadState64(uint32_t index, uint64_t _value)
+{
+       *((uint64_t*)(&threadState[index])) = ENDIAN_SWAP64(_value);
+}
+
+
+
+#undef nlist 
+#undef nlist_64
+class macho_nlist {
+public:
+       uint32_t        n_strx() const;
+       void            set_n_strx(uint32_t);
+
+       uint8_t         n_type() const;
+       void            set_n_type(uint8_t);
+
+       uint8_t         n_sect() const;
+       void            set_n_sect(uint8_t);
+
+       uint16_t        n_desc() const;
+       void            set_n_desc(uint16_t);
+
+       uint64_t        n_value() const;
+       void            set_n_value(uint64_t);
+
+       
+#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
+       enum { size = sizeof(struct nlist_64) };
+#else
+       enum { size = sizeof(struct nlist) };
+#endif
+
+private:
+#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
+       struct nlist_64 content;
+#else
+       struct nlist content;
+#endif
+};
+#define nlist __my_bad
+#define nlist_64 __my_bad
+
+inline  __attribute__((always_inline))
+uint32_t macho_nlist::n_strx() const {
+       return ENDIAN_READ32(content.n_un.n_strx);
+}
+
+inline  __attribute__((always_inline))
+void macho_nlist::set_n_strx(uint32_t _value) {
+       ENDIAN_WRITE32(content.n_un.n_strx, _value);
+}
+
+inline  __attribute__((always_inline))
+uint8_t macho_nlist::n_type() const {
+       return content.n_type;
+}
+
+inline  __attribute__((always_inline))
+void macho_nlist::set_n_type(uint8_t _value) {
+       content.n_type = _value;
+}
+
+inline  __attribute__((always_inline))
+uint8_t macho_nlist::n_sect() const {
+       return content.n_sect;
+}
+
+inline  __attribute__((always_inline))
+void macho_nlist::set_n_sect(uint8_t _value) {
+       content.n_sect = _value;
+}
+
+inline  __attribute__((always_inline))
+uint16_t macho_nlist::n_desc() const {
+       return ENDIAN_READ16(content.n_desc);
+}
+
+inline  __attribute__((always_inline))
+void macho_nlist::set_n_desc(uint16_t _value) {
+       ENDIAN_WRITE16(content.n_desc, _value);
+}
+
+inline  __attribute__((always_inline))
+uint64_t macho_nlist::n_value() const {
+#if defined(ARCH_PPC64)
+       return ENDIAN_SWAP64(content.n_value);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       return ENDIAN_READ32(content.n_value);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+void macho_nlist::set_n_value(uint64_t _value) {
+       content.n_value = ENDIAN_SWAP64(_value);
+}
+
+
+
+#undef relocation_info 
+class macho_relocation_info {
+public:
+       int32_t         r_address() const;
+       void            set_r_address(int32_t);
+
+       uint32_t        r_symbolnum() const;
+       void            set_r_symbolnum(uint32_t);
+
+       bool            r_pcrel() const;
+       void            set_r_pcrel(bool);
+
+       uint8_t         r_length() const;
+       void            set_r_length(uint8_t);
+
+       bool            r_extern() const;
+       void            set_r_extern(bool);
+
+       uint8_t         r_type() const;
+       void            set_r_type(uint8_t);
+
+       enum { size = sizeof(struct relocation_info) };
+#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
+       enum { pointer_length = 3 };
+#else
+       enum { pointer_length = 2 };
+#endif
+       
+private:
+       struct relocation_info content;
+};
+#define relocation_info __my_bad
+
+
+inline  __attribute__((always_inline))
+int32_t macho_relocation_info::r_address() const {
+       return ENDIAN_READ32(content.r_address);
+}
+
+inline  __attribute__((always_inline))
+void macho_relocation_info::set_r_address(int32_t _value) {
+       ENDIAN_WRITE32(content.r_address, _value);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_relocation_info::r_symbolnum() const {
+       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+       return (temp >> 8);
+#elif defined(ARCH_I386)
+       return temp & 0x00FFFFFF;
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+void macho_relocation_info::set_r_symbolnum(uint32_t _value) {
+       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+       temp &= 0x000000FF;
+       temp |= ((_value & 0x00FFFFFF) << 8);
+#elif defined(ARCH_I386)
+       temp &= 0xFF000000;
+       temp |= (_value & 0x00FFFFFF);
+#else
+       #error unknown architecture
+#endif
+       ENDIAN_WRITE32(((uint32_t*)&content)[1], temp);
+}
+
+inline  __attribute__((always_inline))
+bool macho_relocation_info::r_pcrel() const {
+       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+       return ((temp & 0x00000080) != 0);
+#elif defined(ARCH_I386)
+       return ((temp & 0x01000000) != 0);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+void macho_relocation_info::set_r_pcrel(bool _value) {
+       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+       temp &= 0xFFFFFF7F;
+       if ( _value )
+               temp |= 0x00000080;
+#elif defined(ARCH_I386)
+       temp &= 0x7FFFFFFF;
+       if ( _value )
+               temp |= 0x01000000;
+#else
+       #error unknown architecture
+#endif
+       ENDIAN_WRITE32(((uint32_t*)&content)[1], temp);
+}
+
+inline  __attribute__((always_inline))
+uint8_t macho_relocation_info::r_length() const {
+       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+       return ((temp & 0x00000060) >> 5);
+#elif defined(ARCH_I386)
+       return ((temp & 0x06000000) >> 25);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+void macho_relocation_info::set_r_length(uint8_t _value) {
+       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+       temp &= 0xFFFFFF9F;
+       temp |= ((_value & 0x03) << 5);
+#elif defined(ARCH_I386)
+       temp &= 0xF9FFFFFF;
+       temp |= ((_value & 0x03) << 25);
+#else
+       #error unknown architecture
+#endif
+       ENDIAN_WRITE32(((uint32_t*)&content)[1], temp);
+}
+
+inline  __attribute__((always_inline))
+bool macho_relocation_info::r_extern() const {
+       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+       return ((temp & 0x00000010) != 0);
+#elif defined(ARCH_I386)
+       return ((temp & 0x08000000) != 0);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+void macho_relocation_info::set_r_extern(bool _value) {
+       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+       temp &= 0xFFFFFFEF;
+       if ( _value )
+               temp |= 0x00000010;
+#elif defined(ARCH_I386)
+       temp &= 0xEFFFFFFF;
+       if ( _value )
+               temp |= 0x08000000;
+#else
+       #error unknown architecture
+#endif
+       ENDIAN_WRITE32(((uint32_t*)&content)[1], temp);
+}
+
+inline  __attribute__((always_inline))
+uint8_t macho_relocation_info::r_type() const {
+       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+       return (temp & 0x0000000F);
+#elif defined(ARCH_I386)
+       return ((temp & 0xF0000000) >> 28);
+#else
+       #error unknown architecture
+#endif
+}
+
+inline  __attribute__((always_inline))
+void macho_relocation_info::set_r_type(uint8_t _value) {
+       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+       temp &= 0xFFFFFFF0;
+       temp |= (_value & 0x0F);
+#elif defined(ARCH_I386)
+       temp &= 0x0FFFFFFF;
+       temp |= ((_value & 0x0F) << 28);
+#else
+       #error unknown architecture
+#endif
+       ENDIAN_WRITE32(((uint32_t*)&content)[1], temp);
+}
+
+
+
+#undef scattered_relocation_info 
+class macho_scattered_relocation_info {
+public:
+       bool            r_scattered() const;
+       void            set_r_scattered(bool);
+
+       bool            r_pcrel() const;
+       void            set_r_pcrel(bool);
+
+       uint8_t         r_length() const;
+       void            set_r_length(uint8_t);
+
+       uint8_t         r_type() const;
+       void            set_r_type(uint8_t);
+
+       uint32_t        r_address() const;
+       void            set_r_address(uint32_t);
+
+       int32_t         r_value() const;
+       void            set_r_value(int32_t);
+
+private:
+       struct scattered_relocation_info content;
+};
+#define scattered_relocation_info __my_bad
+
+inline  __attribute__((always_inline))
+bool macho_scattered_relocation_info::r_scattered() const {
+       uint32_t temp = *((const uint32_t*)&content);
+       temp = ENDIAN_READ32(temp);
+       return ((temp & 0x80000000) != 0);
+}
+
+inline  __attribute__((always_inline))
+void macho_scattered_relocation_info::set_r_scattered(bool _value) {
+       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
+       if ( _value )
+               temp |= 0x80000000;
+       else
+               temp &= ~0x80000000;
+       ENDIAN_WRITE32(*((uint32_t*)&content), temp);
+}
+
+inline  __attribute__((always_inline))
+bool macho_scattered_relocation_info::r_pcrel() const {
+       uint32_t temp = *((const uint32_t*)&content);
+       temp = ENDIAN_READ32(temp);
+       return ((temp & 0x40000000) != 0);
+}
+
+inline  __attribute__((always_inline))
+void macho_scattered_relocation_info::set_r_pcrel(bool _value) {
+       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
+       if ( _value )
+               temp |= 0x40000000;
+       else
+               temp &= ~0x40000000;
+       ENDIAN_WRITE32(*((uint32_t*)&content), temp);
+}
+
+inline  __attribute__((always_inline))
+uint8_t macho_scattered_relocation_info::r_length() const {
+       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
+       return (temp >> 28) & 0x03;
+}
+
+inline  __attribute__((always_inline))
+void macho_scattered_relocation_info::set_r_length(uint8_t _value) {
+       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
+       temp &= 0xCFFFFFFF;
+       temp |= ((_value & 0x03) << 28);
+       ENDIAN_WRITE32(*((uint32_t*)&content), temp);
+}
+
+inline  __attribute__((always_inline))
+uint8_t macho_scattered_relocation_info::r_type() const {
+       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
+       return (temp >> 24) & 0x0F;
+}
+
+inline  __attribute__((always_inline))
+void macho_scattered_relocation_info::set_r_type(uint8_t _value) {
+       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
+       temp &= 0xF0FFFFFF;
+       temp |= ((_value &0x0F) << 24);
+       ENDIAN_WRITE32(*((uint32_t*)&content), temp);
+}
+
+inline  __attribute__((always_inline))
+uint32_t macho_scattered_relocation_info::r_address() const {
+       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
+       return temp & 0x00FFFFFF;
+}
+
+inline  __attribute__((always_inline))
+void macho_scattered_relocation_info::set_r_address(uint32_t _value) {
+       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
+       _value &= 0x00FFFFFF;
+       temp &= 0xFF000000;
+       temp |= _value;
+       ENDIAN_WRITE32(*((uint32_t*)&content), temp);
+}
+
+inline  __attribute__((always_inline))
+int32_t macho_scattered_relocation_info::r_value() const {
+       return ENDIAN_READ32(content.r_value);
+}
+
+inline  __attribute__((always_inline))
+void macho_scattered_relocation_info::set_r_value(int32_t _value) {
+       ENDIAN_WRITE32(content.r_value, _value);
+}
+
+
+
+
diff --git a/src/ObjDump.cpp b/src/ObjDump.cpp
new file mode 100644 (file)
index 0000000..e3d6082
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <fcntl.h>
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+#include <mach-o/stab.h>
+
+
+#include "ObjectFile.h"
+#include "ObjectFileMachO-all.h"
+
+ __attribute__((noreturn))
+void throwf(const char* format, ...) 
+{
+       va_list list;
+       char*   p;
+       va_start(list, format);
+       vasprintf(&p, format, list);
+       va_end(list);
+       
+       const char*     t = p;
+       throw t;
+}
+
+static void dumpStabs(std::vector<ObjectFile::StabsInfo>* stabs)
+{
+       // debug info
+       const int stabCount = stabs->size();
+       printf("stabs: (%u)\n", stabCount);
+       for (int i=0; i < stabCount; ++i) {
+               ObjectFile::StabsInfo& stab = (*stabs)[i];
+               const char* code = "?????";
+               switch (stab.type) {
+                       case N_GSYM:
+                               code = " GSYM";
+                               break;
+                       case N_FNAME:
+                               code = "FNAME";
+                               break;
+                       case N_FUN:
+                               code = "  FUN";
+                               break;
+                       case N_STSYM:
+                               code = "STSYM";
+                               break;
+                       case N_LCSYM:
+                               code = "LCSYM";
+                               break;
+                       case N_BNSYM:
+                               code = "BNSYM";
+                               break;
+                       case N_OPT:
+                               code = "  OPT";
+                               break;
+                       case N_RSYM:
+                               code = " RSYM";
+                               break;
+                       case N_SLINE:
+                               code = "SLINE";
+                               break;
+                       case N_ENSYM:
+                               code = "ENSYM";
+                               break;
+                       case N_SSYM:
+                               code = " SSYM";
+                               break;
+                       case N_SO:
+                               code = "   SO";
+                               break;
+                       case N_LSYM:
+                               code = " LSYM";
+                               break;
+                       case N_BINCL:
+                               code = "BINCL";
+                               break;
+                       case N_SOL:
+                               code = "  SOL";
+                               break;
+                       case N_PARAMS:
+                               code = "PARMS";
+                               break;
+                       case N_VERSION:
+                               code = " VERS";
+                               break;
+                       case N_OLEVEL:
+                               code = "OLEVL";
+                               break;
+                       case N_PSYM:
+                               code = " PSYM";
+                               break;
+                       case N_EINCL:
+                               code = "EINCL";
+                               break;
+                       case N_ENTRY:
+                               code = "ENTRY";
+                               break;
+                       case N_LBRAC:
+                               code = "LBRAC";
+                               break;
+                       case N_EXCL:
+                               code = " EXCL";
+                               break;
+                       case N_RBRAC:
+                               code = "RBRAC";
+                               break;
+                       case N_BCOMM:
+                               code = "BCOMM";
+                               break;
+                       case N_ECOMM:
+                               code = "ECOMM";
+                               break;
+                       case N_LENG:
+                               code =  "LENG";
+                               break;
+               }
+               printf("   %08X %02X %04X %s %s\n", (uint32_t)stab.atomOffset, stab.other, stab.desc, code, stab.string);
+       }
+}
+
+
+static void dumpAtom(ObjectFile::Atom* atom)
+{
+       //printf("atom:    %p\n", atom);
+       
+       // name
+       printf("name:    %s\n",  atom->getDisplayName());
+       
+       // scope
+       switch ( atom->getScope() ) {
+               case ObjectFile::Atom::scopeTranslationUnit:
+                       printf("scope:   translation unit\n");
+                       break;
+               case ObjectFile::Atom::scopeLinkageUnit:
+                       printf("scope:   linkage unit\n");
+                       break;
+               case ObjectFile::Atom::scopeGlobal:
+                       printf("scope:   global\n");
+                       break;
+               default:
+                       printf("scope:   unknown\n");
+       }
+       
+       // segment and section
+       printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
+
+       // attributes
+       printf("attrs:   ");
+       if ( atom->isWeakDefinition() )
+               printf("weak ");
+       if ( atom->isCoalesableByName() )
+               printf("coalesce-by-name ");
+       if ( atom->isCoalesableByValue() )
+               printf("coalesce-by-value ");
+       if ( atom->dontDeadStrip() )
+               printf("dont-dead-strip ");
+       if ( atom->isZeroFill() )
+               printf("zero-fill ");
+       printf("\n");
+       
+       // size
+       printf("size:    0x%012llX\n", atom->getSize());
+       
+       // alignment
+       printf("align:    %d\n", atom->getAlignment());
+
+       // content
+       uint64_t size = atom->getSize();
+       if ( size < 4096 ) {
+               uint8_t content[size];
+               atom->copyRawContent(content);
+               printf("content: ");
+               if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
+                       printf("\"%s\"", content);
+               }
+               else {
+                       for (unsigned int i=0; i < size; ++i)
+                               printf("%02X ", content[i]);
+               }
+       }
+       printf("\n");
+       
+       // references
+       std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
+       const int refCount = references.size();
+       printf("references: (%u)\n", refCount);
+       for (int i=0; i < refCount; ++i) {
+               ObjectFile::Reference* ref = references[i];
+               printf("   %s\n", ref->getDescription());
+       }
+       
+       // debug info
+       std::vector<ObjectFile::StabsInfo>* stabs = atom->getStabsDebugInfo();
+       if ( stabs != NULL )
+               dumpStabs(stabs);
+}
+
+
+static void dumpFile(ObjectFile::Reader* reader)
+{
+#if 0
+       // debug info
+       std::vector<ObjectFile::StabsInfo>* stabs = reader->getStabsDebugInfo();
+       if ( stabs != NULL )
+               dumpStabs(stabs);
+#endif
+       // atom content
+       std::vector<ObjectFile::Atom*> atoms = reader->getAtoms();
+       const int atomCount = atoms.size();
+       for(int i=0; i < atomCount; ++i) {
+               dumpAtom(atoms[i]);
+               printf("\n");
+       }
+}
+
+
+static ObjectFile::Reader* createReader(const char* path, const ObjectFile::ReaderOptions& options)
+{
+       struct stat stat_buf;
+       
+       int fd = ::open(path, O_RDONLY, 0);
+       if ( fd == -1 )
+               throw "cannot open file";
+       ::fstat(fd, &stat_buf);
+       char* p = (char*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE, fd, 0);
+       ::close(fd);
+       const mach_header* mh = (mach_header*)p;
+       if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+               const struct fat_header* fh = (struct fat_header*)p;
+               const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
+               for (unsigned long i=0; i < fh->nfat_arch; ++i) {
+                       if ( archs[i].cputype == CPU_TYPE_POWERPC64 ) {
+                               p = p + archs[i].offset;
+                               mh = (struct mach_header*)p;
+                       }
+               }
+       }
+       if ( mh->magic == MH_MAGIC ) {
+               if ( mh->filetype == MH_OBJECT ) {
+                       switch ( mh->cputype ) {
+                               case CPU_TYPE_I386:
+                                       return i386::ObjectFileMachO::MakeReader((class i386::macho_header*)mh, path, options);
+                               case CPU_TYPE_POWERPC:
+                                       return ppc::ObjectFileMachO::MakeReader((class ppc::macho_header*)mh, path, options);
+                               case CPU_TYPE_POWERPC64:
+                                       return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
+                               default:
+                                       throw "unknown mach-o cpu type";
+                       }
+               }
+               if ( mh->filetype == MH_DYLIB )
+                       return ppc::ObjectFileDylibMachO::MakeReader((class ppc::macho_header*)mh, path, options);
+               throw "unknown mach-o file type";
+       }
+       else if ( mh->magic == MH_MAGIC_64 ) {
+               if ( mh->filetype == MH_OBJECT )
+                       return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
+               if ( mh->filetype == MH_DYLIB )
+                       return ppc64::ObjectFileDylibMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
+               throw "unknown mach-o file type";
+       }
+       else if ( mh->magic == OSSwapInt32(MH_MAGIC) ) {
+               if ( mh->filetype == OSSwapInt32(MH_OBJECT) ) {
+                       switch ( OSSwapInt32(mh->cputype) ) {
+                               case CPU_TYPE_I386:
+                                       return i386::ObjectFileMachO::MakeReader((class i386::macho_header*)mh, path, options);
+                               case CPU_TYPE_POWERPC:
+                                       return ppc::ObjectFileMachO::MakeReader((class ppc::macho_header*)mh, path, options);
+                               case CPU_TYPE_POWERPC64:
+                                       return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
+                               default:
+                                       throw "unknown mach-o cpu type";
+                       }
+               }
+               if ( mh->filetype == OSSwapInt32(MH_DYLIB) )
+                       return ppc::ObjectFileDylibMachO::MakeReader((class ppc::macho_header*)mh, path, options);
+               throw "unknown mach-o file type";
+       }
+       else if ( mh->magic == OSSwapInt32(MH_MAGIC_64) ) {
+               if ( mh->filetype == OSSwapInt32(MH_OBJECT)  )
+                       return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
+               if ( mh->filetype == OSSwapInt32(MH_DYLIB) )
+                       return ppc64::ObjectFileDylibMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
+               throw "unknown mach-o file type";
+       }
+       throw "unknown file type";
+}
+
+
+int main(int argc, const char* argv[])
+{
+       ObjectFile::ReaderOptions options;
+       //const char* path = argv[1];
+       //ObjectFile::Reader* reader = ObjectFile::Reader::createReader(path);
+       try {
+               ObjectFile::Reader* reader = createReader("/tmp/gcov-1.o", options);
+
+               dumpFile(reader);
+       }
+       catch (const char* msg) {
+               fprintf(stderr, "ObjDump failed: %s\n", msg);
+       }
+       
+       return 0;
+}
+
+
+
diff --git a/src/ObjectFile.h b/src/ObjectFile.h
new file mode 100644 (file)
index 0000000..5a80c26
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __OBJECTFILE__
+#define __OBJECTFILE__
+
+#include <stdint.h>
+#include <vector>
+#include <map>
+
+
+
+namespace ObjectFile {
+
+struct StabsInfo
+{
+       uint64_t        atomOffset;
+       const char* string;
+       uint8_t         type;
+       uint8_t         other;
+       uint16_t        desc;
+};
+
+class ReaderOptions
+{
+public:
+                                               ReaderOptions() : fFullyLoadArchives(false), fLoadObjcClassesInArchives(false), fFlatNamespace(false), 
+                                                                                       fStripDebugInfo(false), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false) {}
+
+       bool                            fFullyLoadArchives;
+       bool                            fLoadObjcClassesInArchives;
+       bool                            fFlatNamespace;
+       bool                            fStripDebugInfo;
+       bool                            fTraceDylibs;
+       bool                            fTraceIndirectDylibs;
+       bool                            fTraceArchives;
+};
+
+
+class Reader
+{
+public:
+       static Reader* createReader(const char* path, const ReaderOptions& options);
+       
+       virtual const char*                                     getPath() = 0;
+       virtual std::vector<class Atom*>&       getAtoms() = 0;
+       virtual std::vector<class Atom*>*       getJustInTimeAtomsFor(const char* name) = 0;
+       virtual std::vector<StabsInfo>*         getStabsDebugInfo() = 0;
+       
+       // For Dynamic Libraries only
+       virtual const char*                                     getInstallPath()                        { return NULL; }
+       virtual uint32_t                                        getTimestamp()                          { return 0; }
+       virtual uint32_t                                        getCurrentVersion()                     { return 0; }
+       virtual uint32_t                                        getCompatibilityVersion()       { return 0; }
+       virtual std::vector<const char*>*       getDependentLibraryPaths()      { return NULL; }
+       virtual bool                                            reExports(Reader*)                      { return false; }
+       virtual bool                                            isDefinitionWeak(const Atom&){ return false; }
+       
+       
+       
+protected:
+                                                                               Reader() {}
+};
+
+class Segment
+{
+public:
+       virtual const char*                     getName() const  = 0;
+       virtual bool                            isContentReadable() const = 0;
+       virtual bool                            isContentWritable() const = 0;
+       virtual bool                            isContentExecutable() const = 0;
+       
+       uint64_t                                        getBaseAddress() const { return fBaseAddress; }
+       void                                            setBaseAddress(uint64_t addr) { fBaseAddress = addr; }
+
+protected:
+               Segment() : fBaseAddress(0) {}
+       uint64_t                                        fBaseAddress;
+};
+
+class Reference;
+
+class Section 
+{
+public:
+       unsigned int    getIndex() { return fIndex; }
+       uint64_t                getBaseAddress() { return fBaseAddress; }
+       void                    setBaseAddress(uint64_t addr) { fBaseAddress = addr; }
+       void*                   fOther;
+       
+protected:
+                                       Section() : fOther(NULL), fBaseAddress(0), fIndex(0)  {}
+       uint64_t                fBaseAddress;
+       unsigned int    fIndex;
+};
+
+
+class ContentWriter
+{
+public:
+       virtual void    write(uint64_t atomOffset, const void* buffer, uint64_t size) = 0;
+};
+
+class Atom 
+{
+public:
+       enum Scope { scopeTranslationUnit, scopeLinkageUnit, scopeGlobal };
+       enum WeakImportSetting { kWeakUnset, kWeakImport, kNonWeakImport };
+       
+       virtual Reader*                                                 getFile() const = 0;
+       virtual const char*                                             getName() const = 0;
+       virtual const char*                                             getDisplayName() const = 0;
+       virtual Scope                                                   getScope() const = 0;
+       virtual bool                                                    isTentativeDefinition() const = 0;
+       virtual bool                                                    isWeakDefinition() const = 0;
+       virtual bool                                                    isCoalesableByName() const = 0;
+       virtual bool                                                    isCoalesableByValue() const = 0;
+       virtual bool                                                    isZeroFill() const = 0;
+       virtual bool                                                    dontDeadStrip() const = 0;
+       virtual bool                                                    dontStripName() const = 0;  // referenced dynamically
+       virtual bool                                                    isImportProxy() const = 0;
+       virtual uint64_t                                                getSize() const = 0;
+       virtual std::vector<ObjectFile::Reference*>&  getReferences() const = 0;
+       virtual bool                                                    mustRemainInSection() const = 0;
+       virtual const char*                                             getSectionName() const = 0;
+       virtual Segment&                                                getSegment() const = 0;
+       virtual bool                                                    requiresFollowOnAtom() const = 0;
+       virtual Atom&                                                   getFollowOnAtom() const = 0;
+       virtual std::vector<StabsInfo>*                 getStabsDebugInfo() const = 0;
+       virtual uint8_t                                                 getAlignment() const = 0;
+       virtual WeakImportSetting                               getImportWeakness() const = 0;
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const = 0;
+       virtual void                                                    writeContent(bool finalLinkedImage, ContentWriter&) const = 0;
+       virtual void                                                    setScope(Scope) = 0;
+       virtual void                                                    setImportWeakness(bool weakImport) = 0; 
+
+       
+                       uint64_t                                                getSectionOffset() const        { return fSectionOffset; }
+                       uint64_t                                                getSegmentOffset() const        { return fSegmentOffset; }
+                       uint64_t                                                getAddress() const      { return fSection->getBaseAddress() + fSectionOffset; }
+                       unsigned int                                    getSortOrder() const { return fSortOrder; }
+                       class Section*                                  getSection() const { return fSection; }
+
+                       void                                                    setSegmentOffset(uint64_t offset) { fSegmentOffset = offset; }
+                       void                                                    setSectionOffset(uint64_t offset) { fSectionOffset = offset; }
+                       void                                                    setSection(class Section* sect) { fSection = sect; } 
+                       unsigned int                                    setSortOrder(unsigned int order); // recursively sets follow-on atoms
+
+protected:
+               Atom() : fSegmentOffset(0), fSectionOffset(0), fSortOrder(0), fSection(NULL) {}
+               
+               uint64_t                                                        fSegmentOffset;
+               uint64_t                                                        fSectionOffset;
+               unsigned int                                            fSortOrder;
+               class Section*                                          fSection;
+};
+
+
+
+// recursively sets follow-on atoms
+inline unsigned int Atom::setSortOrder(unsigned int order)
+{
+       if ( this->requiresFollowOnAtom() ) {
+               fSortOrder = order;
+               return this->getFollowOnAtom().setSortOrder(order+1);
+       }
+       else {
+               fSortOrder = order;
+               return (order + 1);
+       }
+}
+
+
+
+class Reference
+{
+public:
+       enum Kind { noFixUp, pointer, ppcFixupBranch24, ppcFixupBranch14, 
+                               ppcFixupPicBaseLow16, ppcFixupPicBaseLow14, ppcFixupPicBaseHigh16, 
+                               ppcFixupAbsLow16, ppcFixupAbsLow14, ppcFixupAbsHigh16, ppcFixupAbsHigh16AddLow,
+                               pointer32Difference, pointer64Difference, x86FixupBranch32 };
+
+       virtual bool                    isUnbound() const = 0;
+       virtual bool                    isWeakReference() const = 0;
+       virtual bool                    requiresRuntimeFixUp() const = 0;
+       virtual bool                    isLazyReference() const = 0;
+       virtual Kind                    getKind() const = 0;
+       virtual uint64_t                getFixUpOffset() const = 0;
+       virtual const char*             getTargetName() const = 0;
+       virtual Atom&                   getTarget() const = 0;
+       virtual uint64_t                getTargetOffset() const = 0;
+       virtual Atom&                   getFromTarget() const = 0;
+       virtual const char*             getFromTargetName() const = 0;
+       virtual uint64_t                getFromTargetOffset() const = 0;
+
+       virtual void                    setTarget(Atom&) = 0;
+       virtual void                    setFromTarget(Atom&) = 0;
+       virtual const char*             getDescription() const = 0;
+};
+
+
+};     // namespace ObjectFile
+
+
+#endif // __OBJECTFILE__
+
+
+
+
+
+
diff --git a/src/Options.cpp b/src/Options.cpp
new file mode 100644 (file)
index 0000000..6b913af
--- /dev/null
@@ -0,0 +1,1174 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
+#include "Options.h"
+
+ __attribute__((noreturn))
+void throwf(const char* format, ...) 
+{
+       va_list list;
+       char*   p;
+       va_start(list, format);
+       vasprintf(&p, format, list);
+       va_end(list);
+       
+       const char*     t = p;
+       throw t;
+}
+
+
+Options::Options(int argc, const char* argv[])
+ : fOutputFile("a.out"), fArchitecture(CPU_TYPE_POWERPC64), fOutputKind(kDynamicExecutable), fBindAtLoad(false),
+       fStripLocalSymbols(false),  fKeepPrivateExterns(false),
+       fInterposable(false), fIgnoreOtherArchFiles(false), fForceSubtypeAll(false), fNameSpace(kTwoLevelNameSpace),
+       fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fEntryName("start"), fBaseAddress(0),
+       fExportMode(kExportDefault), fLibrarySearchMode(kSearchAllDirsForDylibsThenAllDirsForArchives),
+       fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(false), fPICTreatment(kPICError),
+       fWeakReferenceMismatchTreatment(kWeakReferenceMismatchError), 
+       fUmbrellaName(NULL), fInitFunctionName(NULL), fZeroPageSize(0x1000), fStackSize(0), fStackAddr(0), fMinimumHeaderPad(0),
+       fCommonsMode(kCommonsIgnoreDylibs), fWarnCommons(false)
+{
+       this->parsePreCommandLineEnvironmentSettings();
+       this->parse(argc, argv);
+       this->parsePostCommandLineEnvironmentSettings();
+       this->checkIllegalOptionCombinations();
+}
+
+Options::~Options()
+{
+}
+
+
+ObjectFile::ReaderOptions& Options::readerOptions()
+{
+       return fReaderOptions;
+}
+
+cpu_type_t Options::architecture()
+{
+       return fArchitecture;
+}
+
+
+const char*    Options::getOutputFilePath()
+{
+       return fOutputFile;
+}
+
+
+std::vector<Options::FileInfo>& Options::getInputFiles()
+{
+       return fInputFiles;
+}
+
+Options::OutputKind    Options::outputKind()
+{
+       return fOutputKind;
+}
+
+bool Options::stripLocalSymbols()
+{
+       return fStripLocalSymbols;
+}
+
+bool Options::stripDebugInfo()
+{
+       return fReaderOptions.fStripDebugInfo;
+}
+
+bool Options::bindAtLoad()
+{
+       return fBindAtLoad;
+}
+
+bool Options::fullyLoadArchives()
+{
+       return fReaderOptions.fFullyLoadArchives;
+}
+
+Options::NameSpace Options::nameSpace()
+{
+       return fNameSpace;
+}
+
+const char*    Options::installPath()
+{
+       if ( fDylibInstallName != NULL ) 
+               return fDylibInstallName;
+       else
+               return fOutputFile;
+}
+
+uint32_t Options::currentVersion()
+{
+       return fDylibCurrentVersion;
+}
+
+uint32_t Options::compatibilityVersion()
+{
+       return fDylibCompatVersion;
+}
+
+const char*    Options::entryName()
+{
+       return fEntryName;
+}
+
+uint64_t Options::baseAddress()
+{
+       return fBaseAddress;
+}
+
+bool Options::keepPrivateExterns()
+{
+       return fKeepPrivateExterns;
+}
+
+bool Options::interposable()
+{
+       return fInterposable;
+}
+
+bool Options::ignoreOtherArchInputFiles()
+{
+       return fIgnoreOtherArchFiles;
+}
+
+bool Options::forceCpuSubtypeAll()
+{
+       return fForceSubtypeAll;
+}
+
+bool Options::traceDylibs()
+{
+       return fReaderOptions.fTraceDylibs;
+}
+
+bool Options::traceArchives()
+{
+       return fReaderOptions.fTraceArchives;
+}
+
+Options::UndefinedTreatment Options::undefinedTreatment()
+{
+       return fUndefinedTreatment;
+}
+
+Options::WeakReferenceMismatchTreatment        Options::weakReferenceMismatchTreatment()
+{
+       return fWeakReferenceMismatchTreatment;
+}
+
+const char* Options::umbrellaName()
+{
+       return fUmbrellaName;
+}
+
+uint64_t Options::zeroPageSize()
+{
+       return fZeroPageSize;
+}
+
+bool Options::hasCustomStack()
+{
+       return (fStackSize != 0);
+}
+       
+uint64_t Options::customStackSize()
+{
+       return fStackSize;
+}
+
+uint64_t Options::customStackAddr()
+{
+       return fStackAddr;
+}
+
+std::vector<const char*>& Options::initialUndefines()
+{
+       return fInitialUndefines;
+}
+
+const char*    Options::initFunctionName()
+{
+       return fInitFunctionName;
+}
+
+bool Options::hasExportRestrictList()
+{
+       return (fExportMode != kExportDefault);
+}
+
+uint32_t Options::minimumHeaderPad()
+{
+       return fMinimumHeaderPad;
+}
+
+std::vector<Options::ExtraSection>&    Options::extraSections()
+{
+       return fExtraSections;
+}
+
+std::vector<Options::SectionAlignment>&        Options::sectionAlignments()
+{
+       return fSectionAlignments;
+}
+
+
+Options::CommonsMode Options::commonsMode()
+{
+       return fCommonsMode;
+}
+
+bool Options::warnCommons()
+{
+       return fWarnCommons;
+}
+
+
+bool Options::shouldExport(const char* symbolName)
+{
+       switch (fExportMode) {
+               case kExportSome:
+                       return ( fExportSymbols.find(symbolName) != fExportSymbols.end() );
+               case kDontExportSome:
+                       return ( fDontExportSymbols.find(symbolName) == fDontExportSymbols.end() );
+               case kExportDefault:
+                       return true;
+       }
+       throw "internal error";
+}
+
+
+void Options::parseArch(const char* architecture)
+{
+       if ( architecture == NULL )
+               throw "-arch must be followed by an architecture string";
+       if ( strcmp(architecture, "ppc") == 0 )
+               fArchitecture = CPU_TYPE_POWERPC;
+       else if ( strcmp(architecture, "ppc64") == 0 )
+               fArchitecture = CPU_TYPE_POWERPC64;
+       else if ( strcmp(architecture, "i386") == 0 )
+               fArchitecture = CPU_TYPE_I386;
+       else 
+               throw "-arch followed by unknown architecture name";
+}
+
+bool Options::checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result)
+{
+       struct stat statBuffer;
+       char possiblePath[strlen(dir)+strlen(rootName)+20];
+       sprintf(possiblePath, format,  dir, rootName);
+       if ( stat(possiblePath, &statBuffer) == 0 ) {
+               result.path = strdup(possiblePath);
+               result.fileLen = statBuffer.st_size;
+               return true;
+       }
+       return false;
+} 
+
+
+Options::FileInfo Options::findLibrary(const char* rootName)
+{
+       FileInfo result;
+       const int rootNameLen = strlen(rootName);
+       // if rootName ends in .o there is no .a vs .dylib choice
+       if ( (rootNameLen > 3) && (strcmp(&rootName[rootNameLen-2], ".o") == 0) ) {
+               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
+                       const char* dir = *it;
+                       if ( checkForFile("%s/%s", dir, rootName, result) )
+                               return result;
+               }
+       }
+       else {
+               bool lookForDylibs = ( fOutputKind != Options::kDyld);
+               switch ( fLibrarySearchMode ) {
+                       case kSearchAllDirsForDylibsThenAllDirsForArchives:
+                               // first look in all directories for just for dylibs
+                               if ( lookForDylibs ) {
+                                       for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
+                                               const char* dir = *it;
+                                               if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) )
+                                                       return result;
+                                       }
+                               }
+                               // next look in all directories for just for archives
+                               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
+                                       const char* dir = *it;
+                                       if ( checkForFile("%s/lib%s.a", dir, rootName, result) )
+                                               return result;
+                               }
+                               break;
+
+                       case kSearchDylibAndArchiveInEachDir:
+                               // look in each directory for just for a dylib then for an archive
+                               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
+                                       const char* dir = *it;
+                                       if ( lookForDylibs && checkForFile("%s/lib%s.dylib", dir, rootName, result) )
+                                               return result;
+                                       if ( checkForFile("%s/lib%s.a", dir, rootName, result) )
+                                               return result;
+                               }
+                               break;
+               }
+       }
+       throwf("library not found for -l%s", rootName);
+}
+
+
+Options::FileInfo Options::findFramework(const char* rootName)
+{
+       struct stat statBuffer;
+       const int rootNameLen = strlen(rootName);
+       for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin(); it != fFrameworkSearchPaths.end(); it++) {
+               const char* dir = *it;
+               char possiblePath[strlen(dir)+2*rootNameLen+20];
+               strcpy(possiblePath, dir);
+               strcat(possiblePath, "/");
+               strcat(possiblePath, rootName);
+               strcat(possiblePath, ".framework/");
+               strcat(possiblePath, rootName);
+               if ( stat(possiblePath, &statBuffer) == 0 ) {
+                       FileInfo result;
+                       result.path = strdup(possiblePath);
+                       result.fileLen = statBuffer.st_size;
+                       return result;
+               }
+       }
+       throwf("framework not found %s", rootName);
+}
+
+
+Options::FileInfo Options::makeFileInfo(const char* path)
+{
+       struct stat statBuffer;
+       if ( stat(path, &statBuffer) == 0 ) {
+               FileInfo result;
+               result.path = strdup(path);
+               result.fileLen = statBuffer.st_size;
+               return result;
+       }
+       else {
+               throwf("file not found: %s", path);
+       }
+}
+
+void Options::loadFileList(const char* fileOfPaths)
+{
+       FILE* file = fopen(fileOfPaths, "r");
+       if ( file == NULL ) 
+               throwf("-filelist file not found: %s\n", fileOfPaths);
+       
+       char path[1024];
+       while ( fgets(path, 1024, file) != NULL ) {
+               path[1023] = '\0';
+               char* eol = strchr(path, '\n');
+               if ( eol != NULL )
+                       *eol = '\0';
+                       
+               fInputFiles.push_back(makeFileInfo(path));
+       }
+       fclose(file);
+}
+
+
+void Options::loadExportFile(const char* fileOfExports, const char* option, NameSet& set)
+{
+       // read in whole file
+       int fd = ::open(fileOfExports, O_RDONLY, 0);
+       if ( fd == -1 )
+               throwf("can't open %s file: %s", option, fileOfExports);
+       struct stat stat_buf;
+       ::fstat(fd, &stat_buf);
+       char* p = (char*)malloc(stat_buf.st_size);
+       if ( p == NULL )
+               throwf("can't process %s file: %s", option, fileOfExports);
+       
+       if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size )
+               throwf("can't read %s file: %s", option, fileOfExports);
+       
+       ::close(fd);
+       
+       // parse into symbols and add to hash_set
+       char * const end = &p[stat_buf.st_size];
+       enum { lineStart, inSymbol, inComment } state = lineStart;
+       char* symbolStart = NULL;
+       for (char* s = p; s < end; ++s ) {
+               switch ( state ) {
+                       case lineStart:
+                               if ( *s =='#' ) {
+                                       state = inComment;
+                               }
+                               else if ( !isspace(*s) ) {
+                                       state = inSymbol;
+                                       symbolStart = s;
+                               }
+                               break;
+                       case inSymbol:
+                               if ( *s == '\n' ) {
+                                       *s = '\0';
+                                       // removing any trailing spaces
+                                       char* last = s-1;
+                                       while ( isspace(*last) ) {
+                                               *last = '\0';
+                                               --last;
+                                       }
+                                       set.insert(symbolStart);
+                                       symbolStart = NULL;
+                                       state = lineStart;
+                               }
+                               break;
+                       case inComment:
+                               if ( *s == '\n' )
+                                       state = lineStart;
+                               break;
+               }
+       }
+       // Note: we do not free() the malloc buffer, because the strings are used by the export-set hash table
+}
+
+void Options::setUndefinedTreatment(const char* treatment)
+{
+       if ( treatment == NULL ) 
+               throw "-undefined missing [ warning | error | suppress | dynamic_lookup ]";
+
+       if ( strcmp(treatment, "warning") == 0 )
+               fUndefinedTreatment = kUndefinedWarning;
+       else if ( strcmp(treatment, "error") == 0 )
+               fUndefinedTreatment = kUndefinedError;
+       else if ( strcmp(treatment, "suppress") == 0 )
+               fUndefinedTreatment = kUndefinedSuppress;
+       else if ( strcmp(treatment, "dynamic_lookup") == 0 )
+               fUndefinedTreatment = kUndefinedDynamicLookup;
+       else
+               throw "invalid option to -undefined [ warning | error | suppress | dynamic_lookup ]";
+}
+
+void Options::setReadOnlyRelocTreatment(const char* treatment)
+{
+       if ( treatment == NULL ) 
+               throw "-read_only_relocs missing [ warning | error | suppress ]";
+
+       if ( strcmp(treatment, "warning") == 0 )
+               throw "-read_only_relocs warning not supported";
+       else if ( strcmp(treatment, "suppress") == 0 )
+               throw "-read_only_relocs suppress not supported";
+       else if ( strcmp(treatment, "error") != 0 )
+               throw "invalid option to -read_only_relocs [ warning | error | suppress | dynamic_lookup ]";
+}
+
+void Options::setPICTreatment(const char* treatment)
+{
+       if ( treatment == NULL ) 
+               throw "-sect_diff_relocs missing [ warning | error | suppress ]";
+
+       if ( strcmp(treatment, "warning") == 0 )
+               fPICTreatment = kPICWarning;
+       else if ( strcmp(treatment, "error") == 0 )
+               fPICTreatment = kPICError;
+       else if ( strcmp(treatment, "suppress") == 0 )
+               fPICTreatment = kPICSuppress;
+       else
+               throw "invalid option to -sect_diff_relocs [ warning | error | suppress ]";
+}
+
+void Options::setWeakReferenceMismatchTreatment(const char* treatment)
+{
+       if ( treatment == NULL ) 
+               throw "-weak_reference_mismatches missing [ error | weak | non-weak ]";
+
+       if ( strcmp(treatment, "error") == 0 )
+               fWeakReferenceMismatchTreatment = kWeakReferenceMismatchError;
+       else if ( strcmp(treatment, "weak") == 0 )
+               fWeakReferenceMismatchTreatment = kWeakReferenceMismatchWeak;
+       else if ( strcmp(treatment, "non-weak") == 0 )
+               fWeakReferenceMismatchTreatment = kWeakReferenceMismatchNonWeak;
+       else
+               throw "invalid option to -weak_reference_mismatches [ error | weak | non-weak ]";
+}
+
+Options::CommonsMode Options::parseCommonsTreatment(const char* mode)
+{
+       if ( mode == NULL ) 
+               throw "-commons missing [ ignore_dylibs | use_dylibs | error ]";
+
+       if ( strcmp(mode, "ignore_dylibs") == 0 )
+               return kCommonsIgnoreDylibs;
+       else if ( strcmp(mode, "use_dylibs") == 0 )
+               return kCommonsOverriddenByDylibs;
+       else if ( strcmp(mode, "error") == 0 )
+               return kCommonsConflictsDylibsError;
+       else
+               throw "invalid option to -commons [ ignore_dylibs | use_dylibs | error ]";
+}
+
+
+void Options::setDylibInstallNameOverride(const char* paths)
+{
+
+
+}
+
+void Options::setExecutablePath(const char* path)
+{
+
+
+}
+
+
+
+
+uint64_t Options::parseAddress(const char* addr)
+{
+       char* endptr;
+       uint64_t result = strtoull(addr, &endptr, 16);
+       return result;
+}
+
+
+
+//
+// Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz 
+//
+//
+uint32_t Options::parseVersionNumber(const char* versionString)
+{
+       unsigned long x = 0;
+       unsigned long y = 0;
+       unsigned long z = 0;
+       char* end;
+       x = strtoul(versionString, &end, 10);
+       if ( *end == '.' ) {
+               y = strtoul(&end[1], &end, 10);
+               if ( *end == '.' ) {
+                       z = strtoul(&end[1], &end, 10);
+               }
+       }
+       if ( (*end != '\0') || (x > 0xffff) || (y > 0xff) || (z > 0xff) )
+               throwf("malformed version number: %s", versionString);
+
+       return (x << 16) | ( y << 8 ) | z;
+}
+
+void Options::parseSectionOrderFile(const char* segment, const char* section, const char* path)
+{
+       fprintf(stderr, "ld64: warning -sectorder not yet supported for 64-bit code\n");
+}
+
+void Options::addSection(const char* segment, const char* section, const char* path)
+{
+       if ( strlen(segment) > 16 )
+               throw "-seccreate segment name max 16 chars";
+       if ( strlen(section) > 16 )
+               throw "-seccreate section name max 16 chars";
+
+       // read in whole file
+       int fd = ::open(path, O_RDONLY, 0);
+       if ( fd == -1 )
+               throwf("can't open -sectcreate file: %s", path);
+       struct stat stat_buf;
+       ::fstat(fd, &stat_buf);
+       char* p = (char*)malloc(stat_buf.st_size);
+       if ( p == NULL )
+               throwf("can't process -sectcreate file: %s", path);
+       if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size )
+               throwf("can't read -sectcreate file: %s", path);
+       ::close(fd);
+       
+       // record section to create
+       ExtraSection info = { segment, section, path, (uint8_t*)p, stat_buf.st_size };
+       fExtraSections.push_back(info);
+}
+
+void Options::addSectionAlignment(const char* segment, const char* section, const char* alignmentStr)
+{
+       if ( strlen(segment) > 16 )
+               throw "-sectalign segment name max 16 chars";
+       if ( strlen(section) > 16 )
+               throw "-sectalign section name max 16 chars";
+
+       char* endptr;
+       unsigned long value = strtoul(alignmentStr, &endptr, 16);
+       if ( *endptr != '\0')
+               throw "argument for -sectalign is not a hexadecimal number";
+       if ( value > 0x8000 )
+               throw "argument for -sectalign must be less than or equal to 0x8000";
+       uint8_t alignment = 0;
+       for(unsigned long x=value; x != 1; x >>= 1)
+               ++alignment;
+       if ( (unsigned long)(1 << alignment) != value )
+               throw "argument for -sectalign is not a power of two";
+
+       SectionAlignment info = { segment, section, alignment };
+       fSectionAlignments.push_back(info);
+}
+
+
+void Options::parse(int argc, const char* argv[])
+{
+       // pass one builds search list from -L and -F options
+       this->buildSearchPaths(argc, argv);
+       
+       // pass two parse all other options
+       for(int i=1; i < argc; ++i) {
+               const char* arg = argv[i];
+               
+               if ( arg[0] == '-' ) {
+                       if ( (arg[1] == 'L') || (arg[1] == 'F') ) {
+                               // previously handled
+                       }
+                       else if ( strcmp(arg, "-arch") == 0 ) {
+                               parseArch(argv[++i]);
+                       }
+                       else if ( strcmp(arg, "-dynamic") == 0 ) {
+                               // default
+                       }
+                       else if ( strcmp(arg, "-static") == 0 ) {
+                               fOutputKind = kStaticExecutable;
+                       }
+                       else if ( strcmp(arg, "-dylib") == 0 ) {
+                               fOutputKind = kDynamicLibrary;
+                       }
+                       else if ( strcmp(arg, "-bundle") == 0 ) {
+                               fOutputKind = kDynamicBundle;
+                       }
+                       else if ( strcmp(arg, "-dylinker") == 0 ) {
+                               fOutputKind = kDyld;
+                       }
+                       else if ( strcmp(arg, "-execute") == 0 ) {
+                               if ( fOutputKind != kStaticExecutable )
+                                       fOutputKind = kDynamicExecutable;
+                       }
+                       else if ( strcmp(arg, "-r") == 0 ) {
+                               fOutputKind = kObjectFile;
+                       }
+                       else if ( strcmp(arg, "-o") == 0 ) {
+                               fOutputFile = argv[++i];
+                       }
+                       else if ( arg[1] == 'l' ) {
+                               fInputFiles.push_back(findLibrary(&arg[2]));
+                       }
+                       else if ( strcmp(arg, "-weak-l") == 0 ) {
+                               FileInfo info = findLibrary(&arg[2]);
+                               info.options.fWeakImport = true;
+                               fInputFiles.push_back(info);
+                       }
+                       else if ( strcmp(arg, "-bind_at_load") == 0 ) {
+                               fBindAtLoad = true;
+                       }
+                       else if ( strcmp(arg, "-twolevel_namespace") == 0 ) {
+                               fNameSpace = kTwoLevelNameSpace;
+                       }
+                       else if ( strcmp(arg, "-flat_namespace") == 0 ) {
+                               fNameSpace = kFlatNameSpace;
+                       }
+                       else if ( strcmp(arg, "-force_flat_namespace") == 0 ) {
+                               fNameSpace = kForceFlatNameSpace;
+                       }
+                       else if ( strcmp(arg, "-all_load") == 0 ) {
+                               fReaderOptions.fFullyLoadArchives = true;
+                       }
+                       else if ( strcmp(arg, "-ObjC") == 0 ) {
+                               fReaderOptions.fLoadObjcClassesInArchives = true;
+                       }
+                       else if ( strcmp(arg, "-dylib_compatibility_version") == 0 ) {
+                               fDylibCompatVersion = parseVersionNumber(argv[++i]);
+                       }
+                       else if ( strcmp(arg, "-dylib_current_version") == 0 ) {
+                               fDylibCurrentVersion = parseVersionNumber(argv[++i]);
+                       }
+                       else if ( strcmp(arg, "-sectorder") == 0 ) {
+                               parseSectionOrderFile(argv[i+1], argv[i+2], argv[i+3]);
+                               i += 3;
+                       }
+                       else if ( (strcmp(arg, "-sectcreate") == 0) || (strcmp(arg, "-segcreate") == 0) ) {
+                               addSection(argv[i+1], argv[i+2], argv[i+3]);
+                               i += 3;
+                       }
+                       else if ( (strcmp(arg, "-dylib_install_name") == 0) || (strcmp(arg, "-dylinker_install_name") == 0) ) {
+                               fDylibInstallName = argv[++i];
+                       }
+                       else if ( strcmp(arg, "-seg1addr") == 0 ) {
+                               fBaseAddress = parseAddress(argv[++i]);
+                       }
+                       else if ( strcmp(arg, "-e") == 0 ) {
+                               fEntryName = argv[++i];
+                       }
+                       else if ( strcmp(arg, "-filelist") == 0 ) {
+                                loadFileList(argv[++i]);
+                       }
+                       else if ( strcmp(arg, "-keep_private_externs") == 0 ) {
+                                fKeepPrivateExterns = true;
+                       }
+                       else if ( strcmp(arg, "-final_output") == 0 ) {
+                                ++i;
+                               // ignore for now
+                       }
+                       else if ( (strcmp(arg, "-interposable") == 0) || (strcmp(arg, "-multi_module") == 0)) {
+                                fInterposable = true;
+                       }
+                       else if ( strcmp(arg, "-single_module") == 0 ) {
+                                fInterposable = false;
+                       }
+                       else if ( strcmp(arg, "-exported_symbols_list") == 0 ) {
+                               if ( fExportMode == kDontExportSome )
+                                       throw "can't use -exported_symbols_list and -unexported_symbols_list";
+                               fExportMode = kExportSome;
+                               loadExportFile(argv[++i], "-exported_symbols_list", fExportSymbols);
+                       }
+                       else if ( strcmp(arg, "-unexported_symbols_list") == 0 ) {
+                               if ( fExportMode == kExportSome )
+                                       throw "can't use -exported_symbols_list and -unexported_symbols_list";
+                               fExportMode = kDontExportSome;
+                               loadExportFile(argv[++i], "-unexported_symbols_list", fDontExportSymbols);
+                       }
+                       else if ( strcmp(arg, "-no_arch_warnings") == 0 ) {
+                                fIgnoreOtherArchFiles = true;
+                       }
+                       else if ( strcmp(arg, "-force_cpusubtype_ALL") == 0 ) {
+                                fForceSubtypeAll = true;
+                       }
+                       else if ( strcmp(arg, "-weak_library") == 0 ) {
+                               FileInfo info = makeFileInfo(argv[++i]);
+                               info.options.fWeakImport = true;
+                               fInputFiles.push_back(info);
+                       }
+                       else if ( strcmp(arg, "-framework") == 0 ) {
+                               fInputFiles.push_back(findFramework(argv[++i]));
+                       }
+                       else if ( strcmp(arg, "-weak_framework") == 0 ) {
+                               FileInfo info = findFramework(argv[++i]);
+                               info.options.fWeakImport = true;
+                               fInputFiles.push_back(info);
+                       }
+                       else if ( strcmp(arg, "-search_paths_first") == 0 ) {
+                               fLibrarySearchMode = kSearchDylibAndArchiveInEachDir;
+                       }
+                       else if ( strcmp(arg, "-undefined") == 0 ) {
+                                setUndefinedTreatment(argv[++i]);
+                       }
+                       else if ( strcmp(arg, "-arch_multiple") == 0 ) {
+                                fMessagesPrefixedWithArchitecture = true;
+                       }
+                       else if ( strcmp(arg, "-read_only_relocs") == 0 ) {
+                                setReadOnlyRelocTreatment(argv[++i]);
+                       }
+                       else if ( strcmp(arg, "-sect_diff_relocs") == 0 ) {
+                                setPICTreatment(argv[++i]);
+                       }
+                       else if ( strcmp(arg, "-weak_reference_mismatches") == 0 ) {
+                                setWeakReferenceMismatchTreatment(argv[++i]);
+                       }
+                       else if ( strcmp(arg, "-prebind") == 0 ) {
+                                 // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-noprebind") == 0 ) {
+                                 // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-prebind_allow_overlap") == 0 ) {
+                                 // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-prebind_all_twolevel_modules") == 0 ) {
+                                 // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-noprebind_all_twolevel_modules") == 0 ) {
+                                 // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-nofixprebinding") == 0 ) {
+                                 // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-dylib_file") == 0 ) {
+                                setDylibInstallNameOverride(argv[++i]);
+                       }
+                       else if ( strcmp(arg, "-executable_path") == 0 ) {
+                                setExecutablePath(argv[++i]);
+                       }
+                       else if ( strcmp(arg, "-segalign") == 0 ) {
+                               // FIX FIX
+                               ++i; 
+                       }
+                       else if ( strcmp(arg, "-segaddr") == 0 ) {
+                               // FIX FIX
+                               i += 2; 
+                       }
+                       else if ( strcmp(arg, "-segs_read_only_addr") == 0 ) {
+                               // FIX FIX
+                               ++i; 
+                       }
+                       else if ( strcmp(arg, "-segs_read_write_addr") == 0 ) {
+                               // FIX FIX
+                               ++i; 
+                       }
+                       else if ( strcmp(arg, "-seg_addr_table") == 0 ) {
+                               // FIX FIX
+                               ++i; 
+                       }
+                       else if ( strcmp(arg, "-seg_addr_table_filename") == 0 ) {
+                               // FIX FIX
+                               ++i; 
+                       }
+                       else if ( strcmp(arg, "-segprot") == 0 ) {
+                               // FIX FIX
+                               i += 3; 
+                       }
+                       else if ( strcmp(arg, "-pagezero_size") == 0 ) {
+                               fZeroPageSize = parseAddress(argv[++i]);
+                               fZeroPageSize &= (-4096); // page align
+                       }
+                       else if ( strcmp(arg, "-stack_addr") == 0 ) {
+                               fStackAddr = parseAddress(argv[++i]);
+                       }
+                       else if ( strcmp(arg, "-stack_size") == 0 ) {
+                               fStackSize = parseAddress(argv[++i]);
+                       }
+                       else if ( strcmp(arg, "-sectalign") == 0 ) {
+                               addSectionAlignment(argv[i+1], argv[i+2], argv[i+3]);
+                               i += 3;
+                       }
+                       else if ( strcmp(arg, "-sectorder_detail") == 0 ) {
+                                // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-sectobjectsymbols") == 0 ) {
+                               // FIX FIX
+                               i += 2;
+                       }
+                       else if ( strcmp(arg, "-bundle_loader") == 0 ) {
+                               // FIX FIX
+                               ++i;
+                       }
+                       else if ( strcmp(arg, "-private_bundle") == 0 ) {
+                               // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-twolevel_namespace_hints") == 0 ) {
+                               // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-multiply_defined") == 0 ) {
+                               // FIX FIX
+                               ++i;
+                       }
+                       else if ( strcmp(arg, "-multiply_defined_unused") == 0 ) {
+                               // FIX FIX
+                               ++i;
+                       }
+                       else if ( strcmp(arg, "-nomultidefs") == 0 ) {
+                                // FIX FIX
+                       }
+                       else if ( arg[1] == 'y' ) {
+                                // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-Y") == 0 ) {
+                                ++i;
+                                // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-m") == 0 ) {
+                                // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-whyload") == 0 ) {
+                                // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-u") == 0 ) {
+                               const char* name = argv[++i];
+                               if ( name == NULL )
+                                       throw "-u missing argument";
+                               fInitialUndefines.push_back(name);
+                       }
+                       else if ( strcmp(arg, "-i") == 0 ) {
+                                  // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-U") == 0 ) {
+                                // FIX FIX
+                                ++i;  
+                       }
+                       else if ( strcmp(arg, "-s") == 0 ) {
+                               // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-x") == 0 ) {
+                               // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-S") == 0 ) {
+                               // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-X") == 0 ) {
+                               // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-Si") == 0 ) {
+                               // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-b") == 0 ) {
+                               // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-Sn") == 0 ) {
+                               // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-dead_strip") == 0 ) {
+                                // FIX FIX
+                                fprintf(stderr, "ld64: warning -dead_strip not yet supported for 64-bit code\n");
+                       }
+                       else if ( strcmp(arg, "-v") == 0 ) {
+                               extern const char ld64VersionString[];
+                               fprintf(stderr, "%s", ld64VersionString);
+                                // if only -v specified, exit cleanly
+                                if ( argc == 2 )
+                                       exit(0);
+                       }
+                       else if ( strcmp(arg, "-w") == 0 ) {
+                               // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-arch_errors_fatal") == 0 ) {
+                               // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-M") == 0 ) {
+                               // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-whatsloaded") == 0 ) {
+                               // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-headerpad") == 0 ) {
+                               const char* size = argv[++i];
+                               if ( size == NULL )
+                                       throw "-headerpad missing argument";
+                                fMinimumHeaderPad = parseAddress(size);
+                       }
+                       else if ( strcmp(arg, "-headerpad_max_install_names") == 0 ) {
+                               // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-t") == 0 ) {
+                               // FIX FIX
+                       }
+                       else if ( strcmp(arg, "-A") == 0 ) {
+                                // FIX FIX
+                                ++i;  
+                       }
+                       else if ( strcmp(arg, "-umbrella") == 0 ) {
+                               const char* name = argv[++i];
+                               if ( name == NULL )
+                                       throw "-umbrella missing argument";
+                               fUmbrellaName = name;
+                       }
+                       else if ( strcmp(arg, "-allowable_client") == 0 ) {
+                                // FIX FIX
+                                ++i;  
+                       }
+                       else if ( strcmp(arg, "-client_name") == 0 ) {
+                                // FIX FIX
+                                ++i;  
+                       }
+                       else if ( strcmp(arg, "-sub_umbrella") == 0 ) {
+                               const char* name = argv[++i];
+                               if ( name == NULL )
+                                       throw "-sub_umbrella missing argument";
+                                fSubUmbellas.push_back(name);
+                       }
+                       else if ( strcmp(arg, "-sub_library") == 0 ) {
+                               const char* name = argv[++i];
+                               if ( name == NULL )
+                                       throw "-sub_library missing argument";
+                                fSubLibraries.push_back(name);
+                       }
+                       else if ( strcmp(arg, "-init") == 0 ) {
+                               const char* name = argv[++i];
+                               if ( name == NULL )
+                                       throw "-init missing argument";
+                               fInitFunctionName = name;
+                       }
+                       else if ( strcmp(arg, "-warn_commons") == 0 ) {
+                               fWarnCommons = true;
+                       }
+                       else if ( strcmp(arg, "-commons") == 0 ) {
+                               fCommonsMode = parseCommonsTreatment(argv[++i]);
+                       }
+                       
+                       else {
+                               fprintf(stderr, "unknown option: %s\n", arg);
+                       }
+               }
+               else {
+                       fInputFiles.push_back(makeFileInfo(arg));
+               }
+       }
+}
+
+void Options::buildSearchPaths(int argc, const char* argv[])
+{
+       bool addStandardLibraryDirectories = true;
+       // scan through argv looking for -L and -F options
+       for(int i=0; i < argc; ++i) {
+               if ( (argv[i][0] == '-') && (argv[i][1] == 'L') )
+                       fLibrarySearchPaths.push_back(&argv[i][2]);
+               else if ( (argv[i][0] == '-') && (argv[i][1] == 'F') )
+                       fFrameworkSearchPaths.push_back(&argv[i][2]);
+               else if ( strcmp(argv[i], "-Z") == 0 )
+                       addStandardLibraryDirectories = false;
+       }
+       if ( addStandardLibraryDirectories ) {
+               fLibrarySearchPaths.push_back("/usr/lib");
+               fLibrarySearchPaths.push_back("/usr/local/lib");
+               
+               fFrameworkSearchPaths.push_back("/Library/Frameworks/");
+               fFrameworkSearchPaths.push_back("/Network/Library/Frameworks/");
+               fFrameworkSearchPaths.push_back("/System/Library/Frameworks/");
+       }
+}
+
+// this is run before the command line is parsed
+void Options::parsePreCommandLineEnvironmentSettings()
+{
+       if ( getenv("RC_TRACE_ARCHIVES") != NULL)
+           fReaderOptions.fTraceArchives = true;
+               
+       if ( getenv("RC_TRACE_DYLIBS") != NULL) {
+           fReaderOptions.fTraceDylibs = true;
+               fReaderOptions.fTraceIndirectDylibs = true;
+       }
+}
+
+// this is run after the command line is parsed
+void Options::parsePostCommandLineEnvironmentSettings()
+{
+
+}
+
+void Options::checkIllegalOptionCombinations()
+{
+       // check -undefined setting
+       switch ( fUndefinedTreatment ) {
+               case kUndefinedError:
+               case kUndefinedDynamicLookup:
+                       // always legal
+                       break;
+               case kUndefinedWarning:
+               case kUndefinedSuppress:
+                       // requires flat namespace
+                       if ( fNameSpace == kTwoLevelNameSpace )
+                               throw "can't use -undefined warning or suppress with -twolevel_namespace";
+                       break;
+       }
+       
+       // unify -sub_umbrella with dylibs
+       for (std::vector<const char*>::iterator it = fSubUmbellas.begin(); it != fSubUmbellas.end(); it++) {
+               const char* subUmbrella = *it;
+               bool found = false;
+               for (std::vector<Options::FileInfo>::iterator fit = fInputFiles.begin(); fit != fInputFiles.end(); fit++) {
+                       Options::FileInfo& info = *fit;
+                       const char* lastSlash = strrchr(info.path, '/');
+                       if ( lastSlash == NULL )
+                               lastSlash = info.path - 1;
+                       if ( strcmp(&lastSlash[1], subUmbrella) == 0 ) {
+                               info.options.fReExport = true;
+                               found = true;
+                               break;
+                       }
+               }
+               if ( ! found )
+                       fprintf(stderr, "ld64 warning: -sub_umbrella %s does not match a supplied dylib\n", subUmbrella);
+       }
+       
+       // unify -sub_library with dylibs
+       for (std::vector<const char*>::iterator it = fSubLibraries.begin(); it != fSubLibraries.end(); it++) {
+               const char* subLibrary = *it;
+               bool found = false;
+               for (std::vector<Options::FileInfo>::iterator fit = fInputFiles.begin(); fit != fInputFiles.end(); fit++) {
+                       Options::FileInfo& info = *fit;
+                       const char* lastSlash = strrchr(info.path, '/');
+                       if ( lastSlash == NULL )
+                               lastSlash = info.path - 1;
+                       const char* dot = strchr(lastSlash, '.');
+                       if ( dot == NULL )
+                               dot = &lastSlash[strlen(lastSlash)];
+                       if ( strncmp(&lastSlash[1], subLibrary, dot-lastSlash-1) == 0 ) {
+                               info.options.fReExport = true;
+                               found = true;
+                               break;
+                       }
+               }
+               if ( ! found )
+                       fprintf(stderr, "ld64 warning: -sub_library %s does not match a supplied dylib\n", subLibrary);
+       }
+       
+       // sync reader options
+       if ( fNameSpace != kTwoLevelNameSpace )
+               fReaderOptions.fFlatNamespace = true;
+
+       // check -stack_addr
+       if ( fStackAddr != 0 ) { 
+               switch (fArchitecture) {
+                       case CPU_TYPE_I386:
+                       case CPU_TYPE_POWERPC:
+                               if ( fStackAddr > 0xFFFFFFFF ) 
+                                       throw "-stack_addr must be < 4G for 32-bit processes";
+                               break;
+                       case CPU_TYPE_POWERPC64:
+                               break;
+               }
+               if ( (fStackAddr & -4096) != fStackAddr )
+                       throw "-stack_addr must be multiples of 4K";
+               if ( fStackSize  == 0 )
+                       throw "-stack_addr must be used with -stack_size";
+       }
+       
+       // check -stack_size
+       if ( fStackSize != 0 ) { 
+               switch (fArchitecture) {
+                       case CPU_TYPE_I386:
+                       case CPU_TYPE_POWERPC:
+                               if ( fStackSize > 0xFFFFFFFF ) 
+                                       throw "-stack_size must be < 4G for 32-bit processes";
+                               if ( fStackAddr == 0 ) {
+                                       fprintf(stderr, "ld64 warning: -stack_addr not specified, using the default 0xC0000000\n");
+                                       fStackAddr = 0xC0000000;
+                               }
+                               break;
+                       case CPU_TYPE_POWERPC64:
+                               if ( fStackAddr == 0 ) {
+                                       fprintf(stderr, "ld64 warning: -stack_addr not specified, using the default 0x0008000000000000\n");
+                                       fStackAddr = 0x0008000000000000LL;
+                               }
+                               break;
+               }
+               if ( (fStackSize & -4096) != fStackSize )
+                       throw "-stack_size must be multiples of 4K";
+               switch ( fOutputKind ) {
+                       case Options::kDynamicExecutable:
+                       case Options::kStaticExecutable:
+                               // custom stack size only legeal when building main executable
+                               break;
+                       case Options::kDynamicLibrary:
+                       case Options::kDynamicBundle:
+                       case Options::kObjectFile:
+                       case Options::kDyld:
+                               throw "-stack_size option can only be used when linking a main executable";
+               }
+       }
+       
+       // check -init is only used when building a dylib
+       if ( (fInitFunctionName != NULL) && (fOutputKind != Options::kDynamicLibrary) )
+               throw "-init can only be used with -dynamiclib";
+}
+
+
diff --git a/src/Options.h b/src/Options.h
new file mode 100644 (file)
index 0000000..33d1137
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __OPTIONS__
+#define __OPTIONS__
+
+
+#include <stdint.h>
+#include <mach/machine.h>
+
+#ifndef CPU_TYPE_POWERPC64
+#define CPU_TYPE_POWERPC64 0x1000012
+#endif
+
+
+#include <vector>
+#include <ext/hash_set>
+
+#include "ObjectFile.h"
+
+extern  __attribute__((noreturn)) void throwf(const char* format, ...);
+
+
+class DynamicLibraryOptions 
+{
+public:
+                               DynamicLibraryOptions() : fWeakImport(false), fReExport(false), fInstallPathOverride(NULL) {}
+                               
+       bool            fWeakImport;
+       bool            fReExport;
+       const char* fInstallPathOverride;
+};
+
+
+class Options
+{
+public:
+                                                               Options(int argc, const char* argv[]);
+                                                               ~Options();
+
+       enum OutputKind { kDynamicExecutable, kStaticExecutable, kDynamicLibrary, kDynamicBundle, kObjectFile, kDyld };
+       enum NameSpace { kTwoLevelNameSpace, kFlatNameSpace, kForceFlatNameSpace };
+       enum UndefinedTreatment { kUndefinedError, kUndefinedWarning, kUndefinedSuppress, kUndefinedDynamicLookup };
+       enum PICTreatment { kPICError, kPICWarning, kPICSuppress };
+       enum WeakReferenceMismatchTreatment { kWeakReferenceMismatchError, kWeakReferenceMismatchWeak, kWeakReferenceMismatchNonWeak };
+       enum CommonsMode { kCommonsIgnoreDylibs, kCommonsOverriddenByDylibs, kCommonsConflictsDylibsError };
+
+       struct FileInfo {
+               const char*                             path;
+               uint64_t                                fileLen;
+               DynamicLibraryOptions   options;
+       };
+       
+       struct ExtraSection {
+               const char*                             segmentName;
+               const char*                             sectionName;
+               const char*                             path;
+               const uint8_t*                  data;
+               uint64_t                                dataLen;
+       };
+       
+       struct SectionAlignment {
+               const char*                             segmentName;
+               const char*                             sectionName;
+               uint8_t                                 alignment;
+       };
+
+       ObjectFile::ReaderOptions&      readerOptions();
+       const char*                                     getOutputFilePath();
+       std::vector<FileInfo>&          getInputFiles();
+       
+       cpu_type_t                                      architecture();
+       OutputKind                                      outputKind();
+       bool                                            stripLocalSymbols();
+       bool                                            stripDebugInfo();
+       bool                                            bindAtLoad();
+       bool                                            fullyLoadArchives();
+       NameSpace                                       nameSpace();
+       const char*                                     installPath();                  // only for kDynamicLibrary
+       uint32_t                                        currentVersion();               // only for kDynamicLibrary
+       uint32_t                                        compatibilityVersion(); // only for kDynamicLibrary
+       const char*                                     entryName();                    // only for kDynamicExecutable or kStaticExecutable
+       uint64_t                                        baseAddress();
+       bool                                            keepPrivateExterns();   // only for kObjectFile
+       bool                                            interposable();                 // only for kDynamicLibrary 
+       bool                                            hasExportRestrictList();
+       bool                                            shouldExport(const char*);
+       bool                                            ignoreOtherArchInputFiles();
+       bool                                            forceCpuSubtypeAll();
+       bool                                            traceDylibs();
+       bool                                            traceArchives();
+       UndefinedTreatment                      undefinedTreatment();
+       bool                                            messagesPrefixedWithArchitecture();
+       PICTreatment                            picTreatment();
+       WeakReferenceMismatchTreatment  weakReferenceMismatchTreatment();
+       const char*                                     umbrellaName();
+       const char*                                     initFunctionName();                     // only for kDynamicLibrary
+       uint64_t                                        zeroPageSize();
+       bool                                            hasCustomStack();
+       uint64_t                                        customStackSize();
+       uint64_t                                        customStackAddr();
+       std::vector<const char*>&       initialUndefines();
+       uint32_t                                        minimumHeaderPad();
+       std::vector<ExtraSection>&      extraSections();
+       std::vector<SectionAlignment>&  sectionAlignments();
+       CommonsMode                                     commonsMode();
+       bool                                            warnCommons();
+
+private:
+       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>  NameSet;
+       enum ExportMode { kExportDefault, kExportSome, kDontExportSome };
+       enum LibrarySearchMode { kSearchDylibAndArchiveInEachDir, kSearchAllDirsForDylibsThenAllDirsForArchives };
+
+       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);
+       FileInfo                                        findFramework(const char* rootName);
+       FileInfo                                        makeFileInfo(const char* path);
+       bool                                            checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result);
+       uint32_t                                        parseVersionNumber(const char*);
+       void                                            parseSectionOrderFile(const char* segment, const char* section, const char* path);
+       void                                            addSection(const char* segment, const char* section, const char* path);
+       void                                            addSubLibrary(const char* name);
+       void                                            loadFileList(const char* fileOfPaths);
+       uint64_t                                        parseAddress(const char* addr);
+       void                                            loadExportFile(const char* fileOfExports, const char* option, NameSet& set);
+       void                                            parsePreCommandLineEnvironmentSettings();
+       void                                            parsePostCommandLineEnvironmentSettings();
+       void                                            setUndefinedTreatment(const char* treatment);
+       void                                            setPICTreatment(const char* treatment);
+       void                                            setReadOnlyRelocTreatment(const char* treatment);
+       void                                            setWeakReferenceMismatchTreatment(const char* treatment);
+       void                                            setDylibInstallNameOverride(const char* paths);
+       void                                            setExecutablePath(const char* path);
+       void                                            addSectionAlignment(const char* segment, const char* section, const char* alignment);
+       CommonsMode                                     parseCommonsTreatment(const char* mode);
+               
+               
+
+       ObjectFile::ReaderOptions                       fReaderOptions;
+       const char*                                                     fOutputFile;
+       std::vector<Options::FileInfo>          fInputFiles;
+       cpu_type_t                                                      fArchitecture;
+       OutputKind                                                      fOutputKind;
+       bool                                                            fBindAtLoad;
+       bool                                                            fStripLocalSymbols;
+       bool                                                            fKeepPrivateExterns;
+       bool                                                            fInterposable;
+       bool                                                            fIgnoreOtherArchFiles;
+       bool                                                            fForceSubtypeAll;
+       NameSpace                                                       fNameSpace;
+       uint32_t                                                        fDylibCompatVersion;
+       uint32_t                                                        fDylibCurrentVersion;
+       const char*                                                     fDylibInstallName;
+       const char*                                                     fEntryName;
+       uint64_t                                                        fBaseAddress;
+       NameSet                                                         fExportSymbols;
+       NameSet                                                         fDontExportSymbols;
+       ExportMode                                                      fExportMode;
+       LibrarySearchMode                                       fLibrarySearchMode;
+       UndefinedTreatment                                      fUndefinedTreatment;
+       bool                                                            fMessagesPrefixedWithArchitecture;
+       PICTreatment                                            fPICTreatment;
+       WeakReferenceMismatchTreatment          fWeakReferenceMismatchTreatment;
+       std::vector<const char*>                        fSubUmbellas;
+       std::vector<const char*>                        fSubLibraries;
+       const char*                                                     fUmbrellaName;
+       const char*                                                     fInitFunctionName;
+       uint64_t                                                        fZeroPageSize;
+       uint64_t                                                        fStackSize;
+       uint64_t                                                        fStackAddr;
+       uint32_t                                                        fMinimumHeaderPad;
+       CommonsMode                                                     fCommonsMode;
+       bool                                                            fWarnCommons;
+       std::vector<const char*>                        fInitialUndefines;
+       std::vector<ExtraSection>                       fExtraSections;
+       std::vector<SectionAlignment>           fSectionAlignments;
+       
+       std::vector<const char*>                        fLibrarySearchPaths;
+       std::vector<const char*>                        fFrameworkSearchPaths;
+
+};
+
+
+
+
+#endif // __OPTIONS__
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Readers/ObjectFileArchiveMachO.cpp b/src/Readers/ObjectFileArchiveMachO.cpp
new file mode 100644 (file)
index 0000000..a6851a1
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+
+namespace ObjectFileArchiveMachO {
+
+class Reader : public ObjectFile::Reader 
+{
+public:
+                                                                                               Reader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
+       virtual                                                                         ~Reader();
+       
+       virtual const char*                                                             getPath();
+       virtual std::vector<class ObjectFile::Atom*>&   getAtoms();
+       virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name);
+       virtual std::vector<ObjectFile::StabsInfo>*             getStabsDebugInfo();
+
+private:
+       class Entry : ar_hdr
+       {
+       public:
+               const char*                     getName() const;
+               const uint8_t*          getContent() const;
+               uint32_t                        getContentSize() const;
+               const Entry*            getNext() const;
+       private:
+               bool                            hasLongName() const;
+               unsigned int            getLongNameSpace() const;
+               
+       };
+
+       const struct ranlib*                                                    ranlibBinarySearch(const char* name);
+       const struct ranlib*                                                    ranlibLinearSearch(const char* name);
+       ObjectFile::Reader*                                                             makeObjectReaderForMember(const Entry* member);
+       void                                                                                    dumpTableOfContents();
+       
+       const char*                                                                             fPath;
+       const ObjectFile::ReaderOptions&                                fOptions;
+       const uint8_t*                                                                  fFileContent;
+       uint64_t                                                                                fFileLength;
+       const struct ranlib*                                                    fTableOfContents;
+       uint32_t                                                                                fTableOfContentCount;
+       bool                                                                                    fSorted;
+       const char*                                                                             fStringPool;
+       std::vector<class ObjectFile::Atom*>                    fAllAtoms;
+       std::set<const class Entry*>                                    fInstantiatedEntries;
+       
+       static std::vector<class ObjectFile::Atom*>             fgEmptyList;
+};
+
+std::vector<class ObjectFile::Atom*>           Reader::fgEmptyList;
+
+
+bool Reader::Entry::hasLongName() const
+{
+       return ( strncmp(this->ar_name, AR_EFMT1, strlen(AR_EFMT1)) == 0 );
+}
+
+unsigned int Reader::Entry::getLongNameSpace() const
+{
+       char* endptr;
+       long result = strtol(&this->ar_name[strlen(AR_EFMT1)], &endptr, 10);
+       return result;
+}
+
+const char* Reader::Entry::getName() const
+{
+       if ( this->hasLongName() ) {
+               int len = this->getLongNameSpace();
+               static char longName[256];
+               strncpy(longName, ((char*)this)+sizeof(ar_hdr), len);
+               longName[len] = '\0';
+               return longName;
+       }
+       else {
+               static char shortName[20];
+               strncpy(shortName, this->ar_name, 16);
+               shortName[16] = '\0';
+               char* space = strchr(shortName, ' ');
+               if ( space != NULL )
+                       *space = '\0';
+               return shortName;
+       }
+}
+
+
+const uint8_t* Reader::Entry::getContent() const
+{
+       if ( this->hasLongName() ) 
+               return ((uint8_t*)this) + sizeof(ar_hdr) + this->getLongNameSpace();
+       else
+               return ((uint8_t*)this) + sizeof(ar_hdr);
+}
+
+
+uint32_t Reader::Entry::getContentSize() const
+{
+       char temp[12];
+       strncpy(temp, this->ar_size, 10);
+       temp[10] = '\0';
+       char* endptr;
+       long size = strtol(temp, &endptr, 10);
+       // long name is included in ar_size
+       if ( this->hasLongName() ) 
+               size -= this->getLongNameSpace();
+       return size;
+}
+
+const Reader::Entry*   Reader::Entry::getNext() const
+{
+       const uint8_t* p = this->getContent() + getContentSize();
+       p = (const uint8_t*)(((uint32_t)p+3) & (-4));  // 4-byte align
+       return (Reader::Entry*)p;
+}
+
+
+
+Reader::Reader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options)
+ : fPath(NULL), fOptions(options), fFileContent(NULL), fTableOfContents(NULL), fTableOfContentCount(0),
+   fSorted(false), fStringPool(NULL)
+{
+       fPath = strdup(path);
+       fFileContent = fileContent;
+       fFileLength = fileLength;
+
+       if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
+               throw "not an archive";
+       
+       if ( !options.fFullyLoadArchives ) {
+               const Entry* const firstMember = (Entry*)&fFileContent[8];
+               if ( strcmp(firstMember->getName(), SYMDEF_SORTED) == 0 )
+                       fSorted = true;
+               else if ( strcmp(firstMember->getName(), SYMDEF) == 0 )
+                       fSorted = false;
+               else
+                       throw "archive has no table of contents";
+               const uint8_t* contents = firstMember->getContent();
+               uint32_t ranlibArrayLen = OSReadBigInt32((void *) contents, 0);
+               fTableOfContents = (const struct ranlib*)&contents[4];
+               fTableOfContentCount = ranlibArrayLen / sizeof(struct ranlib);
+               fStringPool = (const char*)&contents[ranlibArrayLen+8];
+       }
+       
+       if ( options.fTraceArchives )
+               printf("[Logging for Build & Integration] Used static archive: %s\n", fPath);
+}
+
+Reader::~Reader()
+{
+}
+
+
+
+ObjectFile::Reader* Reader::makeObjectReaderForMember(const Entry* member)
+{
+       const char* memberName = member->getName();
+       char memberPath[strlen(fPath) + strlen(memberName)+4];
+       strcpy(memberPath, fPath);
+       strcat(memberPath, "(");
+       strcat(memberPath, memberName);
+       strcat(memberPath, ")");
+       //fprintf(stderr, "using %s from %s\n", memberName, fPath);
+       try {
+               return ObjectFileMachO::MakeReader((class macho_header*)member->getContent(), memberPath, fOptions);
+       }
+       catch (const char* msg) {
+               throwf("in %s, %s", memberPath, msg);
+       }
+}
+
+const char* Reader::getPath()
+{
+       return fPath;
+}
+
+std::vector<class ObjectFile::Atom*>&  Reader::getAtoms()
+{
+       if ( fOptions.fFullyLoadArchives ) {
+               // build vector of all atoms from all .o files in this archive
+               const Entry* const start = (Entry*)&fFileContent[8];
+               const Entry* const end = (Entry*)&fFileContent[fFileLength];
+               for (const Entry* p=start; p < end; p = p->getNext()) {
+                       const char* memberName = p->getName();
+                       if ( (p==start) && (strcmp(memberName, SYMDEF_SORTED) == 0) )
+                               continue;
+                       ObjectFile::Reader* r = this->makeObjectReaderForMember(p);
+                       std::vector<class ObjectFile::Atom*>&   atoms = r->getAtoms();
+                       fAllAtoms.insert(fAllAtoms.end(), atoms.begin(), atoms.end());
+               }
+               return fAllAtoms;
+       }
+       else {
+               // return nonthing for now, getJustInTimeAtomsFor() will return atoms as needed
+               return fgEmptyList;
+       }
+}
+
+
+const struct ranlib* Reader::ranlibBinarySearch(const char* key)
+{
+       const struct ranlib* base = fTableOfContents;
+       for (uint32_t n = fTableOfContentCount; n > 0; n /= 2) {
+               const struct ranlib* pivot = &base[n/2];
+               const char* pivotStr = &fStringPool[OSSwapBigToHostInt32(pivot->ran_un.ran_strx)];
+               int cmp = strcmp(key, pivotStr);
+               if ( cmp == 0 )
+                       return pivot;
+               if ( cmp > 0 ) {
+                       // key > pivot 
+                       // move base to symbol after pivot
+                       base = &pivot[1];
+                       --n; 
+               }
+               else {
+                       // key < pivot 
+                       // keep same base
+               }
+       }
+       return NULL;
+}
+
+const struct ranlib* Reader::ranlibLinearSearch(const char* key)
+{
+       for (uint32_t i = 0; i < fTableOfContentCount; ++i) {
+               const struct ranlib* entry = &fTableOfContents[i];
+               const char* entryName = &fStringPool[OSSwapBigToHostInt32(entry->ran_un.ran_strx)];
+               if ( strcmp(key, entryName) == 0 )
+                       return entry;
+       }
+       return NULL;
+}
+
+
+void Reader::dumpTableOfContents()
+{
+       for (unsigned int i=0; i < fTableOfContentCount; ++i) {
+               const struct ranlib* e = &fTableOfContents[i];
+               printf("%s in %s\n", &fStringPool[OSSwapBigToHostInt32(e->ran_un.ran_strx)], ((Entry*)&fFileContent[OSSwapBigToHostInt32(e->ran_off)])->getName());
+       }
+}
+
+std::vector<class ObjectFile::Atom*>* Reader::getJustInTimeAtomsFor(const char* name)
+{
+       if ( fOptions.fFullyLoadArchives ) {
+               return NULL;
+       }
+       else {
+               const struct ranlib* result = NULL;
+               if ( fSorted ) {
+                       // do a binary search of table of contents lookig for requested symbol
+                       result = ranlibBinarySearch(name);
+               }
+               else {
+                       // do a linear search of table of contents lookig for requested symbol
+                       result = ranlibLinearSearch(name);
+               }
+               if ( result != NULL ) {
+                       const Entry* member = (Entry*)&fFileContent[OSSwapBigToHostInt32(result->ran_off)];
+                       //fprintf(stderr, "%s found in %s\n", name, member->getName());
+                       if ( fInstantiatedEntries.count(member) == 0 ) {
+                               // only return these atoms once
+                               fInstantiatedEntries.insert(member);
+                               ObjectFile::Reader* r = makeObjectReaderForMember(member);
+                               return new std::vector<class ObjectFile::Atom*>(r->getAtoms());
+                       }
+               }
+               //fprintf(stderr, "%s NOT found in archive %s\n", name, fPath);
+               return NULL; 
+       }
+}
+
+
+std::vector<ObjectFile::StabsInfo>*    Reader::getStabsDebugInfo()
+{
+       return NULL;
+}
+
+
+
+Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options)
+{
+       return new Reader(fileContent, fileLength, path, options);
+}
+
+
+
+};
+
+
+
+
+
+
+
diff --git a/src/Readers/ObjectFileDylibMachO.cpp b/src/Readers/ObjectFileDylibMachO.cpp
new file mode 100644 (file)
index 0000000..cadbef3
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+
+namespace ObjectFileDylibMachO {
+
+class Reader : public ObjectFile::Reader 
+{
+public:
+                                                                                               Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options);
+       virtual                                                                         ~Reader();
+                                                                                               
+       virtual const char*                                                             getPath();
+       virtual std::vector<class ObjectFile::Atom*>&   getAtoms();
+       virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name);
+       virtual std::vector<ObjectFile::StabsInfo>*             getStabsDebugInfo();
+       virtual const char*                                                             getInstallPath();
+       virtual uint32_t                                                                getTimestamp();
+       virtual uint32_t                                                                getCurrentVersion();
+       virtual uint32_t                                                                getCompatibilityVersion();
+       virtual std::vector<const char*>*                               getDependentLibraryPaths();
+       virtual bool                                                                    reExports(ObjectFile::Reader*);
+       virtual bool                                                                    isDefinitionWeak(const ObjectFile::Atom&);
+       
+private:
+       struct CStringComparor
+       {
+                bool operator()(const char* left, const char* right) { return (strcmp(left, right) > 0); }
+       };
+       typedef std::map<const char*, ObjectFile::Atom*, CStringComparor> Mapper;
+
+
+       void                                                                            init(const macho_header* header,const char* path);
+       const macho_nlist*                                                      binarySearchWithToc(const char* key, const char stringPool[], const macho_nlist symbols[], const struct dylib_table_of_contents toc[], uint32_t symbolCount);
+       const macho_nlist*                                                      binarySearch(const char* key, const char stringPool[], const macho_nlist symbols[], uint32_t symbolCount);
+       bool                                                                            hasExport(const char* name);
+       const macho_nlist*                                                      findExport(const char* name);
+       
+       const char*                                                                     fPath;
+       const macho_header*                                                     fHeader;
+       const char*                                                                     fStrings;
+       const macho_dysymtab_command*                           fDynamicInfo;
+       const macho_dylib_command*                                      fDylibID;
+       const macho_nlist*                                                      fSymbols;
+       uint32_t                                                                        fSymbolCount;
+       Mapper                                                                          fAtoms;
+       std::vector<Reader*>                                            fReExportedDylibs;
+
+       static std::vector<class ObjectFile::Atom*>     fEmptyAtomList;
+};
+
+std::vector<class ObjectFile::Atom*>   Reader::fEmptyAtomList;
+
+
+class Segment : public ObjectFile::Segment
+{
+public:
+                                                               Segment(const char* name)               { fName = name; }
+       virtual const char*                     getName() const                                 { return fName; }
+       virtual bool                            isContentReadable() const               { return true; }
+       virtual bool                            isContentWritable() const               { return false; }
+       virtual bool                            isContentExecutable() const             { return false; }
+private:
+       const char*                                     fName;
+};
+
+
+class ExportAtom : public ObjectFile::Atom
+{
+public:
+       virtual ObjectFile::Reader*                                     getFile() const                         { return &fOwner; }
+       virtual const char*                                                     getName() const                         { return fName; }
+       virtual const char*                                                     getDisplayName() const;
+       virtual Scope                                                           getScope() const                        { return ObjectFile::Atom::scopeGlobal; }
+       virtual bool                                                            isTentativeDefinition() const { return false; }
+       virtual bool                                                            isWeakDefinition() const        { return false; }
+       virtual bool                                                            isCoalesableByName() const      { return false; }
+       virtual bool                                                            isCoalesableByValue() const { return false; }
+       virtual bool                                                            isZeroFill() const                      { return false; }
+       virtual bool                                                            dontDeadStrip() const           { return false; }
+       virtual bool                                                            dontStripName() const           { return false; }
+       virtual bool                                                            isImportProxy() const           { return true; }
+       virtual uint64_t                                                        getSize() const                         { return 0; }
+       virtual std::vector<ObjectFile::Reference*>&  getReferences() const             { return fgEmptyReferenceList; }
+       virtual bool                                                            mustRemainInSection() const { return false; }
+       virtual const char*                                                     getSectionName() const          { return "._imports"; }
+       virtual Segment&                                                        getSegment() const                      { return fgImportSegment; }
+       virtual bool                                                            requiresFollowOnAtom() const{ return false; }
+       virtual ObjectFile::Atom&                                       getFollowOnAtom() const         { return *((ObjectFile::Atom*)NULL); }
+       virtual std::vector<ObjectFile::StabsInfo>*     getStabsDebugInfo() const       { return NULL; }
+       virtual uint8_t                                                         getAlignment() const            { return 0; }
+       virtual WeakImportSetting                                       getImportWeakness() const       { return fWeakImportSetting; }
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const  {}
+       virtual void                                                            writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
+
+       virtual void                                                            setScope(Scope)                         { }
+       virtual void                                                            setImportWeakness(bool weakImport) { fWeakImportSetting = weakImport ? kWeakImport : kNonWeakImport; }
+
+protected:
+       friend class Reader;
+       
+                                                                                       ExportAtom(Reader& owner, const char* name)  : fOwner(owner), fName(name), fWeakImportSetting(kWeakUnset) {}
+       virtual                                                                 ~ExportAtom() {}
+       
+       Reader&                                                                 fOwner;
+       const char*                                                             fName;
+       WeakImportSetting                                               fWeakImportSetting;
+       
+       static std::vector<ObjectFile::Reference*>      fgEmptyReferenceList;
+       static Segment                                                          fgImportSegment;
+};
+
+Segment                                                                ExportAtom::fgImportSegment("__LINKEDIT");
+std::vector<ObjectFile::Reference*>    ExportAtom::fgEmptyReferenceList;
+
+const char* ExportAtom::getDisplayName() const
+{
+       static char temp[300];
+       strcpy(temp, fName);
+       strcat(temp, "$import");
+       return temp;
+}
+
+
+
+Reader::Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options)
+ : fHeader(header), fStrings(NULL), fDylibID(NULL), fSymbols(NULL), fSymbolCount(0)
+{
+       typedef std::pair<const macho_dylib_command*, bool> DylibAndReExportFlag;
+       std::vector<DylibAndReExportFlag>               dependentDylibs;
+
+       fPath = strdup(path);
+       const uint32_t cmd_count = header->ncmds();
+       const macho_load_command* const cmds = (macho_load_command*)((char*)header + macho_header::size);
+       // get all dylib load commands
+       const macho_load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd()) {
+                       case LC_LOAD_DYLIB:
+                       case LC_LOAD_WEAK_DYLIB:
+                               {
+                                       DylibAndReExportFlag info;
+                                       info.first = (struct macho_dylib_command*)cmd;
+                                       info.second = options.fFlatNamespace;
+                                       dependentDylibs.push_back(info);
+                               }
+                               break;
+               }
+               cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
+       }
+       
+       // cache interesting pointers
+       cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd()) {
+                       case LC_SYMTAB:
+                               {
+                                       const macho_symtab_command* symtab = (macho_symtab_command*)cmd;
+                                       fSymbolCount = symtab->nsyms();
+                                       fSymbols = (const macho_nlist*)((char*)header + symtab->symoff());
+                                       fStrings = (char*)header + symtab->stroff();
+                               }
+                               break;
+                       case LC_DYSYMTAB:
+                               fDynamicInfo = (macho_dysymtab_command*)cmd;
+                               break;
+                       case LC_ID_DYLIB:
+                               fDylibID = (macho_dylib_command*)cmd;
+                               break;
+                       case LC_SUB_UMBRELLA:
+                               if ( !options.fFlatNamespace ) {
+                                       const char* frameworkLeafName = ((macho_sub_umbrella_command*)cmd)->name();
+                                       for (std::vector<DylibAndReExportFlag>::iterator it = dependentDylibs.begin(); it != dependentDylibs.end(); it++) {
+                                               const char* dylibName = it->first->name();
+                                               const char* lastSlash = strrchr(dylibName, '/');
+                                               if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
+                                                       it->second = true;
+                                       }
+                               }
+                               break;
+                       case LC_SUB_LIBRARY:
+                               if ( !options.fFlatNamespace ) {
+                                       const char* dylibBaseName = ((macho_sub_library_command*)cmd)->name();
+                                       for (std::vector<DylibAndReExportFlag>::iterator it = dependentDylibs.begin(); it != dependentDylibs.end(); it++) {
+                                               const char* dylibName = it->first->name();
+                                               const char* lastSlash = strrchr(dylibName, '/');
+                                               const char* leafStart = &lastSlash[1];
+                                               if ( lastSlash == NULL )
+                                                       leafStart = dylibName;
+                                               const char* firstDot = strchr(leafStart, '.');
+                                               int len = strlen(leafStart);
+                                               if ( firstDot != NULL )
+                                                       len = firstDot - leafStart;
+                                               if ( strncmp(leafStart, dylibBaseName, len) == 0 )
+                                                       it->second = true;
+                                       }
+                               }
+                               break;
+               }
+               cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
+       }
+       
+       // load dylibs we need to re-export
+       for (std::vector<DylibAndReExportFlag>::iterator it = dependentDylibs.begin(); it != dependentDylibs.end(); it++) {
+               if ( it->second ) {
+                       // printf("%s need to re-export %s\n", path, it->first->name());
+                       //fReExportedDylibs.push_back(
+               }
+       }
+}
+
+
+Reader::~Reader()
+{
+}
+
+const char*     Reader::getPath()
+{
+       return fPath;
+}
+
+
+std::vector<class ObjectFile::Atom*>&  Reader::getAtoms()
+{
+       return fEmptyAtomList;
+}
+
+
+
+const macho_nlist* Reader::binarySearchWithToc(const char* key, const char stringPool[], const macho_nlist symbols[], 
+                                                                                               const struct dylib_table_of_contents toc[], uint32_t symbolCount)
+{
+       int32_t high = symbolCount-1;
+       int32_t mid = symbolCount/2;
+               
+       for (int32_t low = 0; low <= high; mid = (low+high)/2) {
+               const uint32_t index = ENDIAN_READ32(toc[mid].symbol_index);
+               const macho_nlist* pivot = &symbols[index];
+               const char* pivotStr = &stringPool[pivot->n_strx()];
+               int cmp = strcmp(key, pivotStr);
+               if ( cmp == 0 )
+                       return pivot;
+               if ( cmp > 0 ) {
+                       // key > pivot 
+                       low = mid + 1;
+               }
+               else {
+                       // key < pivot 
+                       high = mid - 1;
+               }
+       }
+       return NULL;
+}
+
+
+const macho_nlist* Reader::binarySearch(const char* key, const char stringPool[], const macho_nlist symbols[], uint32_t symbolCount)
+{
+       const macho_nlist* base = symbols;
+       for (uint32_t n = symbolCount; n > 0; n /= 2) {
+               const macho_nlist* pivot = &base[n/2];
+               const char* pivotStr = &stringPool[pivot->n_strx()];
+               int cmp = strcmp(key, pivotStr);
+               if ( cmp == 0 )
+                       return pivot;
+               if ( cmp > 0 ) {
+                       // key > pivot 
+                       // move base to symbol after pivot
+                       base = &pivot[1];
+                       --n; 
+               }
+               else {
+                       // key < pivot 
+                       // keep same base
+               }
+       }
+       return NULL;
+}
+
+const macho_nlist* Reader::findExport(const char* name)
+{
+       if ( fDynamicInfo->tocoff() == 0 )
+               return binarySearch(name, fStrings, &fSymbols[fDynamicInfo->iextdefsym()], fDynamicInfo->nextdefsym());
+       else {
+               return binarySearchWithToc(name, fStrings, fSymbols, (dylib_table_of_contents*)((char*)fHeader + fDynamicInfo->tocoff()), 
+                                                               fDynamicInfo->nextdefsym());
+       }
+}
+
+bool Reader::hasExport(const char* name)
+{
+       return ( findExport(name) != NULL );
+}
+
+std::vector<class ObjectFile::Atom*>* Reader::getJustInTimeAtomsFor(const char* name)
+{
+       std::vector<class ObjectFile::Atom*>* atoms = NULL;
+       // search exports
+       if ( this->hasExport(name) ) {
+               // see if this atom already synthesized
+               ObjectFile::Atom* atom = NULL;
+               Mapper::iterator pos = fAtoms.find(name);
+               if ( pos != fAtoms.end() ) {
+                       atom = pos->second;
+               }
+               else {
+                       atom = new ExportAtom(*this, name);
+                       fAtoms[name] = atom;
+               }
+               // return a vector of one atom
+               atoms = new std::vector<class ObjectFile::Atom*>;
+               atoms->push_back(atom);
+               return atoms;
+       }
+       
+       // check re-exports
+       for (std::vector<Reader*>::iterator it = fReExportedDylibs.begin(); it != fReExportedDylibs.end(); it++) {
+               Reader* reExportedReader = *it;
+               atoms = reExportedReader->getJustInTimeAtomsFor(name);
+               if ( atoms != NULL )
+                       return atoms;
+       }
+       
+       return NULL;
+}
+
+
+std::vector<ObjectFile::StabsInfo>*    Reader::getStabsDebugInfo()
+{
+       return NULL;
+}
+
+const char*    Reader::getInstallPath()
+{
+       return fDylibID->name();
+}
+
+uint32_t Reader::getTimestamp()
+{
+       return fDylibID->timestamp();
+}
+
+uint32_t Reader::getCurrentVersion()
+{
+       return fDylibID->current_version();
+}
+
+uint32_t Reader::getCompatibilityVersion()
+{
+       return fDylibID->compatibility_version();
+}
+
+std::vector<const char*>* Reader::getDependentLibraryPaths()
+{
+       std::vector<const char*>* result = new std::vector<const char*>;
+       const uint32_t cmd_count = fHeader->ncmds();
+       const macho_load_command* const cmds = (macho_load_command*)((char*)fHeader + macho_header::size);
+       const macho_load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd()) {
+                       case LC_LOAD_DYLIB:
+                       case LC_LOAD_WEAK_DYLIB:
+                               {
+                                       result->push_back(((struct macho_dylib_command*)cmd)->name());
+                               }
+                               break;
+               }
+               cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
+       }
+       return result;
+}
+
+bool Reader::reExports(ObjectFile::Reader* child)
+{
+       // A dependent dylib is re-exported under two conditions:
+       //  1) parent contains LC_SUB_UMBRELLA or LC_SUB_LIBRARY with child name
+       {
+               const uint32_t cmd_count = fHeader->ncmds();
+               const macho_load_command* const cmds = (macho_load_command*)((char*)fHeader + macho_header::size);
+               const macho_load_command* cmd = cmds;
+               for (uint32_t i = 0; i < cmd_count; ++i) {
+                       switch (cmd->cmd()) {
+                               case LC_SUB_UMBRELLA:
+                                       {
+                                               const char* frameworkLeafName = ((macho_sub_umbrella_command*)cmd)->name();
+                                               const char* dylibName = child->getPath();
+                                               const char* lastSlash = strrchr(dylibName, '/');
+                                               if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
+                                                       return true;
+                                       }
+                                       break;
+                               case LC_SUB_LIBRARY:
+                                       {
+                                               const char* dylibBaseName = ((macho_sub_library_command*)cmd)->name();
+                                               const char* dylibName = child->getPath();
+                                               const char* lastSlash = strrchr(dylibName, '/');
+                                               const char* leafStart = &lastSlash[1];
+                                               if ( lastSlash == NULL )
+                                                       leafStart = dylibName;
+                                               const char* firstDot = strchr(leafStart, '.');
+                                               int len = strlen(leafStart);
+                                               if ( firstDot != NULL )
+                                                       len = firstDot - leafStart;
+                                               if ( strncmp(leafStart, dylibBaseName, len) == 0 )
+                                                       return true;
+                                       }
+                                       break;
+                       }
+                       cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
+               }
+       }
+       
+       //  2) child contains LC_SUB_FRAMEWORK with parent name 
+       {
+               const uint32_t cmd_count = ((Reader*)child)->fHeader->ncmds();
+               const macho_load_command* const cmds = (macho_load_command*)((char*)(((Reader*)child)->fHeader) + macho_header::size);
+               const macho_load_command* cmd = cmds;
+               for (uint32_t i = 0; i < cmd_count; ++i) {
+                       switch (cmd->cmd()) {
+                               case LC_SUB_FRAMEWORK:
+                                       {
+                                               const char* frameworkLeafName = ((macho_sub_framework_command*)cmd)->name();
+                                               const char* parentName = this->getPath();
+                                               const char* lastSlash = strrchr(parentName, '/');
+                                               if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
+                                                       return true;
+                                       }
+                                       break;
+                       }
+                       cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
+               }
+       }
+       
+       
+       return false;
+}
+
+bool Reader::isDefinitionWeak(const ObjectFile::Atom& atom)
+{
+       const macho_nlist* sym = findExport(atom.getName());
+       if ( sym != NULL ) {
+               if ( (sym->n_desc() & N_WEAK_DEF) != 0 )
+                       return true;
+       }
+       return false;
+}
+
+
+
+Reader* MakeReader(const macho_header* mh, const char* path, const ObjectFile::ReaderOptions& options)
+{
+       return new Reader(mh, path, options);
+}
+
+
+
+};
+
+
+
+
+
+
+
diff --git a/src/Readers/ObjectFileMachO-all.cpp b/src/Readers/ObjectFileMachO-all.cpp
new file mode 100644 (file)
index 0000000..736b2a6
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <sys/mman.h>
+#include <unistd.h> 
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include <ar.h>
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/reloc.h>
+#include <mach-o/ppc/reloc.h>
+#include <mach-o/ranlib.h>
+#include <mach-o/stab.h>
+
+#include "ObjectFile.h"
+#include "Options.h"
+
+
+
+
+// buiild Writer for -arch ppc64
+#undef MACHO_32_SAME_ENDIAN
+#undef MACHO_32_OPPOSITE_ENDIAN
+#undef MACHO_64_SAME_ENDIAN
+#undef MACHO_64_OPPOSITE_ENDIAN
+#if __ppc__ || __ppc64__
+       #define MACHO_64_SAME_ENDIAN
+#elif __i386__
+       #define MACHO_64_OPPOSITE_ENDIAN
+#else
+       #error unknown architecture
+#endif
+namespace ppc64 {
+       #undef  ARCH_PPC
+       #define ARCH_PPC64
+       #undef  ARCH_I386
+       #include "MachOAbstraction.h"
+       #include "ObjectFileMachO.cpp"
+       #include "ObjectFileDylibMachO.cpp"
+       #include "ObjectFileArchiveMachO.cpp"
+};
+
+// buiild Writer for -arch ppc
+#undef MACHO_32_SAME_ENDIAN
+#undef MACHO_32_OPPOSITE_ENDIAN
+#undef MACHO_64_SAME_ENDIAN
+#undef MACHO_64_OPPOSITE_ENDIAN
+#if __ppc__ || __ppc64__
+       #define MACHO_32_SAME_ENDIAN
+#elif __i386__
+       #define MACHO_32_OPPOSITE_ENDIAN
+#else
+       #error unknown architecture
+#endif
+namespace ppc {
+       #define ARCH_PPC
+       #undef  ARCH_PPC64
+       #undef  ARCH_I386
+       #include "MachOAbstraction.h"
+       #include "ObjectFileMachO.cpp"
+       #include "ObjectFileDylibMachO.cpp"
+       #include "ObjectFileArchiveMachO.cpp"
+};
+
+
+// buiild Writer for -arch i386
+#undef MACHO_32_SAME_ENDIAN
+#undef MACHO_32_OPPOSITE_ENDIAN
+#undef MACHO_64_SAME_ENDIAN
+#undef MACHO_64_OPPOSITE_ENDIAN
+#if __ppc__ || __ppc64__
+       #define MACHO_32_OPPOSITE_ENDIAN
+#elif __i386__
+       #define MACHO_32_SAME_ENDIAN
+#else
+       #error unknown architecture
+#endif
+#undef i386 // compiler sometimes #defines this
+namespace i386 {
+       #undef  ARCH_PPC
+       #undef  ARCH_PPC64
+       #define ARCH_I386
+       #include "MachOAbstraction.h"
+       #include "ObjectFileMachO.cpp"
+       #include "ObjectFileDylibMachO.cpp"
+       #include "ObjectFileArchiveMachO.cpp"
+};
+
+
diff --git a/src/Readers/ObjectFileMachO-all.h b/src/Readers/ObjectFileMachO-all.h
new file mode 100644 (file)
index 0000000..0f27244
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __OBJECTFILEMACHO__
+#define __OBJECTFILEMACHO__
+
+class Options;
+
+namespace ppc {
+       class macho_header;
+       namespace ObjectFileMachO {
+               extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
+       };
+       namespace ObjectFileDylibMachO {
+               extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
+       };
+       namespace ObjectFileArchiveMachO {
+               extern class ObjectFile::Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
+       };
+};
+
+namespace ppc64 {
+       class macho_header;
+       namespace ObjectFileMachO {
+               extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
+       };
+       namespace ObjectFileDylibMachO {
+               extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
+       };
+       namespace ObjectFileArchiveMachO {
+               extern class ObjectFile::Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
+       };
+};
+
+#undef i386 // compiler sometimes #defines this
+namespace i386 {
+       class macho_header;
+       namespace ObjectFileMachO {
+               extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
+       };
+       namespace ObjectFileDylibMachO {
+               extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
+       };
+       namespace ObjectFileArchiveMachO {
+               extern class ObjectFile::Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
+       };
+};
+
+
+
+#endif // __OBJECTFILEMACHO__
+
+
+
diff --git a/src/Readers/ObjectFileMachO.cpp b/src/Readers/ObjectFileMachO.cpp
new file mode 100644 (file)
index 0000000..5736d00
--- /dev/null
@@ -0,0 +1,2273 @@
+/*
+ * 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@
+ */
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- */
+
+
+namespace ObjectFileMachO {
+
+class Reference : public ObjectFile::Reference
+{
+public:
+                                                       Reference(macho_uintptr_t fixUpOffset, Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
+                                                       Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
+                                                       Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, class Atom& fromTarget, uint64_t offsetInFromTarget);
+       virtual                                 ~Reference();
+       
+       
+       virtual bool                    isUnbound() const;
+       virtual bool                    isWeakReference() const;
+       virtual bool                    requiresRuntimeFixUp() const;
+       virtual bool                    isLazyReference() const;
+       virtual Kind                    getKind() const;
+       virtual uint64_t                getFixUpOffset() const;
+       virtual const char*             getTargetName() const;
+       virtual ObjectFile::Atom& getTarget() const;
+       virtual uint64_t                getTargetOffset() const;
+       virtual ObjectFile::Atom& getFromTarget() const;
+       virtual const char*             getFromTargetName() const;
+       virtual void                    setTarget(ObjectFile::Atom&);
+       virtual void                    setFromTarget(ObjectFile::Atom&);
+       virtual void                    setFromTargetName(const char*);
+       virtual const char*             getDescription() const;
+       virtual uint64_t                getFromTargetOffset() const;
+       
+       void                                    setLazy(bool);
+       void                                    setWeak(bool);
+private:
+       ObjectFile::Atom*               fTarget;
+       ObjectFile::Atom*               fFromTarget;
+       const char*                             fTargetName;
+       const char*                             fFromTargetName;
+       macho_uintptr_t                 fTargetOffset;
+       macho_uintptr_t                 fFromTargetOffset;
+       macho_uintptr_t                 fFixUpOffsetInSrc;
+       Kind                                    fKind;
+       bool                                    fLazy;
+       bool                                    fWeak;
+};
+
+
+
+class Reader : public ObjectFile::Reader 
+{
+public:
+                                                                                               Reader(const char* path);
+                                                                                               Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options);
+       virtual                                                                         ~Reader();
+                                                                                               
+       virtual const char*                                                             getPath();
+       virtual std::vector<class ObjectFile::Atom*>&   getAtoms();
+       virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name);
+       virtual std::vector<ObjectFile::StabsInfo>*             getStabsDebugInfo(); // stabs info not associated with an atom
+
+
+private:
+       friend class Atom;
+       void                                                                            init(const macho_header* header, const char* path);
+       void                                                                            buildOffsetsSet(const macho_relocation_info* reloc, const macho_section* sect, std::set<uint32_t>& offsets, std::set<uint32_t>& dontUse);
+       void                                                                            addRelocReference(const macho_section* sect, const macho_relocation_info* reloc);
+       Atom*                                                                           findAtomCoveringOffset(uint32_t offset);
+       uint32_t                                                                        findAtomIndex(const Atom& atom);
+       void                                                                            addFixUp(uint32_t srcAddr, uint32_t dstAddr, Reference::Kind kind, uint32_t picBaseAddr);
+       class Segment*                                                          makeSegmentFromSection(const macho_section*);
+       macho_uintptr_t                                                         commonsOffset();
+       void                                                                            insertOffsetIfText(std::set<uint32_t>& offsets, uint32_t value);
+       void                                                                            insertOffsetIfNotText(std::set<uint32_t>& offsets, uint32_t value);
+       const macho_section*                                            findSectionCoveringOffset(uint32_t offset);
+       void                                                                            addCallSiteReference(Atom& src, uint32_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint32_t picBaseOffset, uint32_t offsetInTargetAtom);
+       void                                                                            deadStub(Atom& target);
+       
+       const char*                                                                     fPath;
+       const ObjectFile::ReaderOptions&                        fOptions;
+       const macho_header*                                                     fHeader;
+       const char*                                                                     fStrings;
+       const macho_nlist*                                                      fSymbols;
+       uint32_t                                                                        fSymbolCount;
+       const macho_segment_command*                            fSegment;
+       const uint32_t*                                                         fIndirectTable;
+       std::vector<class Atom*>                                        fAtoms;
+       std::vector<class Segment*>                                     fSegments;
+       std::set<class ObjectFile::Atom*>                       fDeadAtoms;
+       uint32_t                                                                        fNonAtomStabsStartIndex;
+       uint32_t                                                                        fNonAtomStabsCount;
+       std::vector<uint32_t>                                           fNonAtomExtras;
+};
+
+class Segment : public ObjectFile::Segment
+{
+public:
+       virtual const char*                     getName() const;
+       virtual bool                            isContentReadable() const;
+       virtual bool                            isContentWritable() const;
+       virtual bool                            isContentExecutable() const;
+protected:
+               Segment(const macho_section*);
+               friend class Reader;
+private:
+       const macho_section*            fSection;
+};
+
+class Atom : public ObjectFile::Atom
+{
+public:
+       virtual ObjectFile::Reader*                             getFile() const;
+       virtual const char*                                             getName() const;
+       virtual const char*                                             getDisplayName() const;
+       virtual Scope                                                   getScope() const;
+       virtual bool                                                    isTentativeDefinition() const;
+       virtual bool                                                    isWeakDefinition() const;
+       virtual bool                                                    isCoalesableByName() const;
+       virtual bool                                                    isCoalesableByValue() const;
+       virtual bool                                                    isZeroFill() const;
+       virtual bool                                                    dontDeadStrip() const;
+       virtual bool                                                    dontStripName() const;  // referenced dynamically
+       virtual bool                                                    isImportProxy() const;
+       virtual uint64_t                                                        getSize() const;
+       virtual std::vector<ObjectFile::Reference*>&  getReferences() const;
+       virtual bool                                                            mustRemainInSection() const;
+       virtual const char*                                                     getSectionName() const;
+       virtual Segment&                                                        getSegment() const;
+       virtual bool                                                            requiresFollowOnAtom() const;
+       virtual ObjectFile::Atom&                                       getFollowOnAtom() const;
+       virtual std::vector<ObjectFile::StabsInfo>*     getStabsDebugInfo() const;
+       virtual uint8_t                                                         getAlignment() const;
+       virtual WeakImportSetting                                       getImportWeakness() const { return ObjectFile::Atom::kWeakUnset; }
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const;
+       virtual void                                                            writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+       virtual void                                                            setScope(Scope);
+       virtual void                                                            setImportWeakness(bool weakImport) { }
+
+       bool                                                                            isLazyStub();
+
+protected:
+       friend class Reader;
+                                                                                       Atom(Reader&, const macho_nlist*);
+                                                                                       Atom(Reader&, uint32_t offset);
+       virtual                                                                 ~Atom();
+       
+       const macho_section*                                    findSectionFromOffset(macho_uintptr_t offset);
+       const macho_section*                                    getCommonsSection();
+       void                                                                    setSize(macho_uintptr_t);
+       void                                                                    setFollowOnAtom(Atom&);
+       static bool                                                             atomCompare(const Atom* lhs, const Atom* rhs);
+       Reference*                                                              addDirectReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
+       Reference*                                                              addByNameReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
+       Reference*                                                              addDifferenceReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, Atom& fromTarget, uint64_t offsetInFromTarget);
+       Reference*                                                              addReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
+       
+       Reader&                                                                 fOwner;
+       const macho_nlist*                                              fSymbol;
+       macho_uintptr_t                                                 fOffset;
+       macho_uintptr_t                                                 fSize;
+       const macho_section*                                    fSection;
+       Segment*                                                                fSegment;
+       const char*                                                             fSynthesizedName;
+       std::vector<class Reference*>                   fReferences;
+       ObjectFile::Atom::Scope                                 fScope;
+       uint32_t                                                                fStabsStartIndex;
+       uint32_t                                                                fStabsCount;
+       
+       static macho_section                                    fgCommonsSection;       // for us by tentative definitions
+};
+
+
+Reader* MakeReader(const macho_header* mh, const char* path, const ObjectFile::ReaderOptions& options)
+{      
+       return new Reader(mh, path, options);
+}
+
+
+Reader::Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options)
+ : fPath(NULL), fOptions(options), fHeader(NULL), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL)
+{
+       init(header, path);
+}
+
+Reader::Reader(const char* path)
+ : fPath(NULL), fOptions(*(new ObjectFile::ReaderOptions())), fHeader(NULL), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL),
+       fNonAtomStabsStartIndex(0), fNonAtomStabsCount(0)
+{
+       struct stat stat_buf;
+       
+       int fd = ::open(path, O_RDONLY, 0);
+       ::fstat(fd, &stat_buf);
+       void* p = ::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE, fd, 0);
+       ::close(fd);
+       if ( ((macho_header*)p)->magic() == MH_MAGIC ) {
+               init((macho_header*)p, path);
+               return;
+       }
+       throw "add fat handling";
+}
+
+
+Reader::~Reader()
+{
+}
+
+
+bool Atom::atomCompare(const Atom* lhs, const Atom* rhs)
+{
+       return lhs->fOffset < rhs->fOffset;
+}
+
+
+
+void Reader::init(const macho_header* header, const char* path)
+{
+       // sanity check
+#if defined(ARCH_PPC)
+       if ( (header->magic() != MH_MAGIC) || (header->cputype() != CPU_TYPE_POWERPC) )
+               throw "not a valid ppc mach-o file";
+#elif defined(ARCH_I386)
+       if ( (header->magic() != MH_MAGIC) || (header->cputype() != CPU_TYPE_I386) )
+               throw "not a valid i386 mach-o file";
+#elif defined(ARCH_PPC64)
+       if ( (header->magic() != MH_MAGIC_64) || (header->cputype() != CPU_TYPE_POWERPC64) )
+               throw "not a valid ppc64 mach-o file";
+#endif
+
+       // cache intersting pointers
+       fPath = strdup(path);
+       fHeader = header;
+       const uint32_t cmd_count = header->ncmds();
+       const macho_load_command* const cmds = (macho_load_command*)((char*)header + macho_header::size);
+       const macho_load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd()) {
+                       case LC_SYMTAB:
+                               {
+                                       const macho_symtab_command* symtab = (macho_symtab_command*)cmd;
+                                       fSymbolCount = symtab->nsyms();
+                                       fSymbols = (const macho_nlist*)((char*)header + symtab->symoff());
+                                       fStrings = (char*)header + symtab->stroff();
+                               }
+                               break;
+                       case LC_DYSYMTAB:
+                               {
+                                       const macho_dysymtab_command* dsymtab = (struct macho_dysymtab_command*)cmd;
+                                       fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
+                               }
+                               break;
+                       default:
+                               if ( cmd->cmd() == macho_segment_command::command ) {
+                                       fSegment= (macho_segment_command*)cmd;
+                               }
+                               break;
+               }
+               cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
+       }
+       
+       // add all atoms that have entries in symbol table
+       std::set<uint32_t> symbolAtomOffsets;
+       for (uint32_t i=0; i < fSymbolCount; ++i) {
+               const macho_nlist& sym = fSymbols[i];
+               if ( (sym.n_type() & N_STAB) == 0 ) {
+                       uint8_t type =  (sym.n_type() & N_TYPE);
+                       if ( (type == N_SECT) || ((type == N_UNDF) && (sym.n_value() != 0)) ) {
+                               // real definition or "tentative definition"
+                               Atom* newAtom = new Atom(*this, &sym);
+                               fAtoms.push_back(newAtom);
+                               symbolAtomOffsets.insert(newAtom->fOffset);
+                       }
+               }
+       }
+       
+       // add all points referenced in relocations
+       const macho_section* const sectionsStart = (macho_section*)((char*)fSegment + sizeof(macho_segment_command));
+       const macho_section* const sectionsEnd = &sectionsStart[fSegment->nsects()];
+       std::set<uint32_t> cleavePoints;
+       std::set<uint32_t> dontCleavePoints;
+       for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+               const macho_relocation_info* relocs = (macho_relocation_info*)((char*)(fHeader) + sect->reloff());
+               const uint32_t relocCount = sect->nreloc();
+               for (uint32_t r = 0; r < relocCount; ++r) {
+                       buildOffsetsSet(&relocs[r], sect, cleavePoints, dontCleavePoints);
+               }
+       }
+       // add all stub functions and (non)lazy pointers
+       std::set<uint32_t> deadStubOffsets;
+       for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+               uint8_t type (sect->flags() & SECTION_TYPE);
+               switch ( type ) {
+                       case S_SYMBOL_STUBS:
+                               {
+                                       const uint32_t stubSize = sect->reserved2();
+                                       // TVector glue sections are marked as S_SYMBOL_STUBS but are only 8 bytes
+                                       if ( stubSize > 8 ) {
+                                               for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += stubSize) {
+                                                       uint32_t stubAddr = sect->addr() + sectOffset;
+                                                       if ( cleavePoints.count(stubAddr) == 0 ) {
+                                                               cleavePoints.insert(stubAddr);
+                                                               deadStubOffsets.insert(stubAddr);
+                                                       }
+                                               }
+                                       }
+                               }
+                               break;
+                       case S_NON_LAZY_SYMBOL_POINTERS:
+                       case S_LAZY_SYMBOL_POINTERS:
+                               for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += sizeof(macho_uintptr_t)) {
+                                       uint32_t pointerAddr = sect->addr() + sectOffset;
+                                       cleavePoints.insert(pointerAddr);
+                               }
+                               break;
+               }
+               // also make sure each section break is a cleave point
+               if ( sect->size() != 0 ) 
+                       cleavePoints.insert(sect->addr());
+       }
+       
+       for (std::set<uint32_t>::iterator it=cleavePoints.begin(); it != cleavePoints.end(); it++) {
+               uint32_t cleavePoint = *it;
+               //printf("cleave offset 0x%08X\n", cleavePoint);
+               // only create an atom if it is not a don't-cleave point and there is not already an atom at this offset
+               if ( (dontCleavePoints.count(cleavePoint) == 0) && (symbolAtomOffsets.count(cleavePoint) == 0) )
+                       fAtoms.push_back(new Atom(*this, cleavePoint));
+       }
+       
+       const uint32_t atomCount = fAtoms.size();
+       if ( atomCount > 0 ) {
+               // sort the atoms so the occur in source file order
+               std::sort(fAtoms.begin(), fAtoms.end(), Atom::atomCompare);
+               
+               // tell each atom its size and follow on
+               const bool dontDeadStrip = ((fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0);
+               Atom* lastAtom = fAtoms[0];
+               for (uint32_t i=1; i < atomCount; ++i) {
+                       Atom* thisAtom = fAtoms[i];
+                       if ( lastAtom->getSize() == 0 ) {
+                               if ( lastAtom->fSection == thisAtom->fSection )
+                                       lastAtom->setSize(thisAtom->fOffset - lastAtom->fOffset);
+                               else
+                                       lastAtom->setSize(lastAtom->fSection->addr() + lastAtom->fSection->size() - lastAtom->fOffset);
+                       }
+                       if ( dontDeadStrip )
+                               lastAtom->setFollowOnAtom(*thisAtom);
+                       lastAtom = thisAtom;
+               }
+               lastAtom = fAtoms[atomCount-1];
+               if ( lastAtom->getSize() == 0 )
+                       lastAtom->setSize(lastAtom->fSection->addr() + lastAtom->fSection->size() - lastAtom->fOffset);
+               
+               // add relocation based references
+               for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                       const macho_relocation_info* relocs = (macho_relocation_info*)((char*)(fHeader) + sect->reloff());
+                       const uint32_t relocCount = sect->nreloc();
+                       for (uint32_t r = 0; r < relocCount; ++r) {
+                               addRelocReference(sect, &relocs[r]);
+                       }
+               }               
+               
+               // add dead stubs to list to delete
+               for (std::set<uint32_t>::iterator it=deadStubOffsets.begin(); it != deadStubOffsets.end(); it++) {
+                       Atom* deadStub = findAtomCoveringOffset(*it);
+                       this->deadStub(*deadStub);
+               }
+               
+               // remove dead stubs and lazy pointers
+               for (std::set<ObjectFile::Atom*>::iterator deadIt=fDeadAtoms.begin(); deadIt != fDeadAtoms.end(); deadIt++) {
+                       for (std::vector<Atom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
+                               if ( *deadIt == *it ) {
+                                       fAtoms.erase(it);
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       // process stabs debugging info
+       if ( ! fOptions.fStripDebugInfo ) {
+               // scan symbol table for stabs entries
+               fNonAtomStabsStartIndex = 0xFFFFFFFF;
+               fNonAtomStabsCount = 0;
+               uint32_t possibleStart = 0;
+               Atom* atom = NULL;
+               const uint32_t atomCount = fAtoms.size();
+               enum { start, inBeginEnd, foundFirst, inFunction } state = start;
+               for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) {
+                       const macho_nlist* sym = &fSymbols[symbolIndex];
+                       uint8_t type = sym->n_type();
+                       if ( (type & N_STAB) != 0 ) {
+                               if ( fNonAtomStabsStartIndex == 0xFFFFFFFF )
+                                       fNonAtomStabsStartIndex = symbolIndex;
+                               switch (state) {
+                                       case start:
+                                               if ( (type == N_SLINE) || (type == N_SOL) ) {
+                                                       possibleStart = symbolIndex;
+                                                       state = foundFirst;
+                                               } 
+                                               else if ( type == N_BNSYM ) {
+                                                       macho_uintptr_t targetAddr = sym->n_value();
+                                                       atom = this->findAtomCoveringOffset(targetAddr);
+                                                       if ( (atom != NULL) || (atom->fOffset == targetAddr) ) {
+                                                               atom->fStabsStartIndex = symbolIndex;
+                                                               if ( fNonAtomStabsCount == 0 )
+                                                                       fNonAtomStabsCount = symbolIndex - fNonAtomStabsStartIndex;
+                                                       } 
+                                                       else {
+                                                               fprintf(stderr, "can't find atom for stabs 0x%02X at %08X in %s\n", type, targetAddr, path);
+                                                               atom = NULL;
+                                                       }
+                                                       state = inBeginEnd;
+                                               } 
+                                               else if ( (type == N_STSYM) || (type == N_LCSYM) ) {
+                                                       macho_uintptr_t targetAddr = sym->n_value();
+                                                       atom = this->findAtomCoveringOffset(targetAddr);
+                                                       if ( (atom != NULL) || (atom->fOffset == targetAddr) ) {
+                                                               atom->fStabsStartIndex = symbolIndex;
+                                                               atom->fStabsCount = 1;
+                                                               if ( fNonAtomStabsCount == 0 )
+                                                                       fNonAtomStabsCount = symbolIndex - fNonAtomStabsStartIndex;
+                                                       } 
+                                                       else {
+                                                               fprintf(stderr, "can't find atom for stabs 0x%02X at %08X in %s\n", type, targetAddr, path);
+                                                               atom = NULL;
+                                                       }
+                                               }
+                                               else if ( type == N_GSYM ) {
+                                                       // n_value field is NOT atom address ;-(
+                                                       // need to find atom by name match
+                                                       const char* symString = &fStrings[sym->n_strx()];
+                                                       const char* colon = strchr(symString, ':');
+                                                       bool found = false;
+                                                       if ( colon != NULL ) {
+                                                               int nameLen = colon - symString;
+                                                               for (uint32_t searchIndex = 0; searchIndex < atomCount; ++searchIndex) {
+                                                                       const char* atomName = fAtoms[searchIndex]->getName();
+                                                                       if ( (atomName != NULL) && (strncmp(&atomName[1], symString, nameLen) == 0) ) {
+                                                                               atom = fAtoms[searchIndex];
+                                                                               atom->fStabsStartIndex = symbolIndex;
+                                                                               atom->fStabsCount = 1;
+                                                                               if ( fNonAtomStabsCount == 0 )
+                                                                                       fNonAtomStabsCount = symbolIndex - fNonAtomStabsStartIndex;
+                                                                               found = true;
+                                                                               break;
+                                                                       }
+                                                               }
+                                                       }
+                                                       if ( !found ) {
+                                                               fprintf(stderr, "can't find atom for N_GSYM stabs %s in %s\n", symString, path);
+                                                               atom = NULL;
+                                                       }
+                                               }
+                                               else if ( type == N_LSYM ) {
+                                                       if ( fNonAtomStabsCount != 0 ) {
+                                                               // built with -gfull and some type definition not at start of source
+                                                               fNonAtomExtras.push_back(symbolIndex);
+                                                       }
+                                               }
+                                               break;
+                                       case inBeginEnd:
+                                               if ( type == N_ENSYM ) {
+                                                       state = start;
+                                                       if ( atom != NULL ) 
+                                                               atom->fStabsCount = symbolIndex - atom->fStabsStartIndex + 1;
+                                               }
+                                               break;
+                                       case foundFirst:
+                                               if ( (type == N_FUN) && (sym->n_sect() != 0) ) {
+                                                       state = inFunction;
+                                                       macho_uintptr_t targetAddr = sym->n_value();
+                                                       atom = this->findAtomCoveringOffset(targetAddr);
+                                                       if ( (atom == NULL) || (atom->fOffset != targetAddr) ) {
+                                                               fprintf(stderr, "can't find atom for stabs FUN index: %d at 0x%08llX in %s\n", symbolIndex, (uint64_t)targetAddr, path);
+                                                               atom = NULL;
+                                                       }
+                                                       else {
+                                                               atom->fStabsStartIndex = possibleStart;
+                                                               if ( fNonAtomStabsCount == 0 )
+                                                                       fNonAtomStabsCount = possibleStart - fNonAtomStabsStartIndex;
+                                                       } 
+                                               }
+                                               else if ( (type == N_FUN) && (sym->n_sect() == 0) ) {
+                                                       fprintf(stderr, "end stab FUN found without start FUN, index=%d in %s\n", symbolIndex, path);
+                                                       state = start;
+                                               }
+                                               break;
+                                       case inFunction:
+                                               if ( (type == N_FUN) && (sym->n_sect() == 0) ) {
+                                                       state = start;
+                                                       if ( atom != NULL ) 
+                                                               atom->fStabsCount = symbolIndex - atom->fStabsStartIndex + 1;
+                                               }
+                                               break;
+                               }
+                       }
+               }
+       
+       }
+}
+
+
+void Reader::addRelocReference(const macho_section* sect, const macho_relocation_info* reloc)
+{      
+       uint32_t srcAddr;
+       uint32_t dstAddr;
+       Atom* src;
+       Atom* dst;
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+       uint32_t instruction;
+#endif
+       uint32_t* fixUpPtr;
+       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+               fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+               const macho_relocation_info* nextReloc = &reloc[1];
+#endif
+               switch ( reloc->r_type() ) {
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+                       case PPC_RELOC_BR24:
+                               {
+                                       if ( reloc->r_extern() ) {
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               int32_t displacement = (instruction & 0x03FFFFFC);
+                                               if ( (displacement & 0x02000000) != 0 )
+                                                       displacement |= 0xFC000000;
+                                               uint32_t offsetInTarget = sect->addr() + reloc->r_address() + displacement;
+                                               srcAddr = sect->addr() + reloc->r_address();
+                                               src = findAtomCoveringOffset(srcAddr);  
+                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
+                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
+                                               src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupBranch24, targetName, offsetInTarget, 0);
+                                       }
+                                       else {
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               if ( (instruction & 0x4C000000) == 0x48000000 ) {
+                                                       int32_t displacement = (instruction & 0x03FFFFFC);
+                                                       if ( (displacement & 0x02000000) != 0 )
+                                                               displacement |= 0xFC000000;
+                                                       srcAddr = sect->addr() + reloc->r_address();
+                                                       dstAddr = srcAddr + displacement;
+                                                       src = findAtomCoveringOffset(srcAddr);
+                                                       dst = findAtomCoveringOffset(dstAddr);  
+                                                       this->addCallSiteReference(*src, srcAddr - src->fOffset, Reference::ppcFixupBranch24, *dst, 0, dstAddr - dst->fOffset);
+                                               }
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_BR14:
+                               {
+                                       if ( reloc->r_extern() ) {
+                                               srcAddr = sect->addr() + reloc->r_address();
+                                               src = findAtomCoveringOffset(srcAddr);  
+                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
+                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
+                                               src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupBranch14, targetName, 0, 0);
+                                       }
+                                       else {
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               int32_t displacement = (instruction & 0x0000FFFC);
+                                               if ( (displacement & 0x00008000) != 0 )
+                                                       displacement |= 0xFFFF0000;
+                                               srcAddr = sect->addr() + reloc->r_address();
+                                               dstAddr = srcAddr + displacement;
+                                               src = findAtomCoveringOffset(srcAddr);
+                                               dst = findAtomCoveringOffset(dstAddr);  
+                                               this->addCallSiteReference(*src, srcAddr - src->fOffset, Reference::ppcFixupBranch14, *dst, 0, dstAddr - dst->fOffset);
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_PAIR:
+                               // skip, processed by a previous look ahead 
+                               break;
+                       case PPC_RELOC_LO16:
+                               {
+                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+                                               printf("PPC_RELOC_LO16 missing following pair\n");
+                                               break;
+                                       }
+                                       srcAddr = sect->addr() + reloc->r_address();
+                                       if ( reloc->r_extern() ) {
+                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
+                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
+                                               src = findAtomCoveringOffset(srcAddr);  
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFF);
+                                               src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow16, targetName, dstAddr, 0);
+                                       }
+                                       else {
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               int16_t lowBits = (instruction & 0xFFFF);
+                                               dstAddr = (nextReloc->r_address() << 16) + (int32_t)lowBits;
+                                               if ( (lowBits & 0x8000) != 0 )
+                                                       dstAddr += 0x10000;
+                                               addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsLow16, 0);
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_LO14:
+                               {
+                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+                                               printf("PPC_RELOC_LO14 missing following pair\n");
+                                               break;
+                                       }
+                                       srcAddr = sect->addr() + reloc->r_address();
+                                       if ( reloc->r_extern() ) {
+                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
+                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
+                                               src = findAtomCoveringOffset(srcAddr);  
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC);
+                                               src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow14, targetName, dstAddr, 0);
+                                       }
+                                       else {
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC);
+                                               addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsLow14, 0);
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_HI16:
+                               {
+                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+                                               printf("PPC_RELOC_HI16 missing following pair\n");
+                                               break;
+                                       }
+                                       srcAddr = sect->addr() + reloc->r_address();
+                                       if ( reloc->r_extern() ) {
+                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
+                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
+                                               src = findAtomCoveringOffset(srcAddr);  
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
+                                               src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsHigh16, targetName, dstAddr, 0);
+                                       }
+                                       else {
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
+                                               addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsHigh16, 0);
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_HA16:
+                               {
+                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+                                               printf("PPC_RELOC_HA16 missing following pair\n");
+                                               break;
+                                       }
+                                       srcAddr = sect->addr() + reloc->r_address();
+                                       if ( reloc->r_extern() ) {
+                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
+                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF);
+                                               dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
+                                               src = findAtomCoveringOffset(srcAddr);  
+                                               src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsHigh16AddLow, targetName, dstAddr, 0);
+                                       }
+                                       else {
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF);
+                                               dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
+                                               addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsHigh16AddLow, 0);
+                                       }
+                               }
+                               break;
+                       case GENERIC_RELOC_VANILLA:
+                               {
+                                       srcAddr = sect->addr() + reloc->r_address();
+                                       Atom* srcAtom = findAtomCoveringOffset(srcAddr);
+                                       // lazy pointers have references to dyld_stub_binding_helper which need to be ignored
+                                       if ( (srcAtom->fSection->flags() & SECTION_TYPE) != S_LAZY_SYMBOL_POINTERS ) {
+                                               uint32_t offsetInSrcAtom = srcAddr - srcAtom->fOffset;
+                                               macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
+                                               if ( reloc->r_extern() ) {
+                                                       const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
+                                                       uint8_t type = targetSymbol->n_type() & N_TYPE;
+                                                       if ( type == N_UNDF ) {
+                                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
+                                                               macho_uintptr_t addend = pointerValue;
+                                                               srcAtom->addByNameReference(offsetInSrcAtom, Reference::pointer, targetName, addend, 0);
+                                                       }
+                                                       else {
+                                                               dstAddr = targetSymbol->n_value();
+                                                               Atom* dstAtom = findAtomCoveringOffset(dstAddr);
+                                                               macho_uintptr_t addend = pointerValue;
+                                                               srcAtom->addReference(offsetInSrcAtom, Reference::pointer, *dstAtom, addend, 0);
+                                                       }
+                                               }
+                                               else {
+                                                       Atom* dstAtom = findAtomCoveringOffset(pointerValue);   
+                                                       srcAtom->addReference(offsetInSrcAtom, Reference::pointer, *dstAtom, pointerValue-dstAtom->fOffset, 0);
+                                               }
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_JBSR:
+                               // ignore for now
+                               break;
+#endif
+#if defined(ARCH_I386)
+                       case GENERIC_RELOC_VANILLA:
+                               {
+                                       srcAddr = sect->addr() + reloc->r_address();
+                                       src = findAtomCoveringOffset(srcAddr);
+                                       // lazy pointers have references to dyld_stub_binding_helper which need to be ignored
+                                       if ( (src->fSection->flags() & SECTION_TYPE) != S_LAZY_SYMBOL_POINTERS ) {
+                                               if ( reloc->r_length() != 2 )
+                                                       throw "bad vanilla relocation length";
+                                               Reference::Kind kind;
+                                               macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
+                                               if ( reloc->r_pcrel() ) {
+                                                       kind = Reference::x86FixupBranch32;
+                                                       pointerValue += reloc->r_address() + sizeof(macho_uintptr_t);
+                                               }
+                                               else {
+                                                       kind = Reference::pointer;
+                                               }
+                                               uint32_t offsetInSrcAtom = srcAddr - src->fOffset;
+                                               if ( reloc->r_extern() ) {
+                                                       const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
+                                                       uint8_t type = targetSymbol->n_type() & N_TYPE;
+                                                       if ( type == N_UNDF ) {
+                                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
+                                                               macho_uintptr_t addend = pointerValue;
+                                                               src->addByNameReference(offsetInSrcAtom, kind, targetName, addend, 0);
+                                                       }
+                                                       else {
+                                                               dstAddr = targetSymbol->n_value();
+                                                               dst = findAtomCoveringOffset(dstAddr);
+                                                               macho_uintptr_t addend = pointerValue - dstAddr;
+                                                               src->addReference(offsetInSrcAtom, kind, *dst, addend, 0);
+                                                       }
+                                               }
+                                               else {
+                                                       dst = findAtomCoveringOffset(pointerValue);     
+                                                       src->addReference(offsetInSrcAtom, kind, *dst, 0, 0);
+                                               }
+                                       }
+                               }
+                               break;
+#endif
+
+                       default:
+                               printf("unknown relocation type %d\n", reloc->r_type());
+               }
+       }
+       else {
+               const macho_scattered_relocation_info* sreloc = (macho_scattered_relocation_info*)reloc;
+               srcAddr = sect->addr() + sreloc->r_address();
+               dstAddr = sreloc->r_value();
+               fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
+               const macho_scattered_relocation_info* nextSReloc = &sreloc[1];
+               const macho_relocation_info* nextReloc = &reloc[1];
+               // file format allows pair to be scattered or not
+               bool nextRelocIsPair = false;
+               uint32_t nextRelocAddress = 0;
+               uint32_t nextRelocValue = 0;
+               if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
+                       if ( nextReloc->r_type() == PPC_RELOC_PAIR ) {
+                               nextRelocIsPair = true;
+                               nextRelocAddress = nextReloc->r_address();
+                       }
+               }
+               else {
+                       if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
+                               nextRelocIsPair = true;
+                               nextRelocAddress = nextSReloc->r_address();
+                               nextRelocValue = nextSReloc->r_value();
+                       }
+               }
+               switch (sreloc->r_type()) {
+                       case GENERIC_RELOC_VANILLA:
+                               {
+                                       macho_uintptr_t betterDstAddr = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
+                                       //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr);
+                                       // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
+                                       Atom* src = findAtomCoveringOffset(srcAddr);
+                                       Atom* dst = findAtomCoveringOffset(dstAddr);
+                                       src->addReference(srcAddr - src->fOffset, Reference::pointer, *dst, betterDstAddr - dst->fOffset, 0);
+                               }
+                               break;
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+                       case PPC_RELOC_BR24:
+                               {
+                                       instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                       if ( (instruction & 0x4C000000) == 0x48000000 ) {
+                                               int32_t displacement = (instruction & 0x03FFFFFC);
+                                               if ( (displacement & 0x02000000) != 0 )
+                                                       displacement |= 0xFC000000;
+                                               srcAddr = sect->addr() + sreloc->r_address();
+                                               dstAddr = sreloc->r_value();
+                                               src = findAtomCoveringOffset(srcAddr);
+                                               dst = findAtomCoveringOffset(dstAddr);  
+                                               this->addCallSiteReference(*src, srcAddr - src->fOffset, Reference::ppcFixupBranch24, *dst, 0, srcAddr + displacement - sreloc->r_value());
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_LO16_SECTDIFF:
+                               {
+                                       if ( ! nextRelocIsPair) {
+                                               printf("PPC_RELOC_LO16_SECTDIFF missing following PAIR\n");
+                                               break;
+                                       }
+                                       src = findAtomCoveringOffset(srcAddr);  
+                                       dst = findAtomCoveringOffset(dstAddr);  
+                                       instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                       int16_t lowBits = (instruction & 0xFFFF);
+                                       int32_t displacement = (nextRelocAddress << 16) + (int32_t)lowBits;
+                                       if ( (lowBits & 0x8000) != 0 )
+                                               displacement += 0x10000;
+                                       uint32_t picBaseOffset = nextRelocValue - src->fOffset;
+                                       int64_t dstOffset = src->fOffset + picBaseOffset + displacement - dst->fOffset;
+                                       src->addReference(srcAddr - src->fOffset, Reference::ppcFixupPicBaseLow16, *dst, dstOffset, picBaseOffset);
+                               }
+                               break;
+                       case PPC_RELOC_LO14_SECTDIFF:
+                               {
+                                       if ( ! nextRelocIsPair) {
+                                               printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
+                                               break;
+                                       }
+                                       src = findAtomCoveringOffset(srcAddr);  
+                                       dst = findAtomCoveringOffset(dstAddr);  
+                                       instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                       int16_t lowBits = (instruction & 0xFFFC);
+                                       int32_t displacement = (nextRelocAddress << 16) + (int32_t)lowBits;
+                                       if ( (lowBits & 0x8000) != 0 )
+                                               displacement += 0x10000;
+                                       uint32_t picBaseOffset = nextRelocValue - src->fOffset;
+                                       int64_t dstOffset = src->fOffset + picBaseOffset + displacement - dst->fOffset;
+                                       src->addReference(srcAddr - src->fOffset, Reference::ppcFixupPicBaseLow14, *dst, dstOffset, picBaseOffset);
+                               }
+                               break;
+                       case PPC_RELOC_HA16_SECTDIFF:
+                               {
+                                       if ( ! nextRelocIsPair) {
+                                               printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
+                                               break;
+                                       }
+                                       src = findAtomCoveringOffset(srcAddr);  
+                                       dst = findAtomCoveringOffset(dstAddr);  
+                                       instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                       int16_t lowBits = (nextRelocAddress & 0x0000FFFF);
+                                       int32_t displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
+                                       uint32_t picBaseOffset = nextRelocValue - src->fOffset;
+                                       int64_t dstOffset = src->fOffset + picBaseOffset + displacement - dst->fOffset;
+                                       src->addReference(srcAddr - src->fOffset, Reference::ppcFixupPicBaseHigh16, *dst, dstOffset, picBaseOffset);
+                               }
+                               break;
+                       case PPC_RELOC_LO14:
+                               {
+                                       if ( ! nextRelocIsPair) {
+                                               printf("PPC_RELOC_LO14 missing following PAIR\n");
+                                               break;
+                                       }
+                                       src = findAtomCoveringOffset(srcAddr);  
+                                       dst = findAtomCoveringOffset(dstAddr);  
+                                       instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                       int16_t lowBits = (instruction & 0xFFFC);
+                                       uint32_t betterDstAddr = (nextRelocAddress << 16) + (int32_t)lowBits;
+                                       if ( (lowBits & 0x8000) != 0 )
+                                               betterDstAddr += 0x10000;
+                                       src->addReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow14, *dst, betterDstAddr - dst->fOffset, 0);
+                               }
+                               break;
+                       case PPC_RELOC_LO16:
+                               {
+                                       if ( ! nextRelocIsPair) {
+                                               printf("PPC_RELOC_LO16 missing following PAIR\n");
+                                               break;
+                                       }
+                                       src = findAtomCoveringOffset(srcAddr);  
+                                       dst = findAtomCoveringOffset(dstAddr);  
+                                       instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                       int16_t lowBits = (instruction & 0xFFFF);
+                                       uint32_t betterDstAddr = (nextRelocAddress << 16) + (int32_t)lowBits;
+                                       if ( (lowBits & 0x8000) != 0 )
+                                               betterDstAddr += 0x10000;
+                                       src->addReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow16, *dst, betterDstAddr - dst->fOffset, 0);
+                               }
+                               break;
+                       case PPC_RELOC_HA16:
+                               {
+                                       if ( ! nextRelocIsPair) {
+                                               printf("PPC_RELOC_HA16 missing following PAIR\n");
+                                               break;
+                                       }
+                                       src = findAtomCoveringOffset(srcAddr);  
+                                       dst = findAtomCoveringOffset(dstAddr);  
+                                       instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                       int16_t lowBits = (nextRelocAddress & 0xFFFF);
+                                       uint32_t betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
+                                       src->addReference(srcAddr - src->fOffset, Reference::ppcFixupAbsHigh16AddLow, *dst, betterDstAddr - dst->fOffset, 0);
+                               }
+                               break;
+                       case PPC_RELOC_SECTDIFF:
+                       case PPC_RELOC_LOCAL_SECTDIFF:
+                               {
+                                       const macho_scattered_relocation_info* nextReloc = &sreloc[1];
+                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+                                               printf("PPC_RELOC_SECTDIFF missing following pair\n");
+                                               break;
+                                       }
+                                       srcAddr = sect->addr() + sreloc->r_address();
+                                       uint32_t toAddr = sreloc->r_value();
+                                       uint32_t fromAddr = nextReloc->r_value();
+                                       src = findAtomCoveringOffset(srcAddr);  
+                                       Atom* to = findAtomCoveringOffset(toAddr);      
+                                       Atom* from = findAtomCoveringOffset(fromAddr);  
+                                       //macho_intptr_t pointerValue = *(macho_intptr_t*)fixUpPtr;
+                                       //uint64_t toOffset = to->fOffset;
+                                       //uint64_t fromOffset = from->fOffset;
+                                       //int64_t pointerValue64 = pointerValue;
+                                       //uint64_t addend = pointerValue64 - (toOffset - fromOffset);
+                                       Reference::Kind kind = Reference::pointer32Difference;
+                                       if ( sreloc->r_length() == 3 )
+                                               kind =  Reference::pointer64Difference;
+                                       src->addDifferenceReference(srcAddr - src->fOffset, kind, *to, toAddr - to->fOffset, *from, fromAddr - from->fOffset);
+                               }
+                               break;
+                       case PPC_RELOC_PAIR:
+                               break;
+                       case PPC_RELOC_HI16_SECTDIFF:
+                               printf("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF\n");
+                               break;
+#endif
+#if defined(ARCH_I386)
+                       case GENERIC_RELOC_SECTDIFF:
+                       case GENERIC_RELOC_LOCAL_SECTDIFF:
+                               {
+                                       if ( nextSReloc->r_type() != GENERIC_RELOC_PAIR ) {
+                                               printf("GENERIC_RELOC_SECTDIFF missing following pair\n");
+                                               break;
+                                       }
+                                       srcAddr = sect->addr() + sreloc->r_address();
+                                       uint32_t toAddr = sreloc->r_value();
+                                       uint32_t fromAddr = nextSReloc->r_value();
+                                       src = findAtomCoveringOffset(srcAddr);  
+                                       Atom* to = findAtomCoveringOffset(toAddr);      
+                                       Atom* from = findAtomCoveringOffset(fromAddr);  
+                                       Reference::Kind kind = Reference::pointer32Difference;
+                                       if ( sreloc->r_length() != 2 )
+                                               throw "bad length for GENERIC_RELOC_SECTDIFF";
+                                       src->addDifferenceReference(srcAddr - src->fOffset, kind, *to, toAddr - to->fOffset, *from, fromAddr - from->fOffset);
+                               }
+                               break;
+                       case GENERIC_RELOC_PAIR:
+                               // do nothing, already used via a look ahead
+                               break;
+#endif
+                       default:
+                               printf("unknown scattered relocation type %d\n", sreloc->r_type());
+               }
+               
+       }
+}
+
+
+void Reader::addFixUp(uint32_t srcAddr, uint32_t dstAddr, Reference::Kind kind, uint32_t picBaseAddr)
+{
+       Atom* src = findAtomCoveringOffset(srcAddr);    
+       Atom* dst = findAtomCoveringOffset(dstAddr);    
+       src->addReference(srcAddr - src->fOffset, kind, *dst, dstAddr - dst->fOffset, picBaseAddr - src->fOffset);
+}
+
+Atom* Reader::findAtomCoveringOffset(uint32_t offset)
+{
+#if 1
+       // binary search of sorted atoms
+       Atom** base = &fAtoms[0];
+       for (uint32_t n = fAtoms.size(); n > 0; n /= 2) {
+               Atom** pivot = &base[n/2];
+               Atom* pivotAtom = *pivot;
+               if ( pivotAtom->fOffset <= offset ) {
+                       if ( offset < (pivotAtom->fOffset + pivotAtom->fSize) )
+                               return pivotAtom;
+                       // key > pivot 
+                       // move base to symbol after pivot
+                       base = &pivot[1];
+                       --n; 
+               }
+               else {
+                       // key < pivot 
+                       // keep same base
+               }
+       }
+#else
+       const uint32_t atomCount = fAtoms.size();
+       for (uint32_t i=0; i < atomCount; ++i) {
+               Atom* atom = fAtoms[i];
+               if ( (atom->fOffset <= offset) && (offset < (atom->fOffset + atom->fSize)) )
+                       return atom;
+       }
+#endif
+       return NULL;
+}
+
+uint32_t Reader::findAtomIndex(const Atom& atom)
+{
+       const Atom* target = &atom;
+       const uint32_t atomCount = fAtoms.size();
+       for (uint32_t i=0; i < atomCount; ++i) {
+               Atom* anAtom = fAtoms[i];
+               if ( anAtom == target )
+                       return i;
+       }
+       return 0xffffffff;
+}
+
+static void insertOffset(std::set<uint32_t>& offsets, uint32_t value)
+{
+       //fprintf(stderr, "cleave point at 0x%08X\n", value);
+       offsets.insert(value);
+}
+
+void Reader::insertOffsetIfNotText(std::set<uint32_t>& offsets, uint32_t value)
+{
+       const macho_section* sect = findSectionCoveringOffset(value);
+       if ( (sect == NULL) || (strcmp(sect->segname(),"__TEXT") != 0) || (strncmp(sect->sectname(),"__text", 6) != 0) ) {
+               offsets.insert(value);
+       }
+}
+
+void Reader::insertOffsetIfText(std::set<uint32_t>& offsets, uint32_t value)
+{
+       const macho_section* sect = findSectionCoveringOffset(value);
+       if ( (sect != NULL) && (strcmp(sect->segname(),"__TEXT") == 0) && (strncmp(sect->sectname(),"__text", 6) == 0) ) {
+               //fprintf(stderr, "don't cleave point at 0x%08X\n", value);
+               offsets.insert(value);
+       }
+}
+
+const macho_section* Reader::findSectionCoveringOffset(uint32_t offset)
+{
+       const macho_section* const sectionsStart = (macho_section*)((char*)fSegment + sizeof(macho_segment_command));
+       const macho_section* const sectionsEnd = &sectionsStart[fSegment->nsects()];
+       for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+               if ( (sect->addr() <= offset) && (offset < (sect->addr() + sect->size())) )
+                       return sect;
+       }
+       return NULL;
+}
+
+
+void Reader::buildOffsetsSet(const macho_relocation_info* reloc, const macho_section* sect, std::set<uint32_t>& cleavePoints, std::set<uint32_t>& dontCleavePoints)
+{
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+       uint32_t targetAddr;
+#endif
+       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+               uint32_t* fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+               uint32_t instruction;
+#endif
+               switch ( reloc->r_type() ) {
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+                       case PPC_RELOC_BR14:
+                               // do nothing. local branch should not cleave
+                               break;
+                       case PPC_RELOC_BR24:
+                               {
+                                       if ( ! reloc->r_extern() ) {
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               if ( (instruction & 0x4C000000) == 0x48000000 ) {
+                                                       int32_t displacement = (instruction & 0x03FFFFFC);
+                                                       if ( (displacement & 0x02000000) != 0 )
+                                                               displacement |= 0xFC000000;
+                                                       //cleavePoints.insert(reloc->r_address() + displacement);
+                                                       insertOffset(cleavePoints, sect->addr() + reloc->r_address() + displacement);
+                                               }
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_PAIR:
+                               // skip, processed by a look ahead 
+                               break;
+                       case PPC_RELOC_LO16:
+                               {
+                                       const macho_relocation_info* nextReloc = &reloc[1];
+                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+                                               printf("PPC_RELOC_LO16 missing following pair\n");
+                                               break;
+                                       }
+                                       if ( ! reloc->r_extern() ) {
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               targetAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFF);
+                                               //cleavePoints.insert(targetAddr);
+                                               insertOffset(cleavePoints, (targetAddr));
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_LO14:
+                               {
+                                       const macho_relocation_info* nextReloc = &reloc[1];
+                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+                                               printf("PPC_RELOC_LO14 missing following pair\n");
+                                               break;
+                                       }
+                                       if ( ! reloc->r_extern() ) {
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               targetAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC);
+                                               //cleavePoints.insert(targetAddr);
+                                               insertOffset(cleavePoints, (targetAddr));
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_HI16:
+                               {
+                                       const macho_relocation_info* nextReloc = &reloc[1];
+                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+                                               printf("PPC_RELOC_HI16 missing following pair\n");
+                                               break;
+                                       }
+                                       if ( ! reloc->r_extern() ) {
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               targetAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
+                                               //cleavePoints.insert(targetAddr);
+                                               insertOffset(cleavePoints, targetAddr);
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_HA16:
+                               {
+                                       const macho_relocation_info* nextReloc = &reloc[1];
+                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+                                               printf("PPC_RELOC_HA16 missing following pair\n");
+                                               break;
+                                       }
+                                       if ( ! reloc->r_extern() ) {
+                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
+                                               int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF);
+                                               targetAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
+                                               //cleavePoints.insert(targetAddr);
+                                               insertOffset(cleavePoints, targetAddr);
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_JBSR:
+                               // ignore for now
+                               break;
+#endif
+                       case GENERIC_RELOC_VANILLA:
+                               {
+#if defined(ARCH_PPC64)
+                                       if  ( reloc->r_length() != 3 )
+                                               throw "vanilla pointer relocation found that is not 8-bytes";
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+                                       if  ( reloc->r_length() != 2 )
+                                               throw "vanilla pointer relocation found that is not 4-bytes";
+#endif
+                                       //fprintf(stderr, "pcrel=%d, len=%d, extern=%d, type=%d\n", reloc->r_pcrel(), reloc->r_length(), reloc->r_extern(), reloc->r_type());
+                                       if ( !reloc->r_extern() ) {
+                                               macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
+                                               if ( reloc->r_pcrel() )
+                                                       pointerValue += reloc->r_address() + sizeof(macho_uintptr_t);
+                                               // a pointer into code does not cleave the code (gcc always pointers to labels)
+                                               insertOffsetIfNotText(cleavePoints, pointerValue);
+                                       }
+                               }
+                               break;
+                       default:
+                               printf("unknown relocation type %d\n", reloc->r_type());
+               }
+       }
+       else {
+               const macho_scattered_relocation_info* sreloc = (macho_scattered_relocation_info*)reloc;
+               switch (sreloc->r_type()) {
+                       case GENERIC_RELOC_VANILLA:
+                               insertOffset(cleavePoints, sreloc->r_value());
+                               break;
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+                       case PPC_RELOC_BR24:
+                               insertOffset(cleavePoints, sreloc->r_value());
+                               break;
+                       case PPC_RELOC_HA16:
+                       case PPC_RELOC_HI16:
+                       case PPC_RELOC_LO16:
+                       case PPC_RELOC_LO14:
+                       case PPC_RELOC_LO16_SECTDIFF:
+                       case PPC_RELOC_LO14_SECTDIFF:
+                       case PPC_RELOC_HA16_SECTDIFF:
+                       case PPC_RELOC_HI16_SECTDIFF:
+                               //cleavePoints.insert(sreloc->r_value());
+                               insertOffset(cleavePoints, sreloc->r_value());
+                               insertOffsetIfText(dontCleavePoints, sreloc->r_value());
+                               break;
+                       case PPC_RELOC_SECTDIFF:
+                       case PPC_RELOC_LOCAL_SECTDIFF:
+                               // these do not cleave up a .o file
+                               // a SECTDIFF in __TEXT probably means a jump table, and should prevent a cleave
+                               {
+                                       const macho_scattered_relocation_info* nextReloc = &sreloc[1];
+                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+                                               printf("PPC_RELOC_SECTDIFF missing following pair\n");
+                                               break;
+                                       }
+                                       insertOffsetIfText(dontCleavePoints, sreloc->r_value());
+                                       insertOffsetIfText(dontCleavePoints, nextReloc->r_value());
+                               }
+                               break;
+                       case PPC_RELOC_PAIR:
+                               // do nothing, already used via a look ahead
+                               break;
+#endif
+#if defined(ARCH_I386)
+                       case GENERIC_RELOC_SECTDIFF:
+                       case GENERIC_RELOC_LOCAL_SECTDIFF:
+                               // these do not cleave up a .o file
+                               // a SECTDIFF in __TEXT probably means a jump table, and should prevent a cleave
+                               {
+                                       const macho_scattered_relocation_info* nextReloc = &sreloc[1];
+                                       if ( nextReloc->r_type() != GENERIC_RELOC_PAIR ) {
+                                               printf("GENERIC_RELOC_SECTDIFF missing following pair\n");
+                                               break;
+                                       }
+                                       insertOffsetIfText(dontCleavePoints, sreloc->r_value());
+                                       insertOffsetIfText(dontCleavePoints, nextReloc->r_value());
+                               }
+                               break;
+                       case GENERIC_RELOC_PAIR:
+                               // do nothing, already used via a look ahead
+                               break;
+#endif
+                       default:
+                               printf("unknown relocation type %d\n", sreloc->r_type());
+               }
+               
+       }
+}
+
+
+Segment* Reader::makeSegmentFromSection(const macho_section* sect)
+{
+       // make segment object if one does not already exist
+       const uint32_t segmentCount = fSegments.size();
+       for (uint32_t i=0; i < segmentCount; ++i) {
+               Segment* seg = fSegments[i];
+               if ( strcmp(sect->segname(), seg->getName()) == 0 )
+                       return seg;
+       }
+       Segment* seg = new Segment(sect);
+       fSegments.push_back(seg);
+       return seg;
+}
+
+macho_uintptr_t Reader::commonsOffset()
+{
+       return fSegment->vmsize();
+}
+
+const char*    Reader::getPath()
+{
+       return fPath;
+}
+
+std::vector<class ObjectFile::Atom*>&  Reader::getAtoms()
+{
+       return (std::vector<class ObjectFile::Atom*>&)(fAtoms);
+}
+
+std::vector<class ObjectFile::Atom*>*  Reader::getJustInTimeAtomsFor(const char* name)
+{
+       // object files have no just-in-time atoms
+       return NULL;
+}
+
+
+std::vector<ObjectFile::StabsInfo>*    Reader::getStabsDebugInfo()
+{
+       if ( fNonAtomStabsCount == 0 )
+               return NULL;
+               
+       std::vector<ObjectFile::StabsInfo>* stabs = new std::vector<ObjectFile::StabsInfo>();
+       stabs->reserve(fNonAtomStabsCount);
+       
+       for (uint32_t i=0; i < fNonAtomStabsCount; ++i) {
+               const macho_nlist* sym = &fSymbols[fNonAtomStabsStartIndex+i];
+               if ( (sym->n_type() & N_STAB) != 0 ) {
+                       ObjectFile::StabsInfo stab;
+                       stab.atomOffset = sym->n_value();
+                       stab.string             = &fStrings[sym->n_strx()];
+                       stab.type               = sym->n_type();
+                       stab.other              = sym->n_sect();
+                       stab.desc               = sym->n_desc();
+                       // for N_SO n_value is offset of first atom, but our gdb ignores this, so we omit that calculation
+                       if ( stab.type == N_SO ) 
+                               stab.atomOffset = 0;
+                       stabs->push_back(stab);
+               }
+       }
+       
+       // add any extra N_LSYM's not at start of symbol table
+       for (std::vector<uint32_t>::iterator it=fNonAtomExtras.begin(); it != fNonAtomExtras.end(); ++it) {
+               const macho_nlist* sym = &fSymbols[*it];
+               ObjectFile::StabsInfo stab;
+               stab.atomOffset = sym->n_value();
+               stab.string             = &fStrings[sym->n_strx()];
+               stab.type               = sym->n_type();
+               stab.other              = sym->n_sect();
+               stab.desc               = sym->n_desc();
+               stabs->push_back(stab);
+       }
+       
+       return stabs;
+}
+
+void Reader::deadStub(Atom& target)
+{
+       // remove stub
+       fDeadAtoms.insert(&target);
+               
+       // remove lazy pointer
+       const int stubNameLen = strlen(target.fSynthesizedName);
+       char lazyName[stubNameLen+8];
+       strcpy(lazyName, target.fSynthesizedName);
+       strcpy(&lazyName[stubNameLen-5], "$lazy_ptr");
+       const uint32_t atomCount = fAtoms.size();
+       for (uint32_t i=1; i < atomCount; ++i) {
+               Atom* atom = fAtoms[i];
+               if ( (atom->fSynthesizedName != NULL) && (strcmp(atom->fSynthesizedName, lazyName) == 0) ) {
+                       fDeadAtoms.insert(atom);
+                       break;
+               }
+       }
+}
+
+
+void Reader::addCallSiteReference(Atom& src, uint32_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint32_t picBaseOffset, uint32_t offsetInTargetAtom)
+{
+       // the compiler some times produces stub to static functions and then calls the stubs
+       // we need to skip the stub if a static function exists with the same name and remove the stub
+       if ( target.isLazyStub() ) {
+               const macho_section* section = target.fSection;
+               uint32_t index = (target.fOffset - section->addr()) / section->reserved2();
+               uint32_t indirectTableIndex = section->reserved1() + index;
+               uint32_t symbolIndex = ENDIAN_READ32(fIndirectTable[indirectTableIndex]);
+               if ( (symbolIndex & INDIRECT_SYMBOL_LOCAL) == 0 ) {
+                       const macho_nlist* sym = &fSymbols[symbolIndex];
+                       if ( (sym->n_value() != 0) && ((sym->n_type() & N_EXT) == 0) ) {
+                               Atom* betterTarget = this->findAtomCoveringOffset(sym->n_value());
+                               if ( (betterTarget != NULL) && (betterTarget->getScope() == ObjectFile::Atom::scopeTranslationUnit) ) {
+                                       // use direct reference to static function
+                                       src.addDirectReference(offsetInSrcAtom, kind, *betterTarget, offsetInTargetAtom, picBaseOffset);
+                                       
+                                       // remove stub and lazy pointer
+                                       this->deadStub(target);
+                                       return;
+                               }
+                       }
+               }
+       }
+       
+       // fall through to general case
+       src.addReference(offsetInSrcAtom, kind, target, offsetInTargetAtom, picBaseOffset);
+}
+
+
+Atom::Atom(Reader& owner, const macho_nlist* symbol)
+ : fOwner(owner), fSymbol(symbol), fOffset(0), fSize(0), fSection(NULL), fSegment(NULL), fSynthesizedName(NULL),
+       fStabsStartIndex(0), fStabsCount(0)
+{
+       uint8_t type =  symbol->n_type();
+       if ( (type & N_EXT) == 0 )
+               fScope = ObjectFile::Atom::scopeTranslationUnit;
+       else if ( (type & N_PEXT) != 0 )
+               fScope = ObjectFile::Atom::scopeLinkageUnit;
+       else
+               fScope = ObjectFile::Atom::scopeGlobal;
+       if ( (type & N_TYPE) == N_SECT ) {
+               // real definition
+               const macho_section* sections = (macho_section*)((char*)fOwner.fSegment + sizeof(macho_segment_command));
+               fSection = &sections[fSymbol->n_sect()-1];
+               fSegment = owner.makeSegmentFromSection(fSection);
+               fOffset = fSymbol->n_value();
+               uint8_t type = fSection->flags() & SECTION_TYPE;
+               switch ( type ) {
+                       case S_LAZY_SYMBOL_POINTERS:
+                       case S_NON_LAZY_SYMBOL_POINTERS:
+                               {
+                                       // get target name out of indirect symbol table
+                                       uint32_t index = (fOffset - fSection->addr()) / sizeof(macho_uintptr_t);
+                                       index += fSection->reserved1();
+                                       uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]);
+                                       uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx();
+                                       const char* name = &fOwner.fStrings[strOffset];
+                                       Reference* ref = this->addByNameReference(0, Reference::pointer, name, 0, 0);
+                                       if ( type == S_LAZY_SYMBOL_POINTERS ) {
+                                               ref->setLazy(true);
+                                               ref->setFromTargetName("dyld_stub_binding_helper");
+                                       }
+                               }
+                               break;
+               }
+       }
+       else if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) {
+               // tentative definition
+               fSize = symbol->n_value();
+               fSection = getCommonsSection();
+               fSegment = owner.makeSegmentFromSection(fSection);
+               fOffset = owner.commonsOffset();
+       }
+       else {
+               printf("unknown symbol type: %d\n", type);
+       }       
+}
+
+Atom::Atom(Reader& owner, uint32_t offset)
+ : fOwner(owner), fSymbol(NULL), fOffset(offset), fSize(0), fSection(NULL), fSegment(NULL), fSynthesizedName(NULL),
+       fStabsStartIndex(0), fStabsCount(0)
+{
+       fSection = findSectionFromOffset(offset);
+       fScope = ObjectFile::Atom::scopeLinkageUnit;
+       fSegment = owner.makeSegmentFromSection(fSection);
+       uint8_t type = fSection->flags() & SECTION_TYPE;
+       switch ( type ) {
+               case S_SYMBOL_STUBS:
+                       {
+                               uint32_t index = (offset - fSection->addr()) / fSection->reserved2(); 
+                               index += fSection->reserved1();
+                               uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]);
+                               uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx();
+                               const char* name = &fOwner.fStrings[strOffset];
+                               char* str = new char[strlen(name)+8];
+                               strcpy(str, name);
+                               strcat(str, "$stub");
+                               fSynthesizedName = str;
+                       }
+                       break;
+               case S_LAZY_SYMBOL_POINTERS:
+               case S_NON_LAZY_SYMBOL_POINTERS:
+                       {
+                               uint32_t index = (offset - fSection->addr()) / sizeof(macho_uintptr_t);
+                               index += fSection->reserved1();
+                               uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]);
+                               uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx();
+                               const char* name = &fOwner.fStrings[strOffset];
+                               char* str = new char[strlen(name)+16];
+                               strcpy(str, name);
+                               if ( type == S_LAZY_SYMBOL_POINTERS )
+                                       strcat(str, "$lazy_ptr");
+                               else
+                                       strcat(str, "$non_lazy_ptr");
+                               fSynthesizedName = str;
+                               Reference* ref = this->addByNameReference(0, Reference::pointer, name, 0, 0);
+                               if ( type == S_LAZY_SYMBOL_POINTERS ) {
+                                       ref->setLazy(true);
+                                       ref->setFromTargetName("dyld_stub_binding_helper");
+                               }
+                               const macho_nlist* sym = &fOwner.fSymbols[symbolIndex];
+                               if ( (sym->n_type() & N_TYPE) == N_UNDF ) {
+                                       if ( (sym->n_desc() & N_WEAK_REF) != 0 )
+                                               ref->setWeak(true);
+                               }
+                       }
+                       break;
+       }
+}
+
+
+Atom::~Atom()
+{
+}
+
+macho_section Atom::fgCommonsSection;
+
+
+bool Atom::isLazyStub()
+{
+       return ( (fSection->flags() & SECTION_TYPE) == S_SYMBOL_STUBS);
+}
+
+const macho_section* Atom::getCommonsSection() {
+       if ( strcmp(fgCommonsSection.sectname(), "__common") != 0 ) {
+               fgCommonsSection.set_sectname("__common");
+               fgCommonsSection.set_segname("__DATA");
+               fgCommonsSection.set_flags(S_ZEROFILL);
+       }
+       return &fgCommonsSection;
+}
+
+ObjectFile::Reader* Atom::getFile() const
+{
+       return &fOwner;
+}
+
+
+const char* Atom::getName() const
+{
+       if ( fSymbol != NULL )
+               return &fOwner.fStrings[fSymbol->n_strx()];
+       else
+               return fSynthesizedName;
+}
+
+const char* Atom::getDisplayName() const
+{
+       if ( fSymbol != NULL )
+               return &fOwner.fStrings[fSymbol->n_strx()];
+       
+       if ( fSynthesizedName != NULL )
+               return fSynthesizedName;
+               
+       static char temp[32];
+       sprintf(temp, "atom #%u", fOwner.findAtomIndex(*this));
+       return temp;
+}
+
+ObjectFile::Atom::Scope Atom::getScope() const
+{
+       return fScope;
+}
+
+void Atom::setScope(ObjectFile::Atom::Scope newScope)
+{
+       fScope = newScope;
+}
+
+
+bool Atom::isWeakDefinition() const
+{
+       if ( isTentativeDefinition() )
+               return true;
+       if ( fSymbol != NULL ) 
+               return ( (fSymbol->n_desc() & N_WEAK_DEF) != 0 );
+       uint8_t type = fSection->flags() & SECTION_TYPE;
+       switch ( type ) {
+               case S_SYMBOL_STUBS:
+               case S_LAZY_SYMBOL_POINTERS:
+               case S_NON_LAZY_SYMBOL_POINTERS:
+                       return true;
+       }
+       return false;
+}
+
+bool Atom::isTentativeDefinition() const
+{
+       return (fSection == &fgCommonsSection);
+}
+
+bool Atom::isCoalesableByName() const
+{
+       uint8_t type = fSection->flags() & SECTION_TYPE;
+       switch ( type ) {
+               case S_SYMBOL_STUBS:
+               case S_COALESCED:
+                       return true;
+       };
+       if ( isTentativeDefinition() )
+               return true;
+       return false;
+}
+
+bool Atom::isCoalesableByValue() const
+{
+       uint8_t type = fSection->flags() & SECTION_TYPE;
+       switch ( type ) {
+               case S_CSTRING_LITERALS:
+               case S_4BYTE_LITERALS:
+               case S_8BYTE_LITERALS:
+                       return true;
+       };
+       return false;
+}
+
+bool Atom::isZeroFill() const
+{
+       return ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL);
+}
+
+bool Atom::dontDeadStrip() const
+{
+       if ( fSymbol != NULL ) 
+               return ( (fSymbol->n_desc() & N_NO_DEAD_STRIP) != 0 );
+       return false;
+}
+
+
+bool Atom::dontStripName() const
+{
+       if ( fSymbol != NULL ) 
+               return ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0 );
+       return false;
+}
+
+bool Atom::isImportProxy() const
+{
+       return false;
+}
+       
+
+uint64_t Atom::getSize() const
+{
+       //return fOffset;
+       return fSize;
+}
+
+
+std::vector<ObjectFile::Reference*>& Atom::getReferences() const
+{
+       return (std::vector<ObjectFile::Reference*>&)(fReferences);
+}
+
+bool Atom::mustRemainInSection() const
+{
+       return true;
+}
+
+const char*     Atom::getSectionName() const
+{
+       if ( strlen(fSection->sectname()) > 15 ) {
+               static char temp[18];
+               strncpy(temp, fSection->sectname(), 16);
+               temp[17] = '\0';
+               return temp;
+       }
+       return fSection->sectname();
+}
+
+Segment& Atom::getSegment() const
+{
+       return *fSegment;
+}
+
+bool Atom::requiresFollowOnAtom() const
+{
+       // requires follow-on if built with old compiler and not the last atom
+       if ( (fOwner.fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0) {
+               if ( fOwner.findAtomIndex(*this) < (fOwner.fAtoms.size()-1) )
+                       return true;
+       }
+       return false;
+}
+
+ObjectFile::Atom& Atom::getFollowOnAtom() const
+{
+       uint32_t myIndex = fOwner.findAtomIndex(*this);
+       return *fOwner.fAtoms[myIndex+1];
+}
+
+std::vector<ObjectFile::StabsInfo>* Atom::getStabsDebugInfo() const
+{
+       if ( fStabsCount == 0 )
+               return NULL;
+               
+       std::vector<ObjectFile::StabsInfo>* stabs = new std::vector<ObjectFile::StabsInfo>();
+       stabs->reserve(fStabsCount);
+       
+       for (uint32_t i=0; i < fStabsCount; ++i) {
+               const macho_nlist* sym = &fOwner.fSymbols[fStabsStartIndex+i];
+               if ( (sym->n_type() & N_STAB) != 0 ) {
+                       ObjectFile::StabsInfo stab;
+                       stab.atomOffset = sym->n_value();
+                       stab.string             = &fOwner.fStrings[sym->n_strx()];
+                       stab.type               = sym->n_type();
+                       stab.other              = sym->n_sect();
+                       stab.desc               = sym->n_desc();
+                       switch ( stab.type ) {
+                               case N_FUN:
+                                       if ( stab.other == 0 )
+                                               break;
+                                       // end of function N_FUN has size (not address) so should not be adjusted
+                                       // fall through
+                               case N_BNSYM:
+                               case N_ENSYM:
+                               case N_LBRAC:
+                               case N_RBRAC:
+                               case N_SLINE:
+                               case N_STSYM:
+                               case N_LCSYM:
+                                       // all these stab types need their value changed from an absolute address to the atom offset
+                                       stab.atomOffset -= fOffset;
+                                       break;
+                       }
+                       stabs->push_back(stab);
+               }
+       }
+       
+       return stabs;
+}
+
+uint8_t        Atom::getAlignment() const
+{
+       // mach-o file format has no alignment information for atoms - just whole sections
+       if ( fSection != NULL ) {
+               if ( isTentativeDefinition() ) {
+                       // common symbols align to their size
+                       // that is, a 4-byte common aligns to 4-bytes
+                       // to be safe, odd size commons align to the next power-of-2 size
+                       uint8_t alignment = (uint8_t)ceil(log2(this->getSize()));
+                       // limit alignment of extremely large commons to 2^15 bytes (8-page)
+                       if ( alignment < 15 )
+                               return alignment;
+                       else
+                               return 15;
+               }
+               else {
+                       // so we assume every atom requires the same alignment as the whole section
+                       return fSection->align();
+               }
+       }
+       else {
+               return 2;
+       }
+}
+
+void Atom::copyRawContent(uint8_t buffer[]) const
+{
+       // copy base bytes
+       if ( isZeroFill() )
+               bzero(buffer, fSize);
+       else {
+               uint32_t fileOffset = fSection->offset() - fSection->addr() + fOffset;
+               memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
+       }
+}
+
+void Atom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       const uint32_t referencesCount = fReferences.size();
+
+       // skip copy if no fix-ups
+       if ( referencesCount == 0 ) {
+               uint32_t fileOffset = fSection->offset() - fSection->addr() + fOffset;
+               writer.write(0, (char*)(fOwner.fHeader)+fileOffset, fSize);
+               return;
+       }
+       
+       // copy base bytes
+       uint8_t buffer[this->getSize()];
+       this->copyRawContent(buffer);
+
+       // apply any fix-ups
+       for (uint32_t i=0; i < referencesCount; ++i) {
+               Reference* ref = fReferences[i];
+               uint32_t offset = ref->getFixUpOffset();
+               uint32_t* instructionPtr = (uint32_t*)&buffer[offset];
+               ObjectFile::Atom& target = ref->getTarget();
+               if ( &target == NULL ) {
+                       if ( finalLinkedImage )
+                               throw "target not found";
+                       else
+                               continue;
+               }
+               uint32_t instruction;
+               uint32_t newInstruction;
+               switch ( ref->getKind() ) {
+                       case Reference::noFixUp:
+                               break;
+                       case Reference::pointer:
+                               {
+                                       //fprintf(stderr, "writeContent: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
+                                       if ( target.isImportProxy() ) {
+                                               if ( ref->isLazyReference() && finalLinkedImage ) {
+                                                       // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
+                                                       *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getFromTarget().getAddress());
+                                               }
+                                               else {
+                                                       // external realocation ==> pointer contains addend
+                                                       *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getTargetOffset());
+                                               }
+                                       }
+                                       else {
+                                               // internal relocation
+                                               if ( finalLinkedImage || (strcmp(target.getSectionName(), "__common") != 0) ) {
+                                                       // pointer contains target address
+                                                       //printf("Atom::writeContent() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
+                                                       *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(target.getAddress() + ref->getTargetOffset());
+                                               }
+                                               else {
+                                                       // pointer contains addend
+                                                       *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getTargetOffset());
+                                               }
+                                       }
+                               }
+                               break;
+                       case Reference::ppcFixupBranch24:
+                               {
+                                       //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
+                                       int64_t displacement = (target.getAddress() + ref->getTargetOffset() ) - (this->getAddress() + offset);
+                                       if ( !finalLinkedImage && target.isImportProxy() )  {
+                                               // doing "ld -r" to an external symbol
+                                               // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
+                                               displacement -= target.getAddress();
+                                       }
+                                       else {
+                                               const int64_t bl_eightMegLimit = 0x00FFFFFF;
+                                               if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
+                                                       //fprintf(stderr, "bl out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
+                                                       throw "bl out of range";
+                                               }
+                                       }
+                                       instruction = OSReadBigInt32(instructionPtr, 0);
+                                       newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
+                                       //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
+                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);                     
+                               }
+                               break;
+                       case Reference::ppcFixupBranch14:
+                               break;
+                       case Reference::ppcFixupPicBaseLow16:
+                               {
+                                       uint64_t targetAddr = target.getAddress() + ref->getTargetOffset();
+                                       uint64_t picBaseAddr = this->getAddress() + ref->getFromTargetOffset();
+                                       int64_t displacement = targetAddr - picBaseAddr;
+                                       const int64_t picbase_twoGigLimit = 0x80000000;
+                                       if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
+                                               throw "32-bit pic-base out of range";
+                                       uint16_t instructionLowHalf = (displacement & 0xFFFF);
+                                       instruction = OSReadBigInt32(instructionPtr, 0);
+                                       newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
+                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);                     
+                               }
+                               break;
+                       case Reference::ppcFixupPicBaseLow14:
+                               {
+                                       uint64_t targetAddr = target.getAddress() + ref->getTargetOffset();
+                                       uint64_t picBaseAddr = this->getAddress() + ref->getFromTargetOffset();
+                                       int64_t displacement = targetAddr - picBaseAddr;
+                                       const int64_t picbase_twoGigLimit = 0x80000000;
+                                       if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
+                                               throw "32-bit pic-base out of range";
+                                       uint16_t instructionLowHalf = (displacement & 0xFFFF);
+                                       if ( (instructionLowHalf & 0x3) != 0 )
+                                               throw "bad address for lo14 instruction fix-up";
+                                       instruction = OSReadBigInt32(instructionPtr, 0);
+                                       newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
+                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);                     
+                               }
+                               break;
+                       case Reference::ppcFixupPicBaseHigh16:
+                               {
+                                       uint64_t targetAddr = target.getAddress() + ref->getTargetOffset();
+                                       uint64_t picBaseAddr = this->getAddress() + ref->getFromTargetOffset();
+                                       int64_t displacement = targetAddr - picBaseAddr;
+                                       const int64_t picbase_twoGigLimit = 0x80000000;
+                                       if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) ) 
+                                               throw "32-bit pic-base out of range";
+                                       uint16_t instructionLowHalf = displacement >> 16;
+                                       if ( (displacement & 0x00008000) != 0 ) 
+                                               ++instructionLowHalf;
+                                       instruction = OSReadBigInt32(instructionPtr, 0);
+                                       newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
+                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);                     
+                               }
+                               break;
+                       case Reference::ppcFixupAbsLow16:
+                               {
+                                       int64_t addr = target.getAddress() + ref->getTargetOffset();
+                                       if ( !finalLinkedImage && target.isImportProxy() )
+                                               addr -= target.getAddress() ;
+                                       uint16_t instructionLowHalf = (addr & 0xFFFF);
+                                       instruction = OSReadBigInt32(instructionPtr, 0);
+                                       newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
+                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);                     
+                               }
+                               break;
+                       case Reference::ppcFixupAbsLow14:
+                               {
+                                       int64_t addr = target.getAddress() + ref->getTargetOffset();
+                                       if ( !finalLinkedImage && target.isImportProxy() )
+                                               addr -= target.getAddress() ;
+                                       uint16_t instructionLowHalf = (addr & 0xFFFF);
+                                       if ( (instructionLowHalf & 0x3) != 0 )
+                                               throw "bad address for lo14 instruction fix-up";
+                                       instruction = OSReadBigInt32(instructionPtr, 0);
+                                       newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
+                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);                     
+                               }
+                               break;
+                       case Reference::ppcFixupAbsHigh16:
+                               {
+                                       int64_t addr = target.getAddress() + ref->getTargetOffset();
+                                       if ( !finalLinkedImage && target.isImportProxy() )
+                                               addr -= target.getAddress() ;
+                                       uint16_t hi16 = (addr >> 16);
+                                       instruction = OSReadBigInt32(instructionPtr, 0);
+                                       newInstruction = (instruction & 0xFFFF0000) | hi16;
+                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);     
+                               }
+                               break;
+                       case Reference::ppcFixupAbsHigh16AddLow:
+                               {
+                                       int64_t addr = target.getAddress() + ref->getTargetOffset();
+                                       if ( !finalLinkedImage && target.isImportProxy() )
+                                               addr -= target.getAddress() ;
+                                       if ( addr & 0x00008000 )
+                                               addr += 0x00010000;
+                                       instruction = OSReadBigInt32(instructionPtr, 0);
+                                       newInstruction = (instruction & 0xFFFF0000) | (addr >> 16);
+                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);     
+                               }
+                               break;
+                       case Reference::pointer32Difference:
+                               ENDIAN_WRITE32(*instructionPtr, target.getAddress() + ref->getTargetOffset() - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()));
+                               break;
+                       case Reference::pointer64Difference:
+                               *((uint64_t*)instructionPtr) = ENDIAN_SWAP64(target.getAddress() + ref->getTargetOffset() - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()));
+                               break;
+                       case Reference::x86FixupBranch32:
+                               {
+                                       int64_t displacement = target.getAddress() - (this->getAddress() + offset);
+                                       if ( target.isImportProxy() )  {
+                                               displacement = 0;
+                                       }
+                                       else {
+                                               const int64_t bl_twoGigLimit = 0x7FFFFFFF;
+                                               if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_twoGigLimit)) ) {
+                                                       //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
+                                                       throw "call out of range";
+                                               }
+                                       }
+                                       OSWriteLittleInt32(instructionPtr, 0, (int32_t)displacement);                   
+                               }
+                               break;
+               }
+       }
+
+       // write out
+       writer.write(0, buffer, getSize());
+}
+
+
+
+const macho_section* Atom::findSectionFromOffset(macho_uintptr_t offset)
+{
+       const macho_section* const sectionsStart = (const macho_section*)( (char*)fOwner.fSegment + sizeof(macho_segment_command) );
+       const macho_section* const sectionsEnd   = &sectionsStart[fOwner.fSegment->nsects()];
+       for (const macho_section* s = sectionsStart; s < sectionsEnd; ++s) {
+               if ( (s->addr() <= offset) && (offset < (s->addr()+s->size())) ) 
+                       return s;
+       }
+       throw "section not found";
+}
+
+void Atom::setSize(macho_uintptr_t size)
+{
+       fSize = size;
+}
+
+
+void Atom::setFollowOnAtom(Atom&)
+{
+
+}
+
+Reference* Atom::addReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
+{
+       if ( (target.getScope() != ObjectFile::Atom::scopeTranslationUnit) && ((target.fSymbol != NULL) || (target.fSynthesizedName != NULL)) )
+               return this->addByNameReference(offsetInSrcAtom, kind, target.getName(), offsetInTarget, offsetInFromTarget);
+       else 
+               return this->addDirectReference(offsetInSrcAtom, kind, target, offsetInTarget, offsetInFromTarget);
+}
+
+
+Reference* Atom::addDirectReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
+{      
+       Reference* ref = new Reference(offsetInSrcAtom, kind, target, offsetInTarget, offsetInFromTarget);
+       // in rare cases, there may already be a by-name reference to the same atom.  If so, replace with this direct reference
+       for (std::vector<Reference*>::iterator it=fReferences.begin(); it != fReferences.end(); it++) {
+               ObjectFile::Reference* aRef = *it;
+               if ( (aRef->getFixUpOffset() == offsetInSrcAtom) && (aRef->getKind() == kind) ) {
+                       *it = ref;
+                       return ref;
+               }
+       }
+       
+       // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file
+       fReferences.insert(fReferences.begin(), ref);
+       return ref;
+}
+
+Reference* Atom::addByNameReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
+{
+       Reference* ref = new Reference(offsetInSrcAtom, kind, targetName, offsetInTarget, offsetInFromTarget);
+       // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file
+       fReferences.insert(fReferences.begin(), ref);
+       return ref;
+}
+
+Reference* Atom::addDifferenceReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, Atom& fromTarget, uint64_t offsetInFromTarget)
+{
+       Reference* ref = new Reference(offsetInSrcAtom, kind, target, offsetInTarget, fromTarget, offsetInFromTarget);
+       // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file
+       fReferences.insert(fReferences.begin(), ref);
+       return ref;
+}
+
+
+Segment::Segment(const macho_section* sect)
+       : fSection(sect)
+{
+}
+
+const char* Segment::getName() const
+{
+       return fSection->segname();
+}
+
+bool Segment::isContentReadable() const
+{
+       return true;
+}
+
+bool Segment::isContentWritable() const
+{
+       if ( strcmp(fSection->segname(), "__DATA") == 0 )
+               return true;
+       if ( strcmp(fSection->segname(), "__OBJC") == 0 )
+               return true;
+       return false;
+}
+
+bool Segment::isContentExecutable() const
+{
+       return ( strcmp(fSection->segname(), "__TEXT") == 0 );
+}
+
+       
+Reference::Reference(macho_uintptr_t fixUpOffset, Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
+ : fTarget(NULL), fFromTarget(NULL), fTargetName(targetName), fFromTargetName(NULL), fTargetOffset(offsetInTarget), fFromTargetOffset(offsetInFromTarget),
+  fFixUpOffsetInSrc(fixUpOffset), fKind(kind), fLazy(false), fWeak(false)
+{
+}
+
+Reference::Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
+ : fTarget(&target), fFromTarget(NULL), fTargetName(NULL), fFromTargetName(NULL), fTargetOffset(offsetInTarget), fFromTargetOffset(offsetInFromTarget), 
+ fFixUpOffsetInSrc(fixUpOffset), fKind(kind), fLazy(false), fWeak(false)
+{
+}
+
+Reference::Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, class Atom& fromTarget, uint64_t offsetInFromTarget)
+ : fTarget(&target), fFromTarget(&fromTarget), fTargetName(NULL), fFromTargetName(NULL), fTargetOffset(offsetInTarget), fFromTargetOffset(offsetInFromTarget),
+  fFixUpOffsetInSrc(fixUpOffset), fKind(kind), fLazy(false), fWeak(false)
+{
+       // assure no direct references to something that might be coalesced
+       if ( (target.isWeakDefinition() || target.isCoalesableByName()) && (target.getScope() != ObjectFile::Atom::scopeTranslationUnit) && (target.getName() != NULL) ) {
+               //fprintf(stderr, "change TO direct reference to by-name: from %s to %s in %p\n", fromTarget.getDisplayName(), target.getName(), this);
+               fTargetName = target.getName();
+               fTarget = NULL;
+       }
+// Note: We should also allow by-name from references, but many other chunks of code assume from targets are always direct//
+//     if ( (fromTarget.isWeakDefinition() || fromTarget.isCoalesableByName()) && (fromTarget.getScope() != ObjectFile::Atom::scopeTranslationUnit) && (fromTarget.getName() != NULL)) {
+//             fprintf(stderr, "change FROM direct reference to by-name: from %s to %s in %p\n", fromTarget.getDisplayName(), target.getName(), this);
+//             fFromTargetName = fromTarget.getName();
+//             fFromTarget = NULL;
+//     }
+}
+
+
+
+Reference::~Reference()
+{
+}
+
+bool Reference::isUnbound() const
+{
+       if ( fTarget == NULL ) 
+               return true;
+       if ( (fFromTargetName!=NULL) && (fFromTarget==NULL) )
+               return true;
+       return false;
+}
+
+bool Reference::isWeakReference() const
+{
+       return fWeak;
+}
+
+bool Reference::requiresRuntimeFixUp() const
+{
+       return ( fKind == Reference::pointer );
+}
+
+bool Reference::isLazyReference() const
+{
+       return fLazy;
+}
+
+ObjectFile::Reference::Kind    Reference::getKind() const
+{
+       return fKind;
+}
+
+uint64_t Reference::getFixUpOffset() const
+{
+       return fFixUpOffsetInSrc;
+}
+
+const char* Reference::getTargetName() const
+{
+       if ( fTargetName != NULL )
+               return fTargetName;
+       return fTarget->getName();
+}
+
+ObjectFile::Atom& Reference::getTarget() const
+{
+       return *fTarget;
+}
+
+void Reference::setTarget(ObjectFile::Atom& target)
+{
+       fTarget = &target;
+}
+
+
+ObjectFile::Atom& Reference::getFromTarget() const
+{
+       return *fFromTarget;
+}
+
+const char* Reference::getFromTargetName() const
+{
+       if ( fFromTargetName != NULL )
+               return fFromTargetName;
+       return fFromTarget->getName();
+}
+
+void Reference::setFromTarget(ObjectFile::Atom& target)
+{
+       fFromTarget = &target;
+}
+
+void Reference::setFromTargetName(const char* name)
+{
+       fFromTargetName = name;
+}
+
+uint64_t Reference::getTargetOffset() const
+{
+       return fTargetOffset;
+}
+
+
+uint64_t Reference::getFromTargetOffset() const
+{
+       return fFromTargetOffset;
+}
+
+void Reference::setLazy(bool lazy)
+{
+       fLazy = lazy;
+}
+
+void Reference::setWeak(bool weak)
+{
+       fWeak = weak;
+}
+
+const char* Reference::getDescription() const
+{
+       static char temp[256];
+       if ( fKind == pointer32Difference ) {
+               // by-name references have quoted names
+               bool targetByName = ( &(this->getTarget()) == NULL );
+               bool fromByName   = ( &(this->getFromTarget()) == NULL );
+               const char* targetQuotes = targetByName ? "\"" : "";
+               const char* fromQuotes = fromByName ? "\"" : "";
+               sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %lld) - (&%s%s%s + %lld)", 
+                       this->getFixUpOffset(), targetQuotes, this->getTargetName(), targetQuotes, this->getTargetOffset(), 
+                                                  fromQuotes, this->getFromTargetName(), fromQuotes, this->getFromTargetOffset() );
+       }
+       else if ( fKind == pointer64Difference ) {
+               // by-name references have quoted names
+               bool targetByName = ( &(this->getTarget()) == NULL );
+               bool fromByName   = ( &(this->getFromTarget()) == NULL );
+               const char* targetQuotes = targetByName ? "\"" : "";
+               const char* fromQuotes = fromByName ? "\"" : "";
+               sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %lld) - (&%s%s%s + %lld)", 
+                       this->getFixUpOffset(), targetQuotes, this->getTargetName(), targetQuotes, this->getTargetOffset(), 
+                                                  fromQuotes, this->getFromTargetName(), fromQuotes, this->getFromTargetOffset() );
+       }
+       else {
+               switch( fKind ) {
+                       case noFixUp:
+                               sprintf(temp, "reference to ");
+                               break;
+                       case pointer:
+                               {
+                               const char* weak = "";
+                               if ( fWeak )
+                                       weak = "weak ";
+                               const char* lazy = "";
+                               if ( fLazy )
+                                       lazy = "lazy ";
+                               sprintf(temp, "offset 0x%04llX, %s%spointer to ", this->getFixUpOffset(), weak, lazy);
+                               }
+                               break;
+                       case ppcFixupBranch14:
+                       case ppcFixupBranch24:
+                               sprintf(temp, "offset 0x%04llX, bl pc-rel fixup to ", this->getFixUpOffset());
+                               break;
+                       case ppcFixupPicBaseLow16:
+                               sprintf(temp, "offset 0x%04llX, low  16 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
+                               break;
+                       case ppcFixupPicBaseLow14:
+                               sprintf(temp, "offset 0x%04llX, low  14 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
+                               break;
+                       case ppcFixupPicBaseHigh16:
+                               sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
+                               break;
+                       case ppcFixupAbsLow16:
+                               sprintf(temp, "offset 0x%04llX, low  16 fixup to absolute address of ", this->getFixUpOffset());
+                               break;
+                       case ppcFixupAbsLow14:
+                               sprintf(temp, "offset 0x%04llX, low  14 fixup to absolute address of ", this->getFixUpOffset());
+                               break;
+                       case ppcFixupAbsHigh16:
+                               sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", this->getFixUpOffset());
+                               break;
+                       case ppcFixupAbsHigh16AddLow:
+                               sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", this->getFixUpOffset());
+                               break;
+                       case pointer32Difference:
+                       case pointer64Difference:
+                               // handled above
+                               break;
+                       case x86FixupBranch32:
+                               sprintf(temp, "offset 0x%04llX, call pc-rel fixup to ", this->getFixUpOffset());
+                               break;
+               }
+               // always quote by-name references
+               if ( fTargetName != NULL ) {
+                       strcat(temp, "\"");
+                       strcat(temp, fTargetName);
+                       strcat(temp, "\"");
+               }
+               else if ( fTarget != NULL ) {
+                       strcat(temp, fTarget->getDisplayName());
+               }
+               else {
+                       strcat(temp, "NULL target");
+               }
+               if ( fTargetOffset != 0 )
+                       sprintf(&temp[strlen(temp)], " plus 0x%08llX", this->getTargetOffset());
+               if ( (fKind==pointer) && fLazy ) {
+                       strcat(temp, " initially bound to \"");
+                       strcat(temp, this->getFromTargetName());
+                       strcat(temp, "\"");
+               }
+       }
+       return temp;
+}
+
+};
+
+
+
+
+
+
+
diff --git a/src/SectCreate.cpp b/src/SectCreate.cpp
new file mode 100644 (file)
index 0000000..4d48a37
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * 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 <vector>
+
+#include "ObjectFile.h"
+
+namespace SectCreate {
+
+
+class Segment : public ObjectFile::Segment
+{
+public:
+                                                               Segment(const char* name)               { fName = name; }
+       virtual const char*                     getName() const                                 { return fName; }
+       virtual bool                            isContentReadable() const               { return true; }
+       virtual bool                            isContentWritable() const               { return false; }
+       virtual bool                            isContentExecutable() const             { return false; }
+private:
+       const char*                                     fName;
+};
+
+
+class Reader : public ObjectFile::Reader 
+{
+public:
+                                                                                               Reader(const char* segmentName, const char* sectionName, const char* path, const uint8_t fileContent[], uint64_t fileLength);
+       virtual                                                                         ~Reader();
+       
+       virtual const char*                                                             getPath()                                                               { return fPath; }
+       virtual std::vector<class ObjectFile::Atom*>&   getAtoms()                                                              { return fAtoms; }
+       virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name) { return NULL; }
+       virtual std::vector<ObjectFile::StabsInfo>*             getStabsDebugInfo()                                             { return NULL; }
+
+private:
+       const char*                                                                             fPath;
+       std::vector<class ObjectFile::Atom*>                    fAtoms;
+};
+
+
+class Atom : public ObjectFile::Atom {
+public:
+       virtual ObjectFile::Reader*                                     getFile() const                         { return &fOwner; }
+       virtual const char*                                                     getName() const                         { return NULL; }
+       virtual const char*                                                     getDisplayName() const;
+       virtual Scope                                                           getScope() const                        { return ObjectFile::Atom::scopeTranslationUnit; }
+       virtual bool                                                            isTentativeDefinition() const { return false; }
+       virtual bool                                                            isWeakDefinition() const        { return false; }
+       virtual bool                                                            isCoalesableByName() const      { return false; }
+       virtual bool                                                            isCoalesableByValue() const { return false; }
+       virtual bool                                                            isZeroFill() const                      { return false; }
+       virtual bool                                                            dontDeadStrip() const           { return true; }
+       virtual bool                                                            dontStripName() const           { return false; }
+       virtual bool                                                            isImportProxy() const           { return false; }
+       virtual uint64_t                                                        getSize() const                         { return fFileLength; }
+       virtual std::vector<ObjectFile::Reference*>&  getReferences() const             { return fgEmptyReferenceList; }
+       virtual bool                                                            mustRemainInSection() const { return false; }
+       virtual const char*                                                     getSectionName() const          { return fSectionName; }
+       virtual Segment&                                                        getSegment() const                      { return fSegment; }
+       virtual bool                                                            requiresFollowOnAtom() const{ return false; }
+       virtual ObjectFile::Atom&                                       getFollowOnAtom() const         { return *((ObjectFile::Atom*)NULL); }
+       virtual std::vector<ObjectFile::StabsInfo>*     getStabsDebugInfo() const       { return NULL; }
+       virtual uint8_t                                                         getAlignment() const            { return 4; }
+       virtual WeakImportSetting                                       getImportWeakness() const       { return ObjectFile::Atom::kWeakUnset; }
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const;
+       virtual void                                                            writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+
+       virtual void                                                            setScope(Scope)                         { }
+       virtual void                                                            setImportWeakness(bool)         { }
+
+protected:
+       friend class Reader;
+       
+                                                                                       Atom(Reader& owner, Segment& segment, const char* sectionName, const uint8_t fileContent[], uint64_t fileLength) 
+                                                                                               : fOwner(owner), fSegment(segment), fSectionName(sectionName), fFileContent(fileContent), fFileLength(fileLength) {}
+       virtual                                                                 ~Atom() {}
+       
+       Reader&                                                                 fOwner;
+       Segment&                                                                fSegment;
+       const char*                                                             fSectionName;
+       const uint8_t*                                                  fFileContent;
+       uint64_t                                                                fFileLength;
+       
+       static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
+};
+
+
+std::vector<ObjectFile::Reference*> Atom::fgEmptyReferenceList;
+
+
+
+Reader::Reader(const char* segmentName, const char* sectionName, const char* path, const uint8_t fileContent[], uint64_t fileLength)
+ : fPath(path)
+{
+       fAtoms.push_back(new Atom(*this, *(new Segment(segmentName)), sectionName, fileContent, fileLength));
+}
+
+Reader::~Reader()
+{
+}
+
+
+const char*     Atom::getDisplayName() const
+{
+       static char name[64];
+       sprintf(name, "-sectcreate %s %s", fSegment.getName(), fSectionName);
+       return name;
+}
+
+
+void Atom::copyRawContent(uint8_t buffer[]) const
+{
+       memcpy(buffer, fFileContent, fFileLength);
+}
+
+void Atom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       writer.write(0, fFileContent, fFileLength);
+}
+
+
+Reader* MakeReader(const char* segmentName, const char* sectionName, const char* path, const uint8_t fileContent[], uint64_t fileLength)
+{
+       return new Reader(segmentName, sectionName, path, fileContent, fileLength);
+}
+
+
+
+};
+
+
+
+
+
+
+
diff --git a/src/SectCreate.h b/src/SectCreate.h
new file mode 100644 (file)
index 0000000..73b49a5
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __SECTCREATE__
+#define __SECTCREATE__
+
+
+#include "ObjectFile.h"
+
+namespace SectCreate {
+
+       extern ObjectFile::Reader* MakeReader(const char* segmentName, const char* sectionName, const char* path, const uint8_t fileContent[], uint64_t fileLength);
+
+};
+
+
+#endif
+
+
+
+
diff --git a/src/Writers/ExecutableFileMachO-all.cpp b/src/Writers/ExecutableFileMachO-all.cpp
new file mode 100644 (file)
index 0000000..661a3df
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/reloc.h>
+#include <mach-o/ppc/reloc.h>
+#include <mach-o/stab.h>
+
+#include <vector>
+#include <algorithm>
+#include <map>
+#include <set>
+
+#include "ObjectFile.h"
+#include "ExecutableFile.h"
+#include "Options.h"
+
+// buiild Writer for -arch ppc64
+#undef MACHO_32_SAME_ENDIAN
+#undef MACHO_32_OPPOSITE_ENDIAN
+#undef MACHO_64_SAME_ENDIAN
+#undef MACHO_64_OPPOSITE_ENDIAN
+#if __ppc__ || __ppc64__
+       #define MACHO_64_SAME_ENDIAN
+#elif __i386__
+       #define MACHO_64_OPPOSITE_ENDIAN
+#else
+       #error unknown architecture
+#endif
+namespace ppc64 {
+       #undef  ARCH_PPC
+       #define ARCH_PPC64
+       #undef  ARCH_I386
+       #include "MachOAbstraction.h"
+       #include "ExecutableFileMachO.cpp"
+};
+
+// buiild Writer for -arch ppc
+#undef MACHO_32_SAME_ENDIAN
+#undef MACHO_32_OPPOSITE_ENDIAN
+#undef MACHO_64_SAME_ENDIAN
+#undef MACHO_64_OPPOSITE_ENDIAN
+#if __ppc__ || __ppc64__
+       #define MACHO_32_SAME_ENDIAN
+#elif __i386__
+       #define MACHO_32_OPPOSITE_ENDIAN
+#else
+       #error unknown architecture
+#endif
+namespace ppc {
+       #define ARCH_PPC
+       #undef  ARCH_PPC64
+       #undef  ARCH_I386
+       #include "MachOAbstraction.h"
+       #include "ExecutableFileMachO.cpp"
+};
+
+// buiild Writer for -arch i386
+#undef MACHO_32_SAME_ENDIAN
+#undef MACHO_32_OPPOSITE_ENDIAN
+#undef MACHO_64_SAME_ENDIAN
+#undef MACHO_64_OPPOSITE_ENDIAN
+#if __ppc__ || __ppc64__
+       #define MACHO_32_OPPOSITE_ENDIAN
+#elif __i386__
+       #define MACHO_32_SAME_ENDIAN
+#else
+       #error unknown architecture
+#endif
+#undef i386 // compiler sometimes #defines this
+namespace i386 {
+       #undef  ARCH_PPC
+       #undef  ARCH_PPC64
+       #define ARCH_I386
+       #include "MachOAbstraction.h"
+       #include "ExecutableFileMachO.cpp"
+};
+
+
diff --git a/src/Writers/ExecutableFileMachO-all.h b/src/Writers/ExecutableFileMachO-all.h
new file mode 100644 (file)
index 0000000..08d4ae6
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __EXECUTABLEFILEMACHO__
+#define __EXECUTABLEFILEMACHO__
+
+class Options;
+
+namespace ppc {
+       namespace ExecutableFileMachO {
+               extern class ExecutableFile::Writer* MakeWriter(const char* path, Options&, std::vector<ExecutableFile::DyLibUsed>&);
+       }
+};
+
+namespace ppc64 {
+       namespace ExecutableFileMachO {
+               extern class ExecutableFile::Writer* MakeWriter(const char* path, Options&, std::vector<ExecutableFile::DyLibUsed>&);
+       }
+};
+
+#undef i386 // compiler sometimes #defines this
+namespace i386 {
+       namespace ExecutableFileMachO {
+               extern class ExecutableFile::Writer* MakeWriter(const char* path, Options&, std::vector<ExecutableFile::DyLibUsed>&);
+       }
+};
+
+
+
+#endif // __EXECUTABLEFILEMACHO__
+
+
+
diff --git a/src/Writers/ExecutableFileMachO.cpp b/src/Writers/ExecutableFileMachO.cpp
new file mode 100644 (file)
index 0000000..5020cfe
--- /dev/null
@@ -0,0 +1,2554 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+
+namespace ExecutableFileMachO {
+
+class Writer : public ExecutableFile::Writer
+{ 
+public:
+                                                               Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries);
+       virtual                                         ~Writer();
+
+       virtual const char*                                                             getPath();
+       virtual std::vector<class ObjectFile::Atom*>&   getAtoms();
+       virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name);
+       virtual std::vector<ObjectFile::StabsInfo>*             getStabsDebugInfo();
+
+       virtual class ObjectFile::Atom*                                 getUndefinedProxyAtom(const char* name);
+       virtual void                                                                    write(std::vector<class ObjectFile::Atom*>& atoms, class ObjectFile::Atom* entryPointAtom);
+       
+private:
+       void                                            assignFileOffsets();
+       void                                            partitionIntoSections();
+       void                                            adjustLoadCommandsAndPadding();
+       void                                            createDynamicLinkerCommand();
+       void                                            createDylibCommands();
+       void                                            buildLinkEdit();
+       void                                            writeAtoms();
+       void                                            collectExportedAndImportedAndLocalAtoms();
+       void                                            setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
+       void                                            buildSymbolTable();
+       void                                            setExportNlist(const ObjectFile::Atom* atom, macho_nlist* entry);
+       void                                            setImportNlist(const ObjectFile::Atom* atom, macho_nlist* entry);
+       void                                            setLocalNlist(const ObjectFile::Atom* atom, macho_nlist* entry);
+       uint64_t                                        getAtomLoadAddress(const ObjectFile::Atom* atom);
+       uint8_t                                         ordinalForLibrary(ObjectFile::Reader* file);
+       bool                                            shouldExport(ObjectFile::Atom& atom);
+       void                                            buildFixups();
+       void                                            adjustLinkEditSections();
+       void                                            buildObjectFileFixups();
+       void                                            buildExecutableFixups();
+       uint32_t                                        symbolIndex(ObjectFile::Atom& atom);
+       uint32_t                                        addRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
+       unsigned int                            collectStabs();
+       macho_uintptr_t                         valueForStab(const ObjectFile::StabsInfo& stab, const ObjectFile::Atom* atom);
+       void                                            addStabs(uint32_t startIndex, uint32_t count);
+
+       
+       class SectionInfo : public ObjectFile::Section {
+       public:
+                                                                                       SectionInfo();
+               void                                                            setIndex(unsigned int index) { fIndex=index; }
+               std::vector<ObjectFile::Atom*>          fAtoms;
+               char                                                            fSegmentName[20];
+               char                                                            fSectionName[20];
+               uint64_t                                                        fFileOffset;
+               uint64_t                                                        fSize;
+               uint32_t                                                        fRelocCount;
+               uint32_t                                                        fRelocOffset;
+               uint32_t                                                        fIndirectSymbolOffset;
+               uint8_t                                                         fAlignment;
+               bool                                                            fAllLazyPointers;
+               bool                                                            fAllNonLazyPointers;
+               bool                                                            fAllZeroFill;
+               bool                                                            fVirtualSection;
+       };
+       
+       class SegmentInfo 
+       {
+       public:
+                                                                                       SegmentInfo();
+               std::vector<class SectionInfo*>         fSections;
+               char                                                            fName[20];
+               uint32_t                                                        fInitProtection;
+               uint32_t                                                        fMaxProtection;
+               uint64_t                                                        fFileOffset;
+               uint64_t                                                        fFileSize;
+               uint64_t                                                        fBaseAddress;
+               uint64_t                                                        fSize;
+       };
+
+       
+       struct DirectLibrary {
+               class ObjectFile::Reader*               fLibrary;
+               bool                                            fWeak;
+               bool                                            fReExport;      
+       };
+       
+       struct IndirectEntry {
+               uint32_t        indirectIndex;  
+               uint32_t        symbolIndex;
+       };
+
+       struct StabChunks {
+               ObjectFile::Atom*                                       fAtom;
+               ObjectFile::Reader*                                     fReader;
+               unsigned int                                            fOrderInReader;
+               std::vector<ObjectFile::StabsInfo>*     fStabs;
+       };
+
+       static bool                                             stabChunkCompare(const StabChunks& lhs, const StabChunks& rhs);
+
+       friend class WriterAtom;
+       friend class PageZeroAtom;
+       friend class CustomStackAtom;
+       friend class MachHeaderAtom;
+       friend class SegmentLoadCommandsAtom;
+       friend class SymbolTableLoadCommandsAtom;
+       friend class ThreadsLoadCommandsAtom;
+       friend class DylibIDLoadCommandsAtom;
+       friend class RoutinesLoadCommandsAtom;
+       friend class DyldLoadCommandsAtom;
+       friend class LinkEditAtom;
+       friend class LocalRelocationsLinkEditAtom;
+       friend class ExternalRelocationsLinkEditAtom;
+       friend class SymbolTableLinkEditAtom;
+       friend class IndirectTableLinkEditAtom;
+       friend class StringsLinkEditAtom;
+
+       const char*                                                                             fFilePath;
+       Options&                                                                                fOptions;
+       int                                                                                             fFileDescriptor;
+       std::vector<class ObjectFile::Atom*>*                   fAllAtoms;
+       class SectionInfo*                                                              fLoadCommandsSection;
+       class SegmentInfo*                                                              fLoadCommandsSegment;
+       class SegmentLoadCommandsAtom*                                  fSegmentCommands;
+       class SymbolTableLoadCommandsAtom*                              fSymbolTableCommands;
+       class LoadCommandsPaddingAtom*                                  fHeaderPadding;
+       std::vector<class ObjectFile::Atom*>                    fWriterSynthesizedAtoms;
+       std::vector<SegmentInfo*>                                               fSegmentInfos;
+       class ObjectFile::Atom*                                                 fEntryPoint;
+       std::vector<DirectLibrary>                                              fDirectLibraries;
+       std::map<class ObjectFile::Reader*, uint32_t>   fLibraryToOrdinal;
+       std::vector<StabChunks>                                                 fStabChunks;
+       std::vector<class ObjectFile::Atom*>                    fExportedAtoms;
+       std::vector<class ObjectFile::Atom*>                    fImportedAtoms;
+       std::vector<class ObjectFile::Atom*>                    fLocalSymbolAtoms;      
+       LocalRelocationsLinkEditAtom*                                   fLocalRelocationsAtom;
+       ExternalRelocationsLinkEditAtom*                                fExternalRelocationsAtom;
+       SymbolTableLinkEditAtom*                                                fSymbolTableAtom;
+       IndirectTableLinkEditAtom*                                              fIndirectTableAtom;
+       StringsLinkEditAtom*                                                    fStringsAtom;
+       macho_nlist*                                                                    fSymbolTable;
+       //char*                                                                                 fStringPool;
+       //uint32_t                                                                              fStringPoolUsed;
+       //uint32_t                                                                              fStringPoolSize;
+       std::vector<macho_relocation_info>                              fInternalRelocs;
+       std::vector<macho_relocation_info>                              fExternalRelocs;
+       std::vector<IndirectEntry>                                              fIndirectSymbolTable;
+       uint32_t                                                                                fSymbolTableCount;                      
+       uint32_t                                                                                fSymbolTableStabsCount;                 
+       uint32_t                                                                                fSymbolTableStabsStartIndex;                    
+       uint32_t                                                                                fSymbolTableLocalCount;                 
+       uint32_t                                                                                fSymbolTableLocalStartIndex;                    
+       uint32_t                                                                                fSymbolTableExportCount;                        
+       uint32_t                                                                                fSymbolTableExportStartIndex;                   
+       uint32_t                                                                                fSymbolTableImportCount;                        
+       uint32_t                                                                                fSymbolTableImportStartIndex;   
+       bool                                                                                    fEmitVirtualSections;
+       bool                                                                                    fHasWeakExports;
+       bool                                                                                    fReferencesWeakImports;
+};
+
+
+class WriterAtom : public ObjectFile::Atom 
+{
+protected:
+       class Segment;
+public:
+       enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
+                                                                                       WriterAtom(Writer& writer, class WriterAtom::Segment& segment) : fWriter(writer), fSegment(segment) {}
+                                                                                       
+       virtual ObjectFile::Reader*                             getFile() const                                 { return &fWriter; }
+       virtual const char*                                             getName() const                                 { return NULL; }
+       virtual const char*                                             getDisplayName() const                  { return this->getName(); }
+       virtual Scope                                                   getScope() const                                { return ObjectFile::Atom::scopeTranslationUnit; }
+       virtual bool                                                    isTentativeDefinition() const   { return false; }
+       virtual bool                                                    isWeakDefinition() const                { return false; }
+       virtual bool                                                    isCoalesableByName() const              { return false; }
+       virtual bool                                                    isCoalesableByValue() const             { return false; }
+       virtual bool                                                    isZeroFill() const                              { return false; }
+       virtual bool                                                    dontDeadStrip() const                   { return true; }
+       virtual bool                                                    dontStripName() const                   { return false; }
+       virtual bool                                                    isImportProxy() const                   { return false; }
+       virtual std::vector<ObjectFile::Reference*>&  getReferences() const             { return fgEmptyReferenceList; }
+       virtual bool                                                    mustRemainInSection() const             { return true; }
+       virtual ObjectFile::Segment&                    getSegment() const                              { return fSegment; }
+       virtual bool                                                    requiresFollowOnAtom() const    { return false; } 
+       virtual ObjectFile::Atom&                               getFollowOnAtom() const                 { return *((ObjectFile::Atom*)NULL); }
+       virtual std::vector<ObjectFile::StabsInfo>*     getStabsDebugInfo() const       { return NULL; }
+       virtual uint8_t                                                 getAlignment() const                    { return 2; }
+       virtual WeakImportSetting                               getImportWeakness() const               { return Atom::kWeakUnset; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual void                                                    setImportWeakness(bool weakImport) { }
+
+
+protected:
+       virtual                                                                 ~WriterAtom() {}
+       
+       class Segment : public ObjectFile::Segment
+       {
+       public:
+                                                                       Segment(const char* name, bool readable, bool writable, bool executable)
+                                                                                                : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable) {}
+               virtual const char*                     getName() const                                 { return fName; }
+               virtual bool                            isContentReadable() const               { return fReadable; }
+               virtual bool                            isContentWritable() const               { return fWritable; }
+               virtual bool                            isContentExecutable() const             { return fExecutable; }
+       private:
+               const char*                                     fName;
+               const bool                                      fReadable;
+               const bool                                      fWritable;
+               const bool                                      fExecutable;
+       };
+       
+       static std::vector<ObjectFile::Reference*>      fgEmptyReferenceList;
+       static Segment                                                          fgTextSegment;
+       static Segment                                                          fgPageZeroSegment;
+       static Segment                                                          fgLinkEditSegment;
+       static Segment                                                          fgStackSegment;
+       
+       
+       Writer&                                                                 fWriter;
+       Segment&                                                                fSegment;
+};
+
+
+WriterAtom::Segment                                            WriterAtom::fgPageZeroSegment("__PAGEZERO", false, false, false);
+WriterAtom::Segment                                            WriterAtom::fgTextSegment("__TEXT", true, false, true);
+WriterAtom::Segment                                            WriterAtom::fgLinkEditSegment("__LINKEDIT", true, false, false);
+WriterAtom::Segment                                            WriterAtom::fgStackSegment("__UNIXSTACK", true, true, false);
+std::vector<ObjectFile::Reference*>            WriterAtom::fgEmptyReferenceList;
+
+class PageZeroAtom : public WriterAtom 
+{
+public:
+                                                                                       PageZeroAtom(Writer& writer) : WriterAtom(writer, fgPageZeroSegment) {}
+       virtual const char*                                             getDisplayName() const  { return "page zero content"; }
+       virtual bool                                                    isZeroFill() const              { return true; }
+       virtual uint64_t                                                getSize() const                 { return fWriter.fOptions.zeroPageSize(); }
+       virtual const char*                                             getSectionName() const  { return "._zeropage"; }
+       virtual uint8_t                                                 getAlignment() const    { return 12; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
+};
+
+class MachHeaderAtom : public WriterAtom 
+{
+public:
+                                                                                       MachHeaderAtom(Writer& writer)  : WriterAtom(writer, fgTextSegment) {}
+       virtual const char*                                             getName() const;
+       virtual const char*                                             getDisplayName() const;
+       virtual Scope                                                   getScope() const;
+       virtual bool                                                    dontStripName() const;
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const            { return 12; }
+       virtual const char*                                             getSectionName() const          { return "._mach_header"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+};
+
+class CustomStackAtom : public WriterAtom 
+{
+public:
+                                                                                       CustomStackAtom(Writer& writer);
+       virtual const char*                                             getDisplayName() const  { return "custom stack content"; }
+       virtual bool                                                    isZeroFill() const              { return true; }
+       virtual uint64_t                                                getSize() const                 { return fWriter.fOptions.customStackSize(); }
+       virtual const char*                                             getSectionName() const  { return "._stack"; }
+       virtual uint8_t                                                 getAlignment() const    { return 12; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
+};
+
+class SegmentLoadCommandsAtom : public WriterAtom 
+{
+public:
+                                                                                       SegmentLoadCommandsAtom(Writer& writer)  : WriterAtom(writer, fgTextSegment), fCommandCount(0), fSize(0) { writer.fSegmentCommands = this; }
+       virtual const char*                                             getDisplayName() const  { return "segment load commands"; }
+       virtual uint64_t                                                getSize() const                 { return fSize; }
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+       
+       void                                                                    computeSize();
+       void                                                                    setup();
+       unsigned int                                                    commandCount()                  { return fCommandCount; }
+       void                                                                    assignFileOffsets();
+private:
+       unsigned int                                                    fCommandCount;
+       uint32_t                                                                fSize;
+};
+
+class SymbolTableLoadCommandsAtom : public WriterAtom 
+{
+public:
+                                                                                       SymbolTableLoadCommandsAtom(Writer&);
+       virtual const char*                                             getDisplayName() const { return "symbol table load commands"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+       
+private:
+       macho_symtab_command                                    fSymbolTable;
+       macho_dysymtab_command                                  fDynamicSymbolTable;
+};
+
+class ThreadsLoadCommandsAtom : public WriterAtom 
+{
+public:
+                                                                                       ThreadsLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
+       virtual const char*                                             getDisplayName() const { return "thread load commands"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+private:
+       uint8_t*                                                                fBuffer;
+       uint32_t                                                                fBufferSize;
+};
+
+class DyldLoadCommandsAtom : public WriterAtom 
+{
+public:
+                                                                                       DyldLoadCommandsAtom(Writer& writer)  : WriterAtom(writer, fgTextSegment) {}
+       virtual const char*                                             getDisplayName() const  { return "dyld load command"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+};
+
+class DylibLoadCommandsAtom : public WriterAtom 
+{
+public:
+                                                                                       DylibLoadCommandsAtom(Writer& writer, ExecutableFile::DyLibUsed& info)  : WriterAtom(writer, fgTextSegment), fInfo(info) {}
+       virtual const char*                                             getDisplayName() const  { return "dylib load command"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+private:
+       ExecutableFile::DyLibUsed&                              fInfo;
+};
+
+class DylibIDLoadCommandsAtom : public WriterAtom 
+{
+public:
+                                                                                       DylibIDLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
+       virtual const char*                                             getDisplayName() const { return "dylib ID load command"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+};
+
+class RoutinesLoadCommandsAtom : public WriterAtom 
+{
+public:
+                                                                                       RoutinesLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
+       virtual const char*                                             getDisplayName() const { return "routines load command"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+};
+
+class SubUmbrellaLoadCommandsAtom : public WriterAtom 
+{
+public:
+                                                                                       SubUmbrellaLoadCommandsAtom(Writer& writer, const char* name)  : WriterAtom(writer, fgTextSegment), fName(name) {}
+       virtual const char*                                             getDisplayName() const  { return "sub-umbrella load command"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+private:
+       const char*                                                             fName;
+};
+
+class SubLibraryLoadCommandsAtom : public WriterAtom 
+{
+public:
+                                                                                       SubLibraryLoadCommandsAtom(Writer& writer,  const char* nameStart, int nameLen)  
+                                                                                                       : WriterAtom(writer, fgTextSegment), fNameStart(nameStart), fNameLength(nameLen) {}
+       virtual const char*                                             getDisplayName() const  { return "sub-library load command"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+private:
+       const char*                                                             fNameStart;
+       int                                                                             fNameLength;
+};
+
+class UmbrellaLoadCommandsAtom : public WriterAtom 
+{
+public:
+                                                                                       UmbrellaLoadCommandsAtom(Writer& writer, const char* name)  
+                                                                                                       : WriterAtom(writer, fgTextSegment), fName(name) {}
+       virtual const char*                                             getDisplayName() const  { return "umbrella load command"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+private:
+       const char*                                                             fName;
+};
+
+class LoadCommandsPaddingAtom : public WriterAtom 
+{
+public:
+                                                                                       LoadCommandsPaddingAtom(Writer& writer)  
+                                                                                                       : WriterAtom(writer, fgTextSegment), fSize(0) {}
+       virtual const char*                                             getDisplayName() const  { return "header padding"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_cmds_pad"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+       
+       void                                                                    setSize(uint64_t newSize) { fSize = newSize; }
+private:
+       uint64_t                                                                fSize;
+};
+
+class LinkEditAtom : public WriterAtom 
+{
+public:
+                                                                                       LinkEditAtom(Writer& writer) : WriterAtom(writer, fgLinkEditSegment) {}
+       uint64_t                                                                getFileOffset() const;
+};
+
+class LocalRelocationsLinkEditAtom : public LinkEditAtom 
+{
+public:
+                                                                                       LocalRelocationsLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
+       virtual const char*                                             getDisplayName() const  { return "local relocations"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 3; }
+       virtual const char*                                             getSectionName() const  { return "._local_relocs"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+};
+
+class SymbolTableLinkEditAtom : public LinkEditAtom 
+{
+public:
+                                                                                       SymbolTableLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
+       virtual const char*                                             getDisplayName() const  { return "symbol table"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._symbol_table"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+};
+
+class ExternalRelocationsLinkEditAtom : public LinkEditAtom 
+{
+public:
+                                                                                       ExternalRelocationsLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
+       virtual const char*                                             getDisplayName() const  { return "external relocations"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 3; }
+       virtual const char*                                             getSectionName() const  { return "._extern_relocs"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+};
+
+class IndirectTableLinkEditAtom : public LinkEditAtom 
+{
+public:
+                                                                                       IndirectTableLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
+       virtual const char*                                             getDisplayName() const  { return "indirect symbol table"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._indirect_syms"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+};
+
+class StringsLinkEditAtom : public LinkEditAtom 
+{
+public:
+                                                                                       StringsLinkEditAtom(Writer& writer);
+       virtual const char*                                             getDisplayName() const  { return "string pool"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._string_pool"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+       
+       int32_t                                                                 add(const char* name);
+       int32_t                                                                 emptyString();
+       
+private:
+       enum { kBufferSize = 0x01000000 };
+
+       std::vector<char*>                                              fFullBuffers;
+       char*                                                                   fCurrentBuffer;
+       uint32_t                                                                fCurrentBufferUsed;
+};
+
+
+
+class UndefinedSymbolProxyAtom : public WriterAtom 
+{
+public:
+                                                                                       UndefinedSymbolProxyAtom(Writer& writer, const char* name) : WriterAtom(writer, fgLinkEditSegment), fName(name), fWeakImportSetting(Atom::kWeakUnset) {}
+       virtual const char*                                             getName() const                         { return fName; }
+       virtual Scope                                                   getScope() const                        { return ObjectFile::Atom::scopeGlobal; }
+       virtual uint64_t                                                getSize() const                         { return 0; }
+       virtual bool                                                    isWeakDefinition() const        { return true; }
+       virtual bool                                                    isImportProxy() const           { return true; }
+       virtual const char*                                             getSectionName() const          { return "._imports"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
+       virtual WeakImportSetting                               getImportWeakness() const       { return fWeakImportSetting; }
+       virtual void                                                    setImportWeakness(bool weakImport) { fWeakImportSetting = weakImport ? kWeakImport : kNonWeakImport; }
+private:
+       const char*                                                             fName;
+       WeakImportSetting                                               fWeakImportSetting;
+};
+
+
+
+struct ExportSorter
+{
+     bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
+     {
+          return (strcmp(left->getName(), right->getName()) < 0);
+     }
+};
+
+
+ExecutableFile::Writer* MakeWriter(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
+{
+       return new Writer(path, options, dynamicLibraries);
+}
+
+Writer::SectionInfo::SectionInfo()
+ : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0), fIndirectSymbolOffset(0), fAlignment(0),
+       fAllLazyPointers(false), fAllNonLazyPointers(false), fAllZeroFill(false), fVirtualSection(false)
+{
+       fSegmentName[0] = '\0';
+       fSectionName[0] = '\0';
+}
+       
+Writer::SegmentInfo::SegmentInfo()
+ : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0), fBaseAddress(0), fSize(0)
+{
+       fName[0] = '\0';
+}
+
+
+Writer::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
+ : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options), fLoadCommandsSection(NULL), 
+       fLoadCommandsSegment(NULL),
+       //fStringPool(NULL), fStringPoolUsed(0), fStringPoolSize(0), 
+       fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false)
+{
+       int permissions = 0777;
+       if ( fOptions.outputKind() == Options::kObjectFile )
+               permissions = 0666;
+       // Calling unlink first assures the file is gone so that open creates it with correct permissions
+       // It also handles the case where fFilePath file is not writeable but its directory is
+       // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
+       (void)unlink(fFilePath);
+       fFileDescriptor = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);   
+       if ( fFileDescriptor == -1 ) {
+               throw "can't open file for writing";
+       }
+
+       switch ( fOptions.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kStaticExecutable:
+                       fWriterSynthesizedAtoms.push_back(new PageZeroAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this));
+                       if ( fOptions.outputKind() == Options::kDynamicExecutable )
+                               fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom(*this));
+                       if ( fOptions.hasCustomStack() )
+                               fWriterSynthesizedAtoms.push_back(new CustomStackAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this));
+                       break;
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+               case Options::kObjectFile:
+                       fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this));
+                       if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
+                               fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom(*this));
+                               if ( fOptions.initFunctionName() != NULL )
+                                       fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom(*this));
+                       }
+                       fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this));
+                       break;
+               case Options::kDyld:
+                       fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this));
+                       fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this));
+                       break;
+       }
+       
+       // add extra commmands
+       uint8_t ordinal = 1;
+       switch ( fOptions.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+                       {
+                               // add dylib load command atoms for all dynamic libraries
+                               const unsigned int libCount = dynamicLibraries.size();
+                               for (unsigned int i=0; i < libCount; ++i) {
+                                       ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
+                                       if ( dylibInfo.indirect ) {
+                                               // find ordinal of direct reader
+                                               if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) {
+                                                       bool found = false;
+                                                       for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
+                                                               if ( it->first == dylibInfo.directReader ) {
+                                                                       //fprintf(stderr, "ordinal %d for indirect %s\n", it->second, dylibInfo.reader->getPath());
+                                                                       fLibraryToOrdinal[dylibInfo.reader] = it->second;
+                                                                       found = true;
+                                                                       break;
+                                                               }
+                                                       }
+                                                       if ( ! found ) 
+                                                               fprintf(stderr, "ld64 warning: ordinal not found for %s, parent %s\n", dylibInfo.reader->getPath(), dylibInfo.directReader != NULL ? dylibInfo.directReader->getPath() : NULL);
+                                               }
+                                       }
+                                       else {
+                                               // see if a DylibLoadCommandsAtom has already been created for this install path
+                                               bool newDylib = true;
+                                               const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
+                                               if ( dylibInfo.options.fInstallPathOverride != NULL ) 
+                                                       dylibInstallPath = dylibInfo.options.fInstallPathOverride;
+                                               for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
+                                                       ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
+                                                       if ( !seenDylibInfo.indirect ) {
+                                                               const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
+                                                               if ( seenDylibInfo.options.fInstallPathOverride != NULL ) 
+                                                                       seenDylibInstallPath = dylibInfo.options.fInstallPathOverride;
+                                                               if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
+                                                                       fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
+                                                                       newDylib = false;
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                               
+                                               if ( newDylib ) {
+                                                       // assign new ordinal and check for other paired load commands
+                                                       fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
+                                                       fWriterSynthesizedAtoms.push_back(new DylibLoadCommandsAtom(*this, dylibInfo));
+                                                       if ( dylibInfo.options.fReExport ) {
+                                                               // this dylib also needs a sub_x load command
+                                                               bool isFrameworkReExport = false;
+                                                               const char* lastSlash = strrchr(dylibInstallPath, '/');
+                                                               if ( lastSlash != NULL ) {
+                                                                       char frameworkName[strlen(lastSlash)+20];
+                                                                       sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
+                                                                       isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL);
+                                                               }
+                                                               if ( isFrameworkReExport ) {
+                                                                       // needs a LC_SUB_UMBRELLA command
+                                                                       fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom(*this, &lastSlash[1]));
+                                                               }
+                                                               else {
+                                                                       // needs a LC_SUB_LIBRARY command
+                                                                       const char* nameStart = &lastSlash[1];
+                                                                       if ( lastSlash == NULL )
+                                                                               nameStart = dylibInstallPath;
+                                                                       int len = strlen(nameStart);
+                                                                       const char* dot = strchr(nameStart, '.');
+                                                                       if ( dot != NULL )
+                                                                               len = dot - nameStart;
+                                                                       fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom(*this, nameStart, len));
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                               // add umbrella command if needed
+                               if ( fOptions.umbrellaName() != NULL ) {
+                                       fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom(*this, fOptions.umbrellaName()));
+                               }
+                       }
+                       break;
+               case Options::kStaticExecutable:
+               case Options::kObjectFile:
+               case Options::kDyld:
+                       break;
+       }
+       
+       //fprintf(stderr, "ordinals table:\n");
+       //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
+       //      fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
+       //}
+}
+
+Writer::~Writer()
+{
+       if ( fFilePath != NULL )
+               free((void*)fFilePath);
+       if ( fSymbolTable != NULL )
+               delete [] fSymbolTable;
+       //if ( fStringPool != NULL )
+       //      delete [] fStringPool;
+}
+
+const char*     Writer::getPath()
+{
+       return fFilePath;
+}
+
+
+std::vector<class ObjectFile::Atom*>& Writer::getAtoms()
+{
+       return fWriterSynthesizedAtoms;
+}
+
+std::vector<class ObjectFile::Atom*>* Writer::getJustInTimeAtomsFor(const char* name)
+{
+       return NULL;
+}
+
+std::vector<ObjectFile::StabsInfo>*    Writer::getStabsDebugInfo()
+{
+       return NULL;
+}
+
+ObjectFile::Atom* Writer::getUndefinedProxyAtom(const char* name)
+{
+       if ( (fOptions.outputKind() == Options::kObjectFile)
+               || (fOptions.undefinedTreatment() != Options::kUndefinedError) )
+               return new UndefinedSymbolProxyAtom(*this, name);
+       else
+               return NULL;
+}
+
+uint8_t Writer::ordinalForLibrary(ObjectFile::Reader* lib)
+{
+       // flat namespace images use zero for all ordinals
+       if (  fOptions.nameSpace() != Options::kTwoLevelNameSpace )
+               return 0;
+
+       // is an UndefinedSymbolProxyAtom
+       if ( lib == this )
+               if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
+                       return DYNAMIC_LOOKUP_ORDINAL;
+
+       std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
+       if ( pos != fLibraryToOrdinal.end() )
+               return pos->second;
+               
+       throw "can't find ordinal for imported symbol";
+}
+
+void Writer::write(std::vector<class ObjectFile::Atom*>& atoms, class ObjectFile::Atom* entryPointAtom)
+{
+       fAllAtoms =  &atoms;
+       fEntryPoint = entryPointAtom;
+
+       // create SegmentInfo and SectionInfo objects and assign all atoms to a section
+       partitionIntoSections();
+       
+       // segment load command can now be sized and padding can be set
+       adjustLoadCommandsAndPadding();
+       
+       // assign each section a file offset
+       assignFileOffsets();
+       
+       // build symbol table and relocations
+       buildLinkEdit();
+       
+       // write everything
+       writeAtoms();
+}
+
+void Writer::buildLinkEdit()
+{
+       this->collectExportedAndImportedAndLocalAtoms();
+       this->buildSymbolTable();
+       this->buildFixups();
+       this->adjustLinkEditSections();
+}
+
+
+
+uint64_t Writer::getAtomLoadAddress(const ObjectFile::Atom* atom)
+{
+       return atom->getAddress();
+//     SectionInfo* info = (SectionInfo*)atom->getSection();
+//     return info->getBaseAddress() + atom->getSectionOffset();
+}
+
+void Writer::setExportNlist(const ObjectFile::Atom* atom, macho_nlist* entry)
+{
+       // set n_type
+       entry->set_n_type(N_EXT | N_SECT);
+       if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && fOptions.keepPrivateExterns() && (fOptions.outputKind() == Options::kObjectFile) )
+               entry->set_n_type(N_EXT | N_SECT | N_PEXT);
+       
+       // set n_sect (section number of implementation )
+       uint8_t sectionIndex = atom->getSection()->getIndex();
+       entry->set_n_sect(sectionIndex);
+       
+       // the __mh_execute_header is magic and must be an absolute symbol  
+       if ( (fOptions.outputKind() == Options::kDynamicExecutable) && (sectionIndex==0) && atom->dontStripName())
+               entry->set_n_type(N_EXT | N_ABS);
+
+       // set n_desc
+       uint16_t desc = 0;
+       if ( atom->dontStripName() )
+               desc |= REFERENCED_DYNAMICALLY;
+       if ( atom->isWeakDefinition() && (strcmp(atom->getSectionName(), "__common") != 0) ) {
+               desc |= N_WEAK_DEF;
+               fHasWeakExports = true;
+       }
+       entry->set_n_desc(desc);
+       
+       // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
+       entry->set_n_value(this->getAtomLoadAddress(atom));
+}
+
+void Writer::setImportNlist(const ObjectFile::Atom* atom, macho_nlist* entry)
+{
+       // set n_type
+       entry->set_n_type(N_UNDF | N_EXT);
+       
+       // set n_sect
+       entry->set_n_sect(0);
+       
+       uint16_t desc = 0;
+       if ( fOptions.outputKind() != Options::kObjectFile ) {
+               // set n_desc ( high byte is library ordinal, low byte is reference type )
+               desc = REFERENCE_FLAG_UNDEFINED_LAZY; // FIXME
+               try {
+                       uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
+                       SET_LIBRARY_ORDINAL(desc, ordinal);
+               }
+               catch (const char* msg) {
+                       throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
+               }
+       }
+       if ( atom->dontStripName() )
+               desc |= REFERENCED_DYNAMICALLY;
+       // an import proxy is always weak (overridden by definition in .o files)
+       // so we ask its reader if the exported symbol in its dylib is weak
+       if ( ( fOptions.outputKind() != Options::kObjectFile) && atom->getFile()->isDefinitionWeak(*atom) ) {
+               desc |= N_REF_TO_WEAK;
+               fReferencesWeakImports = true;
+       }
+       // set weak_import attribute
+       if ( atom->getImportWeakness() == ObjectFile::Atom::kWeakImport ) 
+               desc |= N_WEAK_REF;
+       entry->set_n_desc(desc);
+       
+       // set n_value, zero for import proxy and size for tentative definition
+       entry->set_n_value(atom->getSize());
+}
+
+void Writer::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist* entry)
+{
+       // set n_type
+       uint8_t type = N_SECT;
+       if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
+               type |= N_PEXT;
+       entry->set_n_type(type);
+       
+       // set n_sect (section number of implementation )
+       uint8_t sectIndex = atom->getSection()->getIndex();
+       if ( sectIndex == 0 ) {
+               // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
+               if ( strcmp(atom->getSectionName(), "._mach_header") == 0 )
+                       sectIndex = 1;
+       }
+       entry->set_n_sect(sectIndex);
+       
+       // set n_desc
+       uint16_t desc = 0;
+       if ( atom->isWeakDefinition() && (strcmp(atom->getSectionName(), "__common") != 0) ) // commons on not weak
+               desc |= N_WEAK_DEF;
+       entry->set_n_desc(desc);
+       
+       // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
+       entry->set_n_value(this->getAtomLoadAddress(atom));
+}
+
+
+void Writer::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
+{
+       macho_nlist* entry = &fSymbolTable[startIndex];
+       for (uint32_t i=0; i < count; ++i, ++entry) {
+               ObjectFile::Atom* atom = atoms[i];
+               entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
+               if ( &atoms == &fExportedAtoms ) {
+                       this->setExportNlist(atom, entry);
+               }
+               else if ( &atoms == &fImportedAtoms ) {
+                       this->setImportNlist(atom, entry);
+               }
+               else {
+                       this->setLocalNlist(atom, entry);
+               }
+       }
+}
+
+void Writer::buildSymbolTable()
+{
+       fSymbolTableStabsStartIndex             = 0;
+       fSymbolTableStabsCount                  = this->collectStabs();
+       fSymbolTableLocalStartIndex             = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
+       fSymbolTableLocalCount                  = fLocalSymbolAtoms.size();
+       fSymbolTableExportStartIndex    = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
+       fSymbolTableExportCount                 = fExportedAtoms.size();
+       fSymbolTableImportStartIndex    = fSymbolTableExportStartIndex + fSymbolTableExportCount;
+       fSymbolTableImportCount                 = fImportedAtoms.size();
+       
+       // allocate symbol table
+       fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
+       fSymbolTable = new macho_nlist[fSymbolTableCount];
+       
+       // fill in symbol table and string pool (do stabs last so strings are at end of pool)
+       setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex,  fSymbolTableLocalCount);
+       setNlistRange(fExportedAtoms,    fSymbolTableExportStartIndex, fSymbolTableExportCount);
+       setNlistRange(fImportedAtoms,    fSymbolTableImportStartIndex, fSymbolTableImportCount);
+       addStabs(fSymbolTableStabsStartIndex, fSymbolTableStabsCount);
+}
+
+
+
+bool Writer::shouldExport(ObjectFile::Atom& atom)
+{
+       switch ( atom.getScope() ) {
+               case ObjectFile::Atom::scopeGlobal:
+                       return true;
+               case ObjectFile::Atom::scopeLinkageUnit:
+                       return ( fOptions.keepPrivateExterns() && (fOptions.outputKind() == Options::kObjectFile) );
+               default:
+                       return false;
+       }
+}
+
+void Writer::collectExportedAndImportedAndLocalAtoms()
+{
+       const int atomCount = fAllAtoms->size();
+       for (int i=0; i < atomCount; ++i) {
+               ObjectFile::Atom* atom = (*fAllAtoms)[i];
+               // only named atoms go in symbol table
+               if ( atom->getName() != NULL ) {
+                       // put atom into correct bucket: imports, exports, locals
+                       //printf("collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
+                       if ( atom->isImportProxy() || ((fOptions.outputKind() == Options::kObjectFile) && (strcmp(atom->getSectionName(), "__common") == 0)) )
+                               fImportedAtoms.push_back(atom);
+                       else if ( this->shouldExport(*atom) )
+                               fExportedAtoms.push_back(atom);
+                       else if ( !fOptions.stripLocalSymbols() )
+                               fLocalSymbolAtoms.push_back(atom);
+               }
+       }
+       
+       // sort exported atoms by name
+       std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), ExportSorter());
+}
+
+
+bool Writer::stabChunkCompare(const struct StabChunks& lhs, const struct StabChunks& rhs)
+{
+       if ( lhs.fReader != rhs.fReader ) {
+               return lhs.fReader < rhs.fReader;
+       }
+       return lhs.fOrderInReader < rhs.fOrderInReader;
+}
+
+unsigned int Writer::collectStabs()
+{      
+       unsigned int count = 0;
+       
+       // collect all stabs chunks
+       std::set<ObjectFile::Reader*> seenReaders;
+       const int atomCount = fAllAtoms->size();
+       for (int i=0; i < atomCount; ++i) {
+               ObjectFile::Atom* atom = (*fAllAtoms)[i];
+               ObjectFile::Reader* atomsReader = atom->getFile();
+               if ( (atomsReader != NULL) && (seenReaders.count(atomsReader) == 0) ) {
+                       seenReaders.insert(atomsReader);
+                       std::vector<ObjectFile::StabsInfo>* readerStabs = atomsReader->getStabsDebugInfo();
+                       if ( readerStabs != NULL ) {
+                               StabChunks chunk;
+                               chunk.fAtom                             = NULL;
+                               chunk.fReader                   = atomsReader;
+                               chunk.fOrderInReader    = 0;
+                               chunk.fStabs                    = readerStabs;
+                               fStabChunks.push_back(chunk);
+                               count += readerStabs->size() + 1; // extra one is for trailing N_SO
+                       }
+               }               
+               std::vector<ObjectFile::StabsInfo>* atomStabs = atom->getStabsDebugInfo();
+               if ( atomStabs != NULL ) {
+                       StabChunks chunk;
+                       chunk.fAtom                             = atom;
+                       chunk.fReader                   = atomsReader;
+                       chunk.fOrderInReader    = atom->getSortOrder();
+                       chunk.fStabs                    = atomStabs;
+                       fStabChunks.push_back(chunk);
+                       count += atomStabs->size();
+               }
+       }
+       
+       // sort by order in original .o file
+       std::sort(fStabChunks.begin(), fStabChunks.end(), stabChunkCompare);
+       
+       return count;
+}
+
+macho_uintptr_t Writer::valueForStab(const ObjectFile::StabsInfo& stab, const ObjectFile::Atom* atom)
+{
+       switch ( stab.type ) {
+               case N_FUN:
+                       if ( stab.other == 0 )
+                               break;
+                       // end of function N_FUN has size (not address) so should not be adjusted
+                       // fall through
+               case N_BNSYM:
+               case N_ENSYM:
+               case N_LBRAC:
+               case N_RBRAC:
+               case N_SLINE:
+               case N_STSYM:
+               case N_LCSYM:
+                       // all these stab types need their value changed from an offset in the atom to an address
+                       if ( atom != NULL )
+                               return getAtomLoadAddress(atom) + stab.atomOffset;
+       }
+       return stab.atomOffset;
+}
+
+void Writer::addStabs(uint32_t startIndex, uint32_t count)
+{
+       macho_nlist* entry = &fSymbolTable[startIndex];
+       const int chunkCount = fStabChunks.size();
+       for (int i=0; i < chunkCount; ++i ) {
+               const StabChunks& chunk = fStabChunks[i];
+               const int stabCount = chunk.fStabs->size();
+               for (int j=0; j < stabCount; ++j ) {
+                       const ObjectFile::StabsInfo& stab = (*chunk.fStabs)[j];
+                       entry->set_n_type(stab.type);
+                       entry->set_n_sect(stab.other);
+                       entry->set_n_desc(stab.desc);
+                       entry->set_n_value(valueForStab(stab, chunk.fAtom));
+                       entry->set_n_strx(this->fStringsAtom->add(stab.string));
+                       ++entry;
+               }       
+               if ( (i == chunkCount-1) || (fStabChunks[i+1].fReader != chunk.fReader) ) {
+                       // need to add empty SO at end of each file
+                       entry->set_n_type(N_SO);
+                       entry->set_n_sect(1);
+                       entry->set_n_desc(0);
+                       entry->set_n_value(0);
+                       entry->set_n_strx(this->fStringsAtom->emptyString());
+                       ++entry;
+               }
+       }
+}
+
+
+
+
+uint32_t Writer::symbolIndex(ObjectFile::Atom& atom)
+{
+       // search imports
+       const int importCount = fImportedAtoms.size();
+       for (int i=0; i < importCount; ++i) {
+               if ( &atom == fImportedAtoms[i] )
+                       return i + fSymbolTableImportStartIndex;
+       }
+       
+       // search locals
+       const int localCount = fLocalSymbolAtoms.size();
+       for (int i=0; i < localCount; ++i) {
+               if ( &atom == fLocalSymbolAtoms[i] )
+                       return i + fSymbolTableLocalStartIndex;
+       }
+       
+       // search exports
+       const int exportCount = fExportedAtoms.size();
+       for (int i=0; i < exportCount; ++i) {
+               if ( &atom == fExportedAtoms[i] )
+                       return i + fSymbolTableExportStartIndex;
+       }
+       
+       fprintf(stderr, "symbolIndex(%s)\n", atom.getDisplayName());
+       fprintf(stderr, "from %s\n", atom.getFile()->getPath());
+       throw "atom not found";
+}
+
+
+void Writer::buildFixups()
+{
+       if ( fOptions.outputKind() == Options::kObjectFile )
+               this->buildObjectFileFixups();
+       else
+               this->buildExecutableFixups();
+}
+
+uint32_t Writer::addRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
+{
+       ObjectFile::Atom& target = ref->getTarget();
+       bool isExtern = target.isImportProxy() || ( strcmp(target.getSectionName(), "__common") == 0 );
+       uint32_t symbolIndex = 0;
+       if ( isExtern ) 
+               symbolIndex = this->symbolIndex(target);
+       uint32_t sectionNum = target.getSection()->getIndex();
+       uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
+       macho_relocation_info reloc1;
+       macho_relocation_info reloc2;
+       macho_scattered_relocation_info* sreloc1 = (macho_scattered_relocation_info*)&reloc1;
+       macho_scattered_relocation_info* sreloc2 = (macho_scattered_relocation_info*)&reloc2;
+       
+       switch ( ref->getKind() ) {
+               case ObjectFile::Reference::noFixUp:
+                       return 0;
+                       
+               case ObjectFile::Reference::pointer:
+                       reloc1.set_r_address(address);
+                       if ( isExtern )
+                               reloc1.set_r_symbolnum(symbolIndex);
+                       else
+                               reloc1.set_r_symbolnum(sectionNum);
+                       reloc1.set_r_pcrel(false);
+                       reloc1.set_r_length(macho_relocation_info::pointer_length); 
+                       reloc1.set_r_extern(isExtern);
+                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                       fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
+                       return 1;
+                       
+               case ObjectFile::Reference::ppcFixupBranch24:
+                       if ( (ref->getTargetOffset() == 0) || isExtern ) {
+                               reloc1.set_r_address(address);
+                               if ( isExtern )
+                                       reloc1.set_r_symbolnum(symbolIndex);
+                               else
+                                       reloc1.set_r_symbolnum(sectionNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(2); 
+                               reloc1.set_r_type(PPC_RELOC_BR24);
+                               reloc1.set_r_extern(isExtern);
+                       } 
+                       else {
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(2); 
+                               sreloc1->set_r_type(PPC_RELOC_BR24);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(target.getAddress());
+                       }
+                       fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
+                       return 1;
+               
+               case ObjectFile::Reference::ppcFixupBranch14:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(sectionNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2); 
+                       reloc1.set_r_extern(false);
+                       reloc1.set_r_type(PPC_RELOC_BR14);
+                       fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
+                       return 1;
+
+               case ObjectFile::Reference::ppcFixupPicBaseLow14:
+               case ObjectFile::Reference::ppcFixupPicBaseLow16:
+                       {
+                               macho_uintptr_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
+                               macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
+                               uint32_t overflow = 0;
+                               if ( ((toAddr-fromAddr) & 0x00008000) != 0 )
+                                       overflow = 1;
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2); 
+                               if ( ref->getKind() == ObjectFile::Reference::ppcFixupPicBaseLow16 )
+                                       sreloc1->set_r_type(PPC_RELOC_LO16_SECTDIFF);
+                               else
+                                       sreloc1->set_r_type(PPC_RELOC_LO14_SECTDIFF);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(target.getAddress());
+                               sreloc2->set_r_scattered(true);
+                               sreloc2->set_r_pcrel(false);
+                               sreloc2->set_r_length(2); 
+                               sreloc2->set_r_type(PPC_RELOC_PAIR);
+                               sreloc2->set_r_address(((toAddr-fromAddr) >> 16));
+                               sreloc2->set_r_value(fromAddr);
+                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
+                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
+                               return 2;
+                       }
+               
+               case ObjectFile::Reference::ppcFixupPicBaseHigh16:
+                       {
+                               macho_uintptr_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
+                               macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2); 
+                               sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(target.getAddress());
+                               sreloc2->set_r_scattered(true);
+                               sreloc2->set_r_pcrel(false);
+                               sreloc2->set_r_length(2); 
+                               sreloc2->set_r_type(PPC_RELOC_PAIR);
+                               sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
+                               sreloc2->set_r_value(fromAddr);
+                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
+                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
+                               return 2;
+                       }
+                       
+               case ObjectFile::Reference::ppcFixupAbsLow14:
+               case ObjectFile::Reference::ppcFixupAbsLow16:
+                       {
+                               macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
+                               if ( (ref->getTargetOffset() == 0) || isExtern ) {
+                                       reloc1.set_r_address(address);
+                                       if ( isExtern )
+                                               reloc1.set_r_symbolnum(symbolIndex);
+                                       else
+                                               reloc1.set_r_symbolnum(sectionNum);
+                                       reloc1.set_r_pcrel(false);
+                                       reloc1.set_r_length(2); 
+                                       reloc1.set_r_extern(isExtern);
+                                       if ( ref->getKind() == ObjectFile::Reference::ppcFixupAbsLow16 )
+                                               reloc1.set_r_type(PPC_RELOC_LO16);
+                                       else
+                                               reloc1.set_r_type(PPC_RELOC_LO14);
+                               }
+                               else {
+                                       sreloc1->set_r_scattered(true);
+                                       sreloc1->set_r_pcrel(false);
+                                       sreloc1->set_r_length(2); 
+                                       if ( ref->getKind() == ObjectFile::Reference::ppcFixupAbsLow16 )
+                                               sreloc1->set_r_type(PPC_RELOC_LO16);
+                                       else
+                                               sreloc1->set_r_type(PPC_RELOC_LO14);
+                                       sreloc1->set_r_address(address);
+                                       sreloc1->set_r_value(target.getAddress());
+                               }
+                               if ( isExtern )
+                                       reloc2.set_r_address(ref->getTargetOffset() >> 16); 
+                               else
+                                       reloc2.set_r_address(toAddr >> 16);  
+                               reloc2.set_r_symbolnum(0);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2); 
+                               reloc2.set_r_extern(false);
+                               reloc2.set_r_type(PPC_RELOC_PAIR);
+                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
+                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
+                               return 2;
+                       }
+                       
+               case ObjectFile::Reference::ppcFixupAbsHigh16:
+                       {
+                               macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
+                               if ( (ref->getTargetOffset() == 0) || isExtern ) {
+                                       reloc1.set_r_address(address);
+                                       if ( isExtern )
+                                               reloc1.set_r_symbolnum(symbolIndex);
+                                       else
+                                               reloc1.set_r_symbolnum(sectionNum);
+                                       reloc1.set_r_pcrel(false);
+                                       reloc1.set_r_length(2); 
+                                       reloc1.set_r_extern(isExtern);
+                                       reloc1.set_r_type(PPC_RELOC_HI16);
+                               }
+                               else {
+                                       sreloc1->set_r_scattered(true);
+                                       sreloc1->set_r_pcrel(false);
+                                       sreloc1->set_r_length(2); 
+                                       sreloc1->set_r_type(PPC_RELOC_HI16);
+                                       sreloc1->set_r_address(address);
+                                       sreloc1->set_r_value(target.getAddress());
+                               }
+                               if ( isExtern )
+                                       reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF); 
+                               else
+                                       reloc2.set_r_address(toAddr & 0xFFFF);  
+                               reloc2.set_r_symbolnum(0);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2); 
+                               reloc2.set_r_extern(false);
+                               reloc2.set_r_type(PPC_RELOC_PAIR);
+                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
+                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
+                               return 2;
+                       }
+               
+               case ObjectFile::Reference::ppcFixupAbsHigh16AddLow:
+                       {
+                               macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
+                               uint32_t overflow = 0;
+                               if ( (toAddr & 0x00008000) != 0 )
+                                       overflow = 0x10000;
+                               if ( (ref->getTargetOffset() == 0) || isExtern ) {
+                                       reloc1.set_r_address(address);
+                                       if ( isExtern )
+                                               reloc1.set_r_symbolnum(symbolIndex);
+                                       else
+                                               reloc1.set_r_symbolnum(sectionNum);
+                                       reloc1.set_r_pcrel(false);
+                                       reloc1.set_r_length(2); 
+                                       reloc1.set_r_extern(isExtern);
+                                       reloc1.set_r_type(PPC_RELOC_HA16);
+                               }
+                               else {
+                                       sreloc1->set_r_scattered(true);
+                                       sreloc1->set_r_pcrel(false);
+                                       sreloc1->set_r_length(2); 
+                                       sreloc1->set_r_type(PPC_RELOC_HA16);
+                                       sreloc1->set_r_address(address);
+                                       sreloc1->set_r_value(target.getAddress());
+                               }
+                               if ( isExtern )
+                                       reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF); 
+                               else
+                                       reloc2.set_r_address(toAddr & 0xFFFF);  
+                               reloc2.set_r_symbolnum(0);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2); 
+                               reloc2.set_r_extern(false);
+                               reloc2.set_r_type(PPC_RELOC_PAIR);
+                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
+                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
+                               return 2;
+                       }
+               
+               case ObjectFile::Reference::pointer32Difference:
+               case ObjectFile::Reference::pointer64Difference:
+                       {
+                               macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
+                               macho_uintptr_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               if ( ref->getKind() == ObjectFile::Reference::pointer64Difference )
+                                       sreloc1->set_r_length(3); 
+                               else
+                                       sreloc1->set_r_length(2); 
+                               if ( ref->getTargetOffset() != 0 )
+                                       sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF); 
+                               else
+                                       sreloc1->set_r_type(PPC_RELOC_SECTDIFF); 
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(toAddr);
+                               sreloc2->set_r_scattered(true);
+                               sreloc2->set_r_pcrel(false);
+                               sreloc2->set_r_length(macho_relocation_info::pointer_length); 
+                               sreloc2->set_r_type(PPC_RELOC_PAIR);
+                               sreloc2->set_r_address(0);
+                               sreloc2->set_r_value(fromAddr);
+                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
+                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
+                               return 2;
+                       }
+                       
+               case ObjectFile::Reference::x86FixupBranch32:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(sectionNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2); 
+                       reloc1.set_r_extern(false);
+                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                       fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
+                       return 1;
+               
+       }
+       return 0;
+}
+
+
+void Writer::buildObjectFileFixups()
+{
+       uint32_t relocIndex = 0;
+       std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
+       const int segCount = segmentInfos.size();
+       for(int i=0; i < segCount; ++i) {
+               SegmentInfo* curSegment = segmentInfos[i];
+               std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
+               const int sectionCount = sectionInfos.size();
+               for(int j=0; j < sectionCount; ++j) {
+                       SectionInfo* curSection = sectionInfos[j];
+                       std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
+                       if ( ! curSection->fAllZeroFill ) {
+                               if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers )
+                                       curSection->fIndirectSymbolOffset = fIndirectSymbolTable.size();
+                               curSection->fRelocOffset = relocIndex;
+                               const int atomCount = sectionAtoms.size();
+                               for (int k=0; k < atomCount; ++k) {
+                                       ObjectFile::Atom* atom = sectionAtoms[k];
+                                       std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
+                                       const int refCount = refs.size();
+                                       for (int l=0; l < refCount; ++l) {
+                                               ObjectFile::Reference* ref = refs[l];
+                                               relocIndex += this->addRelocs(atom, ref);
+                                               if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
+                                                       uint32_t offsetInSection = atom->getSectionOffset();
+                                                       uint32_t indexInSection = offsetInSection / sizeof(macho_uintptr_t);    
+                                                       uint32_t undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
+                                                       uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
+                                                       IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
+                                                       //printf("fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
+                                                       fIndirectSymbolTable.push_back(entry);
+                                               }
+                                       }
+                               }
+                               curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
+                       }
+               }
+       }
+       
+       // now reverse reloc entries
+       for(int i=0; i < segCount; ++i) {
+               SegmentInfo* curSegment = segmentInfos[i];
+               std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
+               const int sectionCount = sectionInfos.size();
+               for(int j=0; j < sectionCount; ++j) {
+                       SectionInfo* curSection = sectionInfos[j];
+                       curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount; 
+               }
+       }
+       
+}
+
+
+void Writer::buildExecutableFixups()
+{
+       const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
+       std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
+       const int segCount = segmentInfos.size();
+       for(int i=0; i < segCount; ++i) {
+               SegmentInfo* curSegment = segmentInfos[i];
+               std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
+               const int sectionCount = sectionInfos.size();
+               for(int j=0; j < sectionCount; ++j) {
+                       SectionInfo* curSection = sectionInfos[j];
+                       std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
+                       if ( ! curSection->fAllZeroFill ) {
+                               if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers )
+                                       curSection->fIndirectSymbolOffset = fIndirectSymbolTable.size();
+                               const int atomCount = sectionAtoms.size();
+                               for (int k=0; k < atomCount; ++k) {
+                                       ObjectFile::Atom* atom = sectionAtoms[k];
+                                       std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
+                                       const int refCount = refs.size();
+                                       //printf("atom %s has %d references\n", atom->getDisplayName(), refCount);
+                                                                       
+                                       for (int l=0; l < refCount; ++l) {
+                                               ObjectFile::Reference* ref = refs[l];
+                                               // only care about references that need dyld fixups
+                                               if ( ref->requiresRuntimeFixUp() ) {
+                                                       if ( ! atom->getSegment().isContentWritable() )
+                                                               throwf("relocations in read-only segments not supported. %s in %s reference to %s", atom->getDisplayName(), atom->getFile()->getPath(), ref->getTarget().getDisplayName());
+                                                       if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
+                                                               // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
+                                                               if ( atom->getSize() != sizeof(macho_uintptr_t) ) {
+                                                                       printf("oversize pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
+                                                               }
+                                                               uint32_t offsetInSection = atom->getSectionOffset();
+                                                               uint32_t indexInSection = offsetInSection / sizeof(macho_uintptr_t);    
+                                                               uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
+                                                               //printf("indirect pointer atom %s section offset = %d\n", atom->getDisplayName(), offsetInSection);
+                                                               if ( ref->getTarget().isImportProxy() 
+                                                                 || ref->getTarget().isWeakDefinition() 
+                                                                 || (fOptions.interposable() && fOptions.shouldExport(ref->getTarget().getName()))
+                                                                 || (fOptions.nameSpace() == Options::kFlatNameSpace) 
+                                                                 || (fOptions.nameSpace() == Options::kForceFlatNameSpace) ) {
+                                                                       undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
+                                                               }
+                                                               uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
+                                                               IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
+                                                               //printf("fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
+                                                               fIndirectSymbolTable.push_back(entry);
+                                                               if ( slideable && curSection->fAllLazyPointers ) {
+                                                                       // if this is a dylib/bundle, need PBLAPTR internal relocation to fix up binding handler if image slides
+                                                                       macho_relocation_info pblaReloc;
+                                                                       macho_scattered_relocation_info* pblaSReloc = (macho_scattered_relocation_info*)&pblaReloc;
+                                                                       pblaSReloc->set_r_scattered(true);
+                                                                       pblaSReloc->set_r_pcrel(false);
+                                                                       pblaSReloc->set_r_length(macho_relocation_info::pointer_length); 
+                                                                       pblaSReloc->set_r_type(PPC_RELOC_PB_LA_PTR);
+                                                                       pblaSReloc->set_r_address(atom->getAddress()-fOptions.baseAddress());
+                                                                       pblaSReloc->set_r_value(ref->getFromTarget().getAddress()); // helper is stored in "from" address
+                                                                       fInternalRelocs.push_back(pblaReloc);
+                                                               }
+                                                       }
+                                                       else if ( ref->getTarget().isImportProxy() ) {
+                                                               // if import is to antoher dylib, this is encoded as an external relocation
+                                                               macho_relocation_info externalReloc;
+                                                               externalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
+                                                               externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
+                                                               externalReloc.set_r_pcrel(false);
+                                                               externalReloc.set_r_length(macho_relocation_info::pointer_length); 
+                                                               externalReloc.set_r_extern(true);
+                                                               externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
+                                                               fExternalRelocs.push_back(externalReloc);
+                                                       }
+                                                       else if ( slideable ) {
+                                                               // if this is a dylib/bundle, need fix-up encoded as an internal relocation
+                                                               macho_relocation_info internalReloc;
+                                                               SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
+                                                               uint32_t sectionNum = sectInfo->getIndex();
+                                                               // special case _mh_dylib_header and friends which are not in any real section
+                                                               if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) ) 
+                                                                       sectionNum = 1;
+                                                               internalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
+                                                               internalReloc.set_r_symbolnum(sectionNum);
+                                                               internalReloc.set_r_pcrel(false);
+                                                               internalReloc.set_r_length(macho_relocation_info::pointer_length); 
+                                                               internalReloc.set_r_extern(false);
+                                                               internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
+                                                               fInternalRelocs.push_back(internalReloc);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+class ContentWriter : public ObjectFile::ContentWriter
+{
+public:
+                                       ContentWriter(int fd, uint64_t fileOffset) : fFileDescriptor(fd), fFileOffset(fileOffset) {}
+       virtual void    write(uint64_t atomOffset, const void* buffer, uint64_t size) {
+               ::pwrite(fFileDescriptor, buffer, size, fFileOffset+atomOffset);
+       }
+private:
+       int                     fFileDescriptor;
+       uint64_t        fFileOffset;
+};
+
+
+void Writer::writeAtoms()
+{
+       const bool requireAllFixUps = (fOptions.outputKind() != Options::kObjectFile);
+
+       std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
+       const int segCount = segmentInfos.size();
+       for(int i=0; i < segCount; ++i) {
+               SegmentInfo* curSegment = segmentInfos[i];
+               bool isText = ((curSegment->fInitProtection & VM_PROT_EXECUTE) != 0);
+               std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
+               const int sectionCount = sectionInfos.size();
+               for(int j=0; j < sectionCount; ++j) {
+                       SectionInfo* curSection = sectionInfos[j];
+                       std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
+                       //printf("writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName);
+                       if ( ! curSection->fAllZeroFill ) {
+                               const int atomCount = sectionAtoms.size();
+                               uint32_t end = curSection->fFileOffset;
+                               for (int k=0; k < atomCount; ++k) {
+                                       ObjectFile::Atom* atom = sectionAtoms[k];
+                                       if ( !atom->isImportProxy() ) {
+                                               uint32_t offset = curSection->fFileOffset + atom->getSectionOffset();
+                                               if ( isText && (offset != end) ) {
+                                                       // fill gaps with no-ops
+                       #if defined(ARCH_PPC) || defined(ARCH_PPC64) 
+                                                       uint32_t ppcNop;
+                                                       OSWriteBigInt32(&ppcNop, 0, 0x60000000);
+                                                       for (uint32_t p=end; p < offset; p += 4)
+                                                               ::pwrite(fFileDescriptor, &ppcNop, 4, p);
+                       #else  defined(ARCH_I386)
+                                                       uint8_t x86Nop = 0x90;
+                                                       for (uint32_t p=end; p < offset; ++p)
+                                                               ::pwrite(fFileDescriptor, &x86Nop, 1, p);
+                       #endif
+                                               }
+                                               ContentWriter writer(fFileDescriptor, offset);
+                                               atom->writeContent(requireAllFixUps, writer);
+                                               end = offset+atom->getSize();
+                                               //printf("wrote 0x%08X -> 0x%08X, atom %s\n", offset, end, atom->getDisplayName());
+                                       }
+                               }
+                       }
+               }
+       }
+}      
+
+
+void Writer::partitionIntoSections()
+{
+       const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
+       
+       // for every atom, set its sectionInfo object and section offset
+       // build up fSegmentInfos along the way
+       ObjectFile::Section* curSection = NULL;
+       SectionInfo* currentSectionInfo = NULL;
+       SegmentInfo* currentSegmentInfo = NULL;
+       unsigned int sectionIndex = 1;
+       for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
+               ObjectFile::Atom* atom = (*fAllAtoms)[i];
+               if ( atom->getSection() != curSection ) {
+                       if ( oneSegmentCommand ) {
+                               if ( currentSegmentInfo == NULL ) {
+                                       currentSegmentInfo = new SegmentInfo();
+                                       currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+                                       currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+                                       this->fSegmentInfos.push_back(currentSegmentInfo);
+                               }
+                               currentSectionInfo = new SectionInfo();
+                               strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
+                               strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
+                               currentSectionInfo->fAlignment = atom->getAlignment();
+                               currentSectionInfo->fAllZeroFill = atom->isZeroFill();
+                               currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
+                               if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
+                                       currentSectionInfo->setIndex(sectionIndex++);
+                               currentSegmentInfo->fSections.push_back(currentSectionInfo);
+                       }
+                       else {
+                               if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
+                                       currentSegmentInfo = new SegmentInfo();
+                                       strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
+                                       uint32_t initprot  = 0;
+                                       if ( atom->getSegment().isContentReadable() )
+                                               initprot |= VM_PROT_READ;
+                                       if ( atom->getSegment().isContentWritable() )
+                                               initprot |= VM_PROT_WRITE;
+                                       if ( atom->getSegment().isContentExecutable() )
+                                               initprot |= VM_PROT_EXECUTE;
+                                       currentSegmentInfo->fInitProtection = initprot;
+                                       if ( initprot == 0 )
+                                               currentSegmentInfo->fMaxProtection = 0;  // pagezero should have maxprot==initprot==0
+                                       else
+                                               currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+                                       currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
+                                       this->fSegmentInfos.push_back(currentSegmentInfo);
+                               }
+                               currentSectionInfo = new SectionInfo();
+                               strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
+                               strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
+                               currentSectionInfo->fAlignment = atom->getAlignment();
+                               // check for -sectalign override
+                               std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
+                               for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
+                                       if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
+                                               currentSectionInfo->fAlignment = it->alignment;
+                               }
+                               currentSectionInfo->fAllZeroFill = atom->isZeroFill();
+                               currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
+                               if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
+                                       currentSectionInfo->setIndex(sectionIndex++);
+                               currentSegmentInfo->fSections.push_back(currentSectionInfo);
+                       }
+                       if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) {
+                               fLoadCommandsSection = currentSectionInfo;
+                               fLoadCommandsSegment = currentSegmentInfo;
+                       }
+                       if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
+                               currentSectionInfo->fAllLazyPointers = true;
+                       if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
+                               currentSectionInfo->fAllNonLazyPointers = true;
+                       curSection = atom->getSection();
+               }
+               // any non-zero fill atoms make whole section marked not-zero-fill
+               if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
+                       currentSectionInfo->fAllZeroFill = false;
+               // change section object to be Writer's SectionInfo object
+               atom->setSection(currentSectionInfo);
+               // section alignment is that of a contained atom with the greatest alignment
+               uint8_t atomAlign = atom->getAlignment();
+               if ( currentSectionInfo->fAlignment < atomAlign )
+                       currentSectionInfo->fAlignment = atomAlign;
+               // calculate section offset for this atom
+               uint64_t offset = currentSectionInfo->fSize;
+               uint64_t alignment = 1 << atomAlign;
+               offset = ( (offset+alignment-1) & (-alignment) );
+               atom->setSectionOffset(offset);
+               currentSectionInfo->fSize = offset + atom->getSize();
+               // add atom to section vector
+               currentSectionInfo->fAtoms.push_back(atom);
+       }
+}
+
+
+void Writer::adjustLoadCommandsAndPadding()
+{
+       fSegmentCommands->computeSize();
+       
+       // recompute load command section offsets
+       uint64_t offset = 0;
+       std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
+       const unsigned int atomCount = loadCommandAtoms.size();
+       for (unsigned int i=0; i < atomCount; ++i) {
+               ObjectFile::Atom* atom = loadCommandAtoms[i];
+               uint64_t alignment = 1 << atom->getAlignment();
+               offset = ( (offset+alignment-1) & (-alignment) );
+               atom->setSectionOffset(offset);
+               offset += atom->getSize();
+               fLoadCommandsSection->fSize = offset;
+       }
+       
+       std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
+       const int sectionCount = sectionInfos.size();
+       uint64_t paddingSize = 0;
+       if ( fOptions.outputKind() == Options::kDyld ) {
+               // dyld itself has special padding requirements.  We want the beginning __text section to start at a stable address
+               uint32_t totalSizeOfHeaderAndLoadCommands = 0;
+               for(int j=0; j < sectionCount; ++j) {
+                       SectionInfo* curSection = sectionInfos[j];
+                       totalSizeOfHeaderAndLoadCommands += curSection->fSize;
+                       if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
+                               break;
+               }
+               paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
+       }
+       else {
+               // calculate max padding to keep segment size same, but all free space at end of load commands
+               uint64_t totalSize = 0;
+               uint64_t worstCaseAlignmentPadding = 0;
+               for(int j=0; j < sectionCount; ++j) {
+                       SectionInfo* curSection = sectionInfos[j];
+                       totalSize += curSection->fSize;
+                       if ( j != 0 ) // don't count aligment of mach_header which is page-aligned
+                               worstCaseAlignmentPadding += (1 << curSection->fAlignment) - 1;
+               }
+               uint64_t segmentSize = ((totalSize+worstCaseAlignmentPadding+4095) & (-4096));
+               // don't know exactly how it will layout, but we can inflate padding atom this big and still keep aligment constraints
+               paddingSize = segmentSize - totalSize;
+               
+               // if command line requires more padding than this
+               if ( paddingSize < fOptions.minimumHeaderPad() ) {
+                       int extraPages = (fOptions.minimumHeaderPad() - paddingSize + 4095)/4096;
+                       paddingSize += extraPages * 4096;
+               }
+       }
+       
+       // adjust atom size and update section size
+       fHeaderPadding->setSize(paddingSize);
+       for(int j=0; j < sectionCount; ++j) {
+               SectionInfo* curSection = sectionInfos[j];
+               if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
+                       curSection->fSize = paddingSize;
+       }
+}
+
+// assign file offsets and logical address to all segments
+void Writer::assignFileOffsets()
+{
+       bool haveFixedSegments = false;
+       uint64_t fileOffset = 0;
+       uint64_t nextContiguousAddress = fOptions.baseAddress();
+       std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
+       const int segCount = segmentInfos.size();
+       for(int i=0; i < segCount; ++i) {
+               SegmentInfo* curSegment = segmentInfos[i];
+               fileOffset = (fileOffset+4095) & (-4096);
+               curSegment->fFileOffset = fileOffset;
+               if ( curSegment->fBaseAddress == 0 ) {
+                       // segment has uses next address
+                       curSegment->fBaseAddress = nextContiguousAddress;
+               }
+               else {
+                       // segment has fixed address
+                       haveFixedSegments = true;
+               }
+               uint64_t address = curSegment->fBaseAddress;
+               std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
+               const int sectionCount = sectionInfos.size();
+               for(int j=0; j < sectionCount; ++j) {
+                       SectionInfo* curSection = sectionInfos[j];
+                       uint64_t alignment = 1 << curSection->fAlignment;
+                       fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
+                       address    = ( (address+alignment-1)    & (-alignment) );
+                       curSection->fFileOffset = fileOffset;
+                       curSection->setBaseAddress(address);
+                       //printf("assignFileOffsets(): setBaseAddress(%s, 0x%08llX)\n", curSection->fSectionName, address);
+                       curSegment->fSize = curSection->getBaseAddress() + curSection->fSize - curSegment->fBaseAddress;
+                       if ( (fOptions.outputKind() != Options::kObjectFile) || ! curSection->fVirtualSection )
+                               address += curSection->fSize;
+                       if ( !curSection->fAllZeroFill ) {
+                               curSegment->fFileSize = curSegment->fSize;
+                               fileOffset += curSection->fSize;
+                       }
+               }
+               if ( curSegment->fBaseAddress == nextContiguousAddress )
+                       nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
+       }
+       
+       // check for segment overlaps
+       if ( haveFixedSegments ) {
+               for(int i=0; i < segCount; ++i) {
+                       SegmentInfo* segment1 = segmentInfos[i];
+                       for(int j=0; j < segCount; ++j) {
+                               if ( i != j ) {
+                                       SegmentInfo* segment2 = segmentInfos[j];
+                                       if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
+                                               if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
+                                                       throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)", 
+                                                               segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
+                                       }
+                                       else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
+                                               if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
+                                                       throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)", 
+                                                               segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
+                                       }
+                                       else {
+                                                       throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)", 
+                                                               segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+void Writer::adjustLinkEditSections()
+{
+       // link edit content is always in last segment
+       SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
+       unsigned int firstLinkEditSectionIndex = 0;
+       while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
+               ++firstLinkEditSectionIndex;
+       
+       const unsigned int sectionCount = lastSeg->fSections.size();
+       uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
+       uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
+       for (unsigned int i=firstLinkEditSectionIndex; i < sectionCount; ++i) {
+               std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
+               const unsigned int atomCount = atoms.size();
+               uint64_t sectionOffset = 0;
+               lastSeg->fSections[i]->fFileOffset = fileOffset;
+               lastSeg->fSections[i]->setBaseAddress(address);
+               for (unsigned int j=0; j < atomCount; ++j) {
+                       ObjectFile::Atom* atom = atoms[j];
+                       uint64_t alignment = 1 << atom->getAlignment();
+                       sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
+                       atom->setSectionOffset(sectionOffset);
+                       sectionOffset += atom->getSize();
+               }
+               lastSeg->fSections[i]->fSize = sectionOffset;
+               fileOffset += sectionOffset;
+               address += sectionOffset;
+       }
+       if ( fOptions.outputKind() == Options::kObjectFile ) {
+               
+               //lastSeg->fBaseAddress = 0;
+               //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
+               //lastSeg->fFileOffset = 0;
+               //lastSeg->fFileSize =
+       }
+       else {
+               lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
+               lastSeg->fSize = address - lastSeg->fBaseAddress;
+       }
+}
+
+
+ObjectFile::Atom::Scope MachHeaderAtom::getScope() const
+{ 
+       switch ( fWriter.fOptions.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kStaticExecutable:
+                       return ObjectFile::Atom::scopeGlobal; 
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+               case Options::kDyld:
+               case Options::kObjectFile:
+                       return ObjectFile::Atom::scopeLinkageUnit; 
+       }
+       throw "unknown header type";
+}
+
+bool MachHeaderAtom::dontStripName() const
+{ 
+       switch ( fWriter.fOptions.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kStaticExecutable:
+                       return true; 
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+               case Options::kDyld:
+               case Options::kObjectFile:
+                       return false; 
+       }
+       throw "unknown header type";
+}
+
+const char* MachHeaderAtom::getName() const
+{
+       switch ( fWriter.fOptions.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kStaticExecutable:
+                       return "__mh_execute_header";
+               case Options::kDynamicLibrary:
+                       return "__mh_dylib_header";
+               case Options::kDynamicBundle:
+                       return "__mh_bundle_header";
+               case Options::kObjectFile:
+                       return NULL;
+               case Options::kDyld:
+                       return "__mh_dylinker_header";
+       }
+       throw "unknown header type";
+}
+
+const char* MachHeaderAtom::getDisplayName() const
+{
+       switch ( fWriter.fOptions.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kStaticExecutable:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+               case Options::kDyld:
+                       return this->getName();
+               case Options::kObjectFile:
+                       return "mach header";
+       }
+       throw "unknown header type";
+}
+
+uint64_t MachHeaderAtom::getSize() const
+{
+       return macho_header::size;
+}
+
+void MachHeaderAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       macho_header mh;
+
+       // get file type
+       uint32_t fileType = 0;
+       switch ( fWriter.fOptions.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kStaticExecutable:
+                       fileType = MH_EXECUTE;
+                       break;
+               case Options::kDynamicLibrary:
+                       fileType = MH_DYLIB;
+                       break;
+               case Options::kDynamicBundle:
+                       fileType = MH_BUNDLE;
+                       break;
+               case Options::kObjectFile:
+                       fileType = MH_OBJECT;
+                       break;
+               case Options::kDyld:
+                       fileType = MH_DYLINKER;
+                       break;
+       }
+
+       // get flags
+       uint32_t flags = 0;
+       if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
+               flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+       }
+       else {
+               flags = MH_DYLDLINK;
+               if ( fWriter.fOptions.bindAtLoad() )
+                       flags |= MH_BINDATLOAD;
+               switch ( fWriter.fOptions.nameSpace() ) {
+                       case Options::kTwoLevelNameSpace:
+                               flags |= MH_TWOLEVEL | MH_NOUNDEFS;
+                               break;
+                       case Options::kFlatNameSpace:
+                               break;
+                       case Options::kForceFlatNameSpace:
+                               flags |= MH_FORCE_FLAT;
+                               break;
+               }
+               if ( fWriter.fHasWeakExports ) 
+                       flags |= MH_WEAK_DEFINES;
+               if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
+                       flags |= MH_BINDS_TO_WEAK;
+       }
+       
+       // get commands info
+       uint32_t commandsSize = 0;
+       uint32_t commandsCount = 0;
+       
+       std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
+       const unsigned int atomCount = loadCommandAtoms.size();
+       for (unsigned int i=0; i < atomCount; ++i) {
+               ObjectFile::Atom* atom = loadCommandAtoms[i];
+               commandsSize += atom->getSize();
+               // segment and symbol table atoms can contain more than one load command
+               if ( atom == fWriter.fSegmentCommands )
+                       commandsCount += fWriter.fSegmentCommands->commandCount();
+               else if ( atom == fWriter.fSymbolTableCommands )
+                       commandsCount += 2;
+               else
+                       ++commandsCount;
+       }
+       
+       // fill out mach_header
+       mh.set_magic(macho_header::magic_value);
+       mh.set_cputype(fWriter.fOptions.architecture());
+       mh.set_cpusubtype(0);
+       mh.set_filetype(fileType);
+       mh.set_ncmds(commandsCount);            
+       mh.set_sizeofcmds(commandsSize);        
+       mh.set_flags(flags);
+       mh.set_reserved();
+       
+       // write it
+       writer.write(0, &mh, macho_header::size);
+}
+
+
+CustomStackAtom::CustomStackAtom(Writer& writer) 
+ : WriterAtom(writer, fgStackSegment)
+{
+#if defined(ARCH_PPC) || defined(ARCH_PPC64) || defined(ARCH_I386)
+       // stack grows down for these architectures
+       fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
+#else
+       #error unknown architecture
+#endif
+}
+
+
+void SegmentLoadCommandsAtom::computeSize() 
+{
+       uint64_t size = 0;
+       std::vector<Writer::SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
+       const int segCount = segmentInfos.size();
+       for(int i=0; i < segCount; ++i) {
+               size += macho_segment_command::size;
+               std::vector<Writer::SectionInfo*>& sectionInfos = segmentInfos[i]->fSections;
+               const int sectionCount = sectionInfos.size();           
+               for(int j=0; j < sectionCount; ++j) {
+                       if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
+                               size += macho_section::content_size;
+               }
+       }
+       fSize = size;
+       fCommandCount = segCount;
+}
+
+
+
+void SegmentLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       uint64_t size = this->getSize();
+       uint8_t buffer[size];
+       const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
+       bzero(buffer, fSize);
+       uint8_t* p = buffer;
+       std::vector<Writer::SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
+       const int segCount = segmentInfos.size();
+       for(int i=0; i < segCount; ++i) {
+               Writer::SegmentInfo* segInfo = segmentInfos[i];
+               const int sectionCount = segInfo->fSections.size();
+               macho_segment_command* cmd = (macho_segment_command*)p;
+               cmd->set_cmd(macho_segment_command::command);
+               cmd->set_segname(segInfo->fName);
+               cmd->set_vmaddr(segInfo->fBaseAddress);
+               cmd->set_vmsize(segInfo->fSize);
+               cmd->set_fileoff(segInfo->fFileOffset);
+               cmd->set_filesize(segInfo->fFileSize);
+               cmd->set_maxprot(segInfo->fMaxProtection);
+               cmd->set_initprot(segInfo->fInitProtection);
+               // add sections array
+               macho_section* const sections = (macho_section*)&p[macho_segment_command::size];
+               unsigned int sectionsEmitted = 0;
+               for (int j=0; j < sectionCount; ++j) {
+                       Writer::SectionInfo* sectInfo = segInfo->fSections[j];
+                       if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
+                               macho_section* sect = &sections[sectionsEmitted++];
+                               if ( oneSegment ) {
+                                       // .o files have weird segment range
+                                       if ( sectionsEmitted == 1 ) {
+                                               cmd->set_vmaddr(sectInfo->getBaseAddress());
+                                               cmd->set_fileoff(sectInfo->fFileOffset);
+                                               cmd->set_filesize(segInfo->fFileSize-sectInfo->fFileOffset);
+                                       }
+                                       cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
+                               }
+                               sect->set_sectname(sectInfo->fSectionName);
+                               sect->set_segname(sectInfo->fSegmentName);
+                               sect->set_addr(sectInfo->getBaseAddress());
+                               sect->set_size(sectInfo->fSize);
+                               sect->set_offset(sectInfo->fFileOffset);
+                               sect->set_align(sectInfo->fAlignment);
+                               if ( sectInfo->fRelocCount != 0 ) {
+                                       sect->set_reloff(sectInfo->fRelocOffset * macho_relocation_info::size + fWriter.fLocalRelocationsAtom->getFileOffset());
+                                       sect->set_nreloc(sectInfo->fRelocCount);
+                               }
+                               if ( sectInfo->fAllZeroFill ) {
+                                       sect->set_flags(S_ZEROFILL);
+                               }
+                               else if ( sectInfo->fAllLazyPointers ) {
+                                       sect->set_flags(S_LAZY_SYMBOL_POINTERS);
+                                       sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
+                               }
+                               else if ( sectInfo->fAllNonLazyPointers ) {
+                                       sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
+                                       sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
+                               }
+                               else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
+                                       sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
+                               }
+                               else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
+                                       sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
+                               }
+                       }
+               }
+               p = &p[macho_segment_command::size + sectionsEmitted*macho_section::content_size];
+               cmd->set_cmdsize(macho_segment_command::size + sectionsEmitted*macho_section::content_size);
+               cmd->set_nsects(sectionsEmitted);
+       }
+       writer.write(0, buffer, size);
+}
+
+
+SymbolTableLoadCommandsAtom::SymbolTableLoadCommandsAtom(Writer& writer)
+ : WriterAtom(writer, fgTextSegment)
+{
+       bzero(&fSymbolTable, macho_symtab_command::size);
+       bzero(&fDynamicSymbolTable, macho_dysymtab_command::size);
+       writer.fSymbolTableCommands = this;
+}
+
+uint64_t SymbolTableLoadCommandsAtom::getSize() const
+{
+       return macho_symtab_command::size + macho_dysymtab_command::size;
+}
+
+void SymbolTableLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       // build LC_DYSYMTAB command
+       macho_symtab_command   symbolTableCmd;
+       bzero(&symbolTableCmd, macho_symtab_command::size);
+       symbolTableCmd.set_cmd(LC_SYMTAB);
+       symbolTableCmd.set_cmdsize(macho_symtab_command::size);
+       symbolTableCmd.set_nsyms(fWriter.fSymbolTableCount);
+       symbolTableCmd.set_symoff(fWriter.fSymbolTableAtom->getFileOffset());
+       symbolTableCmd.set_stroff(fWriter.fStringsAtom->getFileOffset());
+       symbolTableCmd.set_strsize(fWriter.fStringsAtom->getSize());
+       writer.write(0, &symbolTableCmd, macho_symtab_command::size);
+               
+       // build LC_DYSYMTAB command
+       macho_dysymtab_command dynamicSymbolTableCmd;
+       bzero(&dynamicSymbolTableCmd, macho_dysymtab_command::size);
+       dynamicSymbolTableCmd.set_cmd(LC_DYSYMTAB);
+       dynamicSymbolTableCmd.set_cmdsize(macho_dysymtab_command::size);
+       dynamicSymbolTableCmd.set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
+       dynamicSymbolTableCmd.set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
+       dynamicSymbolTableCmd.set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
+       dynamicSymbolTableCmd.set_nextdefsym(fWriter.fSymbolTableExportCount);
+       dynamicSymbolTableCmd.set_iundefsym(fWriter.fSymbolTableImportStartIndex);
+       dynamicSymbolTableCmd.set_nundefsym(fWriter.fSymbolTableImportCount);
+       dynamicSymbolTableCmd.set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
+       dynamicSymbolTableCmd.set_nindirectsyms(fWriter.fIndirectSymbolTable.size());
+       if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
+               dynamicSymbolTableCmd.set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
+               dynamicSymbolTableCmd.set_nextrel(fWriter.fExternalRelocs.size());
+               dynamicSymbolTableCmd.set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
+               dynamicSymbolTableCmd.set_nlocrel(fWriter.fInternalRelocs.size());
+       }
+       writer.write(macho_symtab_command::size, &dynamicSymbolTableCmd, macho_dysymtab_command::size);
+}
+
+uint64_t DyldLoadCommandsAtom::getSize() const
+{
+       uint32_t len = macho_dylinker_command::name_offset + strlen("/usr/lib/dyld");
+       len = (len+7) & (-8);   // 8-byte align
+       return len;
+}
+
+void DyldLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       uint64_t size = this->getSize();
+       uint8_t buffer[size];
+       macho_dylinker_command* cmd = (macho_dylinker_command*)buffer;
+       if ( fWriter.fOptions.outputKind() == Options::kDyld )
+               cmd->set_cmd(LC_ID_DYLINKER);
+       else
+               cmd->set_cmd(LC_LOAD_DYLINKER);
+       cmd->set_cmdsize(this->getSize());
+       cmd->set_name_offset();
+       strcpy((char*)&buffer[macho_dylinker_command::name_offset], "/usr/lib/dyld");
+       writer.write(0, buffer, size);
+}
+
+
+
+uint64_t DylibLoadCommandsAtom::getSize() const
+{
+       const char* path = fInfo.reader->getInstallPath();
+       if ( fInfo.options.fInstallPathOverride != NULL ) 
+               path = fInfo.options.fInstallPathOverride;
+       uint32_t len = macho_dylib_command::name_offset + strlen(path);
+       len = (len+7) & (-8);   // 8-byte align
+       return len;
+}
+
+void DylibLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       uint64_t size = this->getSize();
+       uint8_t buffer[size];
+       bzero(buffer, size);
+       const char* path = fInfo.reader->getInstallPath();
+       if ( fInfo.options.fInstallPathOverride != NULL ) 
+               path = fInfo.options.fInstallPathOverride;
+       macho_dylib_command* cmd = (macho_dylib_command*)buffer;
+       if ( fInfo.options.fWeakImport )
+               cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
+       else
+               cmd->set_cmd(LC_LOAD_DYLIB);
+       cmd->set_cmdsize(this->getSize());
+       cmd->set_timestamp(fInfo.reader->getTimestamp());
+       cmd->set_current_version(fInfo.reader->getCurrentVersion());
+       cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
+       cmd->set_name_offset();
+       strcpy((char*)&buffer[macho_dylib_command::name_offset], path);
+       writer.write(0, buffer, size);
+}
+
+
+
+uint64_t DylibIDLoadCommandsAtom::getSize() const
+{
+       uint32_t len = macho_dylib_command::name_offset + strlen(fWriter.fOptions.installPath());
+       len = (len+7) & (-8);   // 8-byte align
+       return len;
+}
+
+void DylibIDLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       struct timeval currentTime = { 0 , 0 };
+       gettimeofday(&currentTime, NULL);
+       time_t timestamp = currentTime.tv_sec;
+       uint64_t size = this->getSize();
+       uint8_t buffer[size];
+       bzero(buffer, size);
+       macho_dylib_command* cmd = (macho_dylib_command*)buffer;
+       cmd->set_cmd(LC_ID_DYLIB);
+       cmd->set_cmdsize(this->getSize());
+       cmd->set_name_offset();
+       cmd->set_timestamp(timestamp);
+       cmd->set_current_version(fWriter.fOptions.currentVersion());
+       cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
+       strcpy((char*)&buffer[macho_dylib_command::name_offset], fWriter.fOptions.installPath());
+       writer.write(0, buffer, size);
+}
+
+
+uint64_t RoutinesLoadCommandsAtom::getSize() const
+{
+       return macho_routines_command::size;
+}
+
+void RoutinesLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
+       uint8_t buffer[macho_routines_command::size];
+       bzero(buffer, macho_routines_command::size);
+       macho_routines_command* cmd = (macho_routines_command*)buffer;
+       cmd->set_cmd(macho_routines_command::command);
+       cmd->set_cmdsize(this->getSize());
+       cmd->set_init_address(initAddr);
+       writer.write(0, buffer, macho_routines_command::size);
+}
+
+
+uint64_t SubUmbrellaLoadCommandsAtom::getSize() const
+{
+       uint32_t len = macho_sub_umbrella_command::name_offset + strlen(fName);
+       len = (len+7) & (-8);   // 8-byte align
+       return len;
+}
+
+void SubUmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       uint64_t size = this->getSize();
+       uint8_t buffer[size];
+       bzero(buffer, size);
+       macho_sub_umbrella_command* cmd = (macho_sub_umbrella_command*)buffer;
+       cmd->set_cmd(LC_SUB_UMBRELLA);
+       cmd->set_cmdsize(this->getSize());
+       cmd->set_name_offset();
+       strcpy((char*)&buffer[macho_sub_umbrella_command::name_offset], fName);
+       writer.write(0, buffer, size);
+}
+
+
+uint64_t SubLibraryLoadCommandsAtom::getSize() const
+{
+       uint32_t len = macho_sub_library_command::name_offset + fNameLength + 1;
+       len = (len+7) & (-8);   // 8-byte align
+       return len;
+}
+
+void SubLibraryLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       uint64_t size = this->getSize();
+       uint8_t buffer[size];
+       bzero(buffer, size);
+       macho_sub_library_command* cmd = (macho_sub_library_command*)buffer;
+       cmd->set_cmd(LC_SUB_LIBRARY);
+       cmd->set_cmdsize(this->getSize());
+       cmd->set_name_offset();
+       strncpy((char*)&buffer[macho_sub_library_command::name_offset], fNameStart, fNameLength);
+       buffer[macho_sub_library_command::name_offset+fNameLength] = '\0';
+       writer.write(0, buffer, size);
+}
+
+uint64_t UmbrellaLoadCommandsAtom::getSize() const
+{
+       uint32_t len = macho_sub_framework_command::name_offset + strlen(fName);
+       len = (len+7) & (-8);   // 8-byte align
+       return len;
+}
+
+void UmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       uint64_t size = this->getSize();
+       uint8_t buffer[size];
+       bzero(buffer, size);
+       macho_sub_framework_command* cmd = (macho_sub_framework_command*)buffer;
+       cmd->set_cmd(LC_SUB_FRAMEWORK);
+       cmd->set_cmdsize(this->getSize());
+       cmd->set_name_offset();
+       strcpy((char*)&buffer[macho_sub_framework_command::name_offset], fName);
+       writer.write(0, buffer, size);
+}
+
+uint64_t ThreadsLoadCommandsAtom::getSize() const
+{
+#if defined(ARCH_PPC)
+               uint32_t stateSize = 40;                // PPC_THREAD_STATE_COUNT;
+#elif defined(ARCH_PPC64)
+               uint32_t stateSize = 76;                // PPC_THREAD_STATE64_COUNT;
+#elif defined(ARCH_I386)
+               uint32_t stateSize = 16;                // i386_THREAD_STATE_COUNT;
+#else
+       #error unknown architecture
+#endif
+       return macho_thread_command::size + stateSize*4;
+}
+
+void ThreadsLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       uint64_t size = this->getSize();
+       uint8_t buffer[size];
+       uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
+       bzero(buffer, size);
+       macho_thread_command* cmd = (macho_thread_command*)buffer;
+       cmd->set_cmd(LC_UNIXTHREAD);
+       cmd->set_cmdsize(size);
+#if defined(ARCH_PPC)
+       cmd->set_flavor(1);                             // PPC_THREAD_STATE
+       cmd->set_count(40);                             // PPC_THREAD_STATE_COUNT;
+       cmd->set_threadState32(0, start);
+       if ( fWriter.fOptions.hasCustomStack() )
+               cmd->set_threadState32(3, fWriter.fOptions.customStackAddr());  // r1
+#elif defined(ARCH_PPC64)
+       cmd->set_flavor(5);                             // PPC_THREAD_STATE64
+       cmd->set_count(76);                             // PPC_THREAD_STATE64_COUNT;
+       cmd->set_threadState64(0, start);
+       if ( fWriter.fOptions.hasCustomStack() )
+               cmd->set_threadState64(6, fWriter.fOptions.customStackAddr());  // r1
+#elif defined(ARCH_I386)
+       cmd->set_flavor(0xFFFFFFFF);    // i386_THREAD_STATE
+       cmd->set_count(16);                             // i386_THREAD_STATE_COUNT;
+       cmd->set_threadState32(0, start);
+       if ( fWriter.fOptions.hasCustomStack() )
+               cmd->set_threadState32(15, fWriter.fOptions.customStackAddr()); // uesp
+#else
+       #error unknown architecture
+#endif
+       writer.write(0, buffer, size);
+}
+
+
+
+uint64_t LoadCommandsPaddingAtom::getSize() const
+{
+       return fSize;
+}
+
+void LoadCommandsPaddingAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       uint8_t buffer[fSize];
+       bzero(buffer, fSize);
+       writer.write(0, buffer, fSize);
+}
+
+
+uint64_t LinkEditAtom::getFileOffset() const
+{
+       return ((Writer::SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
+}
+
+
+uint64_t LocalRelocationsLinkEditAtom::getSize() const
+{
+       return fWriter.fInternalRelocs.size() * macho_relocation_info::size;
+}
+
+void LocalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       writer.write(0, &fWriter.fInternalRelocs[0], this->getSize());
+}
+
+
+
+uint64_t SymbolTableLinkEditAtom::getSize() const
+{
+       return fWriter.fSymbolTableCount * macho_nlist::size;
+}
+
+void SymbolTableLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       writer.write(0, fWriter.fSymbolTable, this->getSize());
+}
+
+uint64_t ExternalRelocationsLinkEditAtom::getSize() const
+{
+       return fWriter.fExternalRelocs.size() * macho_relocation_info::size;
+}
+
+void ExternalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       writer.write(0, &fWriter.fExternalRelocs[0], this->getSize());
+}
+
+
+
+uint64_t IndirectTableLinkEditAtom::getSize() const
+{
+       return fWriter.fIndirectSymbolTable.size() * sizeof(uint32_t);
+}
+
+void IndirectTableLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       uint64_t size = this->getSize();
+       uint8_t buffer[size];
+       bzero(buffer, size);
+       const uint32_t indirectTableSize = fWriter.fIndirectSymbolTable.size();
+       uint32_t* indirectTable = (uint32_t*)buffer;
+       for (uint32_t i=0; i < indirectTableSize; ++i) {
+               Writer::IndirectEntry& entry = fWriter.fIndirectSymbolTable[i];
+               if ( entry.indirectIndex < indirectTableSize ) {
+                       ENDIAN_WRITE32(indirectTable[entry.indirectIndex], entry.symbolIndex);
+               }
+               else {
+                       throw "malformed indirect table";
+               }
+       }
+       writer.write(0, buffer, size);
+}
+
+
+
+StringsLinkEditAtom::StringsLinkEditAtom(Writer& writer) 
+       : LinkEditAtom(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
+{ 
+       fCurrentBuffer = new char[kBufferSize];
+       // burn first byte of string pool (so zero is never a valid string offset)
+       fCurrentBuffer[fCurrentBufferUsed++] = ' ';
+       // make offset 1 always point to an empty string
+       fCurrentBuffer[fCurrentBufferUsed++] = '\0';
+}
+
+uint64_t StringsLinkEditAtom::getSize() const
+{
+       return kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
+}
+
+void StringsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       uint64_t offset = 0;
+       for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
+               writer.write(offset, fFullBuffers[i], kBufferSize);
+               offset += kBufferSize;
+       }
+       writer.write(offset, fCurrentBuffer, fCurrentBufferUsed);
+}
+
+int32_t StringsLinkEditAtom::add(const char* name)
+{
+       int lenNeeded = strlen(name)+1;
+       while ( lenNeeded + fCurrentBufferUsed >= kBufferSize ) {
+               // first part of string fits in current buffer
+               int firstLen = kBufferSize - fCurrentBufferUsed;
+               memcpy(&fCurrentBuffer[fCurrentBufferUsed], name, firstLen);
+               // alloc next buffer
+               fFullBuffers.push_back(fCurrentBuffer);
+               fCurrentBuffer = new char[kBufferSize];
+               fCurrentBufferUsed = 0;
+               // advance name to second part
+               name += firstLen;
+               lenNeeded -= firstLen;
+       }
+       //fprintf(stderr, "StringsLinkEditAtom::add(): lenNeeded=%d, fCurrentBuffer=%d, fCurrentBufferUsed=%d\n", lenNeeded, fCurrentBuffer, fCurrentBufferUsed);
+       // string all fits in current buffer
+       strcpy(&fCurrentBuffer[fCurrentBufferUsed], name);
+       int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
+       fCurrentBufferUsed += lenNeeded;
+       return offset;
+}
+
+// returns the index of an empty string
+int32_t StringsLinkEditAtom::emptyString()
+{
+        return 1;
+}
+
+
+
+};
+
+
+
diff --git a/src/ld.cpp b/src/ld.cpp
new file mode 100644 (file)
index 0000000..7b05e32
--- /dev/null
@@ -0,0 +1,1304 @@
+/*
+ * 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 <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+
+#include <string>
+#include <set>
+#include <string>
+#include <vector>
+#include <list>
+#include <algorithm>
+#include <ext/hash_map>
+
+#include "Options.h"
+
+#include "ObjectFile.h"
+#include "ObjectFileMachO-all.h"
+
+#include "ExecutableFile.h"
+#include "ExecutableFileMachO-all.h"
+
+#include "SectCreate.h"
+
+#if 0
+static void dumpAtom(ObjectFile::Atom* atom)
+{
+       //printf("atom:    %p\n", atom);
+       
+       // name
+       printf("name:    %s\n",  atom->getDisplayName());
+       
+       // scope
+       switch ( atom->getScope() ) {
+               case ObjectFile::Atom::scopeTranslationUnit:
+                       printf("scope:   translation unit\n");
+                       break;
+               case ObjectFile::Atom::scopeLinkageUnit:
+                       printf("scope:   linkage unit\n");
+                       break;
+               case ObjectFile::Atom::scopeGlobal:
+                       printf("scope:   global\n");
+                       break;
+               default:
+                       printf("scope:   unknown\n");
+       }
+       
+       // segment and section
+       printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
+
+       // attributes
+       printf("attrs:   ");
+       if ( atom->isTentativekDefinition() )
+               printf("tentative ");
+       else if ( atom->isWeakDefinition() )
+               printf("weak ");
+       if ( atom->isCoalesableByName() )
+               printf("coalesce-by-name ");
+       if ( atom->isCoalesableByValue() )
+               printf("coalesce-by-value ");
+       if ( atom->dontDeadStrip() )
+               printf("dont-dead-strip ");
+       if ( atom->isZeroFill() )
+               printf("zero-fill ");
+       printf("\n");
+       
+       // size
+       printf("size:    0x%012llX\n", atom->getSize());
+       
+       // content
+       uint8_t content[atom->getSize()];
+       atom->copyRawContent(content);
+       printf("content: ");
+       if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
+               printf("\"%s\"", content);
+       }
+       else {
+               for (unsigned int i=0; i < sizeof(content); ++i)
+                       printf("%02X ", content[i]);
+       }
+       printf("\n");
+       
+       // references
+       std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
+       const int refCount = references.size();
+       printf("references: (%u)\n", refCount);
+       for (int i=0; i < refCount; ++i) {
+               ObjectFile::Reference* ref = references[i];
+               printf("   %s\n", ref->getDescription());
+       }
+       
+       // attributes
+       
+}
+
+#endif
+
+class CStringComparor
+{
+public:
+       bool operator()(const char* left, const char* right) const { return (strcmp(left, right) < 0); }
+};
+
+class CStringEquals
+{
+public:
+       bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+};
+
+class Section : public ObjectFile::Section
+{
+public:
+       static Section* find(const char* sectionName, const char* segmentName, bool zeroFill);
+       static void             assignIndexes();
+
+private:
+                                       Section(const char* sectionName, const char* segmentName, bool zeroFill);
+
+       struct Sorter {
+               static int      segmentOrdinal(const char* segName);
+               bool operator()(Section* left, Section* right);
+       };
+
+       typedef __gnu_cxx::hash_map<const char*, class Section*, __gnu_cxx::hash<const char*>, CStringEquals> NameToSection;
+       //typedef std::map<const char*, class Section*, CStringComparor> NameToSection;
+
+       const char*             fSectionName;
+       const char*             fSegmentName;
+       bool                    fZeroFill;
+
+       static NameToSection                    fgMapping;
+       static std::vector<Section*>    fgSections;
+};
+
+Section::NameToSection Section::fgMapping;
+std::vector<Section*>  Section::fgSections;
+
+Section::Section(const char* sectionName, const char* segmentName, bool zeroFill)
+ : fSectionName(sectionName), fSegmentName(segmentName), fZeroFill(zeroFill)
+{
+       //fprintf(stderr, "new Section(%s, %s)\n", sectionName, segmentName);
+}
+
+Section* Section::find(const char* sectionName, const char* segmentName, bool zeroFill)
+{
+#if 0
+       std::pair<NameToSection::iterator, NameToSection::iterator> range = fgMapping.equal_range(sectionName);
+       for (NameToSection::iterator it=range.first; it != range.second; it++) {
+               if ( strcmp(it->second->fSegmentName, segmentName) == 0 )
+                       return it->second;
+       }
+#endif
+       NameToSection::iterator pos = fgMapping.find(sectionName);
+       if ( pos != fgMapping.end() ) {
+               if ( strcmp(pos->second->fSegmentName, segmentName) == 0 )
+                       return pos->second;
+               // otherwise same section name is used in different segments, look slow way
+               for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
+                       if ( (strcmp((*it)->fSectionName, sectionName) == 0) && (strcmp((*it)->fSegmentName, segmentName) == 0) )
+                               return *it;
+               }
+       }
+       
+       // does not exist, so make a new one
+       Section* sect = new Section(sectionName, segmentName, zeroFill);
+       sect->fIndex = fgMapping.size();
+       fgMapping[sectionName] = sect;
+       fgSections.push_back(sect);
+       return sect;
+}
+
+int Section::Sorter::segmentOrdinal(const char* segName)
+{
+       if ( strcmp(segName, "__PAGEZERO") == 0 )
+               return 1;
+       if ( strcmp(segName, "__TEXT") == 0 )
+               return 2;
+       if ( strcmp(segName, "__DATA") == 0 )
+               return 3;
+       if ( strcmp(segName, "__OBJC") == 0 )
+               return 4;
+       if ( strcmp(segName, "__LINKEDIT") == 0 )
+               return INT_MAX; // linkedit segment should always sort last
+       else 
+               return 5;
+}
+
+
+bool Section::Sorter::operator()(Section* left, Section* right)
+{
+       // Segment is primary sort key
+       const char* leftSegName = left->fSegmentName;
+       const char* rightSegName = right->fSegmentName;
+       int segNameCmp = strcmp(leftSegName, rightSegName);
+       if ( segNameCmp != 0 )
+       {
+               int leftSegOrdinal = segmentOrdinal(leftSegName);
+               int rightSegOrdinal = segmentOrdinal(rightSegName);
+               if ( leftSegOrdinal < rightSegOrdinal )
+                       return true;
+               if ( leftSegOrdinal == rightSegOrdinal )
+                       return segNameCmp < 0;
+               return false;
+       }
+
+       // zerofill section sort to the end
+       if ( !left->fZeroFill && right->fZeroFill )
+               return true;
+       if ( left->fZeroFill && !right->fZeroFill )
+               return false;
+
+       // section discovery order is last sort key
+       return left->fIndex < right->fIndex;
+}
+
+void Section::assignIndexes()
+{
+       //printf("unsorted:\n");
+       //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
+       //      printf("section: name=%s, segment: name=%s, discovery order=%d\n", (*it)->fSectionName, (*it)->fSegmentName, (*it)->fIndex);
+       //}
+
+       // sort it
+       std::sort(fgSections.begin(), fgSections.end(), Section::Sorter());
+       
+       // assign correct section ordering to each Section object
+       unsigned int newOrder = 1;
+       for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) 
+               (*it)->fIndex = newOrder++;
+
+       //printf("sorted:\n");
+       //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
+       //      printf("section: name=%s\n", (*it)->fSectionName);
+       //}
+}
+
+class Linker {
+public:
+                                               Linker(int argc, const char* argv[]);
+
+       void                            createReaders();
+       void                            createWriter();
+       void                            addInputFile(ObjectFile::Reader* reader);
+       void                            setOutputFile(ExecutableFile::Writer* writer);
+       void                            link();
+       
+       
+private:
+       ObjectFile::Reader*     createReader(const Options::FileInfo&);
+       void                            addAtom(ObjectFile::Atom& atom);
+       void                            addAtoms(std::vector<class ObjectFile::Atom*>& atoms);
+       void                            buildAtomList();
+       void                            loadUndefines();
+       void                            addWeakAtomOverrides();
+       void                            resolveReferences();
+       void                            deadStrip();
+       void                            sortAtoms();
+       void                            tweakLayout();
+       void                            writeOutput();
+       
+       void                            resolve(ObjectFile::Reference* reference);
+       void                            addJustInTimeAtoms(const char* name);
+       
+       void                            addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info);
+       void                            addIndirectLibraries(ObjectFile::Reader* reader);
+       bool                            haveIndirectLibrary(const char* path, ObjectFile::Reader* reader);
+       bool                            haveDirectLibrary(const char* path);
+
+       struct SegmentAndItsAtoms
+       {
+               class Segment*                                          fSegment;
+               uint64_t                                                        fSegmentSize;
+               uint64_t                                                        fSegmentBaseAddress;
+               std::vector<class ObjectFile::Atom*>    fAtoms;
+       };
+       
+       
+       class SymbolTable
+       {
+       public:
+                                                       SymbolTable(Linker&);
+               void                            require(const char* name);
+               bool                            add(ObjectFile::Atom& atom);
+               ObjectFile::Atom*       find(const char* name);
+               unsigned int            getRequireCount() { return fRequireCount; }
+               void                            getNeededNames(bool andWeakDefintions, std::vector<const char*>& undefines);
+       private:
+               typedef std::map<const char*, ObjectFile::Atom*, CStringComparor> Mapper;
+               Linker&                         fOwner;
+               Mapper                          fTable;
+               unsigned int            fRequireCount;
+       };
+       
+       struct AtomSorter
+       {
+               bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right);
+       };
+       
+       typedef std::map<const char*, uint32_t, CStringComparor> SectionOrder;
+       
+       struct IndirectLibrary {
+               const char*                                                     path;
+               uint64_t                                                        fileLen;
+               ObjectFile::Reader*                                     reader;
+               std::set<ObjectFile::Reader*>           parents;
+               ObjectFile::Reader*                                     reExportParent;
+       };
+       
+       Options                                                                                         fOptions;
+       SymbolTable                                                                                     fGlobalSymbolTable;
+       unsigned int                                                                            fWeakSymbolsAddedCount;
+       std::vector<class ObjectFile::Reader*>                          fInputFiles;
+       ExecutableFile::Writer*                                                         fOutputFile;
+       std::vector<ExecutableFile::DyLibUsed>                          fDynamicLibraries;
+       std::list<IndirectLibrary>                                                      fIndirectDynamicLibraries;
+       std::vector<class ObjectFile::Atom*>                            fAllAtoms;
+       std::vector< SegmentAndItsAtoms >                                       fAllAtomsBySegment;
+       std::set<class ObjectFile::Atom*>                                       fDeadAtoms;
+       SectionOrder                                                                            fSectionOrder;
+       unsigned int                                                                            fNextSortOrder;
+       bool                                                                                            fDirectLibrariesComplete;
+};
+
+
+
+Linker::Linker(int argc, const char* argv[])
+ : fOptions(argc, argv), fGlobalSymbolTable(*this), fOutputFile(NULL), fNextSortOrder(1), fDirectLibrariesComplete(false)
+{
+}
+
+void Linker::addInputFile(ObjectFile::Reader* reader)
+{
+       fInputFiles.push_back(reader);
+}
+
+void Linker::setOutputFile(ExecutableFile::Writer* writer)
+{
+       fOutputFile = writer;
+}
+
+void Linker::link()
+{              
+       this->buildAtomList();
+       this->loadUndefines();
+       this->resolveReferences();
+       this->deadStrip();
+       this->sortAtoms();
+       this->tweakLayout();
+       this->writeOutput();
+}
+
+inline void Linker::addAtom(ObjectFile::Atom& atom)
+{
+       // add to list of all atoms
+       fAllAtoms.push_back(&atom);
+       
+       // add atom's references's names to symbol table as to-be-resolved-later
+       std::vector<class ObjectFile::Reference*>& references = atom.getReferences();
+       for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
+               ObjectFile::Reference* reference = *it;
+               if ( reference->isUnbound() ) {
+                       fGlobalSymbolTable.require(reference->getTargetName());
+               }
+       }
+       
+       // if in global namespace, add atom itself to symbol table
+       ObjectFile::Atom::Scope scope = atom.getScope();
+       const char* name = atom.getName();
+       if ( (scope != ObjectFile::Atom::scopeTranslationUnit) && (name != NULL) ) {
+               fGlobalSymbolTable.add(atom);
+               
+               // update scope based on export list (possible that globals are downgraded to private_extern)
+               if ( (scope == ObjectFile::Atom::scopeGlobal) && fOptions.hasExportRestrictList() ) {
+                       bool doExport = fOptions.shouldExport(name);
+                       if ( !doExport ) {
+                               atom.setScope(ObjectFile::Atom::scopeLinkageUnit);
+                       }
+               }
+       }
+               
+       // record section orders so output file can have same order
+       atom.setSection(Section::find(atom.getSectionName(), atom.getSegment().getName(), atom.isZeroFill()));
+       
+       // assign order in which this atom was originally seen
+       if ( atom.getSortOrder() == 0 )
+               fNextSortOrder = atom.setSortOrder(fNextSortOrder);
+}
+
+inline void Linker::addAtoms(std::vector<class ObjectFile::Atom*>& atoms)
+{
+       for (std::vector<ObjectFile::Atom*>::iterator it=atoms.begin(); it != atoms.end(); it++) {
+               this->addAtom(**it);
+       }
+}
+
+void Linker::buildAtomList()
+{
+       // add initial undefines from -u option
+       std::vector<const char*>& initialUndefines = fOptions.initialUndefines();
+       for (std::vector<const char*>::iterator it=initialUndefines.begin(); it != initialUndefines.end(); it++) {
+               fGlobalSymbolTable.require(*it);
+       }
+       
+       // writer can contribute atoms 
+       this->addAtoms(fOutputFile->getAtoms());
+       
+       // each reader contributes atoms
+       const int readerCount = fInputFiles.size();
+       for (int i=0; i < readerCount; ++i) {
+               this->addAtoms(fInputFiles[i]->getAtoms());
+       }
+       
+       // extra command line section always at end
+       std::vector<Options::ExtraSection>& extraSections = fOptions.extraSections();
+       for( std::vector<Options::ExtraSection>::iterator it=extraSections.begin(); it != extraSections.end(); ++it) {
+               this->addAtoms(SectCreate::MakeReader(it->segmentName, it->sectionName, it->path, it->data, it->dataLen)->getAtoms());
+       }
+}
+
+void Linker::loadUndefines()
+{
+       // keep looping until no more undefines were added in last loop
+       unsigned int undefineCount = 0xFFFFFFFF;
+       while ( undefineCount != fGlobalSymbolTable.getRequireCount() ) {
+               undefineCount = fGlobalSymbolTable.getRequireCount();
+               std::vector<const char*> undefineNames;
+               fGlobalSymbolTable.getNeededNames(true, undefineNames);
+               const int undefineCount = undefineNames.size();
+               for (int i=0; i < undefineCount; ++i) {
+                       const char* name = undefineNames[i];
+                       ObjectFile::Atom* possibleAtom = fGlobalSymbolTable.find(name);
+                       if ( (possibleAtom == NULL) || (possibleAtom->isWeakDefinition() && (fOptions.outputKind() != Options::kObjectFile)) )
+                               this->addJustInTimeAtoms(name);
+               }
+       }
+       
+       if ( fOptions.outputKind() != Options::kObjectFile ) {
+               // error out on any remaining undefines
+               bool doPrint = true;
+               bool doError = true;
+               switch ( fOptions.undefinedTreatment() ) {
+                       case Options::kUndefinedError:
+                               break;
+                       case Options::kUndefinedDynamicLookup:
+                               doError = false;
+                               break;
+                       case Options::kUndefinedWarning:
+                               doError = false;
+                               break;
+                       case Options::kUndefinedSuppress:
+                               doError = false;
+                               doPrint = false;
+                               break;
+               }
+               std::vector<const char*> unresolvableUndefines;
+               fGlobalSymbolTable.getNeededNames(false, unresolvableUndefines);
+               const int unresolvableCount = unresolvableUndefines.size();
+               if ( unresolvableCount != 0 ) {
+                       if ( doPrint ) {
+                               fprintf(stderr, "can't resolve symbols:\n");
+                               for (int i=0; i < unresolvableCount; ++i) {
+                                       const char* name = unresolvableUndefines[i];
+                                       const unsigned int nameLen = strlen(name);
+                                       fprintf(stderr, "  %s, referenced from:\n", name);
+                                       char stubName[nameLen+6];
+                                       strcpy(stubName, name);
+                                       strcat(stubName, "$stub");
+                                       char nonLazyName[nameLen+16];
+                                       strcpy(nonLazyName, name);
+                                       strcat(nonLazyName, "$non_lazy_ptr");
+                                       ObjectFile::Atom* lastStubAtomWithUnresolved = NULL;
+                                       ObjectFile::Atom* lastNonLazyAtomWithUnresolved = NULL;
+                                       for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
+                                               ObjectFile::Atom* atom = *it;
+                                               std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
+                                               for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
+                                                       ObjectFile::Reference* reference = *rit;
+                                                       if ( reference->isUnbound() ) {
+                                                               if ( (atom != lastStubAtomWithUnresolved) && (strcmp(reference->getTargetName(), stubName) == 0) ) {
+                                                                       const char* path = atom->getFile()->getPath();
+                                                                       const char* shortPath = strrchr(path, '/');
+                                                                       if ( shortPath == NULL )
+                                                                               shortPath = path;
+                                                                       else
+                                                                               shortPath = &shortPath[1];
+                                                                       fprintf(stderr, "      %s in %s\n", atom->getDisplayName(), shortPath);
+                                                                       lastStubAtomWithUnresolved = atom;
+                                                               }
+                                                               else if ( (atom != lastNonLazyAtomWithUnresolved) && (strcmp(reference->getTargetName(), nonLazyName) == 0) ) {
+                                                                       const char* path = atom->getFile()->getPath();
+                                                                       const char* shortPath = strrchr(path, '/');
+                                                                       if ( shortPath == NULL )
+                                                                               shortPath = path;
+                                                                       else
+                                                                               shortPath = &shortPath[1];
+                                                                       fprintf(stderr, "      %s in %s\n", atom->getDisplayName(), shortPath);
+                                                                       lastNonLazyAtomWithUnresolved = atom;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       if ( doError )
+                               throw "symbol(s) not found";
+               }
+               
+               // now verify that -init routine exists
+               if ( fOptions.initFunctionName() != NULL ) {
+                       if ( fGlobalSymbolTable.find(fOptions.initFunctionName()) == NULL )
+                               throwf("symbol %s not found for -init", fOptions.initFunctionName());
+               }
+       }
+}
+
+
+
+void Linker::addJustInTimeAtoms(const char* name)
+{
+       // give writer a crack at it
+       ObjectFile::Atom* atom = fOutputFile->getUndefinedProxyAtom(name);
+       if ( atom != NULL ) {
+               this->addAtom(*atom);
+       }
+       else {
+               // give direct readers a chance
+               const int readerCount = fInputFiles.size();
+               for (int i=0; i < readerCount; ++i) {
+                       // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
+                       // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
+                       std::vector<class ObjectFile::Atom*>* atoms = fInputFiles[i]->getJustInTimeAtomsFor(name);
+                       if ( atoms != NULL ) {
+                               this->addAtoms(*atoms);
+                               delete atoms;
+                               return;  // found a definition, no need to search anymore
+                               //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file #%d\n", name, i);
+                       }
+               }
+               
+               // give indirect readers a chance
+               for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
+                       ObjectFile::Reader* reader = it->reader;
+                       if ( reader != NULL ) {
+                               std::vector<class ObjectFile::Atom*>* atoms = reader->getJustInTimeAtomsFor(name);
+                               if ( atoms != NULL ) {
+                                       this->addAtoms(*atoms);
+                                       delete atoms;
+                                       break;
+                                       //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file #%d\n", name, i);
+                               }
+                       }
+               }
+       }
+}
+
+void Linker::resolve(ObjectFile::Reference* reference)
+{
+       ObjectFile::Atom* target = NULL;
+       const char* targetName = reference->getTargetName();
+       const int targetNameLen = strlen(targetName);
+       if ( (targetNameLen > 5) && (strcmp(&targetName[targetNameLen-5], "$stub") == 0) ) {
+               // when looking up "_foo$stub", first look for "_foo"
+               char nonStubTarget[targetNameLen+1];
+               strcpy(nonStubTarget, targetName);
+               nonStubTarget[targetNameLen-5] = '\0';
+               // unless interposing and the symbol is exported 
+               if ( !fOptions.interposable() || !fOptions.shouldExport(nonStubTarget) ) {
+                       target = fGlobalSymbolTable.find(nonStubTarget);        
+                       // also need indirection to all exported weak symbols for C++ support
+                       if ( (target != NULL) && !target->isImportProxy() && (!target->isWeakDefinition() || (target->getScope() != ObjectFile::Atom::scopeGlobal)) ) {
+                               reference->setTarget(*target);
+                               // mark stub as no longer being needed
+                               ObjectFile::Atom* stub = fGlobalSymbolTable.find(targetName);
+                               if ( stub != NULL ) {
+                                       char lazySymbol[targetNameLen+8];
+                                       strcpy(lazySymbol, nonStubTarget);
+                                       strcat(lazySymbol, "$lazy_ptr");
+                                       ObjectFile::Atom* lazyPtr = fGlobalSymbolTable.find(lazySymbol);
+                                       fDeadAtoms.insert(stub);
+                                       if ( lazyPtr != NULL )
+                                               fDeadAtoms.insert(lazyPtr);
+                               }
+                               return;
+                       }
+               }
+       }
+       
+       // look in global symbol table
+       target = fGlobalSymbolTable.find(targetName);
+       if ( target == NULL ) {
+               fprintf(stderr, "can't resolve: %s\n", targetName);
+       }
+       reference->setTarget(*target);
+       
+       // handle weak-imports
+       if ( target->isImportProxy() ) {
+               bool mismatch = false;
+               if ( reference->isWeakReference() ) {
+                       switch(target->getImportWeakness()) {
+                               case ObjectFile::Atom::kWeakUnset:
+                                       target->setImportWeakness(true);
+                    break;     
+                               case ObjectFile::Atom::kWeakImport:
+                                       break;
+                               case ObjectFile::Atom::kNonWeakImport:
+                                       mismatch = true;
+                                       break;
+                       }
+               }
+               else {
+                       switch(target->getImportWeakness()) {
+                               case ObjectFile::Atom::kWeakUnset:
+                                       target->setImportWeakness(false);       
+                    break;     
+                               case ObjectFile::Atom::kWeakImport:
+                                       mismatch = true;
+                                       break;
+                               case ObjectFile::Atom::kNonWeakImport:
+                                       break;
+                       }
+               }
+               if ( mismatch ) {
+                       switch ( fOptions.weakReferenceMismatchTreatment() ) {
+                               case Options::kWeakReferenceMismatchError:
+                                       throwf("mismatching weak references for symbol: %s", target->getName());
+                               case Options::kWeakReferenceMismatchWeak:
+                                       target->setImportWeakness(true);
+                                       break;
+                               case Options::kWeakReferenceMismatchNonWeak:
+                                       target->setImportWeakness(false);
+                                       break;
+                       }
+               }
+       }
+       
+       // handle references that have two (from and to) targets
+       if ( reference->isUnbound() ) {
+               const char* fromTargetName = reference->getFromTargetName();
+               ObjectFile::Atom* fromTarget = fGlobalSymbolTable.find(fromTargetName);
+               if ( target == NULL ) {
+                       fprintf(stderr, "can't resolve: %s\n", fromTargetName);
+               }
+               reference->setFromTarget(*fromTarget);
+       }
+}
+
+
+void Linker::resolveReferences()
+{
+       // note: the atom list may grow during this loop as libraries supply needed atoms
+       for (unsigned int j=0; j < fAllAtoms.size(); ++j) {
+               ObjectFile::Atom* atom = fAllAtoms[j];
+               std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
+               for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
+                       ObjectFile::Reference* reference = *it;
+                       if ( reference->isUnbound() ) {
+                               this->resolve(reference);
+                       }
+               }
+       }
+}
+
+class InSet
+{
+public:
+       InSet(std::set<ObjectFile::Atom*>& deadAtoms) : fDeadAtoms(deadAtoms) {}
+       
+       bool operator()(ObjectFile::Atom*& atom) const { 
+               return ( fDeadAtoms.count(atom) != 0 );
+       }
+       
+private:
+       std::set<ObjectFile::Atom*>& fDeadAtoms;
+};
+
+
+void Linker::deadStrip()
+{
+       //printf("Stripping atoms:\n");
+       //for (std::set<ObjectFile::Atom*>::iterator it=fDeadAtoms.begin(); it != fDeadAtoms.end(); it++) {
+       //      printf("\t%s\n", (*it)->getDisplayName());
+       //}
+
+       // for now, just remove atoms weak atoms that have been overridden
+       fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), InSet(fDeadAtoms)), fAllAtoms.end());
+}
+
+
+
+void Linker::sortAtoms()
+{
+       Section::assignIndexes();
+       std::sort(fAllAtoms.begin(), fAllAtoms.end(), Linker::AtomSorter());
+}
+
+
+
+// make sure given addresses are within reach of branches, etc
+void Linker::tweakLayout()
+{
+       
+
+
+}
+
+
+void Linker::writeOutput()
+{
+       // if main executable, find entry point atom
+       ObjectFile::Atom* entryPoint;
+       switch ( fOptions.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kStaticExecutable:
+               case Options::kDyld:
+                       entryPoint = fGlobalSymbolTable.find(fOptions.entryName());
+                       if ( entryPoint == NULL ) {
+                               throwf("could not find entry point: %s", fOptions.entryName());
+                       }
+                       break;
+               case Options::kDynamicLibrary:
+                       if ( fOptions.initFunctionName() != NULL ) {
+                               entryPoint = fGlobalSymbolTable.find(fOptions.initFunctionName());
+                               if ( entryPoint == NULL ) {
+                                       throwf("could not find -init function: %s", fOptions.initFunctionName());
+                               }
+                       }
+                       break;
+               default:
+                       entryPoint = NULL;
+       }
+       
+       // tell writer about each segment's atoms
+       fOutputFile->write(fAllAtoms, entryPoint);
+}
+
+
+
+
+ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
+{
+       // map in whole file
+       uint64_t len = info.fileLen;
+       int fd = ::open(info.path, O_RDONLY, 0);
+       if ( fd == -1 )
+               throw "can't open file";
+       if ( info.fileLen < 20 )
+               throw "file too small";
+       char* p = (char*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE, fd, 0);
+       if ( p == (char*)(-1) )
+               throw "can't map file";
+       ::close(fd);
+       
+       // if fat file, skip to architecture we want
+       const mach_header* mh = (mach_header*)p;
+       if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+               // Fat header is always big-endian
+               const struct fat_header* fh = (struct fat_header*)p;
+               const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
+               for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
+                       if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)fOptions.architecture() ) {
+                               mh = (struct mach_header*)((char*)p + OSSwapBigToHostInt32(archs[i].offset));
+                               len = OSSwapBigToHostInt32(archs[i].size);
+                               break;
+                       }
+               }
+       }
+       
+       if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+               const char* archName = "unknown";
+               switch (fOptions.architecture()) {
+                       case CPU_TYPE_POWERPC:
+                               archName = "ppc";
+                               break;
+                       case CPU_TYPE_POWERPC64:
+                               archName = "ppc64";
+                               break;
+                       case CPU_TYPE_I386:
+                               archName = "i386";
+                               break;
+               }
+               throwf("missing required architecture %s in fat file", archName);
+       }
+       
+       // pull out cpu-type and file-type in endian-safe way
+       cpu_type_t cpuType = 0;
+       uint32_t fileType = 0;
+       if ( mh->magic == MH_MAGIC ) {
+               fileType = mh->filetype;
+               cpuType = mh->cputype;
+       }
+       else if ( mh->magic == OSSwapInt32(MH_MAGIC) ) {
+               fileType = OSSwapInt32(mh->filetype);
+               cpuType = OSSwapInt32(mh->cputype);
+       }
+       else if ( mh->magic == MH_MAGIC_64 ) {
+               fileType = ((mach_header_64*)mh)->filetype;
+               cpuType = ((mach_header_64*)mh)->cputype;
+       }
+       else if ( mh->magic == OSSwapInt32(MH_MAGIC_64) ) {
+               fileType = OSSwapInt32(((mach_header_64*)mh)->filetype);
+               cpuType = OSSwapInt32(((mach_header_64*)mh)->cputype);
+       }
+       else if ( strncmp((const char*)mh, "!<arch>\n", 8) == 0 ) {
+               // is static archive
+               switch ( fOptions.architecture() ) {
+                       case CPU_TYPE_POWERPC:
+                               return ppc::ObjectFileArchiveMachO::MakeReader((const uint8_t*)mh, len, info.path, fOptions.readerOptions());
+                       case CPU_TYPE_POWERPC64:
+                               return ppc64::ObjectFileArchiveMachO::MakeReader((const uint8_t*)mh, len, info.path, fOptions.readerOptions());
+                       case CPU_TYPE_I386:
+                               return i386::ObjectFileArchiveMachO::MakeReader((const uint8_t*)mh, len, info.path, fOptions.readerOptions());
+               }
+               throw "no matching archive reader";
+       }
+       else {
+               throw "unknown file type";      
+       }
+       
+       // bail out if cpu-type does not match requrired architecture
+       if ( fOptions.architecture() == cpuType ) {
+               // make appropriate reader object
+               if ( fileType == MH_OBJECT ) {
+                       switch ( cpuType ) {
+                               case CPU_TYPE_POWERPC:
+                                       return ppc::ObjectFileMachO::MakeReader((class ppc::macho_header*)mh, info.path, fOptions.readerOptions());
+                               case CPU_TYPE_POWERPC64:
+                                       return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, info.path, fOptions.readerOptions());
+                               case CPU_TYPE_I386:
+                                       return i386::ObjectFileMachO::MakeReader((class i386::macho_header*)mh, info.path, fOptions.readerOptions());
+                               default:
+                                       throw "wrong architecture in object file";
+                       }
+               }
+               else if ( fileType == MH_DYLIB ) {
+                       ObjectFile::Reader* dylibReader = NULL;
+                       switch ( cpuType ) {
+                               case CPU_TYPE_POWERPC:
+                                       dylibReader = ppc::ObjectFileDylibMachO::MakeReader((class ppc::macho_header*)mh, info.path, fOptions.readerOptions());
+                                       break;
+                               case CPU_TYPE_POWERPC64:
+                                       dylibReader = ppc64::ObjectFileDylibMachO::MakeReader((class ppc64::macho_header*)mh, info.path, fOptions.readerOptions());
+                                       break;
+                               case CPU_TYPE_I386:
+                                       dylibReader = i386::ObjectFileDylibMachO::MakeReader((class i386::macho_header*)mh, info.path, fOptions.readerOptions());
+                                       break;
+                               default:
+                                       throw "wrong architecture in dylib";
+                       }
+                       this->addDylib(dylibReader, info);
+                       return dylibReader;
+               }
+               throw "unknown mach-o file type";
+       }
+       else {
+               throw "file does not contain requested architecture";
+       }
+
+}
+
+
+void Linker::createReaders()
+{
+       std::vector<Options::FileInfo>& files = fOptions.getInputFiles();
+       const int count = files.size();
+       if ( count == 0 )
+               throw "no object files specified";
+       // add all direct object, archives, and dylibs
+       for (int i=0; i < count; ++i) {
+               Options::FileInfo& entry = files[i];
+               // ignore /usr/lib/dyld on command line in crt.o build
+               if ( strcmp(entry.path, "/usr/lib/dyld") != 0 ) {
+                       try {
+                               this->addInputFile(this->createReader(entry));
+                       }
+                       catch (const char* msg) {
+                               if ( strstr(msg, "architecture") != NULL ) {
+                                       if (  fOptions.ignoreOtherArchInputFiles() ) {
+                                               // ignore, because this is about an architecture not in use
+                                       }
+                                       else {
+                                               fprintf(stderr, "ld64 warning: in %s, %s\n", entry.path, msg);
+                                       }
+                               }
+                               else {
+                                       throwf("in %s, %s", entry.path, msg);
+                               }
+                       }
+               }
+       }
+       
+       // add first level of indirect dylibs
+       fDirectLibrariesComplete = true;
+       for (std::vector<ExecutableFile::DyLibUsed>::iterator it=fDynamicLibraries.begin(); it != fDynamicLibraries.end(); it++) {
+               this->addIndirectLibraries(it->reader);
+       }
+       
+       // indirect handling depends on namespace
+       switch ( fOptions.nameSpace() ) {
+               case Options::kFlatNameSpace:
+               case Options::kForceFlatNameSpace:
+                       // with flat namespace, blindly load all indirect libraries
+                       // the indirect list will grow as indirect libraries are loaded
+                       for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
+                               struct stat statBuffer;
+                               if ( stat(it->path, &statBuffer) == 0 ) {
+                                       Options::FileInfo info;
+                                       info.path = it->path;
+                                       info.fileLen = statBuffer.st_size;
+                                       info.options.fWeakImport = false;
+                                       info.options.fReExport = false;
+                                       info.options.fInstallPathOverride = NULL;
+                                       it->reader = this->createReader(info);
+                               }
+                               else {
+                                       fprintf(stderr, "ld64 warning: indirect library not found: %s\n", it->path);
+                               }
+                       }
+                       break;
+                       
+               case Options::kTwoLevelNameSpace:
+                       // with two-level namespace we only want to use indirect libraries that are re-exported through a library that is used
+                       {
+                               bool indirectAdded = true;
+                               while ( indirectAdded ) {
+                                       indirectAdded = false;
+                                       // instantiate a reader for each indirect library and try to find parent that re-exports it
+                                       for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
+                                               if ( it->reader == NULL ) {
+                                                       try {
+                                                               struct stat statBuffer;
+                                                               if ( stat(it->path, &statBuffer) != 0 ) 
+                                                                       throw "file not found";
+                                                                       
+                                                               Options::FileInfo info;
+                                                               info.path = it->path;
+                                                               info.fileLen = statBuffer.st_size;
+                                                               info.options.fWeakImport = false;
+                                                               info.options.fReExport = false;
+                                                               info.options.fInstallPathOverride = NULL;
+                                                               it->reader = this->createReader(info);
+                                                               indirectAdded = true;
+                                                       }
+                                                       catch (const char* msg) {
+                                                               fprintf(stderr, "ld64 warning: indirect library %s could not be loaded: %s\n", it->path, msg);
+                                                       }
+                                               }
+                                               // if an indirect library does not have an assigned parent, look for one
+                                               if ( (it->reader != NULL) && (it->reExportParent == NULL) ) {
+                                                       // ask each parent if they re-export this dylib
+                                                       for (std::set<ObjectFile::Reader*>::iterator pit=it->parents.begin(); pit != it->parents.end(); pit++) {
+                                                               if ( (*pit)->reExports(it->reader) ) {
+                                                                       it->reExportParent = *pit;
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       break;
+       }
+       
+       // add relevant indirect libraries to the end of fDynamicLibraries
+       for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
+               if ( (it->reExportParent != NULL) || (fOptions.nameSpace() != Options::kTwoLevelNameSpace) ) {
+                       ExecutableFile::DyLibUsed dylibInfo;
+                       dylibInfo.reader = it->reader;
+                       dylibInfo.options.fWeakImport = false;
+                       dylibInfo.options.fReExport = false;
+                       dylibInfo.options.fInstallPathOverride = NULL;
+                       dylibInfo.indirect = true;
+                       dylibInfo.directReader = it->reExportParent;
+                       fDynamicLibraries.push_back(dylibInfo);
+                       if ( fOptions.readerOptions().fTraceIndirectDylibs )
+                               printf("[Logging for Build & Integration] Used indirect dynamic library: %s\n", it->path);
+               }
+       }
+}
+
+
+
+void Linker::addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info)
+{
+       if ( fDirectLibrariesComplete ) {
+               this->addIndirectLibraries(reader);
+       }
+       else {
+               if ( fOptions.readerOptions().fTraceDylibs )
+                       printf("[Logging for Build & Integration] Used dynamic library: %s\n", reader->getPath());
+               ExecutableFile::DyLibUsed dylibInfo;
+               dylibInfo.reader = reader;
+               dylibInfo.options = info.options;
+               dylibInfo.indirect = false;
+               dylibInfo.directReader = NULL;
+               fDynamicLibraries.push_back(dylibInfo);
+       }
+}
+
+
+void Linker::addIndirectLibraries(ObjectFile::Reader* reader)
+{
+       std::vector<const char*>* dependentLibs = reader->getDependentLibraryPaths();
+       if ( dependentLibs != NULL ) {
+               for (std::vector<const char*>::iterator it=dependentLibs->begin(); it != dependentLibs->end(); it++) {
+                       if ( this->haveDirectLibrary(*it) ) {
+                               // do nothing, direct library already exists
+                       }
+                       else if ( this->haveIndirectLibrary(*it, reader) ) {
+                               // side effect of haveIndirectLibrary() added reader to parent list
+                       }
+                       else {
+                               // add to list of indirect libraries
+                               IndirectLibrary indirectLib;
+                               indirectLib.path = *it;
+                               indirectLib.fileLen = 0;
+                               indirectLib.reader = NULL;
+                               indirectLib.parents.insert(reader);
+                               indirectLib.reExportParent = NULL;
+                               fIndirectDynamicLibraries.push_back(indirectLib);
+                               //fprintf(stderr, "add indirect library: %s\n", *it);
+                       }
+               }
+       }
+}
+
+bool Linker::haveIndirectLibrary(const char* path, ObjectFile::Reader* parentReader)
+{
+       for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
+               if ( strcmp(path, it->path) == 0 ) {
+                       it->parents.insert(parentReader);
+                       return true;
+               }
+               if ( it->reader != NULL ) {
+                       const char* installPath = it->reader->getInstallPath();
+                       if ( (installPath != NULL) && (strcmp(path, installPath) == 0) )
+                               return true;
+               }
+       }
+       return false;
+}
+
+bool Linker::haveDirectLibrary(const char* path)
+{
+       for (std::vector<ExecutableFile::DyLibUsed>::iterator it=fDynamicLibraries.begin(); it != fDynamicLibraries.end(); it++) {
+               if ( strcmp(path, it->reader->getPath()) == 0 )
+                       return true;
+               const char* installPath = it->reader->getInstallPath();
+               if ( (installPath != NULL) && (strcmp(path, installPath) == 0) )
+                       return true;
+       }
+       return false;
+}
+
+
+
+
+void Linker::createWriter()
+{
+       const char* path = fOptions.getOutputFilePath();
+       switch ( fOptions.architecture() ) {
+               case CPU_TYPE_POWERPC:
+                       this->setOutputFile(ppc::ExecutableFileMachO::MakeWriter(path, fOptions, fDynamicLibraries));
+                       break;
+               case CPU_TYPE_POWERPC64:
+                       this->setOutputFile(ppc64::ExecutableFileMachO::MakeWriter(path, fOptions, fDynamicLibraries));
+                       break;
+               case CPU_TYPE_I386:
+                       this->setOutputFile(i386::ExecutableFileMachO::MakeWriter(path, fOptions, fDynamicLibraries));
+                       break;
+               default:
+                       throw "unknown architecture";
+       }
+}
+
+
+Linker::SymbolTable::SymbolTable(Linker& owner)
+ : fOwner(owner), fRequireCount(0)
+{
+}
+
+void Linker::SymbolTable::require(const char* name)
+{
+       //fprintf(stderr, "require(%s)\n", name);
+       Mapper::iterator pos = fTable.find(name);
+       if ( pos == fTable.end() ) {
+               fTable[name] = NULL;
+               ++fRequireCount;
+       }
+}
+
+bool Linker::SymbolTable::add(ObjectFile::Atom& atom)
+{
+       const bool log = false;
+       const char* name = atom.getName();
+       //fprintf(stderr, "map.add(%p: %s => %p)\n", &fTable, name, &atom);
+       Mapper::iterator pos = fTable.find(name);
+       if ( pos != fTable.end() ) {
+               ObjectFile::Atom* existingAtom = pos->second;
+               if ( existingAtom != NULL ) {
+                       if ( existingAtom->isTentativeDefinition() ) {
+                               if ( atom.isTentativeDefinition() ) {
+                                       if ( atom.getSize() > existingAtom->getSize() ) {
+                                               // replace common-symbol atom with another larger common-symbol
+                                               if ( fOwner.fOptions.warnCommons() ) 
+                                                       fprintf(stderr, "ld64: replacing common symbol %s size %lld from %s with larger symbol size %lld from %s\n", 
+                                                                       existingAtom->getName(), existingAtom->getSize(), existingAtom->getFile()->getPath(), atom.getSize(), atom.getFile()->getPath());
+                                               fOwner.fDeadAtoms.insert(existingAtom);
+                                               fTable[name] = &atom;
+                                               return true;
+                                       }
+                                       else {
+                                               // keep existing common-symbol atom
+                                               if ( fOwner.fOptions.warnCommons() ) {
+                                                       if ( atom.getSize() == existingAtom->getSize() ) 
+                                                               fprintf(stderr, "ld64: ignoring common symbol %s from %s because already have common from %s with same size\n", 
+                                                                       atom.getName(), atom.getFile()->getPath(), existingAtom->getFile()->getPath());
+                                                       else
+                                                               fprintf(stderr, "ld64: ignoring common symbol %s size %lld from %s because already have larger symbol size %lld from %s\n", 
+                                                                       atom.getName(), atom.getSize(), atom.getFile()->getPath(), existingAtom->getSize(), existingAtom->getFile()->getPath());
+                                               }
+                                               fOwner.fDeadAtoms.insert(&atom);
+                                               return false;
+                                       }
+                               }
+                               else {
+                                       // have common symbol, now found true defintion
+                                       if ( atom.isImportProxy() ) {
+                                               // definition is in a dylib, so commons-mode decides how to handle
+                                               switch ( fOwner.fOptions.commonsMode() ) {
+                                                       case Options::kCommonsIgnoreDylibs:
+                                                               if ( fOwner.fOptions.warnCommons() ) 
+                                                                       fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n", 
+                                                                                       existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
+                                                               fOwner.fDeadAtoms.insert(&atom);
+                                                               return false;
+                                                       case Options::kCommonsOverriddenByDylibs:
+                                                               if ( fOwner.fOptions.warnCommons() ) 
+                                                                       fprintf(stderr, "ld64: replacing common symbol %s from %s with true definition from %s\n", 
+                                                                                       existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
+                                                               fOwner.fDeadAtoms.insert(existingAtom);
+                                                               fTable[name] = &atom;
+                                                               return true;
+                                                       case Options::kCommonsConflictsDylibsError:
+                                                               throwf("common symbol %s from %s conflicts with defintion from dylib %s", 
+                                                                               existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
+                                               }
+                                       }
+                                       else {
+                                               // replace common-symbol atom with true definition from .o file
+                                               if ( fOwner.fOptions.warnCommons() ) {
+                                                       if ( atom.getSize() < existingAtom->getSize() ) 
+                                                               fprintf(stderr, "ld64: warning: replacing common symbol %s size %lld from %s with smaller true definition size %lld from %s\n", 
+                                                                               existingAtom->getName(), existingAtom->getSize(), existingAtom->getFile()->getPath(), atom.getSize(), atom.getFile()->getPath());
+                                                       else
+                                                               fprintf(stderr, "ld64: replacing common symbol %s from %s with true definition from %s\n", 
+                                                                               existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
+                                               }
+                                               fOwner.fDeadAtoms.insert(existingAtom);
+                                               fTable[name] = &atom;
+                                               return true;
+                                       }
+                               }
+                       }
+                       else if ( atom.isTentativeDefinition() ) {
+                               // keep existing true definition, ignore new tentative definition
+                               if ( fOwner.fOptions.warnCommons() ) {
+                                       if ( atom.getSize() > existingAtom->getSize() ) 
+                                               fprintf(stderr, "ld64: warning: ignoring common symbol %s size %lld from %s because already have definition from %s size %lld, even though definition is smaller\n", 
+                                                       atom.getName(), atom.getSize(), atom.getFile()->getPath(), existingAtom->getFile()->getPath(), existingAtom->getSize());
+                                       else
+                                               fprintf(stderr, "ld64: ignoring common symbol %s from %s because already have definition from %s\n", 
+                                                       atom.getName(), atom.getFile()->getPath(), existingAtom->getFile()->getPath());
+                               }
+                               fOwner.fDeadAtoms.insert(&atom);
+                               return false;
+                       }
+                       else {
+                               // neither existing nor new atom are tentative definitions
+                               // if existing is weak, we may replace it
+                               if ( existingAtom->isWeakDefinition() ) {
+                                       if ( atom.isImportProxy() ) {
+                                               // keep weak definition even though one exists in a dylib, because coalescing means dylib's copy may not be used
+                                               if ( log ) fprintf(stderr, "keep weak atom even though also in a dylib: %s\n", atom.getName());
+                                               fOwner.fDeadAtoms.insert(&atom);
+                                               return false;
+                                       }
+                                       else if ( atom.isWeakDefinition() ) {
+                                               // have another weak atom, use existing, mark new as dead
+                                               if ( log ) fprintf(stderr, "already have weak atom: %s\n", atom.getName());
+                                               fOwner.fDeadAtoms.insert(&atom);
+                                               return false;
+                                       }
+                                       else {
+                                               // replace weak atom with non-weak atom
+                                               if ( log ) fprintf(stderr, "replacing weak atom %p from %s with %p from %s: %s\n", existingAtom, existingAtom->getFile()->getPath(), &atom, atom.getFile()->getPath(), atom.getName());
+                                               fOwner.fDeadAtoms.insert(existingAtom);
+                                               fTable[name] = &atom;
+                                               return true;
+                                       }
+                               }
+                       }
+                       if ( atom.isWeakDefinition() ) {
+                               // ignore new weak atom, because we already have a non-weak one
+                               return false;
+                       }
+                       if ( atom.isCoalesableByName() && existingAtom->isCoalesableByName() ) {
+                               // both coalesable, so ignore duplicate
+                               return false;
+                       }
+                       fprintf(stderr, "duplicate symbol %s in %s and %s\n", name, atom.getFile()->getPath(), existingAtom->getFile()->getPath());
+               }
+       }
+       fTable[name] = &atom;
+       return true;
+}
+
+ObjectFile::Atom* Linker::SymbolTable::find(const char* name)
+{
+       Mapper::iterator pos = fTable.find(name);
+       if ( pos != fTable.end() ) {
+               return pos->second;
+       }
+       return NULL;
+}
+
+
+void Linker::SymbolTable::getNeededNames(bool andWeakDefintions, std::vector<const char*>& undefines)
+{
+       for (Mapper::iterator it=fTable.begin(); it != fTable.end(); it++) {
+               if ( (it->second == NULL) || (andWeakDefintions && it->second->isWeakDefinition()) ) {
+                       undefines.push_back(it->first);
+               }
+       }
+}
+
+
+
+
+bool Linker::AtomSorter::operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
+{
+       // first sort by section order (which is already sorted by segment)
+       unsigned int leftSectionIndex  =  left->getSection()->getIndex();
+       unsigned int rightSectionIndex = right->getSection()->getIndex();
+       if ( leftSectionIndex != rightSectionIndex)
+               return (leftSectionIndex < rightSectionIndex);
+               
+       // with a section, sort by original atom order (.o file order and atom order in .o files)
+       return left->getSortOrder() < right->getSortOrder();
+}
+
+
+int main(int argc, const char* argv[])
+{
+       try {
+               // create linker object given command line arguments
+               Linker ld(argc, argv);
+               
+               // open all input files
+               ld.createReaders();
+               
+               // open output file
+               ld.createWriter();
+               
+               // do linking
+               ld.link();
+       }
+       catch (const char* msg) {
+               fprintf(stderr, "ld64 failed: %s\n", msg);
+               return 1;
+       }
+       
+       return 0;
+}
+
+
+
+
+
+
+