]> git.saurik.com Git - apple/ld64.git/blame - src/ld/passes/got.cpp
ld64-128.2.tar.gz
[apple/ld64.git] / src / ld / passes / got.cpp
CommitLineData
a645023d
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2009 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25
26#include <stdint.h>
27#include <math.h>
28#include <unistd.h>
29#include <dlfcn.h>
30
31#include <vector>
32#include <map>
33#include <ext/hash_map>
34
35#include "ld.hpp"
36#include "got.h"
37
38namespace ld {
39namespace passes {
40namespace got {
41
42class File; // forward reference
43
44class GOTEntryAtom : public ld::Atom {
45public:
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),
51 _target(target)
52 { _fixup.weakImport = weakImport; internal.addAtom(*this); }
53
54 virtual const ld::File* file() const { return NULL; }
55 virtual bool translationUnitSource(const char** dir, const char**) const
56 { return false; }
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]; }
64
65private:
66 mutable ld::Fixup _fixup;
67 const ld::Atom* _target;
68
69 static ld::Section _s_section;
70};
71
72ld::Section GOTEntryAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
73
74
75static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom* targetOfGOT, const ld::Fixup* fixup, bool* optimizable)
76{
77 switch (fixup->kind) {
78 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
79 // start by assuming this can be optimized
80 *optimizable = true;
81 // cannot do LEA optimization if target is in another dylib
82 if ( targetOfGOT->definition() == ld::Atom::definitionProxy )
83 *optimizable = false;
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)) ) {
88 *optimizable = false;
89 }
90 if ( targetOfGOT->scope() == ld::Atom::scopeGlobal ) {
91 // cannot do LEA optimization if target is weak exported symbol
b2fa67a8
A
92 if ( (targetOfGOT->definition() == ld::Atom::definitionRegular) && (targetOfGOT->combine() == ld::Atom::combineByName) ) {
93 switch ( opts.outputKind() ) {
94 case Options::kDynamicExecutable:
95 case Options::kDynamicLibrary:
96 case Options::kDynamicBundle:
97 case Options::kKextBundle:
98 *optimizable = false;
99 break;
100 case Options::kStaticExecutable:
101 case Options::kDyld:
102 case Options::kPreload:
103 case Options::kObjectFile:
104 break;
105 }
106 }
a645023d
A
107 // cannot do LEA optimization if target is interposable
108 if ( opts.interposable(targetOfGOT->name()) )
109 *optimizable = false;
110 // cannot do LEA optimization if target is resolver function
111 if ( targetOfGOT->contentType() == ld::Atom::typeResolver )
112 *optimizable = false;
113 // cannot do LEA optimization for flat-namespace
114 if ( opts.nameSpace() != Options::kTwoLevelNameSpace )
115 *optimizable = false;
116 }
117 return true;
118 case ld::Fixup::kindStoreX86PCRel32GOT:
119 *optimizable = false;
120 return true;
afe874b1
A
121 case ld::Fixup::kindNoneGroupSubordinatePersonality:
122 *optimizable = false;
123 return true;
a645023d
A
124 default:
125 break;
126 }
127
128 return false;
129}
130
131struct AtomByNameSorter
132{
133 bool operator()(const ld::Atom* left, const ld::Atom* right)
134 {
135 return (strcmp(left->name(), right->name()) < 0);
136 }
137};
138
139void doPass(const Options& opts, ld::Internal& internal)
140{
141 const bool log = false;
142
143 // only make got section in final linked images
144 if ( opts.outputKind() == Options::kObjectFile )
145 return;
146
afe874b1
A
147 // walk all atoms and fixups looking for GOT-able references
148 // don't create GOT atoms during this loop because that could invalidate the sections iterator
a645023d
A
149 std::vector<const ld::Atom*> atomsReferencingGOT;
150 std::map<const ld::Atom*,ld::Atom*> gotMap;
151 std::map<const ld::Atom*,bool> weakImportMap;
152 atomsReferencingGOT.reserve(128);
153 for (std::vector<ld::Internal::FinalSection*>::iterator sit=internal.sections.begin(); sit != internal.sections.end(); ++sit) {
154 ld::Internal::FinalSection* sect = *sit;
155 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
156 const ld::Atom* atom = *ait;
157 bool atomUsesGOT = false;
158 const ld::Atom* targetOfGOT = NULL;
afe874b1 159 bool targetIsWeakImport = false;
a645023d
A
160 for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
161 if ( fit->firstInCluster() )
162 targetOfGOT = NULL;
163 switch ( fit->binding ) {
164 case ld::Fixup::bindingsIndirectlyBound:
165 targetOfGOT = internal.indirectBindingTable[fit->u.bindingIndex];
afe874b1 166 targetIsWeakImport = fit->weakImport;
a645023d
A
167 break;
168 case ld::Fixup::bindingDirectlyBound:
169 targetOfGOT = fit->u.target;
afe874b1 170 targetIsWeakImport = fit->weakImport;
a645023d
A
171 break;
172 default:
173 break;
174 }
175 bool optimizable;
176 if ( !gotFixup(opts, internal, targetOfGOT, fit, &optimizable) )
177 continue;
178 if ( optimizable ) {
179 // change from load of GOT entry to lea of target
180 if ( log ) fprintf(stderr, "optimized GOT usage in %s to %s\n", atom->name(), targetOfGOT->name());
181 switch ( fit->binding ) {
182 case ld::Fixup::bindingsIndirectlyBound:
183 case ld::Fixup::bindingDirectlyBound:
184 fit->binding = ld::Fixup::bindingDirectlyBound;
185 fit->u.target = targetOfGOT;
186 fit->kind = ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA;
187 break;
188 default:
189 assert(0 && "unsupported GOT reference");
190 break;
191 }
192 }
193 else {
194 // remember that we need to use GOT in this function
195 if ( log ) fprintf(stderr, "found GOT use in %s to %s\n", atom->name(), targetOfGOT->name());
196 if ( !atomUsesGOT ) {
197 atomsReferencingGOT.push_back(atom);
198 atomUsesGOT = true;
199 }
200 gotMap[targetOfGOT] = NULL;
201 // record weak_import attribute
202 std::map<const ld::Atom*,bool>::iterator pos = weakImportMap.find(targetOfGOT);
203 if ( pos == weakImportMap.end() ) {
204 // target not in weakImportMap, so add
afe874b1
A
205 if ( log ) fprintf(stderr, "weakImportMap[%s] = %d\n", targetOfGOT->name(), targetIsWeakImport);
206 weakImportMap[targetOfGOT] = targetIsWeakImport;
a645023d
A
207 }
208 else {
209 // target in weakImportMap, check for weakness mismatch
afe874b1 210 if ( pos->second != targetIsWeakImport ) {
a645023d
A
211 // found mismatch
212 switch ( opts.weakReferenceMismatchTreatment() ) {
213 case Options::kWeakReferenceMismatchError:
214 throwf("mismatching weak references for symbol: %s", targetOfGOT->name());
215 case Options::kWeakReferenceMismatchWeak:
216 pos->second = true;
217 break;
218 case Options::kWeakReferenceMismatchNonWeak:
219 pos->second = false;
220 break;
221 }
222 }
223 }
224 }
225 }
226 }
227 }
228
229 // make GOT entries
230 for (std::map<const ld::Atom*,ld::Atom*>::iterator it = gotMap.begin(); it != gotMap.end(); ++it) {
231 it->second = new GOTEntryAtom(internal, it->first, weakImportMap[it->first]);
232 }
233
234 // update atoms to use GOT entries
235 for (std::vector<const ld::Atom*>::iterator it=atomsReferencingGOT.begin(); it != atomsReferencingGOT.end(); ++it) {
236 const ld::Atom* atom = *it;
237 const ld::Atom* targetOfGOT = NULL;
238 ld::Fixup::iterator fitThatSetTarget = NULL;
239 for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
240 if ( fit->firstInCluster() ) {
241 targetOfGOT = NULL;
242 fitThatSetTarget = NULL;
243 }
244 switch ( fit->binding ) {
245 case ld::Fixup::bindingsIndirectlyBound:
246 targetOfGOT = internal.indirectBindingTable[fit->u.bindingIndex];
247 fitThatSetTarget = fit;
248 break;
249 case ld::Fixup::bindingDirectlyBound:
250 targetOfGOT = fit->u.target;
251 fitThatSetTarget = fit;
252 break;
253 default:
254 break;
255 }
256 bool optimizable;
257 if ( (targetOfGOT == NULL) || !gotFixup(opts, internal, targetOfGOT, fit, &optimizable) )
258 continue;
259 if ( !optimizable ) {
260 // GOT use not optimized away, update to bind to GOT entry
261 assert(fitThatSetTarget != NULL);
262 switch ( fitThatSetTarget->binding ) {
263 case ld::Fixup::bindingsIndirectlyBound:
264 case ld::Fixup::bindingDirectlyBound:
265 fitThatSetTarget->binding = ld::Fixup::bindingDirectlyBound;
266 fitThatSetTarget->u.target = gotMap[targetOfGOT];
267 break;
268 default:
269 assert(0 && "unsupported GOT reference");
270 break;
271 }
272 }
273 }
274 }
275
276 // sort new atoms so links are consistent
277 for (std::vector<ld::Internal::FinalSection*>::iterator sit=internal.sections.begin(); sit != internal.sections.end(); ++sit) {
278 ld::Internal::FinalSection* sect = *sit;
279 if ( sect->type() == ld::Section::typeNonLazyPointer ) {
280 std::sort(sect->atoms.begin(), sect->atoms.end(), AtomByNameSorter());
281 }
282 }
283}
284
285
286} // namespace got
287} // namespace passes
288} // namespace ld