--- /dev/null
+APPLE PUBLIC SOURCE LICENSE
+Version 2.0 - August 6, 2003
+
+Please read this License carefully before downloading this software.
+By downloading or using this software, you are agreeing to be bound by
+the terms of this License. If you do not or cannot agree to the terms
+of this License, please do not download or use the software.
+
+1. General; Definitions. This License applies to any program or other
+work which Apple Computer, Inc. ("Apple") makes publicly available and
+which contains a notice placed by Apple identifying such program or
+work as "Original Code" and stating that it is subject to the terms of
+this Apple Public Source License version 2.0 ("License"). As used in
+this License:
+
+1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is
+the grantor of rights, (i) claims of patents that are now or hereafter
+acquired, owned by or assigned to Apple and (ii) that cover subject
+matter contained in the Original Code, but only to the extent
+necessary to use, reproduce and/or distribute the Original Code
+without infringement; and (b) in the case where You are the grantor of
+rights, (i) claims of patents that are now or hereafter acquired,
+owned by or assigned to You and (ii) that cover subject matter in Your
+Modifications, taken alone or in combination with Original Code.
+
+1.2 "Contributor" means any person or entity that creates or
+contributes to the creation of Modifications.
+
+1.3 "Covered Code" means the Original Code, Modifications, the
+combination of Original Code and any Modifications, and/or any
+respective portions thereof.
+
+1.4 "Externally Deploy" means: (a) to sublicense, distribute or
+otherwise make Covered Code available, directly or indirectly, to
+anyone other than You; and/or (b) to use Covered Code, alone or as
+part of a Larger Work, in any way to provide a service, including but
+not limited to delivery of content, through electronic communication
+with a client other than You.
+
+1.5 "Larger Work" means a work which combines Covered Code or portions
+thereof with code not governed by the terms of this License.
+
+1.6 "Modifications" mean any addition to, deletion from, and/or change
+to, the substance and/or structure of the Original Code, any previous
+Modifications, the combination of Original Code and any previous
+Modifications, and/or any respective portions thereof. When code is
+released as a series of files, a Modification is: (a) any addition to
+or deletion from the contents of a file containing Covered Code;
+and/or (b) any new file or other representation of computer program
+statements that contains any part of Covered Code.
+
+1.7 "Original Code" means (a) the Source Code of a program or other
+work as originally made available by Apple under this License,
+including the Source Code of any updates or upgrades to such programs
+or works made available by Apple under this License, and that has been
+expressly identified by Apple as such in the header file(s) of such
+work; and (b) the object code compiled from such Source Code and
+originally made available by Apple under this License.
+
+1.8 "Source Code" means the human readable form of a program or other
+work that is suitable for making modifications to it, including all
+modules it contains, plus any associated interface definition files,
+scripts used to control compilation and installation of an executable
+(object code).
+
+1.9 "You" or "Your" means an individual or a legal entity exercising
+rights under this License. For legal entities, "You" or "Your"
+includes any entity which controls, is controlled by, or is under
+common control with, You, where "control" means (a) the power, direct
+or indirect, to cause the direction or management of such entity,
+whether by contract or otherwise, or (b) ownership of fifty percent
+(50%) or more of the outstanding shares or beneficial ownership of
+such entity.
+
+2. Permitted Uses; Conditions & Restrictions. Subject to the terms
+and conditions of this License, Apple hereby grants You, effective on
+the date You accept this License and download the Original Code, a
+world-wide, royalty-free, non-exclusive license, to the extent of
+Apple's Applicable Patent Rights and copyrights covering the Original
+Code, to do the following:
+
+2.1 Unmodified Code. You may use, reproduce, display, perform,
+internally distribute within Your organization, and Externally Deploy
+verbatim, unmodified copies of the Original Code, for commercial or
+non-commercial purposes, provided that in each instance:
+
+(a) You must retain and reproduce in all copies of Original Code the
+copyright and other proprietary notices and disclaimers of Apple as
+they appear in the Original Code, and keep intact all notices in the
+Original Code that refer to this License; and
+
+(b) You must include a copy of this License with every copy of Source
+Code of Covered Code and documentation You distribute or Externally
+Deploy, and You may not offer or impose any terms on such Source Code
+that alter or restrict this License or the recipients' rights
+hereunder, except as permitted under Section 6.
+
+2.2 Modified Code. You may modify Covered Code and use, reproduce,
+display, perform, internally distribute within Your organization, and
+Externally Deploy Your Modifications and Covered Code, for commercial
+or non-commercial purposes, provided that in each instance You also
+meet all of these conditions:
+
+(a) You must satisfy all the conditions of Section 2.1 with respect to
+the Source Code of the Covered Code;
+
+(b) You must duplicate, to the extent it does not already exist, the
+notice in Exhibit A in each file of the Source Code of all Your
+Modifications, and cause the modified files to carry prominent notices
+stating that You changed the files and the date of any change; and
+
+(c) If You Externally Deploy Your Modifications, You must make
+Source Code of all Your Externally Deployed Modifications either
+available to those to whom You have Externally Deployed Your
+Modifications, or publicly available. Source Code of Your Externally
+Deployed Modifications must be released under the terms set forth in
+this License, including the license grants set forth in Section 3
+below, for as long as you Externally Deploy the Covered Code or twelve
+(12) months from the date of initial External Deployment, whichever is
+longer. You should preferably distribute the Source Code of Your
+Externally Deployed Modifications electronically (e.g. download from a
+web site).
+
+2.3 Distribution of Executable Versions. In addition, if You
+Externally Deploy Covered Code (Original Code and/or Modifications) in
+object code, executable form only, You must include a prominent
+notice, in the code itself as well as in related documentation,
+stating that Source Code of the Covered Code is available under the
+terms of this License with information on how and where to obtain such
+Source Code.
+
+2.4 Third Party Rights. You expressly acknowledge and agree that
+although Apple and each Contributor grants the licenses to their
+respective portions of the Covered Code set forth herein, no
+assurances are provided by Apple or any Contributor that the Covered
+Code does not infringe the patent or other intellectual property
+rights of any other entity. Apple and each Contributor disclaim any
+liability to You for claims brought by any other entity based on
+infringement of intellectual property rights or otherwise. As a
+condition to exercising the rights and licenses granted hereunder, You
+hereby assume sole responsibility to secure any other intellectual
+property rights needed, if any. For example, if a third party patent
+license is required to allow You to distribute the Covered Code, it is
+Your responsibility to acquire that license before distributing the
+Covered Code.
+
+3. Your Grants. In consideration of, and as a condition to, the
+licenses granted to You under this License, You hereby grant to any
+person or entity receiving or distributing Covered Code under this
+License a non-exclusive, royalty-free, perpetual, irrevocable license,
+under Your Applicable Patent Rights and other intellectual property
+rights (other than patent) owned or controlled by You, to use,
+reproduce, display, perform, modify, sublicense, distribute and
+Externally Deploy Your Modifications of the same scope and extent as
+Apple's licenses under Sections 2.1 and 2.2 above.
+
+4. Larger Works. You may create a Larger Work by combining Covered
+Code with other code not governed by the terms of this License and
+distribute the Larger Work as a single product. In each such instance,
+You must make sure the requirements of this License are fulfilled for
+the Covered Code or any portion thereof.
+
+5. Limitations on Patent License. Except as expressly stated in
+Section 2, no other patent rights, express or implied, are granted by
+Apple herein. Modifications and/or Larger Works may require additional
+patent licenses from Apple which Apple may grant in its sole
+discretion.
+
+6. Additional Terms. You may choose to offer, and to charge a fee for,
+warranty, support, indemnity or liability obligations and/or other
+rights consistent with the scope of the license granted herein
+("Additional Terms") to one or more recipients of Covered Code.
+However, You may do so only on Your own behalf and as Your sole
+responsibility, and not on behalf of Apple or any Contributor. You
+must obtain the recipient's agreement that any such Additional Terms
+are offered by You alone, and You hereby agree to indemnify, defend
+and hold Apple and every Contributor harmless for any liability
+incurred by or claims asserted against Apple or such Contributor by
+reason of any such Additional Terms.
+
+7. Versions of the License. Apple may publish revised and/or new
+versions of this License from time to time. Each version will be given
+a distinguishing version number. Once Original Code has been published
+under a particular version of this License, You may continue to use it
+under the terms of that version. You may also choose to use such
+Original Code under the terms of any subsequent version of this
+License published by Apple. No one other than Apple has the right to
+modify the terms applicable to Covered Code created under this
+License.
+
+8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in
+part pre-release, untested, or not fully tested works. The Covered
+Code may contain errors that could cause failures or loss of data, and
+may be incomplete or contain inaccuracies. You expressly acknowledge
+and agree that use of the Covered Code, or any portion thereof, is at
+Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND
+WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND
+APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE
+PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
+ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF
+MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR
+PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD
+PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST
+INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE
+FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS,
+THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
+ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO
+ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE
+AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.
+You acknowledge that the Covered Code is not intended for use in the
+operation of nuclear facilities, aircraft navigation, communication
+systems, or air traffic control machines in which case the failure of
+the Covered Code could lead to death, personal injury, or severe
+physical or environmental damage.
+
+9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
+EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL,
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING
+TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR
+ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY,
+TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF
+APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY
+REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF
+INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY
+TO YOU. In no event shall Apple's total liability to You for all
+damages (other than as may be required by applicable law) under this
+License exceed the amount of fifty dollars ($50.00).
+
+10. Trademarks. This License does not grant any rights to use the
+trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS",
+"QuickTime", "QuickTime Streaming Server" or any other trademarks,
+service marks, logos or trade names belonging to Apple (collectively
+"Apple Marks") or to any trademark, service mark, logo or trade name
+belonging to any Contributor. You agree not to use any Apple Marks in
+or as part of the name of products derived from the Original Code or
+to endorse or promote products derived from the Original Code other
+than as expressly permitted by and in strict compliance at all times
+with Apple's third party trademark usage guidelines which are posted
+at http://www.apple.com/legal/guidelinesfor3rdparties.html.
+
+11. Ownership. Subject to the licenses granted under this License,
+each Contributor retains all rights, title and interest in and to any
+Modifications made by such Contributor. Apple retains all rights,
+title and interest in and to the Original Code and any Modifications
+made by or on behalf of Apple ("Apple Modifications"), and such Apple
+Modifications will not be automatically subject to this License. Apple
+may, at its sole discretion, choose to license such Apple
+Modifications under this License, or on different terms from those
+contained in this License or may choose not to license them at all.
+
+12. Termination.
+
+12.1 Termination. This License and the rights granted hereunder will
+terminate:
+
+(a) automatically without notice from Apple if You fail to comply with
+any term(s) of this License and fail to cure such breach within 30
+days of becoming aware of such breach;
+
+(b) immediately in the event of the circumstances described in Section
+13.5(b); or
+
+(c) automatically without notice from Apple if You, at any time during
+the term of this License, commence an action for patent infringement
+against Apple; provided that Apple did not first commence
+an action for patent infringement against You in that instance.
+
+12.2 Effect of Termination. Upon termination, You agree to immediately
+stop any further use, reproduction, modification, sublicensing and
+distribution of the Covered Code. All sublicenses to the Covered Code
+which have been properly granted prior to termination shall survive
+any termination of this License. Provisions which, by their nature,
+should remain in effect beyond the termination of this License shall
+survive, including but not limited to Sections 3, 5, 8, 9, 10, 11,
+12.2 and 13. No party will be liable to any other for compensation,
+indemnity or damages of any sort solely as a result of terminating
+this License in accordance with its terms, and termination of this
+License will be without prejudice to any other right or remedy of
+any party.
+
+13. Miscellaneous.
+
+13.1 Government End Users. The Covered Code is a "commercial item" as
+defined in FAR 2.101. Government software and technical data rights in
+the Covered Code include only those rights customarily provided to the
+public as defined in this License. This customary commercial license
+in technical data and software is provided in accordance with FAR
+12.211 (Technical Data) and 12.212 (Computer Software) and, for
+Department of Defense purchases, DFAR 252.227-7015 (Technical Data --
+Commercial Items) and 227.7202-3 (Rights in Commercial Computer
+Software or Computer Software Documentation). Accordingly, all U.S.
+Government End Users acquire Covered Code with only those rights set
+forth herein.
+
+13.2 Relationship of Parties. This License will not be construed as
+creating an agency, partnership, joint venture or any other form of
+legal association between or among You, Apple or any Contributor, and
+You will not represent to the contrary, whether expressly, by
+implication, appearance or otherwise.
+
+13.3 Independent Development. Nothing in this License will impair
+Apple's right to acquire, license, develop, have others develop for
+it, market and/or distribute technology or products that perform the
+same or similar functions as, or otherwise compete with,
+Modifications, Larger Works, technology or products that You may
+develop, produce, market or distribute.
+
+13.4 Waiver; Construction. Failure by Apple or any Contributor to
+enforce any provision of this License will not be deemed a waiver of
+future enforcement of that or any other provision. Any law or
+regulation which provides that the language of a contract shall be
+construed against the drafter will not apply to this License.
+
+13.5 Severability. (a) If for any reason a court of competent
+jurisdiction finds any provision of this License, or portion thereof,
+to be unenforceable, that provision of the License will be enforced to
+the maximum extent permissible so as to effect the economic benefits
+and intent of the parties, and the remainder of this License will
+continue in full force and effect. (b) Notwithstanding the foregoing,
+if applicable law prohibits or restricts You from fully and/or
+specifically complying with Sections 2 and/or 3 or prevents the
+enforceability of either of those Sections, this License will
+immediately terminate and You must immediately discontinue any use of
+the Covered Code and destroy all copies of it that are in your
+possession or control.
+
+13.6 Dispute Resolution. Any litigation or other dispute resolution
+between You and Apple relating to this License shall take place in the
+Northern District of California, and You and Apple hereby consent to
+the personal jurisdiction of, and venue in, the state and federal
+courts within that District with respect to this License. The
+application of the United Nations Convention on Contracts for the
+International Sale of Goods is expressly excluded.
+
+13.7 Entire Agreement; Governing Law. This License constitutes the
+entire agreement between the parties with respect to the subject
+matter hereof. This License shall be governed by the laws of the
+United States and the State of California, except that body of
+California law concerning conflicts of law.
+
+Where You are located in the province of Quebec, Canada, the following
+clause applies: The parties hereby confirm that they have requested
+that this License and all related documents be drafted in English. Les
+parties ont exige que le present contrat et tous les documents
+connexes soient rediges en anglais.
+
+EXHIBIT A.
+
+"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
+Reserved.
+
+This file contains Original Code and/or Modifications of Original Code
+as defined in and that are subject to the Apple Public Source License
+Version 2.0 (the 'License'). You may not use this file except in
+compliance with the License. Please obtain a copy of the License at
+http://www.opensource.apple.com/apsl/ and read it before using this
+file.
+
+The Original Code and all software distributed under the License are
+distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+Please see the License for the specific language governing rights and
+limitations under the License."
--- /dev/null
+.so man1/ld.1
--- /dev/null
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 39;
+ objects = {
+ F9023C2C06D5A227001BBF46 = {
+ children = (
+ F971EED706D5AD240041D381,
+ F9023C3F06D5A254001BBF46,
+ F9C0D48A06DD1E1B001C7193,
+ F9C0D48B06DD1E1B001C7193,
+ F9023C3E06D5A254001BBF46,
+ F9023C4006D5A254001BBF46,
+ F9023C4106D5A254001BBF46,
+ F97288E607D277570031794D,
+ F972890007D27FD00031794D,
+ F9023C4206D5A254001BBF46,
+ F9023C4806D5A254001BBF46,
+ F97F5028070D0BB200B9FCD7,
+ F9023C3A06D5A23E001BBF46,
+ );
+ isa = PBXGroup;
+ refType = 4;
+ sourceTree = "<group>";
+ };
+ F9023C2E06D5A227001BBF46 = {
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ };
+ isa = PBXBuildStyle;
+ name = Development;
+ };
+ F9023C2F06D5A227001BBF46 = {
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ };
+ isa = PBXBuildStyle;
+ name = Deployment;
+ };
+ F9023C3006D5A227001BBF46 = {
+ buildSettings = {
+ };
+ buildStyles = (
+ F9023C2E06D5A227001BBF46,
+ F9023C2F06D5A227001BBF46,
+ );
+ hasScannedForEncodings = 0;
+ isa = PBXProject;
+ mainGroup = F9023C2C06D5A227001BBF46;
+ productRefGroup = F9023C3A06D5A23E001BBF46;
+ projectDirPath = "";
+ targets = (
+ F9023C3806D5A23E001BBF46,
+ F971EED206D5ACF60041D381,
+ );
+ };
+ F9023C3606D5A23E001BBF46 = {
+ buildActionMask = 2147483647;
+ files = (
+ F9023C4E06D5A272001BBF46,
+ F9C0D4BD06DD28D2001C7193,
+ F9023C4F06D5A272001BBF46,
+ F9023C5006D5A272001BBF46,
+ F97288E707D277570031794D,
+ );
+ isa = PBXSourcesBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F9023C3706D5A23E001BBF46 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXFrameworksBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F9023C3806D5A23E001BBF46 = {
+ buildPhases = (
+ F9023C3606D5A23E001BBF46,
+ F9023C3706D5A23E001BBF46,
+ F97F5025070D0B6300B9FCD7,
+ );
+ buildRules = (
+ );
+ 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;
+}
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __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__
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdint.h>
+#include <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);
+}
+
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <fcntl.h>
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+#include <mach-o/stab.h>
+
+
+#include "ObjectFile.h"
+#include "ObjectFileMachO-all.h"
+
+ __attribute__((noreturn))
+void throwf(const char* format, ...)
+{
+ va_list list;
+ char* p;
+ va_start(list, format);
+ vasprintf(&p, format, list);
+ va_end(list);
+
+ const char* t = p;
+ throw t;
+}
+
+static void dumpStabs(std::vector<ObjectFile::StabsInfo>* stabs)
+{
+ // debug info
+ const int stabCount = stabs->size();
+ printf("stabs: (%u)\n", stabCount);
+ for (int i=0; i < stabCount; ++i) {
+ ObjectFile::StabsInfo& stab = (*stabs)[i];
+ const char* code = "?????";
+ switch (stab.type) {
+ case N_GSYM:
+ code = " GSYM";
+ break;
+ case N_FNAME:
+ code = "FNAME";
+ break;
+ case N_FUN:
+ code = " FUN";
+ break;
+ case N_STSYM:
+ code = "STSYM";
+ break;
+ case N_LCSYM:
+ code = "LCSYM";
+ break;
+ case N_BNSYM:
+ code = "BNSYM";
+ break;
+ case N_OPT:
+ code = " OPT";
+ break;
+ case N_RSYM:
+ code = " RSYM";
+ break;
+ case N_SLINE:
+ code = "SLINE";
+ break;
+ case N_ENSYM:
+ code = "ENSYM";
+ break;
+ case N_SSYM:
+ code = " SSYM";
+ break;
+ case N_SO:
+ code = " SO";
+ break;
+ case N_LSYM:
+ code = " LSYM";
+ break;
+ case N_BINCL:
+ code = "BINCL";
+ break;
+ case N_SOL:
+ code = " SOL";
+ break;
+ case N_PARAMS:
+ code = "PARMS";
+ break;
+ case N_VERSION:
+ code = " VERS";
+ break;
+ case N_OLEVEL:
+ code = "OLEVL";
+ break;
+ case N_PSYM:
+ code = " PSYM";
+ break;
+ case N_EINCL:
+ code = "EINCL";
+ break;
+ case N_ENTRY:
+ code = "ENTRY";
+ break;
+ case N_LBRAC:
+ code = "LBRAC";
+ break;
+ case N_EXCL:
+ code = " EXCL";
+ break;
+ case N_RBRAC:
+ code = "RBRAC";
+ break;
+ case N_BCOMM:
+ code = "BCOMM";
+ break;
+ case N_ECOMM:
+ code = "ECOMM";
+ break;
+ case N_LENG:
+ code = "LENG";
+ break;
+ }
+ printf(" %08X %02X %04X %s %s\n", (uint32_t)stab.atomOffset, stab.other, stab.desc, code, stab.string);
+ }
+}
+
+
+static void dumpAtom(ObjectFile::Atom* atom)
+{
+ //printf("atom: %p\n", atom);
+
+ // name
+ printf("name: %s\n", atom->getDisplayName());
+
+ // scope
+ switch ( atom->getScope() ) {
+ case ObjectFile::Atom::scopeTranslationUnit:
+ printf("scope: translation unit\n");
+ break;
+ case ObjectFile::Atom::scopeLinkageUnit:
+ printf("scope: linkage unit\n");
+ break;
+ case ObjectFile::Atom::scopeGlobal:
+ printf("scope: global\n");
+ break;
+ default:
+ printf("scope: unknown\n");
+ }
+
+ // segment and section
+ printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
+
+ // attributes
+ printf("attrs: ");
+ if ( atom->isWeakDefinition() )
+ printf("weak ");
+ if ( atom->isCoalesableByName() )
+ printf("coalesce-by-name ");
+ if ( atom->isCoalesableByValue() )
+ printf("coalesce-by-value ");
+ if ( atom->dontDeadStrip() )
+ printf("dont-dead-strip ");
+ if ( atom->isZeroFill() )
+ printf("zero-fill ");
+ printf("\n");
+
+ // size
+ printf("size: 0x%012llX\n", atom->getSize());
+
+ // alignment
+ printf("align: %d\n", atom->getAlignment());
+
+ // content
+ uint64_t size = atom->getSize();
+ if ( size < 4096 ) {
+ uint8_t content[size];
+ atom->copyRawContent(content);
+ printf("content: ");
+ if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
+ printf("\"%s\"", content);
+ }
+ else {
+ for (unsigned int i=0; i < size; ++i)
+ printf("%02X ", content[i]);
+ }
+ }
+ printf("\n");
+
+ // references
+ std::vector<ObjectFile::Reference*>& references = atom->getReferences();
+ const int refCount = references.size();
+ printf("references: (%u)\n", refCount);
+ for (int i=0; i < refCount; ++i) {
+ ObjectFile::Reference* ref = references[i];
+ printf(" %s\n", ref->getDescription());
+ }
+
+ // debug info
+ std::vector<ObjectFile::StabsInfo>* stabs = atom->getStabsDebugInfo();
+ if ( stabs != NULL )
+ dumpStabs(stabs);
+}
+
+
+static void dumpFile(ObjectFile::Reader* reader)
+{
+#if 0
+ // debug info
+ std::vector<ObjectFile::StabsInfo>* stabs = reader->getStabsDebugInfo();
+ if ( stabs != NULL )
+ dumpStabs(stabs);
+#endif
+ // atom content
+ std::vector<ObjectFile::Atom*> atoms = reader->getAtoms();
+ const int atomCount = atoms.size();
+ for(int i=0; i < atomCount; ++i) {
+ dumpAtom(atoms[i]);
+ printf("\n");
+ }
+}
+
+
+static ObjectFile::Reader* createReader(const char* path, const ObjectFile::ReaderOptions& options)
+{
+ struct stat stat_buf;
+
+ int fd = ::open(path, O_RDONLY, 0);
+ if ( fd == -1 )
+ throw "cannot open file";
+ ::fstat(fd, &stat_buf);
+ char* p = (char*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE, fd, 0);
+ ::close(fd);
+ const mach_header* mh = (mach_header*)p;
+ if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+ const struct fat_header* fh = (struct fat_header*)p;
+ const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
+ for (unsigned long i=0; i < fh->nfat_arch; ++i) {
+ if ( archs[i].cputype == CPU_TYPE_POWERPC64 ) {
+ p = p + archs[i].offset;
+ mh = (struct mach_header*)p;
+ }
+ }
+ }
+ if ( mh->magic == MH_MAGIC ) {
+ if ( mh->filetype == MH_OBJECT ) {
+ switch ( mh->cputype ) {
+ case CPU_TYPE_I386:
+ return i386::ObjectFileMachO::MakeReader((class i386::macho_header*)mh, path, options);
+ case CPU_TYPE_POWERPC:
+ return ppc::ObjectFileMachO::MakeReader((class ppc::macho_header*)mh, path, options);
+ case CPU_TYPE_POWERPC64:
+ return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
+ default:
+ throw "unknown mach-o cpu type";
+ }
+ }
+ if ( mh->filetype == MH_DYLIB )
+ return ppc::ObjectFileDylibMachO::MakeReader((class ppc::macho_header*)mh, path, options);
+ throw "unknown mach-o file type";
+ }
+ else if ( mh->magic == MH_MAGIC_64 ) {
+ if ( mh->filetype == MH_OBJECT )
+ return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
+ if ( mh->filetype == MH_DYLIB )
+ return ppc64::ObjectFileDylibMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
+ throw "unknown mach-o file type";
+ }
+ else if ( mh->magic == OSSwapInt32(MH_MAGIC) ) {
+ if ( mh->filetype == OSSwapInt32(MH_OBJECT) ) {
+ switch ( OSSwapInt32(mh->cputype) ) {
+ case CPU_TYPE_I386:
+ return i386::ObjectFileMachO::MakeReader((class i386::macho_header*)mh, path, options);
+ case CPU_TYPE_POWERPC:
+ return ppc::ObjectFileMachO::MakeReader((class ppc::macho_header*)mh, path, options);
+ case CPU_TYPE_POWERPC64:
+ return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
+ default:
+ throw "unknown mach-o cpu type";
+ }
+ }
+ if ( mh->filetype == OSSwapInt32(MH_DYLIB) )
+ return ppc::ObjectFileDylibMachO::MakeReader((class ppc::macho_header*)mh, path, options);
+ throw "unknown mach-o file type";
+ }
+ else if ( mh->magic == OSSwapInt32(MH_MAGIC_64) ) {
+ if ( mh->filetype == OSSwapInt32(MH_OBJECT) )
+ return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
+ if ( mh->filetype == OSSwapInt32(MH_DYLIB) )
+ return ppc64::ObjectFileDylibMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
+ throw "unknown mach-o file type";
+ }
+ throw "unknown file type";
+}
+
+
+int main(int argc, const char* argv[])
+{
+ ObjectFile::ReaderOptions options;
+ //const char* path = argv[1];
+ //ObjectFile::Reader* reader = ObjectFile::Reader::createReader(path);
+ try {
+ ObjectFile::Reader* reader = createReader("/tmp/gcov-1.o", options);
+
+ dumpFile(reader);
+ }
+ catch (const char* msg) {
+ fprintf(stderr, "ObjDump failed: %s\n", msg);
+ }
+
+ return 0;
+}
+
+
+
--- /dev/null
+/*
+ * 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__
+
+
+
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <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";
+}
+
+
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __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__
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+
+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);
+}
+
+
+
+};
+
+
+
+
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+
+namespace ObjectFileDylibMachO {
+
+class Reader : public ObjectFile::Reader
+{
+public:
+ Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options);
+ virtual ~Reader();
+
+ virtual const char* getPath();
+ virtual std::vector<class ObjectFile::Atom*>& getAtoms();
+ virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name);
+ virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo();
+ virtual const char* getInstallPath();
+ virtual uint32_t getTimestamp();
+ virtual uint32_t getCurrentVersion();
+ virtual uint32_t getCompatibilityVersion();
+ virtual std::vector<const char*>* getDependentLibraryPaths();
+ virtual bool reExports(ObjectFile::Reader*);
+ virtual bool isDefinitionWeak(const ObjectFile::Atom&);
+
+private:
+ struct CStringComparor
+ {
+ bool operator()(const char* left, const char* right) { return (strcmp(left, right) > 0); }
+ };
+ typedef std::map<const char*, ObjectFile::Atom*, CStringComparor> Mapper;
+
+
+ void init(const macho_header* header,const char* path);
+ const macho_nlist* binarySearchWithToc(const char* key, const char stringPool[], const macho_nlist symbols[], const struct dylib_table_of_contents toc[], uint32_t symbolCount);
+ const macho_nlist* binarySearch(const char* key, const char stringPool[], const macho_nlist symbols[], uint32_t symbolCount);
+ bool hasExport(const char* name);
+ const macho_nlist* findExport(const char* name);
+
+ const char* fPath;
+ const macho_header* fHeader;
+ const char* fStrings;
+ const macho_dysymtab_command* fDynamicInfo;
+ const macho_dylib_command* fDylibID;
+ const macho_nlist* fSymbols;
+ uint32_t fSymbolCount;
+ Mapper fAtoms;
+ std::vector<Reader*> fReExportedDylibs;
+
+ static std::vector<class ObjectFile::Atom*> fEmptyAtomList;
+};
+
+std::vector<class ObjectFile::Atom*> Reader::fEmptyAtomList;
+
+
+class Segment : public ObjectFile::Segment
+{
+public:
+ Segment(const char* name) { fName = name; }
+ virtual const char* getName() const { return fName; }
+ virtual bool isContentReadable() const { return true; }
+ virtual bool isContentWritable() const { return false; }
+ virtual bool isContentExecutable() const { return false; }
+private:
+ const char* fName;
+};
+
+
+class ExportAtom : public ObjectFile::Atom
+{
+public:
+ virtual ObjectFile::Reader* getFile() const { return &fOwner; }
+ virtual const char* getName() const { return fName; }
+ virtual const char* getDisplayName() const;
+ virtual Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
+ virtual bool isTentativeDefinition() const { return false; }
+ virtual bool isWeakDefinition() const { return false; }
+ virtual bool isCoalesableByName() const { return false; }
+ virtual bool isCoalesableByValue() const { return false; }
+ virtual bool isZeroFill() const { return false; }
+ virtual bool dontDeadStrip() const { return false; }
+ virtual bool dontStripName() const { return false; }
+ virtual bool isImportProxy() const { return true; }
+ virtual uint64_t getSize() const { return 0; }
+ virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
+ virtual bool mustRemainInSection() const { return false; }
+ virtual const char* getSectionName() const { return "._imports"; }
+ virtual Segment& getSegment() const { return fgImportSegment; }
+ virtual bool requiresFollowOnAtom() const{ return false; }
+ virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
+ virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo() const { return NULL; }
+ virtual uint8_t getAlignment() const { return 0; }
+ virtual WeakImportSetting getImportWeakness() const { return fWeakImportSetting; }
+ virtual void copyRawContent(uint8_t buffer[]) const {}
+ virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
+
+ virtual void setScope(Scope) { }
+ virtual void setImportWeakness(bool weakImport) { fWeakImportSetting = weakImport ? kWeakImport : kNonWeakImport; }
+
+protected:
+ friend class Reader;
+
+ ExportAtom(Reader& owner, const char* name) : fOwner(owner), fName(name), fWeakImportSetting(kWeakUnset) {}
+ virtual ~ExportAtom() {}
+
+ Reader& fOwner;
+ const char* fName;
+ WeakImportSetting fWeakImportSetting;
+
+ static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
+ static Segment fgImportSegment;
+};
+
+Segment ExportAtom::fgImportSegment("__LINKEDIT");
+std::vector<ObjectFile::Reference*> ExportAtom::fgEmptyReferenceList;
+
+const char* ExportAtom::getDisplayName() const
+{
+ static char temp[300];
+ strcpy(temp, fName);
+ strcat(temp, "$import");
+ return temp;
+}
+
+
+
+Reader::Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options)
+ : fHeader(header), fStrings(NULL), fDylibID(NULL), fSymbols(NULL), fSymbolCount(0)
+{
+ typedef std::pair<const macho_dylib_command*, bool> DylibAndReExportFlag;
+ std::vector<DylibAndReExportFlag> dependentDylibs;
+
+ fPath = strdup(path);
+ const uint32_t cmd_count = header->ncmds();
+ const macho_load_command* const cmds = (macho_load_command*)((char*)header + macho_header::size);
+ // get all dylib load commands
+ const macho_load_command* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch (cmd->cmd()) {
+ case LC_LOAD_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ {
+ DylibAndReExportFlag info;
+ info.first = (struct macho_dylib_command*)cmd;
+ info.second = options.fFlatNamespace;
+ dependentDylibs.push_back(info);
+ }
+ break;
+ }
+ cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
+ }
+
+ // cache interesting pointers
+ cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch (cmd->cmd()) {
+ case LC_SYMTAB:
+ {
+ const macho_symtab_command* symtab = (macho_symtab_command*)cmd;
+ fSymbolCount = symtab->nsyms();
+ fSymbols = (const macho_nlist*)((char*)header + symtab->symoff());
+ fStrings = (char*)header + symtab->stroff();
+ }
+ break;
+ case LC_DYSYMTAB:
+ fDynamicInfo = (macho_dysymtab_command*)cmd;
+ break;
+ case LC_ID_DYLIB:
+ fDylibID = (macho_dylib_command*)cmd;
+ break;
+ case LC_SUB_UMBRELLA:
+ if ( !options.fFlatNamespace ) {
+ const char* frameworkLeafName = ((macho_sub_umbrella_command*)cmd)->name();
+ for (std::vector<DylibAndReExportFlag>::iterator it = dependentDylibs.begin(); it != dependentDylibs.end(); it++) {
+ const char* dylibName = it->first->name();
+ const char* lastSlash = strrchr(dylibName, '/');
+ if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
+ it->second = true;
+ }
+ }
+ break;
+ case LC_SUB_LIBRARY:
+ if ( !options.fFlatNamespace ) {
+ const char* dylibBaseName = ((macho_sub_library_command*)cmd)->name();
+ for (std::vector<DylibAndReExportFlag>::iterator it = dependentDylibs.begin(); it != dependentDylibs.end(); it++) {
+ const char* dylibName = it->first->name();
+ const char* lastSlash = strrchr(dylibName, '/');
+ const char* leafStart = &lastSlash[1];
+ if ( lastSlash == NULL )
+ leafStart = dylibName;
+ const char* firstDot = strchr(leafStart, '.');
+ int len = strlen(leafStart);
+ if ( firstDot != NULL )
+ len = firstDot - leafStart;
+ if ( strncmp(leafStart, dylibBaseName, len) == 0 )
+ it->second = true;
+ }
+ }
+ break;
+ }
+ cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
+ }
+
+ // load dylibs we need to re-export
+ for (std::vector<DylibAndReExportFlag>::iterator it = dependentDylibs.begin(); it != dependentDylibs.end(); it++) {
+ if ( it->second ) {
+ // printf("%s need to re-export %s\n", path, it->first->name());
+ //fReExportedDylibs.push_back(
+ }
+ }
+}
+
+
+Reader::~Reader()
+{
+}
+
+const char* Reader::getPath()
+{
+ return fPath;
+}
+
+
+std::vector<class ObjectFile::Atom*>& Reader::getAtoms()
+{
+ return fEmptyAtomList;
+}
+
+
+
+const macho_nlist* Reader::binarySearchWithToc(const char* key, const char stringPool[], const macho_nlist symbols[],
+ const struct dylib_table_of_contents toc[], uint32_t symbolCount)
+{
+ int32_t high = symbolCount-1;
+ int32_t mid = symbolCount/2;
+
+ for (int32_t low = 0; low <= high; mid = (low+high)/2) {
+ const uint32_t index = ENDIAN_READ32(toc[mid].symbol_index);
+ const macho_nlist* pivot = &symbols[index];
+ const char* pivotStr = &stringPool[pivot->n_strx()];
+ int cmp = strcmp(key, pivotStr);
+ if ( cmp == 0 )
+ return pivot;
+ if ( cmp > 0 ) {
+ // key > pivot
+ low = mid + 1;
+ }
+ else {
+ // key < pivot
+ high = mid - 1;
+ }
+ }
+ return NULL;
+}
+
+
+const macho_nlist* Reader::binarySearch(const char* key, const char stringPool[], const macho_nlist symbols[], uint32_t symbolCount)
+{
+ const macho_nlist* base = symbols;
+ for (uint32_t n = symbolCount; n > 0; n /= 2) {
+ const macho_nlist* pivot = &base[n/2];
+ const char* pivotStr = &stringPool[pivot->n_strx()];
+ int cmp = strcmp(key, pivotStr);
+ if ( cmp == 0 )
+ return pivot;
+ if ( cmp > 0 ) {
+ // key > pivot
+ // move base to symbol after pivot
+ base = &pivot[1];
+ --n;
+ }
+ else {
+ // key < pivot
+ // keep same base
+ }
+ }
+ return NULL;
+}
+
+const macho_nlist* Reader::findExport(const char* name)
+{
+ if ( fDynamicInfo->tocoff() == 0 )
+ return binarySearch(name, fStrings, &fSymbols[fDynamicInfo->iextdefsym()], fDynamicInfo->nextdefsym());
+ else {
+ return binarySearchWithToc(name, fStrings, fSymbols, (dylib_table_of_contents*)((char*)fHeader + fDynamicInfo->tocoff()),
+ fDynamicInfo->nextdefsym());
+ }
+}
+
+bool Reader::hasExport(const char* name)
+{
+ return ( findExport(name) != NULL );
+}
+
+std::vector<class ObjectFile::Atom*>* Reader::getJustInTimeAtomsFor(const char* name)
+{
+ std::vector<class ObjectFile::Atom*>* atoms = NULL;
+ // search exports
+ if ( this->hasExport(name) ) {
+ // see if this atom already synthesized
+ ObjectFile::Atom* atom = NULL;
+ Mapper::iterator pos = fAtoms.find(name);
+ if ( pos != fAtoms.end() ) {
+ atom = pos->second;
+ }
+ else {
+ atom = new ExportAtom(*this, name);
+ fAtoms[name] = atom;
+ }
+ // return a vector of one atom
+ atoms = new std::vector<class ObjectFile::Atom*>;
+ atoms->push_back(atom);
+ return atoms;
+ }
+
+ // check re-exports
+ for (std::vector<Reader*>::iterator it = fReExportedDylibs.begin(); it != fReExportedDylibs.end(); it++) {
+ Reader* reExportedReader = *it;
+ atoms = reExportedReader->getJustInTimeAtomsFor(name);
+ if ( atoms != NULL )
+ return atoms;
+ }
+
+ return NULL;
+}
+
+
+std::vector<ObjectFile::StabsInfo>* Reader::getStabsDebugInfo()
+{
+ return NULL;
+}
+
+const char* Reader::getInstallPath()
+{
+ return fDylibID->name();
+}
+
+uint32_t Reader::getTimestamp()
+{
+ return fDylibID->timestamp();
+}
+
+uint32_t Reader::getCurrentVersion()
+{
+ return fDylibID->current_version();
+}
+
+uint32_t Reader::getCompatibilityVersion()
+{
+ return fDylibID->compatibility_version();
+}
+
+std::vector<const char*>* Reader::getDependentLibraryPaths()
+{
+ std::vector<const char*>* result = new std::vector<const char*>;
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command* const cmds = (macho_load_command*)((char*)fHeader + macho_header::size);
+ const macho_load_command* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch (cmd->cmd()) {
+ case LC_LOAD_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ {
+ result->push_back(((struct macho_dylib_command*)cmd)->name());
+ }
+ break;
+ }
+ cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
+ }
+ return result;
+}
+
+bool Reader::reExports(ObjectFile::Reader* child)
+{
+ // A dependent dylib is re-exported under two conditions:
+ // 1) parent contains LC_SUB_UMBRELLA or LC_SUB_LIBRARY with child name
+ {
+ const uint32_t cmd_count = fHeader->ncmds();
+ const macho_load_command* const cmds = (macho_load_command*)((char*)fHeader + macho_header::size);
+ const macho_load_command* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch (cmd->cmd()) {
+ case LC_SUB_UMBRELLA:
+ {
+ const char* frameworkLeafName = ((macho_sub_umbrella_command*)cmd)->name();
+ const char* dylibName = child->getPath();
+ const char* lastSlash = strrchr(dylibName, '/');
+ if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
+ return true;
+ }
+ break;
+ case LC_SUB_LIBRARY:
+ {
+ const char* dylibBaseName = ((macho_sub_library_command*)cmd)->name();
+ const char* dylibName = child->getPath();
+ const char* lastSlash = strrchr(dylibName, '/');
+ const char* leafStart = &lastSlash[1];
+ if ( lastSlash == NULL )
+ leafStart = dylibName;
+ const char* firstDot = strchr(leafStart, '.');
+ int len = strlen(leafStart);
+ if ( firstDot != NULL )
+ len = firstDot - leafStart;
+ if ( strncmp(leafStart, dylibBaseName, len) == 0 )
+ return true;
+ }
+ break;
+ }
+ cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
+ }
+ }
+
+ // 2) child contains LC_SUB_FRAMEWORK with parent name
+ {
+ const uint32_t cmd_count = ((Reader*)child)->fHeader->ncmds();
+ const macho_load_command* const cmds = (macho_load_command*)((char*)(((Reader*)child)->fHeader) + macho_header::size);
+ const macho_load_command* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch (cmd->cmd()) {
+ case LC_SUB_FRAMEWORK:
+ {
+ const char* frameworkLeafName = ((macho_sub_framework_command*)cmd)->name();
+ const char* parentName = this->getPath();
+ const char* lastSlash = strrchr(parentName, '/');
+ if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
+ return true;
+ }
+ break;
+ }
+ cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
+ }
+ }
+
+
+ return false;
+}
+
+bool Reader::isDefinitionWeak(const ObjectFile::Atom& atom)
+{
+ const macho_nlist* sym = findExport(atom.getName());
+ if ( sym != NULL ) {
+ if ( (sym->n_desc() & N_WEAK_DEF) != 0 )
+ return true;
+ }
+ return false;
+}
+
+
+
+Reader* MakeReader(const macho_header* mh, const char* path, const ObjectFile::ReaderOptions& options)
+{
+ return new Reader(mh, path, options);
+}
+
+
+
+};
+
+
+
+
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include <ar.h>
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/reloc.h>
+#include <mach-o/ppc/reloc.h>
+#include <mach-o/ranlib.h>
+#include <mach-o/stab.h>
+
+#include "ObjectFile.h"
+#include "Options.h"
+
+
+
+
+// buiild Writer for -arch ppc64
+#undef MACHO_32_SAME_ENDIAN
+#undef MACHO_32_OPPOSITE_ENDIAN
+#undef MACHO_64_SAME_ENDIAN
+#undef MACHO_64_OPPOSITE_ENDIAN
+#if __ppc__ || __ppc64__
+ #define MACHO_64_SAME_ENDIAN
+#elif __i386__
+ #define MACHO_64_OPPOSITE_ENDIAN
+#else
+ #error unknown architecture
+#endif
+namespace ppc64 {
+ #undef ARCH_PPC
+ #define ARCH_PPC64
+ #undef ARCH_I386
+ #include "MachOAbstraction.h"
+ #include "ObjectFileMachO.cpp"
+ #include "ObjectFileDylibMachO.cpp"
+ #include "ObjectFileArchiveMachO.cpp"
+};
+
+// buiild Writer for -arch ppc
+#undef MACHO_32_SAME_ENDIAN
+#undef MACHO_32_OPPOSITE_ENDIAN
+#undef MACHO_64_SAME_ENDIAN
+#undef MACHO_64_OPPOSITE_ENDIAN
+#if __ppc__ || __ppc64__
+ #define MACHO_32_SAME_ENDIAN
+#elif __i386__
+ #define MACHO_32_OPPOSITE_ENDIAN
+#else
+ #error unknown architecture
+#endif
+namespace ppc {
+ #define ARCH_PPC
+ #undef ARCH_PPC64
+ #undef ARCH_I386
+ #include "MachOAbstraction.h"
+ #include "ObjectFileMachO.cpp"
+ #include "ObjectFileDylibMachO.cpp"
+ #include "ObjectFileArchiveMachO.cpp"
+};
+
+
+// buiild Writer for -arch i386
+#undef MACHO_32_SAME_ENDIAN
+#undef MACHO_32_OPPOSITE_ENDIAN
+#undef MACHO_64_SAME_ENDIAN
+#undef MACHO_64_OPPOSITE_ENDIAN
+#if __ppc__ || __ppc64__
+ #define MACHO_32_OPPOSITE_ENDIAN
+#elif __i386__
+ #define MACHO_32_SAME_ENDIAN
+#else
+ #error unknown architecture
+#endif
+#undef i386 // compiler sometimes #defines this
+namespace i386 {
+ #undef ARCH_PPC
+ #undef ARCH_PPC64
+ #define ARCH_I386
+ #include "MachOAbstraction.h"
+ #include "ObjectFileMachO.cpp"
+ #include "ObjectFileDylibMachO.cpp"
+ #include "ObjectFileArchiveMachO.cpp"
+};
+
+
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __OBJECTFILEMACHO__
+#define __OBJECTFILEMACHO__
+
+class Options;
+
+namespace ppc {
+ class macho_header;
+ namespace ObjectFileMachO {
+ extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
+ };
+ namespace ObjectFileDylibMachO {
+ extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
+ };
+ namespace ObjectFileArchiveMachO {
+ extern class ObjectFile::Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
+ };
+};
+
+namespace ppc64 {
+ class macho_header;
+ namespace ObjectFileMachO {
+ extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
+ };
+ namespace ObjectFileDylibMachO {
+ extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
+ };
+ namespace ObjectFileArchiveMachO {
+ extern class ObjectFile::Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
+ };
+};
+
+#undef i386 // compiler sometimes #defines this
+namespace i386 {
+ class macho_header;
+ namespace ObjectFileMachO {
+ extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
+ };
+ namespace ObjectFileDylibMachO {
+ extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
+ };
+ namespace ObjectFileArchiveMachO {
+ extern class ObjectFile::Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
+ };
+};
+
+
+
+#endif // __OBJECTFILEMACHO__
+
+
+
--- /dev/null
+/*
+ * 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 = §ionsStart[fSegment->nsects()];
+ std::set<uint32_t> cleavePoints;
+ std::set<uint32_t> dontCleavePoints;
+ for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+ const macho_relocation_info* relocs = (macho_relocation_info*)((char*)(fHeader) + sect->reloff());
+ const uint32_t relocCount = sect->nreloc();
+ for (uint32_t r = 0; r < relocCount; ++r) {
+ buildOffsetsSet(&relocs[r], sect, cleavePoints, dontCleavePoints);
+ }
+ }
+ // add all stub functions and (non)lazy pointers
+ std::set<uint32_t> deadStubOffsets;
+ for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+ uint8_t type (sect->flags() & SECTION_TYPE);
+ switch ( type ) {
+ case S_SYMBOL_STUBS:
+ {
+ const uint32_t stubSize = sect->reserved2();
+ // TVector glue sections are marked as S_SYMBOL_STUBS but are only 8 bytes
+ if ( stubSize > 8 ) {
+ for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += stubSize) {
+ uint32_t stubAddr = sect->addr() + sectOffset;
+ if ( cleavePoints.count(stubAddr) == 0 ) {
+ cleavePoints.insert(stubAddr);
+ deadStubOffsets.insert(stubAddr);
+ }
+ }
+ }
+ }
+ break;
+ case S_NON_LAZY_SYMBOL_POINTERS:
+ case S_LAZY_SYMBOL_POINTERS:
+ for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += sizeof(macho_uintptr_t)) {
+ uint32_t pointerAddr = sect->addr() + sectOffset;
+ cleavePoints.insert(pointerAddr);
+ }
+ break;
+ }
+ // also make sure each section break is a cleave point
+ if ( sect->size() != 0 )
+ cleavePoints.insert(sect->addr());
+ }
+
+ for (std::set<uint32_t>::iterator it=cleavePoints.begin(); it != cleavePoints.end(); it++) {
+ uint32_t cleavePoint = *it;
+ //printf("cleave offset 0x%08X\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 = §ionsStart[fSegment->nsects()];
+ for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+ if ( (sect->addr() <= offset) && (offset < (sect->addr() + sect->size())) )
+ return sect;
+ }
+ return NULL;
+}
+
+
+void Reader::buildOffsetsSet(const macho_relocation_info* reloc, const macho_section* sect, std::set<uint32_t>& cleavePoints, std::set<uint32_t>& dontCleavePoints)
+{
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+ uint32_t targetAddr;
+#endif
+ if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+ uint32_t* fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+ uint32_t instruction;
+#endif
+ switch ( reloc->r_type() ) {
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+ case PPC_RELOC_BR14:
+ // do nothing. local branch should not cleave
+ break;
+ case PPC_RELOC_BR24:
+ {
+ if ( ! reloc->r_extern() ) {
+ instruction = OSSwapBigToHostInt32(*fixUpPtr);
+ if ( (instruction & 0x4C000000) == 0x48000000 ) {
+ int32_t displacement = (instruction & 0x03FFFFFC);
+ if ( (displacement & 0x02000000) != 0 )
+ displacement |= 0xFC000000;
+ //cleavePoints.insert(reloc->r_address() + displacement);
+ insertOffset(cleavePoints, sect->addr() + reloc->r_address() + displacement);
+ }
+ }
+ }
+ break;
+ case PPC_RELOC_PAIR:
+ // skip, processed by a look ahead
+ break;
+ case PPC_RELOC_LO16:
+ {
+ const macho_relocation_info* nextReloc = &reloc[1];
+ if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+ printf("PPC_RELOC_LO16 missing following pair\n");
+ break;
+ }
+ if ( ! reloc->r_extern() ) {
+ instruction = OSSwapBigToHostInt32(*fixUpPtr);
+ targetAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFF);
+ //cleavePoints.insert(targetAddr);
+ insertOffset(cleavePoints, (targetAddr));
+ }
+ }
+ break;
+ case PPC_RELOC_LO14:
+ {
+ const macho_relocation_info* nextReloc = &reloc[1];
+ if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+ printf("PPC_RELOC_LO14 missing following pair\n");
+ break;
+ }
+ if ( ! reloc->r_extern() ) {
+ instruction = OSSwapBigToHostInt32(*fixUpPtr);
+ targetAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC);
+ //cleavePoints.insert(targetAddr);
+ insertOffset(cleavePoints, (targetAddr));
+ }
+ }
+ break;
+ case PPC_RELOC_HI16:
+ {
+ const macho_relocation_info* nextReloc = &reloc[1];
+ if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+ printf("PPC_RELOC_HI16 missing following pair\n");
+ break;
+ }
+ if ( ! reloc->r_extern() ) {
+ instruction = OSSwapBigToHostInt32(*fixUpPtr);
+ targetAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
+ //cleavePoints.insert(targetAddr);
+ insertOffset(cleavePoints, targetAddr);
+ }
+ }
+ break;
+ case PPC_RELOC_HA16:
+ {
+ const macho_relocation_info* nextReloc = &reloc[1];
+ if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+ printf("PPC_RELOC_HA16 missing following pair\n");
+ break;
+ }
+ if ( ! reloc->r_extern() ) {
+ instruction = OSSwapBigToHostInt32(*fixUpPtr);
+ int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF);
+ targetAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
+ //cleavePoints.insert(targetAddr);
+ insertOffset(cleavePoints, targetAddr);
+ }
+ }
+ break;
+ case PPC_RELOC_JBSR:
+ // ignore for now
+ break;
+#endif
+ case GENERIC_RELOC_VANILLA:
+ {
+#if defined(ARCH_PPC64)
+ if ( reloc->r_length() != 3 )
+ throw "vanilla pointer relocation found that is not 8-bytes";
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+ if ( reloc->r_length() != 2 )
+ throw "vanilla pointer relocation found that is not 4-bytes";
+#endif
+ //fprintf(stderr, "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 = §ions[fSymbol->n_sect()-1];
+ fSegment = owner.makeSegmentFromSection(fSection);
+ fOffset = fSymbol->n_value();
+ uint8_t type = fSection->flags() & SECTION_TYPE;
+ switch ( type ) {
+ case S_LAZY_SYMBOL_POINTERS:
+ case S_NON_LAZY_SYMBOL_POINTERS:
+ {
+ // get target name out of indirect symbol table
+ uint32_t index = (fOffset - fSection->addr()) / sizeof(macho_uintptr_t);
+ index += fSection->reserved1();
+ uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]);
+ uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx();
+ const char* name = &fOwner.fStrings[strOffset];
+ Reference* ref = this->addByNameReference(0, Reference::pointer, name, 0, 0);
+ if ( type == S_LAZY_SYMBOL_POINTERS ) {
+ ref->setLazy(true);
+ 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 = §ionsStart[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 = ⌖
+}
+
+
+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 = ⌖
+}
+
+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;
+}
+
+};
+
+
+
+
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <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);
+}
+
+
+
+};
+
+
+
+
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __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
+
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/reloc.h>
+#include <mach-o/ppc/reloc.h>
+#include <mach-o/stab.h>
+
+#include <vector>
+#include <algorithm>
+#include <map>
+#include <set>
+
+#include "ObjectFile.h"
+#include "ExecutableFile.h"
+#include "Options.h"
+
+// buiild Writer for -arch ppc64
+#undef MACHO_32_SAME_ENDIAN
+#undef MACHO_32_OPPOSITE_ENDIAN
+#undef MACHO_64_SAME_ENDIAN
+#undef MACHO_64_OPPOSITE_ENDIAN
+#if __ppc__ || __ppc64__
+ #define MACHO_64_SAME_ENDIAN
+#elif __i386__
+ #define MACHO_64_OPPOSITE_ENDIAN
+#else
+ #error unknown architecture
+#endif
+namespace ppc64 {
+ #undef ARCH_PPC
+ #define ARCH_PPC64
+ #undef ARCH_I386
+ #include "MachOAbstraction.h"
+ #include "ExecutableFileMachO.cpp"
+};
+
+// buiild Writer for -arch ppc
+#undef MACHO_32_SAME_ENDIAN
+#undef MACHO_32_OPPOSITE_ENDIAN
+#undef MACHO_64_SAME_ENDIAN
+#undef MACHO_64_OPPOSITE_ENDIAN
+#if __ppc__ || __ppc64__
+ #define MACHO_32_SAME_ENDIAN
+#elif __i386__
+ #define MACHO_32_OPPOSITE_ENDIAN
+#else
+ #error unknown architecture
+#endif
+namespace ppc {
+ #define ARCH_PPC
+ #undef ARCH_PPC64
+ #undef ARCH_I386
+ #include "MachOAbstraction.h"
+ #include "ExecutableFileMachO.cpp"
+};
+
+// buiild Writer for -arch i386
+#undef MACHO_32_SAME_ENDIAN
+#undef MACHO_32_OPPOSITE_ENDIAN
+#undef MACHO_64_SAME_ENDIAN
+#undef MACHO_64_OPPOSITE_ENDIAN
+#if __ppc__ || __ppc64__
+ #define MACHO_32_OPPOSITE_ENDIAN
+#elif __i386__
+ #define MACHO_32_SAME_ENDIAN
+#else
+ #error unknown architecture
+#endif
+#undef i386 // compiler sometimes #defines this
+namespace i386 {
+ #undef ARCH_PPC
+ #undef ARCH_PPC64
+ #define ARCH_I386
+ #include "MachOAbstraction.h"
+ #include "ExecutableFileMachO.cpp"
+};
+
+
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __EXECUTABLEFILEMACHO__
+#define __EXECUTABLEFILEMACHO__
+
+class Options;
+
+namespace ppc {
+ namespace ExecutableFileMachO {
+ extern class ExecutableFile::Writer* MakeWriter(const char* path, Options&, std::vector<ExecutableFile::DyLibUsed>&);
+ }
+};
+
+namespace ppc64 {
+ namespace ExecutableFileMachO {
+ extern class ExecutableFile::Writer* MakeWriter(const char* path, Options&, std::vector<ExecutableFile::DyLibUsed>&);
+ }
+};
+
+#undef i386 // compiler sometimes #defines this
+namespace i386 {
+ namespace ExecutableFileMachO {
+ extern class ExecutableFile::Writer* MakeWriter(const char* path, Options&, std::vector<ExecutableFile::DyLibUsed>&);
+ }
+};
+
+
+
+#endif // __EXECUTABLEFILEMACHO__
+
+
+
--- /dev/null
+/*
+ * 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 = §ions[sectionsEmitted++];
+ if ( oneSegment ) {
+ // .o files have weird segment range
+ if ( sectionsEmitted == 1 ) {
+ cmd->set_vmaddr(sectInfo->getBaseAddress());
+ cmd->set_fileoff(sectInfo->fFileOffset);
+ cmd->set_filesize(segInfo->fFileSize-sectInfo->fFileOffset);
+ }
+ cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
+ }
+ sect->set_sectname(sectInfo->fSectionName);
+ sect->set_segname(sectInfo->fSegmentName);
+ sect->set_addr(sectInfo->getBaseAddress());
+ sect->set_size(sectInfo->fSize);
+ sect->set_offset(sectInfo->fFileOffset);
+ sect->set_align(sectInfo->fAlignment);
+ if ( sectInfo->fRelocCount != 0 ) {
+ sect->set_reloff(sectInfo->fRelocOffset * macho_relocation_info::size + fWriter.fLocalRelocationsAtom->getFileOffset());
+ sect->set_nreloc(sectInfo->fRelocCount);
+ }
+ if ( sectInfo->fAllZeroFill ) {
+ sect->set_flags(S_ZEROFILL);
+ }
+ else if ( sectInfo->fAllLazyPointers ) {
+ sect->set_flags(S_LAZY_SYMBOL_POINTERS);
+ sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
+ }
+ else if ( sectInfo->fAllNonLazyPointers ) {
+ sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
+ sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
+ }
+ else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
+ sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
+ }
+ else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
+ sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
+ }
+ }
+ }
+ 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(¤tTime, NULL);
+ time_t timestamp = currentTime.tv_sec;
+ uint64_t size = this->getSize();
+ uint8_t buffer[size];
+ bzero(buffer, size);
+ macho_dylib_command* cmd = (macho_dylib_command*)buffer;
+ cmd->set_cmd(LC_ID_DYLIB);
+ cmd->set_cmdsize(this->getSize());
+ cmd->set_name_offset();
+ cmd->set_timestamp(timestamp);
+ cmd->set_current_version(fWriter.fOptions.currentVersion());
+ cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
+ strcpy((char*)&buffer[macho_dylib_command::name_offset], fWriter.fOptions.installPath());
+ writer.write(0, buffer, size);
+}
+
+
+uint64_t RoutinesLoadCommandsAtom::getSize() const
+{
+ return macho_routines_command::size;
+}
+
+void RoutinesLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+ uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
+ uint8_t buffer[macho_routines_command::size];
+ bzero(buffer, macho_routines_command::size);
+ macho_routines_command* cmd = (macho_routines_command*)buffer;
+ cmd->set_cmd(macho_routines_command::command);
+ cmd->set_cmdsize(this->getSize());
+ cmd->set_init_address(initAddr);
+ writer.write(0, buffer, macho_routines_command::size);
+}
+
+
+uint64_t SubUmbrellaLoadCommandsAtom::getSize() const
+{
+ uint32_t len = macho_sub_umbrella_command::name_offset + strlen(fName);
+ len = (len+7) & (-8); // 8-byte align
+ return len;
+}
+
+void SubUmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+ uint64_t size = this->getSize();
+ uint8_t buffer[size];
+ bzero(buffer, size);
+ macho_sub_umbrella_command* cmd = (macho_sub_umbrella_command*)buffer;
+ cmd->set_cmd(LC_SUB_UMBRELLA);
+ cmd->set_cmdsize(this->getSize());
+ cmd->set_name_offset();
+ strcpy((char*)&buffer[macho_sub_umbrella_command::name_offset], fName);
+ writer.write(0, buffer, size);
+}
+
+
+uint64_t SubLibraryLoadCommandsAtom::getSize() const
+{
+ uint32_t len = macho_sub_library_command::name_offset + fNameLength + 1;
+ len = (len+7) & (-8); // 8-byte align
+ return len;
+}
+
+void SubLibraryLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+ uint64_t size = this->getSize();
+ uint8_t buffer[size];
+ bzero(buffer, size);
+ macho_sub_library_command* cmd = (macho_sub_library_command*)buffer;
+ cmd->set_cmd(LC_SUB_LIBRARY);
+ cmd->set_cmdsize(this->getSize());
+ cmd->set_name_offset();
+ strncpy((char*)&buffer[macho_sub_library_command::name_offset], fNameStart, fNameLength);
+ buffer[macho_sub_library_command::name_offset+fNameLength] = '\0';
+ writer.write(0, buffer, size);
+}
+
+uint64_t UmbrellaLoadCommandsAtom::getSize() const
+{
+ uint32_t len = macho_sub_framework_command::name_offset + strlen(fName);
+ len = (len+7) & (-8); // 8-byte align
+ return len;
+}
+
+void UmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+ uint64_t size = this->getSize();
+ uint8_t buffer[size];
+ bzero(buffer, size);
+ macho_sub_framework_command* cmd = (macho_sub_framework_command*)buffer;
+ cmd->set_cmd(LC_SUB_FRAMEWORK);
+ cmd->set_cmdsize(this->getSize());
+ cmd->set_name_offset();
+ strcpy((char*)&buffer[macho_sub_framework_command::name_offset], fName);
+ writer.write(0, buffer, size);
+}
+
+uint64_t ThreadsLoadCommandsAtom::getSize() const
+{
+#if defined(ARCH_PPC)
+ uint32_t stateSize = 40; // PPC_THREAD_STATE_COUNT;
+#elif defined(ARCH_PPC64)
+ uint32_t stateSize = 76; // PPC_THREAD_STATE64_COUNT;
+#elif defined(ARCH_I386)
+ uint32_t stateSize = 16; // i386_THREAD_STATE_COUNT;
+#else
+ #error unknown architecture
+#endif
+ return macho_thread_command::size + stateSize*4;
+}
+
+void ThreadsLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+ uint64_t size = this->getSize();
+ uint8_t buffer[size];
+ uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
+ bzero(buffer, size);
+ macho_thread_command* cmd = (macho_thread_command*)buffer;
+ cmd->set_cmd(LC_UNIXTHREAD);
+ cmd->set_cmdsize(size);
+#if defined(ARCH_PPC)
+ cmd->set_flavor(1); // PPC_THREAD_STATE
+ cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
+ cmd->set_threadState32(0, start);
+ if ( fWriter.fOptions.hasCustomStack() )
+ cmd->set_threadState32(3, fWriter.fOptions.customStackAddr()); // r1
+#elif defined(ARCH_PPC64)
+ cmd->set_flavor(5); // PPC_THREAD_STATE64
+ cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
+ cmd->set_threadState64(0, start);
+ if ( fWriter.fOptions.hasCustomStack() )
+ cmd->set_threadState64(6, fWriter.fOptions.customStackAddr()); // r1
+#elif defined(ARCH_I386)
+ cmd->set_flavor(0xFFFFFFFF); // i386_THREAD_STATE
+ cmd->set_count(16); // i386_THREAD_STATE_COUNT;
+ cmd->set_threadState32(0, start);
+ if ( fWriter.fOptions.hasCustomStack() )
+ cmd->set_threadState32(15, fWriter.fOptions.customStackAddr()); // uesp
+#else
+ #error unknown architecture
+#endif
+ writer.write(0, buffer, size);
+}
+
+
+
+uint64_t LoadCommandsPaddingAtom::getSize() const
+{
+ return fSize;
+}
+
+void LoadCommandsPaddingAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+ uint8_t buffer[fSize];
+ bzero(buffer, fSize);
+ writer.write(0, buffer, fSize);
+}
+
+
+uint64_t LinkEditAtom::getFileOffset() const
+{
+ return ((Writer::SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
+}
+
+
+uint64_t LocalRelocationsLinkEditAtom::getSize() const
+{
+ return fWriter.fInternalRelocs.size() * macho_relocation_info::size;
+}
+
+void LocalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+ writer.write(0, &fWriter.fInternalRelocs[0], this->getSize());
+}
+
+
+
+uint64_t SymbolTableLinkEditAtom::getSize() const
+{
+ return fWriter.fSymbolTableCount * macho_nlist::size;
+}
+
+void SymbolTableLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+ writer.write(0, fWriter.fSymbolTable, this->getSize());
+}
+
+uint64_t ExternalRelocationsLinkEditAtom::getSize() const
+{
+ return fWriter.fExternalRelocs.size() * macho_relocation_info::size;
+}
+
+void ExternalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+ writer.write(0, &fWriter.fExternalRelocs[0], this->getSize());
+}
+
+
+
+uint64_t IndirectTableLinkEditAtom::getSize() const
+{
+ return fWriter.fIndirectSymbolTable.size() * sizeof(uint32_t);
+}
+
+void IndirectTableLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+ uint64_t size = this->getSize();
+ uint8_t buffer[size];
+ bzero(buffer, size);
+ const uint32_t indirectTableSize = fWriter.fIndirectSymbolTable.size();
+ uint32_t* indirectTable = (uint32_t*)buffer;
+ for (uint32_t i=0; i < indirectTableSize; ++i) {
+ Writer::IndirectEntry& entry = fWriter.fIndirectSymbolTable[i];
+ if ( entry.indirectIndex < indirectTableSize ) {
+ ENDIAN_WRITE32(indirectTable[entry.indirectIndex], entry.symbolIndex);
+ }
+ else {
+ 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;
+}
+
+
+
+};
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <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;
+}
+
+
+
+
+
+
+