1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2009 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
33 #include <ext/hash_map>
42 class File
; // forward reference
44 class GOTEntryAtom
: public ld::Atom
{
46 GOTEntryAtom(ld::Internal
& internal
, const ld::Atom
* target
, bool weakImport
)
47 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
48 ld::Atom::scopeLinkageUnit
, ld::Atom::typeNonLazyPointer
,
49 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)),
50 _fixup(0, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, target
),
52 { _fixup
.weakImport
= weakImport
; internal
.addAtom(*this); }
54 virtual const ld::File
* file() const { return NULL
; }
55 virtual bool translationUnitSource(const char** dir
, const char**) const
57 virtual const char* name() const { return _target
->name(); }
58 virtual uint64_t size() const { return 8; }
59 virtual uint64_t objectAddress() const { return 0; }
60 virtual void copyRawContent(uint8_t buffer
[]) const { }
61 virtual void setScope(Scope
) { }
62 virtual ld::Fixup::iterator
fixupsBegin() const { return &_fixup
; }
63 virtual ld::Fixup::iterator
fixupsEnd() const { return &((ld::Fixup
*)&_fixup
)[1]; }
66 mutable ld::Fixup _fixup
;
67 const ld::Atom
* _target
;
69 static ld::Section _s_section
;
72 ld::Section
GOTEntryAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer
);
75 static bool gotFixup(const Options
& opts
, ld::Internal
& internal
, const ld::Atom
* targetOfGOT
, const ld::Fixup
* fixup
, bool* optimizable
)
77 switch (fixup
->kind
) {
78 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad
:
79 // start by assuming this can be optimized
81 // cannot do LEA optimization if target is in another dylib
82 if ( targetOfGOT
->definition() == ld::Atom::definitionProxy
)
84 // cannot do LEA optimization if target in __huge section
85 if ( internal
.usingHugeSections
&& (targetOfGOT
->size() > 1024*1024)
86 && ( (targetOfGOT
->section().type() == ld::Section::typeZeroFill
)
87 || (targetOfGOT
->section().type() == ld::Section::typeTentativeDefs
)) ) {
90 if ( targetOfGOT
->scope() == ld::Atom::scopeGlobal
) {
91 // cannot do LEA optimization if target is weak exported symbol
92 if ( (targetOfGOT
->definition() == ld::Atom::definitionRegular
) && (targetOfGOT
->combine() == ld::Atom::combineByName
) )
94 // cannot do LEA optimization if target is interposable
95 if ( opts
.interposable(targetOfGOT
->name()) )
97 // cannot do LEA optimization if target is resolver function
98 if ( targetOfGOT
->contentType() == ld::Atom::typeResolver
)
100 // cannot do LEA optimization for flat-namespace
101 if ( opts
.nameSpace() != Options::kTwoLevelNameSpace
)
102 *optimizable
= false;
105 case ld::Fixup::kindStoreX86PCRel32GOT
:
106 *optimizable
= false;
115 struct AtomByNameSorter
117 bool operator()(const ld::Atom
* left
, const ld::Atom
* right
)
119 return (strcmp(left
->name(), right
->name()) < 0);
123 void doPass(const Options
& opts
, ld::Internal
& internal
)
125 const bool log
= false;
127 // only make got section in final linked images
128 if ( opts
.outputKind() == Options::kObjectFile
)
131 // walk all atoms and fixups looking for stubable references
132 // don't create stubs inline because that could invalidate the sections walk
133 std::vector
<const ld::Atom
*> atomsReferencingGOT
;
134 std::map
<const ld::Atom
*,ld::Atom
*> gotMap
;
135 std::map
<const ld::Atom
*,bool> weakImportMap
;
136 atomsReferencingGOT
.reserve(128);
137 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=internal
.sections
.begin(); sit
!= internal
.sections
.end(); ++sit
) {
138 ld::Internal::FinalSection
* sect
= *sit
;
139 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
140 const ld::Atom
* atom
= *ait
;
141 bool atomUsesGOT
= false;
142 const ld::Atom
* targetOfGOT
= NULL
;
143 for (ld::Fixup::iterator fit
= atom
->fixupsBegin(), end
=atom
->fixupsEnd(); fit
!= end
; ++fit
) {
144 if ( fit
->firstInCluster() )
146 switch ( fit
->binding
) {
147 case ld::Fixup::bindingsIndirectlyBound
:
148 targetOfGOT
= internal
.indirectBindingTable
[fit
->u
.bindingIndex
];
150 case ld::Fixup::bindingDirectlyBound
:
151 targetOfGOT
= fit
->u
.target
;
157 if ( !gotFixup(opts
, internal
, targetOfGOT
, fit
, &optimizable
) )
160 // change from load of GOT entry to lea of target
161 if ( log
) fprintf(stderr
, "optimized GOT usage in %s to %s\n", atom
->name(), targetOfGOT
->name());
162 switch ( fit
->binding
) {
163 case ld::Fixup::bindingsIndirectlyBound
:
164 case ld::Fixup::bindingDirectlyBound
:
165 fit
->binding
= ld::Fixup::bindingDirectlyBound
;
166 fit
->u
.target
= targetOfGOT
;
167 fit
->kind
= ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA
;
170 assert(0 && "unsupported GOT reference");
175 // remember that we need to use GOT in this function
176 if ( log
) fprintf(stderr
, "found GOT use in %s to %s\n", atom
->name(), targetOfGOT
->name());
177 if ( !atomUsesGOT
) {
178 atomsReferencingGOT
.push_back(atom
);
181 gotMap
[targetOfGOT
] = NULL
;
182 // record weak_import attribute
183 std::map
<const ld::Atom
*,bool>::iterator pos
= weakImportMap
.find(targetOfGOT
);
184 if ( pos
== weakImportMap
.end() ) {
185 // target not in weakImportMap, so add
186 weakImportMap
[targetOfGOT
] = fit
->weakImport
;
187 // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
188 const ld::dylib::File
* dylib
= dynamic_cast<const ld::dylib::File
*>(targetOfGOT
->file());
189 if ( dylib
!= NULL
) {
190 if ( fit
->weakImport
)
191 (const_cast<ld::dylib::File
*>(dylib
))->setUsingWeakImportedSymbols();
193 (const_cast<ld::dylib::File
*>(dylib
))->setUsingNonWeakImportedSymbols();
197 // target in weakImportMap, check for weakness mismatch
198 if ( pos
->second
!= fit
->weakImport
) {
200 switch ( opts
.weakReferenceMismatchTreatment() ) {
201 case Options::kWeakReferenceMismatchError
:
202 throwf("mismatching weak references for symbol: %s", targetOfGOT
->name());
203 case Options::kWeakReferenceMismatchWeak
:
206 case Options::kWeakReferenceMismatchNonWeak
:
218 for (std::map
<const ld::Atom
*,ld::Atom
*>::iterator it
= gotMap
.begin(); it
!= gotMap
.end(); ++it
) {
219 it
->second
= new GOTEntryAtom(internal
, it
->first
, weakImportMap
[it
->first
]);
222 // update atoms to use GOT entries
223 for (std::vector
<const ld::Atom
*>::iterator it
=atomsReferencingGOT
.begin(); it
!= atomsReferencingGOT
.end(); ++it
) {
224 const ld::Atom
* atom
= *it
;
225 const ld::Atom
* targetOfGOT
= NULL
;
226 ld::Fixup::iterator fitThatSetTarget
= NULL
;
227 for (ld::Fixup::iterator fit
= atom
->fixupsBegin(), end
=atom
->fixupsEnd(); fit
!= end
; ++fit
) {
228 if ( fit
->firstInCluster() ) {
230 fitThatSetTarget
= NULL
;
232 switch ( fit
->binding
) {
233 case ld::Fixup::bindingsIndirectlyBound
:
234 targetOfGOT
= internal
.indirectBindingTable
[fit
->u
.bindingIndex
];
235 fitThatSetTarget
= fit
;
237 case ld::Fixup::bindingDirectlyBound
:
238 targetOfGOT
= fit
->u
.target
;
239 fitThatSetTarget
= fit
;
245 if ( (targetOfGOT
== NULL
) || !gotFixup(opts
, internal
, targetOfGOT
, fit
, &optimizable
) )
247 if ( !optimizable
) {
248 // GOT use not optimized away, update to bind to GOT entry
249 assert(fitThatSetTarget
!= NULL
);
250 switch ( fitThatSetTarget
->binding
) {
251 case ld::Fixup::bindingsIndirectlyBound
:
252 case ld::Fixup::bindingDirectlyBound
:
253 fitThatSetTarget
->binding
= ld::Fixup::bindingDirectlyBound
;
254 fitThatSetTarget
->u
.target
= gotMap
[targetOfGOT
];
257 assert(0 && "unsupported GOT reference");
264 // sort new atoms so links are consistent
265 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=internal
.sections
.begin(); sit
!= internal
.sections
.end(); ++sit
) {
266 ld::Internal::FinalSection
* sect
= *sit
;
267 if ( sect
->type() == ld::Section::typeNonLazyPointer
) {
268 std::sort(sect
->atoms
.begin(), sect
->atoms
.end(), AtomByNameSorter());
275 } // namespace passes